diff --git a/pkg/bbgo/exit_roi_stop_loss.go b/pkg/bbgo/exit_roi_stop_loss.go index 606002218..b57a8f52e 100644 --- a/pkg/bbgo/exit_roi_stop_loss.go +++ b/pkg/bbgo/exit_roi_stop_loss.go @@ -3,14 +3,23 @@ package bbgo import ( "context" + log "github.com/sirupsen/logrus" + "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) type RoiStopLoss struct { - Symbol string + Symbol string + + // Percentage is the ROI loss percentage + // 1% means when you loss 1% and it will close the position Percentage fixedpoint.Value `json:"percentage"` + // Partial is a percentage of the position to be closed + // 50% means you will close halt the position + Partial fixedpoint.Value `json:"partial,omitempty"` + session *ExchangeSession orderExecutor *GeneralOrderExecutor } @@ -47,10 +56,25 @@ func (s *RoiStopLoss) checkStopPrice(closePrice fixedpoint.Value, position *type roi := position.ROI(closePrice) // logrus.Debugf("ROIStopLoss: price=%f roi=%s stop=%s", closePrice.Float64(), roi.Percentage(), s.Percentage.Neg().Percentage()) - if roi.Compare(s.Percentage.Neg()) < 0 { - // stop loss - 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, "roiStopLoss") + + if roi.Compare(s.Percentage.Neg()) > 0 { return } + + // default to close the whole position + percent := one + if !s.Partial.IsZero() { + percent = s.Partial + } + + Notify("[RoiStopLoss] %s stop loss triggered by ROI %s/%s, price: %f, closing: %s", + position.Symbol, + roi.Percentage(), + s.Percentage.Neg().Percentage(), + closePrice.Float64(), + percent.Percentage()) + + if err := s.orderExecutor.ClosePosition(context.Background(), percent, "roiStopLoss"); err != nil { + log.WithError(err).Error("failed to close position") + } } diff --git a/pkg/bbgo/exit_roi_take_profit.go b/pkg/bbgo/exit_roi_take_profit.go index d6af7d771..c4bc92e48 100644 --- a/pkg/bbgo/exit_roi_take_profit.go +++ b/pkg/bbgo/exit_roi_take_profit.go @@ -3,6 +3,8 @@ package bbgo import ( "context" + log "github.com/sirupsen/logrus" + "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) @@ -12,6 +14,10 @@ type RoiTakeProfit struct { Symbol string `json:"symbol"` Percentage fixedpoint.Value `json:"percentage"` + // Partial is a percentage of the position to be closed + // 50% means you will close halt the position + Partial fixedpoint.Value `json:"partial,omitempty"` + session *ExchangeSession orderExecutor *GeneralOrderExecutor } @@ -33,11 +39,26 @@ func (s *RoiTakeProfit) Bind(session *ExchangeSession, orderExecutor *GeneralOrd } roi := position.ROI(closePrice) - if roi.Compare(s.Percentage) >= 0 { - // stop loss - Notify("[RoiTakeProfit] %s take profit is triggered by ROI %s/%s, price: %f", position.Symbol, roi.Percentage(), s.Percentage.Percentage(), kline.Close.Float64()) - _ = orderExecutor.ClosePosition(context.Background(), fixedpoint.One, "roiTakeProfit") + if roi.Compare(s.Percentage) < 0 { return } + + // default to close the whole position + percent := one + if !s.Partial.IsZero() { + percent = s.Partial + } + + // stop loss + Notify("[RoiTakeProfit] %s take profit is triggered by ROI %s/%s, price: %f, closing: %s", + position.Symbol, + roi.Percentage(), + s.Percentage.Percentage(), + kline.Close.Float64(), + percent.Percentage()) + + if err := orderExecutor.ClosePosition(context.Background(), percent, "roiTakeProfit"); err != nil { + log.WithError(err).Error("failed to close position") + } })) }