mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 23:05:15 +00:00
pivotshort: pull out stop price check to a single method
This commit is contained in:
parent
ef31e90728
commit
3604bae933
|
@ -5,10 +5,8 @@ import "github.com/c9s/bbgo/pkg/bbgo"
|
||||||
type ExitMethod struct {
|
type ExitMethod struct {
|
||||||
RoiStopLoss *RoiStopLoss `json:"roiStopLoss"`
|
RoiStopLoss *RoiStopLoss `json:"roiStopLoss"`
|
||||||
ProtectionStopLoss *ProtectionStopLoss `json:"protectionStopLoss"`
|
ProtectionStopLoss *ProtectionStopLoss `json:"protectionStopLoss"`
|
||||||
|
|
||||||
RoiTakeProfit *RoiTakeProfit `json:"roiTakeProfit"`
|
RoiTakeProfit *RoiTakeProfit `json:"roiTakeProfit"`
|
||||||
LowerShadowTakeProfit *LowerShadowTakeProfit `json:"lowerShadowTakeProfit"`
|
LowerShadowTakeProfit *LowerShadowTakeProfit `json:"lowerShadowTakeProfit"`
|
||||||
|
|
||||||
CumulatedVolumeTakeProfit *CumulatedVolumeTakeProfit `json:"cumulatedVolumeTakeProfit"`
|
CumulatedVolumeTakeProfit *CumulatedVolumeTakeProfit `json:"cumulatedVolumeTakeProfit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,20 @@ func (s *ProtectionStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *
|
||||||
s.handleChange(context.Background(), position, kline.Close, s.orderExecutor)
|
s.handleChange(context.Background(), position, kline.Close, s.orderExecutor)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if !bbgo.IsBackTesting {
|
||||||
|
session.MarketDataStream.OnMarketTrade(func(trade types.Trade) {
|
||||||
|
if trade.Symbol != position.Symbol {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.stopLossPrice.IsZero() || s.PlaceStopOrder {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.checkStopPrice(trade.Price, position)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProtectionStopLoss) handleChange(ctx context.Context, position *types.Position, closePrice fixedpoint.Value, orderExecutor *bbgo.GeneralOrderExecutor) {
|
func (s *ProtectionStopLoss) handleChange(ctx context.Context, position *types.Position, closePrice fixedpoint.Value, orderExecutor *bbgo.GeneralOrderExecutor) {
|
||||||
|
@ -136,19 +150,27 @@ func (s *ProtectionStopLoss) handleChange(ctx context.Context, position *types.P
|
||||||
|
|
||||||
log.Infof("[ProtectionStopLoss] %s protection stop loss activated, current price = %f, average cost = %f, stop loss price = %f",
|
log.Infof("[ProtectionStopLoss] %s protection stop loss activated, current price = %f, average cost = %f, stop loss price = %f",
|
||||||
position.Symbol, closePrice.Float64(), position.AverageCost.Float64(), s.stopLossPrice.Float64())
|
position.Symbol, closePrice.Float64(), position.AverageCost.Float64(), s.stopLossPrice.Float64())
|
||||||
|
|
||||||
|
if s.PlaceStopOrder {
|
||||||
|
if err := s.placeStopOrder(ctx, position, orderExecutor); err != nil {
|
||||||
|
log.WithError(err).Errorf("failed to place stop limit order")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// not activated, skip setup stop order
|
// not activated, skip setup stop order
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.PlaceStopOrder {
|
// check stop price
|
||||||
if err := s.placeStopOrder(ctx, position, orderExecutor); err != nil {
|
s.checkStopPrice(closePrice, position)
|
||||||
log.WithError(err).Errorf("failed to place stop limit order")
|
}
|
||||||
}
|
|
||||||
} else if s.shouldStop(closePrice) {
|
func (s *ProtectionStopLoss) checkStopPrice(closePrice fixedpoint.Value, position *types.Position) {
|
||||||
|
if s.shouldStop(closePrice) {
|
||||||
log.Infof("[ProtectionStopLoss] protection stop order is triggered at price %f, position = %+v", closePrice.Float64(), position)
|
log.Infof("[ProtectionStopLoss] protection stop order is triggered at price %f, position = %+v", closePrice.Float64(), position)
|
||||||
if err := orderExecutor.ClosePosition(ctx, one); err != nil {
|
if err := s.orderExecutor.ClosePosition(context.Background(), one); err != nil {
|
||||||
log.WithError(err).Errorf("failed to close position")
|
log.WithError(err).Errorf("failed to close position")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,30 @@ func (s *RoiStopLoss) Bind(session *bbgo.ExchangeSession, orderExecutor *bbgo.Ge
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
closePrice := kline.Close
|
s.checkStopPrice(kline.Close, position)
|
||||||
if position.IsClosed() || position.IsDust(closePrice) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
roi := position.ROI(closePrice)
|
|
||||||
if roi.Compare(s.Percentage.Neg()) < 0 {
|
|
||||||
// stop loss
|
|
||||||
bbgo.Notify("[RoiStopLoss] %s stop loss triggered by ROI %s/%s, price: %f", position.Symbol, roi.Percentage(), s.Percentage.Neg().Percentage(), kline.Close.Float64())
|
|
||||||
_ = orderExecutor.ClosePosition(context.Background(), fixedpoint.One)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if !bbgo.IsBackTesting {
|
||||||
|
session.MarketDataStream.OnMarketTrade(func(trade types.Trade) {
|
||||||
|
if trade.Symbol != position.Symbol {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.checkStopPrice(trade.Price, position)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RoiStopLoss) checkStopPrice(closePrice fixedpoint.Value, position *types.Position) {
|
||||||
|
if position.IsClosed() || position.IsDust(closePrice) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
roi := position.ROI(closePrice)
|
||||||
|
if roi.Compare(s.Percentage.Neg()) < 0 {
|
||||||
|
// stop loss
|
||||||
|
bbgo.Notify("[RoiStopLoss] %s stop loss triggered by ROI %s/%s, price: %f", position.Symbol, roi.Percentage(), s.Percentage.Neg().Percentage(), closePrice.Float64())
|
||||||
|
_ = s.orderExecutor.ClosePosition(context.Background(), fixedpoint.One)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,10 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
||||||
if s.BounceShort != nil && s.BounceShort.Enabled {
|
if s.BounceShort != nil && s.BounceShort.Enabled {
|
||||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.BounceShort.Interval})
|
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.BounceShort.Interval})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !bbgo.IsBackTesting {
|
||||||
|
session.Subscribe(types.MarketTradeChannel, s.Symbol, types.SubscribeOptions{})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) useQuantityOrBaseBalance(quantity fixedpoint.Value) fixedpoint.Value {
|
func (s *Strategy) useQuantityOrBaseBalance(quantity fixedpoint.Value) fixedpoint.Value {
|
||||||
|
@ -189,6 +193,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.TradeStats = &types.TradeStats{}
|
s.TradeStats = &types.TradeStats{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.lastLow = fixedpoint.Zero
|
||||||
|
|
||||||
// StrategyController
|
// StrategyController
|
||||||
s.Status = types.StrategyStatusRunning
|
s.Status = types.StrategyStatusRunning
|
||||||
|
|
||||||
|
@ -230,7 +236,13 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.stopEWMA = standardIndicator.EWMA(*s.BreakLow.StopEMA)
|
s.stopEWMA = standardIndicator.EWMA(*s.BreakLow.StopEMA)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.lastLow = fixedpoint.Zero
|
for _, method := range s.ExitMethods {
|
||||||
|
method.Bind(session, s.orderExecutor)
|
||||||
|
}
|
||||||
|
|
||||||
|
session.MarketDataStream.OnMarketTrade(func(trade types.Trade) {
|
||||||
|
log.Info(trade)
|
||||||
|
})
|
||||||
|
|
||||||
session.UserDataStream.OnStart(func() {
|
session.UserDataStream.OnStart(func() {
|
||||||
lastKLine := s.preloadPivot(s.pivot, store)
|
lastKLine := s.preloadPivot(s.pivot, store)
|
||||||
|
@ -264,10 +276,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, method := range s.ExitMethods {
|
|
||||||
method.Bind(session, s.orderExecutor)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always check whether you can open a short position or not
|
// Always check whether you can open a short position or not
|
||||||
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
||||||
if s.Status != types.StrategyStatusRunning {
|
if s.Status != types.StrategyStatusRunning {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user