This strategy recreates the MetaTrader 5 expert advisor "Divergence EA pip sl tp" in the StockSharp framework. The algorithm searches for classical divergences between price action and the MACD histogram, then validates the signal with an overbought/oversold Stochastic oscillator filter before opening reversal trades.
Trading logic
Subscribe to the primary timeframe candles selected by the CandleType parameter.
Calculate the MACD histogram (MACD line - Signal line) and the Stochastic %K/%D values on every finished candle.
Track the latest two swing highs and lows of both price and histogram values.
Bearish divergence: a new higher price high accompanied by a lower MACD histogram peak and Stochastic %K above StochasticUpperLevel triggers a short position or reverses an existing long.
Bullish divergence: a new lower price low with a higher MACD histogram trough and %K below StochasticLowerLevel opens or reverses into a long position.
Optional protective TakeProfitSteps and StopLossSteps are converted to StockSharp step units and activated once when the strategy starts.
Implementation notes
Built with StockSharp high-level API using a single candle subscription bound to MovingAverageConvergenceDivergenceSignal and StochasticOscillator indicators.
Maintains divergence state without calling indicator GetValue helpers, complying with the conversion guidelines.
Chart integration displays price candles, MACD, and Stochastic lines when a chart area is available.
Positions are reversed by adding the absolute current position size to the base Volume, ensuring immediate direction changes after confirmed divergences.
Parameters
Parameter
Description
Default
CandleType
Timeframe used for divergence calculations.
1-hour candles
MacdFastLength, MacdSlowLength, MacdSignalLength
MACD EMA lengths replicating the original EA inputs.
12 / 26 / 9
MacdDivergenceThreshold
Minimum histogram difference between consecutive swings required to confirm divergence.
0.0005
StochasticLength
Fast %K period of the Stochastic oscillator.
50
StochasticSlowK, StochasticSlowD
Additional %K/%D smoothing lengths mirroring the EA configuration.
9 / 9
StochasticUpperLevel, StochasticLowerLevel
Overbought and oversold filters validating bearish/bullish setups.
80 / 20
TakeProfitSteps, StopLossSteps
Optional protection distances expressed in price steps (0 disables the level).
50
Usage
Attach the strategy to a StockSharp connector with a security supporting the selected timeframe.
Configure position size through the base Volume property and adjust indicator settings as desired.
Start the strategy—orders will be generated automatically whenever the divergence and Stochastic conditions are satisfied.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Divergence MACD Stochastic" MetaTrader expert.
/// Uses MACD histogram divergence (price vs histogram) with RSI confirmation.
/// MACD is computed manually from two EMAs.
/// </summary>
public class DivergenceMacdStochasticStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _rsiPeriod;
// Manual EMA for MACD
private decimal _fastEma;
private decimal _slowEma;
private bool _emaInitialized;
private int _barCount;
private decimal _fastMultiplier;
private decimal _slowMultiplier;
private readonly decimal[] _macdWindow = new decimal[DivergenceLookback];
private readonly decimal[] _priceWindow = new decimal[DivergenceLookback];
private int _windowCount;
private int _windowIndex;
private const int DivergenceLookback = 10;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MacdFast
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
public int MacdSlow
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public DivergenceMacdStochasticStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for divergence detection", "General");
_macdFast = Param(nameof(MacdFast), 20)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "Fast EMA length", "Indicators");
_macdSlow = Param(nameof(MacdSlow), 50)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "Slow EMA length", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_windowCount = 0;
_windowIndex = 0;
_emaInitialized = false;
_barCount = 0;
_fastMultiplier = 2m / (MacdFast + 1);
_slowMultiplier = 2m / (MacdSlow + 1);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
_barCount++;
// Manual EMA computation
if (!_emaInitialized)
{
_fastEma = close;
_slowEma = close;
_emaInitialized = true;
}
else
{
_fastEma = close * _fastMultiplier + _fastEma * (1 - _fastMultiplier);
_slowEma = close * _slowMultiplier + _slowEma * (1 - _slowMultiplier);
}
if (_barCount < MacdSlow)
return;
var macdLine = _fastEma - _slowEma;
_macdWindow[_windowIndex] = macdLine;
_priceWindow[_windowIndex] = close;
_windowIndex = (_windowIndex + 1) % DivergenceLookback;
if (_windowCount < DivergenceLookback)
_windowCount++;
if (_windowCount < DivergenceLookback)
return;
var volume = Volume;
if (volume <= 0)
volume = 1;
var oldestIndex = _windowIndex;
var newestIndex = (_windowIndex + DivergenceLookback - 1) % DivergenceLookback;
var oldMacd = _macdWindow[oldestIndex];
var newMacd = _macdWindow[newestIndex];
var oldPrice = _priceWindow[oldestIndex];
var newPrice = _priceWindow[newestIndex];
var minPriceMove = oldPrice * 0.005m;
// Bullish divergence: price makes lower low but MACD makes higher low.
var bullishDiv = newPrice < oldPrice - minPriceMove && newMacd > oldMacd;
// Bearish divergence: price makes higher high but MACD makes lower high.
var bearishDiv = newPrice > oldPrice + minPriceMove && newMacd < oldMacd;
if (bullishDiv)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (bearishDiv)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastEma = 0;
_slowEma = 0;
_emaInitialized = false;
_barCount = 0;
_fastMultiplier = 0;
_slowMultiplier = 0;
Array.Clear(_macdWindow, 0, _macdWindow.Length);
Array.Clear(_priceWindow, 0, _priceWindow.Length);
_windowCount = 0;
_windowIndex = 0;
}
}
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.Strategies import Strategy
class divergence_macd_stochastic_strategy(Strategy):
DIVERGENCE_LOOKBACK = 10
def __init__(self):
super(divergence_macd_stochastic_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._macd_fast = self.Param("MacdFast", 20)
self._macd_slow = self.Param("MacdSlow", 50)
self._fast_ema = 0.0
self._slow_ema = 0.0
self._ema_initialized = False
self._bar_count = 0
self._fast_multiplier = 0.0
self._slow_multiplier = 0.0
self._macd_window = []
self._price_window = []
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MacdFast(self):
return self._macd_fast.Value
@MacdFast.setter
def MacdFast(self, value):
self._macd_fast.Value = value
@property
def MacdSlow(self):
return self._macd_slow.Value
@MacdSlow.setter
def MacdSlow(self, value):
self._macd_slow.Value = value
def OnReseted(self):
super(divergence_macd_stochastic_strategy, self).OnReseted()
self._fast_ema = 0.0
self._slow_ema = 0.0
self._ema_initialized = False
self._bar_count = 0
self._macd_window = []
self._price_window = []
def OnStarted2(self, time):
super(divergence_macd_stochastic_strategy, self).OnStarted2(time)
self._fast_ema = 0.0
self._slow_ema = 0.0
self._ema_initialized = False
self._bar_count = 0
self._fast_multiplier = 2.0 / (self.MacdFast + 1)
self._slow_multiplier = 2.0 / (self.MacdSlow + 1)
self._macd_window = []
self._price_window = []
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
self._bar_count += 1
if not self._ema_initialized:
self._fast_ema = close
self._slow_ema = close
self._ema_initialized = True
else:
self._fast_ema = close * self._fast_multiplier + self._fast_ema * (1 - self._fast_multiplier)
self._slow_ema = close * self._slow_multiplier + self._slow_ema * (1 - self._slow_multiplier)
if self._bar_count < self.MacdSlow:
return
macd_line = self._fast_ema - self._slow_ema
self._macd_window.append(macd_line)
self._price_window.append(close)
while len(self._macd_window) > self.DIVERGENCE_LOOKBACK:
self._macd_window.pop(0)
self._price_window.pop(0)
if len(self._macd_window) < self.DIVERGENCE_LOOKBACK:
return
old_macd = self._macd_window[0]
new_macd = self._macd_window[-1]
old_price = self._price_window[0]
new_price = self._price_window[-1]
min_price_move = old_price * 0.005
# Bullish divergence: price makes lower low but MACD makes higher low
bullish_div = new_price < old_price - min_price_move and new_macd > old_macd
# Bearish divergence: price makes higher high but MACD makes lower high
bearish_div = new_price > old_price + min_price_move and new_macd < old_macd
if bullish_div:
if self.Position <= 0:
self.BuyMarket()
elif bearish_div:
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return divergence_macd_stochastic_strategy()