mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-21 22:43:52 +00:00
strategy: supertrend strategy TP/SL
This commit is contained in:
parent
7c98fca0c2
commit
a5124c743f
|
@ -46,3 +46,12 @@ exchangeStrategies:
|
|||
averageTrueRangeWindow: 39
|
||||
# ATR Multiplier for calculating super trend prices, the higher, the stronger the trends are
|
||||
averageTrueRangeMultiplier: 3
|
||||
|
||||
# TP according to ATR multiple, 0 to disable this
|
||||
takeProfitMultiplier: 3
|
||||
|
||||
# Set SL price to the low of the triggering Kline
|
||||
stopLossByTriggeringK: true
|
||||
|
||||
# TP/SL by reversed signals
|
||||
tpslBySignal: true
|
||||
|
|
|
@ -22,6 +22,12 @@ This strategy needs margin enabled in order to submit short orders, but you can
|
|||
- The MA window of the ATR indicator used by Supertrend.
|
||||
- `averageTrueRangeMultiplier`
|
||||
- Multiplier for calculating upper and lower bond prices, the higher, the stronger the trends are, but also makes it less sensitive.
|
||||
- `takeProfitMultiplier`
|
||||
- TP according to ATR multiple, 0 to disable this.
|
||||
- `stopLossByTriggeringK`
|
||||
- Set SL price to the low of the triggering Kline.
|
||||
- `tpslBySignal`
|
||||
- TP/SL by reversed signals.
|
||||
|
||||
|
||||
#### Examples
|
||||
|
|
|
@ -13,7 +13,8 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// TODO: Strategy control
|
||||
// TODO: Margin side effect
|
||||
// TODO: Update balance
|
||||
|
||||
const ID = "supertrend"
|
||||
|
||||
|
@ -143,7 +144,17 @@ type Strategy struct {
|
|||
// Leverage
|
||||
Leverage float64 `json:"leverage"`
|
||||
|
||||
bbgo.QuantityOrAmount
|
||||
// TakeProfitMultiplier TP according to ATR multiple, 0 to disable this
|
||||
TakeProfitMultiplier float64 `json:"takeProfitMultiplier"`
|
||||
|
||||
// StopLossByTriggeringK Set SL price to the low of the triggering Kline
|
||||
StopLossByTriggeringK bool `json:"stopLossByTriggeringK"`
|
||||
|
||||
// TPSLBySignal TP/SL by reversed signals
|
||||
TPSLBySignal bool `json:"tpslBySignal"`
|
||||
|
||||
currentTakeProfitPrice fixedpoint.Value
|
||||
currentStopLossPrice fixedpoint.Value
|
||||
|
||||
// StrategyController
|
||||
bbgo.StrategyController
|
||||
|
@ -275,6 +286,15 @@ func (s *Strategy) CalculateQuantity(currentPrice fixedpoint.Value) fixedpoint.V
|
|||
return quantity
|
||||
}
|
||||
|
||||
func (s *Strategy) HasTradableBase(currentPrice fixedpoint.Value) bool {
|
||||
base := s.Position.GetBase()
|
||||
quantity := base.Abs()
|
||||
if quantity.Compare(s.Market.MinQuantity) > 0 && quantity.Mul(currentPrice).Compare(s.Market.MinNotional) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, session *bbgo.ExchangeSession) error {
|
||||
s.session = session
|
||||
s.Market, _ = session.Market(s.Symbol)
|
||||
|
@ -306,7 +326,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
|
||||
s.OnEmergencyStop(func() {
|
||||
// Close 100% position
|
||||
_ = s.ClosePosition(ctx, fixedpoint.NewFromFloat(1.0))
|
||||
if err := s.ClosePosition(ctx, fixedpoint.One); err != nil {
|
||||
s.Notify("can not close position")
|
||||
}
|
||||
|
||||
_ = s.Persistence.Sync(s)
|
||||
})
|
||||
|
@ -314,6 +336,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
// Setup indicators
|
||||
s.SetupIndicators()
|
||||
|
||||
s.currentStopLossPrice = fixedpoint.Zero
|
||||
s.currentTakeProfitPrice = fixedpoint.Zero
|
||||
|
||||
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
||||
// StrategyController
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
|
@ -341,24 +366,35 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
demaSignal = types.DirectionNone
|
||||
}
|
||||
|
||||
// TP/SL
|
||||
base := s.Position.GetBase()
|
||||
quantity := base.Abs()
|
||||
if quantity.Compare(s.Market.MinQuantity) > 0 && quantity.Mul(kline.GetClose()).Compare(s.Market.MinNotional) > 0 {
|
||||
var side types.SideType
|
||||
if base.Sign() < 0 && (stSignal == types.DirectionUp || demaSignal == types.DirectionUp) {
|
||||
side = types.SideTypeBuy
|
||||
} else if base.Sign() > 0 && (stSignal == types.DirectionDown || demaSignal == types.DirectionDown) {
|
||||
side = types.SideTypeSell
|
||||
}
|
||||
if side == types.SideTypeBuy || side == types.SideTypeSell {
|
||||
orderForm := s.GenerateOrderForm(side, quantity)
|
||||
log.Infof("submit TP/SL order %v", orderForm)
|
||||
order, err := orderExecutor.SubmitOrders(ctx, orderForm)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not place TP/SL order")
|
||||
// TP/SL if there's non-dust position
|
||||
if s.HasTradableBase(kline.GetClose()) {
|
||||
baseSign := s.Position.GetBase().Sign()
|
||||
if s.StopLossByTriggeringK && !s.currentStopLossPrice.IsZero() && ((baseSign < 0 && kline.GetClose().Compare(s.currentStopLossPrice) > 0) || (baseSign > 0 && kline.GetClose().Compare(s.currentStopLossPrice) < 0)) {
|
||||
// SL by triggered Kline low
|
||||
if err := s.ClosePosition(ctx, fixedpoint.One); err != nil {
|
||||
s.Notify("can not place SL order")
|
||||
} else {
|
||||
s.currentStopLossPrice = fixedpoint.Zero
|
||||
s.currentTakeProfitPrice = fixedpoint.Zero
|
||||
}
|
||||
} else if s.TakeProfitMultiplier > 0 && !s.currentTakeProfitPrice.IsZero() && ((baseSign < 0 && kline.GetClose().Compare(s.currentTakeProfitPrice) < 0) || (baseSign > 0 && kline.GetClose().Compare(s.currentTakeProfitPrice) > 0)) {
|
||||
// TP by multiple of ATR
|
||||
if err := s.ClosePosition(ctx, fixedpoint.One); err != nil {
|
||||
s.Notify("can not place TP order")
|
||||
} else {
|
||||
s.currentStopLossPrice = fixedpoint.Zero
|
||||
s.currentTakeProfitPrice = fixedpoint.Zero
|
||||
}
|
||||
} else if s.TPSLBySignal {
|
||||
// Use signals to TP/SL
|
||||
if (baseSign < 0 && (stSignal == types.DirectionUp || demaSignal == types.DirectionUp)) || (baseSign > 0 && (stSignal == types.DirectionDown || demaSignal == types.DirectionDown)) {
|
||||
if err := s.ClosePosition(ctx, fixedpoint.One); err != nil {
|
||||
s.Notify("can not place TP/SL order")
|
||||
} else {
|
||||
s.currentStopLossPrice = fixedpoint.Zero
|
||||
s.currentTakeProfitPrice = fixedpoint.Zero
|
||||
}
|
||||
}
|
||||
s.orderStore.Add(order...)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,21 +402,43 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
var side types.SideType
|
||||
if stSignal == types.DirectionUp && demaSignal == types.DirectionUp {
|
||||
side = types.SideTypeBuy
|
||||
if s.StopLossByTriggeringK {
|
||||
s.currentStopLossPrice = kline.GetLow()
|
||||
}
|
||||
if s.TakeProfitMultiplier > 0 {
|
||||
s.currentTakeProfitPrice = kline.GetClose().Add(fixedpoint.NewFromFloat(s.SuperTrend.AverageTrueRange.Last() * s.TakeProfitMultiplier))
|
||||
}
|
||||
} else if stSignal == types.DirectionDown && demaSignal == types.DirectionDown {
|
||||
side = types.SideTypeSell
|
||||
if s.StopLossByTriggeringK {
|
||||
s.currentStopLossPrice = kline.GetHigh()
|
||||
}
|
||||
if s.TakeProfitMultiplier > 0 {
|
||||
s.currentTakeProfitPrice = kline.GetClose().Sub(fixedpoint.NewFromFloat(s.SuperTrend.AverageTrueRange.Last() * s.TakeProfitMultiplier))
|
||||
}
|
||||
}
|
||||
|
||||
if side == types.SideTypeSell || side == types.SideTypeBuy {
|
||||
baseSign := s.Position.GetBase().Sign()
|
||||
// Close opposite position if any
|
||||
if s.HasTradableBase(kline.GetClose()) && ((side == types.SideTypeSell && baseSign > 0) || (side == types.SideTypeBuy && baseSign < 0)) {
|
||||
if err := s.ClosePosition(ctx, fixedpoint.One); err != nil {
|
||||
s.Notify("can not place position close order")
|
||||
}
|
||||
}
|
||||
|
||||
orderForm := s.GenerateOrderForm(side, s.CalculateQuantity(kline.GetClose()))
|
||||
log.Infof("submit open position order %v", orderForm)
|
||||
order, err := orderExecutor.SubmitOrders(ctx, orderForm)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("can not place open position order")
|
||||
s.Notify("can not place open position order")
|
||||
} else {
|
||||
s.orderStore.Add(order...)
|
||||
}
|
||||
s.orderStore.Add(order...)
|
||||
}
|
||||
|
||||
s.tradeCollector.Process()
|
||||
s.tradeCollector.Process()
|
||||
}
|
||||
})
|
||||
|
||||
s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.Position, s.orderStore)
|
||||
|
|
Loading…
Reference in New Issue
Block a user