Skip to content

Commit

Permalink
Bithumb: Add subscription configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
gbjk committed Aug 17, 2024
1 parent 225429b commit 56a820f
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 38 deletions.
81 changes: 49 additions & 32 deletions exchanges/bithumb/bithumb_websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"
"text/template"
"time"

"github.com/Masterminds/sprig/v3"
"github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
Expand All @@ -22,10 +27,15 @@ const (
)

var (
wsDefaultTickTypes = []string{"30M"} // alternatives "1H", "12H", "24H", "MID"
location *time.Location
location *time.Location
)

var defaultSubscriptions = subscription.List{
{Enabled: true, Asset: asset.Spot, Channel: subscription.TickerChannel, Interval: kline.ThirtyMin}, // alternatives "1H", "12H", "24H"
{Enabled: true, Asset: asset.Spot, Channel: subscription.OrderbookChannel},
{Enabled: true, Asset: asset.Spot, Channel: subscription.AllTradesChannel},
}

// WsConnect initiates a websocket connection
func (b *Bithumb) WsConnect() error {
if !b.Websocket.IsEnabled() || !b.IsEnabled() {
Expand Down Expand Up @@ -169,41 +179,19 @@ func (b *Bithumb) wsHandleData(respRaw []byte) error {

// generateSubscriptions generates the default subscription set
func (b *Bithumb) generateSubscriptions() (subscription.List, error) {
var channels = []string{"ticker", "transaction", "orderbookdepth"}
var subscriptions subscription.List
pairs, err := b.GetEnabledPairs(asset.Spot)
if err != nil {
return nil, err
}
return b.Features.Subscriptions.ExpandTemplates(b)
}

pFmt, err := b.GetPairFormat(asset.Spot, true)
if err != nil {
return nil, err
}
pairs = pairs.Format(pFmt)

for y := range channels {
subscriptions = append(subscriptions, &subscription.Subscription{
Channel: channels[y],
Pairs: pairs,
Asset: asset.Spot,
})
}
return subscriptions, nil
// GetSubscriptionTemplate returns a subscription channel template
func (b *Bithumb) GetSubscriptionTemplate(_ *subscription.Subscription) (*template.Template, error) {
return template.New("master.tmpl").Funcs(sprig.FuncMap()).Funcs(template.FuncMap{"subToReq": subToReq}).Parse(subTplText)
}

// Subscribe subscribes to a set of channels
func (b *Bithumb) Subscribe(channelsToSubscribe subscription.List) error {
func (b *Bithumb) Subscribe(subs subscription.List) error {
var errs error
for _, s := range channelsToSubscribe {
req := &WsSubscribe{
Type: s.Channel,
Symbols: s.Pairs,
}
if s.Channel == "ticker" {
req.TickTypes = wsDefaultTickTypes
}
err := b.Websocket.Conn.SendJSONMessage(req)
for _, s := range subs {
err := b.Websocket.Conn.SendJSONMessage(json.RawMessage(s.QualifiedChannel))
if err == nil {
err = b.Websocket.AddSuccessfulSubscriptions(s)
}
Expand All @@ -213,3 +201,32 @@ func (b *Bithumb) Subscribe(channelsToSubscribe subscription.List) error {
}
return errs
}

// subToReq returns the subscription as a map to populate WsSubscribe
func subToReq(s *subscription.Subscription, p currency.Pairs) *WsSubscribe {
req := &WsSubscribe{
Type: s.Channel,
Symbols: common.SortStrings(p),
}
switch s.Channel {
case subscription.TickerChannel:
// As-is
case subscription.OrderbookChannel:
req.Type = "orderbookdepth"
case subscription.AllTradesChannel:
req.Type = "transaction"
default:
panic(fmt.Errorf("%w: %s", subscription.ErrNotSupported, s.Channel))
}
if s.Interval > 0 {
req.TickTypes = []string{strings.ToUpper(s.Interval.Short())}
}
return req
}

const subTplText = `
{{ range $asset, $pairs := $.AssetPairs }}
{{- subToReq $.S $pairs | mustToJson }}
{{- $.AssetSeparator }}
{{- end }}
`
45 changes: 39 additions & 6 deletions exchanges/bithumb/bithumb_websocket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ import (
"errors"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
testsubs "github.com/thrasher-corp/gocryptotrader/internal/testing/subscriptions"
)

var (
Expand Down Expand Up @@ -87,13 +93,40 @@ func TestWsHandleData(t *testing.T) {
}
}

func TestSubToReq(t *testing.T) {
t.Parallel()
p := currency.Pairs{currency.NewPairWithDelimiter("BTC", "KRW", "_"), currency.NewPairWithDelimiter("ETH", "KRW", "_")}
r := subToReq(&subscription.Subscription{Channel: subscription.AllTradesChannel}, p)
assert.Equal(t, "transaction", r.Type)
assert.True(t, p.Equal(r.Symbols))
r = subToReq(&subscription.Subscription{Channel: subscription.OrderbookChannel}, p)
assert.Equal(t, "orderbookdepth", r.Type)
assert.True(t, p.Equal(r.Symbols))
r = subToReq(&subscription.Subscription{Channel: subscription.TickerChannel, Interval: kline.OneHour}, p)
assert.Equal(t, "ticker", r.Type)
assert.True(t, p.Equal(r.Symbols))
assert.Equal(t, []string{"1H"}, r.TickTypes)
assert.PanicsWithError(t,
"subscription channel not supported: myTrades",
func() { subToReq(&subscription.Subscription{Channel: subscription.MyTradesChannel}, p) },
"should panic on invalid channel",
)
}

func TestGenerateSubscriptions(t *testing.T) {
t.Parallel()
sub, err := b.generateSubscriptions()
if err != nil {
t.Fatal(err)
}
if sub == nil {
t.Fatal("unexpected value")
b := new(Bithumb)
require.NoError(t, testexch.Setup(b), "Test instance Setup must not error")
p := currency.Pairs{currency.NewPairWithDelimiter("BTC", "KRW", "_"), currency.NewPairWithDelimiter("ETH", "KRW", "_")}
require.NoError(t, b.CurrencyPairs.StorePairs(asset.Spot, p, false))
require.NoError(t, b.CurrencyPairs.StorePairs(asset.Spot, p, true))
subs, err := b.generateSubscriptions()
require.NoError(t, err)
exp := subscription.List{
{Asset: asset.Spot, Channel: subscription.AllTradesChannel, Pairs: p, QualifiedChannel: `{"type":"transaction","symbols":["BTC_KRW","ETH_KRW"]}`},
{Asset: asset.Spot, Channel: subscription.OrderbookChannel, Pairs: p, QualifiedChannel: `{"type":"orderbookdepth","symbols":["BTC_KRW","ETH_KRW"]}`},
{Asset: asset.Spot, Channel: subscription.TickerChannel, Pairs: p, Interval: kline.ThirtyMin,
QualifiedChannel: `{"type":"ticker","symbols":["BTC_KRW","ETH_KRW"],"tickTypes":["30M"]}`},
}
testsubs.EqualLists(t, exp, subs)
}
1 change: 1 addition & 0 deletions exchanges/bithumb/bithumb_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func (b *Bithumb) SetDefaults() {
GlobalResultLimit: 1500,
},
},
Subscriptions: defaultSubscriptions.Clone(),
}
b.Requester, err = request.New(b.Name,
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout),
Expand Down
1 change: 1 addition & 0 deletions exchanges/subscription/subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var (
ErrInStateAlready = errors.New("subscription already in state")
ErrInvalidState = errors.New("invalid subscription state")
ErrDuplicate = errors.New("duplicate subscription")
ErrNotSupported = errors.New("subscription channel not supported")
)

// State tracks the status of a subscription channel
Expand Down
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/thrasher-corp/gocryptotrader
go 1.23.0

require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/buger/jsonparser v1.1.1
github.com/d5/tengo/v2 v2.17.0
github.com/gofrs/uuid v4.4.0+incompatible
Expand Down Expand Up @@ -33,14 +34,21 @@ require (
)

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/friendsofgo/errors v0.9.2 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
Expand Down
Loading

0 comments on commit 56a820f

Please sign in to comment.