Открыть на GitHub

Стратегия MultiBreakout V001k

Обзор

MultiBreakout V001k полностью повторяет советник MT4 «Multibreakout_v001k». После завершения выбранного часа стратегия анализирует свечу H1 и выставляет серии отложенных ордеров на пробой диапазона. Алгоритм управления позицией включает ступенчатые тейк-профиты, перенос стопа в безубыток и опциональный «движущийся» безубыток с привязкой к новым экстремумам.

Правила торговли

  1. Референсный час – можно задать до четырех торговых сессий. Когда выбранный час завершается, стратегия рассчитывает его диапазон и готовит ордера для следующего часа.
  2. Размещение ордеров
    • Бай-стопы ставятся на максимум прошедшего часа + текущий спред + буфер входа (PipsForEntry).
    • Селл-стопы ставятся на минимум прошедшего часа − буфер входа.
    • В каждом направлении выставляется NumberOfOrdersPerSide ордеров одинакового объема.
  3. Лесенка тейк-профитов – каждый ордер имеет свою цель, разделенную на TakeProfitIncrement пунктов. Когда цена достигает уровня, стратегия закрывает одну долю позиции по рынку, повторяя очередь тейк-профитов оригинала.
  4. Стоп-лосс – стартовый стоп находится на расстоянии StopLoss пунктов. При достижении прибыли BreakEven стоп переносится в точку входа. Если активирован MovingBreakEven и выдержана задержка (MovingBreakEvenHoursToStart), стоп начинает подтягиваться по последним минимумам/максимумам завершенных часовых свечей.
  5. Выход из сессии – при наступлении ExitMinute внутри заданного часа стратегия закрывает все позиции и снимает оставшиеся ордера.

Параметры

Параметр Описание
TradeVolume Объем каждого отложенного ордера.
NumberOfOrdersPerSide Количество ордеров, выставляемых в каждом направлении.
TakeProfitIncrement Шаг между соседними тейк-профитами в пунктах.
PipsForEntry Дополнительный буфер для входа выше/ниже диапазона.
StopLoss Исходная дистанция стоп-лосса.
BreakEven Прибыль в пунктах, необходимая для переноса стопа в безубыток.
MovingBreakEven Включение алгоритма движущегося безубытка.
MovingBreakEvenHoursToStart Сколько часов ждать после сессии перед включением движущегося безубытка.
BrokerOffsetToGmt Смещение серверного времени относительно GMT для расписания движущегося безубытка.
TradeSession1..4 Флаги активации четырех торговых сессий.
SessionHour1..4 Час (0-23), определяющий каждую сессию.
ExitMinute Минута внутри часа, когда нужно закрыть позиции и убрать ордера.
CandleType Тип свечей для измерения референсного часа (по умолчанию H1).

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

  • Убедитесь, что инструмент имеет корректный PriceStep, чтобы расчеты пунктов совпадали с MT4.
  • Предполагается, что серверное время совпадает со временем свечей; при ином смещении настройте BrokerOffsetToGmt.
  • Движущийся безубыток анализирует две последние завершенные часовые свечи и подтягивает стоп только при обновлении локальных минимумов/максимумов в пользу позиции.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Multi-breakout strategy - Highest/Lowest channel breakout.
/// Buys when price breaks above the channel high, sells when below channel low.
/// Reverses position on opposite breakout.
/// </summary>
public class MultiBreakoutV001kStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

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

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

	public MultiBreakoutV001kStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 20)
			.SetDisplay("Channel Period", "Lookback for breakout channel", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

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

	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 high, decimal low)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var close = candle.ClosePrice;
		var mid = (high + low) / 2m;

		if (!_hasPrev)
		{
			_prevClose = close;
			_prevHigh = mid;
			_prevLow = mid;
			_hasPrev = true;
			return;
		}

		// Cross above midpoint - go long
		if (_prevClose <= _prevHigh && close > mid && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Cross below midpoint - go short
		else if (_prevClose >= _prevLow && close < mid && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevHigh = mid;
		_prevLow = mid;
	}
}