Zone Recovery Hedge Strategy — это порт советника MetaTrader Zone Recovery Hedge V1 на платформу StockSharp. Алгоритм чередует покупки и продажи вокруг опорной цены, открывая новую сделку при выходе цены за границы восстановительной зоны. Объём каждой последующей сделки увеличивается по мартингейлу, что позволяет закрыть серию как только суммарная плавающая прибыль достигает заданной цели или срабатывает ограничение по убытку.
Логика работы
Фильтр входа. В режиме RSI Multi-Timeframe стратегия анализирует выбранные таймфреймы (от M1 до MN1) и ждёт, пока RSI на всех активных периодах одновременно выйдет из зоны перекупленности/перепроданности. Выход из перепроданности запускает цикл покупок, а выход из перекупленности — цикл продаж. В режиме Manual автоматические сигналы отключены и новую серию можно запустить методами StartManualMarketCycle или StartManualPendingCycle.
Первый ордер. Начальный объём рассчитывается либо как фиксированный лот, либо как процент от капитала исходя из планируемой дистанции стопа. При включённом ATR длина стопа и ширина зоны берутся из дневного ATR; без ATR используются значения в пунктах брокера.
Восстановительная сетка. Если цена проходит против текущего направления расстояние зоны, стратегия открывает противоположный ордер с увеличенным лотом (по таблице кастомных значений, через множитель или через добавку). Серия чередует направления вокруг исходной цены до тех пор, пока не достигнута цель по прибыли или не исчерпан лимит сделок.
Контроль прибыли. Цель задаётся в деньгах. Используется базовый тейк-профит или отдельный recovery-тейк (с возможностью расчёта от ATR). Параметр Test Commission позволяет учесть комиссии при оценке цели. Когда плавающая прибыль превышает цель с учётом издержек, все позиции закрываются.
Защита капитала. Если MaxTrades больше нуля и активен флаг SetMaxLoss, то при достижении максимума сделок и просадке ниже MaxLoss серия принудительно закрывается.
Важно. В StockSharp позиции учётные (netting). Поэтому восстановительная логика реализована через разворот совокупной позиции, а не через одновременное удержание покупок и продаж, как в MT4. При этом последовательность шагов и расчёт прибыли сохранены.
Основные параметры
CandleType — рабочий таймфрейм.
Mode — Manual (только ручные циклы) или RsiMultiTimeframe (автосигналы по RSI).
RsiPeriod, OverboughtLevel, OversoldLevel, флаги UseM1Timeframe … UseMonthlyTimeframe — настройка RSI на разных периодах.
TradeOnBarOpen — использовать предыдущий бар в качестве подтверждения (как в оригинале).
RecoveryZoneSize, TakeProfitPoints — ширина зоны и базовый тейк-профит без ATR.
PendingPrice — опорная цена для метода StartManualPendingCycle.
Рекомендации
Источник данных должен предоставлять таймфреймы, выбранные для RSI. При необходимости старшие периоды собираются из базового интервала.
В ручном режиме используйте StartManualMarketCycle(true/false) для мгновенного запуска серии по рынку или StartManualPendingCycle для запуска от заданной цены.
При расчёте по проценту риска значение автоматически ограничивается десятью процентами депозита, как и в версии для MT4.
Для корректного расчёта прибыли необходимы параметры PriceStep и StepPrice инструмента.
Отличия от версии MetaTrader
Нет графической панели, кнопок и линий тейк-профита — управление осуществляется через параметры и методы.
Расчёт спреда не реализован, учитывается только заданная комиссия TestCommission.
Из-за netting учёта сделки противоположных направлений взаимно уменьшают позицию, однако логика чередования и наращивания объёма сохранена.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Zone Recovery Hedge strategy: RSI mean reversion with trend filter.
/// Buys when RSI crosses above oversold with close above SMA, sells on overbought cross below SMA.
/// </summary>
public class ZoneRecoveryHedgeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _smaPeriod;
private decimal _prevRsi;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public ZoneRecoveryHedgeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_smaPeriod = Param(nameof(SmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA trend filter period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, sma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal smaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevRsi < 30 && rsiValue >= 30 && candle.ClosePrice > smaValue && Position <= 0)
BuyMarket();
else if (_prevRsi > 70 && rsiValue <= 70 && candle.ClosePrice < smaValue && Position >= 0)
SellMarket();
}
_prevRsi = rsiValue;
_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
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class zone_recovery_hedge_strategy(Strategy):
def __init__(self):
super(zone_recovery_hedge_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._sma_period = self.Param("SmaPeriod", 50)
self._prev_rsi = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def SmaPeriod(self):
return self._sma_period.Value
@SmaPeriod.setter
def SmaPeriod(self, value):
self._sma_period.Value = value
def OnReseted(self):
super(zone_recovery_hedge_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(zone_recovery_hedge_strategy, self).OnStarted2(time)
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
sma = SimpleMovingAverage()
sma.Length = self.SmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, sma, self._process_candle).Start()
def _process_candle(self, candle, rsi_value, sma_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
sma_val = float(sma_value)
close = float(candle.ClosePrice)
if self._has_prev:
if self._prev_rsi < 30 and rsi_val >= 30 and close > sma_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_rsi > 70 and rsi_val <= 70 and close < sma_val and self.Position >= 0:
self.SellMarket()
self._prev_rsi = rsi_val
self._has_prev = True
def CreateClone(self):
return zone_recovery_hedge_strategy()