mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
fix: enable interval parsing for non-whitelisted time spans
This commit is contained in:
parent
6c8902dd9c
commit
1d0893b699
|
@ -56,12 +56,12 @@ exchangeStrategies:
|
|||
# when farest price from entry goes over that ratio, start using the callback ratio accordingly to do trailingstop
|
||||
#trailingActivationRatio: [0.01, 0.016, 0.05]
|
||||
#trailingActivationRatio: [0.001, 0.0081, 0.022]
|
||||
trailingActivationRatio: [0.0029, 0.028]
|
||||
trailingActivationRatio: [0.0012, 0.01]
|
||||
#trailingActivationRatio: []
|
||||
#trailingCallbackRate: []
|
||||
#trailingCallbackRate: [0.002, 0.01, 0.1]
|
||||
#trailingCallbackRate: [0.0004, 0.0009, 0.018]
|
||||
trailingCallbackRate: [0.0005, 0.0149]
|
||||
trailingCallbackRate: [0.0006, 0.0049]
|
||||
|
||||
generateGraph: true
|
||||
graphPNLDeductFee: false
|
||||
|
@ -124,15 +124,15 @@ sync:
|
|||
- BTCUSDT
|
||||
|
||||
backtest:
|
||||
startTime: "2022-08-01"
|
||||
endTime: "2022-08-31"
|
||||
startTime: "2022-09-01"
|
||||
endTime: "2022-09-15"
|
||||
symbols:
|
||||
- BTCUSDT
|
||||
sessions: [binance]
|
||||
accounts:
|
||||
binance:
|
||||
makerFeeRate: 0.000
|
||||
#takerFeeRate: 0.000
|
||||
takerFeeRate: 0.000
|
||||
balances:
|
||||
BTC: 0
|
||||
USDT: 21
|
||||
|
|
|
@ -23,14 +23,14 @@ exchangeStrategies:
|
|||
|
||||
- on: binance
|
||||
elliottwave:
|
||||
symbol: BTCUSDT
|
||||
symbol: BNBBUSD
|
||||
# kline interval for indicators
|
||||
interval: 4m
|
||||
stoploss: 0.5%
|
||||
interval: 3m
|
||||
stoploss: 0.2%
|
||||
windowATR: 14
|
||||
windowQuick: 10
|
||||
windowSlow: 96
|
||||
source: hlc3
|
||||
windowQuick: 5
|
||||
windowSlow: 19
|
||||
source: hl2
|
||||
pendingMinutes: 10
|
||||
useHeikinAshi: true
|
||||
|
||||
|
@ -44,12 +44,12 @@ exchangeStrategies:
|
|||
# when farest price from entry goes over that ratio, start using the callback ratio accordingly to do trailingstop
|
||||
#trailingActivationRatio: [0.01, 0.016, 0.05]
|
||||
#trailingActivationRatio: [0.001, 0.0081, 0.022]
|
||||
trailingActivationRatio: [0.0008, 0.0012, 0.0017, 0.01, 0.015]
|
||||
trailingActivationRatio: [0.0017, 0.01, 0.015]
|
||||
#trailingActivationRatio: []
|
||||
#trailingCallbackRate: []
|
||||
#trailingCallbackRate: [0.002, 0.01, 0.1]
|
||||
#trailingCallbackRate: [0.0004, 0.0009, 0.018]
|
||||
trailingCallbackRate: [0.0002, 0.0003, 0.0006, 0.0049, 0.006]
|
||||
trailingCallbackRate: [0.0006, 0.0049, 0.006]
|
||||
|
||||
#exits:
|
||||
# - roiStopLoss:
|
||||
|
@ -105,18 +105,18 @@ sync:
|
|||
sessions:
|
||||
- binance
|
||||
symbols:
|
||||
- BTCUSDT
|
||||
- BNBBUSD
|
||||
|
||||
backtest:
|
||||
startTime: "2022-08-01"
|
||||
startTime: "2022-09-01"
|
||||
endTime: "2022-09-30"
|
||||
symbols:
|
||||
- BTCUSDT
|
||||
- BNBBUSD
|
||||
sessions: [binance]
|
||||
accounts:
|
||||
binance:
|
||||
makerFeeRate: 0.000
|
||||
takerFeeRate: 0.000
|
||||
balances:
|
||||
BTC: 0
|
||||
USDT: 5000
|
||||
BNB: 0
|
||||
BUSD: 20
|
||||
|
|
1060
pkg/strategy/drift/backup
Normal file
1060
pkg/strategy/drift/backup
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -125,9 +125,9 @@ func (s *Strategy) InstanceID() string {
|
|||
}
|
||||
|
||||
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{
|
||||
Interval: s.Interval,
|
||||
})
|
||||
// by default, bbgo only pre-subscribe 1000 klines.
|
||||
// this is not enough if we're subscribing 30m intervals using SerialMarketDataStore
|
||||
bbgo.KLineLimit = int64((s.Interval.Minutes()*s.Window/1000 + 1) * 1000)
|
||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{
|
||||
Interval: types.Interval1m,
|
||||
})
|
||||
|
@ -173,7 +173,7 @@ func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Valu
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Strategy) initIndicators() error {
|
||||
func (s *Strategy) initIndicators(store *bbgo.SerialMarketDataStore) error {
|
||||
s.ma = &indicator.SMA{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.HLRangeWindow}}
|
||||
s.stdevHigh = &indicator.StdDev{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.HLRangeWindow}}
|
||||
s.stdevLow = &indicator.StdDev{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.HLRangeWindow}}
|
||||
|
@ -207,7 +207,6 @@ func (s *Strategy) initIndicators() error {
|
|||
s.atr = &indicator.ATR{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.ATRWindow}}
|
||||
s.trendLine = &indicator.EWMA{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.TrendWindow}}
|
||||
|
||||
store, _ := s.Session.MarketDataStore(s.Symbol)
|
||||
klines, ok := store.KLinesOfInterval(s.Interval)
|
||||
klinesLength := len(*klines)
|
||||
if !ok || klinesLength == 0 {
|
||||
|
@ -243,7 +242,7 @@ func (s *Strategy) initIndicators() error {
|
|||
if s.kline1m != nil && klines != nil {
|
||||
s.kline1m.Set(&(*klines)[len(*klines)-1])
|
||||
}
|
||||
s.startTime = s.kline1m.EndTime.Time()
|
||||
s.startTime = s.kline1m.StartTime.Time().Add(s.kline1m.Interval.Duration())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -257,7 +256,7 @@ func (s *Strategy) smartCancel(ctx context.Context, pricef, atr float64) (int, e
|
|||
|
||||
drift := s.drift1m.Array(2)
|
||||
for _, order := range nonTraded {
|
||||
log.Warnf("%v", order)
|
||||
log.Warnf("%v | counter: %d, system: %d", order, s.orderPendingCounter[order.OrderID], s.minutesCounter)
|
||||
if s.minutesCounter-s.orderPendingCounter[order.OrderID] > s.PendingMinutes {
|
||||
if order.Side == types.SideTypeBuy && drift[1] < drift[0] {
|
||||
continue
|
||||
|
@ -566,9 +565,6 @@ func (s *Strategy) CalcAssetValue(price fixedpoint.Value) fixedpoint.Value {
|
|||
}
|
||||
|
||||
func (s *Strategy) klineHandler1m(ctx context.Context, kline types.KLine) {
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
return
|
||||
}
|
||||
s.kline1m.Set(&kline)
|
||||
s.drift1m.Update(s.GetSource(&kline).Float64(), kline.Volume.Float64())
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
|
@ -917,12 +913,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
s.frameKLine = &types.KLine{}
|
||||
s.kline1m = &types.KLine{}
|
||||
s.priceLines = types.NewQueue(300)
|
||||
if err := s.initIndicators(); err != nil {
|
||||
log.WithError(err).Errorf("initIndicator failed")
|
||||
return nil
|
||||
}
|
||||
s.initTickerFunctions(ctx)
|
||||
|
||||
s.initTickerFunctions(ctx)
|
||||
startTime := s.Environment.StartTime()
|
||||
s.TradeStats.SetIntervalProfitCollector(types.NewIntervalProfitCollector(types.Interval1d, startTime))
|
||||
s.TradeStats.SetIntervalProfitCollector(types.NewIntervalProfitCollector(types.Interval1w, startTime))
|
||||
|
@ -993,8 +985,12 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
if !ok {
|
||||
panic("cannot get 1m history")
|
||||
}
|
||||
if err := s.initIndicators(store); err != nil {
|
||||
log.WithError(err).Errorf("initIndicator failed")
|
||||
return nil
|
||||
}
|
||||
store.OnKLineClosed(func(kline types.KLine) {
|
||||
s.minutesCounter = int(kline.StartTime.Time().Sub(s.startTime).Minutes())
|
||||
s.minutesCounter = int(kline.StartTime.Time().Add(kline.Interval.Duration()).Sub(s.startTime).Minutes())
|
||||
if kline.Interval == types.Interval1m {
|
||||
s.klineHandler1m(ctx, kline)
|
||||
} else if kline.Interval == s.Interval {
|
||||
|
|
|
@ -100,7 +100,7 @@ func (s *Strategy) InstanceID() string {
|
|||
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
||||
// by default, bbgo only pre-subscribe 1000 klines.
|
||||
// this is not enough if we're subscribing 30m intervals using SerialMarketDataStore
|
||||
bbgo.KLineLimit = int64(s.Interval.Minutes()*s.WindowSlow + 1000)
|
||||
bbgo.KLineLimit = int64((s.Interval.Minutes()*s.WindowSlow/1000 + 1) + 1000)
|
||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{
|
||||
Interval: types.Interval1m,
|
||||
})
|
||||
|
@ -159,7 +159,8 @@ func (s *Strategy) initIndicators(store *bbgo.SerialMarketDataStore) error {
|
|||
if !ok || klineLength == 0 {
|
||||
return errors.New("klines not exists")
|
||||
}
|
||||
s.startTime = (*klines)[klineLength-1].EndTime.Time()
|
||||
tmpK := (*klines)[klineLength-1]
|
||||
s.startTime = tmpK.StartTime.Time().Add(tmpK.Interval.Duration())
|
||||
s.heikinAshi = NewHeikinAshi(500)
|
||||
|
||||
for _, kline := range *klines {
|
||||
|
@ -178,6 +179,7 @@ func (s *Strategy) smartCancel(ctx context.Context, pricef float64) int {
|
|||
if len(nonTraded) > 0 {
|
||||
left := 0
|
||||
for _, order := range nonTraded {
|
||||
log.Warnf("%v | counter: %d, system: %d", order, s.orderPendingCounter[order.OrderID], s.minutesCounter)
|
||||
toCancel := false
|
||||
if s.minutesCounter-s.orderPendingCounter[order.OrderID] >= s.PendingMinutes {
|
||||
toCancel = true
|
||||
|
@ -364,7 +366,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
s.InitDrawCommands(store, &profit, &cumProfit)
|
||||
store.OnKLineClosed(func(kline types.KLine) {
|
||||
s.minutesCounter = int(kline.StartTime.Time().Sub(s.startTime).Minutes())
|
||||
s.minutesCounter = int(kline.StartTime.Time().Add(kline.Interval.Duration()).Sub(s.startTime).Minutes())
|
||||
if kline.Interval == types.Interval1m {
|
||||
s.klineHandler1m(ctx, kline)
|
||||
} else if kline.Interval == s.Interval {
|
||||
|
|
|
@ -3,13 +3,18 @@ package types
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Interval string
|
||||
|
||||
func (i Interval) Minutes() int {
|
||||
return SupportedIntervals[i]
|
||||
m, ok := SupportedIntervals[i]
|
||||
if !ok {
|
||||
return ParseInterval(i)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (i Interval) Duration() time.Duration {
|
||||
|
@ -56,6 +61,34 @@ var Interval1w = Interval("1w")
|
|||
var Interval2w = Interval("2w")
|
||||
var Interval1mo = Interval("1mo")
|
||||
|
||||
func ParseInterval(input Interval) int {
|
||||
t := 0
|
||||
index := 0
|
||||
for i, rn := range string(input) {
|
||||
if rn >= '0' && rn <= '9' {
|
||||
t = t*10 + int(rn-'0')
|
||||
} else {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(string(input[index:])) {
|
||||
case "m":
|
||||
return t
|
||||
case "h":
|
||||
t *= 60
|
||||
case "d":
|
||||
t *= 60 * 24
|
||||
case "w":
|
||||
t *= 60 * 24 * 7
|
||||
case "mo":
|
||||
t *= 60 * 24 * 30
|
||||
default:
|
||||
panic("unknown input: " + input)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
var SupportedIntervals = map[Interval]int{
|
||||
Interval1m: 1,
|
||||
Interval3m: 3,
|
||||
|
|
14
pkg/types/interval_test.go
Normal file
14
pkg/types/interval_test.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseInterval(t *testing.T) {
|
||||
assert.Equal(t, ParseInterval("3m"), 3)
|
||||
assert.Equal(t, ParseInterval("15h"), 15*60)
|
||||
assert.Equal(t, ParseInterval("72d"), 72*24*60)
|
||||
assert.Equal(t, ParseInterval("3Mo"), 3*30*24*60)
|
||||
}
|
Loading…
Reference in New Issue
Block a user