mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
Merge pull request #953 from zenixls2/fix/drift
fix: drift minus weight, preloaded kline not enough
This commit is contained in:
commit
3230088f9f
|
@ -26,42 +26,42 @@ exchangeStrategies:
|
|||
canvasPath: "./output.png"
|
||||
symbol: BTCUSDT
|
||||
# kline interval for indicators
|
||||
interval: 15m
|
||||
interval: 4m
|
||||
window: 1
|
||||
stoploss: 1.2%
|
||||
source: close
|
||||
stoploss: 0.22%
|
||||
source: hl2
|
||||
predictOffset: 2
|
||||
noTrailingStopLoss: false
|
||||
trailingStopLossType: kline
|
||||
trailingStopLossType: realtime
|
||||
# stddev on high/low-source
|
||||
hlVarianceMultiplier: 0.1
|
||||
hlVarianceMultiplier: 0.01
|
||||
hlRangeWindow: 5
|
||||
smootherWindow: 1
|
||||
fisherTransformWindow: 34
|
||||
smootherWindow: 2
|
||||
fisherTransformWindow: 27
|
||||
window1m: 58
|
||||
smootherWindow1m: 118
|
||||
fisherTransformWindow1m: 319
|
||||
atrWindow: 14
|
||||
# orders not been traded will be canceled after `pendingMinutes` minutes
|
||||
pendingMinutes: 10
|
||||
pendingMinutes: 2
|
||||
noRebalance: true
|
||||
trendWindow: 576
|
||||
rebalanceFilter: 0
|
||||
driftFilterPos: 1.8
|
||||
driftFilterNeg: -1.8
|
||||
ddriftFilterPos: 0.5
|
||||
ddriftFilterNeg: -0.5 #-1.6
|
||||
driftFilterPos: 0.6
|
||||
driftFilterNeg: -0.6
|
||||
ddriftFilterPos: 0.00008
|
||||
ddriftFilterNeg: -0.00008
|
||||
|
||||
# ActivationRatio should be increasing order
|
||||
# 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.0012, 0.01]
|
||||
trailingActivationRatio: [0.0012, 0.0016, 0.01]
|
||||
#trailingActivationRatio: []
|
||||
#trailingCallbackRate: []
|
||||
#trailingCallbackRate: [0.002, 0.01, 0.1]
|
||||
#trailingCallbackRate: [0.0004, 0.0009, 0.018]
|
||||
trailingCallbackRate: [0.0006, 0.0049]
|
||||
trailingCallbackRate: [0.0003, 0.0006, 0.0019]
|
||||
|
||||
generateGraph: true
|
||||
graphPNLDeductFee: false
|
||||
|
@ -125,7 +125,7 @@ sync:
|
|||
|
||||
backtest:
|
||||
startTime: "2022-09-01"
|
||||
endTime: "2022-09-15"
|
||||
endTime: "2022-09-30"
|
||||
symbols:
|
||||
- BTCUSDT
|
||||
sessions: [binance]
|
||||
|
|
|
@ -23,19 +23,23 @@ type WeightedDrift struct {
|
|||
}
|
||||
|
||||
func (inc *WeightedDrift) Update(value float64, weight float64) {
|
||||
win := 10
|
||||
if inc.Window > win {
|
||||
win = inc.Window
|
||||
}
|
||||
if inc.chng == nil {
|
||||
inc.SeriesBase.Series = inc
|
||||
if inc.MA == nil {
|
||||
inc.MA = &SMA{IntervalWindow: types.IntervalWindow{Interval: inc.Interval, Window: inc.Window}}
|
||||
}
|
||||
inc.Weight = types.NewQueue(10)
|
||||
inc.Weight = types.NewQueue(win)
|
||||
inc.chng = types.NewQueue(inc.Window)
|
||||
inc.LastValue = value
|
||||
inc.Weight.Update(weight)
|
||||
return
|
||||
}
|
||||
inc.Weight.Update(weight)
|
||||
base := inc.Weight.Lowest(10)
|
||||
base := inc.Weight.Lowest(win)
|
||||
multiplier := int(weight / base)
|
||||
var chng float64
|
||||
if value == 0 {
|
||||
|
@ -119,7 +123,7 @@ func (inc *WeightedDrift) Length() int {
|
|||
var _ types.SeriesExtend = &Drift{}
|
||||
|
||||
func (inc *WeightedDrift) PushK(k types.KLine) {
|
||||
inc.Update(k.Close.Float64(), k.Volume.Float64())
|
||||
inc.Update(k.Close.Float64(), k.Volume.Abs().Float64())
|
||||
}
|
||||
|
||||
func (inc *WeightedDrift) CalculateAndUpdate(allKLines []types.KLine) {
|
||||
|
|
|
@ -126,7 +126,13 @@ 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.KLinePreloadLimit = int64((s.Interval.Minutes()*s.Window/1000 + 1) * 1000)
|
||||
maxWindow := (s.Window + s.SmootherWindow + s.FisherTransformWindow) * s.Interval.Minutes()
|
||||
maxWindow1m := s.Window1m + s.SmootherWindow1m + s.FisherTransformWindow1m
|
||||
if maxWindow < maxWindow1m {
|
||||
maxWindow = maxWindow1m
|
||||
}
|
||||
bbgo.KLinePreloadLimit = int64((maxWindow/1000 + 1) * 1000)
|
||||
log.Errorf("set kLinePreloadLimit to %d, %d %d", bbgo.KLinePreloadLimit, s.Interval.Minutes(), maxWindow)
|
||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{
|
||||
Interval: types.Interval1m,
|
||||
})
|
||||
|
@ -218,7 +224,7 @@ func (s *Strategy) initIndicators(store *bbgo.SerialMarketDataStore) error {
|
|||
s.ma.Update(source)
|
||||
s.stdevHigh.Update(high - s.ma.Last())
|
||||
s.stdevLow.Update(s.ma.Last() - low)
|
||||
s.drift.Update(source, kline.Volume.Float64())
|
||||
s.drift.Update(source, kline.Volume.Abs().Float64())
|
||||
s.trendLine.Update(source)
|
||||
s.atr.PushK(kline)
|
||||
s.priceLines.Update(source)
|
||||
|
@ -233,7 +239,7 @@ func (s *Strategy) initIndicators(store *bbgo.SerialMarketDataStore) error {
|
|||
}
|
||||
for _, kline := range *klines {
|
||||
source := s.GetSource(&kline).Float64()
|
||||
s.drift1m.Update(source, kline.Volume.Float64())
|
||||
s.drift1m.Update(source, kline.Volume.Abs().Float64())
|
||||
if s.drift1m.Last() != s.drift1m.Last() {
|
||||
panic(fmt.Sprintf("%f %v %f %f", source, s.drift1m.drift.Values.Index(1), s.drift1m.ma2.Last(), s.drift1m.drift.LastValue))
|
||||
}
|
||||
|
@ -411,9 +417,15 @@ func (s *Strategy) DrawIndicators(time types.Time) *types.Canvas {
|
|||
h1m := s.drift1m.Abs().Highest(Length * s.Interval.Minutes())
|
||||
ratio := highestPrice / highestDrift
|
||||
|
||||
canvas.Plot("upband", s.ma.Add(s.stdevHigh), time, Length)
|
||||
//canvas.Plot("upband", s.ma.Add(s.stdevHigh), time, Length)
|
||||
canvas.Plot("ma", s.ma, time, Length)
|
||||
canvas.Plot("downband", s.ma.Minus(s.stdevLow), time, Length)
|
||||
//canvas.Plot("downband", s.ma.Minus(s.stdevLow), time, Length)
|
||||
canvas.Plot("pos", types.NumberSeries(s.DriftFilterPos*ratio+mean), time, Length)
|
||||
canvas.Plot("neg", types.NumberSeries(s.DriftFilterNeg*ratio+mean), time, Length)
|
||||
fmt.Printf("%f %f\n", highestPrice, hi)
|
||||
canvas.Plot("ppos", types.NumberSeries(s.DDriftFilterPos*(highestPrice/hi)+mean), time, Length)
|
||||
canvas.Plot("nneg", types.NumberSeries(s.DDriftFilterNeg*(highestPrice/hi)+mean), time, Length)
|
||||
|
||||
canvas.Plot("drift", s.drift.Mul(ratio).Add(mean), time, Length)
|
||||
canvas.Plot("driftOrig", s.drift.drift.Mul(highestPrice/hi).Add(mean), time, Length)
|
||||
canvas.Plot("drift1m", s.drift1m.Mul(highestPrice/h1m).Add(mean), time, Length*s.Interval.Minutes(), types.Interval1m)
|
||||
|
@ -556,7 +568,7 @@ func (s *Strategy) CalcAssetValue(price fixedpoint.Value) fixedpoint.Value {
|
|||
|
||||
func (s *Strategy) klineHandler1m(ctx context.Context, kline types.KLine) {
|
||||
s.kline1m.Set(&kline)
|
||||
s.drift1m.Update(s.GetSource(&kline).Float64(), kline.Volume.Float64())
|
||||
s.drift1m.Update(s.GetSource(&kline).Float64(), kline.Volume.Abs().Float64())
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
return
|
||||
}
|
||||
|
@ -575,6 +587,11 @@ func (s *Strategy) klineHandler1m(ctx context.Context, kline types.KLine) {
|
|||
if s.highestPrice > 0 && highf > s.highestPrice {
|
||||
s.highestPrice = highf
|
||||
}
|
||||
drift := s.drift1m.Array(2)
|
||||
if len(drift) < 2 {
|
||||
s.positionLock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
numPending := 0
|
||||
var err error
|
||||
|
@ -617,17 +634,10 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
s.priceLines.Update(sourcef)
|
||||
s.ma.Update(sourcef)
|
||||
s.trendLine.Update(sourcef)
|
||||
s.drift.Update(sourcef, kline.Volume.Float64())
|
||||
s.drift.Update(sourcef, kline.Volume.Abs().Float64())
|
||||
|
||||
s.atr.PushK(kline)
|
||||
drift = s.drift.Array(2)
|
||||
if len(drift) < 2 || len(drift) < s.PredictOffset {
|
||||
return
|
||||
}
|
||||
ddrift := s.drift.drift.Array(2)
|
||||
if len(ddrift) < 2 || len(ddrift) < s.PredictOffset {
|
||||
return
|
||||
}
|
||||
|
||||
driftPred = s.drift.Predict(s.PredictOffset)
|
||||
ddriftPred := s.drift.drift.Predict(s.PredictOffset)
|
||||
atr = s.atr.Last()
|
||||
|
@ -639,6 +649,14 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
s.stdevLow.Update(lowdiff)
|
||||
highdiff := highf - s.ma.Last()
|
||||
s.stdevHigh.Update(highdiff)
|
||||
drift = s.drift.Array(2)
|
||||
if len(drift) < 2 || len(drift) < s.PredictOffset {
|
||||
return
|
||||
}
|
||||
ddrift := s.drift.drift.Array(2)
|
||||
if len(ddrift) < 2 || len(ddrift) < s.PredictOffset {
|
||||
return
|
||||
}
|
||||
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
return
|
||||
|
@ -646,7 +664,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
stoploss := s.StopLoss.Float64()
|
||||
|
||||
s.positionLock.Lock()
|
||||
log.Errorf("highdiff: %3.2f ma: %.2f, close: %8v, high: %8v, low: %8v, time: %v %v", s.stdevHigh.Last(), s.ma.Last(), kline.Close, kline.High, kline.Low, kline.StartTime, kline.EndTime)
|
||||
log.Infof("highdiff: %3.2f ma: %.2f, close: %8v, high: %8v, low: %8v, time: %v %v", s.stdevHigh.Last(), s.ma.Last(), kline.Close, kline.High, kline.Low, kline.StartTime, kline.EndTime)
|
||||
if s.lowestPrice > 0 && lowf < s.lowestPrice {
|
||||
s.lowestPrice = lowf
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user