Открыть на GitHub

Стратегия «Morning/Evening Star + MFI»

Обзор

Стратегия воспроизводит логику советника MetaTrader Expert_AMS_ES_MFI, сочетая свечные разворотные модели и подтверждение импульса индикатором Money Flow Index (MFI). На выбранном таймфрейме анализируются трехсвечные фигуры «Morning Star» и «Evening Star», после чего сигнал фильтруется порогами MFI, чтобы подтвердить исчерпанность текущего движения. Пересечения уровней MFI также используются для выхода из позиции.

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

  • Источник данных: закрытые свечи заданного таймфрейма и рассчитанные значения MFI.
  • Индикаторы:
    • Money Flow Index (MFI) с настраиваемым периодом (по умолчанию 49).
  • Правила входа:
    • Покупка: обнаружить модель «Morning Star» (сильная медвежья свеча, маленькая центральная свеча, сильная бычья свеча, закрывающаяся выше середины тела первой) и убедиться, что значение MFI на предыдущей свече ниже порога подтверждения (по умолчанию 40).
    • Продажа: обнаружить модель «Evening Star» (сильная бычья свеча, маленькая центральная свеча, сильная медвежья свеча, закрывающаяся ниже середины тела первой) и убедиться, что значение MFI на предыдущей свече выше порога подтверждения (по умолчанию 60).
    • При смене направления стратегия сначала закрывает противоположную позицию и только затем открывает новую.
  • Правила выхода:
    • Выход из лонга: зафиксировать позицию, если MFI пересекает сверху уровень перекупленности (по умолчанию 70) или опускается ниже уровня перепроданности (по умолчанию 30), что сигнализирует о перегреве импульса или срыве разворота.
    • Выход из шорта: зафиксировать позицию, если MFI пробивает вверх уровень перепроданности (30) либо продолжает рост выше перекупленности (70), что указывает на усиление быков.
  • Тип заявок: рыночные ордера с объемом, заданным в настройках StockSharp.

Параметры

Название Описание Значение по умолчанию
CandleType Таймфрейм анализируемых свечей. Свечи 1 часа
MfiPeriod Период индикатора MFI. 49
BullishMfiThreshold Порог MFI для подтверждения сигналов Morning Star. 40
BearishMfiThreshold Порог MFI для подтверждения сигналов Evening Star. 60
UpperExitLevel Уровень MFI для фиксации перекупленности. 70
LowerExitLevel Уровень MFI для фиксации перепроданности. 30

Все параметры можно оптимизировать в StockSharp Designer или Optimizer.

Рекомендации по использованию

  1. Подключите стратегию к нужному инструменту и выставьте CandleType, соответствующий таймфрейму исходного MQL-советника.
  2. Настройте риск-параметры (объем, кредитное плечо, ограничения брокера) в интерфейсе StockSharp.
  3. Запустите стратегию — она автоматически подпишется на свечи, рассчитает значения MFI и начнет управление позицией по описанным правилам.

Происхождение

Стратегия является прямой конверсией советника из каталога MQL/323, сохраняет его логику на основе свечных моделей и MFI, но реализована средствами высокоуровневого API StockSharp.

namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Morning/Evening Star + MFI strategy.
/// Buys on morning star with low MFI, sells on evening star with high MFI.
/// </summary>
public class MorningEveningMfiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _mfiPeriod;
	private readonly StrategyParam<decimal> _mfiLow;
	private readonly StrategyParam<decimal> _mfiHigh;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private ICandleMessage _prevCandle;
	private ICandleMessage _prevPrevCandle;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
	public decimal MfiLow { get => _mfiLow.Value; set => _mfiLow.Value = value; }
	public decimal MfiHigh { get => _mfiHigh.Value; set => _mfiHigh.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public MorningEveningMfiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_mfiPeriod = Param(nameof(MfiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("MFI Period", "MFI period", "Indicators");
		_mfiLow = Param(nameof(MfiLow), 40m)
			.SetDisplay("MFI Low", "MFI oversold threshold", "Signals");
		_mfiHigh = Param(nameof(MfiHigh), 60m)
			.SetDisplay("MFI High", "MFI overbought threshold", "Signals");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

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

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

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_prevCandle != null && _prevPrevCandle != null)
		{
			var prevBody = Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice);
			var prevRange = _prevCandle.HighPrice - _prevCandle.LowPrice;
			var isSmallBody = prevRange > 0 && prevBody < prevRange * 0.3m;
			var firstMidpoint = (_prevPrevCandle.OpenPrice + _prevPrevCandle.ClosePrice) / 2m;

			var firstBearish = _prevPrevCandle.OpenPrice > _prevPrevCandle.ClosePrice;
			var currBullish = candle.ClosePrice > candle.OpenPrice;
			var isMorningStar = firstBearish && isSmallBody && currBullish && candle.ClosePrice > firstMidpoint;

			var firstBullish = _prevPrevCandle.ClosePrice > _prevPrevCandle.OpenPrice;
			var currBearish = candle.OpenPrice > candle.ClosePrice;
			var isEveningStar = firstBullish && isSmallBody && currBearish && candle.ClosePrice < firstMidpoint;

			if (isMorningStar && mfiValue < MfiLow && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (isEveningStar && mfiValue > MfiHigh && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevPrevCandle = _prevCandle;
		_prevCandle = candle;
	}
}