View on GitHub

ADX MACD Deev Strategy

Overview

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

  1. 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.
  2. 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.
  3. 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;
	}
}