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
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).
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.
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).
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.
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;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class ah_hm_mfi_strategy(Strategy):
def __init__(self):
super(ah_hm_mfi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._mfi_period = self.Param("MfiPeriod", 14)
self._mfi_low = self.Param("MfiLow", 35.0)
self._mfi_high = self.Param("MfiHigh", 65.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 8)
self._candles_since_trade = 8
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MfiPeriod(self):
return self._mfi_period.Value
@MfiPeriod.setter
def MfiPeriod(self, value):
self._mfi_period.Value = value
@property
def MfiLow(self):
return self._mfi_low.Value
@MfiLow.setter
def MfiLow(self, value):
self._mfi_low.Value = value
@property
def MfiHigh(self):
return self._mfi_high.Value
@MfiHigh.setter
def MfiHigh(self, value):
self._mfi_high.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(ah_hm_mfi_strategy, self).OnReseted()
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(ah_hm_mfi_strategy, self).OnStarted2(time)
self._candles_since_trade = self.SignalCooldownCandles
rsi = RelativeStrengthIndex()
rsi.Length = self.MfiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, mfi_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
mfi_val = float(mfi_value)
body = abs(float(candle.ClosePrice) - float(candle.OpenPrice))
rng = float(candle.HighPrice) - float(candle.LowPrice)
if rng <= 0 or body <= 0:
return
upper_shadow = float(candle.HighPrice) - max(float(candle.OpenPrice), float(candle.ClosePrice))
lower_shadow = min(float(candle.OpenPrice), float(candle.ClosePrice)) - float(candle.LowPrice)
is_hammer = lower_shadow > body * 2.5 and upper_shadow < body * 0.5
is_hanging_man = upper_shadow > body * 2.5 and lower_shadow < body * 0.5
if is_hammer and mfi_val < self.MfiLow and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif is_hanging_man and mfi_val > self.MfiHigh and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return ah_hm_mfi_strategy()