This strategy is a StockSharp port of the MetaTrader expert ADX_MA (fortrader).
It combines a smoothed moving average (SMMA) filter with the Average Directional Index (ADX)
so that trades are taken only when the trend is both confirmed by a crossover and strong enough
according to ADX. The port keeps the asymmetric risk management from the original robot:
long positions use wide take-profit and trailing distances, while short trades employ tighter
targets and protection.
Trading Logic
Build a smoothed moving average on median candle prices and an ADX with the configured periods.
Evaluate signals on closed candles only to mimic the MQL4 logic (iClose(...,1) / iClose(...,2)).
Enter long when the previous candle closes above the SMMA, the candle before it closes below the
same SMMA value, and the previous ADX reading is above the threshold.
Enter short when the previous candle closes below the SMMA, the candle before it closes above the
same SMMA value, and ADX is above the threshold.
Once in position, exits are driven by:
Moving-average flip in the opposite direction.
Individual stop-loss and take-profit levels measured in pips.
Optional trailing stop distances that ratchet in the trade's favor.
All price offsets are converted from pips using the security's price step. If the instrument does not
report a valid step, a value of 1 is used as a safe fallback.
Parameters
Name
Description
SMMA Period
Length of the smoothed moving average (default 21).
ADX Period
Length of the Average Directional Index (default 14).
ADX Threshold
Minimum ADX value required to allow entries (default 16).
Long Take Profit (pips)
Take-profit distance for buy positions (default 1300 pips).
Long Stop Loss (pips)
Stop-loss distance for buy positions (default 30 pips).
Long Trailing Stop (pips)
Trailing-stop distance for buy positions (default 270 pips).
Short Take Profit (pips)
Take-profit distance for sell positions (default 160 pips).
Short Stop Loss (pips)
Stop-loss distance for sell positions (default 50 pips).
Short Trailing Stop (pips)
Trailing-stop distance for sell positions (default 20 pips).
Volume
Order volume used for new entries (default 0.1).
Candle Type
Primary candle series for calculations (default 1-minute time frame).
All parameters are exposed for optimization. The defaults match the original EA settings.
Notes
Trailing stops activate only after the price moves at least the configured distance from the entry.
Opposite signals close the active position before opening a new one.
The strategy automatically draws candles, indicators, and own trades on the chart if a chart area is available.
There are no automated tests for this port; use manual backtesting to validate the behaviour on your instruments.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class AdxMaStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AdxMaStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA lookback", "Indicators");
_smaPeriod = Param(nameof(SmaPeriod), 50).SetDisplay("SMA Period", "SMA trend filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }
if (_prevClose <= _prevEma && close > ema && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevClose >= _prevEma && close < ema && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); }
_prevClose = close; _prevEma = ema;
}
}
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 CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class adx_ma_strategy(Strategy):
"""
ADX MA strategy: EMA crossover with price for trend-following entries.
"""
def __init__(self):
super(adx_ma_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 14) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._sma_period = self.Param("SmaPeriod", 50) \
.SetDisplay("SMA Period", "SMA trend filter", "Indicators")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def SmaPeriod(self):
return self._sma_period.Value
@SmaPeriod.setter
def SmaPeriod(self, value):
self._sma_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(adx_ma_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(adx_ma_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if not self._has_prev:
self._prev_close = close
self._prev_ema = ema
self._has_prev = True
return
if self._prev_close <= self._prev_ema and close > ema and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close >= self._prev_ema and close < ema and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_ema = ema
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return adx_ma_strategy()