Открыть на GitHub

Стратегия RangeBreakout2

Описание

RangeBreakout2 — перенос советника MetaTrader "RangeBreakout2" на платформу StockSharp. Стратегия в заданные моменты строит ценовой диапазон и открывает одну рыночную сделку при выходе бид/аск за его пределы. После закрытия позиции цикл подготовки диапазона запускается заново. Перенесены все режимы управления объёмом (Constant, Linear, Martingale, Fibonacci) и расширение тейк‑профита после убыточной сделки.

Алгоритм работает по одному инструменту и использует лучшие котировки. Для корректной работы необходима онлайн‑лента стакана (best bid/ask).

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

  1. Расписание — в заданный день/час фиксируется текущая цена Ask, вокруг которой строятся уровни пробоя.
  2. Расчёт диапазона — исходная ширина определяется одним из трёх способов:
    • ATR — берётся значение ATR и умножается на AtrPercentage.
    • Percent — используется PricePercentage процентов от текущей цены Ask.
    • FixedFixedRangePoints переводится в абсолютную величину через шаг цены.
  3. Отслеживание пробоя — пока стратегия находится в фазе Setup, анализируются котировки bid/ask. Выход Ask выше верхнего уровня или Bid ниже нижнего уровня приводит к отправке рыночной заявки.
  4. Тип входа — параметр TradeMode задаёт направление торговли: пробой (Stop), контртренд (Limit) или случайный выбор при каждом сигнале.
  5. Защита позиции — стоп‑лосс и тейк‑профит вычисляются от базового диапазона. После убыточной сделки тейк‑профит можно расширить с помощью RangeMultiplier.
  6. Управление объёмом — базовый объём рассчитывается от свободного капитала портфеля (CurrentValue - BlockedValue). Далее применяется выбранный режим:
    • Constant — всегда торгуется базовый объём.
    • Linear — при убыточной сделке объём увеличивается линейно.
    • Martingale — объём умножается на LotMultiplier после убытка.
    • Fibonacci — применяется последовательность Фибоначчи для убыточной серии.

После закрытия позиции стратегия возвращается в фазу ожидания и ждёт следующего срабатывания расписания.

Параметры

Группа Параметр Описание Значение по умолчанию
Расписание Periodicity Частота построения диапазона: Weekly / Daily / NonStop. Weekly
Расписание Day День недели для weekly‑режима. Monday
Расписание Hour Час формирования диапазона (значение из MQL увеличено на 1 и при ≥23 сбрасывается в 0). 0
Диапазон RangeMode Способ расчёта ширины (ATR / Percent / Fixed). Atr
Диапазон AtrPercentage Процент от ATR. 50
Диапазон AtrLength Длина ATR в свечах. 20
Диапазон PricePercentage Процент от цены Ask для режима Percent. 1
Диапазон FixedRangePoints Фиксированный диапазон в шагах цены. 1000
Торговля RangePercentage Процент от исходного диапазона для уровней пробоя. 100
Торговля TradeMode Тип входа: пробой / контртренд / случайно. Stop
Торговля TakeProfitPercentage Дистанция тейк‑профита в процентах от диапазона. 100
Торговля StopLossPercentage Дистанция стоп‑лосса в процентах от базового диапазона. 100
Риск LotMode Схема управления объёмом (Constant / Linear / Martingale / Fibonacci). Martingale
Риск MarginPercentage Доля свободного капитала, выделяемая на базовый объём. 10
Риск LotMultiplier Множитель объёма для мартингейла и подобных режимов. 2
Риск RangeMultiplier Увеличение тейк‑профита после убытка. 1
Данные SignalCandleType Тип свечей для проверки расписания. 1 минута
Данные AtrCandleType Тип свечей для расчёта ATR (используется только при RangeMode = Atr). 1 день

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

  • Для корректной работы стратегии необходимы актуальные котировки bid/ask. Без них пробой не будет определён.
  • При отсутствии данных портфеля (CurrentValue, BlockedValue) объём заявок сводится к минимальному объёму инструмента.
  • Защитные заявки выставляются методами SetStopLoss и SetTakeProfit, куда передаётся итоговая позиция после входа.
  • Если ATR ещё не сформирован, диапазон по умолчанию равен 1% от текущей цены Ask — поведение полностью повторяет оригинальный советник.
  • В режиме Random направление (пробой или контртренд) выбирается при каждом срабатывании при помощи стандартного генератора Random.

Рекомендации

  1. Подбирайте SignalCandleType в зависимости от желаемой точности расписания. Свечи 1m максимально близки к тиковой логике MetaTrader.
  2. Убедитесь, что часовой пояс терминала соответствует ожиданиям оригинального советника, иначе weekly/daily режимы могут сработать не вовремя.
  3. Использование RangeMultiplier > 1 вместе с мартингейлом сильно увеличивает нагрузку на счёт при серии убытков.
  4. Увеличение RangePercentage автоматически расширяет стоп и тейк‑профит — учитывайте это при подборе параметров.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Range Breakout 2 strategy: Donchian channel breakout.
/// Buys on new high breakout, sells on new low breakout.
/// </summary>
public class RangeBreakout2Strategy : 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 RangeBreakout2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_channelPeriod = Param(nameof(ChannelPeriod), 30)
			.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;
	}
}