Ver en GitHub

MACD Stochastic Trailing Strategy

Overview

  • 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

  1. Hourly MACD(22,27,9) main line crosses above its previous value while remaining below zero.
  2. M15 Stochastic(%K=5,%D=3,slowing=11) is below 26 and rising versus its previous value.
  3. The current M1 close pierces the prior M1 high.
  4. When all conditions align and no position is open, the strategy buys OrderVolume plus any quantity required to flip an existing short.

Short Entry

  1. Hourly MACD(19,77,9) main line falls below its previous value, with the previous value above zero.
  2. M15 Stochastic(%K=9,%D=3,slowing=19) is above 70.
  3. The current M1 close breaks below the prior M1 low.
  4. 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;
	}
}