Открыть на GitHub

Стратегия Range Breakout Weekly (ID 3412)

Range Breakout Weekly — это реализация эксперта MetaTrader 5 RangeBreakout.mq5, переписанная на высокоуровневый API StockSharp. Алгоритм еженедельно подготавливает торговый диапазон для заданного дня недели и часа, а затем открывает единственную позицию при пробое верхней или нижней границы. Маркетинговое масштабирование объёма и механизм компенсации убытков сохранены, при этом используются подписки StockSharp на свечи, котировки Level1 и индикаторы.

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

  1. Подготовка раз в неделю. После закрытия часовой свечи в выбранный день недели стратегия фиксирует её цену закрытия как базовую и переводит состояние из режима «Ожидание» в «Подготовка».
  2. Расчёт диапазона.
    • Основой служит дневной ATR с периодом 20. Полученное значение умножается на ATR Percentage и нормализуется по минимальному шагу цены.
    • Если актуальное значение ATR ещё не получено, используется запасной вариант: текущая цена Ask умножается на Price Percentage.
  3. Защитные уровни.
    • Верхний и нижний триггеры располагаются на величину диапазона выше и ниже базовой цены.
    • Расстояния до тейк-профита и стоп-лосса задаются процентами от диапазона. После убыточной сделки компенсационный буфер заменяет тейк-профит на накопленное значение и расширяет стоп на ту же величину, полностью повторяя исходный алгоритм.
  4. Исполнение заявок.
    • В режиме «Подготовка» анализируются котировки Level1. Пробой верхней границы открывает длинную позицию, пробой нижней — короткую. Используются рыночные заявки с нормализацией цены.
    • В режиме «Торговля» котировки продолжают отслеживаться, срабатывание цели или стопа приводит к немедленному закрытию позиции рыночной заявкой.
  5. Мартингейл и компенсация.
    • После убыточного выхода объём следующей сделки удваивается, а потерянное расстояние добавляется в компенсационный буфер.
    • При прибыльном выходе множитель и буфер сбрасываются.
  6. Возврат к ожиданию. По завершении сделки стратегия возвращается в состояние «Ожидание» и ждёт следующего подходящего дня и часа.

Параметры

Параметр Значение по умолчанию Описание
Trading Day Monday День недели, в который формируется опорная свеча. При выборе субботы или воскресенья день автоматически заменяется на понедельник с информирующим логом.
Start Hour 0 Час (0–23), закрытие которого используется как база для расчёта. Параметр доступен для оптимизации.
Price Percentage 1.0 Процент от текущего Ask, применяемый, когда ATR ещё не сформирован.
ATR Percentage 100 Множитель дневного ATR для вычисления ширины диапазона.
Take Profit Percentage 100 Процент диапазона, добавляемый к цене входа для формирования тейк-профита. При активной компенсации заменяется накопленным значением.
Stop Loss Percentage 100 Процент диапазона, вычитаемый от цены входа для стоп-лосса. Компенсация расширяет стоп на ту же величину.
Base Volume 0.1 Базовый объём сделки до применения мартингейла. Значение приводится к шагу объёма и ограничивается минимумом/максимумом инструмента.
ATR Period 20 Количество дневных свечей, передаваемых индикатору ATR.
Hour Candle Type Свечи 1 час Подписка на свечи, определяющая момент подготовки диапазона.
ATR Candle Type Свечи 1 день Подписка на свечи, снабжающая индикатор ATR данными.

Особенности реализации

  • Подписки на данные. Используются три подписки: часовые свечи для расписания, дневные свечи для ATR и Level1 для контроля цен Bid/Ask. API Bind позволяет получать значения индикатора без ручной работы с буферами.
  • Нормализация цен. Все уровни проходят через Security.ShrinkPrice, что соответствует функции NormalizeDouble из MetaTrader и гарантирует корректные шаги цены.
  • Проверка объёма. Перед отправкой заявок объём корректируется по VolumeStep и ограничивается интервалом [VolumeMin, VolumeMax], полностью повторяя MQL-функцию SetVolume.
  • Машина состояний. Состояния «Ожидание» → «Подготовка» → «Торговля» обеспечивают ровно одну сделку на подготовительный период. После закрытия позиции состояние сбрасывается.
  • Компенсационный буфер. Поле compensationOffset хранит сумму убытков в ценовом выражении; при включении оно заменяет тейк-профит и расширяет стоп, как это делает исходный эксперт.
  • Информационные сообщения. При выборе выходных дней в лог выводится предупреждение, а рабочий день меняется на понедельник.

Рекомендации по применению

  1. Подбирайте Trading Day и Start Hour под конкретные сессии: например, азиатский флэт или открытие Лондона.
  2. Настраивайте ATR Percentage, Take Profit Percentage и Stop Loss Percentage совместно. Рост диапазона уменьшает частоту сделок, а изменение процентных значений влияет на соотношение риск/прибыль.
  3. Используйте оптимизацию для поиска подходящих значений часа старта, базового объёма и процентных коэффициентов, как это делалось в исходном советнике.
  4. Контролируйте рост экспозиции при мартингейле — при высокой нагрузке на депозит уменьшайте Base Volume.
  5. Запускайте несколько экземпляров стратегии с разными инструментами или параметрами, чтобы распределить риски.

Детали конверсии

  • ✅ Сохранены расписание, расчёт диапазона, защитные уровни и мартингейл-логика оригинального советника.
  • ✅ Все обращения к API MetaTrader (iATR, CopyBuffer, OrderSend и др.) заменены на идиоматичные вызовы StockSharp (SubscribeCandles, AverageTrueRange, BuyMarket/SellMarket).
  • ✅ Комментарии в коде написаны на английском языке, а документация подробно описывает работу стратегии.
  • ✅ Python-версия и тестовые проекты не затрагивались, как требовалось в задании.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Range Breakout Weekly strategy: periodic range breakout using highest/lowest channels.
/// Buys on breakout above recent high, sells on breakout below recent low.
/// </summary>
public class RangeBreakoutWeeklyStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _channelPeriod;

	private decimal _prevHigh;
	private decimal _prevLow;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }

	public RangeBreakoutWeeklyStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_channelPeriod = Param(nameof(ChannelPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Channel Period", "Highest/Lowest period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHigh = 0m;
		_prevLow = 0m;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(highest, lowest, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal highValue, decimal lowValue)
	{
		if (candle.State != CandleStates.Finished) return;

		var close = candle.ClosePrice;

		if (_hasPrev)
		{
			if (close > _prevHigh && Position <= 0)
				BuyMarket();
			else if (close < _prevLow && Position >= 0)
				SellMarket();
		}

		_prevHigh = highValue;
		_prevLow = lowValue;
		_hasPrev = true;
	}
}