GitHub で見る

ABE BE CCI 巻き込み戦略

この StockSharp 戦略は、MetaTrader 5 エキスパート アドバイザ Expert_ABE_BE_CCI (フォルダ MQL/306) を移植します。オリジナルの EA は、強気/弱気巻き込みローソク足パターンと商品チャネル指数 (CCI) 確認モジュールおよび固定ロットの資金管理を組み合わせています。 C# 実装では、同じ意思決定ロジックを維持しながら、StockSharp が提供する高レベルのサブスクリプションとインジケーター バインディングを活用します。

エンジンは、選択した時間枠で完了したローソク足を監視し、ローソク体の移動平均、終値の平均、および構成可能な期間の CCI を計算します。強気または弱気の巻き込みパターンは、ローソク足の実体が最近の平均を上回り、巻き込まれたローソク足の中点が移動平均の正しい側にある場合にのみ受け入れられ、MQL CCandlePattern チェックを模倣します。ロングトレードには強気の巻き込みに加えて売られ過ぎの閾値を下回るCCIが必要ですが、ショートトレードには買われ過ぎの閾値を上回るCCIのミラー条件が必要です。ポジションの出口は、EA の「投票」ロジックを反映しています。CCI の ±ExitLevel のクロスは、方向に関係なくオープン ポジションを無効にします。

ワークフロー

  1. 構成されたローソク足タイプをサブスクライブし、次のように計算します。
    • BodyAveragePeriod バーにわたるローソク足の実体平均。
    • 同じウィンドウにおける終値の移動平均。
    • 長さ CciPeriod の商品チャネル インデックス。
  2. 完成したキャンドルごとに:
    • 前のローソク足が反対色の飲み込まれたバーを形成していることを確認します。
    • 巻き込み体が回転体の平均よりも大きく、前の開いた状態を超えて閉じて、MQL フィルターを複製していることを確認します。
    • 前回のローソク足の中間点と終値の移動平均を比較して、トレンドの状況を確認します。
    • CCI 対 EntryOversoldLevel または EntryOverboughtLevel で勢いを確認します。
  3. 取引を管理する:
    • 強気の条件が整い、アクティブなロングポジションがない場合は、ショートを閉じて、設定されたボリュームを購入します。
    • 弱気の条件が一致し、アクティブなショートがない場合は、ロングを閉じて、設定された数量を売ります。
    • CCI の出口を監視します。+ExitLevel を下回るか、-ExitLevel を横切るクロスはロングを閉じますが、-ExitLevel を上回るか、+ExitLevel を下回るクロスはショートを閉じます。これは、EA の 40 ポイントの「投票」ロジックと一致します。

デフォルトパラメータ

名前 デフォルト 説明
CciPeriod 49 商品チャネル指数インジケーターの長さ。
BodyAveragePeriod 11 ローソク足の本体サイズと終値平均を平均するためのウィンドウ。
EntryOversoldLevel -50 CCI のしきい値は強気の巻き込みセットアップを確認します。
EntryOverboughtLevel 50 CCI のしきい値は弱気の飲み込みセットアップを確認します。
ExitLevel 80 絶対的な CCI レベルを超えるとポジション終了がトリガーされます。
CandleType 1時間 キャンドルのサブスクリプションに使用される時間枠。

注意事項

  • ボリューム処理は典型的な StockSharp コンバージョンを反映しています。Volume は基本注文サイズを定義します。反対のポジションは反転する前にフラットになります。
  • MQL パッケージのトレーリングおよび資金管理コンポーネント (TrailingNoneMoneyFixedLot) は再作成されません。 StockSharp の注文サイジングは、固定ロットの動作をすでにカバーしています。
  • コード内のコメントはすべて英語であり、インデントにはタブが使用され、リポジトリのガイドラインに従って、GetValue を介してインジケーター値は取得されません。
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>
/// ABE BE CCI strategy: Engulfing pattern with CCI confirmation.
/// Bullish engulfing + negative CCI for long, bearish engulfing + positive CCI for short.
/// </summary>
public class AbeBeCciStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<decimal> _entryLevel;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private readonly List<ICandleMessage> _candles = new();
	private decimal _prevCci;
	private bool _hasPrevCci;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
	public decimal EntryLevel { get => _entryLevel.Value; set => _entryLevel.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public AbeBeCciStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_cciPeriod = Param(nameof(CciPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Period", "CCI period", "Indicators");
		_entryLevel = Param(nameof(EntryLevel), 100m)
			.SetDisplay("Entry Level", "CCI threshold for 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();
		_prevCci = 0m;
		_hasPrevCci = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

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

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

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

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

			var bullishEngulfing = prev.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice > curr.OpenPrice
				&& curr.OpenPrice <= prev.ClosePrice
				&& curr.ClosePrice >= prev.OpenPrice;

			var bearishEngulfing = prev.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice > curr.ClosePrice
				&& curr.OpenPrice >= prev.ClosePrice
				&& curr.ClosePrice <= prev.OpenPrice;

			if (bullishEngulfing && cciValue < -EntryLevel && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (bearishEngulfing && cciValue > EntryLevel && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		if (_hasPrevCci)
		{
			if (Position > 0 && _prevCci > EntryLevel && cciValue < EntryLevel && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
			else if (Position < 0 && _prevCci < -EntryLevel && cciValue > -EntryLevel && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevCci = cciValue;
		_hasPrevCci = true;
	}
}