The Simple MACD EA strategy is a direct port of the classic MetaTrader expert advisor "Simple MACD EA". The approach uses two exponential moving averages (EMAs) to emulate the MACD histogram and determine the dominant trend on one-minute candles. Long positions are opened when the fast EMA (period 100) crosses above the slow EMA (user-defined MACD level). Short positions are opened when the fast EMA drops below the slow EMA. Only one position is maintained at any time.
Trade Management Logic
Trend detection: The difference between the 100-period EMA and the configurable MACD EMA defines the current trend direction (+1, 0, -1). A reversal from negative to positive opens a long position. A reversal from positive to negative opens a short position.
Momentum confirmation: The strategy keeps track of the difference between the MACD EMA and a slightly slower EMA (MACD level + 1). If the difference shrinks against the current trade after the price has moved at least five points in profit, the position is closed early.
Time-based protection: After a trade stays open for a user-defined number of evaluation cycles, the system activates a soft stop that reduces tolerance for adverse price movement relative to the entry price.
Trailing exit: Once the trade moves into profit and stays active for enough cycles, an internal trailing stop is engaged. The stop level follows the price by the configured number of points and can be updated a limited number of times. If the limit is reached the position is closed.
Trend reversal exit: When the trend signal flips in the opposite direction while price is already five points in profit, the position is closed immediately.
Parameters
Candle Type – Time frame used for the EMA calculations (default: 1-minute candles).
Volume – Order volume for new entries.
MACD Level – EMA length that defines the slow MACD component. A secondary EMA with length MACD Level + 1 is derived automatically.
Trailing Stop – Distance in points for the trailing exit. Set to zero to disable.
Trailing Updates – Maximum number of trailing stop adjustments per trade.
Wait Cycles – Number of candle evaluations to wait before the adaptive soft stop becomes active.
Additional Notes
The strategy always flattens the current position before reversing direction.
Price step information from the selected security is used to translate point-based distances into actual prices.
The implementation relies on StockSharp's high-level candle subscription API and does not enqueue custom indicator buffers.
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>
/// Simple MACD EA strategy using fast/slow EMA difference for trend detection.
/// Buy when EMA difference crosses above zero, sell when it crosses below zero.
/// </summary>
public class SimpleMacdEaStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevDiff;
private bool _hasPrev;
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public SimpleMacdEaStrategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 12)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 26)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevDiff = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
var diff = fast - slow;
if (!_hasPrev)
{
_prevDiff = diff;
_hasPrev = true;
return;
}
// Buy: MACD crosses above zero
var longSignal = _prevDiff <= 0 && diff > 0;
// Sell: MACD crosses below zero
var shortSignal = _prevDiff >= 0 && diff < 0;
if (Position <= 0 && longSignal)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (Position >= 0 && shortSignal)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevDiff = diff;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class simple_macd_ea_strategy(Strategy):
"""Simple MACD EA using fast/slow EMA difference for trend detection.
Buy when EMA difference crosses above zero, sell when it crosses below zero."""
def __init__(self):
super(simple_macd_ea_strategy, self).__init__()
self._fast_ema_period = self.Param("FastEmaPeriod", 12) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_ema_period = self.Param("SlowEmaPeriod", 26) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_diff = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastEmaPeriod(self):
return self._fast_ema_period.Value
@property
def SlowEmaPeriod(self):
return self._slow_ema_period.Value
def OnReseted(self):
super(simple_macd_ea_strategy, self).OnReseted()
self._prev_diff = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(simple_macd_ea_strategy, self).OnStarted2(time)
self._has_prev = False
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastEmaPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowEmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._process_candle).Start()
def _process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
diff = float(fast) - float(slow)
if not self._has_prev:
self._prev_diff = diff
self._has_prev = True
return
# Buy: MACD crosses above zero
long_signal = self._prev_diff <= 0 and diff > 0
# Sell: MACD crosses below zero
short_signal = self._prev_diff >= 0 and diff < 0
if self.Position <= 0 and long_signal:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self.Position >= 0 and short_signal:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_diff = diff
def CreateClone(self):
return simple_macd_ea_strategy()