Auf GitHub ansehen

Expert AML MFI Strategy

Overview

The Expert AML MFI Strategy replicates the MetaTrader 5 expert advisor "Expert_AML_MFI" using the StockSharp high-level API. It focuses on the Meeting Lines candlestick pattern and validates every signal with the Money Flow Index (MFI) oscillator. The strategy automatically maintains the necessary candle statistics, identifies bullish or bearish reversals, and manages open positions whenever the MFI crosses oversold or overbought thresholds.

Trading Logic

  1. Candle preparation – the strategy subscribes to the selected timeframe (H1 by default) and keeps the last two completed candles together with the moving average of candle bodies. The average body size is calculated through a SimpleMovingAverage applied to the absolute candle body size, mirroring the MT5 implementation.
  2. Pattern detection – two specialized helpers recognise Bullish Meeting Lines and Bearish Meeting Lines:
    • Bullish setup: a long bearish candle followed by a long bullish candle that closes near the previous close (within 10% of the average body).
    • Bearish setup: a long bullish candle followed by a long bearish candle with similar closing prices.
  3. MFI confirmation – the previous MFI value must be below the bullish entry level (default 40) for long trades or above the bearish entry level (default 60) for short trades.
  4. Position management – the last two MFI readings are tracked to detect crossings of the oversold (30) and overbought (70) levels:
    • A cross above either level exits short positions.
    • A cross below the oversold level or above the overbought level exits long positions.
  5. Order execution – when a valid pattern and MFI confirmation occur, the strategy closes any opposite exposure and opens a new position at market with the configured base volume.

Parameters

Name Description Default
CandleType Timeframe used for candle subscription. 1 hour time frame
MfiPeriod Number of bars for the MFI oscillator. 12
BodyAveragePeriod Window length for the average body size calculation. 4
BullishEntryLevel Maximum MFI value allowed for bullish entries. 40
BearishEntryLevel Minimum MFI value required for bearish entries. 60
OversoldLevel Oversold level used for exit signals. 30
OverboughtLevel Overbought level used for exit signals. 70
TradeVolume Base order volume applied to new trades. 1

All parameters can be optimised directly inside StockSharp Designer thanks to the StrategyParam wrappers.

Indicators and Visuals

  • Money Flow Index – bound to the candle subscription for confirmation and displayed on the chart when a chart area is available.
  • Simple Moving Average of candle bodies – internal use only, reproducing the MT5 average body calculation.

Notes

  • The strategy calls StartProtection() once to enable built-in position protection facilities.
  • Trade commands use BuyMarket and SellMarket helpers to flatten the current position before opening a new one, matching the MetaTrader expert advisor behaviour.
  • No Python port is provided in accordance with the project requirements.
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;
	}
}