Skip to content

Commit 335b90a

Browse files
authored
Merge pull request #989 from austin362667/austin362667/irr
strategy:irr: a mean reversion based on box of klines in same direction
2 parents 04855b0 + 6e29359 commit 335b90a

File tree

4 files changed

+190
-101
lines changed

4 files changed

+190
-101
lines changed

config/irr.yaml

+11-16
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,23 @@ sessions:
1010
binance:
1111
exchange: binance
1212
envVarPrefix: binance
13+
max:
14+
exchange: max
15+
envVarPrefix: max
16+
ftx:
17+
exchange: ftx
18+
envVarPrefix: ftx
1319

1420
exchangeStrategies:
1521
- on: binance
1622
irr:
1723
symbol: BTCBUSD
18-
interval: 1m
19-
window: 120
20-
amount: 5_000.0
24+
# in milliseconds(ms)
25+
# must > 10 ms
26+
hftInterval: 1000
27+
# qty per trade
28+
quantity: 0.001
2129
# Draw pnl
2230
drawGraph: true
2331
graphPNLPath: "./pnl.png"
2432
graphCumPNLPath: "./cumpnl.png"
25-
26-
backtest:
27-
sessions:
28-
- binance
29-
startTime: "2022-09-01"
30-
endTime: "2022-10-04"
31-
symbols:
32-
- BTCBUSD
33-
accounts:
34-
binance:
35-
takerFeeRate: 0.0
36-
balances:
37-
BUSD: 5_000.0

pkg/strategy/irr/draw.go

+21-8
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,36 @@ import (
1111
"github.com/wcharczuk/go-chart/v2"
1212
)
1313

14-
func (s *Strategy) InitDrawCommands(profit, cumProfit types.Series) {
15-
bbgo.RegisterCommand("/pnl", "Draw PNL(%) per trade", func(reply interact.Reply) {
14+
func (s *Strategy) InitDrawCommands(profit, cumProfit, cumProfitDollar types.Series) {
15+
bbgo.RegisterCommand("/rt", "Draw Return Rate(%) Per Trade", func(reply interact.Reply) {
16+
1617
canvas := DrawPNL(s.InstanceID(), profit)
1718
var buffer bytes.Buffer
1819
if err := canvas.Render(chart.PNG, &buffer); err != nil {
19-
log.WithError(err).Errorf("cannot render pnl in drift")
20-
reply.Message(fmt.Sprintf("[error] cannot render pnl in ewo: %v", err))
20+
log.WithError(err).Errorf("cannot render return in irr")
21+
reply.Message(fmt.Sprintf("[error] cannot render return in irr: %v", err))
2122
return
2223
}
2324
bbgo.SendPhoto(&buffer)
2425
})
25-
bbgo.RegisterCommand("/cumpnl", "Draw Cummulative PNL(Quote)", func(reply interact.Reply) {
26+
bbgo.RegisterCommand("/nav", "Draw Net Assets Value", func(reply interact.Reply) {
27+
2628
canvas := DrawCumPNL(s.InstanceID(), cumProfit)
2729
var buffer bytes.Buffer
2830
if err := canvas.Render(chart.PNG, &buffer); err != nil {
29-
log.WithError(err).Errorf("cannot render cumpnl in drift")
30-
reply.Message(fmt.Sprintf("[error] canot render cumpnl in drift: %v", err))
31+
log.WithError(err).Errorf("cannot render nav in irr")
32+
reply.Message(fmt.Sprintf("[error] canot render nav in irr: %v", err))
33+
return
34+
}
35+
bbgo.SendPhoto(&buffer)
36+
})
37+
bbgo.RegisterCommand("/pnl", "Draw Cumulative Profit & Loss", func(reply interact.Reply) {
38+
39+
canvas := DrawCumPNL(s.InstanceID(), cumProfitDollar)
40+
var buffer bytes.Buffer
41+
if err := canvas.Render(chart.PNG, &buffer); err != nil {
42+
log.WithError(err).Errorf("cannot render pnl in irr")
43+
reply.Message(fmt.Sprintf("[error] canot render pnl in irr: %v", err))
3144
return
3245
}
3346
bbgo.SendPhoto(&buffer)
@@ -77,7 +90,7 @@ func DrawPNL(instanceID string, profit types.Series) *types.Canvas {
7790

7891
func DrawCumPNL(instanceID string, cumProfit types.Series) *types.Canvas {
7992
canvas := types.NewCanvas(instanceID)
80-
canvas.PlotRaw("cummulative pnl", cumProfit, cumProfit.Length())
93+
canvas.PlotRaw("cumulative pnl", cumProfit, cumProfit.Length())
8194
canvas.YAxis = chart.YAxis{
8295
ValueFormatter: func(v interface{}) string {
8396
if vf, isFloat := v.(float64); isFloat {

pkg/strategy/irr/neg_return_rate.go

+8-16
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,21 @@ type NRR struct {
3030

3131
var _ types.SeriesExtend = &NRR{}
3232

33-
func (inc *NRR) Update(price float64) {
33+
func (inc *NRR) Update(openPrice, closePrice float64) {
3434
if inc.SeriesBase.Series == nil {
3535
inc.SeriesBase.Series = inc
3636
inc.Prices = types.NewQueue(inc.Window)
3737
}
38-
inc.Prices.Update(price)
38+
inc.Prices.Update(closePrice)
3939
if inc.Prices.Length() < inc.Window {
4040
return
4141
}
42-
irr := (inc.Prices.Last() / inc.Prices.Index(inc.Window-1)) - 1
42+
// D0
43+
irr := openPrice - closePrice
44+
// D1
45+
// -1*((inc.Prices.Last() / inc.Prices.Index(inc.Window-1)) - 1)
4346

44-
inc.Values.Push(-irr) // neg ret here
47+
inc.Values.Push(irr) // neg ret here
4548
inc.RankedValues.Push(inc.Rank(inc.RankingWindow).Last() / float64(inc.RankingWindow)) // ranked neg ret here
4649

4750
}
@@ -75,7 +78,7 @@ func (inc *NRR) PushK(k types.KLine) {
7578
return
7679
}
7780

78-
inc.Update(indicator.KLineClosePriceMapper(k))
81+
inc.Update(indicator.KLineOpenPriceMapper(k), indicator.KLineClosePriceMapper(k))
7982
inc.EndTime = k.EndTime.Time()
8083
inc.EmitUpdate(inc.Last())
8184
}
@@ -86,14 +89,3 @@ func (inc *NRR) LoadK(allKLines []types.KLine) {
8689
}
8790
inc.EmitUpdate(inc.Last())
8891
}
89-
90-
//func calculateReturn(klines []types.KLine, window int, val KLineValueMapper) (float64, error) {
91-
// length := len(klines)
92-
// if length == 0 || length < window {
93-
// return 0.0, fmt.Errorf("insufficient elements for calculating VOL with window = %d", window)
94-
// }
95-
//
96-
// rate := val(klines[length-1])/val(klines[length-2]) - 1
97-
//
98-
// return rate, nil
99-
//}

0 commit comments

Comments
 (0)