implement strategy yaml loader

This commit is contained in:
c9s 2020-10-20 13:52:25 +08:00
parent a08aebaa17
commit 2fbf19455e
8 changed files with 135 additions and 1 deletions

2
go.mod
View File

@ -39,5 +39,5 @@ require (
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
gopkg.in/yaml.v2 v2.3.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c // indirect
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
)

View File

@ -17,6 +17,13 @@ import (
"github.com/c9s/bbgo/pkg/types"
)
var LoadedStrategies = make(map[string]interface{})
func RegisterStrategy(key string, configmap interface{}) {
LoadedStrategies[key] = configmap
}
// Environment presents the real exchange data layer
type Environment struct {
TradeService *service.TradeService

2
pkg/bbgo/loader.go Normal file
View File

@ -0,0 +1,2 @@
package bbgo

2
pkg/bbgo/loader_test.go Normal file
View File

@ -0,0 +1,2 @@
package bbgo

65
pkg/loader/loader.go Normal file
View File

@ -0,0 +1,65 @@
package loader
import (
"encoding/json"
"io/ioutil"
"reflect"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
"github.com/c9s/bbgo/pkg/bbgo"
)
func LoadExchangeStrategies(configFile string) (strategies []bbgo.SingleExchangeStrategy, err error) {
config, err := ioutil.ReadFile(configFile)
if err != nil {
return nil, err
}
conf := make(map[string]interface{})
if err := yaml.Unmarshal(config, conf); err != nil {
return nil, err
}
exchangeStrategiesConf, ok := conf["exchangeStrategies"]
if !ok {
return nil, errors.New("exchangeStrategies is not defined")
}
strategiesConfList, ok := exchangeStrategiesConf.([]interface{})
if !ok {
return nil, errors.New("exchangeStrategies should be a list")
}
for _, strategiesConf := range strategiesConfList {
sConf, ok := strategiesConf.(map[string]interface{})
if !ok {
return nil, errors.New("strategy config should be a map")
}
for id, conf := range sConf {
if st, ok := bbgo.LoadedStrategies[id]; ok {
// get the type "*Strategy"
rt := reflect.TypeOf(st)
val := reflect.New(rt)
// now we have &(*Strategy) -> **Strategy
valinf := val.Interface()
plain, err := json.Marshal(conf)
if err != nil {
return nil, err
}
if err := json.Unmarshal(plain, valinf); err != nil {
return nil, err
}
strategies = append(strategies, val.Elem().Interface().(bbgo.SingleExchangeStrategy))
}
}
}
return strategies, nil
}

48
pkg/loader/loader_test.go Normal file
View File

@ -0,0 +1,48 @@
package loader
import (
"testing"
"github.com/stretchr/testify/assert"
// register the strategies
_ "github.com/c9s/bbgo/pkg/strategy/buyandhold"
)
func TestLoadStrategies(t *testing.T) {
type args struct {
configFile string
}
tests := []struct {
name string
args args
wantErr bool
length int
}{
{
name: "simple",
args: args{
configFile: "testdata/strategy.yaml",
},
wantErr: false,
length: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
strategies, err := LoadExchangeStrategies(tt.args.configFile)
if err != nil {
t.Errorf("LoadExchangeStrategies() error = %v", err)
} else {
if tt.wantErr {
t.Errorf("LoadExchangeStrategies() error = %v, wantErr %v", err, tt.wantErr)
}
}
t.Logf("%+v", strategies[0])
assert.Len(t, strategies, tt.length)
})
}
}

6
pkg/loader/testdata/strategy.yaml vendored Normal file
View File

@ -0,0 +1,6 @@
---
exchangeStrategies:
- buyandhold:
symbol: "BTCUSDT"
interval: "1m"
minDropPercentage: -0.05

View File

@ -13,6 +13,10 @@ import (
"github.com/c9s/bbgo/pkg/util"
)
func init() {
bbgo.RegisterStrategy("buyandhold", &Strategy{})
}
type Strategy struct {
Symbol string `json:"symbol"`
Interval string `json:"interval"`