Открыть на GitHub

Стратегия Heiken Ashi Engulf

Обзор

Стратегия повторяет логику советников MetaTrader 5 heiken ashi engulf ea buy mt5.mq5 и heiken ashi engulf sell ea mt5.mq5, объединяя длинные и короткие сценарии внутри одного класса StockSharp. На каждом завершённом баре заново строятся свечи Heiken Ashi, проверяется модель поглощения, затем следуют подтверждения двумя скользящими средними и двумя фильтрами RSI. При выполнении всех условий отправляется рыночная заявка с фиксированными стоп-лоссом и тейк-профитом в метатрейдеровских пипсах.

Настройки «Buy» и «Sell» сохранены раздельно, чтобы их можно было оптимизировать независимо. Параметр Direction позволяет включить только покупки, только продажи либо оба направления.

Логика торговли

Построение Heiken Ashi

  1. Для каждого закрывшегося бара рассчитываются открытие, максимум, минимум и закрытие Heiken Ashi по классической формуле MT.
  2. В памяти хранятся две последние синтетические свечи (shift = 1 и shift = 2), что полностью повторяет смещения, используемые в исходных .mq5 файлах.

Вход в покупку

  1. Позиция должна быть равна нулю (аналог блока NoOpenedOrders).
  2. Последняя Heiken Ashi свеча бычья, а предыдущая медвежья (ChosenCandleType = 1, PreviousCandleType = 2).
  3. Реальная свеча закрылась выше максимума позапрошлой (Close[1] > High[2]), а сама позапрошлая свеча была медвежьей (Close[2] < Open[2]).
  4. Закрытие Heiken Ashi находится выше базовой скользящей средней (BuyBaselinePeriod/Method).
  5. Быстрая средняя выше медленной (BuyFast против BuySlow).
  6. Оба фильтра RSI удерживают значения в заданных границах на указанном количестве баров (поведение блока IndicatorWithinLimits с учётом допустимых исключений).
  7. После выполнения условий отправляется рыночная покупка нужного объёма, стоп и тейк пересчитываются из пипсов в цену и выставляются через SetStopLoss / SetTakeProfit. По желанию выводится сообщение в лог (замена алерта MT5).

Вход в продажу

Условия зеркальны:

  1. Позиция отсутствует.
  2. Последняя Heiken Ashi свеча медвежья, предыдущая бычья.
  3. Текущая реальная свеча закрылась ниже минимума позапрошлой (Close[1] < Low[2]), позапрошлая свеча бычья (Close[2] > Open[2]).
  4. Закрытие Heiken Ashi ниже своей базовой средней, быстрая средняя ниже медленной.
  5. Оба фильтра RSI подтверждают сигнал в собственных диапазонах.
  6. Открывается короткая позиция, стоп-лосс и тейк-профит пересчитываются по параметрам «Sell».

Параметры

Имя Значение по умолчанию Описание
CandleType H1 Таймфрейм для построения свечей и расчёта индикаторов.
Direction Both Какие сигналы активны: только покупки, только продажи либо оба направления.
BuyVolume 0.01 Объём сделки в лотах для входа в длинную позицию.
BuyStopLossPips 50 Стоп-лосс в пипсах MetaTrader для длинной позиции (0 отключает фиксированный стоп).
BuyTakeProfitPips 50 Тейк-профит в пипсах MetaTrader для длинной позиции (0 отключает цель).
BuyBaselinePeriod / BuyBaselineMethod 20 / Exponential Скользящая средняя, сравниваемая с бычьей свечой Heiken Ashi (inp1_Ro_*).
BuyFastPeriod / BuyFastMethod 20 / Exponential Быстрая средняя трендового фильтра (inp12_Lo_*).
BuySlowPeriod / BuySlowMethod 30 / Exponential Медленная средняя трендового фильтра (inp12_Ro_*).
BuyPrimaryRsi* 14, сдвиг 1, окно 2, исключения 0, пределы [0;100] Первый RSI-фильтр (inp13_*).
BuySecondaryRsi* 5, сдвиг 2, окно 3, исключения 0, пределы [0;100] Второй RSI-фильтр (inp14_*).
SellVolume 0.01 Объём сделки в лотах для входа в короткую позицию.
SellStopLossPips 50 Стоп-лосс в пипсах MetaTrader для короткой позиции.
SellTakeProfitPips 50 Тейк-профит в пипсах MetaTrader для короткой позиции.
SellBaselinePeriod / SellBaselineMethod 20 / Exponential Базовая средняя для медвежьего сценария (inp15_*).
SellFastPeriod / SellFastMethod 20 / Exponential Быстрая средняя (inp26_Lo_*).
SellSlowPeriod / SellSlowMethod 30 / Exponential Медленная средняя (inp26_Ro_*).
SellPrimaryRsi* 14, сдвиг 1, окно 2, исключения 0, пределы [0;100] Первый RSI-фильтр для продаж (inp27_*).
SellSecondaryRsi* 5, сдвиг 2, окно 3, исключения 0, пределы [0;100] Второй RSI-фильтр для продаж (inp28_*).
AlertTitle «Alert Message» Текст уведомления в журнале при открытии позиции.
SendNotification true Включает запись сообщения в лог (аналог уведомления MT5).

Управление рисками

  • Дистанции стоп-лосса и тейк-профита конвертируются из пипсов в ценовые единицы с учётом шага цены инструмента (автоматически поддерживаются 3- и 5-знаковые котировки).
  • После входа в рынок метод SetStopLoss / SetTakeProfit получает расчётную итоговую позицию, что повторяет логику «виртуальных» стопов исходного советника.
  • Дополнительных трейлинг-стопов в оригинале не было, они не добавлялись.

Дополнительно

  • Фильтры RSI работают по той же схеме «окно + количество исключений». Если истории недостаточно, сигнал отклоняется до накопления нужного количества значений.
  • Хранение Heiken Ashi по каждому бару обеспечивает полное совпадение смещений (Shift + CandlesShift) с MetaTrader.
  • Переключение Direction не сбрасывает параметры противоположной стороны, что удобно при оптимизации.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Heiken Ashi Engulf strategy: WMA crossover with candle direction filter.
/// Buys when price crosses above WMA with bullish candle, sells on bearish cross below.
/// </summary>
public class HeikenAshiEngulfStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal _prevClose;
	private decimal _prevWma;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int Period { get => _period.Value; set => _period.Value = value; }

	public HeikenAshiEngulfStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_period = Param(nameof(Period), 50)
			.SetGreaterThanZero()
			.SetDisplay("Period", "WMA period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevWma = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = 0;
		_prevWma = 0;
		_hasPrev = false;
		var wma = new ExponentialMovingAverage { Length = Period };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(wma, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			var bullish = candle.ClosePrice > candle.OpenPrice;
			var bearish = candle.ClosePrice < candle.OpenPrice;

			if (_prevClose <= _prevWma && candle.ClosePrice > wmaValue && bullish && Position <= 0)
				BuyMarket();
			else if (_prevClose >= _prevWma && candle.ClosePrice < wmaValue && bearish && Position >= 0)
				SellMarket();
		}

		_prevClose = candle.ClosePrice;
		_prevWma = wmaValue;
		_hasPrev = true;
	}
}