GitHub で見る
MFI確認戦略によるモーニング/イブニングスター
概要
この戦略は、MetaTrader の専門家 Expert_AMS_ES_MFI のロジックを再現しており、複数のローソク足の反転パターンとマネー フロー インデックス (MFI) からのモメンタム確認を組み合わせています。選択した時間枠で 3 本のローソク足のモーニング スターとイブニング スターのフォーメーションを監視し、MFI しきい値を使用してシグナルをフィルター処理して、取引に入る前に現在のスイングの枯渇を確認します。 MFI クロスによって検出されたモメンタムの反転は、オープン ポジションを閉じるためにも使用されます。
取引ロジック
- データ ソース: 設定されたタイムフレームの完了したローソク足とそれに関連する MFI 値。
- 指標:
- マネー フロー インデックス (MFI) – 期間は構成可能です (デフォルトは 49)。
- エントリールール:
- ロング: モーニング スター パターン (強い弱気のローソク足、小さなボディの真ん中のローソク足、最初のローソク足の中点より上で閉じる強い強気のローソク足) を検出し、前のローソク足の MFI が強気の確認しきい値 (デフォルト 40) を下回っている必要があります。
- ショート: イブニング スター パターン (強い強気のローソク足、小さなボディの真ん中のローソク足、最初のローソク足の中間点を下回って閉じる強い弱気のローソク足) を検出し、前のローソク足の MFI が弱気の確認しきい値 (デフォルト 60) を超えていることを要求します。
- ポジションを反転する場合、この戦略では、新しい取引を開始する前に、まず反対側のエクスポージャーをクローズします。
- 終了ルール:
- ロングイグジット: MFI が上方出口レベル (デフォルト 70) を超えるか、下方出口レベル (デフォルト 30) を下回るとポジションを閉じ、買われすぎの勢いまたは反転の失敗を示します。
- ショートエグジット: MFI が下限エグジットレベル (デフォルト 30) または上限エグジットレベル (デフォルト 70) を超えたときにポジションを閉じ、強気の勢いが高まっていることを示します。
- 注文タイプ: StockSharp 環境で設定された戦略ボリュームを使用した成行注文。
パラメーター
| 名前 |
説明 |
デフォルト |
CandleType |
分析に使用されるローソク足のタイムフレーム。 |
1時間キャンドル |
MfiPeriod |
MFI インジケーターの期間。 |
49 |
BullishMfiThreshold |
モーニングスター信号を確認するMFIレベル。 |
40 |
BearishMfiThreshold |
Evening Star信号を確認するMFIレベル。 |
60 |
UpperExitLevel |
買われ過ぎの出口検出に使用される MFI レベル。 |
70 |
LowerExitLevel |
売られ過ぎの出口検出に使用される MFI レベル。 |
30 |
すべてのパラメータは、StockSharp デザイナー/オプティマイザー内で最適化できます。
使用上の注意
- 戦略を目的の証券に添付し、元の MQL 専門家からのチャートの時間枠と一致するように
CandleType を設定します。
- StockSharp プラットフォームを介して、戦略ボリュームやブローカー固有の注文サイズなどのリスク パラメーターを設定します。
- 戦略を有効にします。上記のルールに従って、ローソク足を自動的に購読し、MFI 値を計算し、ポジションを管理します。
起源
この戦略は、MQL/323 にある MQL5 エキスパート アドバイザーを直接変換したもので、そのパターンと MFI ベースの意思決定ロジックを維持しながら、StockSharp の高レベルの API に適応させます。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Morning/Evening Star + MFI strategy.
/// Buys on morning star with low MFI, sells on evening star with high MFI.
/// </summary>
public class MorningEveningMfiStrategy : 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 ICandleMessage _prevCandle;
private ICandleMessage _prevPrevCandle;
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 MorningEveningMfiStrategy()
{
_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), 40m)
.SetDisplay("MFI Low", "MFI oversold threshold", "Signals");
_mfiHigh = Param(nameof(MfiHigh), 60m)
.SetDisplay("MFI High", "MFI overbought threshold", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_prevPrevCandle = null;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_prevPrevCandle = null;
_candlesSinceTrade = SignalCooldownCandles;
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 (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (_prevCandle != null && _prevPrevCandle != null)
{
var prevBody = Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice);
var prevRange = _prevCandle.HighPrice - _prevCandle.LowPrice;
var isSmallBody = prevRange > 0 && prevBody < prevRange * 0.3m;
var firstMidpoint = (_prevPrevCandle.OpenPrice + _prevPrevCandle.ClosePrice) / 2m;
var firstBearish = _prevPrevCandle.OpenPrice > _prevPrevCandle.ClosePrice;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var isMorningStar = firstBearish && isSmallBody && currBullish && candle.ClosePrice > firstMidpoint;
var firstBullish = _prevPrevCandle.ClosePrice > _prevPrevCandle.OpenPrice;
var currBearish = candle.OpenPrice > candle.ClosePrice;
var isEveningStar = firstBullish && isSmallBody && currBearish && candle.ClosePrice < firstMidpoint;
if (isMorningStar && mfiValue < MfiLow && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (isEveningStar && mfiValue > MfiHigh && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevPrevCandle = _prevCandle;
_prevCandle = candle;
}
}
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 MoneyFlowIndex
from StockSharp.Algo.Strategies import Strategy
class morning_evening_mfi_strategy(Strategy):
def __init__(self):
super(morning_evening_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", 40.0)
self._mfi_high = self.Param("MfiHigh", 60.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._prev_candle = None
self._prev_prev_candle = None
self._candles_since_trade = 6
@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(morning_evening_mfi_strategy, self).OnReseted()
self._prev_candle = None
self._prev_prev_candle = None
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(morning_evening_mfi_strategy, self).OnStarted2(time)
self._prev_candle = None
self._prev_prev_candle = None
self._candles_since_trade = self.SignalCooldownCandles
mfi = MoneyFlowIndex()
mfi.Length = self.MfiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(mfi, 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)
if self._prev_candle is not None and self._prev_prev_candle is not None:
prev_body = abs(float(self._prev_candle.ClosePrice) - float(self._prev_candle.OpenPrice))
prev_range = float(self._prev_candle.HighPrice) - float(self._prev_candle.LowPrice)
is_small_body = prev_range > 0 and prev_body < prev_range * 0.3
first_midpoint = (float(self._prev_prev_candle.OpenPrice) + float(self._prev_prev_candle.ClosePrice)) / 2.0
first_bearish = float(self._prev_prev_candle.OpenPrice) > float(self._prev_prev_candle.ClosePrice)
curr_bullish = float(candle.ClosePrice) > float(candle.OpenPrice)
is_morning_star = first_bearish and is_small_body and curr_bullish and float(candle.ClosePrice) > first_midpoint
first_bullish = float(self._prev_prev_candle.ClosePrice) > float(self._prev_prev_candle.OpenPrice)
curr_bearish = float(candle.OpenPrice) > float(candle.ClosePrice)
is_evening_star = first_bullish and is_small_body and curr_bearish and float(candle.ClosePrice) < first_midpoint
if is_morning_star 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_evening_star and mfi_val > self.MfiHigh and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
self._prev_prev_candle = self._prev_candle
self._prev_candle = candle
def CreateClone(self):
return morning_evening_mfi_strategy()