mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
fix: move some modify implementation to dynamic
This commit is contained in:
parent
d40b34e4d6
commit
aaa657dcc3
|
@ -325,8 +325,6 @@ type Config struct {
|
||||||
CrossExchangeStrategies []CrossExchangeStrategy `json:"-" yaml:"-"`
|
CrossExchangeStrategies []CrossExchangeStrategy `json:"-" yaml:"-"`
|
||||||
|
|
||||||
PnLReporters []PnLReporterConfig `json:"reportPnL,omitempty" yaml:"reportPnL,omitempty"`
|
PnLReporters []PnLReporterConfig `json:"reportPnL,omitempty" yaml:"reportPnL,omitempty"`
|
||||||
|
|
||||||
ConfigFile string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Map() (map[string]interface{}, error) {
|
func (c *Config) Map() (map[string]interface{}, error) {
|
||||||
|
@ -480,10 +478,6 @@ func Load(configFile string, loadStrategies bool) (*Config, error) {
|
||||||
if err := yaml.Unmarshal(content, &config); err != nil {
|
if err := yaml.Unmarshal(content, &config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.ConfigFile = configFile
|
|
||||||
for _, session := range config.Sessions {
|
|
||||||
session.ConfigPath = config.ConfigFile
|
|
||||||
}
|
|
||||||
|
|
||||||
// for backward compatible
|
// for backward compatible
|
||||||
if config.Build == nil {
|
if config.Build == nil {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/dynamic"
|
||||||
"github.com/c9s/bbgo/pkg/interact"
|
"github.com/c9s/bbgo/pkg/interact"
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -23,37 +23,33 @@ func RegisterModifier(s interface{}) {
|
||||||
RegisterCommand("/modify", "Modify config", func(reply interact.Reply) {
|
RegisterCommand("/modify", "Modify config", func(reply interact.Reply) {
|
||||||
reply.Message("Please choose the field name in config to modify:")
|
reply.Message("Please choose the field name in config to modify:")
|
||||||
mapping = make(map[string]string)
|
mapping = make(map[string]string)
|
||||||
for i := 0; i < val.Type().NumField(); i++ {
|
dynamic.GetModifiableFields(val, func(tagName, name string) {
|
||||||
t := val.Type().Field(i)
|
mapping[tagName] = name
|
||||||
if !t.IsExported() {
|
reply.AddButton(tagName, tagName, tagName)
|
||||||
continue
|
})
|
||||||
}
|
}).Next(func(target string, reply interact.Reply) error {
|
||||||
modifiable := t.Tag.Get("modifiable")
|
|
||||||
if modifiable != "true" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
jsonTag := t.Tag.Get("json")
|
|
||||||
if jsonTag == "" || jsonTag == "-" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name := strings.Split(jsonTag, ",")[0]
|
|
||||||
mapping[name] = t.Name
|
|
||||||
reply.AddButton(name, name, name)
|
|
||||||
}
|
|
||||||
}).Next(func(target string, reply interact.Reply) {
|
|
||||||
targetName = mapping[target]
|
targetName = mapping[target]
|
||||||
field := val.FieldByName(targetName)
|
field, ok := dynamic.GetModifiableField(val, targetName)
|
||||||
|
if !ok {
|
||||||
|
reply.Message(fmt.Sprintf("target %s is not modifiable", targetName))
|
||||||
|
return fmt.Errorf("target %s is not modifiable", targetName)
|
||||||
|
}
|
||||||
currVal = field.Interface()
|
currVal = field.Interface()
|
||||||
if e, err := json.Marshal(currVal); err == nil {
|
if e, err := json.Marshal(currVal); err == nil {
|
||||||
currVal = string(e)
|
currVal = string(e)
|
||||||
}
|
}
|
||||||
reply.Message(fmt.Sprintf("Please enter the new value, current value: %v", currVal))
|
reply.Message(fmt.Sprintf("Please enter the new value, current value: %v", currVal))
|
||||||
|
return nil
|
||||||
}).Next(func(value string, reply interact.Reply) {
|
}).Next(func(value string, reply interact.Reply) {
|
||||||
log.Infof("%s", value)
|
log.Infof("try to modify from %s to %s", currVal, value)
|
||||||
if kc, ok := reply.(interact.KeyboardController); ok {
|
if kc, ok := reply.(interact.KeyboardController); ok {
|
||||||
kc.RemoveKeyboard()
|
kc.RemoveKeyboard()
|
||||||
}
|
}
|
||||||
field := val.FieldByName(targetName)
|
field, ok := dynamic.GetModifiableField(val, targetName)
|
||||||
|
if !ok {
|
||||||
|
reply.Message(fmt.Sprintf("target %s is not modifiable", targetName))
|
||||||
|
return
|
||||||
|
}
|
||||||
x := reflect.New(field.Type())
|
x := reflect.New(field.Type())
|
||||||
xi := x.Interface()
|
xi := x.Interface()
|
||||||
if err := json.Unmarshal([]byte(value), &xi); err != nil {
|
if err := json.Unmarshal([]byte(value), &xi); err != nil {
|
|
@ -40,7 +40,6 @@ type ExchangeSession struct {
|
||||||
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
|
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
|
||||||
Passphrase string `json:"passphrase,omitempty" yaml:"passphrase,omitempty"`
|
Passphrase string `json:"passphrase,omitempty" yaml:"passphrase,omitempty"`
|
||||||
SubAccount string `json:"subAccount,omitempty" yaml:"subAccount,omitempty"`
|
SubAccount string `json:"subAccount,omitempty" yaml:"subAccount,omitempty"`
|
||||||
ConfigPath string
|
|
||||||
|
|
||||||
// Withdrawal is used for enabling withdrawal functions
|
// Withdrawal is used for enabling withdrawal functions
|
||||||
Withdrawal bool `json:"withdrawal,omitempty" yaml:"withdrawal,omitempty"`
|
Withdrawal bool `json:"withdrawal,omitempty" yaml:"withdrawal,omitempty"`
|
||||||
|
|
|
@ -267,7 +267,6 @@ var BacktestCmd = &cobra.Command{
|
||||||
exchangeFromConfig := userConfig.Sessions[name.String()]
|
exchangeFromConfig := userConfig.Sessions[name.String()]
|
||||||
if exchangeFromConfig != nil {
|
if exchangeFromConfig != nil {
|
||||||
session.UseHeikinAshi = exchangeFromConfig.UseHeikinAshi
|
session.UseHeikinAshi = exchangeFromConfig.UseHeikinAshi
|
||||||
session.ConfigPath = exchangeFromConfig.ConfigPath
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package dynamic
|
package dynamic
|
||||||
|
|
||||||
import "reflect"
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
func HasField(rs reflect.Value, fieldName string) (field reflect.Value, ok bool) {
|
func HasField(rs reflect.Value, fieldName string) (field reflect.Value, ok bool) {
|
||||||
field = rs.FieldByName(fieldName)
|
field = rs.FieldByName(fieldName)
|
||||||
|
@ -24,3 +27,39 @@ func LookupSymbolField(rs reflect.Value) (string, bool) {
|
||||||
return field.String(), true
|
return field.String(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used by bbgo/interact_modify.go
|
||||||
|
func GetModifiableFields(val reflect.Value, callback func(tagName, name string)) {
|
||||||
|
for i := 0; i < val.Type().NumField(); i++ {
|
||||||
|
t := val.Type().Field(i)
|
||||||
|
if !t.IsExported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
modifiable := t.Tag.Get("modifiable")
|
||||||
|
if modifiable != "true" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
jsonTag := t.Tag.Get("json")
|
||||||
|
if jsonTag == "" || jsonTag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := strings.Split(jsonTag, ",")[0]
|
||||||
|
callback(name, t.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ZeroValue reflect.Value = reflect.Zero(reflect.TypeOf(0))
|
||||||
|
|
||||||
|
func GetModifiableField(val reflect.Value, name string) (reflect.Value, bool) {
|
||||||
|
field, ok := val.Type().FieldByName(name)
|
||||||
|
if !ok {
|
||||||
|
return ZeroValue, ok
|
||||||
|
}
|
||||||
|
if field.Tag.Get("modifiable") != "true" {
|
||||||
|
return ZeroValue, false
|
||||||
|
}
|
||||||
|
jsonTag := field.Tag.Get("json")
|
||||||
|
if jsonTag == "" || jsonTag == "-" {
|
||||||
|
return ZeroValue, false
|
||||||
|
}
|
||||||
|
return val.FieldByName(name), true
|
||||||
|
}
|
||||||
|
|
37
pkg/dynamic/field_test.go
Normal file
37
pkg/dynamic/field_test.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package dynamic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Strategy struct {
|
||||||
|
Field1 fixedpoint.Value `json:"field1" modifiable:"true"`
|
||||||
|
Field2 float64 `json:"field2"`
|
||||||
|
field3 float64 `json:"field3" modifiable:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetModifiableFields(t *testing.T) {
|
||||||
|
s := Strategy{}
|
||||||
|
val := reflect.ValueOf(s)
|
||||||
|
GetModifiableFields(val, func(tagName, name string) {
|
||||||
|
assert.Equal(t, tagName, "field1")
|
||||||
|
assert.Equal(t, name, "Field1")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetModifiableField(t *testing.T) {
|
||||||
|
s := Strategy{}
|
||||||
|
val := reflect.ValueOf(s)
|
||||||
|
_, ok := GetModifiableField(val, "Field1")
|
||||||
|
assert.True(t, ok)
|
||||||
|
_, ok = GetModifiableField(val, "Field2")
|
||||||
|
assert.False(t, ok)
|
||||||
|
_, ok = GetModifiableField(val, "Field3")
|
||||||
|
assert.False(t, ok)
|
||||||
|
_, ok = GetModifiableField(val, "Random")
|
||||||
|
assert.False(t, ok)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user