The Plan X breakout strategy replicates the MetaTrader expert advisor "plan x" by Peter Ingram. It focuses on the London late-morning session and waits for price to break away from a reference candle before entering. Only one net position can be open at a time, and risk is controlled through pip-based stops that trail behind the trade as it moves in favor.
Trading Logic
Session Anchor
The strategy watches 15-minute candles.
At the configured session start hour (default 11:00), it records the close of that candle. This close acts as the anchor price for the rest of the session.
Trading is only considered after at least one additional candle has closed and before the session end hour (default 15:00).
Entry Conditions
Long: When the latest finished candle closes more than LongTargetPips (default 25 pips) above the anchor close and no position is open.
Short: When the latest finished candle closes more than ShortTargetPips (default 20 pips) below the anchor close and no position is open.
All comparisons are done in pip units derived from the instrument tick size.
Position Management
A fixed initial stop-loss equal to InitialStopPips (default 25 pips) is set relative to the entry price.
The stop converts into a trailing stop once the trade gains at least TrailTriggerPips (default 10 pips).
Each time price advances by another TrailTriggerPips, the stop is moved by TrailStepPips (default 5 pips) further in the profitable direction.
If price hits the stop, the position is closed at market.
Volume
Orders use the TradeVolume parameter (default 0.1 lots). Adjust to match the security contract size.
Parameters
Name
Description
Default
TradeVolume
Market order volume used for entries and exits.
0.1
LongTargetPips
Breakout distance above the anchor required for long entries.
25
ShortTargetPips
Breakout distance below the anchor required for short entries.
20
InitialStopPips
Distance from entry price to the protective stop-loss.
25
TrailTriggerPips
Profit in pips needed before the trailing stop activates or advances.
10
TrailStepPips
Pip increment applied to the trailing stop each time it moves.
5
SessionStartHour
Decimal hour indicating when the anchor candle begins (e.g., 11.0, 11.5).
11.0
SessionEndHour
Decimal hour after which no new entries are taken. Must be later than SessionStartHour.
15.0
CandleType
Candle series used for evaluations. Defaults to 15-minute candles.
15-minute
Notes
The pip size adapts automatically based on the instrument's PriceStep and decimal precision (3 or 5 decimals receive a 10x multiplier).
The strategy expects a continuous intraday market; on instruments with daily gaps, re-anchor behavior occurs each trading day.
Because StockSharp strategies use net positions, the conversion assumes only one open direction at a time. This mirrors the original expert's default behavior when no hedging is active.
Files
CS/PlanXBreakoutStrategy.cs – C# implementation of the Plan X breakout logic for 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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class plan_x_breakout_strategy(Strategy):
"""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."""
def __init__(self):
super(plan_x_breakout_strategy, self).__init__()
self._lookback = self.Param("Lookback", 20) \
.SetDisplay("Lookback", "Channel lookback period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def Lookback(self):
return self._lookback.Value
def OnReseted(self):
super(plan_x_breakout_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(plan_x_breakout_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.Lookback
lowest = Lowest()
lowest.Length = self.Lookback
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._process_candle).Start()
def _process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
high_val = float(highest)
low_val = float(lowest)
close = float(candle.ClosePrice)
if not self._has_prev:
self._prev_high = high_val
self._prev_low = low_val
self._has_prev = True
return
# Breakout above previous highest high
if self.Position <= 0 and close > self._prev_high:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Breakout below previous lowest low
elif self.Position >= 0 and close < self._prev_low:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = high_val
self._prev_low = low_val
def CreateClone(self):
return plan_x_breakout_strategy()