rewrite trade profit handling

This commit is contained in:
c9s 2022-03-11 21:27:45 +08:00
parent 6fec30d79c
commit 5db4e11167
6 changed files with 51 additions and 40 deletions

View File

@ -22,6 +22,7 @@ import (
"gopkg.in/tucnak/telebot.v2" "gopkg.in/tucnak/telebot.v2"
"github.com/c9s/bbgo/pkg/cmd/cmdutil" "github.com/c9s/bbgo/pkg/cmd/cmdutil"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/interact" "github.com/c9s/bbgo/pkg/interact"
"github.com/c9s/bbgo/pkg/notifier/slacknotifier" "github.com/c9s/bbgo/pkg/notifier/slacknotifier"
"github.com/c9s/bbgo/pkg/notifier/telegramnotifier" "github.com/c9s/bbgo/pkg/notifier/telegramnotifier"
@ -596,15 +597,20 @@ func (environ *Environment) RecordPosition(position *types.Position, trade types
position.StrategyInstanceID = profit.StrategyInstanceID position.StrategyInstanceID = profit.StrategyInstanceID
} }
if profit != nil {
if err := environ.PositionService.Insert(position, trade, profit.Profit); err != nil { if err := environ.PositionService.Insert(position, trade, profit.Profit); err != nil {
log.WithError(err).Errorf("can not insert position record") log.WithError(err).Errorf("can not insert position record")
} }
if profit != nil {
if err := environ.ProfitService.Insert(*profit); err != nil { if err := environ.ProfitService.Insert(*profit); err != nil {
log.WithError(err).Errorf("can not insert profit record: %+v", profit) log.WithError(err).Errorf("can not insert profit record: %+v", profit)
} }
} else {
if err := environ.PositionService.Insert(position, trade, fixedpoint.Zero); err != nil {
log.WithError(err).Errorf("can not insert position record")
} }
}
// if: // if:
// 1) we are not using sync // 1) we are not using sync

View File

@ -23,7 +23,7 @@ type TradeCollector struct {
doneTrades map[types.TradeKey]struct{} doneTrades map[types.TradeKey]struct{}
recoverCallbacks []func(trade types.Trade) recoverCallbacks []func(trade types.Trade)
tradeCallbacks []func(trade types.Trade) tradeCallbacks []func(trade types.Trade, profit, netProfit fixedpoint.Value)
positionUpdateCallbacks []func(position *types.Position) positionUpdateCallbacks []func(position *types.Position)
profitCallbacks []func(trade types.Trade, profit, netProfit fixedpoint.Value) profitCallbacks []func(trade types.Trade, profit, netProfit fixedpoint.Value)
} }
@ -108,10 +108,10 @@ func (c *TradeCollector) Process() bool {
if c.orderStore.Exists(trade.OrderID) { if c.orderStore.Exists(trade.OrderID) {
c.doneTrades[key] = struct{}{} c.doneTrades[key] = struct{}{}
if profit, netProfit, madeProfit := c.position.AddTrade(trade); madeProfit { if profit, netProfit, madeProfit := c.position.AddTrade(trade); madeProfit {
c.EmitTrade(trade) c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
c.EmitProfit(trade, profit, netProfit) c.EmitProfit(trade, profit, netProfit)
} else { } else {
c.EmitTrade(trade) c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
} }
positionChanged = true positionChanged = true
return true return true
@ -139,10 +139,10 @@ func (c *TradeCollector) processTrade(trade types.Trade) bool {
} }
if profit, netProfit, madeProfit := c.position.AddTrade(trade); madeProfit { if profit, netProfit, madeProfit := c.position.AddTrade(trade); madeProfit {
c.EmitTrade(trade) c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
c.EmitProfit(trade, profit, netProfit) c.EmitProfit(trade, profit, netProfit)
} else { } else {
c.EmitTrade(trade) c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
} }
c.EmitPositionUpdate(c.position) c.EmitPositionUpdate(c.position)
c.doneTrades[key] = struct{}{} c.doneTrades[key] = struct{}{}

View File

@ -17,13 +17,13 @@ func (c *TradeCollector) EmitRecover(trade types.Trade) {
} }
} }
func (c *TradeCollector) OnTrade(cb func(trade types.Trade)) { func (c *TradeCollector) OnTrade(cb func(trade types.Trade, profit fixedpoint.Value, netProfit fixedpoint.Value)) {
c.tradeCallbacks = append(c.tradeCallbacks, cb) c.tradeCallbacks = append(c.tradeCallbacks, cb)
} }
func (c *TradeCollector) EmitTrade(trade types.Trade) { func (c *TradeCollector) EmitTrade(trade types.Trade, profit fixedpoint.Value, netProfit fixedpoint.Value) {
for _, cb := range c.tradeCallbacks { for _, cb := range c.tradeCallbacks {
cb(trade) cb(trade, profit, netProfit)
} }
} }

View File

@ -566,22 +566,26 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.orderStore.BindStream(session.UserDataStream) s.orderStore.BindStream(session.UserDataStream)
s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.state.Position, s.orderStore) s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.state.Position, s.orderStore)
s.tradeCollector.OnProfit(func(trade types.Trade, profit fixedpoint.Value, netProfit fixedpoint.Value) { s.tradeCollector.OnProfit(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
log.Infof("generated profit: %v", profit)
p := s.state.Position.NewProfit(trade, profit, netProfit)
p.Strategy = ID
p.StrategyInstanceID = instanceID
s.Environment.RecordPosition(s.state.Position, trade, &p)
s.state.ProfitStats.AddProfit(p)
s.Notify(&p)
s.Notify(&s.state.ProfitStats) s.Notify(&s.state.ProfitStats)
}) })
s.tradeCollector.OnTrade(func(trade types.Trade) { s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
s.Notifiability.Notify(trade) s.Notifiability.Notify(trade)
s.state.ProfitStats.AddTrade(trade) s.state.ProfitStats.AddTrade(trade)
if profit.Compare(fixedpoint.Zero) == 0 {
s.Environment.RecordPosition(s.state.Position, trade, nil) s.Environment.RecordPosition(s.state.Position, trade, nil)
} else {
log.Infof("%s generated profit: %v", s.Symbol, profit)
p := s.state.Position.NewProfit(trade, profit, netProfit)
p.Strategy = ID
p.StrategyInstanceID = instanceID
s.state.ProfitStats.AddProfit(p)
s.Notify(&p)
s.Environment.RecordPosition(s.state.Position, trade, &p)
}
}) })
s.tradeCollector.OnPositionUpdate(func(position *types.Position) { s.tradeCollector.OnPositionUpdate(func(position *types.Position) {

View File

@ -605,7 +605,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.state.Position, s.orderStore) s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.state.Position, s.orderStore)
s.tradeCollector.OnTrade(func(trade types.Trade) { s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
s.Notifiability.Notify(trade) s.Notifiability.Notify(trade)
s.state.ProfitStats.AddTrade(trade) s.state.ProfitStats.AddTrade(trade)
}) })

View File

@ -38,6 +38,7 @@ type Strategy struct {
*bbgo.Graceful *bbgo.Graceful
*bbgo.Notifiability *bbgo.Notifiability
*bbgo.Persistence *bbgo.Persistence
Environment *bbgo.Environment
Symbol string `json:"symbol"` Symbol string `json:"symbol"`
@ -745,12 +746,12 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.state.Position, s.orderStore) s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.state.Position, s.orderStore)
if s.NotifyTrade { if s.NotifyTrade {
s.tradeCollector.OnTrade(func(trade types.Trade) { s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
s.Notifiability.Notify(trade) s.Notifiability.Notify(trade)
}) })
} }
s.tradeCollector.OnTrade(func(trade types.Trade) { s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
c := trade.PositionChange() c := trade.PositionChange()
if trade.Exchange == s.sourceSession.ExchangeName { if trade.Exchange == s.sourceSession.ExchangeName {
s.state.CoveredPosition = s.state.CoveredPosition.Add(c) s.state.CoveredPosition = s.state.CoveredPosition.Add(c)
@ -758,25 +759,25 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
s.state.ProfitStats.AddTrade(trade) s.state.ProfitStats.AddTrade(trade)
if profit.Compare(fixedpoint.Zero) == 0 {
s.Environment.RecordPosition(s.state.Position, trade, nil)
} else {
log.Infof("%s generated profit: %v", s.Symbol, profit)
p := s.state.Position.NewProfit(trade, profit, netProfit)
p.Strategy = ID
p.StrategyInstanceID = instanceID
s.Notify(&p)
s.state.ProfitStats.AddProfit(p)
s.Environment.RecordPosition(s.state.Position, trade, &p)
}
if err := s.SaveState(); err != nil { if err := s.SaveState(); err != nil {
log.WithError(err).Error("save state error") log.WithError(err).Error("save state error")
} }
}) })
s.tradeCollector.OnProfit(func(trade types.Trade, profit fixedpoint.Value, netProfit fixedpoint.Value) {
p := types.Profit{
Symbol: s.Symbol,
Profit: profit,
NetProfit: netProfit,
QuoteQuantity: trade.QuoteQuantity,
ProfitMargin: profit.Div(trade.QuoteQuantity),
NetProfitMargin: netProfit.Div(trade.QuoteQuantity),
QuoteCurrency: s.state.Position.QuoteCurrency,
BaseCurrency: s.state.Position.BaseCurrency,
TradedAt: trade.Time.Time(),
}
s.state.ProfitStats.AddProfit(p)
s.Notify(&p)
})
s.tradeCollector.OnPositionUpdate(func(position *types.Position) { s.tradeCollector.OnPositionUpdate(func(position *types.Position) {
s.Notifiability.Notify(position) s.Notifiability.Notify(position)
}) })