This strategy reproduces the "Previous Candle Breakdown" MetaTrader expert advisor. It waits for the price to break above or below the previous reference candle with a configurable indent measured in price steps. The implementation relies on high-level StockSharp APIs with candle subscriptions for level calculations and tick subscriptions for execution decisions.
Trading Logic
At the close of every reference candle (default 4 hours) the strategy stores the previous candle high and low and offsets them by IndentSteps * Security.PriceStep to build breakout levels.
Tick prices (last trades) are monitored. A long entry is triggered when price reaches the upper level and a short entry when price falls through the lower level.
An optional moving-average filter requires the fast MA (with optional forward shift) to stay above the slow MA for long trades and below it for short trades. Setting either MA period to zero disables the filter.
Trades are allowed only inside the configured session window between StartTime and EndTime. Crossing-midnight sessions are supported.
Floating profit is monitored continuously: stops, targets and trailing rules close existing positions before a breakout signal can trigger reversals.
Risk Management
StopLossSteps / TakeProfitSteps — distances in price steps from the entry price. Steps are converted via distance = steps * Security.PriceStep.
TrailingStopSteps / TrailingStepSteps — enables a trailing exit once the position moves in favor by at least the trailing distance. The stop is moved further only when profit advances by the trailing step.
ProfitClose — closes all positions once the unrealized profit (Position * (last price - PositionPrice)) exceeds the threshold. Set to 0 to disable.
MaxNetPosition — caps the absolute net position so the strategy cannot pyramid beyond that amount. Position size itself is controlled by the strategy Volume property.
Parameters
Parameter
Description
CandleType
Reference timeframe used to calculate breakout levels.
IndentSteps
Offset above/below the previous candle high/low expressed in price steps.
FastMaPeriod / FastMaShift
Fast moving average length and optional forward shift (bars).
SlowMaPeriod / SlowMaShift
Slow moving average length and optional forward shift (bars).
StopLossSteps
Stop loss distance in price steps.
TakeProfitSteps
Take profit distance in price steps.
TrailingStopSteps
Trailing stop distance (0 disables trailing).
TrailingStepSteps
Minimal gain required before the trailing stop is advanced. Must be > 0 when trailing is used.
ProfitClose
Floating profit target that closes all positions.
MaxNetPosition
Maximum absolute net position allowed.
StartTime / EndTime
Trading window boundaries.
Usage Notes
Set the Volume property of the strategy instance to control order size. Risk-based position sizing from the MetaTrader version is intentionally not ported.
The moving averages use simple moving averages (SMA). If other smoothing modes are required, extend the strategy accordingly.
The profit close threshold uses unrealized profit in instrument price units (quantity × price difference). Adjust the threshold so it matches your instrument.
The strategy operates in a netting environment; reversing trades send market orders in the opposite direction, automatically closing the current exposure first.
Trailing stop requires a positive TrailingStepSteps value; otherwise the strategy throws an exception during start-up.
Differences from the Original MQL Version
Money management based on fixed lots or risk percentage is not implemented; StockSharp users should manage size via the Volume property or external portfolio managers.
Only simple moving averages are supported; the original allowed different MA types.
Profit-close logic uses floating PnL computed from average position price instead of account currency, because brokerage-specific swap/commission data are not directly available.
Logging is handled by StockSharp; detailed trade result messages from MetaTrader are omitted.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class PreviousCandleBreakdownLevelsStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevHigh, _prevLow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public PreviousCandleBreakdownLevelsStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = null;
_prevLow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = null; _prevLow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevHigh = candle.HighPrice; _prevLow = candle.LowPrice; return; }
if (_prevHigh == null) { _prevHigh = candle.HighPrice; _prevLow = candle.LowPrice; return; }
var close = candle.ClosePrice;
if (fast > slow && close > _prevHigh.Value && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (fast < slow && close < _prevLow.Value && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevHigh = candle.HighPrice; _prevLow = candle.LowPrice;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class previous_candle_breakdown_levels_strategy(Strategy):
def __init__(self):
super(previous_candle_breakdown_levels_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 8) \
.SetDisplay("Fast EMA", "Fast period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow EMA", "Slow period", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(previous_candle_breakdown_levels_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(previous_candle_breakdown_levels_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
return
if self._prev_high is None:
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
return
close = float(candle.ClosePrice)
if fv > sv and close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif fv < sv and close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
def CreateClone(self):
return previous_candle_breakdown_levels_strategy()