positionmodifier: move functions into types.Position

This commit is contained in:
Andy Cheng 2022-07-29 14:40:54 +08:00
parent 9588a6f6bd
commit 4bc70820c4
5 changed files with 90 additions and 112 deletions

View File

@ -27,9 +27,9 @@ type closePositionContext struct {
percentage fixedpoint.Value percentage fixedpoint.Value
} }
type updatePositionContext struct { type modifyPositionContext struct {
signature string signature string
updater StrategyPositionUpdater modifier *types.Position
target string target string
value fixedpoint.Value value fixedpoint.Value
} }
@ -40,7 +40,7 @@ type CoreInteraction struct {
exchangeStrategies map[string]SingleExchangeStrategy exchangeStrategies map[string]SingleExchangeStrategy
closePositionContext closePositionContext closePositionContext closePositionContext
updatePositionContext updatePositionContext modifyPositionContext modifyPositionContext
} }
func NewCoreInteraction(environment *Environment, trader *Trader) *CoreInteraction { func NewCoreInteraction(environment *Environment, trader *Trader) *CoreInteraction {
@ -74,6 +74,21 @@ func filterStrategyByInterface(checkInterface interface{}, exchangeStrategies ma
return strategies, found return strategies, found
} }
func filterStrategyByField(fieldName string, fieldType reflect.Type, exchangeStrategies map[string]SingleExchangeStrategy) (strategies map[string]SingleExchangeStrategy, found bool) {
found = false
strategies = make(map[string]SingleExchangeStrategy)
for signature, strategy := range exchangeStrategies {
r := reflect.ValueOf(strategy).Elem()
f := r.FieldByName(fieldName)
if !f.IsZero() && f.Type() == fieldType {
strategies[signature] = strategy
found = true
}
}
return strategies, found
}
func generateStrategyButtonsForm(strategies map[string]SingleExchangeStrategy) [][3]string { func generateStrategyButtonsForm(strategies map[string]SingleExchangeStrategy) [][3]string {
var buttonsForm [][3]string var buttonsForm [][3]string
signatures := getStrategySignatures(strategies) signatures := getStrategySignatures(strategies)
@ -397,14 +412,14 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
}) })
// Position updater // Position updater
i.PrivateCommand("/setposition", "Set Strategy Position", func(reply interact.Reply) error { i.PrivateCommand("/modifyposition", "Modify Strategy Position", func(reply interact.Reply) error {
// it.trader.exchangeStrategies // it.trader.exchangeStrategies
// send symbol options // send symbol options
if strategies, found := filterStrategyByInterface((*StrategyPositionUpdater)(nil), it.exchangeStrategies); found { if strategies, found := filterStrategyByField("Position", reflect.TypeOf(types.NewPosition("", "", "")), it.exchangeStrategies); found {
reply.AddMultipleButtons(generateStrategyButtonsForm(strategies)) reply.AddMultipleButtons(generateStrategyButtonsForm(strategies))
reply.Message("Please choose one strategy") reply.Message("Please choose one strategy")
} else { } else {
reply.Message("No strategy supports StrategyPositionUpdater") reply.Message("No strategy supports Position Modify")
} }
return nil return nil
}).Next(func(signature string, reply interact.Reply) error { }).Next(func(signature string, reply interact.Reply) error {
@ -414,14 +429,16 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
return fmt.Errorf("strategy %s not found", signature) return fmt.Errorf("strategy %s not found", signature)
} }
updater, implemented := strategy.(StrategyPositionUpdater) r := reflect.ValueOf(strategy).Elem()
f := r.FieldByName("Position")
positionModifier, implemented := f.Interface().(*types.Position)
if !implemented { if !implemented {
reply.Message(fmt.Sprintf("Strategy %s does not support StrategyPositionUpdater", signature)) reply.Message(fmt.Sprintf("Strategy %s does not support Position Modify", signature))
return fmt.Errorf("strategy %s does not implement StrategyPositionUpdater", signature) return fmt.Errorf("strategy %s does not implement Position Modify", signature)
} }
it.updatePositionContext.updater = updater it.modifyPositionContext.modifier = positionModifier
it.updatePositionContext.signature = signature it.modifyPositionContext.signature = signature
reply.Message("Please choose what you want to change") reply.Message("Please choose what you want to change")
reply.AddButton("base", "Base", "base") reply.AddButton("base", "Base", "base")
@ -435,13 +452,13 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
return fmt.Errorf("%q is not a valid target string", target) return fmt.Errorf("%q is not a valid target string", target)
} }
it.updatePositionContext.target = target it.modifyPositionContext.target = target
reply.Message("Enter the amount to change") reply.Message("Enter the amount to change")
return nil return nil
}).Next(func(valueStr string, reply interact.Reply) error { }).Next(func(valueStr string, reply interact.Reply) error {
value, err := strconv.ParseFloat(valueStr, 64) value, err := fixedpoint.NewFromString(valueStr)
if err != nil { if err != nil {
reply.Message(fmt.Sprintf("%q is not a valid value string", valueStr)) reply.Message(fmt.Sprintf("%q is not a valid value string", valueStr))
return err return err
@ -451,12 +468,12 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
kc.RemoveKeyboard() kc.RemoveKeyboard()
} }
if it.updatePositionContext.target == "base" { if it.modifyPositionContext.target == "base" {
err = it.updatePositionContext.updater.UpdateBase(value) err = it.modifyPositionContext.modifier.ModifyBase(value)
} else if it.updatePositionContext.target == "quote" { } else if it.modifyPositionContext.target == "quote" {
err = it.updatePositionContext.updater.UpdateQuote(value) err = it.modifyPositionContext.modifier.ModifyQuote(value)
} else if it.updatePositionContext.target == "cost" { } else if it.modifyPositionContext.target == "cost" {
err = it.updatePositionContext.updater.UpdateAverageCost(value) err = it.modifyPositionContext.modifier.ModifyAverageCost(value)
} }
if err != nil { if err != nil {
@ -464,7 +481,7 @@ func (it *CoreInteraction) Commands(i *interact.Interact) {
return err return err
} }
reply.Message(fmt.Sprintf("Position of strategy %s modified.", it.updatePositionContext.signature)) reply.Message(fmt.Sprintf("Position of strategy %s modified.", it.modifyPositionContext.signature))
return nil return nil
}) })
} }

View File

@ -1,46 +0,0 @@
package bbgo
import (
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
//go:generate callbackgen -type PositionUpdater -interface
type PositionUpdater struct {
Position *types.Position
// Callbacks
updateBaseCallbacks []func()
updateQuoteCallbacks []func()
updateAverageCostCallbacks []func()
}
func (s *PositionUpdater) UpdateBase(qty float64) error {
s.Position.Base = fixedpoint.NewFromFloat(qty)
s.EmitUpdateBase()
return nil
}
func (s *PositionUpdater) UpdateQuote(qty float64) error {
s.Position.Quote = fixedpoint.NewFromFloat(qty)
s.EmitUpdateQuote()
return nil
}
func (s *PositionUpdater) UpdateAverageCost(price float64) error {
s.Position.AverageCost = fixedpoint.NewFromFloat(price)
s.EmitUpdateAverageCost()
return nil
}
type StrategyPositionUpdater interface {
UpdateBase(qty float64) error
UpdateQuote(qty float64) error
UpdateAverageCost(price float64) error
}

View File

@ -1,43 +0,0 @@
// Code generated by "callbackgen -type PositionUpdater -interface"; DO NOT EDIT.
package bbgo
import ()
func (s *PositionUpdater) OnUpdateBase(cb func()) {
s.updateBaseCallbacks = append(s.updateBaseCallbacks, cb)
}
func (s *PositionUpdater) EmitUpdateBase() {
for _, cb := range s.updateBaseCallbacks {
cb()
}
}
func (s *PositionUpdater) OnUpdateQuote(cb func()) {
s.updateQuoteCallbacks = append(s.updateQuoteCallbacks, cb)
}
func (s *PositionUpdater) EmitUpdateQuote() {
for _, cb := range s.updateQuoteCallbacks {
cb()
}
}
func (s *PositionUpdater) OnUpdateAverageCost(cb func()) {
s.updateAverageCostCallbacks = append(s.updateAverageCostCallbacks, cb)
}
func (s *PositionUpdater) EmitUpdateAverageCost() {
for _, cb := range s.updateAverageCostCallbacks {
cb()
}
}
type PositionUpdaterEventHub interface {
OnUpdateBase(cb func())
OnUpdateQuote(cb func())
OnUpdateAverageCost(cb func())
}

View File

@ -84,9 +84,6 @@ type Strategy struct {
// StrategyController // StrategyController
bbgo.StrategyController bbgo.StrategyController
// PositionUpdater
bbgo.PositionUpdater
} }
func (s *Strategy) ID() string { func (s *Strategy) ID() string {

View File

@ -59,6 +59,11 @@ type Position struct {
AccumulatedProfit fixedpoint.Value `json:"accumulatedProfit,omitempty" db:"accumulated_profit"` AccumulatedProfit fixedpoint.Value `json:"accumulatedProfit,omitempty" db:"accumulated_profit"`
sync.Mutex sync.Mutex
// Modify position callbacks
modifyBaseCallbacks []func(qty fixedpoint.Value)
modifyQuoteCallbacks []func(qty fixedpoint.Value)
modifyAverageCostCallbacks []func(price fixedpoint.Value)
} }
func (p *Position) CsvHeader() []string { func (p *Position) CsvHeader() []string {
@ -195,6 +200,54 @@ func (p *Position) UnrealizedProfit(price fixedpoint.Value) fixedpoint.Value {
return fixedpoint.Zero return fixedpoint.Zero
} }
// ModifyBase modifies position base quantity with `qty`
func (p *Position) ModifyBase(qty fixedpoint.Value) error {
p.Base = qty
p.EmitModifyBase(qty)
return nil
}
// EmitModifyBase triggers callbacks
func (p *Position) EmitModifyBase(qty fixedpoint.Value) {
for _, cb := range p.modifyBaseCallbacks {
cb(qty)
}
}
// ModifyQuote modifies position quote quantity with `qty`
func (p *Position) ModifyQuote(qty fixedpoint.Value) error {
p.Quote = qty
p.EmitModifyQuote(qty)
return nil
}
// EmitModifyQuote triggers callbacks
func (p *Position) EmitModifyQuote(qty fixedpoint.Value) {
for _, cb := range p.modifyQuoteCallbacks {
cb(qty)
}
}
// ModifyAverageCost modifies position average cost with `price`
func (p *Position) ModifyAverageCost(price fixedpoint.Value) error {
p.AverageCost = price
p.EmitModifyAverageCost(price)
return nil
}
// EmitModifyAverageCost triggers callbacks
func (p *Position) EmitModifyAverageCost(price fixedpoint.Value) {
for _, cb := range p.modifyAverageCostCallbacks {
cb(price)
}
}
type FuturesPosition struct { type FuturesPosition struct {
Symbol string `json:"symbol"` Symbol string `json:"symbol"`
BaseCurrency string `json:"baseCurrency"` BaseCurrency string `json:"baseCurrency"`