mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
improve config loader
This commit is contained in:
parent
4ee10de40f
commit
324a493aad
105
pkg/config/loader.go
Normal file
105
pkg/config/loader.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ExchangeStrategies []bbgo.SingleExchangeStrategy
|
||||
CrossExchangeStrategies []bbgo.CrossExchangeStrategy
|
||||
}
|
||||
|
||||
type Stash map[string]interface{}
|
||||
|
||||
func loadStash(configFile string) (Stash, error) {
|
||||
config, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stash := make(Stash)
|
||||
if err := yaml.Unmarshal(config, stash); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stash, err
|
||||
}
|
||||
|
||||
func Load(configFile string) (*Config, error) {
|
||||
var config Config
|
||||
|
||||
stash, err := loadStash(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
strategies, err := loadExchangeStrategies(stash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.ExchangeStrategies = strategies
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func loadExchangeStrategies(stash Stash) (strategies []bbgo.SingleExchangeStrategy, err error) {
|
||||
exchangeStrategiesConf, ok := stash["exchangeStrategies"]
|
||||
if !ok {
|
||||
return nil, errors.New("exchangeStrategies is not defined")
|
||||
}
|
||||
|
||||
list, ok := exchangeStrategiesConf.([]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("exchangeStrategies should be a list")
|
||||
}
|
||||
|
||||
for _, entry := range list {
|
||||
configStash, ok := entry.(Stash)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("strategy config should be a map, given: %T %+v", entry, entry)
|
||||
}
|
||||
|
||||
for id, conf := range configStash {
|
||||
// look up the real struct type
|
||||
if st, ok := bbgo.LoadedExchangeStrategies[id]; ok {
|
||||
val, err := reUnmarshal(conf, st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
strategies = append(strategies, val.(bbgo.SingleExchangeStrategy))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strategies, nil
|
||||
}
|
||||
|
||||
func reUnmarshal(conf interface{}, tpe interface{}) (interface{}, error) {
|
||||
// get the type "*Strategy"
|
||||
rt := reflect.TypeOf(tpe)
|
||||
|
||||
// allocate new object from the given type
|
||||
val := reflect.New(rt)
|
||||
|
||||
// now we have &(*Strategy) -> **Strategy
|
||||
valRef := val.Interface()
|
||||
|
||||
plain, err := json.Marshal(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(plain, valRef); err != nil {
|
||||
return nil, errors.Wrapf(err, "json parsing error, given payload: %s", plain)
|
||||
}
|
||||
|
||||
return val.Elem().Interface(), nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package loader
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -32,18 +32,21 @@ func TestLoadStrategies(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
strategies, err := LoadExchangeStrategies(tt.args.configFile)
|
||||
config, err := Load(tt.args.configFile)
|
||||
if err != nil {
|
||||
t.Errorf("LoadExchangeStrategies() error = %v", err)
|
||||
t.Errorf("Load() error = %v", err)
|
||||
return
|
||||
} else {
|
||||
if tt.wantErr {
|
||||
t.Errorf("LoadExchangeStrategies() error = %v, wantErr %v", err, tt.wantErr)
|
||||
t.Errorf("Load() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("%+v", strategies[0])
|
||||
assert.NotNil(t, config)
|
||||
assert.Len(t, config.ExchangeStrategies, tt.length)
|
||||
|
||||
assert.Len(t, strategies, tt.length)
|
||||
t.Logf("%+v", config.ExchangeStrategies[0])
|
||||
})
|
||||
}
|
||||
}
|
16
pkg/config/testdata/strategy.yaml
vendored
Normal file
16
pkg/config/testdata/strategy.yaml
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
sessions:
|
||||
max:
|
||||
exchange: max
|
||||
keyVar: MAX_API_KEY
|
||||
secretVar: MAX_API_SECRET
|
||||
binance:
|
||||
exchange: binance
|
||||
keyVar: BINANCE_API_KEY
|
||||
secretVar: BINANCE_API_SECRET
|
||||
exchangeStrategies:
|
||||
- buyandhold:
|
||||
symbol: "BTCUSDT"
|
||||
interval: "1m"
|
||||
baseQuantity: 0.1
|
||||
minDropPercentage: -0.05
|
|
@ -1,76 +0,0 @@
|
|||
package loader
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
)
|
||||
|
||||
type Stash map[string]interface{}
|
||||
|
||||
func Load(configFile string) (Stash, error) {
|
||||
config, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stash := make(Stash)
|
||||
if err := yaml.Unmarshal(config, stash); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stash, err
|
||||
}
|
||||
|
||||
func LoadExchangeStrategies(configFile string) (strategies []bbgo.SingleExchangeStrategy, err error) {
|
||||
stash, err := Load(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exchangeStrategiesConf, ok := stash["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.LoadedExchangeStrategies[id]; ok {
|
||||
// get the type "*Strategy"
|
||||
rt := reflect.TypeOf(st)
|
||||
val := reflect.New(rt)
|
||||
|
||||
// now we have &(*Strategy) -> **Strategy
|
||||
valRef := val.Interface()
|
||||
|
||||
plain, err := json.Marshal(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(plain, valRef); err != nil {
|
||||
return nil, errors.Wrapf(err, "json parsing error, given payload: %s", plain)
|
||||
}
|
||||
|
||||
strategies = append(strategies, val.Elem().Interface().(bbgo.SingleExchangeStrategy))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strategies, nil
|
||||
}
|
7
pkg/loader/testdata/strategy.yaml
vendored
7
pkg/loader/testdata/strategy.yaml
vendored
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
exchangeStrategies:
|
||||
- buyandhold:
|
||||
symbol: "BTCUSDT"
|
||||
interval: "1m"
|
||||
baseQuantity: 0.1
|
||||
minDropPercentage: -0.05
|
Loading…
Reference in New Issue
Block a user