Auf GitHub ansehen

AH HM MFI-Strategie

Zusammenfassung

Die AH HM MFI-Strategie handelt mit Hammer- und Hängemann-Kerzenmustern, die durch den Money Flow Index (MFI) bestätigt werden. Wenn in einem kurzfristigen Abwärtstrend ein bullischer Hammer erscheint und der MFI unter einem überverkauften Schwellenwert bleibt, eröffnet die Strategie eine Long-Position. Wenn sich in einem Aufwärtstrend ein bärischer hängender Mann bildet, während der MFI über einer überkauften Schwelle liegt, eröffnet er eine Short-Position. Schutzausgänge werden ausgelöst, wenn der MFI vordefinierte Ober- oder Untergrenzen überschreitet.

Kernlogik

  1. Abonnieren Sie die konfigurierten Zeitrahmenkerzen und berechnen Sie zwei Indikatoren:
    • Geldflussindex mit konfigurierbarem Zeitraum (Standard: 47).
    • Einfacher gleitender Durchschnitt der Schlusskurse zur Annäherung an den Trendfilter der ursprünglichen MQL-Strategie (Standardlänge: 5).
  2. Hammer- und Hanging Man-Muster erkennen:
    • Der Kerzenkörper liegt im oberen Drittel des Sortiments.
    • Langer unterer Schatten im Verhältnis zum realen Körper.
    • Lücke in der Trendrichtung im Vergleich zur vorherigen Kerze.
    • Trendbestätigung anhand des Mittelpunkts der vorherigen Kerze im Vergleich zum gleitenden Durchschnitt.
  3. Eingaben mit MFI-Schwellenwerten bestätigen:
    • Geben Sie „long“ ein, wenn ein Hammer erkannt wird und der MFI auf oder unter dem konfigurierten Überverkauft-Niveau liegt (Standard: 40).
    • Geben Sie Short ein, wenn ein hängender Mann erkannt wird und der MFI auf oder über dem konfigurierten Überkaufniveau liegt (Standard: 60).
  4. Ausgänge über MFI-Kreuzungen verwalten:
    • Schließen Sie Short-Positionen, wenn der MFI das untere oder obere Ausgangsniveau nach oben überschreitet (Standardwerte: 30 und 70).
    • Schließen Sie Long-Positionen, wenn der MFI die obere Ausstiegsebene nach oben oder die untere Ausstiegsebene nach unten kreuzt.
  5. Starten Sie das integrierte Risikoschutzmodul, um Notstopps durchzuführen.

Parameter

Name Beschreibung Standard
CandleType Kerzendatentyp und Zeitrahmen, die zur Mustererkennung verwendet werden. 30-minütiger Zeitrahmen
MfiPeriod Rückblickzeitraum für die MFI-Berechnung. 47
MaPeriod Länge des SMA, der zur Trendbestätigung auf die Schlusskurse angewendet wird. 5
HammerEntryThreshold Maximal zulässiger MFI-Wert vor Eingabe eines Hammersignals. 40
HangingEntryThreshold Erforderlicher Mindest-MFI-Wert vor dem Betreten eines Hängenden-Mann-Signals. 60
MfiUpperExitLevel Obere MFI-Grenze; Wenn Sie darüber kreuzen, wird jede offene Position geschlossen. 70
MfiLowerExitLevel Untere MFI-Grenze; Bei einem Schnitt darunter werden Long-Positionen geschlossen, bei einem Schnitt darüber werden Short-Positionen geschlossen. 30

Notizen

  • Die Strategie bewertet nur fertige Kerzen, um zu vermeiden, dass auf unvollständigen Informationen reagiert wird.
  • Die Erkennung von Hammer und hängendem Mann ist konservativ: Es sind sowohl ein langer unterer Schatten als auch ein Körper in der Nähe der Kerzenhöhe erforderlich.
  • Der gleitende Durchschnitt ersetzt den Filter MetaTrader 5 CloseAvg des ursprünglichen Expertenberaters und stellt sicher, dass die Einträge mit dem breiteren Trend übereinstimmen.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Hammer/Hanging Man + MFI strategy.
/// Buys on hammer with low MFI (oversold), sells on hanging man with high MFI (overbought).
/// </summary>
public class AhHmMfiStrategy : 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 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 AhHmMfiStrategy()
	{
		_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), 35m)
			.SetDisplay("MFI Low", "MFI oversold threshold for buy", "Signals");
		_mfiHigh = Param(nameof(MfiHigh), 65m)
			.SetDisplay("MFI High", "MFI overbought threshold for sell", "Signals");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 8)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

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

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

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
		var range = candle.HighPrice - candle.LowPrice;
		if (range <= 0 || body <= 0) return;

		var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
		var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;

		var isHammer = lowerShadow > body * 2.5m && upperShadow < body * 0.5m;
		var isHangingMan = upperShadow > body * 2.5m && lowerShadow < body * 0.5m;

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