mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 08:45:16 +00:00
dynamic: add CallStructFieldsMethod for map struct field call
Signed-off-by: c9s <yoanlin93@gmail.com>
This commit is contained in:
parent
527070d13d
commit
e2ab363e64
|
@ -1,10 +1,9 @@
|
||||||
package bbgo
|
package bbgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/dynamic"
|
"github.com/c9s/bbgo/pkg/dynamic"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExitMethod struct {
|
type ExitMethod struct {
|
||||||
|
@ -16,34 +15,29 @@ type ExitMethod struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ExitMethod) Subscribe(session *ExchangeSession) {
|
func (m *ExitMethod) Subscribe(session *ExchangeSession) {
|
||||||
// TODO: pull out this implementation as a simple function to reflect.go
|
if err := dynamic.CallStructFieldsMethod(m, "Subscribe", session); err != nil {
|
||||||
rv := reflect.ValueOf(m)
|
panic(errors.Wrap(err, "dynamic call failed"))
|
||||||
rt := reflect.TypeOf(m)
|
|
||||||
|
|
||||||
rv = rv.Elem()
|
|
||||||
rt = rt.Elem()
|
|
||||||
infType := reflect.TypeOf((*types.Subscriber)(nil)).Elem()
|
|
||||||
|
|
||||||
argValues := dynamic.ToReflectValues(session)
|
|
||||||
for i := 0; i < rt.NumField(); i++ {
|
|
||||||
fieldType := rt.Field(i)
|
|
||||||
if fieldType.Type.Implements(infType) {
|
|
||||||
method := rv.Field(i).MethodByName("Subscribe")
|
|
||||||
method.Call(argValues)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ExitMethod) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
|
func (m *ExitMethod) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
|
||||||
if m.ProtectiveStopLoss != nil {
|
if m.ProtectiveStopLoss != nil {
|
||||||
m.ProtectiveStopLoss.Bind(session, orderExecutor)
|
m.ProtectiveStopLoss.Bind(session, orderExecutor)
|
||||||
} else if m.RoiStopLoss != nil {
|
}
|
||||||
|
|
||||||
|
if m.RoiStopLoss != nil {
|
||||||
m.RoiStopLoss.Bind(session, orderExecutor)
|
m.RoiStopLoss.Bind(session, orderExecutor)
|
||||||
} else if m.RoiTakeProfit != nil {
|
}
|
||||||
|
|
||||||
|
if m.RoiTakeProfit != nil {
|
||||||
m.RoiTakeProfit.Bind(session, orderExecutor)
|
m.RoiTakeProfit.Bind(session, orderExecutor)
|
||||||
} else if m.LowerShadowTakeProfit != nil {
|
}
|
||||||
|
|
||||||
|
if m.LowerShadowTakeProfit != nil {
|
||||||
m.LowerShadowTakeProfit.Bind(session, orderExecutor)
|
m.LowerShadowTakeProfit.Bind(session, orderExecutor)
|
||||||
} else if m.CumulatedVolumeTakeProfit != nil {
|
}
|
||||||
|
|
||||||
|
if m.CumulatedVolumeTakeProfit != nil {
|
||||||
m.CumulatedVolumeTakeProfit.Bind(session, orderExecutor)
|
m.CumulatedVolumeTakeProfit.Bind(session, orderExecutor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
41
pkg/dynamic/call.go
Normal file
41
pkg/dynamic/call.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package dynamic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CallStructFieldsMethod iterates field from the given struct object
|
||||||
|
// check if the field object implements the interface, if it's implemented, then we call a specific method
|
||||||
|
func CallStructFieldsMethod(m interface{}, method string, args ...interface{}) error {
|
||||||
|
rv := reflect.ValueOf(m)
|
||||||
|
rt := reflect.TypeOf(m)
|
||||||
|
|
||||||
|
if rt.Kind() != reflect.Ptr {
|
||||||
|
return errors.New("the given object needs to be a pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = rv.Elem()
|
||||||
|
rt = rt.Elem()
|
||||||
|
|
||||||
|
if rt.Kind() != reflect.Struct {
|
||||||
|
return errors.New("the given object needs to be struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
argValues := ToReflectValues(args...)
|
||||||
|
for i := 0; i < rt.NumField(); i++ {
|
||||||
|
fieldType := rt.Field(i)
|
||||||
|
|
||||||
|
// skip non-exported fields
|
||||||
|
if !fieldType.IsExported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := fieldType.Type.MethodByName(method); ok {
|
||||||
|
refMethod := rv.Field(i).MethodByName(method)
|
||||||
|
refMethod.Call(argValues)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
29
pkg/dynamic/call_test.go
Normal file
29
pkg/dynamic/call_test.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package dynamic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type callTest struct {
|
||||||
|
ChildCall1 *childCall1
|
||||||
|
ChildCall2 *childCall2
|
||||||
|
}
|
||||||
|
|
||||||
|
type childCall1 struct{}
|
||||||
|
|
||||||
|
func (c *childCall1) Subscribe(a int) {}
|
||||||
|
|
||||||
|
type childCall2 struct{}
|
||||||
|
|
||||||
|
func (c *childCall2) Subscribe(a int) {}
|
||||||
|
|
||||||
|
func TestCallStructFieldsMethod(t *testing.T) {
|
||||||
|
c := &callTest{
|
||||||
|
ChildCall1: &childCall1{},
|
||||||
|
ChildCall2: &childCall2{},
|
||||||
|
}
|
||||||
|
err := CallStructFieldsMethod(c, "Subscribe", 10)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
type Subscriber interface {
|
|
||||||
Subscribe()
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user