Открыть на GitHub

Стратегия Early Bird Range Break

Обзор

Early Bird Range Break — порт MetaTrader-советника "earlyBird3" на C#. Стратегия отслеживает утренний боковой диапазон, формирующийся перед европейской сессией, и торгует его пробой. Для подтверждения используется RSI с периодом 14. При появлении сигнала выставляются три рыночных ордера, каждый со своим тейк-профитом, общим стоп-лоссом и опциональным трейлингом, который активируется только при росте волатильности.

Требования к данным

  • Поток свечей одного таймфрейма (по умолчанию 5 минут) по торгуемому инструменту.
  • У инструмента должен быть задан PriceStep, поскольку все дистанции указаны в пунктах.
  • Временные фильтры используют метки времени свечей (то есть серверное время поставщика данных).

Торговая сессия

  1. Построение диапазона — между RangeStartHour и RangeEndHour фиксируются максимумы и минимумы.
  2. Окно торговли — после TradingStartHour:TradingStartMinute и до TradingEndHour работает логика пробоя.
  3. Принудительное закрытие — в ClosingHour стратегия закрывает все позиции независимо от результата.
  4. Рабочие дни — сигналы учитываются только с понедельника по пятницу.

Логика входа

  1. Уровень покупки = максимум диапазона + EntryBufferPoints; уровень продажи = минимум диапазона - EntryBufferPoints (в пунктах).
  2. Для длинной позиции RSI должен быть > 50, для короткой — ≤ 50.
  3. В день допускается по одному пробою в каждую сторону. При срабатывании выставляются три рыночных ордера (по умолчанию по 0.1 лота).
  4. Если открыта позиция в противоположную сторону и HedgeTrading = false, сигнал игнорируется. При HedgeTrading = true стратегия сначала закрывает текущую позицию и затем открывает новую — это имитирует хеджирование оригинального советника в условиях неттингового учёта StockSharp.

Управление позицией

  1. Стоп-лосс — общий уровень StopLossPoints, пересчитанный в цену. При его достижении оставшийся объём закрывается.
  2. Лестница тейк-профитов — значения TakeProfit1Points, TakeProfit2Points, TakeProfit3Points закрывают по одной части позиции. Последняя часть остаётся в рынке до срабатывания стоп-лосса/трейлинга или конца сессии.
  3. Трейлинг-стоп — активируется только когда осталась одна часть позиции. Текущий диапазон свечи должен превышать ATR * TrailingRiskMultiplier, а цена должна пройти не меньше TrailingStopPoints. После этого стоп подтягивается, сохраняя исходное расстояние.
  4. Закрытие дня — по наступлении ClosingHour стратегия полностью выходит из рынка.

Параметры

Параметр Описание Значение по умолчанию
AutoTrading Включение/выключение торговли. true
HedgeTrading Разрешить разворот при противоположном сигнале (реализовано через закрытие и открытие в обратную сторону). true
OrderType 0 — обе стороны, 1 — только long, 2 — только short. 0
TradeVolume Объём каждого рыночного ордера. 0.1
StopLossPoints Дистанция стоп-лосса в пунктах. 60
TakeProfit1Points Тейк-профит для первой части позиции. 10
TakeProfit2Points Тейк-профит для второй части. 20
TakeProfit3Points Тейк-профит для третьей части. 30
TrailingStopPoints Минимальный прогресс цены для включения трейлинга. 15
TrailingRiskMultiplier Множитель ATR при проверке роста волатильности. 1.0
EntryBufferPoints Дополнительный буфер к уровням пробоя. 2
RangeStartHour Начало формирования диапазона (час). 3
RangeEndHour Окончание формирования диапазона (час). 7
TradingStartHour Час начала торговли пробоев. 7
TradingStartMinute Минута начала торговли пробоев. 15
TradingEndHour Час остановки новых входов. 15
ClosingHour Час принудительного закрытия позиций. 17
RsiPeriod Период RSI. 14
VolatilityPeriod Период ATR. 16
CandleType Используемый тип свечей (по умолчанию 5 минут). TimeSpan.FromMinutes(5)

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

  • Свечи подписываются через высокоуровневый API StockSharp, RSI и ATR подключаются через Bind.
  • Индикаторы обрабатываются прямо в ProcessCandle без вызовов GetValue() и без дополнительных буферов.
  • Используются только завершённые свечи.
  • Перевод пунктов в цену выполняется через Security.PriceStep, поэтому необходимо корректно настроить шаг цены инструмента.
  • В оригинальном советнике каждое направление велось отдельными ордерами. В StockSharp применяется неттинговый учёт, поэтому при HedgeTrading = true выполняется последовательное закрытие и открытие позиции в обратную сторону.

Рекомендации по использованию

  • Настройте RangeStartHour, RangeEndHour и торговое окно в соответствии с тайм-зоной вашего поставщика данных, чтобы диапазон соответствовал европейскому утру.
  • При оптимизации уделяйте внимание буферу пробоя, ступеням тейк-профита и фильтру волатильности — именно они определяют баланс между ложными пробоями и упущенными движениями.
  • Чтобы сделать трейлинг более агрессивным, уменьшите TrailingRiskMultiplier или StopLossPoints, тогда стоп будет пододвигаться чаще.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Early Bird RangeBreak: EMA trend following with ATR stops.
/// </summary>
public class EarlyBirdRangeBreakStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevClose;
	private decimal _entryPrice;

	public EarlyBirdRangeBreakStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_emaLength = Param(nameof(EmaLength), 20)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevClose = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = 0; _entryPrice = 0;
		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (_prevClose == 0 || atrVal <= 0) { _prevClose = close; return; }

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || close < emaVal) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || close > emaVal) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (close > emaVal && _prevClose <= emaVal) { _entryPrice = close; BuyMarket(); }
			else if (close < emaVal && _prevClose >= emaVal) { _entryPrice = close; SellMarket(); }
		}
		_prevClose = close;
	}
}