This strategy trades breakouts that occur when the most recent completed bar closes far away from an older reference bar. It was inspired by the "Nextbar" MetaTrader expert advisor and keeps the original money-management features such as pip-based stops, trailing logic, and limited position lifetime.
The default configuration aims at fast-moving FX or index futures charts on the 15-minute timeframe, but the logic works on any symbol that provides regular candles. Every order is sent at market using the configured position size.
Trading logic
Signal detection
When a new bar finishes, the algorithm compares the close of the previous bar with the close that occurred SignalBar bars ago.
If the previous close is higher than the distant close by more than MinDistancePips, a long setup is generated.
If the previous close is lower than the distant close by more than MinDistancePips, a short setup appears.
The ReverseSignals switch flips the direction of every setup to match contrarian workflows.
Order handling
Orders are ignored while a position is open. The strategy only holds a single position at a time just like the original expert advisor.
Every fill stores the entry price and pre-computes the stop-loss and take-profit levels in price units. Pip-based values are converted using the security price step (5-digit instruments automatically use a 10× multiplier to match MetaTrader pip size).
Exit rules
Stop loss / take profit – Both levels are optional. A value of zero disables the corresponding protection. The strategy monitors candle highs and lows to trigger exits when levels are crossed.
Trailing stop – When enabled (TrailingStopPips > 0), the stop is moved closer to the current price once profit exceeds TrailingStopPips + TrailingStepPips. The distance from price to stop never shrinks, ensuring a monotonic trailing behaviour.
Position lifetime – After staying in the market for LifetimeBars completed candles, the position is closed on the next bar open regardless of profit. This reproduces the original "expire after N bars" mechanism.
Parameters
CandleType – Timeframe used for signal evaluation. Defaults to 15-minute time-frame candles.
OrderVolume – Quantity sent with each market order.
StopLossPips – Distance from the entry price to the protective stop, expressed in pips.
TakeProfitPips – Distance from the entry price to the profit target, expressed in pips.
TrailingStopPips – Distance maintained by the trailing stop. Set to zero to disable trailing logic.
TrailingStepPips – Additional profit required before the trailing stop is advanced again. Ignored when trailing is disabled.
SignalBar – Number of bars between the comparison closes. Must be at least two to avoid referencing the current bar.
MinDistancePips – Minimum pip distance between the compared closes before a signal is accepted.
LifetimeBars – Maximum number of completed candles that a position may remain open. Set to zero to disable the timer.
ReverseSignals – Inverts long/short signals when enabled.
Implementation notes
The strategy relies on a short rolling list of previous closes rather than heavy historical structures, which keeps the signal calculation lightweight.
Pips are converted into price units using the security price step. Instruments quoted with 3 or 5 decimal places automatically map to the traditional pip definition.
All risk controls are enforced on completed candles. If you need intra-bar protection, combine the strategy with exchange-native stop orders through the platform configuration.
No automated tests are supplied with this sample. Validate it on historical data before using it in production.
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>
/// Next Bar Momentum strategy. Compares close with a reference bar for momentum breakout.
/// </summary>
public class NextBarMomentumStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumPeriod;
private decimal? _prevMom;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MomentumPeriod
{
get => _momentumPeriod.Value;
set => _momentumPeriod.Value = value;
}
public NextBarMomentumStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_momentumPeriod = Param(nameof(MomentumPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Momentum Period", "Rate of change lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMom = null;
var momentum = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(momentum, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
var momArea = CreateChartArea();
if (momArea != null)
DrawIndicator(momArea, momentum);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal momVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevMom = momVal;
return;
}
if (_prevMom == null)
{
_prevMom = momVal;
return;
}
// Momentum crosses above zero → buy
if (_prevMom.Value <= 100m && momVal > 100m && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Momentum crosses below zero → sell
else if (_prevMom.Value >= 100m && momVal < 100m && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMom = momVal;
}
}
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 Momentum
from StockSharp.Algo.Strategies import Strategy
class next_bar_momentum_strategy(Strategy):
def __init__(self):
super(next_bar_momentum_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._momentum_period = self.Param("MomentumPeriod", 10) \
.SetDisplay("Momentum Period", "Rate of change lookback", "Indicators")
self._prev_mom = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MomentumPeriod(self):
return self._momentum_period.Value
def OnReseted(self):
super(next_bar_momentum_strategy, self).OnReseted()
self._prev_mom = None
def OnStarted2(self, time):
super(next_bar_momentum_strategy, self).OnStarted2(time)
self._prev_mom = None
momentum = Momentum()
momentum.Length = self.MomentumPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(momentum, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
ind_area = self.CreateChartArea()
if ind_area is not None:
self.DrawIndicator(ind_area, momentum)
def _on_process(self, candle, mom_value):
if candle.State != CandleStates.Finished:
return
mv = float(mom_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_mom = mv
return
if self._prev_mom is None:
self._prev_mom = mv
return
# Momentum crosses above 100
if self._prev_mom <= 100.0 and mv > 100.0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Momentum crosses below 100
elif self._prev_mom >= 100.0 and mv < 100.0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_mom = mv
def CreateClone(self):
return next_bar_momentum_strategy()