-
-
Notifications
You must be signed in to change notification settings - Fork 296
/
profit_stats_tracker.go
96 lines (74 loc) · 2.65 KB
/
profit_stats_tracker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package report
import (
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/core"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
type ProfitStatsTracker struct {
types.IntervalWindow
// Accumulated profit report
AccumulatedProfitReport *AccumulatedProfitReport `json:"accumulatedProfitReport"`
Market types.Market
ProfitStatsSlice []*types.ProfitStats
CurrentProfitStats **types.ProfitStats
tradeStats *types.TradeStats
}
func (p *ProfitStatsTracker) Subscribe(session *bbgo.ExchangeSession, symbol string) {
session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{Interval: p.Interval})
}
// InitLegacy is for backward capability. ps is the ProfitStats of the strategy, Market is the strategy Market
func (p *ProfitStatsTracker) InitLegacy(market types.Market, ps **types.ProfitStats, ts *types.TradeStats) {
p.Market = market
if *ps == nil {
*ps = types.NewProfitStats(p.Market)
}
p.tradeStats = ts
p.CurrentProfitStats = ps
p.ProfitStatsSlice = append(p.ProfitStatsSlice, *ps)
if p.AccumulatedProfitReport != nil {
p.AccumulatedProfitReport.Initialize(p.Market.Symbol, p.Interval, p.Window)
}
}
// Init initialize the tracker with the given Market
func (p *ProfitStatsTracker) Init(market types.Market, ts *types.TradeStats) {
ps := types.NewProfitStats(p.Market)
p.InitLegacy(market, &ps, ts)
}
func (p *ProfitStatsTracker) Bind(session *bbgo.ExchangeSession, tradeCollector *core.TradeCollector) {
tradeCollector.OnProfit(func(trade types.Trade, profit *types.Profit) {
if profit == nil {
return
}
p.AddProfit(*profit)
})
tradeCollector.OnTrade(func(trade types.Trade, profit fixedpoint.Value, netProfit fixedpoint.Value) {
p.AddTrade(trade)
})
// Rotate profitStats slice
session.MarketDataStream.OnKLineClosed(types.KLineWith(p.Market.Symbol, p.Interval, func(kline types.KLine) {
p.Rotate()
}))
}
// Rotate the tracker to make a new ProfitStats to record the profits
func (p *ProfitStatsTracker) Rotate() {
// Update report
if p.AccumulatedProfitReport != nil {
p.AccumulatedProfitReport.Rotate(*p.CurrentProfitStats, p.tradeStats)
}
*p.CurrentProfitStats = types.NewProfitStats(p.Market)
p.ProfitStatsSlice = append(p.ProfitStatsSlice, *p.CurrentProfitStats)
// Truncate
if len(p.ProfitStatsSlice) > p.Window {
p.ProfitStatsSlice = p.ProfitStatsSlice[len(p.ProfitStatsSlice)-p.Window:]
}
}
func (p *ProfitStatsTracker) AddProfit(profit types.Profit) {
(*p.CurrentProfitStats).AddProfit(profit)
}
func (p *ProfitStatsTracker) AddTrade(trade types.Trade) {
(*p.CurrentProfitStats).AddTrade(trade)
if p.AccumulatedProfitReport != nil {
p.AccumulatedProfitReport.AddTrade(trade)
}
}