价格回撤策略
该策略用于交易日内价格缺口。 在选定的交易日开始时,比较上一根收盘价与24小时前的开盘价。 当差值超过 Corridor 参数时,在期望回撤的方向开仓:
- 向上跳空 → 做空。
- 向下跳空 → 做多。
交易使用固定的止损和止盈距离。 当持仓盈利时启用带步长的跟踪止损。 所有持仓在接近收盘时段(22:45)被关闭。
参数
Corridor– 缺口阈值。StopLoss– 固定止损距离。TakeProfit– 固定止盈目标。TrailingStop– 跟踪止损距离。TrailingStep– 更新跟踪止损所需的移动。TradingDay– 开仓的星期几(0=周日)。CandleType– 计算所用的时间框架。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Price rollback strategy that detects price gaps (large moves) and trades the pullback.
/// When price gaps up beyond a corridor, it sells expecting rollback.
/// When price gaps down beyond a corridor, it buys expecting rollback.
/// Uses trailing stop and take profit for exits.
/// </summary>
public class PriceRollbackStrategy : Strategy
{
private readonly StrategyParam<decimal> _corridor;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _trailingStop;
private readonly StrategyParam<DataType> _type;
private decimal _prevClose;
private bool _hasPrev;
public decimal Corridor { get => _corridor.Value; set => _corridor.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal TrailingStop { get => _trailingStop.Value; set => _trailingStop.Value = value; }
public DataType CandleType { get => _type.Value; set => _type.Value = value; }
public PriceRollbackStrategy()
{
_corridor = Param(nameof(Corridor), 5000m)
.SetDisplay("Corridor", "Minimum gap size for entry", "General");
_stopLoss = Param(nameof(StopLoss), 500m)
.SetDisplay("Stop Loss", "Stop loss distance", "Risk");
_takeProfit = Param(nameof(TakeProfit), 400m)
.SetDisplay("Take Profit", "Take profit distance", "Risk");
_trailingStop = Param(nameof(TrailingStop), 300m)
.SetDisplay("Trailing Stop", "Trailing stop distance", "Risk");
_type = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0m;
_hasPrev = false;
}
public override IEnumerable<(Security, DataType)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var atr = new AverageTrueRange { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, atr);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (_hasPrev && Position == 0)
{
// Detect strong candle move (body > corridor) - trade rollback
var body = close - candle.OpenPrice;
var bodySize = Math.Abs(body);
if (bodySize > atrValue * 1.5m)
{
// Strong move up - sell expecting rollback
if (body > 0)
{
SellMarket();
}
// Strong move down - buy expecting rollback
else if (body < 0)
{
BuyMarket();
}
}
}
_prevClose = close;
_hasPrev = true;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class price_rollback_strategy(Strategy):
def __init__(self):
super(price_rollback_strategy, self).__init__()
self._corridor = self.Param("Corridor", 5000.0)
self._stop_loss = self.Param("StopLoss", 500.0)
self._take_profit = self.Param("TakeProfit", 400.0)
self._trailing_stop = self.Param("TrailingStop", 300.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_close = 0.0
self._entry_price = 0.0
self._trail_price = 0.0
self._has_prev = False
@property
def Corridor(self):
return self._corridor.Value
@Corridor.setter
def Corridor(self, value):
self._corridor.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def TrailingStop(self):
return self._trailing_stop.Value
@TrailingStop.setter
def TrailingStop(self, value):
self._trailing_stop.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(price_rollback_strategy, self).OnStarted2(time)
self._has_prev = False
self._entry_price = 0.0
self._trail_price = 0.0
self._prev_close = 0.0
atr = AverageTrueRange()
atr.Length = 14
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(atr, self.ProcessCandle).Start()
self.StartProtection(
Unit(2.0, UnitTypes.Percent),
Unit(1.0, UnitTypes.Percent))
def ProcessCandle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
atr_val = float(atr_value)
if self._has_prev and self.Position == 0:
body = close - open_price
body_size = abs(body)
if body_size > atr_val * 1.5:
if body > 0.0:
self.SellMarket()
elif body < 0.0:
self.BuyMarket()
self._prev_close = close
self._has_prev = True
def OnReseted(self):
super(price_rollback_strategy, self).OnReseted()
self._prev_close = 0.0
self._entry_price = 0.0
self._trail_price = 0.0
self._has_prev = False
def CreateClone(self):
return price_rollback_strategy()