The 4 SMA strategy replicates the MetaTrader expert advisor 4 SMA.mq4. It works on 30-minute candles calculated with median prices and compares four simple moving averages (5, 20, 40, and 60 periods) to detect momentum breakouts. The StockSharp port keeps the single-position behaviour of the original code and uses high-level API helpers for market entries and risk management.
Trading Logic
Calculate the median price (high + low) / 2 for each finished candle and feed it into the four SMAs.
Long entry happens when the fast SMA is above the medium SMA, the medium SMA is above the slow SMA, the slow SMA is above the very slow SMA by at least one price step, and the previous slow SMA was below or equal to the very slow SMA. Only one long position can be active at a time.
Short entry is the mirror condition: the fast SMA is below the medium SMA, the medium SMA is below the slow SMA, the very slow SMA is above the slow SMA by at least one price step, and the previous slow SMA was above or equal to the very slow SMA. Only one short position can be active at a time.
Position Management
The strategy closes longs when the slow SMA crosses below the very slow SMA and closes shorts when the slow SMA crosses above the very slow SMA.
Protective levels are pre-computed after each entry. Stop-loss and take-profit distances follow the original point-based settings and rely on the security price step.
Trailing stops activate after price moves beyond the configured trailing distance. The stop is trailed candle by candle and never loosened.
Parameters
Name
Description
Default
CandleType
Candle series used for calculations (30-minute by default).
M30 time frame
TakeProfit
Take-profit distance in points.
50
StopLoss
Stop-loss distance in points.
50
TrailingStop
Trailing stop distance in points.
11
FastLength
Length of the fast SMA.
5
MediumLength
Length of the medium SMA.
20
SlowLength
Length of the slow SMA.
40
VerySlowLength
Length of the very slow SMA.
60
All numeric parameters are exposed for optimisation via the StockSharp parameter UI.
Differences from the MQL Version
The original trailing stop manipulated MT4 orders directly; the port recalculates exit prices and issues market orders when levels are breached.
Price-step aware calculations let the strategy operate on instruments with non-forex tick sizes.
The StockSharp implementation relies on high-level SubscribeCandles bindings and strategy parameters, staying close to framework best practices.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class FourSmaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldownRemaining;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FourSmaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, 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; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevFast = fast;
_prevSlow = slow;
}
}