Auf GitHub ansehen

CDC PL MFI-Strategie

Überblick

Die CDC PL MFI Strategy reproduziert den MetaTrader-Expertenberater Expert_ADC_PL_MFI (MQL/299) in StockSharp. Es sucht nach den Zwei-Kerzen-Umkehrmustern Dark Cloud Cover und Piercing Line und validiert jedes Signal mit dem Money Flow Index (MFI)-Oszillator. Die Strategie verwendet die gleichen Indikatorperioden und Niveauschwellen wie der ursprüngliche Experte, fügt optionalen Stop-Loss- und Take-Profit-Schutz in Pip-Einheiten hinzu und schließt Positionen, wenn der MFI konfigurierbare Umkehrniveaus überschreitet.

Handelslogik

  1. Abonnieren Sie den konfigurierten Kerzentyp (standardmäßig einstündige Kerzen) und berechnen Sie einen Geldflussindex mit dem angegebenen Zeitraum. Behalten Sie einfache gleitende Durchschnitte der Kerzenkörpergröße und Schlusskurse bei, um die ursprünglichen Trend- und Volatilitätsfilter nachzubilden.
  2. Wenn sich ein zinsbullisches Piercing Line-Muster bildet (Lücke unter dem vorherigen Tief, zinsbullischer Schlusskurs über dem Mittelpunkt der vorherigen bärischen Kerze, beide Kerzen größer als der durchschnittliche Körper und der vorherige Schlusskurs unter dem Trenddurchschnitt) und der aktuelle MFI-Wert unter dem LongEntryLevel (Standard 40) liegt, gehen Sie eine Long-Position ein oder wechseln Sie zu einer Long-Position.
  3. Wenn sich ein bärisches Dark Cloud Cover-Muster bildet (Lücke über dem vorherigen Hoch, bärischer Schlusskurs unter dem Mittelpunkt der vorherigen bullischen Kerze, beide Kerzen größer als der durchschnittliche Körper und der vorherige Schlusskurs über dem Trenddurchschnitt) und der aktuelle MFI-Wert über dem ShortEntryLevel (Standard 60) liegt, gehen Sie eine Short-Position ein oder wechseln Sie zu einer Short-Position.
  4. Überwachen Sie das MFI, um Positionen proaktiv zu schließen:
    • Schließen Sie Short-Positionen, wenn der MFI ExitLowerLevel (30) oder ExitUpperLevel (70) überschreitet.
    • Schließen Sie Long-Positionen, wenn der MFI unter ExitUpperLevel (70) oder ExitLowerLevel (30) fällt.
  5. Schutzanordnungen sind optional. Wenn TakeProfitPips oder StopLossPips größer als Null sind, ruft die Strategie StartProtection mit den entsprechenden Preisoffsets auf (Pip-Abstand multipliziert mit dem Wertpapierpreisschritt).

Parameter

Parameter Beschreibung Standard
CandleType Kerzendatentyp, der zur Mustererkennung verwendet wird. 1 hour Zeitrahmen
MfiPeriod Länge des Money-Flow-Index-Oszillators. 49
BodyAveragePeriod Zeitraum des gleitenden Durchschnitts des Kerzenkörpers, der zur Qualifizierung „langer“ Kerzen verwendet wird. 11
LongEntryLevel MFI-Schwellenwert, der bullische Piercing-Line-Setups bestätigt. 40
ShortEntryLevel MFI-Schwellenwert, der eine rückläufige Entwicklung der dunklen Wolkendecke bestätigt. 60
ExitLowerLevel Niedrigeres MFI-Niveau, das die Deckung von Short-Positionen auslöst. 30
ExitUpperLevel Oberes MFI-Niveau, das die Schließung von Long-Positionen auslöst. 70
StopLossPips Optionaler Stop-Loss-Abstand in Pips (0 deaktiviert den Schutz). 50
TakeProfitPips Optionale Take-Profit-Distanz in Pips (0 deaktiviert den Schutz). 50

Notizen

  • Das Volumen beträgt standardmäßig 1 Lot. When the strategy flips direction it sends a single market order sized to close the existing position and open the new one, matching the MQL behavior.
  • Die Mustererkennung spiegelt die MetaTrader-Logik wider: Es werden nur abgeschlossene Kerzen ausgewertet, Lücken müssen über das vorherige Hoch/Tief hinausgehen und ein einfacher gleitender Durchschnitt erzwingt die vorherrschende Trendbedingung.
  • Die Werte des Geldflussindex stammen direkt vom gebundenen Indikator. Es ist keine manuelle Pufferung des Indikatorverlaufs erforderlich. Die Strategie speichert nur die aktuellsten Werte, um Schwellenwertüberschreitungen zu erkennen.
  • Es wird kein Python-Port bereitgestellt. In diesem Verzeichnis ist nur die C#-Implementierung enthalten.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// CDC PL MFI strategy: Dark Cloud Cover and Piercing Line candlestick patterns
/// confirmed by Money Flow Index levels.
/// </summary>
public class CdcPlMfiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _mfiPeriod;
	private readonly StrategyParam<decimal> _longLevel;
	private readonly StrategyParam<decimal> _shortLevel;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private readonly List<ICandleMessage> _candles = new();
	private decimal _prevMfi;
	private bool _hasPrevMfi;
	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 LongLevel { get => _longLevel.Value; set => _longLevel.Value = value; }
	public decimal ShortLevel { get => _shortLevel.Value; set => _shortLevel.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public CdcPlMfiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_mfiPeriod = Param(nameof(MfiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("MFI Period", "Money Flow Index period", "Indicators");
		_longLevel = Param(nameof(LongLevel), 40m)
			.SetDisplay("Long Level", "MFI below this for long entry", "Signals");
		_shortLevel = Param(nameof(ShortLevel), 60m)
			.SetDisplay("Short Level", "MFI above this for short entry", "Signals");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candles.Clear();
		_prevMfi = 0m;
		_hasPrevMfi = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

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

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		_candles.Add(candle);
		if (_candles.Count > 5)
			_candles.RemoveAt(0);

		if (_candles.Count >= 2 && _hasPrevMfi)
		{
			var curr = _candles[^1];
			var prev = _candles[^2];

			// Piercing Line: prev bearish, curr bullish, opens below prev low, closes above midpoint
			var isPiercing = prev.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice > curr.OpenPrice
				&& curr.OpenPrice < prev.LowPrice
				&& curr.ClosePrice > (prev.OpenPrice + prev.ClosePrice) / 2m;

			// Dark Cloud Cover: prev bullish, curr bearish, opens above prev high, closes below midpoint
			var isDarkCloud = prev.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice > curr.ClosePrice
				&& curr.OpenPrice > prev.HighPrice
				&& curr.ClosePrice < (prev.OpenPrice + prev.ClosePrice) / 2m;

			if (isPiercing && mfiValue < LongLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (isDarkCloud && mfiValue > ShortLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevMfi = mfiValue;
		_hasPrevMfi = true;
	}
}