GitHub で見る

CDC PL MFI 戦略

概要

CDC PL MFI 戦略 は、StockSharp の MetaTrader エキスパート アドバイザー Expert_ADC_PL_MFI (MQL/299) を再現します。 暗雲覆ピアシング ラインの 2 本のローソク足反転パターンを検索し、マネー フロー インデックス (MFI) オシレーターを使用して各シグナルを検証します。この戦略は、元のエキスパートと同じ指標期間とレベルしきい値を使用し、ピップ単位でオプションのストップロスとテイクプロフィット保護を追加し、MFI が設定可能な反転レベルを超えたときにポジションをクローズします。

取引ロジック

  1. 構成されたローソク足タイプ (デフォルトでは 1 時間足ローソク足) をサブスクライブし、指定された期間でマネー フロー インデックスを計算します。ローソク足の本体サイズと終値の単純な移動平均を維持して、元のトレンドとボラティリティのフィルターを再現します。
  2. 強気の ピアシング ライン パターンが形成された場合 (前回の安値を下回るギャップ、前の弱気のローソク足の中間点を超える強気の終値、両方のローソク足が平均実体より大きい、および前の終値がトレンド平均を下回る) かつ 現在の MFI 値が LongEntryLevel (デフォルトは 40) を下回っている場合、ロング ポジションにエントリーするか反転します。
  3. 弱気の Dark Cloud Cover パターンが形成された場合 (前の高値を上回るギャップ、前の強気のローソク足の中点を下回る弱気の終値、両方のローソク足が平均実体より大きい、および前の終値がトレンド平均を上回る) かつ 現在の MFI 値が ShortEntryLevel (デフォルトは 60) を上回っている場合、ショート ポジションにエントリーするか反転します。
  4. MFI を監視してポジションを積極的にクローズします。
    • MFI が ExitLowerLevel (30) または ExitUpperLevel (70) を上回ったときにショート ポジションを閉じます。
    • MFI が ExitUpperLevel (70) または ExitLowerLevel (30) を下回ったときにロング ポジションを閉じます。
  5. 保護命令は任意です。 TakeProfitPips または StopLossPips がゼロより大きい場合、ストラテジーは対応する価格オフセット (ピップ距離に証券価格ステップを乗算) を指定して StartProtection を呼び出します。

パラメーター

パラメータ 説明 デフォルト
CandleType パターン検出に使用されるキャンドルのデータ型。 1 hour 時間枠
MfiPeriod マネーフローインデックスオシレーターの長さ。 49
BodyAveragePeriod 「長い」ローソク足を認定するために使用されるローソク体移動平均の期間。 11
LongEntryLevel 強気のピアシングライン設定を確認するMFI閾値。 40
ShortEntryLevel 弱気の暗雲カバー設定を確認する MFI しきい値。 60
ExitLowerLevel ショートポジションのカバーをトリガーする低いMFIレベル。 30
ExitUpperLevel ロングポジションのクローズをトリガーする上位 MFI レベル。 70
StopLossPips オプションのストップロス距離 (ピップ単位) (0 は保護を無効にします)。 50
TakeProfitPips オプションのテイクプロフィット距離 (ピップ単位) (0 は保護を無効にします)。 50

注意事項

  • ボリュームのデフォルトは 1 ロットです。戦略が方向を転換すると、MQL の動作に一致する、既存のポジションを決済して新しいポジションをオープンするサイズの単一の成行注文が送信されます。
  • パターン検出は MetaTrader ロジックを反映しています。完了したローソク足のみが評価され、前の高値/安値を超えてギャップが発生する必要があり、単純な移動平均によって一般的なトレンド条件が適用されます。
  • マネー フロー インデックスの値は、バインドされたインジケーターから直接取得されます。指標履歴を手動でバッファリングする必要はありません。この戦略では、しきい値超過を検出するために最新の値のみが保存されます。
  • Python ポートは提供されません。このディレクトリには C# 実装のみが含まれます。
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// CDC PL MFI strategy: Dark Cloud Cover and Piercing Line candlestick patterns
/// confirmed by Money Flow Index levels.
/// </summary>
public class CdcPlMfiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _mfiPeriod;
	private readonly StrategyParam<decimal> _longLevel;
	private readonly StrategyParam<decimal> _shortLevel;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private readonly List<ICandleMessage> _candles = new();
	private decimal _prevMfi;
	private bool _hasPrevMfi;
	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 LongLevel { get => _longLevel.Value; set => _longLevel.Value = value; }
	public decimal ShortLevel { get => _shortLevel.Value; set => _shortLevel.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public CdcPlMfiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_mfiPeriod = Param(nameof(MfiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("MFI Period", "Money Flow Index period", "Indicators");
		_longLevel = Param(nameof(LongLevel), 40m)
			.SetDisplay("Long Level", "MFI below this for long entry", "Signals");
		_shortLevel = Param(nameof(ShortLevel), 60m)
			.SetDisplay("Short Level", "MFI above this for short entry", "Signals");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candles.Clear();
		_prevMfi = 0m;
		_hasPrevMfi = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candles.Clear();
		_hasPrevMfi = false;
		_candlesSinceTrade = SignalCooldownCandles;
		var mfi = new MoneyFlowIndex { Length = MfiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(mfi, ProcessCandle).Start();

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		_candles.Add(candle);
		if (_candles.Count > 5)
			_candles.RemoveAt(0);

		if (_candles.Count >= 2 && _hasPrevMfi)
		{
			var curr = _candles[^1];
			var prev = _candles[^2];

			// Piercing Line: prev bearish, curr bullish, opens below prev low, closes above midpoint
			var isPiercing = prev.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice > curr.OpenPrice
				&& curr.OpenPrice < prev.LowPrice
				&& curr.ClosePrice > (prev.OpenPrice + prev.ClosePrice) / 2m;

			// Dark Cloud Cover: prev bullish, curr bearish, opens above prev high, closes below midpoint
			var isDarkCloud = prev.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice > curr.ClosePrice
				&& curr.OpenPrice > prev.HighPrice
				&& curr.ClosePrice < (prev.OpenPrice + prev.ClosePrice) / 2m;

			if (isPiercing && mfiValue < LongLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (isDarkCloud && mfiValue > ShortLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevMfi = mfiValue;
		_hasPrevMfi = true;
	}
}