Открыть на GitHub

Стратегия Plan X

Стратегия Plan X воспроизводит советник MetaTrader «plan x» Питера Ингрэма. Она ориентирована на европейскую сессию и наблюдает за 15-минутными свечами. После фиксирования контрольной свечи стратегия ожидает пробоя на заданное количество пунктов и открывает одну чистую позицию. Управление риском выполняется через стоп-лоссы и трейлинг-стопы, выраженные в пунктах.

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

  1. Опорная свеча

    • Анализируются 15-минутные свечи.
    • В момент начала торгового окна (по умолчанию 11:00) сохраняется цена закрытия свечи. Она служит опорной ценой до конца окна.
    • Сигналы рассматриваются только после закрытия следующей свечи и до окончания окна (по умолчанию 15:00).
  2. Условия входа

    • Покупка: последняя завершённая свеча закрылась выше опорной цены более чем на LongTargetPips (по умолчанию 25 пунктов), позиция отсутствует.
    • Продажа: последняя завершённая свеча закрылась ниже опорной цены более чем на ShortTargetPips (по умолчанию 20 пунктов), позиция отсутствует.
    • Сравнения выполняются в пунктах, рассчитываемых из шага цены инструмента.
  3. Сопровождение позиций

    • Сразу после входа устанавливается фиксированный стоп-лосс на расстоянии InitialStopPips (по умолчанию 25 пунктов).
    • Когда прибыль достигает TrailTriggerPips (по умолчанию 10 пунктов), стоп превращается в трейлинг.
    • Каждый раз, когда цена проходит ещё TrailTriggerPips, стоп сдвигается на TrailStepPips (по умолчанию 5 пунктов) в прибыльную сторону.
    • При срабатывании стопа позиция закрывается рыночной заявкой.
  4. Объём

    • Входы и выходы используют параметр TradeVolume (по умолчанию 0.1 лота). Подберите значение под контракт инструмента.

Параметры

Имя Описание Значение по умолчанию
TradeVolume Объём рыночных заявок. 0.1
LongTargetPips Минимальный пробой вверх от опорной цены. 25
ShortTargetPips Минимальный пробой вниз от опорной цены. 20
InitialStopPips Расстояние стоп-лосса от цены входа. 25
TrailTriggerPips Прибыль, после которой активируется/обновляется трейлинг. 10
TrailStepPips Шаг сдвига трейлинг-стопа. 5
SessionStartHour Час начала окна (десятичный формат, например 11.5 = 11:30). 11.0
SessionEndHour Час завершения окна. Должен быть больше SessionStartHour. 15.0
CandleType Тип свечей для расчётов (по умолчанию 15 минут). 15 минут

Примечания

  • Размер пункта определяется автоматически по PriceStep и количеству десятичных знаков инструмента (для 3 и 5 знаков множитель 10).
  • Опорная цена пересчитывается каждый торговый день; на инструментах с гэпами учитывайте возможные разрывы.
  • В реализации StockSharp используется чистая позиция, поэтому стратегия открывает только одно направление одновременно, что соответствует оригинальному советнику без хеджирования.

Файлы

  • CS/PlanXBreakoutStrategy.cs – реализация логики Plan X на C# для StockSharp.
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>
/// Plan X Breakout strategy using highest high / lowest low channel breakout.
/// Buy when price breaks above the highest high of the lookback period.
/// Sell when price breaks below the lowest low of the lookback period.
/// </summary>
public class PlanXBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _lookback;
	private readonly StrategyParam<DataType> _candleType;

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

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

	public PlanXBreakoutStrategy()
	{
		_lookback = Param(nameof(Lookback), 20)
			.SetDisplay("Lookback", "Channel lookback period", "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();

		_prevHigh = 0m;
		_prevLow = 0m;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasPrev = false;

		var highestHigh = new Highest { Length = Lookback };
		var lowestLow = new Lowest { Length = Lookback };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(highestHigh, lowestLow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevHigh = highest;
			_prevLow = lowest;
			_hasPrev = true;
			return;
		}

		// Breakout above previous highest high
		if (Position <= 0 && candle.ClosePrice > _prevHigh)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Breakout below previous lowest low
		else if (Position >= 0 && candle.ClosePrice < _prevLow)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevHigh = highest;
		_prevLow = lowest;
	}
}