The strategy replicates the behaviour of the original MQL/34176/MACross.mq4 expert advisor using the StockSharp high-level API. It trades a single instrument on a moving-average crossover and keeps all risk controls expressed in pips and account equity.
Trading logic
Two simple moving averages (SMA) are built on the configured candle type:
FastPeriod reacts quickly to price changes.
SlowPeriod smooths the longer-term trend.
At the close of each finished candle the fast and slow averages are compared:
A bullish crossover (fast crossing above slow) opens a long position. Any active short is flattened first.
A bearish crossover (fast crossing below slow) opens a short position after closing an existing long.
Every entry uses a fixed market volume derived from LotSize and aligned with the instrument limits (VolumeStep, MinVolume, MaxVolume).
After the position is opened the strategy tracks two risk targets measured in pips. The pip size is automatically inferred from Security.Decimals (or PriceStep as a fallback):
TakeProfitPips defines the distance to the profit target. Hitting it issues a market exit in the current direction.
StopLossPips defines the protective stop distance. Breaching it closes the position immediately.
Trading can be paused by the MinEquity guard. When the current portfolio value is below the threshold the strategy keeps managing the active position but does not allow new entries.
All calculations work on finished candles only, fully matching the original expert advisor that waited for a new bar before evaluating the moving averages.
Visualisation
When a chart pane is available the strategy plots:
Input candles from the subscribed series.
The fast and slow SMAs.
Own trades to highlight entries and exits triggered by the crossover rules.
Parameters
Name
Type
Default
Description
FastPeriod
int
8
Length of the fast SMA that generates crossover signals.
SlowPeriod
int
20
Length of the slow SMA used as the reference trend line.
TakeProfitPips
decimal
20
Profit target distance expressed in pips. The pip size is inferred from the instrument decimals.
StopLossPips
decimal
20
Protective stop distance in pips. Uses the same pip size calculation as the profit target.
LotSize
decimal
1
Base order volume. The strategy rounds it to the nearest allowed size before sending market orders.
MinEquity
decimal
100
Minimum account equity. New trades are blocked while the portfolio value is below this level.
CandleType
DataType
TimeSpan.FromMinutes(1).TimeFrame()
Candle series used for SMA calculations and signal evaluation.
Differences vs. MQL version
The original MQL expert passed stop-loss and take-profit prices to OrderSend as zero. The StockSharp port emulates the same behaviour with manual exits that monitor the close price of each finished candle.
Equity validation (cekMinEquity) now reads Portfolio.CurrentValue and Portfolio.BeginValue instead of AccountEquity() but preserves the threshold logic.
Pip size detection mirrors the GetPipPoint helper: 2- or 3-digit quotes use 0.01, 4- or 5-digit quotes use 0.0001, otherwise PriceStep is taken.
The resulting strategy can be optimised through all exposed parameters and combines seamlessly with StockSharp charting and risk management infrastructure.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MA Cross strategy: SMA crossover.
/// Buys when fast SMA crosses above slow SMA, sells on cross below.
/// </summary>
public class MacrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public MacrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_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 fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
SellMarket();
}
else
{
if (fastValue > slowValue && Position <= 0)
BuyMarket();
else if (fastValue < slowValue && Position >= 0)
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
_hasPrev = true;
}
}
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 ma_cross_strategy(Strategy):
"""
MA Cross strategy: EMA crossover.
Buys when fast crosses above slow, sells on cross below.
"""
def __init__(self):
super(ma_cross_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._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60))).SetDisplay("Candle Type", "Timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_cross_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ma_cross_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
f = float(fast_val)
s = float(slow_val)
if self._has_prev:
if self._prev_fast <= self._prev_slow and f > s and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and self.Position >= 0:
self.SellMarket()
else:
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = f
self._prev_slow = s
self._has_prev = True
return
if f > s and self.Position <= 0:
self.BuyMarket()
elif f < s and self.Position >= 0:
self.SellMarket()
self._prev_fast = f
self._prev_slow = s
self._has_prev = True
def CreateClone(self):
return ma_cross_strategy()