The ADX MACD Deev Strategy is a StockSharp port of the MetaTrader expert advisor with the same name. It combines the trend strength signal from the Average Directional Index (ADX) with momentum confirmation from the Moving Average Convergence Divergence (MACD). The strategy trades only when both indicators agree on the market direction and can optionally secure profits through trailing stops and partial position exits.
How it Works
Indicator preparation
ADX is calculated with a configurable averaging period. The strategy tracks the latest ADX values and requires them to move consistently in one direction before allowing a trade.
MACD uses configurable fast, slow and signal exponential moving averages. The histogram and signal line must jointly show sustained growth for longs or sustained decline for shorts.
Entry logic
Long entries: triggered when the MACD histogram exceeds the MACD Minimum (pips) threshold, both MACD histogram and signal line increase for the selected number of bars, and ADX stays above the required strength while also rising.
Short entries: triggered when the MACD histogram is below the negative threshold, both MACD histogram and signal line decline over the selected interval, and ADX remains above the minimum while decreasing.
Only one position can be open at a time.
Risk management
Initial stop-loss and take-profit levels are placed in price units derived from the instrument PriceStep and the chosen pip distances.
A trailing stop can follow profitable positions once price advances by Trailing Stop + Trailing Step pips.
When Take Half Profit is enabled the strategy closes half of the current position at the take-profit level and lets the rest run with the trailing stop.
Parameters
Group
Name
Description
Trading
Order Volume
Volume of each new market order.
Risk
Stop Loss (pips)
Initial stop-loss offset from entry.
Risk
Take Profit (pips)
Initial take-profit offset from entry.
Risk
Trailing Stop (pips)
Trailing stop distance. Set to zero to disable trailing.
Risk
Trailing Step (pips)
Extra price move before the trailing stop moves again.
Risk
Take Half Profit
Enables partial exit when the take-profit level is hit.
Indicators
ADX Period
ADX averaging period.
Indicators
ADX Bars Interval
Number of recent ADX bars that must trend in one direction.
Indicators
ADX Minimum
Minimum ADX value required for entries.
Indicators
MACD Fast EMA
Fast EMA length used by MACD.
Indicators
MACD Slow EMA
Slow EMA length used by MACD.
Indicators
MACD Signal EMA
Signal EMA length used by MACD.
Indicators
MACD Bars Interval
Number of MACD bars that must align in the same direction.
Indicators
MACD Minimum (pips)
Minimum MACD magnitude converted to pips.
General
Candle Type
Candle type or time-frame used for calculations.
Usage Notes
The strategy requires instruments with a valid PriceStep. If PriceStep is zero the pip-based thresholds fall back to raw MACD values.
Volume rounding for partial exits follows the VolumeStep of the instrument.
Trailing stop adjustments are evaluated on closed candles only.
The strategy uses high-level API bindings (SubscribeCandles().BindEx(...)) and does not rely on manual indicator value polling.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class AdxMacdDeevStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public AdxMacdDeevStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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_macd_deev_strategy(Strategy):
"""
ADX MACD Deev: dual EMA crossover with stop-loss/take-profit in price steps.
"""
def __init__(self):
super(adx_macd_deev_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12) \
.SetGreaterThanZero() \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetGreaterThanZero() \
.SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@StopLossPoints.setter
def StopLossPoints(self, value):
self._stop_loss_points.Value = value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@TakeProfitPoints.setter
def TakeProfitPoints(self, value):
self._take_profit_points.Value = value
def OnReseted(self):
super(adx_macd_deev_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(adx_macd_deev_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(tf(5))
subscription.Bind(fast, slow, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_value
self._prev_slow = slow_value
return
close = float(candle.ClosePrice)
step = 1.0
if self.Position > 0 and self._entry_price > 0:
if self.StopLossPoints > 0 and close <= self._entry_price - self.StopLossPoints * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
if self.TakeProfitPoints > 0 and close >= self._entry_price + self.TakeProfitPoints * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
elif self.Position < 0 and self._entry_price > 0:
if self.StopLossPoints > 0 and close >= self._entry_price + self.StopLossPoints * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
if self.TakeProfitPoints > 0 and close <= self._entry_price - self.TakeProfitPoints * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
return
if self._prev_fast <= self._prev_slow and fast_value > slow_value and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_value < slow_value and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_value
self._prev_slow = slow_value
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return adx_macd_deev_strategy()