Recreates the breakout and reversal logic from the original Noah10pips2006 MetaTrader 4 expert advisor.
Builds previous-session price channels and places stop orders around the mid-point.
Applies secure-profit trailing, optional dynamic position sizing, and an optional reversal trade after the first position closes.
Trading Logic
Session Range Calculation
At the start of every new trading day (after applying the configured time-zone offset) the strategy records the previous session high and low. These levels are used to compute:
The mid-point between high and low.
A "pass" buffer positioned 20 pips above/below the range.
An entry channel obtained by subtracting/adding 40 pips (or 25% of the range if the range is larger than 160 pips).
Initial Pending Order
When the market enters the trading window, the strategy checks the latest close:
If the close is between the mid-point and the upper buffer, a sell stop is placed at the mid-point.
If the close is between the lower buffer and the mid-point, a buy stop is placed at the mid-point.
The range width must exceed the configured minimum before any orders are placed.
Second Pending Order
If only one stop order remains active, the system adds the opposite-direction order at the corresponding buffer (upper buffer for a buy stop, lower buffer for a sell stop). This mirrors the original EA behaviour and prepares the strategy for breakouts on both sides of the range.
Position Management
Protective stop-loss and take-profit orders are created after an entry fills.
Once floating profit reaches the secure trigger threshold, the stop-loss is moved to lock in the configured secure profit.
When the secure lock is active, an optional trailing stop keeps following price with the specified distance.
Daily Shutdown
All pending orders and open positions are closed when the trading window ends or when the Friday cut-off is reached.
Reversal Trade
The first completed position can trigger an opposite-direction market order, reproducing the "reverse after stop" behaviour from the original code. The reversal is skipped if the secure-profit adjustment already locked in gains.
Parameters
Parameter
Description
CandleType
Candle series used to drive calculations and timing. Default: 1-hour candles.
TimeZoneOffset
Shift (in hours) applied to exchange timestamps before daily calculations.
StartHour, StartMinute
Opening time of the trading window in the shifted time-zone.
EndHour, EndMinute
Closing time of the trading window. New entries are not placed afterwards.
FridayEndHour
Hour on Friday when positions are force-closed.
TradeFriday
Enables or disables opening new positions on Friday.
StopLossPips, TakeProfitPips
Distance (in pips) of protective orders created after entry.
TrailingStopPips
Trailing-stop distance used after the secure-profit step. Set to 0 to disable trailing.
SecureProfitPips
Profit locked when the secure trigger activates.
TrailSecureProfitPips
Profit threshold required before moving the stop to the secure level.
MinimumRangePips
Minimum width of the entry channel required to place orders.
StartYear, StartMonth
Ignore market data that is older than this date.
MinVolume, MaxVolume
Bounds applied to the computed order volume.
MaximumRiskPercent
Percentage of portfolio value risked per trade when dynamic sizing is enabled.
FixedVolume
When true, the strategy uses the Volume property instead of the risk model.
Practical Notes
The instrument must provide valid PriceStep and StepPrice values when the risk-based position sizing mode is used.
Trailing and secure-profit adjustments rely on completed candles, so intrabar fills are processed on the next finished candle.
The strategy cancels and replaces protective orders whenever the trailing logic updates the stop price.
Ensure the time-zone offset matches the source of historical data; otherwise, the previous-day range can differ from the original MT4 expert.
Conversion Caveats
Visual drawing objects from the MT4 version were omitted; use the supplied levels or add custom chart annotations if needed.
The algorithm assumes four-digit Forex quoting when converting the fixed 20/40 pip buffers; adjust parameters for different asset classes.
Reverse trades execute at market with the current volume model, matching the behaviour of the original EA after deleting opposite pending orders.
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>
/// Noah 10 Pips 2006 - session breakout strategy.
/// Tracks the previous session's high/low range.
/// Buys on breakout above the midpoint, sells on breakout below.
/// Uses Highest/Lowest indicators as channel reference.
/// </summary>
public class Noah10Pips2006Strategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevHigh;
private decimal _prevLow;
private decimal _prevMid;
private decimal _prevClose;
private bool _hasPrev;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Noah10Pips2006Strategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 24)
.SetDisplay("Channel Period", "Lookback for high/low 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();
_prevHigh = 0m;
_prevLow = 0m;
_prevMid = 0m;
_prevClose = 0m;
_hasPrev = false;
}
/// <inheritdoc />
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)
{
_prevHigh = high;
_prevLow = low;
_prevMid = mid;
_prevClose = close;
_hasPrev = true;
return;
}
// Breakout above channel high - buy
if (_prevClose <= _prevHigh && close > high && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Breakout below channel low - sell
else if (_prevClose >= _prevLow && close < low && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Cross above midpoint from below - buy signal
else if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Cross below midpoint from above - sell signal
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevHigh = high;
_prevLow = low;
_prevMid = mid;
_prevClose = close;
}
}
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 noah10_pips2006_strategy(Strategy):
"""Session breakout strategy. Tracks channel high/low/midpoint.
Buys on breakout above channel high or cross above midpoint.
Sells on breakout below channel low or cross below midpoint."""
def __init__(self):
super(noah10_pips2006_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 24) \
.SetDisplay("Channel Period", "Lookback for high/low channel", "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._prev_mid = 0.0
self._prev_close = 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 ChannelPeriod(self):
return self._channel_period.Value
def OnReseted(self):
super(noah10_pips2006_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_mid = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(noah10_pips2006_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.ChannelPeriod
lowest = Lowest()
lowest.Length = self.ChannelPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._process_candle).Start()
def _process_candle(self, candle, high, low):
if candle.State != CandleStates.Finished:
return
high_val = float(high)
low_val = float(low)
close = float(candle.ClosePrice)
mid = (high_val + low_val) / 2.0
if not self._has_prev:
self._prev_high = high_val
self._prev_low = low_val
self._prev_mid = mid
self._prev_close = close
self._has_prev = True
return
# Breakout above channel high - buy
if self._prev_close <= self._prev_high and close > high_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Breakout below channel low - sell
elif self._prev_close >= self._prev_low and close < low_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Cross above midpoint from below - buy
elif self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Cross below midpoint from above - sell
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = high_val
self._prev_low = low_val
self._prev_mid = mid
self._prev_close = close
def CreateClone(self):
return noah10_pips2006_strategy()