Открыть на GitHub

Стратегия FT TIME BIGDOG (пробой диапазона)

Обзор

FT TIME BIGDOG — это пробойная стратегия сессии Лондона, перенесённая из советника MetaTrader 4 FT_TIME_BIGDOG.mq4 (каталог MQL/9259). Стратегия измеряет ценовой коридор между заданными часами начала и окончания, а затем выставляет отложенные стоп-заявки выше и ниже диапазона после закрытия окна. Порт на StockSharp сохраняет исходную логику и добавляет параметры для настройки времени, фильтра диапазона и управления рисками.

Логика торговли

  1. Для каждого торгового дня фиксируются максимумы и минимумы закрытых свечей, открывающихся между StartHour и StopHour (включительно).
  2. После закрытия свечи на часе StopHour, если ширина диапазона меньше RangeLimitPoints, становятся доступны две отложенные заявки:
    • Buy Stop на уровне зафиксированного максимума.
    • Sell Stop на уровне зафиксированного минимума.
  3. Заявка выставляется только если текущая цена удалена от уровня входа минимум на OrderBufferPoints. Используются лучшие bid/ask из потока Level1, при их отсутствии берётся цена закрытия свечи.
  4. Каждая заявка получает стоп-лосс на противоположной границе диапазона и тейк-профит, рассчитанный по TakeProfitPoints.
  5. После входа в позицию противоположная заявка отменяется. Открытая позиция отслеживается по закрытиям свечей: при достижении стоп-лосса или тейк-профита позиция закрывается рыночной заявкой.
  6. Цикл выполняется не более одного раза в день; в начале нового дня состояние сбрасывается.

Параметры

Параметр Значение по умолчанию Описание
StartHour 14 Час (0–23), с которого начинается накопительный диапазон.
StopHour 16 Час, после которого допускается выставление стоп-заявок. Должен быть ≥ StartHour.
RangeLimitPoints 50 Максимальная ширина диапазона в пунктах брокера (пункт × PointMultiplier). Если диапазон шире — сделок нет.
TakeProfitPoints 50 Размер тейк-профита в пунктах брокера.
OrderBufferPoints 20 Минимальное расстояние от текущей цены до отложенной заявки. Предотвращает вход слишком близко к рынку.
PointMultiplier 1 Множитель для учёта пятизначных котировок (установите 10 для 5-значных форекс-инструментов).
Volume 0.1 Объём ордеров для обеих стоп-заявок.
CandleType 1 час Тип свечей, по которым рассчитывается диапазон.

Управление рисками и сделками

  • Стоп-лосс для длинных позиций = нижняя граница диапазона, для коротких — верхняя граница.
  • Тейк-профит рассчитывается от уровня входа с использованием TakeProfitPoints и шага цены инструмента.
  • Все проверки выполняются на закрытии свечи, поэтому внутрисвечные проколы могут привести к задержке выхода.

Отличия от оригинального советника

  • В MT4 советник работает по тиковым данным, в StockSharp используется закрытие свечей и поток Level1. Возможно небольшое расхождение внутри свечи.
  • Перевод пунктов использует Security.PriceStep, умноженный на PointMultiplier; перед реальной торговлей убедитесь, что шаг цены указан верно.
  • Поддерживаются только окна, где StartHour <= StopHour. Пересечение полуночного рубежа в данной версии не реализовано.

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

  1. Выберите инструмент и убедитесь, что поставщик данных отдаёт поток Level1 для корректной проверки буфера.
  2. Настройте часы под серверное время брокера.
  3. Перед запуском на реале протестируйте стратегию в симуляции, чтобы проверить пересчёт пунктов и тайминг.
  4. Перед ручной модификацией отложенных заявок остановите стратегию, чтобы избежать рассинхронизации состояния.

Файлы

  • CS/FtTimeBigdogStrategy.cs — порт стратегии на StockSharp с подробными комментариями.
  • MQL/9259/FT_TIME_BIGDOG.mq4 — исходный код советника MetaTrader.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// FT Time Bigdog: Range breakout using N-bar high/low channel with ATR stops.
/// </summary>
public class FtTimeBigdogStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _channelLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _entryPrice;
	private decimal _highest;
	private decimal _lowest;
	private int _barCount;
	private readonly decimal[] _highs = new decimal[20];
	private readonly decimal[] _lows = new decimal[20];

	public FtTimeBigdogStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_channelLength = Param(nameof(ChannelLength), 20)
			.SetDisplay("Channel Length", "Lookback for high/low channel.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

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

	public int ChannelLength
	{
		get => _channelLength.Value;
		set => _channelLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

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

		_entryPrice = 0;
		_barCount = 0;
		_highest = 0;
		_lowest = 0;
		Array.Clear(_highs, 0, _highs.Length);
		Array.Clear(_lows, 0, _lows.Length);
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_entryPrice = 0;
		_barCount = 0;
		_highest = 0;
		_lowest = 0;
		Array.Clear(_highs, 0, _highs.Length);
		Array.Clear(_lows, 0, _lows.Length);

		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

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

		var len = Math.Min(ChannelLength, _highs.Length);
		var idx = _barCount % len;
		_highs[idx] = candle.HighPrice;
		_lows[idx] = candle.LowPrice;
		_barCount++;

		if (_barCount < len || atrVal <= 0)
			return;

		var high = decimal.MinValue;
		var low = decimal.MaxValue;
		for (var i = 0; i < len; i++)
		{
			if (_highs[i] > high) high = _highs[i];
			if (_lows[i] < low) low = _lows[i];
		}

		var prevHigh = _highest;
		var prevLow = _lowest;
		_highest = high;
		_lowest = low;

		if (prevHigh == 0 || prevLow == 0)
			return;

		var close = candle.ClosePrice;

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

		if (Position == 0)
		{
			if (close > prevHigh)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (close < prevLow)
			{
				_entryPrice = close;
				SellMarket();
			}
		}
	}
}