Открыть на GitHub

Стратегия Zone Recovery Hedge

Zone Recovery Hedge Strategy — это порт советника MetaTrader Zone Recovery Hedge V1 на платформу StockSharp. Алгоритм чередует покупки и продажи вокруг опорной цены, открывая новую сделку при выходе цены за границы восстановительной зоны. Объём каждой последующей сделки увеличивается по мартингейлу, что позволяет закрыть серию как только суммарная плавающая прибыль достигает заданной цели или срабатывает ограничение по убытку.

Логика работы

  1. Фильтр входа. В режиме RSI Multi-Timeframe стратегия анализирует выбранные таймфреймы (от M1 до MN1) и ждёт, пока RSI на всех активных периодах одновременно выйдет из зоны перекупленности/перепроданности. Выход из перепроданности запускает цикл покупок, а выход из перекупленности — цикл продаж. В режиме Manual автоматические сигналы отключены и новую серию можно запустить методами StartManualMarketCycle или StartManualPendingCycle.
  2. Первый ордер. Начальный объём рассчитывается либо как фиксированный лот, либо как процент от капитала исходя из планируемой дистанции стопа. При включённом ATR длина стопа и ширина зоны берутся из дневного ATR; без ATR используются значения в пунктах брокера.
  3. Восстановительная сетка. Если цена проходит против текущего направления расстояние зоны, стратегия открывает противоположный ордер с увеличенным лотом (по таблице кастомных значений, через множитель или через добавку). Серия чередует направления вокруг исходной цены до тех пор, пока не достигнута цель по прибыли или не исчерпан лимит сделок.
  4. Контроль прибыли. Цель задаётся в деньгах. Используется базовый тейк-профит или отдельный recovery-тейк (с возможностью расчёта от ATR). Параметр Test Commission позволяет учесть комиссии при оценке цели. Когда плавающая прибыль превышает цель с учётом издержек, все позиции закрываются.
  5. Защита капитала. Если MaxTrades больше нуля и активен флаг SetMaxLoss, то при достижении максимума сделок и просадке ниже MaxLoss серия принудительно закрывается.

Важно. В StockSharp позиции учётные (netting). Поэтому восстановительная логика реализована через разворот совокупной позиции, а не через одновременное удержание покупок и продаж, как в MT4. При этом последовательность шагов и расчёт прибыли сохранены.

Основные параметры

  • CandleType — рабочий таймфрейм.
  • ModeManual (только ручные циклы) или RsiMultiTimeframe (автосигналы по RSI).
  • RsiPeriod, OverboughtLevel, OversoldLevel, флаги UseM1TimeframeUseMonthlyTimeframe — настройка RSI на разных периодах.
  • TradeOnBarOpen — использовать предыдущий бар в качестве подтверждения (как в оригинале).
  • RecoveryZoneSize, TakeProfitPoints — ширина зоны и базовый тейк-профит без ATR.
  • UseAtr, AtrPeriod, AtrZoneFraction, AtrTakeProfitFraction, AtrRecoveryFraction, AtrCandleType — параметры ATR.
  • UseRecoveryTakeProfit, RecoveryTakeProfitPoints — отдельная цель после входа в фазу восстановления.
  • MaxTrades, SetMaxLoss, MaxLoss, TestCommission — ограничения по сериям и учёт комиссий.
  • RiskPercent, InitialLotSize, LotMultiplier, LotAddition, CustomLotSize1CustomLotSize10 — алгоритм подбора объёмов.
  • UseTimer, StartHour, StartMinute, EndHour, EndMinute, UseLocalTime — торговое окно.
  • 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;
	}
}