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 デザイナー/オプティマイザー内で最適化できます。

使用上の注意

  1. 戦略を目的の証券に添付し、元の MQL 専門家からのチャートの時間枠と一致するように CandleType を設定します。
  2. StockSharp プラットフォームを介して、戦略ボリュームやブローカー固有の注文サイズなどのリスク パラメーターを設定します。
  3. 戦略を有効にします。上記のルールに従って、ローソク足を自動的に購読し、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;
	}
}