fix/drift_stoploss

This commit is contained in:
zenix 2022-10-03 14:00:18 +09:00
parent 294a58cbfd
commit 5c1d0f95e2
5 changed files with 130 additions and 33 deletions

View File

@ -26,7 +26,7 @@ exchangeStrategies:
- on: binance - on: binance
drift: drift:
limitOrder: false limitOrder: true
#quantity: 0.0012 #quantity: 0.0012
canvasPath: "./output.png" canvasPath: "./output.png"
symbol: BTCUSDT symbol: BTCUSDT
@ -34,21 +34,21 @@ exchangeStrategies:
interval: 1m interval: 1m
window: 6 window: 6
useAtr: true useAtr: true
useStopLoss: false useStopLoss: true
stoploss: 0.04% stoploss: 0.05%
source: hl2 source: hl2
predictOffset: 2 predictOffset: 2
noTrailingStopLoss: false noTrailingStopLoss: false
trailingStopLossType: realtime trailingStopLossType: kline
# stddev on high/low-source # stddev on high/low-source
hlVarianceMultiplier: 0.15 hlVarianceMultiplier: 0.14
hlRangeWindow: 4 hlRangeWindow: 4
smootherWindow: 3 smootherWindow: 3
fisherTransformWindow: 181 fisherTransformWindow: 125
#fisherTransformWindow: 117 #fisherTransformWindow: 117
atrWindow: 24 atrWindow: 24
# orders not been traded will be canceled after `pendingMinutes` minutes # orders not been traded will be canceled after `pendingMinutes` minutes
pendingMinutes: 5 pendingMinutes: 10
noRebalance: true noRebalance: true
trendWindow: 15 trendWindow: 15
rebalanceFilter: -0.1 rebalanceFilter: -0.1
@ -57,12 +57,12 @@ exchangeStrategies:
# when farest price from entry goes over that ratio, start using the callback ratio accordingly to do trailingstop # 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.01, 0.016, 0.05]
#trailingActivationRatio: [0.001, 0.0081, 0.022] #trailingActivationRatio: [0.001, 0.0081, 0.022]
trailingActivationRatio: [0.0004, 0.008, 0.002, 0.01] trailingActivationRatio: [0.0008, 0.002, 0.01]
#trailingActivationRatio: [] #trailingActivationRatio: []
#trailingCallbackRate: [] #trailingCallbackRate: []
#trailingCallbackRate: [0.002, 0.01, 0.1] #trailingCallbackRate: [0.002, 0.01, 0.1]
#trailingCallbackRate: [0.0004, 0.0009, 0.018] #trailingCallbackRate: [0.0004, 0.0009, 0.018]
trailingCallbackRate: [0.00005, 0.00012, 0.0008, 0.0016] trailingCallbackRate: [0.00014, 0.0003, 0.0016]
generateGraph: true generateGraph: true
graphPNLDeductFee: false graphPNLDeductFee: false
@ -126,7 +126,7 @@ sync:
backtest: backtest:
startTime: "2022-09-25" startTime: "2022-09-25"
endTime: "2022-09-30" endTime: "2022-10-30"
symbols: symbols:
- BTCUSDT - BTCUSDT
sessions: [binance] sessions: [binance]

View File

@ -1,15 +1,15 @@
package drift package drift
func (s *Strategy) CheckStopLoss() bool { func (s *Strategy) CheckStopLoss() bool {
stoploss := s.StopLoss.Float64()
atr := s.atr.Last()
if s.UseStopLoss { if s.UseStopLoss {
stoploss := s.StopLoss.Float64()
if s.sellPrice > 0 && s.sellPrice*(1.+stoploss) <= s.highestPrice || if s.sellPrice > 0 && s.sellPrice*(1.+stoploss) <= s.highestPrice ||
s.buyPrice > 0 && s.buyPrice*(1.-stoploss) >= s.lowestPrice { s.buyPrice > 0 && s.buyPrice*(1.-stoploss) >= s.lowestPrice {
return true return true
} }
} }
if s.UseAtr { if s.UseAtr {
atr := s.atr.Last()
if s.sellPrice > 0 && s.sellPrice+atr <= s.highestPrice || if s.sellPrice > 0 && s.sellPrice+atr <= s.highestPrice ||
s.buyPrice > 0 && s.buyPrice-atr >= s.lowestPrice { s.buyPrice > 0 && s.buyPrice-atr >= s.lowestPrice {
return true return true

View File

@ -0,0 +1,58 @@
package drift
import (
"testing"
"github.com/c9s/bbgo/pkg/datatype/floats"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/indicator"
"github.com/stretchr/testify/assert"
)
func Test_StopLossLong(t *testing.T) {
s := &Strategy{}
s.highestPrice = 30.
s.buyPrice = 30.
s.lowestPrice = 29.7
s.StopLoss = fixedpoint.NewFromFloat(0.01)
s.UseAtr = false
s.UseStopLoss = true
assert.True(t, s.CheckStopLoss())
}
func Test_StopLossShort(t *testing.T) {
s := &Strategy{}
s.lowestPrice = 30.
s.sellPrice = 30.
s.highestPrice = 30.3
s.StopLoss = fixedpoint.NewFromFloat(0.01)
s.UseAtr = false
s.UseStopLoss = true
assert.True(t, s.CheckStopLoss())
}
func Test_ATRLong(t *testing.T) {
s := &Strategy{}
s.highestPrice = 30.
s.buyPrice = 30.
s.lowestPrice = 28.7
s.UseAtr = true
s.UseStopLoss = false
s.atr = &indicator.ATR{RMA: &indicator.RMA{
Values: floats.Slice{1., 1.2, 1.3},
}}
assert.True(t, s.CheckStopLoss())
}
func Test_ATRShort(t *testing.T) {
s := &Strategy{}
s.highestPrice = 31.3
s.sellPrice = 30.
s.lowestPrice = 30.
s.UseAtr = true
s.UseStopLoss = false
s.atr = &indicator.ATR{RMA: &indicator.RMA{
Values: floats.Slice{1., 1.2, 1.3},
}}
assert.True(t, s.CheckStopLoss())
}

View File

@ -274,10 +274,8 @@ func (s *Strategy) smartCancel(ctx context.Context, pricef, atr float64) (int, e
if toCancel { if toCancel {
err := s.GeneralOrderExecutor.GracefulCancel(ctx) err := s.GeneralOrderExecutor.GracefulCancel(ctx)
// TODO: clean orderPendingCounter on cancel/trade // TODO: clean orderPendingCounter on cancel/trade
if err == nil { for _, order := range nonTraded {
for _, order := range nonTraded { delete(s.orderPendingCounter, order.OrderID)
delete(s.orderPendingCounter, order.OrderID)
}
} }
log.Warnf("cancel all %v", err) log.Warnf("cancel all %v", err)
return 0, err return 0, err
@ -306,7 +304,7 @@ func (s *Strategy) trailingCheck(price float64, direction string) bool {
} }
} else { } else {
if (s.highestPrice-s.buyPrice)/s.buyPrice > trailingActivationRatio { if (s.highestPrice-s.buyPrice)/s.buyPrice > trailingActivationRatio {
return (s.highestPrice-price)/price > trailingCallbackRate return (s.highestPrice-price)/s.buyPrice > trailingCallbackRate
} }
} }
} }
@ -352,14 +350,18 @@ func (s *Strategy) initTickerFunctions(ctx context.Context) {
if s.lowestPrice > 0 && s.lowestPrice > pricef { if s.lowestPrice > 0 && s.lowestPrice > pricef {
s.lowestPrice = pricef s.lowestPrice = pricef
} }
if s.CheckStopLoss() {
s.positionLock.Unlock()
s.ClosePosition(ctx, fixedpoint.One)
return
}
// for trailing stoploss during the realtime // for trailing stoploss during the realtime
if s.NoTrailingStopLoss || s.TrailingStopLossType == "kline" { if s.NoTrailingStopLoss || s.TrailingStopLossType == "kline" {
s.positionLock.Unlock() s.positionLock.Unlock()
return return
} }
exitCondition := s.CheckStopLoss() || exitCondition := s.trailingCheck(pricef, "short") || s.trailingCheck(pricef, "long")
s.trailingCheck(pricef, "short") || s.trailingCheck(pricef, "long")
s.positionLock.Unlock() s.positionLock.Unlock()
if exitCondition { if exitCondition {
@ -683,15 +685,15 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
s.positionLock.Unlock() s.positionLock.Unlock()
return return
} }
/*source = source.Sub(fixedpoint.NewFromFloat(s.stdevLow.Last() * s.HighLowVarianceMultiplier)) source = source.Sub(fixedpoint.NewFromFloat(s.stdevLow.Last() * s.HighLowVarianceMultiplier))
if source.Compare(price) > 0 {
source = price
}*/
source = fixedpoint.NewFromFloat(s.ma.Last() - s.stdevLow.Last()*s.HighLowVarianceMultiplier)
if source.Compare(price) > 0 { if source.Compare(price) > 0 {
source = price source = price
} }
sourcef = source.Float64() /*source = fixedpoint.NewFromFloat(s.ma.Last() - s.stdevLow.Last()*s.HighLowVarianceMultiplier)
if source.Compare(price) > 0 {
source = price
}
sourcef = source.Float64()*/
log.Infof("source in long %v %v %f", source, price, s.stdevLow.Last()) log.Infof("source in long %v %v %f", source, price, s.stdevLow.Last())
s.positionLock.Unlock() s.positionLock.Unlock()
@ -721,15 +723,15 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
return return
} }
/*source = source.Add(fixedpoint.NewFromFloat(s.stdevHigh.Last() * s.HighLowVarianceMultiplier)) source = source.Add(fixedpoint.NewFromFloat(s.stdevHigh.Last() * s.HighLowVarianceMultiplier))
if source.Compare(price) < 0 {
source = price
}*/
source = fixedpoint.NewFromFloat(s.ma.Last() + s.stdevHigh.Last()*s.HighLowVarianceMultiplier)
if source.Compare(price) < 0 { if source.Compare(price) < 0 {
source = price source = price
} }
sourcef = source.Float64() /*source = fixedpoint.NewFromFloat(s.ma.Last() + s.stdevHigh.Last()*s.HighLowVarianceMultiplier)
if source.Compare(price) < 0 {
source = price
}
sourcef = source.Float64()*/
log.Infof("source in short: %v", source) log.Infof("source in short: %v", source)
@ -845,11 +847,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
s.buyPrice = s.p.ApproximateAverageCost.Float64() //trade.Price.Float64() s.buyPrice = s.p.ApproximateAverageCost.Float64() //trade.Price.Float64()
s.sellPrice = 0 s.sellPrice = 0
s.highestPrice = math.Max(s.buyPrice, s.highestPrice) s.highestPrice = math.Max(s.buyPrice, s.highestPrice)
s.lowestPrice = 0 s.lowestPrice = s.buyPrice
} else if s.p.IsShort() { } else if s.p.IsShort() {
s.sellPrice = s.p.ApproximateAverageCost.Float64() //trade.Price.Float64() s.sellPrice = s.p.ApproximateAverageCost.Float64() //trade.Price.Float64()
s.buyPrice = 0 s.buyPrice = 0
s.highestPrice = 0 s.highestPrice = s.sellPrice
if s.lowestPrice == 0 { if s.lowestPrice == 0 {
s.lowestPrice = s.sellPrice s.lowestPrice = s.sellPrice
} else { } else {

View File

@ -0,0 +1,37 @@
package drift
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_TrailingCheckLong(t *testing.T) {
s := &Strategy{}
s.highestPrice = 30.
s.buyPrice = 30.
s.TrailingActivationRatio = []float64{0.002, 0.01}
s.TrailingCallbackRate = []float64{0.0008, 0.0016}
assert.False(t, s.trailingCheck(31., "long"))
assert.False(t, s.trailingCheck(31., "short"))
assert.False(t, s.trailingCheck(30.96, "short"))
assert.False(t, s.trailingCheck(30.96, "long"))
assert.False(t, s.trailingCheck(30.95, "short"))
assert.True(t, s.trailingCheck(30.95, "long"))
}
func Test_TrailingCheckShort(t *testing.T) {
s := &Strategy{}
s.lowestPrice = 30.
s.sellPrice = 30.
s.TrailingActivationRatio = []float64{0.002, 0.01}
s.TrailingCallbackRate = []float64{0.0008, 0.0016}
assert.False(t, s.trailingCheck(29.96, "long"))
assert.False(t, s.trailingCheck(29.96, "short"))
assert.False(t, s.trailingCheck(29.99, "short"))
assert.False(t, s.trailingCheck(29.99, "long"))
assert.False(t, s.trailingCheck(29.93, "short"))
assert.False(t, s.trailingCheck(29.93, "long"))
assert.True(t, s.trailingCheck(29.96, "short"))
assert.False(t, s.trailingCheck(29.96, "long"))
}