Открыть на GitHub

Стратегия подтверждения свечных паттернов Стохастиком

Эта стратегия переносит эксперта MetaTrader Expert_CP_Stoch в инфраструктуру StockSharp. Она комбинирует японские свечные разворотные паттерны с фильтром по сигнальной линии стохастика %D. Алгоритм анализирует каждую закрытую свечу, проверяет три предыдущие свечи на наличие бычьих или медвежьих формаций и требует, чтобы стохастик находился в зоне перепроданности/перекупленности перед открытием позиции. Закрытие позиций происходит при появлении противоположного паттерна или при пересечении сигнальной линией заданных границ.

Параметры по умолчанию повторяют оригинал: %K = 33, %D = 37, замедление = 30, уровни перепроданности/перекупленности = 30/70, границы выходов = 20/80. Стохастик в StockSharp рассчитывается по High/Low/Close, что соответствует настройке STO_LOWHIGH. Распознавание паттернов использует 12 последних тел свечей для вычисления среднего размера, как в исходном советнике.

Детали

  • Условия входа:
    • Лонг: обнаружен один из бычьих паттернов (Три белых солдата, Поглощение снизу, Утренняя доджи, Бычье поглощение, Бычье харами, Утренняя звезда, Встречные бычьи линии) и значение %D на предыдущей свече ниже порога перепроданности (по умолчанию 30).
    • Шорт: обнаружен один из медвежьих паттернов (Три чёрные вороны, Тёмное облачное покрытие, Вечерняя доджи, Медвежье поглощение, Медвежье харами, Вечерняя звезда, Встречные медвежьи линии) и значение %D на предыдущей свече выше порога перекупленности (по умолчанию 70).
  • Условия выхода:
    • Лонг: немедленное закрытие при появлении медвежьего паттерна либо при пробое %D ниже верхней (80) или нижней (20) границы выхода.
    • Шорт: немедленное закрытие при появлении бычьего паттерна либо при пробое %D выше нижней (20) или верхней (80) границы выхода.
  • Направление: открывает позиции в обе стороны по симметричным правилам.
  • Стопы: фиксированные стоп-лоссы и тейк-профиты не используются; выход основан на паттернах и пересечениях стохастика. При необходимости можно подключить защиту портфеля на уровне запуска.
  • Параметры по умолчанию:
    • Body Average Period = 12 свечей для расчёта среднего тела.
    • Stochastic %K = 33, Stochastic %D = 37, Stochastic Smoothing = 30.
    • Oversold Threshold = 30, Overbought Threshold = 70.
    • Lower Exit Level = 20, Upper Exit Level = 80.
  • Фильтры:
    • Категория: свечные паттерны + осциллятор.
    • Направление: лонг и шорт.
    • Индикаторы: стохастик и несколько свечных моделей.
    • Стопы: выход только по сигналам (без механических стопов/тейков).
    • Сложность: высокая (много условий и исторических расчётов).
    • Таймфрейм: любой, по умолчанию часовые свечи.
    • Сезонность: нет.
    • Нейросети: нет.
    • Дивергенция: отсутствует, подтверждение через уровни осциллятора.
    • Риск: средне-высокий из-за отсутствия жёстких стопов.

Как работает алгоритм

  1. Подписывается на выбранную серию свечей и привязывает стохастик (%K, %D, замедление).
  2. Хранит три последние закрытые свечи и скользящие средние тел/закрытий для воспроизведения логики MetaTrader.
  3. На каждой свече проверяет группы бычьих и медвежьих паттернов с точными математическими условиями (средние тела, отношения mid-point, гэпы и т.д.).
  4. Извлекает значения %D за две предыдущие свечи, чтобы выявить зоны перепроданности/перекупленности и пересечения уровней.
  5. При совпадении паттерна и фильтра открывает или закрывает позиции рыночными заявками через высокоуровневые методы BuyMarket/SellMarket.
  6. Для добавления стоп-менеджмента можно активировать StartProtection в конфигураторе.

Практические рекомендации

  • Для корректной работы необходимо иметь минимум Body Average Period + 3 исторических свечей; иначе среднее тело не рассчитано и сигналы будут отсутствовать.
  • Фильтр стохастика использует значение %D именно на предыдущей свече, полностью повторяя условие StochSignal(1) из исходного MQL.
  • Свечные паттерны чувствительны к гэпам и качеству данных. На низколиквидных инструментах возможны отклонения.
  • Оптимизацию можно начинать с уровней перепроданности/перекупленности и периодов стохастика, не изменяя правила распознавания паттернов.
  • Для варианта STO_CLOSECLOSE потребуется модификация индикатора в будущем, если вам нужен расчёт только по закрытиям.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Candlestick + Stochastic strategy.
/// Buys on bullish engulfing with low stochastic, sells on bearish engulfing with high stochastic.
/// </summary>
public class CandlestickStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _stochPeriod;
	private readonly StrategyParam<decimal> _stochLow;
	private readonly StrategyParam<decimal> _stochHigh;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private ICandleMessage _prevCandle;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int StochPeriod { get => _stochPeriod.Value; set => _stochPeriod.Value = value; }
	public decimal StochLow { get => _stochLow.Value; set => _stochLow.Value = value; }
	public decimal StochHigh { get => _stochHigh.Value; set => _stochHigh.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public CandlestickStochasticStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_stochPeriod = Param(nameof(StochPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Stoch Period", "Stochastic K period", "Indicators");
		_stochLow = Param(nameof(StochLow), 40m)
			.SetDisplay("Stoch Low", "Stochastic oversold level", "Signals");
		_stochHigh = Param(nameof(StochHigh), 60m)
			.SetDisplay("Stoch High", "Stochastic overbought level", "Signals");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCandle = null;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevCandle = null;
		_candlesSinceTrade = SignalCooldownCandles;
		var rsi = new RelativeStrengthIndex { Length = StochPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal stochValue)
	{
		if (candle.State != CandleStates.Finished) return;

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_prevCandle != null)
		{
			var bullishEngulf = _prevCandle.OpenPrice > _prevCandle.ClosePrice &&
								candle.ClosePrice > candle.OpenPrice &&
								candle.ClosePrice > _prevCandle.OpenPrice &&
								candle.OpenPrice < _prevCandle.ClosePrice;

			var bearishEngulf = _prevCandle.ClosePrice > _prevCandle.OpenPrice &&
								candle.OpenPrice > candle.ClosePrice &&
								candle.OpenPrice > _prevCandle.ClosePrice &&
								candle.ClosePrice < _prevCandle.OpenPrice;

			if (bullishEngulf && stochValue < StochLow && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (bearishEngulf && stochValue > StochHigh && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevCandle = candle;
	}
}