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
drift:
limitOrder: false
limitOrder: true
#quantity: 0.0012
canvasPath: "./output.png"
symbol: BTCUSDT
@ -34,21 +34,21 @@ exchangeStrategies:
interval: 1m
window: 6
useAtr: true
useStopLoss: false
stoploss: 0.04%
useStopLoss: true
stoploss: 0.05%
source: hl2
predictOffset: 2
noTrailingStopLoss: false
trailingStopLossType: realtime
trailingStopLossType: kline
# stddev on high/low-source
hlVarianceMultiplier: 0.15
hlVarianceMultiplier: 0.14
hlRangeWindow: 4
smootherWindow: 3
fisherTransformWindow: 181
fisherTransformWindow: 125
#fisherTransformWindow: 117
atrWindow: 24
# orders not been traded will be canceled after `pendingMinutes` minutes
pendingMinutes: 5
pendingMinutes: 10
noRebalance: true
trendWindow: 15
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
#trailingActivationRatio: [0.01, 0.016, 0.05]
#trailingActivationRatio: [0.001, 0.0081, 0.022]
trailingActivationRatio: [0.0004, 0.008, 0.002, 0.01]
trailingActivationRatio: [0.0008, 0.002, 0.01]
#trailingActivationRatio: []
#trailingCallbackRate: []
#trailingCallbackRate: [0.002, 0.01, 0.1]
#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
graphPNLDeductFee: false
@ -126,7 +126,7 @@ sync:
backtest:
startTime: "2022-09-25"
endTime: "2022-09-30"
endTime: "2022-10-30"
symbols:
- BTCUSDT
sessions: [binance]

View File

@ -1,15 +1,15 @@
package drift
func (s *Strategy) CheckStopLoss() bool {
stoploss := s.StopLoss.Float64()
atr := s.atr.Last()
if s.UseStopLoss {
stoploss := s.StopLoss.Float64()
if s.sellPrice > 0 && s.sellPrice*(1.+stoploss) <= s.highestPrice ||
s.buyPrice > 0 && s.buyPrice*(1.-stoploss) >= s.lowestPrice {
return true
}
}
if s.UseAtr {
atr := s.atr.Last()
if s.sellPrice > 0 && s.sellPrice+atr <= s.highestPrice ||
s.buyPrice > 0 && s.buyPrice-atr >= s.lowestPrice {
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 {
err := s.GeneralOrderExecutor.GracefulCancel(ctx)
// TODO: clean orderPendingCounter on cancel/trade
if err == nil {
for _, order := range nonTraded {
delete(s.orderPendingCounter, order.OrderID)
}
for _, order := range nonTraded {
delete(s.orderPendingCounter, order.OrderID)
}
log.Warnf("cancel all %v", err)
return 0, err
@ -306,7 +304,7 @@ func (s *Strategy) trailingCheck(price float64, direction string) bool {
}
} else {
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 {
s.lowestPrice = pricef
}
if s.CheckStopLoss() {
s.positionLock.Unlock()
s.ClosePosition(ctx, fixedpoint.One)
return
}
// for trailing stoploss during the realtime
if s.NoTrailingStopLoss || s.TrailingStopLossType == "kline" {
s.positionLock.Unlock()
return
}
exitCondition := s.CheckStopLoss() ||
s.trailingCheck(pricef, "short") || s.trailingCheck(pricef, "long")
exitCondition := s.trailingCheck(pricef, "short") || s.trailingCheck(pricef, "long")
s.positionLock.Unlock()
if exitCondition {
@ -683,15 +685,15 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
s.positionLock.Unlock()
return
}
/*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)
source = source.Sub(fixedpoint.NewFromFloat(s.stdevLow.Last() * s.HighLowVarianceMultiplier))
if source.Compare(price) > 0 {
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())
s.positionLock.Unlock()
@ -721,15 +723,15 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
return
}
/*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)
source = source.Add(fixedpoint.NewFromFloat(s.stdevHigh.Last() * s.HighLowVarianceMultiplier))
if source.Compare(price) < 0 {
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)
@ -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.sellPrice = 0
s.highestPrice = math.Max(s.buyPrice, s.highestPrice)
s.lowestPrice = 0
s.lowestPrice = s.buyPrice
} else if s.p.IsShort() {
s.sellPrice = s.p.ApproximateAverageCost.Float64() //trade.Price.Float64()
s.buyPrice = 0
s.highestPrice = 0
s.highestPrice = s.sellPrice
if s.lowestPrice == 0 {
s.lowestPrice = s.sellPrice
} 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"))
}