From 4c928b496dd3a5d6bc34b6681537869bd02a36e6 Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Wed, 4 Oct 2023 12:56:35 +1100 Subject: [PATCH] engine: Adds new helper functions for default exchange deployment (#1243) * engine: changes (cherry_pick_me_pls_ser) * engine/helpers: refactor * glorious nits: purge code * engine/helpers: update tests so that we can ensure a default exchange and setup is good to go. * -_- * glorious: nits --------- Co-authored-by: Ryan O'Hara-Reid --- engine/exchange_manager.go | 102 +++------------------------------- engine/helpers.go | 110 +++++++++++++++++++++++++++++++++++++ engine/helpers_test.go | 61 ++++++++++++++++++++ 3 files changed, 180 insertions(+), 93 deletions(-) diff --git a/engine/exchange_manager.go b/engine/exchange_manager.go index fb5f66bd..2d3cfca3 100644 --- a/engine/exchange_manager.go +++ b/engine/exchange_manager.go @@ -8,33 +8,6 @@ import ( "time" exchange "github.com/thrasher-corp/gocryptotrader/exchanges" - "github.com/thrasher-corp/gocryptotrader/exchanges/binance" - "github.com/thrasher-corp/gocryptotrader/exchanges/binanceus" - "github.com/thrasher-corp/gocryptotrader/exchanges/bitfinex" - "github.com/thrasher-corp/gocryptotrader/exchanges/bitflyer" - "github.com/thrasher-corp/gocryptotrader/exchanges/bithumb" - "github.com/thrasher-corp/gocryptotrader/exchanges/bitmex" - "github.com/thrasher-corp/gocryptotrader/exchanges/bitstamp" - "github.com/thrasher-corp/gocryptotrader/exchanges/bittrex" - "github.com/thrasher-corp/gocryptotrader/exchanges/btcmarkets" - "github.com/thrasher-corp/gocryptotrader/exchanges/btse" - "github.com/thrasher-corp/gocryptotrader/exchanges/bybit" - "github.com/thrasher-corp/gocryptotrader/exchanges/coinbasepro" - "github.com/thrasher-corp/gocryptotrader/exchanges/coinut" - "github.com/thrasher-corp/gocryptotrader/exchanges/exmo" - "github.com/thrasher-corp/gocryptotrader/exchanges/gateio" - "github.com/thrasher-corp/gocryptotrader/exchanges/gemini" - "github.com/thrasher-corp/gocryptotrader/exchanges/hitbtc" - "github.com/thrasher-corp/gocryptotrader/exchanges/huobi" - "github.com/thrasher-corp/gocryptotrader/exchanges/itbit" - "github.com/thrasher-corp/gocryptotrader/exchanges/kraken" - "github.com/thrasher-corp/gocryptotrader/exchanges/kucoin" - "github.com/thrasher-corp/gocryptotrader/exchanges/lbank" - "github.com/thrasher-corp/gocryptotrader/exchanges/okcoin" - "github.com/thrasher-corp/gocryptotrader/exchanges/okx" - "github.com/thrasher-corp/gocryptotrader/exchanges/poloniex" - "github.com/thrasher-corp/gocryptotrader/exchanges/yobit" - "github.com/thrasher-corp/gocryptotrader/exchanges/zb" "github.com/thrasher-corp/gocryptotrader/log" ) @@ -148,76 +121,19 @@ func (m *ExchangeManager) GetExchangeByName(exchangeName string) (exchange.IBotE func (m *ExchangeManager) NewExchangeByName(name string) (exchange.IBotExchange, error) { nameLower := strings.ToLower(name) _, err := m.GetExchangeByName(nameLower) - if err != nil && !errors.Is(err, ErrExchangeNotFound) { - return nil, fmt.Errorf("exchange manager: %s %w", name, err) - } - if err == nil { + if err != nil { + if !errors.Is(err, ErrExchangeNotFound) { + return nil, fmt.Errorf("exchange manager: %s %w", name, err) + } + } else { return nil, fmt.Errorf("exchange manager: %s %w", name, ErrExchangeAlreadyLoaded) } - var exch exchange.IBotExchange - switch nameLower { - case "binanceus": - exch = new(binanceus.Binanceus) - case "binance": - exch = new(binance.Binance) - case "bitfinex": - exch = new(bitfinex.Bitfinex) - case "bitflyer": - exch = new(bitflyer.Bitflyer) - case "bithumb": - exch = new(bithumb.Bithumb) - case "bitmex": - exch = new(bitmex.Bitmex) - case "bitstamp": - exch = new(bitstamp.Bitstamp) - case "bittrex": - exch = new(bittrex.Bittrex) - case "btc markets": - exch = new(btcmarkets.BTCMarkets) - case "btse": - exch = new(btse.BTSE) - case "bybit": - exch = new(bybit.Bybit) - case "coinut": - exch = new(coinut.COINUT) - case "exmo": - exch = new(exmo.EXMO) - case "coinbasepro": - exch = new(coinbasepro.CoinbasePro) - case "gateio": - exch = new(gateio.Gateio) - case "gemini": - exch = new(gemini.Gemini) - case "hitbtc": - exch = new(hitbtc.HitBTC) - case "huobi": - exch = new(huobi.HUOBI) - case "itbit": - exch = new(itbit.ItBit) - case "kraken": - exch = new(kraken.Kraken) - case "kucoin": - exch = new(kucoin.Kucoin) - case "lbank": - exch = new(lbank.Lbank) - case "okcoin": - exch = new(okcoin.Okcoin) - case "okx": - exch = new(okx.Okx) - case "poloniex": - exch = new(poloniex.Poloniex) - case "yobit": - exch = new(yobit.Yobit) - case "zb": - exch = new(zb.ZB) - default: - if m.Builder != nil { - return m.Builder.NewExchangeByName(nameLower) - } - return nil, fmt.Errorf("exchange manager: %s, %w", nameLower, ErrExchangeNotFound) + if m.Builder != nil { + return m.Builder.NewExchangeByName(nameLower) } - return exch, nil + + return NewSupportedExchangeByName(nameLower) } // Shutdown shuts down all exchanges and unloads them diff --git a/engine/helpers.go b/engine/helpers.go index 84f9e60d..6634b83d 100644 --- a/engine/helpers.go +++ b/engine/helpers.go @@ -27,10 +27,37 @@ import ( exchange "github.com/thrasher-corp/gocryptotrader/exchanges" "github.com/thrasher-corp/gocryptotrader/exchanges/account" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" + "github.com/thrasher-corp/gocryptotrader/exchanges/binance" + "github.com/thrasher-corp/gocryptotrader/exchanges/binanceus" + "github.com/thrasher-corp/gocryptotrader/exchanges/bitfinex" + "github.com/thrasher-corp/gocryptotrader/exchanges/bitflyer" + "github.com/thrasher-corp/gocryptotrader/exchanges/bithumb" + "github.com/thrasher-corp/gocryptotrader/exchanges/bitmex" + "github.com/thrasher-corp/gocryptotrader/exchanges/bitstamp" + "github.com/thrasher-corp/gocryptotrader/exchanges/bittrex" + "github.com/thrasher-corp/gocryptotrader/exchanges/btcmarkets" + "github.com/thrasher-corp/gocryptotrader/exchanges/btse" + "github.com/thrasher-corp/gocryptotrader/exchanges/bybit" + "github.com/thrasher-corp/gocryptotrader/exchanges/coinbasepro" + "github.com/thrasher-corp/gocryptotrader/exchanges/coinut" "github.com/thrasher-corp/gocryptotrader/exchanges/deposit" + "github.com/thrasher-corp/gocryptotrader/exchanges/exmo" + "github.com/thrasher-corp/gocryptotrader/exchanges/gateio" + "github.com/thrasher-corp/gocryptotrader/exchanges/gemini" + "github.com/thrasher-corp/gocryptotrader/exchanges/hitbtc" + "github.com/thrasher-corp/gocryptotrader/exchanges/huobi" + "github.com/thrasher-corp/gocryptotrader/exchanges/itbit" + "github.com/thrasher-corp/gocryptotrader/exchanges/kraken" + "github.com/thrasher-corp/gocryptotrader/exchanges/kucoin" + "github.com/thrasher-corp/gocryptotrader/exchanges/lbank" + "github.com/thrasher-corp/gocryptotrader/exchanges/okcoin" + "github.com/thrasher-corp/gocryptotrader/exchanges/okx" "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook" + "github.com/thrasher-corp/gocryptotrader/exchanges/poloniex" "github.com/thrasher-corp/gocryptotrader/exchanges/stats" "github.com/thrasher-corp/gocryptotrader/exchanges/ticker" + "github.com/thrasher-corp/gocryptotrader/exchanges/yobit" + "github.com/thrasher-corp/gocryptotrader/exchanges/zb" "github.com/thrasher-corp/gocryptotrader/gctscript/vm" "github.com/thrasher-corp/gocryptotrader/log" ) @@ -963,3 +990,86 @@ func genCert(targetDir string) error { log.Infof(log.Global, "gRPC TLS key.pem and cert.pem files written to %s\n", targetDir) return nil } + +// NewSupportedExchangeByName helps create a new exchange to be loaded that is +// supported by GCT. This function will return an error if the exchange is not +// supported. +func NewSupportedExchangeByName(name string) (exchange.IBotExchange, error) { + switch strings.ToLower(name) { + case "binanceus": + return new(binanceus.Binanceus), nil + case "binance": + return new(binance.Binance), nil + case "bitfinex": + return new(bitfinex.Bitfinex), nil + case "bitflyer": + return new(bitflyer.Bitflyer), nil + case "bithumb": + return new(bithumb.Bithumb), nil + case "bitmex": + return new(bitmex.Bitmex), nil + case "bitstamp": + return new(bitstamp.Bitstamp), nil + case "bittrex": + return new(bittrex.Bittrex), nil + case "btc markets": + return new(btcmarkets.BTCMarkets), nil + case "btse": + return new(btse.BTSE), nil + case "bybit": + return new(bybit.Bybit), nil + case "coinut": + return new(coinut.COINUT), nil + case "exmo": + return new(exmo.EXMO), nil + case "coinbasepro": + return new(coinbasepro.CoinbasePro), nil + case "gateio": + return new(gateio.Gateio), nil + case "gemini": + return new(gemini.Gemini), nil + case "hitbtc": + return new(hitbtc.HitBTC), nil + case "huobi": + return new(huobi.HUOBI), nil + case "itbit": + return new(itbit.ItBit), nil + case "kraken": + return new(kraken.Kraken), nil + case "kucoin": + return new(kucoin.Kucoin), nil + case "lbank": + return new(lbank.Lbank), nil + case "okcoin": + return new(okcoin.Okcoin), nil + case "okx": + return new(okx.Okx), nil + case "poloniex": + return new(poloniex.Poloniex), nil + case "yobit": + return new(yobit.Yobit), nil + case "zb": + return new(zb.ZB), nil + default: + return nil, fmt.Errorf("'%s', %w", name, ErrExchangeNotFound) + } +} + +// NewExchangeByNameWithDefaults returns a defaulted exchange by its name if it +// exists. This will allocate a new exchange and setup the default config for it. +// This will automatically fetch available pairs. +func NewExchangeByNameWithDefaults(ctx context.Context, name string) (exchange.IBotExchange, error) { + exch, err := NewSupportedExchangeByName(name) + if err != nil { + return nil, err + } + defaultConfig, err := exch.GetDefaultConfig(ctx) + if err != nil { + return nil, err + } + err = exch.Setup(defaultConfig) + if err != nil { + return nil, err + } + return exch, nil +} diff --git a/engine/helpers_test.go b/engine/helpers_test.go index d5511ee9..590214bc 100644 --- a/engine/helpers_test.go +++ b/engine/helpers_test.go @@ -9,10 +9,13 @@ import ( "crypto/x509/pkix" "encoding/pem" "errors" + "fmt" "math/big" "net" "os" "path/filepath" + "strings" + "sync" "testing" "time" @@ -1347,3 +1350,61 @@ func TestCheckAndGenCerts(t *testing.T) { t.Fatal(err) } } + +func TestNewSupportedExchangeByName(t *testing.T) { + t.Parallel() + + for x := range exchange.Exchanges { + exch, err := NewSupportedExchangeByName(exchange.Exchanges[x]) + if err != nil { + t.Fatal(err) + } + + if exch == nil { + t.Fatalf("received nil exchange") + } + } + + _, err := NewSupportedExchangeByName("") + if !errors.Is(err, ErrExchangeNotFound) { + t.Fatalf("received: '%v' but expected: '%v'", err, ErrExchangeNotFound) + } +} + +func TestNewExchangeByNameWithDefaults(t *testing.T) { + t.Parallel() + + _, err := NewExchangeByNameWithDefaults(context.Background(), "meow") + if !errors.Is(err, ErrExchangeNotFound) { + t.Fatalf("received: '%v' but expected: '%v'", err, ErrExchangeNotFound) + } + + ch := make(chan error, len(exchange.Exchanges)) + wg := sync.WaitGroup{} + for x := range exchange.Exchanges { + wg.Add(1) + go func(x int) { + defer wg.Done() + exch, err := NewExchangeByNameWithDefaults(context.Background(), exchange.Exchanges[x]) + if err != nil { + ch <- err + return + } + + if !strings.EqualFold(exch.GetName(), exchange.Exchanges[x]) { + ch <- fmt.Errorf("received: '%v' but expected: '%v'", exch.GetName(), exchange.Exchanges[x]) + } + }(x) + } + wg.Wait() + +outta: + for { + select { + case err := <-ch: + t.Error(err) + default: + break outta + } + } +}