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"
"github.com/c9s/bbgo/pkg/cmd/cmdutil"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/interact"
"github.com/c9s/bbgo/pkg/notifier/slacknotifier"
"github.com/c9s/bbgo/pkg/notifier/telegramnotifier"
@ -596,16 +597,21 @@ func (environ *Environment) RecordPosition(position *types.Position, trade types
position.StrategyInstanceID = profit.StrategyInstanceID
}
if err := environ.PositionService.Insert(position, trade, profit.Profit); err != nil {
log.WithError(err).Errorf("can not insert position record")
}
if profit != nil {
if err := environ.PositionService.Insert(position, trade, profit.Profit); err != nil {
log.WithError(err).Errorf("can not insert position record")
}
if err := environ.ProfitService.Insert(*profit); err != nil {
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:
// 1) we are not using sync
// 2) and not sync-ing trades from the user data stream

View File

@ -23,7 +23,7 @@ type TradeCollector struct {
doneTrades map[types.TradeKey]struct{}
recoverCallbacks []func(trade types.Trade)
tradeCallbacks []func(trade types.Trade)
tradeCallbacks []func(trade types.Trade, profit, netProfit fixedpoint.Value)
positionUpdateCallbacks []func(position *types.Position)
profitCallbacks []func(trade types.Trade, profit, netProfit fixedpoint.Value)
}
@ -108,10 +108,10 @@ func (c *TradeCollector) Process() bool {
if c.orderStore.Exists(trade.OrderID) {
c.doneTrades[key] = struct{}{}
if profit, netProfit, madeProfit := c.position.AddTrade(trade); madeProfit {
c.EmitTrade(trade)
c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
c.EmitProfit(trade, profit, netProfit)
} else {
c.EmitTrade(trade)
c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
}
positionChanged = true
return true
@ -139,10 +139,10 @@ func (c *TradeCollector) processTrade(trade types.Trade) bool {
}
if profit, netProfit, madeProfit := c.position.AddTrade(trade); madeProfit {
c.EmitTrade(trade)
c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
c.EmitProfit(trade, profit, netProfit)
} else {
c.EmitTrade(trade)
c.EmitTrade(trade, fixedpoint.Zero, fixedpoint.Zero)
}
c.EmitPositionUpdate(c.position)
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)
}
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 {
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.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.state.Position, s.orderStore)
s.tradeCollector.OnProfit(func(trade types.Trade, profit fixedpoint.Value, 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.tradeCollector.OnProfit(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
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.state.ProfitStats.AddTrade(trade)
s.Environment.RecordPosition(s.state.Position, trade, nil)
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.state.ProfitStats.AddProfit(p)
s.Notify(&p)
s.Environment.RecordPosition(s.state.Position, trade, &p)
}
})
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.OnTrade(func(trade types.Trade) {
s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
s.Notifiability.Notify(trade)
s.state.ProfitStats.AddTrade(trade)
})

View File

@ -38,6 +38,7 @@ type Strategy struct {
*bbgo.Graceful
*bbgo.Notifiability
*bbgo.Persistence
Environment *bbgo.Environment
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)
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.tradeCollector.OnTrade(func(trade types.Trade) {
s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) {
c := trade.PositionChange()
if trade.Exchange == s.sourceSession.ExchangeName {
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)
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 {
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.Notifiability.Notify(position)
})