GitHub で見る

iCHO トレンド CCIDualOnMA フィルター戦略

この戦略は、MetaTrader エキスパート アドバイザ 「iCHO Trend CCIDualOnMA Filter」 の上位レベルの StockSharp 移植です。これは、チャイキン オシレーターのゼロライン レジーム フィルターと、平滑化された価格系列に基づいて計算されるデュアル コモディティ チャネル インデックス (CCI) 確認を組み合わせています。その結果、モメンタムの変化に反応するトレンド追跡アプローチが得られますが、それでも取引に入る前に CCI ペアからのモメンタムの確認が必要です。

取引ロジック

  1. チャイキン オシレーター コア – 累積/分配ラインは、構成可能な 2 つの移動平均によって平滑化されます。それらの違いはチャイキン発振器を再現します。ゼロを上回る/下のクロスは、支配的な資本フローの変化を示します。
  2. デュアル CCI フィルター – 両方の CCI インスタンスは同じ移動平均平滑化価格入力を使用しますが、異なるルックバック期間を使用します。長いセットアップでは、チャイキン オシレーターがゼロ以上に留まる間に、高速の CCI がマイナス領域から回復し、低速の CCI を超える必要があります。短いセットアップはこれらの条件を反映します。
  3. オプションのリバーサル – オリジナルの EA は、ロング信号とショート信号を交換する「リバース」フラグを提供します。ポートではこの動作が維持されるため、同じルールを逆トレンド テストに使用できます。
  4. ポジション管理 – オプションのフラグは、新しいポジションをオープンする前に反対側のエクスポージャーをクローズし、戦略を 1 つのオープン ポジションに制限します。 MetaTrader の実装を模倣するために、バーごとに 1 つの取引ルールが適用されます。
  5. セッションフィルター – 取引は、真夜中を過ぎるラップアラウンドセッションを含む、ユーザー定義の日中ウィンドウに制限できます。

パラメーター

パラメータ 説明
FastChaikinLength Chaikin オシレーター内で使用される高速移動平均期間。
SlowChaikinLength チャイキン オシレーター内で使用される低速移動平均期間。
ChaikinMethod 移動平均法(単純、指数関数、平滑化、線形重み付け)を累積/分配線に適用します。
FastCciLength 高速コモディティ・チャネル指数の振り返り。
SlowCciLength 低調な商品チャネル指数の振り返り。
MaLength CCI をフィードする前処理移動平均の長さ。
MaMethod CCI に到達する前に価格を前処理するために使用される移動平均法。
MaPrice CCI の前に平滑化される価格タイプ (終値、始値、高値、安値、中央値、標準、加重)。
UseClosedBar 完全に完成したキャンドルのみを処理します(デフォルトは true、EA の SignalsBarCurrent=bar_1 と同じ)。
ReverseSignals ロングロジックとショートロジックを交換します。
CloseOpposite 新しいポジションに入る前に、オープンポジションを反対方向に閉じてください。
OnlyOnePosition 常に 1 つのオープンポジションのみを許可します。
TradeMode 約定をロング、ショート、またはその両方に制限します (BuyOnly、SellOnly、BuyAndSell)。
UseTimeFilter 取引セッションフィルターを有効にします。
StartHour, StartMinute, EndHour, EndMinute 交換時間で表されるセッション境界 (開始を含み、終了は除く)。ラップアラウンドセッションがサポートされています。
CandleType インジケーターをフィードするローソク足サブスクリプションの時間枠。

注意事項

  • この戦略では、高レベルの SubscribeCandles バインディングと組み込みインジケーターのみが使用されます。カスタム バッファーや履歴リクエストは必要ありません。
  • すべての価格ベースの計算では、平滑化された価格系列を CCI に供給することにより、MetaTrader CCIDualOnMA インジケーターと同じ移動平均前処理が採用されます。
  • デフォルトのパラメータは、元の EA のデフォルトを再現します。Chaikin 3/10 EMA、CCI 期間 14 と 50、12 期間の SMA 前処理、および 10:01 から 15:02 までの取引ウィンドウです。
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Combines a Chaikin oscillator zero-line filter with CCI confirmation.
/// Buys when Chaikin crosses above zero and CCI is rising, sells on opposite.
/// </summary>
public class iCHO_Trend_CCIDualOnMA_FilterStrategy : Strategy
{
	private readonly StrategyParam<int> _cciLength;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _cciLevel;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal? _prevCci;
	private decimal? _prevPrevCci;
	private int _candlesSinceTrade;

	public int CciLength
	{
		get => _cciLength.Value;
		set => _cciLength.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public decimal CciLevel
	{
		get => _cciLevel.Value;
		set => _cciLevel.Value = value;
	}

	public int SignalCooldownCandles
	{
		get => _signalCooldownCandles.Value;
		set => _signalCooldownCandles.Value = value;
	}

	public iCHO_Trend_CCIDualOnMA_FilterStrategy()
	{
		_cciLength = Param(nameof(CciLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Length", "CCI period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Primary candle series", "Data");

		_cciLevel = Param(nameof(CciLevel), 100m)
			.SetDisplay("CCI Level", "CCI threshold for entry", "Indicators");

		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between entries", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCci = null;
		_prevPrevCci = null;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevCci = null;
		_prevPrevCci = null;
		_candlesSinceTrade = SignalCooldownCandles;

		var cci = new CommodityChannelIndex { Length = CciLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(cci, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, cci);
			DrawOwnTrades(area);
		}
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_prevCci.HasValue && _prevPrevCci.HasValue)
		{
			if (_prevPrevCci.Value < -CciLevel && _prevCci.Value < -CciLevel && cciValue > -CciLevel && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (_prevPrevCci.Value > CciLevel && _prevCci.Value > CciLevel && cciValue < CciLevel && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevPrevCci = _prevCci;
		_prevCci = cciValue;
	}
}