diff --git a/cmd/exchange_template/wrapper_file.tmpl b/cmd/exchange_template/wrapper_file.tmpl index 3175dee9..83143d71 100644 --- a/cmd/exchange_template/wrapper_file.tmpl +++ b/cmd/exchange_template/wrapper_file.tmpl @@ -2,8 +2,9 @@ package {{.Name}} import ( - "sync" "context" + "fmt" + "sync" "time" "github.com/thrasher-corp/gocryptotrader/common" @@ -129,12 +130,18 @@ func ({{.Variable}} *{{.CapitalName}}) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func ({{.Variable}} *{{.CapitalName}}) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { {{.Variable}}.SetEnabled(false) return nil } - - {{.Variable}}.SetupDefaults(exch) + err = {{.Variable}}.SetupDefaults(exch) + if err != nil { + return err + } /* wsRunningEndpoint, err := {{.Variable}}.API.Endpoints.GetURL(exchange.WebsocketSpot) @@ -171,12 +178,16 @@ func ({{.Variable}} *{{.CapitalName}}) Setup(exch *config.Exchange) error { } // Start starts the {{.CapitalName}} go routine -func ({{.Variable}} *{{.CapitalName}}) Start(wg *sync.WaitGroup) { +func ({{.Variable}} *{{.CapitalName}}) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { {{.Variable}}.Run() wg.Done() }() + return nil } // Run implements the {{.CapitalName}} wrapper diff --git a/cmd/exchange_wrapper_coverage/main.go b/cmd/exchange_wrapper_coverage/main.go index 9d339b25..166b0b43 100644 --- a/cmd/exchange_wrapper_coverage/main.go +++ b/cmd/exchange_wrapper_coverage/main.go @@ -1,23 +1,15 @@ package main import ( - "context" "errors" + "fmt" "log" - "math/rand" + "reflect" "sync" - "time" "github.com/thrasher-corp/gocryptotrader/common" - "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/engine" exchange "github.com/thrasher-corp/gocryptotrader/exchanges" - "github.com/thrasher-corp/gocryptotrader/exchanges/asset" - "github.com/thrasher-corp/gocryptotrader/exchanges/kline" -) - -const ( - totalWrappers = 25 ) func main() { @@ -29,12 +21,16 @@ func main() { engine.Bot.Settings = engine.Settings{ DisableExchangeAutoPairUpdates: true, + EnableDryRun: true, } + engine.Bot.Config.PurgeExchangeAPICredentials() + engine.Bot.ExchangeManager = engine.SetupExchangeManager() + log.Printf("Loading exchanges..") var wg sync.WaitGroup for x := range exchange.Exchanges { - err := engine.Bot.LoadExchange(exchange.Exchanges[x], &wg) + err = engine.Bot.LoadExchange(exchange.Exchanges[x], &wg) if err != nil { log.Printf("Failed to load exchange %s. Err: %s", exchange.Exchanges[x], @@ -53,17 +49,28 @@ func main() { exch := exchanges[x] wg.Add(1) go func(e exchange.IBotExchange) { - results[e.GetName()] = testWrappers(e) + results[e.GetName()], err = testWrappers(e) + if err != nil { + fmt.Printf("failed to test wrappers for %s %s", e.GetName(), err) + } wg.Done() }(exch) } wg.Wait() log.Println("Done.") + var dummyInterface exchange.IBotExchange + totalWrappers := reflect.TypeOf(&dummyInterface).Elem().NumMethod() + log.Println() for name, funcs := range results { pct := float64(totalWrappers-len(funcs)) / float64(totalWrappers) * 100 - log.Printf("Exchange %s wrapper coverage [%d/%d - %.2f%%] | Total missing: %d", name, totalWrappers-len(funcs), totalWrappers, pct, len(funcs)) + log.Printf("Exchange %s wrapper coverage [%d/%d - %.2f%%] | Total missing: %d", + name, + totalWrappers-len(funcs), + totalWrappers, + pct, + len(funcs)) log.Printf("\t Wrappers not implemented:") for x := range funcs { @@ -73,149 +80,39 @@ func main() { } } -func testWrappers(e exchange.IBotExchange) []string { - p := currency.NewPair(currency.BTC, currency.USD) - assetType := asset.Spot - if !e.SupportsAsset(assetType) { - assets := e.GetAssetTypes(false) - rand.Seed(time.Now().Unix()) - assetType = assets[rand.Intn(len(assets))] // nolint:gosec // basic number generation required, no need for crypo/rand - } +// testWrappers executes and checks each IBotExchange's function return for the +// error common.ErrNotYetImplemented to verify whether the wrapper function has +// been implemented yet. +func testWrappers(e exchange.IBotExchange) ([]string, error) { + iExchange := reflect.TypeOf(&e).Elem() + actualExchange := reflect.ValueOf(e) + errType := reflect.TypeOf(common.ErrNotYetImplemented) var funcs []string + for x := 0; x < iExchange.NumMethod(); x++ { + name := iExchange.Method(x).Name + method := actualExchange.MethodByName(name) + inputs := make([]reflect.Value, method.Type().NumIn()) + for y := 0; y < method.Type().NumIn(); y++ { + input := method.Type().In(y) + inputs[y] = reflect.Zero(input) + } - _, err := e.FetchTicker(context.TODO(), p, assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "FetchTicker") + outputs := method.Call(inputs) + for y := range outputs { + incoming := outputs[y].Interface() + if reflect.TypeOf(incoming) == errType { + err, ok := incoming.(error) + if !ok { + return nil, fmt.Errorf("%s type assertion failure for %v", name, incoming) + } + if errors.Is(err, common.ErrNotYetImplemented) { + funcs = append(funcs, name) + } + // found error; there should not be another error in this slice. + break + } + } } - - _, err = e.UpdateTicker(context.TODO(), p, assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "UpdateTicker") - } - - _, err = e.FetchOrderbook(context.TODO(), p, assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "FetchOrderbook") - } - - _, err = e.UpdateOrderbook(context.TODO(), p, assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "UpdateOrderbook") - } - - _, err = e.FetchTradablePairs(context.TODO(), asset.Spot) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "FetchTradablePairs") - } - - err = e.UpdateTradablePairs(context.TODO(), false) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "UpdateTradablePairs") - } - - _, err = e.FetchAccountInfo(context.TODO(), assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetAccountInfo") - } - - _, err = e.GetRecentTrades(context.TODO(), p, assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetRecentTrades") - } - - _, err = e.GetHistoricTrades(context.TODO(), p, assetType, time.Time{}, time.Time{}) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetHistoricTrades") - } - - _, err = e.GetFundingHistory(context.TODO()) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetFundingHistory") - } - - _, err = e.SubmitOrder(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "SubmitOrder") - } - - _, err = e.ModifyOrder(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "ModifyOrder") - } - - err = e.CancelOrder(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "CancelOrder") - } - - _, err = e.CancelBatchOrders(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "CancelBatchOrders") - } - - _, err = e.CancelAllOrders(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "CancelAllOrders") - } - - _, err = e.GetOrderInfo(context.TODO(), "1", p, assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetOrderInfo") - } - - _, err = e.GetOrderHistory(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetOrderHistory") - } - - _, err = e.GetActiveOrders(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetActiveOrders") - } - - _, err = e.GetDepositAddress(context.TODO(), currency.BTC, "", "") - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetDepositAddress") - } - - _, err = e.WithdrawCryptocurrencyFunds(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "WithdrawCryptocurrencyFunds") - } - - _, err = e.WithdrawFiatFunds(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "WithdrawFiatFunds") - } - _, err = e.WithdrawFiatFundsToInternationalBank(context.TODO(), nil) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "WithdrawFiatFundsToInternationalBank") - } - - _, err = e.GetHistoricCandles(context.TODO(), currency.Pair{}, asset.Spot, time.Unix(0, 0), time.Unix(0, 0), kline.OneDay) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetHistoricCandles") - } - - _, err = e.GetHistoricCandlesExtended(context.TODO(), currency.Pair{}, asset.Spot, time.Unix(0, 0), time.Unix(0, 0), kline.OneDay) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetHistoricCandlesExtended") - } - - _, err = e.UpdateAccountInfo(context.TODO(), assetType) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "UpdateAccountInfo") - } - - _, err = e.GetFeeByType(context.TODO(), &exchange.FeeBuilder{}) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "GetFeeByType") - } - - err = e.UpdateOrderExecutionLimits(context.TODO(), asset.DownsideProfitContract) - if errors.Is(err, common.ErrNotYetImplemented) { - funcs = append(funcs, "UpdateOrderExecutionLimits") - } - return funcs + return funcs, nil } diff --git a/common/common.go b/common/common.go index 0b30df09..252d7665 100644 --- a/common/common.go +++ b/common/common.go @@ -50,7 +50,9 @@ var ( // ErrStartEqualsEnd is an error for start end check calculations ErrStartEqualsEnd = errors.New("start date equals end date") // ErrStartAfterTimeNow is an error for start end check calculations - ErrStartAfterTimeNow = errors.New("start date is after current time") + ErrStartAfterTimeNow = errors.New("start date is after current time") + // ErrNilPointer defines an error for a nil pointer + ErrNilPointer = errors.New("nil pointer") errCannotSetInvalidTimeout = errors.New("cannot set new HTTP client with timeout that is equal or less than 0") errUserAgentInvalid = errors.New("cannot set invalid user agent") errHTTPClientInvalid = errors.New("custom http client cannot be nil") diff --git a/config/config.go b/config/config.go index 035f0bdb..b7d0ba53 100644 --- a/config/config.go +++ b/config/config.go @@ -29,6 +29,9 @@ import ( "github.com/thrasher-corp/gocryptotrader/portfolio/banking" ) +// errExchangeConfigIsNil defines an error when the config is nil +var errExchangeConfigIsNil = errors.New("exchange config is nil") + // GetCurrencyConfig returns currency configurations func (c *Config) GetCurrencyConfig() CurrencyConfig { return c.Currency @@ -1893,3 +1896,11 @@ func (c *Config) GetDataPath(elem ...string) string { } return filepath.Join(append([]string{baseDir}, elem...)...) } + +// Validate checks if exchange config is valid +func (c *Exchange) Validate() error { + if c == nil { + return errExchangeConfigIsNil + } + return nil +} diff --git a/config/config_test.go b/config/config_test.go index 8e3b2f2f..52e71002 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -2358,3 +2358,15 @@ func TestMigrateConfig(t *testing.T) { }) } } + +func TestExchangeConfigValidate(t *testing.T) { + err := (*Exchange)(nil).Validate() + if !errors.Is(err, errExchangeConfigIsNil) { + t.Fatalf("received: '%v' but expected: '%v'", err, errExchangeConfigIsNil) + } + + err = (&Exchange{}).Validate() + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } +} diff --git a/docs/ADD_NEW_EXCHANGE.md b/docs/ADD_NEW_EXCHANGE.md index 410ac451..297877a6 100644 --- a/docs/ADD_NEW_EXCHANGE.md +++ b/docs/ADD_NEW_EXCHANGE.md @@ -1096,12 +1096,15 @@ Add websocket functionality if supported to Setup: ```go // Setup takes in the supplied exchange configuration details and sets params func (f *FTX) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { f.SetEnabled(false) return nil } - - err := f.SetupDefaults(exch) + err = f.SetupDefaults(exch) if err != nil { return err } diff --git a/engine/database_connection.go b/engine/database_connection.go index e11eaaeb..0316ec8b 100644 --- a/engine/database_connection.go +++ b/engine/database_connection.go @@ -6,6 +6,7 @@ import ( "sync/atomic" "time" + "github.com/thrasher-corp/gocryptotrader/common" "github.com/thrasher-corp/gocryptotrader/database" dbpsql "github.com/thrasher-corp/gocryptotrader/database/drivers/postgres" dbsqlite3 "github.com/thrasher-corp/gocryptotrader/database/drivers/sqlite3" @@ -68,6 +69,9 @@ func (m *DatabaseConnectionManager) IsConnected() bool { // Start sets up the database connection manager to maintain a SQL connection func (m *DatabaseConnectionManager) Start(wg *sync.WaitGroup) (err error) { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } if m == nil { return fmt.Errorf("%s %w", DatabaseConnectionManagerName, ErrNilSubsystem) } diff --git a/engine/engine.go b/engine/engine.go index 7beb8b11..d429645b 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -861,13 +861,15 @@ func (bot *Engine) LoadExchange(name string, wg *sync.WaitGroup) error { } if wg != nil { - exch.Start(wg) - } else { - tempWG := sync.WaitGroup{} - exch.Start(&tempWG) - tempWG.Wait() + return exch.Start(wg) } + tempWG := sync.WaitGroup{} + err = exch.Start(&tempWG) + if err != nil { + return err + } + tempWG.Wait() return nil } diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index d2832255..af70bf57 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -48,6 +48,20 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestUServerTime(t *testing.T) { t.Parallel() _, err := b.UServerTime(context.Background()) diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 2ba72721..daa0820c 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -209,11 +209,15 @@ func (b *Binance) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (b *Binance) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { + b.SetEnabled(false) return nil } - - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } @@ -246,12 +250,16 @@ func (b *Binance) Setup(exch *config.Exchange) error { } // Start starts the Binance go routine -func (b *Binance) Start(wg *sync.WaitGroup) { +func (b *Binance) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the Binance wrapper @@ -1292,6 +1300,9 @@ func (b *Binance) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *wit // GetFeeByType returns an estimate of fee based on type of transaction func (b *Binance) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if (!b.AllowAuthenticatedRequest() || b.SkipAuthCheck) && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/bitfinex/bitfinex_test.go b/exchanges/bitfinex/bitfinex_test.go index 43177c8e..6737dee7 100644 --- a/exchanges/bitfinex/bitfinex_test.go +++ b/exchanges/bitfinex/bitfinex_test.go @@ -2,13 +2,16 @@ package bitfinex import ( "context" + "errors" "log" "net/http" "os" + "sync" "testing" "time" "github.com/gorilla/websocket" + "github.com/thrasher-corp/gocryptotrader/common" "github.com/thrasher-corp/gocryptotrader/config" "github.com/thrasher-corp/gocryptotrader/core" "github.com/thrasher-corp/gocryptotrader/currency" @@ -62,6 +65,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetV2MarginFunding(t *testing.T) { if !areTestAPIKeysSet() { t.Skip("api keys are not set or invalid") diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index 62b36480..1424d6e8 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -184,15 +184,19 @@ func (b *Bitfinex) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (b *Bitfinex) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil } - - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } + wsEndpoint, err := b.API.Endpoints.GetURL(exchange.WebsocketSpot) if err != nil { return err @@ -231,12 +235,16 @@ func (b *Bitfinex) Setup(exch *config.Exchange) error { } // Start starts the Bitfinex go routine -func (b *Bitfinex) Start(wg *sync.WaitGroup) { +func (b *Bitfinex) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the Bitfinex wrapper @@ -854,6 +862,9 @@ func (b *Bitfinex) WithdrawFiatFundsToInternationalBank(ctx context.Context, wit // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bitfinex) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !b.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/bitflyer/bitflyer_test.go b/exchanges/bitflyer/bitflyer_test.go index b23504ff..5fb03824 100644 --- a/exchanges/bitflyer/bitflyer_test.go +++ b/exchanges/bitflyer/bitflyer_test.go @@ -2,8 +2,10 @@ package bitflyer import ( "context" + "errors" "log" "os" + "sync" "testing" "time" @@ -49,6 +51,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetLatestBlockCA(t *testing.T) { t.Parallel() _, err := b.GetLatestBlockCA(context.Background()) diff --git a/exchanges/bitflyer/bitflyer_wrapper.go b/exchanges/bitflyer/bitflyer_wrapper.go index 56595219..8b0bb911 100644 --- a/exchanges/bitflyer/bitflyer_wrapper.go +++ b/exchanges/bitflyer/bitflyer_wrapper.go @@ -2,6 +2,7 @@ package bitflyer import ( "context" + "fmt" "sort" "strconv" "strings" @@ -108,6 +109,9 @@ func (b *Bitflyer) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (b *Bitflyer) Setup(exch *config.Exchange) error { + if err := exch.Validate(); err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil @@ -116,12 +120,16 @@ func (b *Bitflyer) Setup(exch *config.Exchange) error { } // Start starts the Bitflyer go routine -func (b *Bitflyer) Start(wg *sync.WaitGroup) { +func (b *Bitflyer) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the Bitflyer wrapper @@ -443,6 +451,9 @@ func (b *Bitflyer) GetOrderHistory(_ context.Context, _ *order.GetOrdersRequest) // GetFeeByType returns an estimate of fee based on the type of transaction func (b *Bitflyer) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !b.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/bithumb/bithumb_test.go b/exchanges/bithumb/bithumb_test.go index 5246ab31..e0eb8cf1 100644 --- a/exchanges/bithumb/bithumb_test.go +++ b/exchanges/bithumb/bithumb_test.go @@ -5,6 +5,7 @@ import ( "errors" "log" "os" + "sync" "testing" "time" @@ -53,6 +54,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetTradablePairs(t *testing.T) { t.Parallel() _, err := b.GetTradablePairs(context.Background()) diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index ae131466..1a5223d2 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -148,11 +148,15 @@ func (b *Bithumb) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (b *Bithumb) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil } - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } @@ -187,12 +191,16 @@ func (b *Bithumb) Setup(exch *config.Exchange) error { } // Start starts the Bithumb go routine -func (b *Bithumb) Start(wg *sync.WaitGroup) { +func (b *Bithumb) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the Bithumb wrapper @@ -658,6 +666,9 @@ func (b *Bithumb) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *wit // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bithumb) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !b.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/bitmex/bitmex_test.go b/exchanges/bitmex/bitmex_test.go index c569612d..2ba2bff5 100644 --- a/exchanges/bitmex/bitmex_test.go +++ b/exchanges/bitmex/bitmex_test.go @@ -2,6 +2,7 @@ package bitmex import ( "context" + "errors" "log" "net/http" "os" @@ -57,8 +58,15 @@ func TestMain(m *testing.M) { func TestStart(t *testing.T) { t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } var testWg sync.WaitGroup - b.Start(&testWg) + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } testWg.Wait() } diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index c127a01b..90e20ca9 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -143,12 +143,15 @@ func (b *Bitmex) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (b *Bitmex) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil } - - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } @@ -180,12 +183,16 @@ func (b *Bitmex) Setup(exch *config.Exchange) error { } // Start starts the Bitmex go routine -func (b *Bitmex) Start(wg *sync.WaitGroup) { +func (b *Bitmex) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the Bitmex wrapper @@ -718,6 +725,9 @@ func (b *Bitmex) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *with // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bitmex) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !b.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/bitstamp/bitstamp_test.go b/exchanges/bitstamp/bitstamp_test.go index 13b9244d..6f81f626 100644 --- a/exchanges/bitstamp/bitstamp_test.go +++ b/exchanges/bitstamp/bitstamp_test.go @@ -3,6 +3,7 @@ package bitstamp import ( "context" "errors" + "sync" "testing" "time" @@ -40,6 +41,20 @@ func setFeeBuilder() *exchange.FeeBuilder { } } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + // TestGetFeeByTypeOfflineTradeFee logic test func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { t.Parallel() diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index 11f1f24e..c502acf5 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -3,6 +3,7 @@ package bitstamp import ( "context" "errors" + "fmt" "sort" "strconv" "sync" @@ -147,12 +148,15 @@ func (b *Bitstamp) SetDefaults() { // Setup sets configuration values to bitstamp func (b *Bitstamp) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil } - - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } @@ -184,12 +188,16 @@ func (b *Bitstamp) Setup(exch *config.Exchange) error { } // Start starts the Bitstamp go routine -func (b *Bitstamp) Start(wg *sync.WaitGroup) { +func (b *Bitstamp) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the Bitstamp wrapper @@ -353,6 +361,9 @@ func (b *Bitstamp) FetchTicker(ctx context.Context, p currency.Pair, assetType a // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bitstamp) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if (!b.AllowAuthenticatedRequest() || b.SkipAuthCheck) && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/bittrex/bittrex_test.go b/exchanges/bittrex/bittrex_test.go index d7086537..45ff98ab 100644 --- a/exchanges/bittrex/bittrex_test.go +++ b/exchanges/bittrex/bittrex_test.go @@ -2,8 +2,10 @@ package bittrex import ( "context" + "errors" "log" "os" + "sync" "testing" "time" @@ -56,6 +58,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetMarkets(t *testing.T) { t.Parallel() _, err := b.GetMarkets(context.Background()) diff --git a/exchanges/bittrex/bittrex_wrapper.go b/exchanges/bittrex/bittrex_wrapper.go index 9a3f6823..b9292930 100644 --- a/exchanges/bittrex/bittrex_wrapper.go +++ b/exchanges/bittrex/bittrex_wrapper.go @@ -142,12 +142,15 @@ func (b *Bittrex) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (b *Bittrex) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil } - - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } @@ -187,12 +190,16 @@ func (b *Bittrex) Setup(exch *config.Exchange) error { } // Start starts the Bittrex go routine -func (b *Bittrex) Start(wg *sync.WaitGroup) { +func (b *Bittrex) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the Bittrex wrapper @@ -885,6 +892,9 @@ func (b *Bittrex) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque // GetFeeByType returns an estimate of fee based on type of transaction func (b *Bittrex) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !b.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/btcmarkets/btcmarkets_test.go b/exchanges/btcmarkets/btcmarkets_test.go index 87a09db8..6b4a3654 100644 --- a/exchanges/btcmarkets/btcmarkets_test.go +++ b/exchanges/btcmarkets/btcmarkets_test.go @@ -2,9 +2,11 @@ package btcmarkets import ( "context" + "errors" "fmt" "log" "os" + "sync" "testing" "time" @@ -63,6 +65,20 @@ func areTestAPIKeysSet() bool { return b.AllowAuthenticatedRequest() } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetMarkets(t *testing.T) { t.Parallel() _, err := b.GetMarkets(context.Background()) diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index 13101586..816083f7 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -138,12 +138,15 @@ func (b *BTCMarkets) SetDefaults() { // Setup takes in an exchange configuration and sets all parameters func (b *BTCMarkets) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil } - - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } @@ -174,12 +177,16 @@ func (b *BTCMarkets) Setup(exch *config.Exchange) error { } // Start starts the BTC Markets go routine -func (b *BTCMarkets) Start(wg *sync.WaitGroup) { +func (b *BTCMarkets) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the BTC Markets wrapper @@ -710,6 +717,9 @@ func (b *BTCMarkets) WithdrawFiatFundsToInternationalBank(_ context.Context, _ * // GetFeeByType returns an estimate of fee based on type of transaction func (b *BTCMarkets) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !b.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/btse/btse_test.go b/exchanges/btse/btse_test.go index d46ca77e..3055affc 100644 --- a/exchanges/btse/btse_test.go +++ b/exchanges/btse/btse_test.go @@ -6,6 +6,7 @@ import ( "log" "os" "strings" + "sync" "testing" "time" @@ -58,6 +59,20 @@ func areTestAPIKeysSet() bool { return b.ValidateAPICredentials() } +func TestStart(t *testing.T) { + t.Parallel() + err := b.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = b.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestFetchFundingHistory(t *testing.T) { _, err := b.FetchFundingHistory(context.Background(), "") if err != nil { diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 0047961d..9c59178b 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -169,12 +169,15 @@ func (b *BTSE) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (b *BTSE) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { b.SetEnabled(false) return nil } - - err := b.SetupDefaults(exch) + err = b.SetupDefaults(exch) if err != nil { return err } @@ -210,12 +213,16 @@ func (b *BTSE) Setup(exch *config.Exchange) error { } // Start starts the BTSE go routine -func (b *BTSE) Start(wg *sync.WaitGroup) { +func (b *BTSE) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { b.Run() wg.Done() }() + return nil } // Run implements the BTSE wrapper @@ -923,6 +930,9 @@ func (b *BTSE) GetOrderHistory(ctx context.Context, getOrdersRequest *order.GetO // GetFeeByType returns an estimate of fee based on type of transaction func (b *BTSE) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !b.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/coinbasepro/coinbasepro_test.go b/exchanges/coinbasepro/coinbasepro_test.go index 983787ae..99dead92 100644 --- a/exchanges/coinbasepro/coinbasepro_test.go +++ b/exchanges/coinbasepro/coinbasepro_test.go @@ -2,9 +2,11 @@ package coinbasepro import ( "context" + "errors" "log" "net/http" "os" + "sync" "testing" "time" @@ -61,6 +63,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := c.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = c.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetProducts(t *testing.T) { _, err := c.GetProducts(context.Background()) if err != nil { diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index 5c568af9..c1a007b8 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -150,12 +150,15 @@ func (c *CoinbasePro) SetDefaults() { // Setup initialises the exchange parameters with the current configuration func (c *CoinbasePro) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { c.SetEnabled(false) return nil } - - err := c.SetupDefaults(exch) + err = c.SetupDefaults(exch) if err != nil { return err } @@ -187,12 +190,16 @@ func (c *CoinbasePro) Setup(exch *config.Exchange) error { } // Start starts the coinbasepro go routine -func (c *CoinbasePro) Start(wg *sync.WaitGroup) { +func (c *CoinbasePro) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { c.Run() wg.Done() }() + return nil } // Run implements the coinbasepro wrapper @@ -719,6 +726,9 @@ func (c *CoinbasePro) WithdrawFiatFundsToInternationalBank(ctx context.Context, // GetFeeByType returns an estimate of fee based on type of transaction func (c *CoinbasePro) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !c.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/coinbene/coinbene_test.go b/exchanges/coinbene/coinbene_test.go index ab2f9ee2..ff1f587f 100644 --- a/exchanges/coinbene/coinbene_test.go +++ b/exchanges/coinbene/coinbene_test.go @@ -2,8 +2,10 @@ package coinbene import ( "context" + "errors" "log" "os" + "sync" "testing" "time" @@ -56,6 +58,20 @@ func areTestAPIKeysSet() bool { return c.AllowAuthenticatedRequest() } +func TestStart(t *testing.T) { + t.Parallel() + err := c.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = c.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetAllPairs(t *testing.T) { t.Parallel() _, err := c.GetAllPairs(context.Background()) diff --git a/exchanges/coinbene/coinbene_wrapper.go b/exchanges/coinbene/coinbene_wrapper.go index 3a898ae5..50b1544f 100644 --- a/exchanges/coinbene/coinbene_wrapper.go +++ b/exchanges/coinbene/coinbene_wrapper.go @@ -170,12 +170,15 @@ func (c *Coinbene) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (c *Coinbene) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { c.SetEnabled(false) return nil } - - err := c.SetupDefaults(exch) + err = c.SetupDefaults(exch) if err != nil { return err } @@ -207,12 +210,16 @@ func (c *Coinbene) Setup(exch *config.Exchange) error { } // Start starts the Coinbene go routine -func (c *Coinbene) Start(wg *sync.WaitGroup) { +func (c *Coinbene) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { c.Run() wg.Done() }() + return nil } // Run implements the Coinbene wrapper @@ -853,6 +860,9 @@ func (c *Coinbene) GetOrderHistory(ctx context.Context, getOrdersRequest *order. // GetFeeByType returns an estimate of fee based on the type of transaction func (c *Coinbene) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } fpair, err := c.FormatExchangeCurrency(feeBuilder.Pair, asset.Spot) if err != nil { return 0, err diff --git a/exchanges/coinut/coinut_test.go b/exchanges/coinut/coinut_test.go index d5e3e466..ab532345 100644 --- a/exchanges/coinut/coinut_test.go +++ b/exchanges/coinut/coinut_test.go @@ -2,9 +2,11 @@ package coinut import ( "context" + "errors" "log" "net/http" "os" + "sync" "testing" "time" @@ -88,6 +90,20 @@ func setupWSTestAuth(t *testing.T) { } } +func TestStart(t *testing.T) { + t.Parallel() + err := c.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = c.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetInstruments(t *testing.T) { _, err := c.GetInstruments(context.Background()) if err != nil { diff --git a/exchanges/coinut/coinut_wrapper.go b/exchanges/coinut/coinut_wrapper.go index 67056003..1ba6771e 100644 --- a/exchanges/coinut/coinut_wrapper.go +++ b/exchanges/coinut/coinut_wrapper.go @@ -132,12 +132,15 @@ func (c *COINUT) SetDefaults() { // Setup sets the current exchange configuration func (c *COINUT) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { c.SetEnabled(false) return nil } - - err := c.SetupDefaults(exch) + err = c.SetupDefaults(exch) if err != nil { return err } @@ -171,12 +174,16 @@ func (c *COINUT) Setup(exch *config.Exchange) error { } // Start starts the COINUT go routine -func (c *COINUT) Start(wg *sync.WaitGroup) { +func (c *COINUT) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { c.Run() wg.Done() }() + return nil } // Run implements the COINUT wrapper @@ -830,6 +837,9 @@ func (c *COINUT) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *with // GetFeeByType returns an estimate of fee based on type of transaction func (c *COINUT) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !c.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/exchange.go b/exchanges/exchange.go index e0e88136..1ca828ce 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -569,6 +569,11 @@ func (b *Base) SetAPIKeys(apiKey, apiSecret, clientID string) { // SetupDefaults sets the exchange settings based on the supplied config func (b *Base) SetupDefaults(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } + b.Enabled = true b.LoadedByConfig = true b.Config = exch @@ -587,7 +592,7 @@ func (b *Base) SetupDefaults(exch *config.Exchange) error { exch.HTTPTimeout = DefaultHTTPTimeout } - err := b.SetHTTPClientTimeout(exch.HTTPTimeout) + err = b.SetHTTPClientTimeout(exch.HTTPTimeout) if err != nil { return err } diff --git a/exchanges/exmo/exmo_test.go b/exchanges/exmo/exmo_test.go index 13c55a5e..243e061b 100644 --- a/exchanges/exmo/exmo_test.go +++ b/exchanges/exmo/exmo_test.go @@ -2,8 +2,10 @@ package exmo import ( "context" + "errors" "log" "os" + "sync" "testing" "time" @@ -51,6 +53,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := e.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = e.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetTrades(t *testing.T) { t.Parallel() _, err := e.GetTrades(context.Background(), "BTC_USD") diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index 838f1054..89e5e999 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -124,6 +124,9 @@ func (e *EXMO) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (e *EXMO) Setup(exch *config.Exchange) error { + if err := exch.Validate(); err != nil { + return err + } if !exch.Enabled { e.SetEnabled(false) return nil @@ -132,12 +135,16 @@ func (e *EXMO) Setup(exch *config.Exchange) error { } // Start starts the EXMO go routine -func (e *EXMO) Start(wg *sync.WaitGroup) { +func (e *EXMO) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { e.Run() wg.Done() }() + return nil } // Run implements the EXMO wrapper @@ -598,6 +605,9 @@ func (e *EXMO) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withdr // GetFeeByType returns an estimate of fee based on type of transaction func (e *EXMO) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !e.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/ftx/ftx_test.go b/exchanges/ftx/ftx_test.go index e1e1560b..30c21840 100644 --- a/exchanges/ftx/ftx_test.go +++ b/exchanges/ftx/ftx_test.go @@ -5,9 +5,11 @@ import ( "errors" "log" "os" + "sync" "testing" "time" + "github.com/thrasher-corp/gocryptotrader/common" "github.com/thrasher-corp/gocryptotrader/config" "github.com/thrasher-corp/gocryptotrader/currency" exchange "github.com/thrasher-corp/gocryptotrader/exchanges" @@ -75,6 +77,20 @@ func areTestAPIKeysSet() bool { // Implement tests for API endpoints below +func TestStart(t *testing.T) { + t.Parallel() + err := f.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = f.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetMarkets(t *testing.T) { t.Parallel() _, err := f.GetMarkets(context.Background()) diff --git a/exchanges/ftx/ftx_wrapper.go b/exchanges/ftx/ftx_wrapper.go index 8954efe9..c5564061 100644 --- a/exchanges/ftx/ftx_wrapper.go +++ b/exchanges/ftx/ftx_wrapper.go @@ -166,12 +166,15 @@ func (f *FTX) SetDefaults() { // Setup takes in the supplied exchange configuration details and sets params func (f *FTX) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { f.SetEnabled(false) return nil } - - err := f.SetupDefaults(exch) + err = f.SetupDefaults(exch) if err != nil { return err } @@ -203,12 +206,16 @@ func (f *FTX) Setup(exch *config.Exchange) error { } // Start starts the FTX go routine -func (f *FTX) Start(wg *sync.WaitGroup) { +func (f *FTX) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { f.Run() wg.Done() }() + return nil } // Run implements the FTX wrapper @@ -1092,6 +1099,9 @@ func (f *FTX) GetOrderHistory(ctx context.Context, getOrdersRequest *order.GetOr // GetFeeByType returns an estimate of fee based on the type of transaction func (f *FTX) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } return f.GetFee(ctx, feeBuilder) } diff --git a/exchanges/gateio/gateio_test.go b/exchanges/gateio/gateio_test.go index 3ca51e67..774974e2 100644 --- a/exchanges/gateio/gateio_test.go +++ b/exchanges/gateio/gateio_test.go @@ -2,9 +2,11 @@ package gateio import ( "context" + "errors" "log" "net/http" "os" + "sync" "testing" "time" @@ -58,6 +60,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := g.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = g.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetSymbols(t *testing.T) { t.Parallel() _, err := g.GetSymbols(context.Background()) diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index e565668a..4491da84 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -149,12 +149,15 @@ func (g *Gateio) SetDefaults() { // Setup sets user configuration func (g *Gateio) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { g.SetEnabled(false) return nil } - - err := g.SetupDefaults(exch) + err = g.SetupDefaults(exch) if err != nil { return err } @@ -185,12 +188,16 @@ func (g *Gateio) Setup(exch *config.Exchange) error { } // Start starts the GateIO go routine -func (g *Gateio) Start(wg *sync.WaitGroup) { +func (g *Gateio) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { g.Run() wg.Done() }() + return nil } // Run implements the GateIO wrapper @@ -682,6 +689,9 @@ func (g *Gateio) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *with // GetFeeByType returns an estimate of fee based on type of transaction func (g *Gateio) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !g.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/gemini/gemini_test.go b/exchanges/gemini/gemini_test.go index 8c775739..a1bad158 100644 --- a/exchanges/gemini/gemini_test.go +++ b/exchanges/gemini/gemini_test.go @@ -2,8 +2,10 @@ package gemini import ( "context" + "errors" "net/url" "strings" + "sync" "testing" "time" @@ -30,6 +32,20 @@ const testCurrency = "btcusd" var g Gemini +func TestStart(t *testing.T) { + t.Parallel() + err := g.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = g.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetSymbols(t *testing.T) { t.Parallel() _, err := g.GetSymbols(context.Background()) diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index cdd9ce6d..0a6c1e75 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -132,12 +132,15 @@ func (g *Gemini) SetDefaults() { // Setup sets exchange configuration parameters func (g *Gemini) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { g.SetEnabled(false) return nil } - - err := g.SetupDefaults(exch) + err = g.SetupDefaults(exch) if err != nil { return err } @@ -186,12 +189,16 @@ func (g *Gemini) Setup(exch *config.Exchange) error { } // Start starts the Gemini go routine -func (g *Gemini) Start(wg *sync.WaitGroup) { +func (g *Gemini) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { g.Run() wg.Done() }() + return nil } // Run implements the Gemini wrapper @@ -650,6 +657,9 @@ func (g *Gemini) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *with // GetFeeByType returns an estimate of fee based on type of transaction func (g *Gemini) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if (!g.AllowAuthenticatedRequest() || g.SkipAuthCheck) && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/hitbtc/hitbtc_test.go b/exchanges/hitbtc/hitbtc_test.go index 2a48f0f7..5b728dcb 100644 --- a/exchanges/hitbtc/hitbtc_test.go +++ b/exchanges/hitbtc/hitbtc_test.go @@ -2,9 +2,11 @@ package hitbtc import ( "context" + "errors" "log" "net/http" "os" + "sync" "testing" "time" @@ -55,6 +57,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := h.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = h.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetOrderbook(t *testing.T) { _, err := h.GetOrderbook(context.Background(), "BTCUSD", 50) if err != nil { diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index c4fabbe7..cc438d0c 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -148,12 +148,15 @@ func (h *HitBTC) SetDefaults() { // Setup sets user exchange configuration settings func (h *HitBTC) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { h.SetEnabled(false) return nil } - - err := h.SetupDefaults(exch) + err = h.SetupDefaults(exch) if err != nil { return err } @@ -187,12 +190,16 @@ func (h *HitBTC) Setup(exch *config.Exchange) error { } // Start starts the HitBTC go routine -func (h *HitBTC) Start(wg *sync.WaitGroup) { +func (h *HitBTC) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { h.Run() wg.Done() }() + return nil } // Run implements the HitBTC wrapper @@ -686,6 +693,9 @@ func (h *HitBTC) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *with // GetFeeByType returns an estimate of fee based on type of transaction func (h *HitBTC) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !h.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/huobi/huobi_test.go b/exchanges/huobi/huobi_test.go index d603fbf9..b852edca 100644 --- a/exchanges/huobi/huobi_test.go +++ b/exchanges/huobi/huobi_test.go @@ -2,10 +2,12 @@ package huobi import ( "context" + "errors" "log" "os" "strconv" "strings" + "sync" "testing" "time" @@ -83,6 +85,20 @@ func setupWsTests(t *testing.T) { wsSetupRan = true } +func TestStart(t *testing.T) { + t.Parallel() + err := h.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = h.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetCurrenciesIncludingChains(t *testing.T) { t.Parallel() r, err := h.GetCurrenciesIncludingChains(context.Background(), currency.Code{}) diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index a0941a2f..77798636 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -179,12 +179,15 @@ func (h *HUOBI) SetDefaults() { // Setup sets user configuration func (h *HUOBI) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { h.SetEnabled(false) return nil } - - err := h.SetupDefaults(exch) + err = h.SetupDefaults(exch) if err != nil { return err } @@ -227,12 +230,16 @@ func (h *HUOBI) Setup(exch *config.Exchange) error { } // Start starts the HUOBI go routine -func (h *HUOBI) Start(wg *sync.WaitGroup) { +func (h *HUOBI) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { h.Run() wg.Done() }() + return nil } // Run implements the HUOBI wrapper @@ -1295,6 +1302,9 @@ func (h *HUOBI) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withd // GetFeeByType returns an estimate of fee based on type of transaction func (h *HUOBI) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !h.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/interfaces.go b/exchanges/interfaces.go index 5bb72729..e97baecd 100644 --- a/exchanges/interfaces.go +++ b/exchanges/interfaces.go @@ -24,7 +24,7 @@ import ( // GoCryptoTrader type IBotExchange interface { Setup(exch *config.Exchange) error - Start(wg *sync.WaitGroup) + Start(wg *sync.WaitGroup) error SetDefaults() GetName() string IsEnabled() bool diff --git a/exchanges/itbit/itbit_test.go b/exchanges/itbit/itbit_test.go index 82bd880b..3ece000a 100644 --- a/exchanges/itbit/itbit_test.go +++ b/exchanges/itbit/itbit_test.go @@ -2,9 +2,11 @@ package itbit import ( "context" + "errors" "log" "net/url" "os" + "sync" "testing" "time" @@ -52,6 +54,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := i.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = i.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetTicker(t *testing.T) { t.Parallel() _, err := i.GetTicker(context.Background(), "XBTUSD") diff --git a/exchanges/itbit/itbit_wrapper.go b/exchanges/itbit/itbit_wrapper.go index d38430f0..79c6524c 100644 --- a/exchanges/itbit/itbit_wrapper.go +++ b/exchanges/itbit/itbit_wrapper.go @@ -107,6 +107,9 @@ func (i *ItBit) SetDefaults() { // Setup sets the exchange parameters from exchange config func (i *ItBit) Setup(exch *config.Exchange) error { + if err := exch.Validate(); err != nil { + return err + } if !exch.Enabled { i.SetEnabled(false) return nil @@ -115,12 +118,16 @@ func (i *ItBit) Setup(exch *config.Exchange) error { } // Start starts the ItBit go routine -func (i *ItBit) Start(wg *sync.WaitGroup) { +func (i *ItBit) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { i.Run() wg.Done() }() + return nil } // Run implements the ItBit wrapper @@ -505,6 +512,9 @@ func (i *ItBit) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withd // GetFeeByType returns an estimate of fee based on type of transaction func (i *ItBit) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !i.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index 59d63909..b5cbe68a 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "strings" + "sync" "testing" "time" @@ -60,7 +61,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -// TestGetServerTime API endpoint test +func TestStart(t *testing.T) { + t.Parallel() + err := k.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = k.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetServerTime(t *testing.T) { t.Parallel() _, err := k.GetServerTime(context.Background()) diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 7d13d423..a959e908 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -191,12 +191,15 @@ func (k *Kraken) SetDefaults() { // Setup sets current exchange configuration func (k *Kraken) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { k.SetEnabled(false) return nil } - - err := k.SetupDefaults(exch) + err = k.SetupDefaults(exch) if err != nil { return err } @@ -245,12 +248,16 @@ func (k *Kraken) Setup(exch *config.Exchange) error { } // Start starts the Kraken go routine -func (k *Kraken) Start(wg *sync.WaitGroup) { +func (k *Kraken) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { k.Run() wg.Done() }() + return nil } // Run implements the Kraken wrapper @@ -1068,6 +1075,9 @@ func (k *Kraken) WithdrawFiatFundsToInternationalBank(ctx context.Context, withd // GetFeeByType returns an estimate of fee based on type of transaction func (k *Kraken) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !k.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/lbank/lbank_test.go b/exchanges/lbank/lbank_test.go index 2f1512e1..4df70be1 100644 --- a/exchanges/lbank/lbank_test.go +++ b/exchanges/lbank/lbank_test.go @@ -2,12 +2,15 @@ package lbank import ( "context" + "errors" "log" "os" "strconv" + "sync" "testing" "time" + "github.com/thrasher-corp/gocryptotrader/common" "github.com/thrasher-corp/gocryptotrader/config" "github.com/thrasher-corp/gocryptotrader/currency" exchange "github.com/thrasher-corp/gocryptotrader/exchanges" @@ -51,6 +54,20 @@ func areTestAPIKeysSet() bool { return l.AllowAuthenticatedRequest() } +func TestStart(t *testing.T) { + t.Parallel() + err := l.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = l.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetTicker(t *testing.T) { t.Parallel() _, err := l.GetTicker(context.Background(), testCurrencyPair) diff --git a/exchanges/lbank/lbank_wrapper.go b/exchanges/lbank/lbank_wrapper.go index 8402d883..9aab8bcc 100644 --- a/exchanges/lbank/lbank_wrapper.go +++ b/exchanges/lbank/lbank_wrapper.go @@ -121,12 +121,15 @@ func (l *Lbank) SetDefaults() { // Setup sets exchange configuration profile func (l *Lbank) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { l.SetEnabled(false) return nil } - - err := l.SetupDefaults(exch) + err = l.SetupDefaults(exch) if err != nil { return err } @@ -142,12 +145,16 @@ func (l *Lbank) Setup(exch *config.Exchange) error { } // Start starts the Lbank go routine -func (l *Lbank) Start(wg *sync.WaitGroup) { +func (l *Lbank) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { l.Run() wg.Done() }() + return nil } // Run implements the Lbank wrapper @@ -814,6 +821,9 @@ func (l *Lbank) GetOrderHistory(ctx context.Context, getOrdersRequest *order.Get // GetFeeByType returns an estimate of fee based on the type of transaction * func (l *Lbank) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } var resp float64 if feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { return feeBuilder.Amount * feeBuilder.PurchasePrice * 0.002, nil diff --git a/exchanges/localbitcoins/localbitcoins_test.go b/exchanges/localbitcoins/localbitcoins_test.go index 57c0abaf..fd49cf0c 100644 --- a/exchanges/localbitcoins/localbitcoins_test.go +++ b/exchanges/localbitcoins/localbitcoins_test.go @@ -2,6 +2,8 @@ package localbitcoins import ( "context" + "errors" + "sync" "testing" "time" @@ -24,6 +26,20 @@ const ( var l LocalBitcoins +func TestStart(t *testing.T) { + t.Parallel() + err := l.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = l.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetTicker(t *testing.T) { t.Parallel() diff --git a/exchanges/localbitcoins/localbitcoins_wrapper.go b/exchanges/localbitcoins/localbitcoins_wrapper.go index 79a9f594..0dbafa91 100644 --- a/exchanges/localbitcoins/localbitcoins_wrapper.go +++ b/exchanges/localbitcoins/localbitcoins_wrapper.go @@ -106,6 +106,9 @@ func (l *LocalBitcoins) SetDefaults() { // Setup sets exchange configuration parameters func (l *LocalBitcoins) Setup(exch *config.Exchange) error { + if err := exch.Validate(); err != nil { + return err + } if !exch.Enabled { l.SetEnabled(false) return nil @@ -114,12 +117,16 @@ func (l *LocalBitcoins) Setup(exch *config.Exchange) error { } // Start starts the LocalBitcoins go routine -func (l *LocalBitcoins) Start(wg *sync.WaitGroup) { +func (l *LocalBitcoins) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { l.Run() wg.Done() }() + return nil } // Run implements the LocalBitcoins wrapper @@ -512,6 +519,9 @@ func (l *LocalBitcoins) WithdrawFiatFundsToInternationalBank(_ context.Context, // GetFeeByType returns an estimate of fee based on type of transaction func (l *LocalBitcoins) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if (!l.AllowAuthenticatedRequest() || l.SkipAuthCheck) && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/okcoin/okcoin_test.go b/exchanges/okcoin/okcoin_test.go index 20c01cda..fcdc4617 100644 --- a/exchanges/okcoin/okcoin_test.go +++ b/exchanges/okcoin/okcoin_test.go @@ -3,10 +3,12 @@ package okcoin import ( "context" "encoding/json" + "errors" "log" "net/http" "os" "strings" + "sync" "testing" "time" @@ -81,6 +83,20 @@ func areTestAPIKeysSet() bool { return o.ValidateAPICredentials() } +func TestStart(t *testing.T) { + t.Parallel() + err := o.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = o.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func testStandardErrorHandling(t *testing.T, err error) { t.Helper() if !areTestAPIKeysSet() && err == nil { diff --git a/exchanges/okcoin/okcoin_wrapper.go b/exchanges/okcoin/okcoin_wrapper.go index 7234264c..e110e3f6 100644 --- a/exchanges/okcoin/okcoin_wrapper.go +++ b/exchanges/okcoin/okcoin_wrapper.go @@ -154,12 +154,16 @@ func (o *OKCoin) SetDefaults() { } // Start starts the OKGroup go routine -func (o *OKCoin) Start(wg *sync.WaitGroup) { +func (o *OKCoin) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { o.Run() wg.Done() }() + return nil } // Run implements the OKEX wrapper diff --git a/exchanges/okex/okex_test.go b/exchanges/okex/okex_test.go index ef616ab3..d8882241 100644 --- a/exchanges/okex/okex_test.go +++ b/exchanges/okex/okex_test.go @@ -3,12 +3,14 @@ package okex import ( "context" "encoding/json" + "errors" "fmt" "log" "net/http" "os" "strconv" "strings" + "sync" "testing" "time" @@ -81,6 +83,20 @@ func areTestAPIKeysSet() bool { return o.ValidateAPICredentials() } +func TestStart(t *testing.T) { + t.Parallel() + err := o.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = o.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestUpdateOrderbook(t *testing.T) { tradablePairs, err := o.FetchTradablePairs(context.Background(), asset.Futures) if err != nil { diff --git a/exchanges/okex/okex_wrapper.go b/exchanges/okex/okex_wrapper.go index cc8a7bcb..ca67f1e5 100644 --- a/exchanges/okex/okex_wrapper.go +++ b/exchanges/okex/okex_wrapper.go @@ -212,12 +212,16 @@ func (o *OKEX) SetDefaults() { } // Start starts the OKGroup go routine -func (o *OKEX) Start(wg *sync.WaitGroup) { +func (o *OKEX) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { o.Run() wg.Done() }() + return nil } // Run implements the OKEX wrapper diff --git a/exchanges/okgroup/okgroup_wrapper.go b/exchanges/okgroup/okgroup_wrapper.go index 30a8ddc8..59124a1b 100644 --- a/exchanges/okgroup/okgroup_wrapper.go +++ b/exchanges/okgroup/okgroup_wrapper.go @@ -31,12 +31,15 @@ import ( // Setup sets user exchange configuration settings func (o *OKGroup) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { o.SetEnabled(false) return nil } - - err := o.SetupDefaults(exch) + err = o.SetupDefaults(exch) if err != nil { return err } @@ -579,6 +582,9 @@ func (o *OKGroup) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque // GetFeeByType returns an estimate of fee based on type of transaction func (o *OKGroup) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !o.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/poloniex/poloniex_test.go b/exchanges/poloniex/poloniex_test.go index 61f46edc..5cf1c21b 100644 --- a/exchanges/poloniex/poloniex_test.go +++ b/exchanges/poloniex/poloniex_test.go @@ -5,6 +5,7 @@ import ( "errors" "net/http" "strings" + "sync" "testing" "time" @@ -34,6 +35,20 @@ func areTestAPIKeysSet() bool { return p.ValidateAPICredentials() } +func TestStart(t *testing.T) { + t.Parallel() + err := p.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = p.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestGetTicker(t *testing.T) { t.Parallel() _, err := p.GetTicker(context.Background()) diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index a766361d..ed675308 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -152,12 +152,15 @@ func (p *Poloniex) SetDefaults() { // Setup sets user exchange configuration settings func (p *Poloniex) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { p.SetEnabled(false) return nil } - - err := p.SetupDefaults(exch) + err = p.SetupDefaults(exch) if err != nil { return err } @@ -190,12 +193,16 @@ func (p *Poloniex) Setup(exch *config.Exchange) error { } // Start starts the Poloniex go routine -func (p *Poloniex) Start(wg *sync.WaitGroup) { +func (p *Poloniex) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { p.Run() wg.Done() }() + return nil } // Run implements the Poloniex wrapper @@ -793,6 +800,9 @@ func (p *Poloniex) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *wi // GetFeeByType returns an estimate of fee based on type of transaction func (p *Poloniex) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if (!p.AllowAuthenticatedRequest() || p.SkipAuthCheck) && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/sharedtestvalues/customex.go b/exchanges/sharedtestvalues/customex.go index a7d453c5..155ebc8b 100644 --- a/exchanges/sharedtestvalues/customex.go +++ b/exchanges/sharedtestvalues/customex.go @@ -28,7 +28,8 @@ func (c *CustomEx) Setup(exch *config.Exchange) error { return nil } -func (c *CustomEx) Start(wg *sync.WaitGroup) { +func (c *CustomEx) Start(wg *sync.WaitGroup) error { + return nil } func (c *CustomEx) SetDefaults() { diff --git a/exchanges/yobit/yobit_test.go b/exchanges/yobit/yobit_test.go index 6ac68966..0f7d3787 100644 --- a/exchanges/yobit/yobit_test.go +++ b/exchanges/yobit/yobit_test.go @@ -2,9 +2,11 @@ package yobit import ( "context" + "errors" "log" "math" "os" + "sync" "testing" "time" @@ -50,6 +52,20 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestStart(t *testing.T) { + t.Parallel() + err := y.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = y.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestFetchTradablePairs(t *testing.T) { t.Parallel() _, err := y.FetchTradablePairs(context.Background(), asset.Spot) diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index 35a6f9c3..3dbeea5a 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -3,6 +3,7 @@ package yobit import ( "context" "errors" + "fmt" "math" "sort" "strconv" @@ -112,6 +113,9 @@ func (y *Yobit) SetDefaults() { // Setup sets exchange configuration parameters for Yobit func (y *Yobit) Setup(exch *config.Exchange) error { + if err := exch.Validate(); err != nil { + return err + } if !exch.Enabled { y.SetEnabled(false) return nil @@ -120,12 +124,16 @@ func (y *Yobit) Setup(exch *config.Exchange) error { } // Start starts the WEX go routine -func (y *Yobit) Start(wg *sync.WaitGroup) { +func (y *Yobit) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { y.Run() wg.Done() }() + return nil } // Run implements the Yobit wrapper @@ -543,6 +551,9 @@ func (y *Yobit) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withd // GetFeeByType returns an estimate of fee based on type of transaction func (y *Yobit) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if !y.AllowAuthenticatedRequest() && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/exchanges/zb/zb_test.go b/exchanges/zb/zb_test.go index c17a3a1e..8d322585 100644 --- a/exchanges/zb/zb_test.go +++ b/exchanges/zb/zb_test.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "strconv" + "sync" "testing" "time" @@ -53,6 +54,20 @@ func setupWsAuth(t *testing.T) { wsSetupRan = true } +func TestStart(t *testing.T) { + t.Parallel() + err := z.Start(nil) + if !errors.Is(err, common.ErrNilPointer) { + t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) + } + var testWg sync.WaitGroup + err = z.Start(&testWg) + if err != nil { + t.Fatal(err) + } + testWg.Wait() +} + func TestSpotNewOrder(t *testing.T) { t.Parallel() diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index af4c0c6d..e0103993 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -149,12 +149,15 @@ func (z *ZB) SetDefaults() { // Setup sets user configuration func (z *ZB) Setup(exch *config.Exchange) error { + err := exch.Validate() + if err != nil { + return err + } if !exch.Enabled { z.SetEnabled(false) return nil } - - err := z.SetupDefaults(exch) + err = z.SetupDefaults(exch) if err != nil { return err } @@ -186,12 +189,16 @@ func (z *ZB) Setup(exch *config.Exchange) error { } // Start starts the OKEX go routine -func (z *ZB) Start(wg *sync.WaitGroup) { +func (z *ZB) Start(wg *sync.WaitGroup) error { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } wg.Add(1) go func() { z.Run() wg.Done() }() + return nil } // Run implements the OKEX wrapper @@ -680,6 +687,9 @@ func (z *ZB) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withdraw // GetFeeByType returns an estimate of fee based on type of transaction func (z *ZB) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) { + if feeBuilder == nil { + return 0, fmt.Errorf("%T %w", feeBuilder, common.ErrNilPointer) + } if (!z.AllowAuthenticatedRequest() || z.SkipAuthCheck) && // Todo check connection status feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { feeBuilder.FeeType = exchange.OfflineTradeFee diff --git a/gctscript/vm/manager.go b/gctscript/vm/manager.go index bfbc644e..294b5d25 100644 --- a/gctscript/vm/manager.go +++ b/gctscript/vm/manager.go @@ -6,6 +6,7 @@ import ( "sync" "sync/atomic" + "github.com/thrasher-corp/gocryptotrader/common" "github.com/thrasher-corp/gocryptotrader/log" ) @@ -46,6 +47,9 @@ func (g *GctScriptManager) IsRunning() bool { // Start starts gctscript subsystem and creates shutdown channel func (g *GctScriptManager) Start(wg *sync.WaitGroup) (err error) { + if wg == nil { + return fmt.Errorf("%T %w", wg, common.ErrNilPointer) + } if !atomic.CompareAndSwapInt32(&g.started, 0, 1) { return fmt.Errorf("%s %s", caseName, ErrScriptFailedValidation) }