Converted from the MetaTrader 4 expert advisor MQL/7637/3_lccfpgubwykd__www_forex-instruments_info.mq4.
Uses a three-timeframe workflow: hourly candles drive both MACD filters, 15-minute candles supply Stochastic oscillators, and 1-minute candles confirm price breakouts and manage trailing exits.
Implements a high-level StockSharp strategy using SubscribeCandles(...).Bind(...) / BindEx(...) without manual data polling.
Positions are opened with market orders and managed entirely inside the strategy (no external test harness changes were required).
Indicators and Parameters
Name
Type
Default
Description
LongStopLoss
decimal
17
Initial stop distance for long trades, expressed in instrument points.
ShortStopLoss
decimal
40
Initial stop distance for short trades (points).
LongTrailingStop
decimal
88
Trailing distance for long positions.
ShortTrailingStop
decimal
76
Trailing distance for short positions.
OrderVolume
decimal
0.1
Base trade volume (lots) mirrored from the MQL input.
MacdCandleType
DataType
H1
Timeframe for the bullish and bearish MACD filters (22/27/9 and 19/77/9).
StochasticCandleType
DataType
M15
Timeframe used for both Stochastic oscillators (5/3/11 and 9/3/19).
EntryCandleType
DataType
M1
Timeframe that provides breakout confirmation and trailing logic.
All point-based settings are converted to absolute prices through the instrument PriceStep, faithfully reproducing the MetaTrader Point multiplier.
Trading Rules
Long Entry
Hourly MACD(22,27,9) main line crosses above its previous value while remaining below zero.
M15 Stochastic(%K=5,%D=3,slowing=11) is below 26 and rising versus its previous value.
The current M1 close pierces the prior M1 high.
When all conditions align and no position is open, the strategy buys OrderVolume plus any quantity required to flip an existing short.
Short Entry
Hourly MACD(19,77,9) main line falls below its previous value, with the previous value above zero.
M15 Stochastic(%K=9,%D=3,slowing=19) is above 70.
The current M1 close breaks below the prior M1 low.
A short is opened with the same position-flip logic as the original EA.
Exit and Trailing
Initial stops mirror the MQL StopLoss distances in points.
Trailing stops activate once price moves more than the specified trailing distance in favor of the position and are recalculated on each finished M1 candle.
If price touches the active stop level (initial or trailed), the position is closed with a market order.
Implementation Notes
Candle subscriptions are split by timeframe so indicator updates remain independent, exactly matching the EA's multi-timeframe behavior.
The MQL Bid/Ask trailing comparisons are approximated with finished M1 candle highs/lows, which is the closest representation within the candle-based high-level API.
The code follows repository guidelines: tab indentation, namespace StockSharp.Samples.Strategies, English comments, and parameter declarations inside the constructor via Param(...).
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>
/// MACD + Stochastic trailing strategy.
/// Enters long when MACD histogram is positive and Stochastic K crosses above D from oversold.
/// Enters short when MACD histogram is negative and Stochastic K crosses below D from overbought.
/// </summary>
public class MacdStochasticTrailingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevK;
private decimal? _prevD;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MacdStochasticTrailingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
_prevK = null;
_prevD = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevK = null;
_prevD = null;
var macd = new MovingAverageConvergenceDivergenceSignal();
var stoch = new StochasticOscillator();
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, stoch, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFinal || !stochValue.IsFinal)
return;
var macdVal = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
var stochVal = (StochasticOscillatorValue)stochValue;
if (macdVal.Macd is not decimal macd || macdVal.Signal is not decimal signal)
return;
if (stochVal.K is not decimal k || stochVal.D is not decimal d)
return;
if (_prevK is not decimal prevK || _prevD is not decimal prevD)
{
_prevK = k;
_prevD = d;
return;
}
var histogram = macd - signal;
var kCrossUp = prevK <= prevD && k > d;
var kCrossDown = prevK >= prevD && k < d;
// Buy: MACD histogram positive + stochastic K crosses above D
if (histogram > 0 && kCrossUp && k < 50 && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Sell: MACD histogram negative + stochastic K crosses below D
else if (histogram < 0 && kCrossDown && k > 50 && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevK = k;
_prevD = d;
}
}
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 MovingAverageConvergenceDivergenceSignal, StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
class macd_stochastic_trailing_strategy(Strategy):
"""MACD + Stochastic trailing strategy.
Enters long when MACD histogram positive and Stochastic K crosses above D from oversold.
Enters short when MACD histogram negative and Stochastic K crosses below D from overbought."""
def __init__(self):
super(macd_stochastic_trailing_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_k = None
self._prev_d = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(macd_stochastic_trailing_strategy, self).OnReseted()
self._prev_k = None
self._prev_d = None
def OnStarted2(self, time):
super(macd_stochastic_trailing_strategy, self).OnStarted2(time)
self._prev_k = None
self._prev_d = None
macd = MovingAverageConvergenceDivergenceSignal()
stoch = StochasticOscillator()
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, stoch, self._process_candle).Start()
def _process_candle(self, candle, macd_value, stoch_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not stoch_value.IsFinal:
return
macd_raw = macd_value.Macd if hasattr(macd_value, 'Macd') else None
signal_raw = macd_value.Signal if hasattr(macd_value, 'Signal') else None
if macd_raw is None or signal_raw is None:
return
macd_main = float(macd_raw)
signal_line = float(signal_raw)
k_raw = stoch_value.K if hasattr(stoch_value, 'K') else None
d_raw = stoch_value.D if hasattr(stoch_value, 'D') else None
if k_raw is None or d_raw is None:
return
k = float(k_raw)
d = float(d_raw)
if self._prev_k is None or self._prev_d is None:
self._prev_k = k
self._prev_d = d
return
prev_k = self._prev_k
prev_d = self._prev_d
histogram = macd_main - signal_line
k_cross_up = prev_k <= prev_d and k > d
k_cross_down = prev_k >= prev_d and k < d
# Buy: MACD histogram positive + stochastic K crosses above D from oversold
if histogram > 0 and k_cross_up and k < 50 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Sell: MACD histogram negative + stochastic K crosses below D from overbought
elif histogram < 0 and k_cross_down and k > 50 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_k = k
self._prev_d = d
def CreateClone(self):
return macd_stochastic_trailing_strategy()