diff --git a/pkg/bbgo/config.go b/pkg/bbgo/config.go index e66c87409..e4c8e2e50 100644 --- a/pkg/bbgo/config.go +++ b/pkg/bbgo/config.go @@ -1,6 +1,7 @@ package bbgo import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -207,11 +208,51 @@ func (c *Config) Map() (map[string]interface{}, error) { strategyID: params, }) } - data["exchangeStrategies"] = exchangeStrategies + + if len(exchangeStrategies) > 0 { + data["exchangeStrategies"] = exchangeStrategies + } + + var crossExchangeStrategies []map[string]interface{} + for _, st := range c.CrossExchangeStrategies { + strategyID := st.ID() + + var params Stash + + out, err := json.Marshal(st) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(out, ¶ms); err != nil { + return nil, err + } + + crossExchangeStrategies = append(crossExchangeStrategies, map[string]interface{}{ + strategyID: params, + }) + } + + if len(crossExchangeStrategies) > 0 { + data["crossExchangeStrategies"] = crossExchangeStrategies + } return data, err } +func (c *Config) YAML() ([]byte, error) { + m, err := c.Map() + if err != nil { + return nil, err + } + + var buf bytes.Buffer + var enc = yaml.NewEncoder(&buf) + enc.SetIndent(2) + err = enc.Encode(m) + return buf.Bytes(), err +} + type Stash map[string]interface{} func loadStash(config []byte) (Stash, error) { @@ -367,10 +408,26 @@ func loadExchangeStrategies(config *Config, stash Stash) (err error) { var mounts []string if val, ok := configStash["on"]; ok { - if values, ok := val.([]string); ok { - mounts = append(mounts, values...) - } else if str, ok := val.(string); ok { - mounts = append(mounts, str) + switch tv := val.(type) { + + case []string: + mounts = append(mounts, tv...) + + case string: + mounts = append(mounts, tv) + + case []interface{}: + for _, f := range tv { + s, ok := f.(string) + if !ok { + return fmt.Errorf("%+v (%T) is not a string", f, f) + } + + mounts = append(mounts, s) + } + + default: + return fmt.Errorf("unexpected mount type: %T value: %+v", val, val) } } diff --git a/pkg/bbgo/config_test.go b/pkg/bbgo/config_test.go index 347708d8b..75e4a73cb 100644 --- a/pkg/bbgo/config_test.go +++ b/pkg/bbgo/config_test.go @@ -2,9 +2,11 @@ package bbgo import ( "context" + "io/ioutil" "testing" "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" ) func init() { @@ -62,16 +64,16 @@ func TestLoadConfig(t *testing.T) { wantErr: false, f: func(t *testing.T, config *Config) { assert.Len(t, config.ExchangeStrategies, 1) - assert.Equal(t, config.ExchangeStrategies, []ExchangeStrategyMount{{ + assert.Equal(t, []ExchangeStrategyMount{{ Mounts: []string{"binance"}, Strategy: &TestStrategy{ Symbol: "BTCUSDT", Interval: "1m", BaseQuantity: 0.1, - MaxAssetQuantity: 0, + MaxAssetQuantity: 1.1, MinDropPercentage: -0.05, }, - }}) + }}, config.ExchangeStrategies) m, err := config.Map() assert.NoError(t, err) @@ -108,12 +110,30 @@ func TestLoadConfig(t *testing.T) { "symbol": "BTCUSDT", "baseQuantity": 0.1, "interval": "1m", - "maxAssetQuantity": 0.0, + "maxAssetQuantity": 1.1, "minDropPercentage": -0.05, }, }, }, }, m) + + yamlText, err := config.YAML() + assert.NoError(t, err) + + yamlTextSource, err := ioutil.ReadFile("testdata/strategy.yaml") + assert.NoError(t, err) + + var sourceMap map[string]interface{} + err = yaml.Unmarshal(yamlTextSource, &sourceMap) + assert.NoError(t, err) + delete(sourceMap, "build") + + var actualMap map[string]interface{} + err = yaml.Unmarshal(yamlText, &actualMap) + assert.NoError(t, err) + delete(actualMap, "build") + + assert.Equal(t, sourceMap, actualMap) }, }, diff --git a/pkg/bbgo/testdata/strategy.yaml b/pkg/bbgo/testdata/strategy.yaml index a40c3bae7..c1ade5564 100644 --- a/pkg/bbgo/testdata/strategy.yaml +++ b/pkg/bbgo/testdata/strategy.yaml @@ -3,16 +3,15 @@ sessions: max: exchange: max envVarPrefix: MAX_ - binance: exchange: binance envVarPrefix: BINANCE_ exchangeStrategies: -- on: binance +- on: ["binance"] test: symbol: "BTCUSDT" interval: "1m" baseQuantity: 0.1 minDropPercentage: -0.05 - + maxAssetQuantity: 1.1