Skip to content

Commit a03d065

Browse files
shazbertshazbertgbjkgloriousCode
authored
gateio: add websocket resub manager and orderbook update with snapshot functionality [spot] (#2045)
* feat(gateio): add websocket subscription manager and orderbook update with snapshot functionality [spot] * linter + other fixes * AI+Boss: nits * ai+glorious: nits * bossking: nits * drop cross/margin handling for spot pathway as its turned off anyway, handle error from LastUpdateID * linter: fix * Update currency/pair.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update currency/pair.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/gateio/gateio.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/gateio/gateio_types.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/gateio/gateio_types.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/gateio/gateio_websocket.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/gateio/gateio_websocket_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Update exchanges/gateio/gateio_websocket_test.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * gk: nits * Update exchanges/deribit/deribit_websocket.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * linter: fix * Update exchanges/gateio/gateio_websocket.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * glorious: suggestion update * glorious: nits --------- Co-authored-by: shazbert <ryan.oharareid@thrasher.io> Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
1 parent 89bf1a0 commit a03d065

18 files changed

+367
-40
lines changed

common/common.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ var (
7575
ErrGettingField = errors.New("error getting field")
7676
ErrSettingField = errors.New("error setting field")
7777
ErrParsingWSField = errors.New("error parsing websocket field")
78+
ErrMalformedData = errors.New("malformed data")
7879
)
7980

8081
var (

currency/pair.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import (
77
"unicode"
88
)
99

10+
// Public errors
11+
var (
12+
ErrCreatingPair = errors.New("error creating currency pair")
13+
)
14+
1015
var (
11-
errCannotCreatePair = errors.New("cannot create currency pair")
1216
errDelimiterNotFound = errors.New("delimiter not found")
1317
errDelimiterCannotBeEmpty = errors.New("delimiter cannot be empty")
1418
)
@@ -70,7 +74,7 @@ func NewPairWithDelimiter(base, quote, delimiter string) Pair {
7074
// with or without delimiter
7175
func NewPairFromString(currencyPair string) (Pair, error) {
7276
if len(currencyPair) < 3 {
73-
return EMPTYPAIR, fmt.Errorf("%w from %s string too short to be a currency pair", errCannotCreatePair, currencyPair)
77+
return EMPTYPAIR, fmt.Errorf("%w from %s string too short to be a currency pair", ErrCreatingPair, currencyPair)
7478
}
7579

7680
for x := range currencyPair {

currency/pair_methods.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (p *Pair) UnmarshalJSON(d []byte) error {
6161
// incorrectly converted to DUS-KUSDT, ELKRW (Bithumb) which will convert
6262
// converted to ELK-RW and HTUSDT (Lbank) which will be incorrectly
6363
// converted to HTU-SDT.
64-
return fmt.Errorf("%w from %s cannot ensure pair is in correct format, please use exchange method MatchSymbolWithAvailablePairs", errCannotCreatePair, pair)
64+
return fmt.Errorf("%w from %s cannot ensure pair is in correct format, please use exchange method MatchSymbolWithAvailablePairs", ErrCreatingPair, pair)
6565
}
6666

6767
// MarshalJSON conforms type to the marshaler interface

currency/pair_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func TestPairUnmarshalJSON(t *testing.T) {
5454
assert.Equal(t, "usd", p.Quote.String(), "Quote should be correct")
5555
assert.Equal(t, "_", p.Delimiter, "Delimiter should be correct")
5656

57-
assert.ErrorIs(t, p.UnmarshalJSON([]byte(`"btcusd"`)), errCannotCreatePair, "UnmarshalJSON with no delimiter should error")
57+
assert.ErrorIs(t, p.UnmarshalJSON([]byte(`"btcusd"`)), ErrCreatingPair, "UnmarshalJSON with no delimiter should error")
5858

5959
assert.NoError(t, p.UnmarshalJSON([]byte(`""`)), "UnmarshalJSON should not error on empty value")
6060
assert.Equal(t, EMPTYPAIR, p, "UnmarshalJSON empty value should give EMPTYPAIR")

currency/pairs_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func TestPairsFromString(t *testing.T) {
5454
_, err := NewPairsFromString("", "")
5555
assert.ErrorIs(t, err, errNoDelimiter)
5656
_, err = NewPairsFromString("", ",")
57-
assert.ErrorIs(t, err, errCannotCreatePair)
57+
assert.ErrorIs(t, err, ErrCreatingPair)
5858

5959
pairs, err := NewPairsFromString("ALGO-AUD,BAT-AUD,BCH-AUD,BSV-AUD,BTC-AUD,COMP-AUD,ENJ-AUD,ETC-AUD,ETH-AUD,ETH-BTC,GNT-AUD,LINK-AUD,LTC-AUD,LTC-BTC,MCAU-AUD,OMG-AUD,POWR-AUD,UNI-AUD,USDT-AUD,XLM-AUD,XRP-AUD,XRP-BTC", ",")
6060
require.NoError(t, err)

exchanges/deribit/deribit_types.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ var (
4242
errInvalidID = errors.New("invalid id")
4343
errInvalidMarginModel = errors.New("missing margin model")
4444
errInvalidEmailAddress = errors.New("invalid email address")
45-
errMalformedData = errors.New("malformed data")
4645
errWebsocketConnectionNotAuthenticated = errors.New("websocket connection is not authenticated")
4746
errResolutionNotSet = errors.New("resolution not set")
4847
errInvalidDestinationID = errors.New("invalid destination id")

exchanges/deribit/deribit_websocket.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ func (e *Exchange) wsSendHeartbeat(ctx context.Context) {
333333

334334
func (e *Exchange) processUserOrders(respRaw []byte, channels []string) error {
335335
if len(channels) != 4 && len(channels) != 5 {
336-
return fmt.Errorf("%w, expected format 'user.orders.{instrument_name}.raw, user.orders.{instrument_name}.{interval}, user.orders.{kind}.{currency}.raw, or user.orders.{kind}.{currency}.{interval}', but found %s", errMalformedData, strings.Join(channels, "."))
336+
return fmt.Errorf("%w, expected format 'user.orders.{instrument_name}.raw, user.orders.{instrument_name}.{interval}, user.orders.{kind}.{currency}.raw, or user.orders.{kind}.{currency}.{interval}', but found %s", common.ErrMalformedData, strings.Join(channels, "."))
337337
}
338338
var response wsResponse
339339
orderData := []WsOrder{}
@@ -382,7 +382,7 @@ func (e *Exchange) processUserOrders(respRaw []byte, channels []string) error {
382382

383383
func (e *Exchange) processUserOrderChanges(respRaw []byte, channels []string) error {
384384
if len(channels) < 4 || len(channels) > 5 {
385-
return fmt.Errorf("%w, expected format 'trades.{instrument_name}.{interval} or trades.{kind}.{currency}.{interval}', but found %s", errMalformedData, strings.Join(channels, "."))
385+
return fmt.Errorf("%w, expected format 'trades.{instrument_name}.{interval} or trades.{kind}.{currency}.{interval}', but found %s", common.ErrMalformedData, strings.Join(channels, "."))
386386
}
387387
var response wsResponse
388388
changeData := &wsChanges{}
@@ -492,7 +492,7 @@ func (e *Exchange) processTrades(respRaw []byte, channels []string) error {
492492
}
493493

494494
if len(channels) < 3 || len(channels) > 5 {
495-
return fmt.Errorf("%w, expected format 'trades.{instrument_name}.{interval} or trades.{kind}.{currency}.{interval}', but found %s", errMalformedData, strings.Join(channels, "."))
495+
return fmt.Errorf("%w, expected format 'trades.{instrument_name}.{interval} or trades.{kind}.{currency}.{interval}', but found %s", common.ErrMalformedData, strings.Join(channels, "."))
496496
}
497497
var response wsResponse
498498
var tradeList []wsTrade
@@ -536,7 +536,7 @@ func (e *Exchange) processTrades(respRaw []byte, channels []string) error {
536536

537537
func (e *Exchange) processIncrementalTicker(respRaw []byte, channels []string) error {
538538
if len(channels) != 2 {
539-
return fmt.Errorf("%w, expected format 'incremental_ticker.{instrument_name}', but found %s", errMalformedData, strings.Join(channels, "."))
539+
return fmt.Errorf("%w, expected format 'incremental_ticker.{instrument_name}', but found %s", common.ErrMalformedData, strings.Join(channels, "."))
540540
}
541541
a, cp, err := getAssetPairByInstrument(channels[1])
542542
if err != nil {
@@ -568,7 +568,7 @@ func (e *Exchange) processIncrementalTicker(respRaw []byte, channels []string) e
568568

569569
func (e *Exchange) processInstrumentTicker(respRaw []byte, channels []string) error {
570570
if len(channels) != 3 {
571-
return fmt.Errorf("%w, expected format 'ticker.{instrument_name}.{interval}', but found %s", errMalformedData, strings.Join(channels, "."))
571+
return fmt.Errorf("%w, expected format 'ticker.{instrument_name}.{interval}', but found %s", common.ErrMalformedData, strings.Join(channels, "."))
572572
}
573573
return e.processTicker(respRaw, channels)
574574
}
@@ -623,7 +623,7 @@ func (e *Exchange) processData(respRaw []byte, result any) error {
623623

624624
func (e *Exchange) processCandleChart(respRaw []byte, channels []string) error {
625625
if len(channels) != 4 {
626-
return fmt.Errorf("%w, expected format 'chart.trades.{instrument_name}.{resolution}', but found %s", errMalformedData, strings.Join(channels, "."))
626+
return fmt.Errorf("%w, expected format 'chart.trades.{instrument_name}.{resolution}', but found %s", common.ErrInvalidResponse, strings.Join(channels, "."))
627627
}
628628
a, cp, err := getAssetPairByInstrument(channels[2])
629629
if err != nil {
@@ -666,15 +666,15 @@ func (e *Exchange) processOrderbook(respRaw []byte, channels []string) error {
666666
asks := make(orderbook.Levels, 0, len(orderbookData.Asks))
667667
for x := range orderbookData.Asks {
668668
if len(orderbookData.Asks[x]) != 3 {
669-
return errMalformedData
669+
return common.ErrMalformedData
670670
}
671671
price, okay := orderbookData.Asks[x][1].(float64)
672672
if !okay {
673-
return fmt.Errorf("%w, invalid orderbook price", errMalformedData)
673+
return fmt.Errorf("%w, invalid orderbook price", common.ErrMalformedData)
674674
}
675675
amount, okay := orderbookData.Asks[x][2].(float64)
676676
if !okay {
677-
return fmt.Errorf("%w, invalid amount", errMalformedData)
677+
return fmt.Errorf("%w, invalid amount", common.ErrMalformedData)
678678
}
679679
asks = append(asks, orderbook.Level{
680680
Price: price,
@@ -684,17 +684,17 @@ func (e *Exchange) processOrderbook(respRaw []byte, channels []string) error {
684684
bids := make(orderbook.Levels, 0, len(orderbookData.Bids))
685685
for x := range orderbookData.Bids {
686686
if len(orderbookData.Bids[x]) != 3 {
687-
return errMalformedData
687+
return common.ErrMalformedData
688688
}
689689
price, okay := orderbookData.Bids[x][1].(float64)
690690
if !okay {
691-
return fmt.Errorf("%w, invalid orderbook price", errMalformedData)
691+
return fmt.Errorf("%w, invalid orderbook price", common.ErrMalformedData)
692692
} else if price == 0.0 {
693693
continue
694694
}
695695
amount, okay := orderbookData.Bids[x][2].(float64)
696696
if !okay {
697-
return fmt.Errorf("%w, invalid amount", errMalformedData)
697+
return fmt.Errorf("%w, invalid amount", common.ErrMalformedData)
698698
}
699699
bids = append(bids, orderbook.Level{
700700
Price: price,
@@ -735,17 +735,17 @@ func (e *Exchange) processOrderbook(respRaw []byte, channels []string) error {
735735
asks := make(orderbook.Levels, 0, len(orderbookData.Asks))
736736
for x := range orderbookData.Asks {
737737
if len(orderbookData.Asks[x]) != 2 {
738-
return errMalformedData
738+
return common.ErrMalformedData
739739
}
740740
price, okay := orderbookData.Asks[x][0].(float64)
741741
if !okay {
742-
return fmt.Errorf("%w, invalid orderbook price", errMalformedData)
742+
return fmt.Errorf("%w, invalid orderbook price", common.ErrMalformedData)
743743
} else if price == 0 {
744744
continue
745745
}
746746
amount, okay := orderbookData.Asks[x][1].(float64)
747747
if !okay {
748-
return fmt.Errorf("%w, invalid amount", errMalformedData)
748+
return fmt.Errorf("%w, invalid amount", common.ErrMalformedData)
749749
}
750750
asks = append(asks, orderbook.Level{
751751
Price: price,
@@ -755,17 +755,17 @@ func (e *Exchange) processOrderbook(respRaw []byte, channels []string) error {
755755
bids := make([]orderbook.Level, 0, len(orderbookData.Bids))
756756
for x := range orderbookData.Bids {
757757
if len(orderbookData.Bids[x]) != 2 {
758-
return errMalformedData
758+
return common.ErrMalformedData
759759
}
760760
price, okay := orderbookData.Bids[x][0].(float64)
761761
if !okay {
762-
return fmt.Errorf("%w, invalid orderbook price", errMalformedData)
762+
return fmt.Errorf("%w, invalid orderbook price", common.ErrMalformedData)
763763
} else if price == 0 {
764764
continue
765765
}
766766
amount, okay := orderbookData.Bids[x][1].(float64)
767767
if !okay {
768-
return fmt.Errorf("%w, invalid amount", errMalformedData)
768+
return fmt.Errorf("%w, invalid amount", common.ErrMalformedData)
769769
}
770770
bids = append(bids, orderbook.Level{
771771
Price: price,

exchanges/gateio/gateio.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ type Exchange struct {
195195

196196
messageIDSeq common.Counter
197197
wsOBUpdateMgr *wsOBUpdateManager
198+
wsOBResubMgr *wsOBResubManager
198199
}
199200

200201
// ***************************************** SubAccounts ********************************

exchanges/gateio/gateio_types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,17 @@ type WsOrderbookUpdate struct {
20922092
Asks orderbook.LevelsArrayPriceAmount `json:"a"`
20932093
}
20942094

2095+
// WsOrderbookUpdateWithSnapshot represents websocket orderbook update push data
2096+
type WsOrderbookUpdateWithSnapshot struct {
2097+
UpdateTime types.Time `json:"t"`
2098+
Full bool `json:"full"`
2099+
Channel string `json:"s"`
2100+
FirstUpdateID int64 `json:"U"`
2101+
LastUpdateID int64 `json:"u"`
2102+
Bids orderbook.LevelsArrayPriceAmount `json:"b"`
2103+
Asks orderbook.LevelsArrayPriceAmount `json:"a"`
2104+
}
2105+
20952106
// WsOrderbookSnapshot represents a websocket orderbook snapshot push data
20962107
type WsOrderbookSnapshot struct {
20972108
UpdateTime types.Time `json:"t"`

exchanges/gateio/gateio_websocket.go

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const (
4646
spotOrderbookTickerChannel = "spot.book_ticker" // Best bid or ask price
4747
spotOrderbookUpdateChannel = "spot.order_book_update" // Changed order book levels
4848
spotOrderbookChannel = "spot.order_book" // Limited-Level Full Order Book Snapshot
49+
spotOrderbookV2 = "spot.obu"
4950
spotOrdersChannel = "spot.orders"
5051
spotUserTradesChannel = "spot.usertrades"
5152
spotBalancesChannel = "spot.balances"
@@ -64,6 +65,7 @@ var defaultSubscriptions = subscription.List{
6465
{Enabled: true, Channel: subscription.OrderbookChannel, Asset: asset.Spot, Interval: kline.HundredMilliseconds},
6566
{Enabled: false, Channel: spotOrderbookTickerChannel, Asset: asset.Spot, Interval: kline.TenMilliseconds, Levels: 1},
6667
{Enabled: false, Channel: spotOrderbookChannel, Asset: asset.Spot, Interval: kline.HundredMilliseconds, Levels: 100},
68+
{Enabled: false, Channel: spotOrderbookV2, Asset: asset.Spot, Levels: 50},
6769
{Enabled: true, Channel: spotBalancesChannel, Asset: asset.Spot, Authenticated: true},
6870
{Enabled: true, Channel: crossMarginBalanceChannel, Asset: asset.CrossMargin, Authenticated: true},
6971
{Enabled: true, Channel: marginBalancesChannel, Asset: asset.Margin, Authenticated: true},
@@ -191,6 +193,8 @@ func (e *Exchange) WsHandleSpotData(ctx context.Context, conn websocket.Connecti
191193
return e.processOrderbookUpdate(ctx, push.Result, push.Time)
192194
case spotOrderbookChannel:
193195
return e.processOrderbookSnapshot(push.Result, push.Time)
196+
case spotOrderbookV2:
197+
return e.processOrderbookUpdateWithSnapshot(conn, push.Result, push.Time, asset.Spot)
194198
case spotOrdersChannel:
195199
return e.processSpotOrders(respRaw)
196200
case spotUserTradesChannel:
@@ -324,7 +328,7 @@ func (e *Exchange) processCandlestick(incoming []byte) error {
324328
}
325329
icp := strings.Split(data.NameOfSubscription, currency.UnderscoreDelimiter)
326330
if len(icp) < 3 {
327-
return errors.New("malformed candlestick websocket push data")
331+
return fmt.Errorf("%w: candlestick websocket", common.ErrMalformedData)
328332
}
329333
currencyPair, err := currency.NewPairFromString(strings.Join(icp[1:], currency.UnderscoreDelimiter))
330334
if err != nil {
@@ -409,6 +413,59 @@ func (e *Exchange) processOrderbookSnapshot(incoming []byte, lastPushed time.Tim
409413
return nil
410414
}
411415

416+
func (e *Exchange) processOrderbookUpdateWithSnapshot(conn websocket.Connection, incoming []byte, lastPushed time.Time, a asset.Item) error {
417+
var data WsOrderbookUpdateWithSnapshot
418+
if err := json.Unmarshal(incoming, &data); err != nil {
419+
return err
420+
}
421+
422+
channelParts := strings.Split(data.Channel, ".")
423+
if len(channelParts) < 3 {
424+
return fmt.Errorf("%w: %q", common.ErrMalformedData, data.Channel)
425+
}
426+
427+
pair, err := currency.NewPairFromString(channelParts[1])
428+
if err != nil {
429+
return err
430+
}
431+
432+
if data.Full {
433+
if err := e.Websocket.Orderbook.LoadSnapshot(&orderbook.Book{
434+
Exchange: e.Name,
435+
Pair: pair,
436+
Asset: a,
437+
LastUpdated: data.UpdateTime.Time(),
438+
LastPushed: lastPushed,
439+
LastUpdateID: data.LastUpdateID,
440+
Bids: data.Bids.Levels(),
441+
Asks: data.Asks.Levels(),
442+
}); err != nil {
443+
return err
444+
}
445+
e.wsOBResubMgr.CompletedResubscribe(pair, a)
446+
return nil
447+
}
448+
449+
if e.wsOBResubMgr.IsResubscribing(pair, a) {
450+
return nil // Drop incremental updates; waiting for a fresh snapshot
451+
}
452+
453+
lastUpdateID, err := e.Websocket.Orderbook.LastUpdateID(pair, a)
454+
if err != nil || lastUpdateID+1 != data.FirstUpdateID {
455+
return common.AppendError(err, e.wsOBResubMgr.Resubscribe(e, conn, data.Channel, pair, a))
456+
}
457+
return e.Websocket.Orderbook.Update(&orderbook.Update{
458+
Pair: pair,
459+
Asset: a,
460+
UpdateTime: data.UpdateTime.Time(),
461+
LastPushed: lastPushed,
462+
UpdateID: data.LastUpdateID,
463+
Bids: data.Bids.Levels(),
464+
Asks: data.Asks.Levels(),
465+
AllowEmpty: true,
466+
})
467+
}
468+
412469
func (e *Exchange) processSpotOrders(data []byte) error {
413470
resp := struct {
414471
Time types.Time `json:"time"`
@@ -608,11 +665,12 @@ func (e *Exchange) GetSubscriptionTemplate(_ *subscription.Subscription) (*templ
608665
return template.New("master.tmpl").
609666
Funcs(sprig.FuncMap()).
610667
Funcs(template.FuncMap{
611-
"channelName": channelName,
612-
"singleSymbolChannel": singleSymbolChannel,
613-
"orderbookInterval": orderbookChannelInterval,
614-
"candlesInterval": candlesChannelInterval,
615-
"levels": channelLevels,
668+
"channelName": channelName,
669+
"singleSymbolChannel": singleSymbolChannel,
670+
"orderbookInterval": orderbookChannelInterval,
671+
"candlesInterval": candlesChannelInterval,
672+
"levels": channelLevels,
673+
"compactOrderbookPayload": isCompactOrderbookPayload,
616674
}).Parse(subTplText)
617675
}
618676

@@ -700,7 +758,7 @@ func channelName(s *subscription.Subscription) string {
700758
// singleSymbolChannel returns if the channel should be fanned out into single symbol requests
701759
func singleSymbolChannel(name string) bool {
702760
switch name {
703-
case spotCandlesticksChannel, spotOrderbookUpdateChannel, spotOrderbookChannel:
761+
case spotCandlesticksChannel, spotOrderbookUpdateChannel, spotOrderbookChannel, spotOrderbookV2:
704762
return true
705763
}
706764
return false
@@ -739,6 +797,7 @@ func isSingleOrderbookChannel(name string) bool {
739797
case spotOrderbookUpdateChannel,
740798
spotOrderbookChannel,
741799
spotOrderbookTickerChannel,
800+
spotOrderbookV2,
742801
futuresOrderbookChannel,
743802
futuresOrderbookTickerChannel,
744803
futuresOrderbookUpdateChannel,
@@ -812,6 +871,7 @@ var channelLevelsMap = map[asset.Item]map[string][]int{
812871
spotOrderbookTickerChannel: {},
813872
spotOrderbookUpdateChannel: {},
814873
spotOrderbookChannel: {1, 5, 10, 20, 50, 100},
874+
spotOrderbookV2: {50, 400},
815875
},
816876
asset.Futures: {
817877
futuresOrderbookChannel: {1, 5, 10, 20, 50, 100},
@@ -852,16 +912,27 @@ func channelLevels(s *subscription.Subscription, a asset.Item) (string, error) {
852912
return strconv.Itoa(s.Levels), nil
853913
}
854914

915+
func isCompactOrderbookPayload(channel string) bool {
916+
return channel == spotOrderbookV2
917+
}
918+
855919
const subTplText = `
856920
{{- with $name := channelName $.S }}
857921
{{- range $asset, $pairs := $.AssetPairs }}
858922
{{- if singleSymbolChannel $name }}
859923
{{- range $i, $p := $pairs -}}
860-
{{- with $i := candlesInterval $.S }}{{ $i -}} , {{- end }}
861-
{{- $p }}
862-
{{- with $l := levels $.S $asset -}} , {{- $l }}{{ end }}
863-
{{- with $i := orderbookInterval $.S $asset -}} , {{- $i }}{{- end }}
864-
{{- $.PairSeparator }}
924+
{{- if compactOrderbookPayload $name }}
925+
{{- with $l := levels $.S $asset -}}
926+
ob.{{ $p }}.{{ $l }}
927+
{{- end -}}
928+
{{- $.PairSeparator }}
929+
{{- else }}
930+
{{- with $i := candlesInterval $.S }}{{ $i -}} , {{- end }}
931+
{{- $p }}
932+
{{- with $l := levels $.S $asset -}} , {{- $l }}{{ end }}
933+
{{- with $i := orderbookInterval $.S $asset -}} , {{- $i }}{{- end }}
934+
{{- $.PairSeparator }}
935+
{{- end }}
865936
{{- end }}
866937
{{- $.AssetSeparator }}
867938
{{- else }}

0 commit comments

Comments
 (0)