Открыть на GitHub

Стратегия Expert AML MFI

Обзор

Expert AML MFI Strategy повторяет советник MetaTrader 5 «Expert_AML_MFI» с использованием высокоуровневого API StockSharp. В центре внимания — свечная модель Meeting Lines (встречные линии), подтверждаемая осциллятором Money Flow Index (MFI). Стратегия автоматически поддерживает статистику по свечам, определяет бычьи и медвежьи разворотные комбинации и управляет позициями при пересечениях MFI уровней перепроданности и перекупленности.

Логика работы

  1. Подготовка данных. Подписка на выбранный таймфрейм (по умолчанию H1). Стратегия хранит две последние завершённые свечи и скользящее среднее модуля свечного тела. Средний размер тела рассчитывается индикатором SimpleMovingAverage, который применяется к абсолютной разнице между ценами открытия и закрытия — полностью аналогично оригиналу на MT5.
  2. Определение паттерна. Вспомогательные методы выявляют Bullish Meeting Lines и Bearish Meeting Lines:
    • Бычий сигнал: длинная «чёрная» свеча, за которой следует длинная «белая» свеча с закрытием около предыдущего (не далее 10% от среднего тела).
    • Медвежий сигнал: длинная «белая» свеча и за ней длинная «чёрная» свеча с почти совпадающими ценами закрытия.
  3. Подтверждение MFI. Предыдущее значение MFI должно быть ниже уровня входа в лонг (по умолчанию 40) либо выше уровня входа в шорт (по умолчанию 60).
  4. Управление позицией. Сохраняются два последних значения MFI, чтобы фиксировать пересечения уровней перепроданности (30) и перекупленности (70):
    • Пересечение любого из уровней вверх закрывает короткие позиции.
    • Пересечение уровня 30 сверху вниз или уровня 70 снизу вверх закрывает длинные позиции.
  5. Исполнение ордеров. При подтверждённом паттерне стратегия закрывает противоположную позицию (если она есть) и открывает новую рыночную сделку заданным базовым объёмом.

Параметры

Имя Описание Значение по умолчанию
CandleType Таймфрейм для подписки на свечи. Часовые свечи
MfiPeriod Период расчёта MFI. 12
BodyAveragePeriod Количество свечей в среднем по телам. 4
BullishEntryLevel Максимальное значение MFI для бычьего входа. 40
BearishEntryLevel Минимальное значение MFI для медвежьего входа. 60
OversoldLevel Уровень перепроданности для выходов. 30
OverboughtLevel Уровень перекупленности для выходов. 70
TradeVolume Базовый объём новой позиции. 1

Каждый параметр оформлен через StrategyParam, поэтому доступна оптимизация в Designer.

Индикаторы и визуализация

  • Money Flow Index — подключён к подписке на свечи и отображается на графике при наличии области.
  • Simple Moving Average от модулей тел — служебный индикатор для оценки «длины» свечей.

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

  • Метод StartProtection() активирует стандартную защиту позиции один раз при запуске.
  • Команды BuyMarket и SellMarket сначала закрывают противоположную позицию, после чего открывают новую, что повторяет поведение оригинального эксперта.
  • Python-версия умышленно не создаётся, согласно требованиям репозитория.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Meeting Lines + MFI strategy.
/// Buys on bullish meeting lines with low MFI, sells on bearish meeting lines with high MFI.
/// </summary>
public class ExpertAmlMfiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _mfiPeriod;
	private readonly StrategyParam<decimal> _mfiLow;
	private readonly StrategyParam<decimal> _mfiHigh;

	private ICandleMessage _prevCandle;

	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 ExpertAmlMfiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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 level for bullish entry", "Signals");
		_mfiHigh = Param(nameof(MfiHigh), 60m)
			.SetDisplay("MFI High", "MFI level for bearish entry", "Signals");
	}

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevCandle = null;
		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 (_prevCandle != null)
		{
			var avgBody = (Math.Abs(candle.ClosePrice - candle.OpenPrice) +
						   Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice)) / 2m;

			if (avgBody > 0)
			{
				var prevBearish = _prevCandle.OpenPrice > _prevCandle.ClosePrice;
				var currBullish = candle.ClosePrice > candle.OpenPrice;
				var closesNear = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;

				if (prevBearish && currBullish && closesNear && mfiValue < MfiLow && Position <= 0)
					BuyMarket();

				var prevBullish = _prevCandle.ClosePrice > _prevCandle.OpenPrice;
				var currBearish = candle.OpenPrice > candle.ClosePrice;
				var closesNear2 = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;

				if (prevBullish && currBearish && closesNear2 && mfiValue > MfiHigh && Position >= 0)
					SellMarket();
			}
		}

		_prevCandle = candle;
	}
}