Открыть на GitHub

Стратегия MACD + Stochastic с трейлинг-стопом

Обзор

  • Конвертирована из эксперта MetaTrader 4 MQL/7637/3_lccfpgubwykd__www_forex-instruments_info.mq4.
  • Использует три таймфрейма: часовые свечи обновляют обе линии MACD, 15-минутные свечи питают два стохастика, а минутные свечи подтверждают пробои и сопровождают трейлинг-стоп.
  • Построена на высокоуровневом API StockSharp (SubscribeCandles(...).Bind(...) / BindEx(...)) без ручного перебора данных.
  • Сделки открываются рыночными ордерами, управление позицией полностью реализовано внутри стратегии, тестовая инфраструктура не изменялась.

Индикаторы и параметры

Имя Тип Значение по умолчанию Описание
LongStopLoss decimal 17 Дистанция первичного стоп-лосса для покупок в пунктах инструмента.
ShortStopLoss decimal 40 Первичный стоп-лосс для продаж (в пунктах).
LongTrailingStop decimal 88 Размер трейлинг-стопа для длинных позиций.
ShortTrailingStop decimal 76 Размер трейлинг-стопа для коротких позиций.
OrderVolume decimal 0.1 Базовый объём сделки (лоты), перенесённый из параметра Lots.
MacdCandleType DataType H1 Таймфрейм для MACD (наборы 22/27/9 и 19/77/9).
StochasticCandleType DataType M15 Таймфрейм для стохастиков (5/3/11 и 9/3/19).
EntryCandleType DataType M1 Таймфрейм, который подтверждает пробои и управляет выходами.

Все точечные параметры умножаются на PriceStep инструмента, что соответствует использованию Point в MetaTrader.

Торговые правила

Покупка

  1. MACD(22,27,9) на H1 растёт относительно предыдущего значения и остаётся ниже нуля.
  2. Стохастик M15 (%K=5,%D=3,slowing=11) ниже 26 и растёт относительно предыдущей точки.
  3. Закрытие текущей минутной свечи выше максимума предыдущей минутной свечи.
  4. При выполнении условий и отсутствии позиции открывается покупка объёмом OrderVolume, при необходимости закрывая обратный шорт.

Продажа

  1. MACD(19,77,9) на H1 снижается относительно предыдущей точки, при этом предыдущее значение выше нуля.
  2. Стохастик M15 (%K=9,%D=3,slowing=19) превышает 70.
  3. Закрытие текущей минутной свечи ниже минимума предыдущей минутной свечи.
  4. Открывается короткая позиция с тем же механизмом реверса, что и в оригинальном советнике.

Выходы и трейлинг

  • Первичные стопы совпадают с параметрами MQL по пунктам.
  • Трейлинг активируется после прохождения цены на заданную дистанцию в прибыльную сторону и пересчитывается на каждой завершённой минутной свече.
  • При касании текущего стоп-уровня позиция закрывается рыночным ордером.

Особенности реализации

  • Раздельные подписки по таймфреймам сохраняют последовательность обновления индикаторов, полностью повторяя многофреймовую логику советника.
  • Сравнение Bid/Ask из MQL аппроксимировано максимумами и минимумами минутных свечей — это максимально близкая модель в рамках свечного API.
  • Стратегия следует правилам репозитория: табуляция, пространство имён StockSharp.Samples.Strategies, комментарии на английском и объявление параметров через 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;
	}
}