Initial commit

This commit is contained in:
jackyu66git
2026-05-03 16:54:36 +08:00
commit 719f0a061d
22 changed files with 2436 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
package exchange
import (
"encoding/json"
"log"
"time"
)
// AevoWS connects to Aevo WebSocket for ticker data.
type AevoWS struct {
Conn *PriceConnector
Tracked []TrackedSymbol // coin + instrument name pairs
}
type TrackedSymbol struct {
Coin string // "BTC"
InstrumentID string // "BTC-PERP"
}
type aevoTickerMsg struct {
Op string `json:"op"`
Data json.RawMessage `json:"data"`
}
type aevoTickerData struct {
Timestamp string `json:"timestamp"`
Tickers []aevoInstrument `json:"tickers"`
}
type aevoInstrument struct {
InstrumentName string `json:"instrument_name"`
Mark *aevoPriceObj `json:"mark,omitempty"`
LastPrice string `json:"last_price,omitempty"`
}
type aevoPriceObj struct {
Price string `json:"price"`
}
func NewAevoWS(tracked []TrackedSymbol) *AevoWS {
ae := &AevoWS{
Tracked: tracked,
Conn: NewPriceConnector("wss://ws.aevo.xyz", "Aevo", 120*time.Second, 30*time.Second),
}
ae.Conn.PingInterval = 45 * time.Second
return ae
}
// Run connects to Aevo WS and streams ticker data.
func (a *AevoWS) Run(updateFn func(coin string, price float64)) error {
a.Conn.OnConnect = func() {
log.Printf("[Aevo WS] Connected, subscribing to %d tickers", len(a.Tracked))
for _, t := range a.Tracked {
sub := map[string]interface{}{
"op": "subscribe",
"data": []string{"ticker:" + t.Coin},
}
if err := a.Conn.SendJSON(sub); err != nil {
log.Printf("[Aevo WS] Subscribe %s error: %v", t.InstrumentID, err)
}
}
}
a.Conn.OnMessage = func(msg []byte) {
var raw map[string]json.RawMessage
if err := json.Unmarshal(msg, &raw); err != nil {
return
}
// Check for error
if errMsg, hasErr := raw["error"]; hasErr {
var errStr string
json.Unmarshal(errMsg, &errStr)
if errStr != "" {
// Log once, skip errors
return
}
}
// Parse ticker data
op, hasOp := raw["op"]
if !hasOp {
return
}
var opStr string
if err := json.Unmarshal(op, &opStr); err != nil || opStr != "ticker" {
return
}
dataRaw, hasData := raw["data"]
if !hasData {
return
}
var data aevoTickerData
if err := json.Unmarshal(dataRaw, &data); err != nil {
return
}
for _, ticker := range data.Tickers {
// Find the coin for this instrument
coin := ""
for _, t := range a.Tracked {
if t.InstrumentID == ticker.InstrumentName {
coin = t.Coin
break
}
}
if coin == "" {
continue
}
// Try mark price first, then last_price
var price float64
if ticker.Mark != nil && ticker.Mark.Price != "" {
price = parseFloat(ticker.Mark.Price)
} else if ticker.LastPrice != "" {
price = parseFloat(ticker.LastPrice)
}
if price > 0 {
updateFn(coin, price)
}
}
}
return a.Conn.Run()
}