From 73bccbf4ec29b67cecbc5afd833cf45b94fcc194 Mon Sep 17 00:00:00 2001 From: Gareth Kirwan Date: Thu, 28 Nov 2024 14:44:31 +0700 Subject: [PATCH] Exchanges: Rename StoreAssetPairStore Previously we were calling it "Format", but accepting everything from the PairStore. We were also defaulting to turning the Asset on. Now callers need to get their AssetEnabled set as they want it, so there's no magic This change also moves responsibility for error wrapping outside to the caller. --- cmd/exchange_template/wrapper_file.tmpl | 10 +-- docs/ADD_NEW_EXCHANGE.md | 10 +-- engine/rpcserver_test.go | 4 +- exchanges/binance/binance_wrapper.go | 86 ++++++++++-------------- exchanges/binanceus/binanceus_wrapper.go | 8 ++- exchanges/bitfinex/bitfinex_wrapper.go | 39 +++++------ exchanges/bitmex/bitmex_wrapper.go | 44 +++++------- exchanges/btse/btse_wrapper.go | 40 ++++------- exchanges/bybit/bybit_wrapper.go | 8 +-- exchanges/deribit/deribit_wrapper.go | 13 ++-- exchanges/exchange.go | 26 +++---- exchanges/exchange_test.go | 46 +++++-------- exchanges/huobi/huobi_wrapper.go | 53 +++++---------- exchanges/kraken/kraken_wrapper.go | 49 +++++--------- exchanges/kucoin/kucoin_wrapper.go | 35 +++++----- 15 files changed, 181 insertions(+), 290 deletions(-) diff --git a/cmd/exchange_template/wrapper_file.tmpl b/cmd/exchange_template/wrapper_file.tmpl index 68e1639ca31..54eb099eed8 100644 --- a/cmd/exchange_template/wrapper_file.tmpl +++ b/cmd/exchange_template/wrapper_file.tmpl @@ -55,22 +55,24 @@ func ({{.Variable}} *{{.CapitalName}}) SetDefaults() { // can use this example below: fmt1 := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true}, } fmt2 := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: ":"}, } - err = {{.Variable}}.StoreAssetPairFormat(asset.Spot, fmt1) + err = {{.Variable}}.StoreAssetPairStore(asset.Spot, fmt1) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", {{.Variable}}.Name, asset.Spot, err) } - err = {{.Variable}}.StoreAssetPairFormat(asset.Margin, fmt2) + err = {{.Variable}}.StoreAssetPairStore(asset.Margin, fmt2) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", {{.Variable}}.Name, asset.Margin, err) } // Fill out the capabilities/features that the exchange supports diff --git a/docs/ADD_NEW_EXCHANGE.md b/docs/ADD_NEW_EXCHANGE.md index 41e5712d192..f90d260f1f3 100644 --- a/docs/ADD_NEW_EXCHANGE.md +++ b/docs/ADD_NEW_EXCHANGE.md @@ -156,6 +156,7 @@ Similar to the configs, spot support is inbuilt but other asset types will need ```go spot := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{ Uppercase: true, Delimiter: "/", @@ -166,6 +167,7 @@ Similar to the configs, spot support is inbuilt but other asset types will need }, } futures := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{ Uppercase: true, Delimiter: "-", @@ -176,14 +178,14 @@ Similar to the configs, spot support is inbuilt but other asset types will need }, } - err := f.StoreAssetPairFormat(asset.Spot, spot) + err := f.StoreAssetPairStore(asset.Spot, spot) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `spot` default asset formats: %s", bi.Name, err) } - err = f.StoreAssetPairFormat(asset.Futures, futures) + err = f.StoreAssetPairStore(asset.Futures, futures) if err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error storing `futures` default asset formats: %s", bi.Name, err) } ``` diff --git a/engine/rpcserver_test.go b/engine/rpcserver_test.go index 1f687e7a6b2..9661d6a2d3e 100644 --- a/engine/rpcserver_test.go +++ b/engine/rpcserver_test.go @@ -1548,6 +1548,7 @@ func TestCheckVars(t *testing.T) { for _, a := range []asset.Item{asset.Spot, asset.Margin, asset.CoinMarginedFutures, asset.USDTMarginedFutures} { fmt := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Delimiter: currency.DashDelimiter, Uppercase: true}, } @@ -1558,8 +1559,7 @@ func TestCheckVars(t *testing.T) { case asset.USDTMarginedFutures: fmt.ConfigFormat = ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter} } - require.NoError(t, b.StoreAssetPairFormat(a, fmt), "StoreAssetPairFormat must not error") - require.NoError(t, b.CurrencyPairs.SetAssetEnabled(a, true), "SetAssetEnabled must not error") + require.NoError(t, b.StoreAssetPairStore(a, fmt), "StoreAssetPairStore must not error") } err = checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT)) diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 261ed1516ef..088b5ffca1d 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -36,6 +36,29 @@ import ( "github.com/thrasher-corp/gocryptotrader/portfolio/withdraw" ) +var defaultAssetPairStores = map[asset.Item]currency.PairStore{ + asset.Spot: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Delimiter: currency.DashDelimiter, Uppercase: true}, + }, + asset.Margin: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Delimiter: currency.DashDelimiter, Uppercase: true}, + }, + asset.CoinMarginedFutures: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + }, + asset.USDTMarginedFutures: { + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + }, +} + // SetDefaults sets the basic defaults for Binance func (b *Binance) SetDefaults() { b.Name = "Binance" @@ -45,60 +68,18 @@ func (b *Binance) SetDefaults() { b.API.CredentialsValidator.RequiresSecret = true b.SetValues() - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{ - Delimiter: currency.DashDelimiter, - Uppercase: true, - }, - } - coinFutures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - } - usdtFutures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - } - err := b.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.Margin, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.DisableAssetWebsocketSupport(asset.Margin) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.CoinMarginedFutures, coinFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.DisableAssetWebsocketSupport(asset.CoinMarginedFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.USDTMarginedFutures, usdtFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for a, ps := range defaultAssetPairStores { + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } - err = b.DisableAssetWebsocketSupport(asset.USDTMarginedFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + + for _, a := range []asset.Item{asset.Margin, asset.CoinMarginedFutures, asset.USDTMarginedFutures} { + if err := b.DisableAssetWebsocketSupport(a); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", b.Name, a, err) + } } + b.Features = exchange.Features{ Supports: exchange.FeaturesSupported{ REST: true, @@ -196,6 +177,7 @@ func (b *Binance) SetDefaults() { }, } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimits())) diff --git a/exchanges/binanceus/binanceus_wrapper.go b/exchanges/binanceus/binanceus_wrapper.go index d3992d4e73e..fe107c9281a 100644 --- a/exchanges/binanceus/binanceus_wrapper.go +++ b/exchanges/binanceus/binanceus_wrapper.go @@ -40,15 +40,15 @@ func (bi *Binanceus) SetDefaults() { bi.SetValues() fmt1 := currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{ Delimiter: currency.DashDelimiter, Uppercase: true, }, } - err := bi.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := bi.StoreAssetPairStore(asset.Spot, fmt1); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `spot` default asset formats: %s", bi.Name, err) } bi.Features = exchange.Features{ @@ -122,6 +122,8 @@ func (bi *Binanceus) SetDefaults() { }, }, } + + var err error bi.Requester, err = request.New(bi.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index 97026e7fdfc..41e3e35b869 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -41,33 +41,23 @@ func (b *Bitfinex) SetDefaults() { b.API.CredentialsValidator.RequiresKey = true b.API.CredentialsValidator.RequiresSecret = true - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, - } - - fmt2 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: ":"}, - } - - err := b.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.Margin, fmt2) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = b.StoreAssetPairFormat(asset.MarginFunding, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Margin, asset.MarginFunding} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Margin { + ps.ConfigFormat.Delimiter = ":" + } + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } // Margin WS Currently not fully implemented and causes subscription collisions with spot - err = b.DisableAssetWebsocketSupport(asset.Margin) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := b.DisableAssetWebsocketSupport(asset.Margin); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", b.Name, asset.Margin, err) } // TODO: Implement Futures and Securities asset types. @@ -162,6 +152,7 @@ func (b *Bitfinex) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index eea24d81326..3648430e884 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -42,37 +42,22 @@ func (b *Bitmex) SetDefaults() { b.API.CredentialsValidator.RequiresKey = true b.API.CredentialsValidator.RequiresSecret = true - configFmt := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter} - standardRequestFmt := ¤cy.PairFormat{Uppercase: true} - spotRequestFormat := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter} - - spot := currency.PairStore{RequestFormat: spotRequestFormat, ConfigFormat: configFmt} - err := b.StoreAssetPairFormat(asset.Spot, spot) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - perp := currency.PairStore{RequestFormat: standardRequestFmt, ConfigFormat: configFmt} - err = b.StoreAssetPairFormat(asset.PerpetualContract, perp) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - futures := currency.PairStore{RequestFormat: standardRequestFmt, ConfigFormat: configFmt} - err = b.StoreAssetPairFormat(asset.Futures, futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - index := currency.PairStore{RequestFormat: standardRequestFmt, ConfigFormat: configFmt} - err = b.StoreAssetPairFormat(asset.Index, index) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.PerpetualContract, asset.Futures, asset.Index} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Spot { + ps.RequestFormat = ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter} + } + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } - err = b.DisableAssetWebsocketSupport(asset.Index) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := b.DisableAssetWebsocketSupport(asset.Index); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", b.Name, asset.Index, err) } b.Features = exchange.Features{ @@ -139,6 +124,7 @@ func (b *Bitmex) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 3b897a4a7f9..d1598c9639e 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -45,33 +45,18 @@ func (b *BTSE) SetDefaults() { b.API.CredentialsValidator.RequiresKey = true b.API.CredentialsValidator.RequiresSecret = true - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - err := b.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - fmt2 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - err = b.StoreAssetPairFormat(asset.Futures, fmt2) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Spot { + ps.RequestFormat.Delimiter = currency.DashDelimiter + } + if err := b.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", b.Name, a, err) + } } b.Features = exchange.Features{ @@ -142,6 +127,7 @@ func (b *BTSE) SetDefaults() { }, } + var err error b.Requester, err = request.New(b.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/bybit/bybit_wrapper.go b/exchanges/bybit/bybit_wrapper.go index 662f1e900b1..9b9753c1cff 100644 --- a/exchanges/bybit/bybit_wrapper.go +++ b/exchanges/bybit/bybit_wrapper.go @@ -61,15 +61,15 @@ func (by *Bybit) SetDefaults() { by.API.CredentialsValidator.RequiresSecret = true for _, n := range assetPairFmts { - ps := currency.PairStore{RequestFormat: n.reqFmt, ConfigFormat: n.cfgFmt} - if err := by.StoreAssetPairFormat(n.asset, ps); err != nil { - log.Errorf(log.ExchangeSys, "%v %v", n.asset, err) + ps := currency.PairStore{AssetEnabled: true, RequestFormat: n.reqFmt, ConfigFormat: n.cfgFmt} + if err := by.StoreAssetPairStore(n.asset, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", by.Name, n.asset, err) } } for _, a := range []asset.Item{asset.CoinMarginedFutures, asset.USDTMarginedFutures, asset.USDCMarginedFutures, asset.Options} { if err := by.DisableAssetWebsocketSupport(a); err != nil { - log.Errorln(log.ExchangeSys, err) + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", by.Name, a, err) } } diff --git a/exchanges/deribit/deribit_wrapper.go b/exchanges/deribit/deribit_wrapper.go index 38023875caa..67be25905cf 100644 --- a/exchanges/deribit/deribit_wrapper.go +++ b/exchanges/deribit/deribit_wrapper.go @@ -65,13 +65,12 @@ func (d *Deribit) SetDefaults() { dashFormat := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter} underscoreFormat := ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter} - err := d.StoreAssetPairFormat(asset.Spot, currency.PairStore{RequestFormat: underscoreFormat, ConfigFormat: underscoreFormat}) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := d.StoreAssetPairStore(asset.Spot, currency.PairStore{AssetEnabled: true, RequestFormat: underscoreFormat, ConfigFormat: underscoreFormat}); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", d.Name, asset.Spot, err) } - for _, assetType := range []asset.Item{asset.Futures, asset.Options, asset.OptionCombo, asset.FutureCombo} { - if err = d.StoreAssetPairFormat(assetType, currency.PairStore{RequestFormat: dashFormat, ConfigFormat: dashFormat}); err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Futures, asset.Options, asset.OptionCombo, asset.FutureCombo} { + if err := d.StoreAssetPairStore(a, currency.PairStore{AssetEnabled: true, RequestFormat: dashFormat, ConfigFormat: dashFormat}); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", d.Name, a, err) } } @@ -149,6 +148,8 @@ func (d *Deribit) SetDefaults() { }, }, } + + var err error d.Requester, err = request.New(d.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimits()), diff --git a/exchanges/exchange.go b/exchanges/exchange.go index 5df91dd0891..5068deb5258 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -55,6 +55,7 @@ var ( ) var ( + errStoreAssetPairStore = errors.New("error storing asset pair store") errEndpointStringNotFound = errors.New("endpoint string not found") errConfigPairFormatRequiresDelimiter = errors.New("config pair format requires delimiter") errSetDefaultsNotCalled = errors.New("set defaults not called") @@ -990,26 +991,18 @@ func (b *Base) EnableRateLimiter() error { return b.Requester.EnableRateLimiter() } -// StoreAssetPairFormat initialises and stores a defined asset format -func (b *Base) StoreAssetPairFormat(a asset.Item, f currency.PairStore) error { +// StoreAssetPairStore initialises and stores a defined asset format +func (b *Base) StoreAssetPairStore(a asset.Item, f currency.PairStore) error { if a.String() == "" { - return fmt.Errorf("%s cannot add to pairs manager, no asset provided", - b.Name) - } - - if f.RequestFormat == nil { - return fmt.Errorf("%s cannot add to pairs manager, request pair format not provided", - b.Name) + return asset.ErrInvalidAsset } - if f.ConfigFormat == nil { - return fmt.Errorf("%s cannot add to pairs manager, config pair format not provided", - b.Name) + if f.RequestFormat == nil || f.ConfigFormat == nil { + return currency.ErrPairFormatIsNil } if f.ConfigFormat.Delimiter == "" { - return fmt.Errorf("exchange %s cannot set asset %s pair format %w", - b.Name, a, errConfigPairFormatRequiresDelimiter) + return errConfigPairFormatRequiresDelimiter } if b.CurrencyPairs.Pairs == nil { @@ -1017,6 +1010,7 @@ func (b *Base) StoreAssetPairFormat(a asset.Item, f currency.PairStore) error { } b.CurrencyPairs.Pairs[a] = &f + return nil } @@ -1453,9 +1447,7 @@ func getURLTypeFromString(ep string) (URL, error) { // check availability of asset type. func (b *Base) DisableAssetWebsocketSupport(aType asset.Item) error { if !b.SupportsAsset(aType) { - return fmt.Errorf("%s %w", - aType, - asset.ErrNotSupported) + return fmt.Errorf("%s %w", aType, asset.ErrNotSupported) } b.AssetWebsocketSupport.m.Lock() if b.AssetWebsocketSupport.unsupported == nil { diff --git a/exchanges/exchange_test.go b/exchanges/exchange_test.go index e555ca22098..b5e958b4b7e 100644 --- a/exchanges/exchange_test.go +++ b/exchanges/exchange_test.go @@ -1396,47 +1396,37 @@ func TestGetFormattedPairAndAssetType(t *testing.T) { } } -func TestStoreAssetPairFormat(t *testing.T) { +func TestStoreAssetPairStore(t *testing.T) { b := Base{ Config: &config.Exchange{Name: "kitties"}, } - err := b.StoreAssetPairFormat(asset.Empty, currency.PairStore{}) - if err == nil { - t.Error("error cannot be nil") - } + err := b.StoreAssetPairStore(asset.Empty, currency.PairStore{}) + assert.ErrorIs(t, err, asset.ErrInvalidAsset) - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{}) - if err == nil { - t.Error("error cannot be nil") - } + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{}) + assert.ErrorIs(t, err, currency.ErrPairFormatIsNil) - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}}) - if err == nil { - t.Error("error cannot be nil") - } + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{RequestFormat: ¤cy.PairFormat{Uppercase: true}}) + assert.ErrorIs(t, err, currency.ErrPairFormatIsNil) - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{ RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true}}) - if !errors.Is(err, errConfigPairFormatRequiresDelimiter) { - t.Fatalf("received: '%v' but expected: '%v'", err, errConfigPairFormatRequiresDelimiter) - } + assert.ErrorIs(t, err, errConfigPairFormatRequiresDelimiter) - err = b.StoreAssetPairFormat(asset.Futures, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Futures, currency.PairStore{ RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) + assert.False(t, b.CurrencyPairs.Pairs[asset.Futures].AssetEnabled, "StoreAssetPairStore should not magically enable AssetTypes") - err = b.StoreAssetPairFormat(asset.Futures, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Futures, currency.PairStore{ + AssetEnabled: true, RequestFormat: ¤cy.PairFormat{Uppercase: true}, ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}}) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) + assert.True(t, b.CurrencyPairs.Pairs[asset.Futures].AssetEnabled, "AssetEnabled should be respected") } func TestSetGlobalPairsManager(t *testing.T) { @@ -1796,7 +1786,7 @@ func TestFormatSymbol(t *testing.T) { Uppercase: true, }, } - err := b.StoreAssetPairFormat(asset.Spot, spotStore) + err := b.StoreAssetPairStore(asset.Spot, spotStore) if err != nil { t.Error(err) } @@ -1908,7 +1898,7 @@ func TestAssetWebsocketFunctionality(t *testing.T) { t.Fatalf("expected error: %v but received: %v", asset.ErrNotSupported, err) } - err = b.StoreAssetPairFormat(asset.Spot, currency.PairStore{ + err = b.StoreAssetPairStore(asset.Spot, currency.PairStore{ RequestFormat: ¤cy.PairFormat{ Uppercase: true, }, diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index f0deb80ad87..2fbd6f486bc 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -41,43 +41,21 @@ func (h *HUOBI) SetDefaults() { h.API.CredentialsValidator.RequiresKey = true h.API.CredentialsValidator.RequiresSecret = true - fmt1 := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: false}, - ConfigFormat: ¤cy.PairFormat{ - Delimiter: currency.DashDelimiter, - Uppercase: true, - }, - } - coinFutures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - futuresFormatting := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.DashDelimiter, - }, - } - err := h.StoreAssetPairFormat(asset.Spot, fmt1) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = h.StoreAssetPairFormat(asset.CoinMarginedFutures, coinFutures) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = h.StoreAssetPairFormat(asset.Futures, futuresFormatting) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.CoinMarginedFutures, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + switch a { + case asset.Spot: + ps.RequestFormat.Uppercase = false + case asset.CoinMarginedFutures: + ps.RequestFormat.Delimiter = currency.DashDelimiter + } + if err := h.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", h.Name, a, err) + } } h.Features = exchange.Features{ @@ -164,6 +142,7 @@ func (h *HUOBI) SetDefaults() { }, } + var err error h.Requester, err = request.New(h.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit())) diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 610350c27f8..8bcfdc14d23 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -43,42 +43,22 @@ func (k *Kraken) SetDefaults() { k.API.CredentialsValidator.RequiresSecret = true k.API.CredentialsValidator.RequiresBase64DecodeSecret = true - pairStore := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Uppercase: true, - Separator: ",", - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - Separator: ",", - }, - } - - futures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{ - Delimiter: currency.UnderscoreDelimiter, - Uppercase: true, - }, - ConfigFormat: ¤cy.PairFormat{ - Uppercase: true, - Delimiter: currency.UnderscoreDelimiter, - }, - } - - err := k.StoreAssetPairFormat(asset.Spot, pairStore) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - err = k.StoreAssetPairFormat(asset.Futures, futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, + } + if a == asset.Futures { + ps.RequestFormat.Delimiter = currency.UnderscoreDelimiter + } + if err := k.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", k.Name, a, err) + } } - err = k.DisableAssetWebsocketSupport(asset.Futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + if err := k.DisableAssetWebsocketSupport(asset.Futures); err != nil { + log.Errorf(log.ExchangeSys, "%s error disabling `%s` asset type websocket support: %s", k.Name, asset.Futures, err) } k.Features = exchange.Features{ @@ -171,6 +151,7 @@ func (k *Kraken) SetDefaults() { Subscriptions: defaultSubscriptions.Clone(), } + var err error k.Requester, err = request.New(k.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(request.NewBasicRateLimit(krakenRateInterval, krakenRequestRate, 1))) diff --git a/exchanges/kucoin/kucoin_wrapper.go b/exchanges/kucoin/kucoin_wrapper.go index 12a2bc42216..d8c1d2a2978 100644 --- a/exchanges/kucoin/kucoin_wrapper.go +++ b/exchanges/kucoin/kucoin_wrapper.go @@ -44,26 +44,21 @@ func (ku *Kucoin) SetDefaults() { ku.API.CredentialsValidator.RequiresSecret = true ku.API.CredentialsValidator.RequiresClientID = true - spot := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, - } - futures := currency.PairStore{ - RequestFormat: ¤cy.PairFormat{Uppercase: true}, - ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.UnderscoreDelimiter}, - } - err := ku.StoreAssetPairFormat(asset.Spot, spot) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = ku.StoreAssetPairFormat(asset.Margin, spot) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - err = ku.StoreAssetPairFormat(asset.Futures, futures) - if err != nil { - log.Errorln(log.ExchangeSys, err) + for _, a := range []asset.Item{asset.Spot, asset.Margin, asset.Futures} { + ps := currency.PairStore{ + AssetEnabled: true, + RequestFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: currency.DashDelimiter}, + } + if a == asset.Futures { + ps.RequestFormat.Delimiter = "" + ps.ConfigFormat.Delimiter = currency.UnderscoreDelimiter + } + if err := ku.StoreAssetPairStore(a, ps); err != nil { + log.Errorf(log.ExchangeSys, "%s error storing `%s` default asset formats: %s", ku.Name, a, err) + } } + ku.Features = exchange.Features{ CurrencyTranslations: currency.NewTranslations(map[currency.Code]currency.Code{ currency.XBT: currency.BTC, @@ -151,6 +146,8 @@ func (ku *Kucoin) SetDefaults() { }, Subscriptions: defaultSubscriptions.Clone(), } + + var err error ku.Requester, err = request.New(ku.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout), request.WithLimiter(GetRateLimit()))