AH HM MFI 戦略
概要
AH HM MFI 戦略は、マネー フロー インデックス (MFI) によって確認されるハンマーとハンギングマンのローソク足パターンを取引します。短期的な下降トレンドに強気のハンマーが現れ、MFI が売られすぎのしきい値を下回っている場合、この戦略はロングポジションをオープンします。 MFIが買われ過ぎの閾値を上回っている間に弱気のハンギングマンが上昇トレンドを形成すると、ショートポジションがオープンします。保護的出口は、MFI が事前に定義された上限または下限の境界を超えるとトリガーされます。
中核ロジック
- 構成された時間枠のローソク足をサブスクライブし、2 つのインジケーターを計算します。
- マネー フロー インデックス (設定可能な期間) (デフォルト: 47)。
- 元の MQL 戦略からのトレンド フィルターを近似する終値の 単純移動平均 (デフォルトの長さ: 5)。
- ハンマー と 吊り下げられた男 パターンを検出します。
- キャンドル本体は範囲の上部 3 分の 1 に位置します。
- 実体に対して長い下の影。
- 前のローソク足と比較したトレンドの方向のギャップ。
- 前のローソク足と移動平均の中点を使用してトレンドを確認します。
- MFI しきい値を使用してエントリを確認します。
- ハンマーが検出され、MFI が設定された売られ過ぎレベル (デフォルト: 40) 以下の場合は、ロングを入力します。
- ぶら下がっている男性が検出され、MFI が設定された買われすぎレベル (デフォルト: 60) 以上である場合は、ショートを入力します。
- MFI 交差点を使用して出口を管理します。
- MFI が下限または上限の出口レベル (デフォルト: 30 および 70) を超えて上向きにクロスしたときに、ショート ポジションを閉じます。
- MFIが上方出口レベルを上方に通過するか、下方出口レベルを下方に下方に通過すると、ロングポジションを閉じます。
- 内蔵のリスク保護モジュールを起動して緊急停止を処理します。
パラメーター
| 名前 | 説明 | デフォルト |
|---|---|---|
CandleType |
パターン検出に使用されるローソク足のデータ型とタイムフレーム。 | 30分の時間枠 |
MfiPeriod |
MFI 計算のルックバック期間。 | 47 |
MaPeriod |
トレンド確認のために終値に適用される SMA の長さ。 | 5 |
HammerEntryThreshold |
ハンマー信号を入力する前に許可される最大 MFI 値。 | 40 |
HangingEntryThreshold |
ぶら下がりマン信号に入る前に必要な最小 MFI 値。 | 60 |
MfiUpperExitLevel |
MFI の上限境界。それを超えるとオープンポジションがクローズされます。 | 70 |
MfiLowerExitLevel |
MFI 境界の下限。それを下回るとロングポジションがクローズされ、上をクロスするとショートポジションがクローズされます。 | 30 |
注意事項
- この戦略は、不完全な情報に基づいて行動することを避けるために、完成したキャンドルのみを評価します。
- ハンマーと吊るされた男の検出は保守的です。長い下影とろうそくの高値付近にある本体の両方が必要です。
- 移動平均は、元のエキスパートアドバイザーの MetaTrader 5
CloseAvgフィルターを置き換え、エントリがより広範な傾向に一致することを保証します。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Hammer/hanging-man lower-shadow patterns confirmed by previous SMA trend and MFI.
/// </summary>
public class AhHmMfiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _mfiPeriod;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _hammerEntryThreshold;
private readonly StrategyParam<decimal> _hangingEntryThreshold;
private readonly StrategyParam<decimal> _mfiUpperExitLevel;
private readonly StrategyParam<decimal> _mfiLowerExitLevel;
private MoneyFlowIndex _mfi;
private SimpleMovingAverage _ma;
private ICandleMessage _previousCandle;
private decimal? _previousMa;
private decimal? _previousMfi;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
public decimal HammerEntryThreshold { get => _hammerEntryThreshold.Value; set => _hammerEntryThreshold.Value = value; }
public decimal HangingEntryThreshold { get => _hangingEntryThreshold.Value; set => _hangingEntryThreshold.Value = value; }
public decimal MfiUpperExitLevel { get => _mfiUpperExitLevel.Value; set => _mfiUpperExitLevel.Value = value; }
public decimal MfiLowerExitLevel { get => _mfiLowerExitLevel.Value; set => _mfiLowerExitLevel.Value = value; }
public AhHmMfiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame());
_mfiPeriod = Param(nameof(MfiPeriod), 47).SetGreaterThanZero();
_maPeriod = Param(nameof(MaPeriod), 5).SetGreaterThanZero();
_hammerEntryThreshold = Param(nameof(HammerEntryThreshold), 40m);
_hangingEntryThreshold = Param(nameof(HangingEntryThreshold), 60m);
_mfiUpperExitLevel = Param(nameof(MfiUpperExitLevel), 70m);
_mfiLowerExitLevel = Param(nameof(MfiLowerExitLevel), 30m);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetRuntime();
}
private void ResetRuntime()
{
_previousCandle = null;
_previousMa = null;
_previousMfi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetRuntime();
_mfi = new MoneyFlowIndex { Length = MfiPeriod };
_ma = new SimpleMovingAverage { Length = MaPeriod };
SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var mfiValue = _mfi.Process(candle);
var maValue = _ma.Process(candle.ClosePrice, candle.OpenTime, true);
if (!mfiValue.IsFormed || !maValue.IsFormed)
{
Remember(candle, maValue.IsFormed ? maValue.ToDecimal() : null,
mfiValue.IsFormed ? mfiValue.ToDecimal() : null);
return;
}
var mfi = mfiValue.ToDecimal();
var ma = maValue.ToDecimal();
if (_previousMfi is decimal previousMfi)
{
if (Position > 0m &&
((previousMfi <= MfiUpperExitLevel && mfi > MfiUpperExitLevel) ||
(previousMfi >= MfiLowerExitLevel && mfi < MfiLowerExitLevel)))
{
ClosePosition();
Remember(candle, ma, mfi);
return;
}
if (Position < 0m &&
((previousMfi <= MfiLowerExitLevel && mfi > MfiLowerExitLevel) ||
(previousMfi <= MfiUpperExitLevel && mfi > MfiUpperExitLevel)))
{
ClosePosition();
Remember(candle, ma, mfi);
return;
}
}
if (Position == 0m && _previousCandle is { } previous && _previousMa is decimal previousMa)
{
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
var range = candle.HighPrice - candle.LowPrice;
if (body > 0m && range > 0m)
{
var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;
var bodyInUpperThird = Math.Min(candle.OpenPrice, candle.ClosePrice) >= candle.HighPrice - range / 3m;
var lowerTailPattern = bodyInUpperThird && lowerShadow >= body * 2.5m && upperShadow <= body * 0.5m;
var previousMidpoint = (previous.OpenPrice + previous.ClosePrice) / 2m;
if (lowerTailPattern && candle.OpenPrice < previous.ClosePrice &&
previousMidpoint < previousMa && mfi <= HammerEntryThreshold)
BuyMarket();
else if (lowerTailPattern && candle.OpenPrice > previous.ClosePrice &&
previousMidpoint > previousMa && mfi >= HangingEntryThreshold)
SellMarket();
}
}
Remember(candle, ma, mfi);
}
private void Remember(ICandleMessage candle, decimal? ma, decimal? mfi)
{
_previousCandle = candle;
_previousMa = ma;
_previousMfi = mfi;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
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 MoneyFlowIndex, SimpleMovingAverage, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import process_float
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(30)))
self._mfi_period = self.Param("MfiPeriod", 47)
self._ma_period = self.Param("MaPeriod", 5)
self._hammer_entry_threshold = self.Param("HammerEntryThreshold", 40.0)
self._hanging_entry_threshold = self.Param("HangingEntryThreshold", 60.0)
self._mfi_upper_exit_level = self.Param("MfiUpperExitLevel", 70.0)
self._mfi_lower_exit_level = self.Param("MfiLowerExitLevel", 30.0)
self._reset_runtime()
@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 MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
@property
def HammerEntryThreshold(self):
return self._hammer_entry_threshold.Value
@HammerEntryThreshold.setter
def HammerEntryThreshold(self, value):
self._hammer_entry_threshold.Value = value
@property
def HangingEntryThreshold(self):
return self._hanging_entry_threshold.Value
@HangingEntryThreshold.setter
def HangingEntryThreshold(self, value):
self._hanging_entry_threshold.Value = value
@property
def MfiUpperExitLevel(self):
return self._mfi_upper_exit_level.Value
@MfiUpperExitLevel.setter
def MfiUpperExitLevel(self, value):
self._mfi_upper_exit_level.Value = value
@property
def MfiLowerExitLevel(self):
return self._mfi_lower_exit_level.Value
@MfiLowerExitLevel.setter
def MfiLowerExitLevel(self, value):
self._mfi_lower_exit_level.Value = value
def _reset_runtime(self):
self._previous_candle = None
self._previous_ma = None
self._previous_mfi = None
def OnReseted(self):
super(ah_hm_mfi_strategy, self).OnReseted()
self._reset_runtime()
def OnStarted2(self, time):
super(ah_hm_mfi_strategy, self).OnStarted2(time)
self._reset_runtime()
self._mfi = MoneyFlowIndex()
self._mfi.Length = self.MfiPeriod
self._ma = SimpleMovingAverage()
self._ma.Length = self.MaPeriod
self.SubscribeCandles(self.CandleType).Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
mfi_input = CandleIndicatorValue(self._mfi, candle)
mfi_input.IsFinal = True
mfi_value = self._mfi.Process(mfi_input)
ma_value = process_float(self._ma, candle.ClosePrice, candle.OpenTime, True)
if not mfi_value.IsFormed or not ma_value.IsFormed:
self._remember(
candle,
float(ma_value) if ma_value.IsFormed else None,
float(mfi_value) if mfi_value.IsFormed else None
)
return
mfi = float(mfi_value)
ma = float(ma_value)
if self._previous_mfi is not None:
prior = self._previous_mfi
if self.Position > 0 and (
(prior <= self.MfiUpperExitLevel and mfi > self.MfiUpperExitLevel)
or (prior >= self.MfiLowerExitLevel and mfi < self.MfiLowerExitLevel)):
self.ClosePosition()
self._remember(candle, ma, mfi)
return
if self.Position < 0 and (
(prior <= self.MfiLowerExitLevel and mfi > self.MfiLowerExitLevel)
or (prior <= self.MfiUpperExitLevel and mfi > self.MfiUpperExitLevel)):
self.ClosePosition()
self._remember(candle, ma, mfi)
return
previous = self._previous_candle
if self.Position == 0 and previous is not None and self._previous_ma is not None:
candle_open = float(candle.OpenPrice)
candle_close = float(candle.ClosePrice)
candle_high = float(candle.HighPrice)
candle_low = float(candle.LowPrice)
body = abs(candle_close - candle_open)
bar_range = candle_high - candle_low
if body > 0 and bar_range > 0:
upper_shadow = candle_high - max(candle_open, candle_close)
lower_shadow = min(candle_open, candle_close) - candle_low
body_upper_third = min(candle_open, candle_close) >= candle_high - bar_range / 3.0
lower_tail = (body_upper_third and lower_shadow >= body * 2.5
and upper_shadow <= body * 0.5)
previous_midpoint = (float(previous.OpenPrice) + float(previous.ClosePrice)) / 2.0
previous_close = float(previous.ClosePrice)
if (lower_tail and candle_open < previous_close
and previous_midpoint < self._previous_ma
and mfi <= self.HammerEntryThreshold):
self.BuyMarket()
elif (lower_tail and candle_open > previous_close
and previous_midpoint > self._previous_ma
and mfi >= self.HangingEntryThreshold):
self.SellMarket()
self._remember(candle, ma, mfi)
def _remember(self, candle, ma, mfi):
self._previous_candle = candle
self._previous_ma = ma
self._previous_mfi = mfi
def CreateClone(self):
return ah_hm_mfi_strategy()