The MultiTimeframeEmaAlignmentStrategy is a StockSharp port of the MetaTrader 4 expert advisor 1h-4h-1d.mq4 from the folder MQL/7713. The original robot aligns fast and slow exponential moving averages across three timeframes and applies protective money management via fixed stop loss, take profit and trailing stop levels. This C# version follows the same high-level idea while leveraging StockSharp's indicator bindings and high-level order helpers.
Trading Logic
The strategy subscribes to three candle series simultaneously: M1 (signal timeframe), M5 (mid-term filter) and M30 (higher timeframe trend confirmation).
Each series feeds a pair of exponential moving averages (EMA) with configurable lengths (default 8 and 64).
A bullish setup requires the fast EMA to stay above the slow EMA on all three timeframes. Additionally, the fast EMA must not lose momentum (current value greater than or equal to the previous value and also above the value ShiftDepth bars ago).
A bearish setup requires the fast EMA to stay below the slow EMA on all three timeframes with the fast EMA decreasing in momentum.
Orders are triggered on the close of the M1 candle when the alignment and momentum checks are satisfied. Long signals are allowed only when no long position is open (or an existing short is closed first) and vice versa.
This interpretation recreates the intent of the MT4 conditions with StockSharp's high-level API. The MQL "MA shift" comparisons are emulated through the ShiftDepth buffer that tracks EMA values a few candles back and ensures momentum is consistent with the entry direction.
Risk Management
Position size is controlled by the TradeVolume parameter (default 3 lots like the original EA).
Optional stop loss and take profit distances are provided in pips. They are converted to prices through the instrument's PriceStep (falls back to 0.0001 when missing).
The trailing stop replicates the EA's behaviour by moving the stop price closer to the market whenever the trade advances enough.
Risk parameters can be toggled independently, matching the StopLossMode, TakeProfitMode and TrailingStopMode flags from the MQL script.
Parameters
Parameter
Description
Default
TradeVolume
Order volume used by BuyMarket / SellMarket. Mirrors the Lots input.
3
FastLength
EMA period for the fast line.
8
SlowLength
EMA period for the slow line.
64
ShiftDepth
Number of historical candles used to emulate the MQL moving average shift comparisons.
3
UseStopLoss
Enables fixed stop loss.
true
StopLossPips
Stop loss distance expressed in pips.
75
UseTakeProfit
Enables take profit.
true
TakeProfitPips
Take profit distance expressed in pips.
150
UseTrailingStop
Enables trailing stop management.
true
TrailingStopPips
Trailing distance in pips.
30
M1CandleType
Candle type for the signal timeframe (default 1 minute).
1m
M5CandleType
Candle type for the mid-term filter (default 5 minutes).
5m
M30CandleType
Candle type for the higher timeframe (default 30 minutes).
30m
Usage Notes
Attach the strategy to an instrument and ensure historical data is available for all three timeframes to allow the EMA buffers to populate.
The ShiftDepth parameter should remain at least 2 so the strategy can validate short-term momentum.
When UseTrailingStop is active without UseStopLoss, the trailing logic still initializes a stop value once the trade moves in favour.
Because StockSharp executes on candle close, results can differ slightly from the tick-by-tick execution of the MT4 version, especially on volatile markets. The core trend-alignment behaviour remains intact.
Conversion Notes
Indicator calculations rely exclusively on StockSharp's Bind mechanism; no manual indicator history collections are used.
Order management is implemented with high-level helpers (BuyMarket, SellMarket) and internal price tracking instead of direct OrderSend calls.
Mail notifications and slippage controls from the MQL script are omitted because they are outside StockSharp's scope.
Files
CS/MultiTimeframeEmaAlignmentStrategy.cs – main C# strategy implementation.
README_ru.md – Russian documentation.
README_zh.md – Chinese documentation.
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>
/// Multi-Timeframe EMA Alignment strategy - fast/slow EMA crossover with trend EMA filter.
/// Buys when fast EMA crosses above slow EMA while close is above trend EMA.
/// Sells when fast EMA crosses below slow EMA while close is below trend EMA.
/// </summary>
public class MultiTimeframeEmaAlignmentStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _trendPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int TrendPeriod { get => _trendPeriod.Value; set => _trendPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MultiTimeframeEmaAlignmentStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_trendPeriod = Param(nameof(TrendPeriod), 100)
.SetDisplay("Trend EMA", "Trend EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var trend = new ExponentialMovingAverage { Length = TrendPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, trend, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal trend)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
if (_prevFast <= _prevSlow && fast > slow && close > trend && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (_prevFast >= _prevSlow && fast < slow && close < trend && Position >= 0)
{
if (Position > 0)
SellMarket();
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class multi_timeframe_ema_alignment_strategy(Strategy):
def __init__(self):
super(multi_timeframe_ema_alignment_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._trend_period = self.Param("TrendPeriod", 100).SetDisplay("Trend EMA", "Trend EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False
@property
def fast_period(self): return self._fast_period.Value
@property
def slow_period(self): return self._slow_period.Value
@property
def trend_period(self): return self._trend_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(multi_timeframe_ema_alignment_strategy, self).OnReseted()
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(multi_timeframe_ema_alignment_strategy, self).OnStarted2(time)
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.fast_period
slow = ExponentialMovingAverage()
slow.Length = self.slow_period
trend = ExponentialMovingAverage()
trend.Length = self.trend_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, trend, self.process_candle).Start()
def process_candle(self, candle, fast, slow, trend):
if candle.State != CandleStates.Finished: return
close = float(candle.ClosePrice)
f = float(fast); s = float(slow); t = float(trend)
if not self._has_prev:
self._prev_fast = f; self._prev_slow = s; self._has_prev = True; return
if self._prev_fast <= self._prev_slow and f > s and close > t and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and close < t and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_fast = f; self._prev_slow = s
def CreateClone(self): return multi_timeframe_ema_alignment_strategy()