mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +00:00
fix/drift_stoploss
This commit is contained in:
parent
294a58cbfd
commit
5c1d0f95e2
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
58
pkg/strategy/drift/stoploss_test.go
Normal file
58
pkg/strategy/drift/stoploss_test.go
Normal 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())
|
||||
}
|
|
@ -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 {
|
||||
|
|
37
pkg/strategy/drift/strategy_test.go
Normal file
37
pkg/strategy/drift/strategy_test.go
Normal 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"))
|
||||
}
|
Loading…
Reference in New Issue
Block a user