The N Candles strategy replicates the MQL expert advisor that enters a trade when a configurable number of consecutive candles share the same direction. Once the most recent N finished candles are all bullish, the strategy sends a market buy order. When all are bearish, it sends a market sell order. No exit logic is included; the position must be managed externally or by additional strategies.
Overview
Market Regime: Works best in markets that exhibit short momentum bursts.
Instruments: Any instrument supporting continuous trading (FX, futures, crypto).
Timeframes: Configurable; default is 1-hour candles.
Order Types: Market orders without protective stops or targets.
How It Works
On every finished candle the strategy evaluates the last N candles.
If every candle in that window is bullish, it issues a buy market order with the configured volume.
If every candle is bearish, it issues a sell market order.
Doji candles (equal open and close) reset the count and suppress trading until a new streak forms.
The strategy does not manage open positions; repeated signals add to the existing direction on netting accounts.
Parameters
Consecutive Candles: Number of identical candles required before placing an order.
Volume: Market order size sent on each signal.
Candle Type: Candle series used for streak detection (timeframe or custom candle type).
Usage Notes
Because the strategy lacks stops or exits, combine it with manual management, protective strategies, or portfolio risk controls.
On highly volatile markets consider lowering the candle count or timeframe to capture faster streaks.
Excessive consecutive streaks can accumulate large positions; monitor leverage and account limits.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trades in the direction of consecutive candles of the same color.
/// </summary>
public class NCandlesStrategy : Strategy
{
private readonly StrategyParam<int> _consecutiveCandles;
private readonly StrategyParam<DataType> _candleType;
private int _currentDirection;
private int _streakLength;
/// <summary>
/// Number of identical candles that must appear in a row to trigger an order.
/// </summary>
public int ConsecutiveCandles
{
get => _consecutiveCandles.Value;
set => _consecutiveCandles.Value = value;
}
/// <summary>
/// The type of candles used for analysis.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public NCandlesStrategy()
{
_consecutiveCandles = Param(nameof(ConsecutiveCandles), 4)
.SetGreaterThanZero()
.SetDisplay("Consecutive Candles", "Number of identical candles required", "General")
.SetOptimize(2, 6, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles to analyze", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_currentDirection = 0;
_streakLength = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var direction = 0;
if (candle.ClosePrice > candle.OpenPrice)
{
direction = 1;
}
else if (candle.ClosePrice < candle.OpenPrice)
{
direction = -1;
}
else
{
// Doji candle breaks the streak just like in the original expert.
_currentDirection = 0;
_streakLength = 0;
return;
}
if (direction == _currentDirection)
{
_streakLength = Math.Min(_streakLength + 1, ConsecutiveCandles);
}
else
{
_currentDirection = direction;
_streakLength = 1;
}
if (_streakLength < ConsecutiveCandles)
return;
if (direction > 0 && Position <= 0)
{
BuyMarket();
}
else if (direction < 0 && Position >= 0)
{
SellMarket();
}
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class n_candles_strategy(Strategy):
def __init__(self):
super(n_candles_strategy, self).__init__()
self._consecutive_candles = self.Param("ConsecutiveCandles", 4)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._current_direction = 0
self._streak_length = 0
@property
def ConsecutiveCandles(self):
return self._consecutive_candles.Value
@ConsecutiveCandles.setter
def ConsecutiveCandles(self, value):
self._consecutive_candles.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(n_candles_strategy, self).OnStarted2(time)
self._current_direction = 0
self._streak_length = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
direction = 0
if close > open_price:
direction = 1
elif close < open_price:
direction = -1
else:
self._current_direction = 0
self._streak_length = 0
return
consecutive = int(self.ConsecutiveCandles)
if direction == self._current_direction:
self._streak_length = min(self._streak_length + 1, consecutive)
else:
self._current_direction = direction
self._streak_length = 1
if self._streak_length < consecutive:
return
if direction > 0 and self.Position <= 0:
self.BuyMarket()
elif direction < 0 and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(n_candles_strategy, self).OnReseted()
self._current_direction = 0
self._streak_length = 0
def CreateClone(self):
return n_candles_strategy()