diff --git a/.golangci.yml b/.golangci.yml index c61cdb1a..698ce31c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -99,4 +99,13 @@ issues: exclude-rules: - text: "Expect WriteFile permissions to be 0600 or less" linters: - - gosec \ No newline at end of file + - gosec + + # List of regexps of issue texts to exclude, empty list by default. + # But independently from this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. To list all + # excluded by default patterns execute `golangci-lint run --help` + exclude: + # The following silences false positives in table tests + # https://github.com/kyoh86/scopelint/issues/4 + - Using the variable on range scope `ti` in function literal diff --git a/backtester/common/common_test.go b/backtester/common/common_test.go new file mode 100644 index 00000000..9b621297 --- /dev/null +++ b/backtester/common/common_test.go @@ -0,0 +1,45 @@ +package common + +import ( + "fmt" + "testing" +) + +func TestDataTypeConversion(t *testing.T) { + for _, ti := range []struct { + title string + dataType string + want int64 + expectErr bool + }{ + { + title: "Candle data type", + dataType: CandleStr, + want: DataCandle, + }, + { + title: "Trade data type", + dataType: TradeStr, + want: DataTrade, + }, + { + title: "Unknown data type", + dataType: "unknown", + want: 0, + expectErr: true, + }, + } { + t.Run(ti.title, func(t *testing.T) { + got, err := DataTypeToInt(ti.dataType) + if ti.expectErr { + if err == nil { + t.Errorf("expected error") + } + } else { + if err != nil || got != ti.want { + t.Error(fmt.Errorf("%s: expected %d, got %d, err: %v", ti.dataType, ti.want, got, err)) + } + } + }) + } +} diff --git a/backtester/config/config_test.go b/backtester/config/config_test.go index a8b16343..885092fb 100644 --- a/backtester/config/config_test.go +++ b/backtester/config/config_test.go @@ -80,6 +80,11 @@ func TestPrintSettings(t *testing.T) { Goal: "To demonstrate rendering of settings", StrategySettings: StrategySettings{ Name: dca, + CustomSettings: map[string]interface{}{ + "dca-dummy1": 30.0, + "dca-dummy2": 30.0, + "dca-dummy3": 30.0, + }, }, CurrencySettings: []CurrencySettings{ { @@ -1004,4 +1009,21 @@ func TestValidateCurrencySettings(t *testing.T) { if err != nil { t.Error(err) } + c.CurrencySettings[0].MinimumSlippagePercent = -1.0 + err = c.ValidateCurrencySettings() + if !errors.Is(ErrBadSlippageRates, err) { + t.Errorf("expected %v, received %v", ErrBadSlippageRates, err) + } + c.CurrencySettings[0].MinimumSlippagePercent = 2.0 + c.CurrencySettings[0].MaximumSlippagePercent = -1.0 + err = c.ValidateCurrencySettings() + if !errors.Is(ErrBadSlippageRates, err) { + t.Errorf("expected %v, received %v", ErrBadSlippageRates, err) + } + c.CurrencySettings[0].MinimumSlippagePercent = 2.0 + c.CurrencySettings[0].MaximumSlippagePercent = 1.0 + err = c.ValidateCurrencySettings() + if !errors.Is(ErrBadSlippageRates, err) { + t.Errorf("expected %v, received %v", ErrBadSlippageRates, err) + } } diff --git a/backtester/data/data_test.go b/backtester/data/data_test.go index a9c32133..176dd831 100644 --- a/backtester/data/data_test.go +++ b/backtester/data/data_test.go @@ -2,17 +2,26 @@ package data import ( "testing" + "time" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" + "github.com/thrasher-corp/gocryptotrader/exchanges/kline" ) const testExchange = "binance" +type fakeDataHandler struct { + time int +} + func TestBaseDataFunctions(t *testing.T) { t.Parallel() var d Base - d.Latest() + latest := d.Latest() + if latest != nil { + t.Error("expected nil") + } d.Next() o := d.Offset() if o != 0 { @@ -27,8 +36,14 @@ func TestBaseDataFunctions(t *testing.T) { if o != 0 { t.Error("expected 0") } - d.List() - d.History() + list := d.List() + if list != nil { + t.Error("expected nil") + } + history := d.History() + if history != nil { + t.Error("expected nil") + } d.SetStream(nil) st := d.GetStream() if st != nil { @@ -48,6 +63,55 @@ func TestSetup(t *testing.T) { } } +func TestStream(t *testing.T) { + var d Base + var f fakeDataHandler + + // shut up coverage report + f.GetOffset() + f.SetOffset(1) + f.IsEvent() + f.Pair() + f.GetExchange() + f.GetInterval() + f.GetAssetType() + f.GetReason() + f.AppendReason("fake") + f.ClosePrice() + f.HighPrice() + f.LowPrice() + f.OpenPrice() + + d.AppendStream(fakeDataHandler{time: 1}) + d.AppendStream(fakeDataHandler{time: 4}) + d.AppendStream(fakeDataHandler{time: 10}) + d.AppendStream(fakeDataHandler{time: 2}) + d.AppendStream(fakeDataHandler{time: 20}) + + d.SortStream() + + f = d.Next().(fakeDataHandler) + if f.time != 1 { + t.Error("expected 1") + } + f = d.Next().(fakeDataHandler) + if f.time != 2 { + t.Error("expected 2") + } + f = d.Next().(fakeDataHandler) + if f.time != 4 { + t.Error("expected 4") + } + f = d.Next().(fakeDataHandler) + if f.time != 10 { + t.Error("expected 10") + } + f = d.Next().(fakeDataHandler) + if f.time != 20 { + t.Error("expected 20") + } +} + func TestSetDataForCurrency(t *testing.T) { t.Parallel() d := HandlerPerCurrency{} @@ -107,3 +171,58 @@ func TestReset(t *testing.T) { t.Error("expected nil") } } + +// methods that satisfy the common.DataEventHandler interface +func (t fakeDataHandler) GetOffset() int64 { + return 0 +} + +func (t fakeDataHandler) SetOffset(int64) { +} + +func (t fakeDataHandler) IsEvent() bool { + return false +} + +func (t fakeDataHandler) GetTime() time.Time { + return time.Now().Add(time.Hour * time.Duration(t.time)) +} + +func (t fakeDataHandler) Pair() currency.Pair { + return currency.NewPair(currency.BTC, currency.USD) +} + +func (t fakeDataHandler) GetExchange() string { + return "fake" +} + +func (t fakeDataHandler) GetInterval() kline.Interval { + return kline.Interval(time.Minute) +} + +func (t fakeDataHandler) GetAssetType() asset.Item { + return asset.Spot +} + +func (t fakeDataHandler) GetReason() string { + return "fake" +} + +func (t fakeDataHandler) AppendReason(string) { +} + +func (t fakeDataHandler) ClosePrice() float64 { + return 0 +} + +func (t fakeDataHandler) HighPrice() float64 { + return 0 +} + +func (t fakeDataHandler) LowPrice() float64 { + return 0 +} + +func (t fakeDataHandler) OpenPrice() float64 { + return 0 +}