The 5/8 EMA Cross Protect Strategy replicates the MetaTrader expert advisor 5_8macrossv2.mq4 by comparing two configurable moving averages on the same symbol. A bullish crossover of the fast moving average above the slow one opens long positions, while a bearish crossover opens short positions. The ported version follows StockSharp high-level patterns and adds optional take-profit, stop-loss, and trailing-stop management.
Trading Logic
Two moving averages are calculated on the selected candle subscription. By default, a 5-period exponential MA on close prices is compared to an 8-period exponential MA on open prices.
When the fast MA crosses above the slow MA on the latest finished candle, the strategy opens or reverses into a long position. If a short position is active, its volume is included in the new market buy order to flip direction.
When the fast MA crosses below the slow MA, the strategy opens or reverses into a short position using the same volume-normalisation logic.
MA shift parameters emulate the original horizontal offset. Positive values delay the signal by that many closed candles; negative values are rounded to zero because forward-shifted values are unavailable in real-time data.
Risk Management
Take-profit and stop-loss distances are expressed in pips (price steps). When a long position is opened, protective levels are placed above and below the entry price respectively; the logic mirrors for shorts.
Trailing stop (also in pips) constantly tightens the protective level as price moves in favour of the position. For longs the trailing stop only moves upward; for shorts it only moves downward.
If any protective condition is met on a finished candle (high hits take-profit, low hits stop-loss or trailing level), the strategy exits the position with a market order and resets its internal state.
Parameters
Name
Type
Default
Description
TradeVolume
decimal
0.1
Order volume for new entries. The strategy adds the absolute position size when reversing.
TakeProfitPips
decimal
40
Distance from entry in pips for closing the position with profit. Set to 0 to disable.
StopLossPips
decimal
0
Distance from entry in pips for protective stop-loss. Set to 0 to disable.
TrailingStopPips
decimal
0
Trailing-stop distance in pips. Set to 0 to disable.
FastPeriod
int
5
Period of the fast moving average.
FastShift
int
-1
Horizontal shift for the fast MA. Negative values are treated as zero in this port.
FastMethod
MovingAverageMethod
Exponential
Smoothing algorithm for the fast MA (Simple, Exponential, Smoothed, LinearWeighted).
FastPrice
AppliedPrice
Close
Candle price used for the fast MA.
SlowPeriod
int
8
Period of the slow moving average.
SlowShift
int
0
Horizontal shift for the slow MA.
SlowMethod
MovingAverageMethod
Exponential
Smoothing algorithm for the slow MA.
SlowPrice
AppliedPrice
Open
Candle price used for the slow MA.
CandleType
DataType
TimeSpan.FromMinutes(30).TimeFrame()
Candle series used for calculations.
Notes
The conversion keeps the logic focused on finished candles to avoid premature signals.
Trailing stops and profit targets are computed with Security.PriceStep; if a symbol does not define it, the risk parameters remain inactive.
The Python version is intentionally omitted per task requirements.
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>
/// 5/8 MA Cross Protect strategy - EMA(5) and EMA(8) crossover.
/// Buys when EMA(5) crosses above EMA(8).
/// Sells when EMA(5) crosses below EMA(8).
/// </summary>
public class FiveEightMaCrossProtectStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
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 DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FiveEightMaCrossProtectStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 8)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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 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 (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (_prevFast >= _prevSlow && fast < slow && 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 five_eight_ma_cross_protect_strategy(Strategy):
def __init__(self):
super(five_eight_ma_cross_protect_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 5).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 8).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).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 candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(five_eight_ma_cross_protect_strategy, self).OnReseted()
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(five_eight_ma_cross_protect_strategy, self).OnStarted2(time)
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.fast_period
slow = ExponentialMovingAverage()
slow.Length = self.slow_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self.process_candle).Start()
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished: return
f = float(fast); s = float(slow)
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 self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_fast = f; self._prev_slow = s
def CreateClone(self): return five_eight_ma_cross_protect_strategy()