improve legacy state handling and move fnv

This commit is contained in:
c9s 2022-05-05 14:39:29 +08:00
parent 7378c63cb7
commit 019e6a2a88
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
5 changed files with 42 additions and 57 deletions

View File

@ -8,14 +8,13 @@ import (
"time" "time"
"github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/indicator"
"github.com/c9s/bbgo/pkg/util"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/exchange/max"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/service"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
) )
@ -37,9 +36,12 @@ func init() {
bbgo.RegisterStrategy(ID, &Strategy{}) bbgo.RegisterStrategy(ID, &Strategy{})
} }
// Deprecated: State is deprecated, please use the persistence tag
type State struct { type State struct {
// Deprecated: position is deprecated, please define the Position field in the strategy struct directly. // Deprecated: Position is deprecated, please define the Position field in the strategy struct directly.
Position *types.Position `json:"position,omitempty"` Position *types.Position `json:"position,omitempty"`
// Deprecated: ProfitStats is deprecated, please define the ProfitStats field in the strategy struct directly.
ProfitStats types.ProfitStats `json:"profitStats,omitempty"` ProfitStats types.ProfitStats `json:"profitStats,omitempty"`
} }
@ -148,8 +150,9 @@ type Strategy struct {
state *State state *State
// TODO: we're moving position from state to outside // persistence fields
Position *types.Position `json:"position,omitempty" persistence:"position"` Position *types.Position `json:"position,omitempty" persistence:"position"`
ProfitStats *types.ProfitStats `json:"profitStats,omitempty" persistence:"profit_stats"`
activeMakerOrders *bbgo.LocalActiveOrderBook activeMakerOrders *bbgo.LocalActiveOrderBook
orderStore *bbgo.OrderStore orderStore *bbgo.OrderStore
@ -173,6 +176,10 @@ func (s *Strategy) ID() string {
return ID return ID
} }
func (s *Strategy) InstanceID() string {
return fmt.Sprintf("%s:%s", ID, s.Symbol)
}
func (s *Strategy) Initialize() error { func (s *Strategy) Initialize() error {
return s.SmartStops.InitializeStopControllers(s.Symbol) return s.SmartStops.InitializeStopControllers(s.Symbol)
} }
@ -264,14 +271,6 @@ func (s *Strategy) Suspend(ctx context.Context) error {
} }
s.tradeCollector.Process() s.tradeCollector.Process()
// Save state
if err := s.SaveState(); err != nil {
log.WithError(err).Errorf("can not save state: %+v", s.state)
} else {
log.Infof("%s position is saved.", s.Symbol)
}
return nil return nil
} }
@ -292,36 +291,21 @@ func (s *Strategy) EmergencyStop(ctx context.Context) error {
return err return err
} }
func (s *Strategy) SaveState() error { func (s *Strategy) newProfitStats() *types.ProfitStats {
if err := s.Persistence.Save(s.state, ID, s.Symbol, stateKey); err != nil { return &types.ProfitStats{
return err Symbol: s.Market.Symbol,
BaseCurrency: s.Market.BaseCurrency,
QuoteCurrency: s.Market.QuoteCurrency,
AccumulatedSince: time.Now().Unix(),
} }
log.Infof("state is saved => %+v", s.state)
return nil
} }
func (s *Strategy) LoadState() error { func (s *Strategy) LoadState() error {
var state State var state State
// load position // load position
if err := s.Persistence.Load(&state, ID, s.Symbol, stateKey); err != nil { if err := s.Persistence.Load(&state, ID, s.Symbol, stateKey); err == nil {
if err != service.ErrPersistenceNotExists {
return err
}
s.state = &State{}
} else {
s.state = &state s.state = &state
log.Infof("state is restored: %+v", s.state)
}
// init profit states
s.state.ProfitStats.Symbol = s.Market.Symbol
s.state.ProfitStats.BaseCurrency = s.Market.BaseCurrency
s.state.ProfitStats.QuoteCurrency = s.Market.QuoteCurrency
if s.state.ProfitStats.AccumulatedSince == 0 {
s.state.ProfitStats.AccumulatedSince = time.Now().Unix()
} }
return nil return nil
@ -566,10 +550,6 @@ func (s *Strategy) adjustOrderQuantity(submitOrder types.SubmitOrder) types.Subm
return submitOrder return submitOrder
} }
func (s *Strategy) InstanceID() string {
return fmt.Sprintf("%s-%s", ID, s.Symbol)
}
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error { func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
// StrategyController // StrategyController
s.status = types.StrategyStatusRunning s.status = types.StrategyStatusRunning
@ -601,7 +581,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
// calculate group id for orders // calculate group id for orders
instanceID := s.InstanceID() instanceID := s.InstanceID()
s.groupID = max.GenerateGroupID(instanceID) s.groupID = util.FNV32(instanceID)
log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID) log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID)
// restore state // restore state
@ -612,13 +592,24 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
// If position is nil, we need to allocate a new position for calculation // If position is nil, we need to allocate a new position for calculation
if s.Position == nil { if s.Position == nil {
// fallback to the legacy position struct in the state // fallback to the legacy position struct in the state
if s.state.Position != nil { if s.state != nil && s.state.Position != nil {
s.Position = s.state.Position s.Position = s.state.Position
} else { } else {
s.Position = types.NewPositionFromMarket(s.Market) s.Position = types.NewPositionFromMarket(s.Market)
} }
} }
if s.ProfitStats == nil {
if s.state != nil {
// copy stats
p2 := s.state.ProfitStats
s.ProfitStats = &p2
} else {
s.ProfitStats = s.newProfitStats()
}
}
// Always update the position fields // Always update the position fields
s.Position.Strategy = ID s.Position.Strategy = ID
s.Position.StrategyInstanceID = instanceID s.Position.StrategyInstanceID = instanceID
@ -640,7 +631,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
} }
s.Notifiability.Notify(trade) s.Notifiability.Notify(trade)
s.state.ProfitStats.AddTrade(trade) s.ProfitStats.AddTrade(trade)
if profit.Compare(fixedpoint.Zero) == 0 { if profit.Compare(fixedpoint.Zero) == 0 {
s.Environment.RecordPosition(s.Position, trade, nil) s.Environment.RecordPosition(s.Position, trade, nil)
@ -651,8 +642,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
p.StrategyInstanceID = instanceID p.StrategyInstanceID = instanceID
s.Notify(&p) s.Notify(&p)
s.state.ProfitStats.AddProfit(p) s.ProfitStats.AddProfit(p)
s.Notify(&s.state.ProfitStats) s.Notify(&s.ProfitStats)
s.Environment.RecordPosition(s.Position, trade, &p) s.Environment.RecordPosition(s.Position, trade, &p)
} }
@ -726,10 +717,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
} }
s.tradeCollector.Process() s.tradeCollector.Process()
if err := s.SaveState(); err != nil {
log.WithError(err).Errorf("can not save state: %+v", s.state)
}
}) })
return nil return nil

View File

@ -9,10 +9,10 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/exchange/max"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/service" "github.com/c9s/bbgo/pkg/service"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
"github.com/c9s/bbgo/pkg/util"
) )
const ID = "grid" const ID = "grid"
@ -586,7 +586,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
} }
instanceID := s.InstanceID() instanceID := s.InstanceID()
s.groupID = max.GenerateGroupID(instanceID) s.groupID = util.FNV32(instanceID)
log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID) log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID)
if err := s.LoadState(); err != nil { if err := s.LoadState(); err != nil {

View File

@ -11,7 +11,6 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/exchange/max"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/service" "github.com/c9s/bbgo/pkg/service"
"github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/types"
@ -232,7 +231,7 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se
s.tradingSession.UserDataStream.OnTradeUpdate(s.handleTradeUpdate) s.tradingSession.UserDataStream.OnTradeUpdate(s.handleTradeUpdate)
instanceID := fmt.Sprintf("%s-%s", ID, s.Symbol) instanceID := fmt.Sprintf("%s-%s", ID, s.Symbol)
s.groupID = max.GenerateGroupID(instanceID) s.groupID = util.FNV32(instanceID)
log.Infof("using group id %d from fnv32(%s)", s.groupID, instanceID) log.Infof("using group id %d from fnv32(%s)", s.groupID, instanceID)
go func() { go func() {

View File

@ -11,7 +11,6 @@ import (
"golang.org/x/time/rate" "golang.org/x/time/rate"
"github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/exchange/max"
"github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/indicator"
"github.com/c9s/bbgo/pkg/service" "github.com/c9s/bbgo/pkg/service"
@ -710,7 +709,7 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
// restore state // restore state
instanceID := fmt.Sprintf("%s-%s", ID, s.Symbol) instanceID := fmt.Sprintf("%s-%s", ID, s.Symbol)
s.groupID = max.GenerateGroupID(instanceID) s.groupID = util.FNV32(instanceID)
log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID) log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID)
if err := s.LoadState(); err != nil { if err := s.LoadState(); err != nil {

View File

@ -1,8 +1,8 @@
package max package util
import "hash/fnv" import "hash/fnv"
func GenerateGroupID(s string) uint32 { func FNV32(s string) uint32 {
h := fnv.New32a() h := fnv.New32a()
h.Write([]byte(s)) h.Write([]byte(s))
return h.Sum32() return h.Sum32()