2023-10-18 03:25:50 +00:00
|
|
|
package bitget
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
func getTestClientOrSkip(t *testing.T) *Stream {
|
|
|
|
if b, _ := strconv.ParseBool(os.Getenv("CI")); b {
|
|
|
|
t.Skip("skip test for CI")
|
|
|
|
}
|
|
|
|
|
2023-11-10 13:56:18 +00:00
|
|
|
return NewStream(os.Getenv("BITGET_API_KEY"),
|
|
|
|
os.Getenv("BITGET_API_SECRET"),
|
|
|
|
os.Getenv("BITGET_API_PASSPHRASE"))
|
2023-10-18 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestStream(t *testing.T) {
|
|
|
|
t.Skip()
|
|
|
|
s := getTestClientOrSkip(t)
|
|
|
|
|
|
|
|
symbols := []string{
|
|
|
|
"AAVEUSDT",
|
2024-02-23 07:43:37 +00:00
|
|
|
"ADAUSDT",
|
|
|
|
"ALICEUSDT",
|
2023-10-18 03:25:50 +00:00
|
|
|
"AXSUSDT",
|
2024-02-23 07:43:37 +00:00
|
|
|
"BTCUSDT",
|
|
|
|
"COMPUSDT",
|
|
|
|
"DAIUSDT",
|
2023-10-18 03:25:50 +00:00
|
|
|
"DOGEUSDT",
|
2024-02-23 07:43:37 +00:00
|
|
|
"DOTUSDT",
|
|
|
|
"ETHUSDT",
|
|
|
|
"FILUSDT",
|
|
|
|
"GALAUSDT",
|
|
|
|
"GRTUSDT",
|
|
|
|
"LINKUSDT",
|
|
|
|
"LTCUSDT",
|
|
|
|
"MANAUSDT",
|
|
|
|
"MATICUSDT",
|
|
|
|
"PAXGUSDT",
|
|
|
|
"SANDUSDT",
|
|
|
|
"SLPUSDT",
|
|
|
|
"SOLUSDT",
|
|
|
|
"UNIUSDT",
|
|
|
|
"XLMUSDT",
|
|
|
|
"YFIUSDT",
|
|
|
|
"APEUSDT",
|
|
|
|
"ARUSDT",
|
|
|
|
"BNBUSDT",
|
|
|
|
"CHZUSDT",
|
|
|
|
"ENSUSDT",
|
|
|
|
"ETCUSDT",
|
|
|
|
"FTMUSDT",
|
|
|
|
"GMTUSDT",
|
|
|
|
"LOOKSUSDT",
|
|
|
|
"XTZUSDT",
|
|
|
|
"ARBUSDT",
|
|
|
|
"LDOUSDT",
|
|
|
|
"TRXUSDT",
|
2023-10-18 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("book test", func(t *testing.T) {
|
|
|
|
s.Subscribe(types.BookChannel, "BTCUSDT", types.SubscribeOptions{
|
|
|
|
Depth: types.DepthLevel5,
|
|
|
|
})
|
|
|
|
s.SetPublicOnly()
|
|
|
|
err := s.Connect(context.Background())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
s.OnBookSnapshot(func(book types.SliceOrderBook) {
|
|
|
|
t.Log("got snapshot", len(book.Bids), len(book.Asks), book.Symbol, book.Time, book)
|
|
|
|
})
|
|
|
|
s.OnBookUpdate(func(book types.SliceOrderBook) {
|
|
|
|
t.Log("got update", len(book.Bids), len(book.Asks), book.Symbol, book.Time, book)
|
|
|
|
})
|
|
|
|
c := make(chan struct{})
|
|
|
|
<-c
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("book test on unsubscribe and reconnect", func(t *testing.T) {
|
|
|
|
for _, symbol := range symbols {
|
|
|
|
s.Subscribe(types.BookChannel, symbol, types.SubscribeOptions{
|
|
|
|
Depth: types.DepthLevel200,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
s.SetPublicOnly()
|
|
|
|
err := s.Connect(context.Background())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
s.OnBookSnapshot(func(book types.SliceOrderBook) {
|
|
|
|
t.Log("got snapshot", book)
|
|
|
|
})
|
|
|
|
s.OnBookUpdate(func(book types.SliceOrderBook) {
|
|
|
|
t.Log("got update", book)
|
|
|
|
})
|
|
|
|
|
|
|
|
<-time.After(2 * time.Second)
|
|
|
|
|
|
|
|
s.Unsubscribe()
|
|
|
|
for _, symbol := range symbols {
|
|
|
|
s.Subscribe(types.BookChannel, symbol, types.SubscribeOptions{
|
|
|
|
Depth: types.DepthLevel200,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
<-time.After(2 * time.Second)
|
|
|
|
|
|
|
|
s.Reconnect()
|
|
|
|
|
|
|
|
c := make(chan struct{})
|
|
|
|
<-c
|
|
|
|
})
|
2023-10-19 10:12:05 +00:00
|
|
|
|
|
|
|
t.Run("trade test", func(t *testing.T) {
|
|
|
|
s.Subscribe(types.MarketTradeChannel, "BTCUSDT", types.SubscribeOptions{})
|
|
|
|
s.SetPublicOnly()
|
|
|
|
err := s.Connect(context.Background())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
s.OnMarketTrade(func(trade types.Trade) {
|
|
|
|
t.Log("got update", trade)
|
|
|
|
})
|
|
|
|
c := make(chan struct{})
|
|
|
|
<-c
|
|
|
|
})
|
|
|
|
|
2023-10-31 13:53:13 +00:00
|
|
|
t.Run("kline test", func(t *testing.T) {
|
|
|
|
s.Subscribe(types.KLineChannel, "BTCUSDT", types.SubscribeOptions{Interval: types.Interval1w})
|
|
|
|
s.SetPublicOnly()
|
|
|
|
err := s.Connect(context.Background())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
s.OnKLine(func(kline types.KLine) {
|
|
|
|
t.Log("got update", kline)
|
|
|
|
})
|
|
|
|
s.OnKLineClosed(func(kline types.KLine) {
|
|
|
|
t.Log("got closed update", kline)
|
|
|
|
})
|
|
|
|
c := make(chan struct{})
|
|
|
|
<-c
|
|
|
|
})
|
|
|
|
|
2023-11-10 13:56:18 +00:00
|
|
|
t.Run("private test", func(t *testing.T) {
|
2023-12-12 09:30:51 +00:00
|
|
|
s.SetPrivateChannelSymbols([]string{"BTCUSDT"})
|
2023-11-10 13:56:18 +00:00
|
|
|
err := s.Connect(context.Background())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-11-10 14:35:39 +00:00
|
|
|
s.OnBalanceSnapshot(func(balances types.BalanceMap) {
|
|
|
|
t.Log("get balances", balances)
|
|
|
|
})
|
|
|
|
s.OnBalanceUpdate(func(balances types.BalanceMap) {
|
|
|
|
t.Log("get update", balances)
|
|
|
|
})
|
2023-11-14 03:23:30 +00:00
|
|
|
s.OnOrderUpdate(func(order types.Order) {
|
|
|
|
t.Log("order update", order)
|
|
|
|
})
|
|
|
|
s.OnTradeUpdate(func(trade types.Trade) {
|
|
|
|
t.Log("trade update", trade)
|
|
|
|
})
|
2023-11-10 14:35:39 +00:00
|
|
|
|
2023-11-10 13:56:18 +00:00
|
|
|
c := make(chan struct{})
|
|
|
|
<-c
|
|
|
|
})
|
|
|
|
|
2023-10-18 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestStream_parseWebSocketEvent(t *testing.T) {
|
|
|
|
t.Run("op subscribe event", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"event":"subscribe",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-18 03:25:50 +00:00
|
|
|
"channel":"books5",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
res, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
opEvent, ok := res.(*WsEvent)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, WsEvent{
|
|
|
|
Event: WsEventSubscribe,
|
|
|
|
Arg: WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-18 03:25:50 +00:00
|
|
|
Channel: ChannelOrderBook5,
|
|
|
|
InstId: "BTCUSDT",
|
|
|
|
},
|
|
|
|
}, *opEvent)
|
|
|
|
|
|
|
|
assert.NoError(t, opEvent.IsValid())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("op unsubscribe event", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"event":"unsubscribe",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-18 03:25:50 +00:00
|
|
|
"channel":"books5",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
res, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
opEvent, ok := res.(*WsEvent)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, WsEvent{
|
|
|
|
Event: WsEventUnsubscribe,
|
|
|
|
Arg: WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-18 03:25:50 +00:00
|
|
|
Channel: ChannelOrderBook5,
|
|
|
|
InstId: "BTCUSDT",
|
|
|
|
},
|
|
|
|
}, *opEvent)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("op error event", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"event":"error",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-18 03:25:50 +00:00
|
|
|
"channel":"books5",
|
|
|
|
"instId":"BTCUSDT-"
|
|
|
|
},
|
|
|
|
"code":30001,
|
|
|
|
"msg":"instType:sp,channel:books5,instId:BTCUSDT- doesn't exist",
|
|
|
|
"op":"subscribe"
|
|
|
|
}`
|
|
|
|
res, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
opEvent, ok := res.(*WsEvent)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, WsEvent{
|
|
|
|
Event: WsEventError,
|
|
|
|
Code: 30001,
|
|
|
|
Msg: "instType:sp,channel:books5,instId:BTCUSDT- doesn't exist",
|
|
|
|
Op: "subscribe",
|
|
|
|
Arg: WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-18 03:25:50 +00:00
|
|
|
Channel: ChannelOrderBook5,
|
|
|
|
InstId: "BTCUSDT-",
|
|
|
|
},
|
|
|
|
}, *opEvent)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Orderbook event", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-18 03:25:50 +00:00
|
|
|
"channel":"books5",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
|
|
|
{
|
|
|
|
"asks":[
|
|
|
|
[
|
|
|
|
"28350.78",
|
|
|
|
"0.2082"
|
|
|
|
],
|
|
|
|
[
|
|
|
|
"28350.80",
|
|
|
|
"0.2081"
|
|
|
|
]
|
|
|
|
],
|
|
|
|
"bids":[
|
|
|
|
[
|
|
|
|
"28350.70",
|
|
|
|
"0.5585"
|
|
|
|
],
|
|
|
|
[
|
|
|
|
"28350.67",
|
|
|
|
"6.8175"
|
|
|
|
]
|
|
|
|
],
|
|
|
|
"checksum":0,
|
|
|
|
"ts":"1697593934630"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"ts":1697593934630
|
|
|
|
}`
|
|
|
|
|
|
|
|
eventFn := func(in string, actionType ActionType) {
|
|
|
|
res, err := parseWebSocketEvent([]byte(in))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
book, ok := res.(*BookEvent)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, BookEvent{
|
|
|
|
Events: []struct {
|
|
|
|
Asks types.PriceVolumeSlice `json:"asks"`
|
|
|
|
// Order book on buy side, descending order
|
|
|
|
Bids types.PriceVolumeSlice `json:"bids"`
|
|
|
|
Ts types.MillisecondTimestamp `json:"ts"`
|
|
|
|
Checksum int `json:"checksum"`
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
Asks: []types.PriceVolume{
|
|
|
|
{
|
|
|
|
Price: fixedpoint.NewFromFloat(28350.78),
|
|
|
|
Volume: fixedpoint.NewFromFloat(0.2082),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Price: fixedpoint.NewFromFloat(28350.80),
|
|
|
|
Volume: fixedpoint.NewFromFloat(0.2081),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Bids: []types.PriceVolume{
|
|
|
|
{
|
|
|
|
Price: fixedpoint.NewFromFloat(28350.70),
|
|
|
|
Volume: fixedpoint.NewFromFloat(0.5585),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Price: fixedpoint.NewFromFloat(28350.67),
|
|
|
|
Volume: fixedpoint.NewFromFloat(6.8175),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Ts: types.NewMillisecondTimestampFromInt(1697593934630),
|
|
|
|
Checksum: 0,
|
|
|
|
},
|
|
|
|
},
|
2023-10-19 10:12:05 +00:00
|
|
|
actionType: actionType,
|
|
|
|
instId: "BTCUSDT",
|
2023-10-18 03:25:50 +00:00
|
|
|
}, *book)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("snapshot type", func(t *testing.T) {
|
|
|
|
snapshotInput := fmt.Sprintf(input, ActionTypeSnapshot)
|
|
|
|
eventFn(snapshotInput, ActionTypeSnapshot)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("update type", func(t *testing.T) {
|
|
|
|
snapshotInput := fmt.Sprintf(input, ActionTypeUpdate)
|
|
|
|
eventFn(snapshotInput, ActionTypeUpdate)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-10-19 10:12:05 +00:00
|
|
|
func Test_parseWebSocketEvent_MarketTrade(t *testing.T) {
|
|
|
|
t.Run("MarketTrade event", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-19 10:12:05 +00:00
|
|
|
"channel":"trade",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 16:01:30 +00:00
|
|
|
{
|
|
|
|
"ts":"1723476690562",
|
|
|
|
"price":"59440.52",
|
|
|
|
"size":"0.018545",
|
|
|
|
"side":"sell",
|
|
|
|
"tradeId":"1206914205132210181"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ts":"1723476690562",
|
|
|
|
"price":"59440.52",
|
|
|
|
"size":"0.001255",
|
|
|
|
"side":"sell",
|
|
|
|
"tradeId":"1206914205132210179"
|
|
|
|
}
|
|
|
|
],
|
2023-10-19 10:12:05 +00:00
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
|
|
|
|
eventFn := func(in string, actionType ActionType) {
|
|
|
|
res, err := parseWebSocketEvent([]byte(in))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
book, ok := res.(*MarketTradeEvent)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, MarketTradeEvent{
|
|
|
|
Events: MarketTradeSlice{
|
|
|
|
{
|
2024-08-12 16:01:30 +00:00
|
|
|
Ts: types.NewMillisecondTimestampFromInt(1723476690562),
|
|
|
|
Price: fixedpoint.NewFromFloat(59440.52),
|
|
|
|
Size: fixedpoint.NewFromFloat(0.018545),
|
|
|
|
Side: "sell",
|
|
|
|
TradeId: 1206914205132210181,
|
2023-10-19 10:12:05 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2024-08-12 16:01:30 +00:00
|
|
|
Ts: types.NewMillisecondTimestampFromInt(1723476690562),
|
|
|
|
Price: fixedpoint.NewFromFloat(59440.52),
|
|
|
|
Size: fixedpoint.NewFromFloat(0.001255),
|
|
|
|
Side: "sell",
|
|
|
|
TradeId: 1206914205132210179,
|
2023-10-19 10:12:05 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
actionType: actionType,
|
|
|
|
instId: "BTCUSDT",
|
|
|
|
}, *book)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("snapshot type", func(t *testing.T) {
|
|
|
|
snapshotInput := fmt.Sprintf(input, ActionTypeSnapshot)
|
|
|
|
eventFn(snapshotInput, ActionTypeSnapshot)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("update type", func(t *testing.T) {
|
|
|
|
snapshotInput := fmt.Sprintf(input, ActionTypeUpdate)
|
|
|
|
eventFn(snapshotInput, ActionTypeUpdate)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected timestamp", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-19 10:12:05 +00:00
|
|
|
"channel":"trade",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
2024-08-12 16:01:30 +00:00
|
|
|
"data":[{"ts":"TIMESTAMP","price":"59440.52","size":"0.018545","side":"sell","tradeId":"1206914205132210181"},{"ts":"1723476690562","price":"59440.52","size":"0.001255","side":"sell","tradeId":"1206914205132210179"}],
|
2023-10-19 10:12:05 +00:00
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
2024-08-12 16:01:30 +00:00
|
|
|
assert.ErrorContains(t, err, "failed to unmarshal data")
|
2023-10-19 10:12:05 +00:00
|
|
|
})
|
|
|
|
|
2024-08-12 16:01:30 +00:00
|
|
|
// TODO: If a non-numeric value causes panic, then let's comment out this test for now.
|
|
|
|
//t.Run("Unexpected price", func(t *testing.T) {
|
|
|
|
// input := `{
|
|
|
|
// "action":"%s",
|
|
|
|
// "arg":{
|
|
|
|
// "instType":"SPOT",
|
|
|
|
// "channel":"trade",
|
|
|
|
// "instId":"BTCUSDT"
|
|
|
|
// },
|
|
|
|
// "data":[{"ts":"1723476690562","price":"UNEXPECTED","size":"0.018545","side":"sell","tradeId":"1206914205132210181"},{"ts":"1723476690562","price":"59440.52","size":"0.001255","side":"sell","tradeId":"1206914205132210179"}],
|
|
|
|
// "ts":1697697791670
|
|
|
|
// }`
|
|
|
|
// _, err := parseWebSocketEvent([]byte(input))
|
|
|
|
// assert.ErrorContains(t, err, "failed to unmarshal data")
|
|
|
|
//})
|
|
|
|
//
|
|
|
|
// TODO: If a non-numeric value causes panic, then let's comment out this test for now.
|
|
|
|
//t.Run("Unexpected size", func(t *testing.T) {
|
|
|
|
// input := `{
|
|
|
|
// "action":"%s",
|
|
|
|
// "arg":{
|
|
|
|
// "instType":"SPOT",
|
|
|
|
// "channel":"trade",
|
|
|
|
// "instId":"BTCUSDT"
|
|
|
|
// },
|
|
|
|
// "data":[{"ts":"1723476690562","price":"59440.52","size":"2v","side":"sell","tradeId":"1206914205132210181"},{"ts":"1723476690562","price":"59440.52","size":"0.001255","side":"sell","tradeId":"1206914205132210179"}],
|
|
|
|
// "ts":1697697791670
|
|
|
|
// }`
|
|
|
|
// _, err := parseWebSocketEvent([]byte(input))
|
|
|
|
// assert.ErrorContains(t, err, "failed to unmarshal data")
|
|
|
|
//})
|
2023-10-19 10:12:05 +00:00
|
|
|
|
|
|
|
t.Run("Unexpected side", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-19 10:12:05 +00:00
|
|
|
"channel":"trade",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
2024-08-12 16:01:30 +00:00
|
|
|
"data":[{"ts":"1723476690562","price":"59440.52","size":"0.018545","side":"ssss","tradeId":"1206914205132210181"},{"ts":"1723476690562","price":"59440.52","size":"0.001255","side":"sell","tradeId":"1206914205132210179"}],
|
2023-10-19 10:12:05 +00:00
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
2024-08-12 16:01:30 +00:00
|
|
|
assert.ErrorContains(t, err, "failed to unmarshal data")
|
2023-10-19 10:12:05 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-10-31 13:53:13 +00:00
|
|
|
func Test_parseWebSocketEvent_KLine(t *testing.T) {
|
|
|
|
t.Run("KLine event", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["1698744600000","34361.49","34458.98","34355.53","34416.41","99.6631", "123456", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
|
|
|
|
eventFn := func(in string, actionType ActionType) {
|
|
|
|
res, err := parseWebSocketEvent([]byte(in))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
kline, ok := res.(*KLineEvent)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, KLineEvent{
|
|
|
|
channel: "candle5m",
|
|
|
|
Events: KLineSlice{
|
|
|
|
{
|
|
|
|
StartTime: types.NewMillisecondTimestampFromInt(1698744600000),
|
|
|
|
OpenPrice: fixedpoint.NewFromFloat(34361.49),
|
|
|
|
HighestPrice: fixedpoint.NewFromFloat(34458.98),
|
|
|
|
LowestPrice: fixedpoint.NewFromFloat(34355.53),
|
|
|
|
ClosePrice: fixedpoint.NewFromFloat(34416.41),
|
|
|
|
Volume: fixedpoint.NewFromFloat(99.6631),
|
2024-08-12 15:07:32 +00:00
|
|
|
QuoteVolume: fixedpoint.NewFromFloat(123456),
|
2023-10-31 13:53:13 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
actionType: actionType,
|
|
|
|
instId: "BTCUSDT",
|
|
|
|
}, *kline)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("snapshot type", func(t *testing.T) {
|
|
|
|
snapshotInput := fmt.Sprintf(input, ActionTypeSnapshot)
|
|
|
|
eventFn(snapshotInput, ActionTypeSnapshot)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("update type", func(t *testing.T) {
|
|
|
|
snapshotInput := fmt.Sprintf(input, ActionTypeUpdate)
|
|
|
|
eventFn(snapshotInput, ActionTypeUpdate)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected length of kline", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["1698744600000","34361.49","34458.98","34355.53","34416.41","99.6631", "123456", "123", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.ErrorContains(t, err, "unexpected kline length")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected timestamp", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["timestamp","34361.49","34458.98","34355.53","34416.41","99.6631", "123456", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.ErrorContains(t, err, "timestamp")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected open price", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["1698744600000","1p","34458.98","34355.53","34416.41","99.6631", "123456", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.ErrorContains(t, err, "open price")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected highest price", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["1698744600000","34361.49","3p","34355.53","34416.41","99.6631", "123456", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.ErrorContains(t, err, "highest price")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected lowest price", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["1698744600000","34361.49","34458.98","1p","34416.41","99.6631", "123456", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.ErrorContains(t, err, "lowest price")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected close price", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["1698744600000","34361.49","34458.98","34355.53","1c","99.6631", "123456", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.ErrorContains(t, err, "close price")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Unexpected volume", func(t *testing.T) {
|
|
|
|
input := `{
|
|
|
|
"action":"%s",
|
|
|
|
"arg":{
|
2024-08-12 15:07:32 +00:00
|
|
|
"instType":"SPOT",
|
2023-10-31 13:53:13 +00:00
|
|
|
"channel":"candle5m",
|
|
|
|
"instId":"BTCUSDT"
|
|
|
|
},
|
|
|
|
"data":[
|
2024-08-12 15:07:32 +00:00
|
|
|
["1698744600000","34361.49","34458.98","34355.53","34416.41","1v", "123456", "123"]
|
2023-10-31 13:53:13 +00:00
|
|
|
],
|
|
|
|
"ts":1697697791670
|
|
|
|
}`
|
|
|
|
_, err := parseWebSocketEvent([]byte(input))
|
|
|
|
assert.ErrorContains(t, err, "volume")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-10-18 03:25:50 +00:00
|
|
|
func Test_convertSubscription(t *testing.T) {
|
|
|
|
t.Run("BookChannel.ChannelOrderBook5", func(t *testing.T) {
|
|
|
|
res, err := convertSubscription(types.Subscription{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Channel: types.BookChannel,
|
|
|
|
Options: types.SubscribeOptions{
|
|
|
|
Depth: types.DepthLevel5,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-18 03:25:50 +00:00
|
|
|
Channel: ChannelOrderBook5,
|
|
|
|
InstId: "BTCUSDT",
|
|
|
|
}, res)
|
|
|
|
})
|
|
|
|
t.Run("BookChannel.DepthLevel15", func(t *testing.T) {
|
|
|
|
res, err := convertSubscription(types.Subscription{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Channel: types.BookChannel,
|
|
|
|
Options: types.SubscribeOptions{
|
|
|
|
Depth: types.DepthLevel15,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-18 03:25:50 +00:00
|
|
|
Channel: ChannelOrderBook15,
|
|
|
|
InstId: "BTCUSDT",
|
|
|
|
}, res)
|
|
|
|
})
|
|
|
|
t.Run("BookChannel.DepthLevel200", func(t *testing.T) {
|
|
|
|
res, err := convertSubscription(types.Subscription{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Channel: types.BookChannel,
|
|
|
|
Options: types.SubscribeOptions{
|
|
|
|
Depth: types.DepthLevel200,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-18 03:25:50 +00:00
|
|
|
Channel: ChannelOrderBook,
|
|
|
|
InstId: "BTCUSDT",
|
|
|
|
}, res)
|
|
|
|
})
|
2023-10-19 10:12:05 +00:00
|
|
|
t.Run("TradeChannel", func(t *testing.T) {
|
|
|
|
res, err := convertSubscription(types.Subscription{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Channel: types.MarketTradeChannel,
|
|
|
|
Options: types.SubscribeOptions{},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-19 10:12:05 +00:00
|
|
|
Channel: ChannelTrade,
|
|
|
|
InstId: "BTCUSDT",
|
|
|
|
}, res)
|
|
|
|
})
|
2023-10-31 13:53:13 +00:00
|
|
|
t.Run("CandleChannel", func(t *testing.T) {
|
|
|
|
for gInterval, localInterval := range toLocalInterval {
|
|
|
|
res, err := convertSubscription(types.Subscription{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
Channel: types.KLineChannel,
|
|
|
|
Options: types.SubscribeOptions{
|
|
|
|
Interval: gInterval,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, WsArg{
|
2024-08-12 15:07:32 +00:00
|
|
|
InstType: instSpV2,
|
2023-10-31 13:53:13 +00:00
|
|
|
Channel: ChannelType(localInterval),
|
|
|
|
InstId: "BTCUSDT",
|
|
|
|
}, res)
|
|
|
|
}
|
|
|
|
})
|
2023-10-18 03:25:50 +00:00
|
|
|
}
|