The Suffic369 strategy is a trend-following breakout system that combines two short moving averages with wide Bollinger Bands. The expert advisor enters long positions when the fast simple moving average (SMA) of closing prices crosses above the SMA of recent highs while the market trades near the lower Bollinger Band. Short positions are opened when the fast SMA crosses below the SMA of recent lows while the price is pressing against the upper band. The converted StockSharp version keeps the original MQL logic but expresses it with high-level candle subscriptions and indicator bindings.
Indicators
Fast SMA (Close, length = 3) – measures short-term direction of the closing price.
High SMA (High, length = 5) – averages recent highs and acts as a bullish resistance reference.
Low SMA (Low, length = 5) – averages recent lows and provides the bearish support reference.
All indicators are updated on completed candles. Previous values are cached to reproduce the one-bar shift used in the original MetaTrader program.
Trading Rules
Long Entry
Previous fast SMA (close) is below the previous high SMA.
Current fast SMA (close) crosses above the current high SMA.
Candle closing price is below the lower Bollinger Band.
Short Entry
Previous fast SMA (close) is above the previous low SMA.
Current fast SMA (close) crosses below the current low SMA.
Candle closing price is above the upper Bollinger Band.
Exit Logic
Opposite Signal: A long position is closed when a fresh short entry signal appears, and vice versa.
Stop-Loss: Optional price-step based stop that protects the position once activated.
Take-Profit: Optional price-step based target mirroring the original TakeProfit parameter.
Trailing Stop: Optional trailing stop that tightens behind profitable trades exactly like the MQL logic (uses current close to move the stop only when profit exceeds the configured distance).
The strategy holds at most one position at a time. After a stop, target, or opposite signal closes the trade, no new entry is evaluated until the next finished candle.
Parameters
Name
Default
Description
FastMaLength
3
Length of the fast SMA built on close prices.
HighMaLength
5
Length of the SMA calculated on candle highs.
LowMaLength
5
Length of the SMA calculated on candle lows.
BollingerLength
156
Window size of the Bollinger Bands.
BollingerDeviation
1
Standard deviation multiplier for the bands.
UseStopLoss
true
Enables the stop-loss block.
StopLossPoints
30
Stop distance in instrument price steps.
UseTakeProfit
true
Enables the take-profit block.
TakeProfitPoints
60
Profit target distance in price steps.
UseTrailingStop
true
Enables trailing stop management.
TrailingStopPoints
30
Trailing offset in price steps.
CandleType
15-minute time frame
Candle type used for calculations.
All numeric parameters are exposed as StrategyParam<T> instances so they can be optimised directly inside StockSharp.
Risk Management
Stop-loss, take-profit, and trailing stops use the instrument price step (Security.PriceStep) to convert point distances into absolute prices.
Trailing stops follow profitable moves only when the price has advanced more than the configured distance, replicating the original order-modification logic.
StartProtection() is invoked on start to enable StockSharp’s built-in protective features.
Usage Notes
Subscribe the strategy to an instrument that supports the selected candle type.
Ensure the Volume property is set to the desired trade size before starting the strategy.
The strategy waits for fully formed indicator values before issuing any orders; initial candles are used to seed indicator history.
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>
/// Suffic369 breakout strategy based on fast/slow SMA crossover.
/// Buy when fast SMA crosses above slow SMA, sell when fast crosses below slow.
/// </summary>
public class Suffic369Strategy : Strategy
{
private readonly StrategyParam<int> _fastMaLength;
private readonly StrategyParam<int> _slowMaLength;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
/// <summary>
/// Fast SMA length.
/// </summary>
public int FastMaLength
{
get => _fastMaLength.Value;
set => _fastMaLength.Value = value;
}
/// <summary>
/// Slow SMA length.
/// </summary>
public int SlowMaLength
{
get => _slowMaLength.Value;
set => _slowMaLength.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="Suffic369Strategy"/> class.
/// </summary>
public Suffic369Strategy()
{
_fastMaLength = Param(nameof(FastMaLength), 3)
.SetDisplay("Fast SMA Length", "Fast moving average period", "Indicators");
_slowMaLength = Param(nameof(SlowMaLength), 6)
.SetDisplay("Slow SMA Length", "Slow moving average period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Primary candle source", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fastSma = new SimpleMovingAverage { Length = FastMaLength };
var slowSma = new SimpleMovingAverage { Length = SlowMaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastSma, slowSma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
// Buy signal: fast SMA crosses above slow SMA
var longSignal = _prevFast <= _prevSlow && fast > slow;
// Sell signal: fast SMA crosses below slow SMA
var shortSignal = _prevFast >= _prevSlow && fast < slow;
if (Position > 0 && shortSignal)
{
SellMarket();
}
else if (Position < 0 && longSignal)
{
BuyMarket();
}
else if (Position == 0)
{
if (longSignal)
BuyMarket();
else if (shortSignal)
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class suffic369_strategy(Strategy):
"""Fast/slow SMA crossover (3/6)."""
def __init__(self):
super(suffic369_strategy, self).__init__()
self._fast_ma_length = self.Param("FastMaLength", 3).SetDisplay("Fast SMA Length", "Fast moving average period", "Indicators")
self._slow_ma_length = self.Param("SlowMaLength", 6).SetDisplay("Slow SMA Length", "Slow moving average period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Primary candle source", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(suffic369_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
def OnStarted2(self, time):
super(suffic369_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._has_prev = False
fast_sma = SimpleMovingAverage()
fast_sma.Length = self._fast_ma_length.Value
slow_sma = SimpleMovingAverage()
slow_sma.Length = self._slow_ma_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast_sma, slow_sma, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast_sma)
self.DrawIndicator(area, slow_sma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
if not self._has_prev:
self._prev_fast = fast
self._prev_slow = slow
self._has_prev = True
return
long_signal = self._prev_fast <= self._prev_slow and fast > slow
short_signal = self._prev_fast >= self._prev_slow and fast < slow
if self.Position > 0 and short_signal:
self.SellMarket()
elif self.Position < 0 and long_signal:
self.BuyMarket()
elif self.Position == 0:
if long_signal:
self.BuyMarket()
elif short_signal:
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return suffic369_strategy()