GitHub で見る

USD/CHF CCI チャネルストップ戦略

概要

USD/CHF CCI チャネル ストップ戦略 は、MetaTrader 4 エキスパート アドバイザー UsdChf_new の StockSharp の高レベル実装です。この戦略は、H4 タイムフレームでのコモディティ チャネル インデックス (CCI) のブレイクアウトをリッスンし、現在の価格を上回るか下回る保留中のストップ注文を展開します。注文が約定されると、ポジションは元のロボットで使用されていたのと同じピップベースの資金管理ルールによって保護されます。つまり、固定ストップロス、失効した未決注文のオプションのキャンセル、損益分岐点の再配置、およびトレーリングストップ管理です。

この変換では、元の実行フローが維持されますが、慣用的な StockSharp ワークフロー: キャンドル サブスクリプション、インジケーター バインディング、高レベルの注文ヘルパー (BuyStopSellStopBuyMarketSellMarket) が組み込まれています。外国為替ユーザーにとって馴染みのあるものとなるよう、すべてのリスクディスタンスは依然としてピップ単位で設定されています。

取引ロジック

  1. インジケーターと信号
    • 完成した H4 ローソク足で構成された期間を使用して CCI を計算します。
    • チャネル境界を監視します: +CCI Channel-CCI Channel
    • 以前の値に対する現在の値のクロスオーバーを検出して信号を生成します。
      • -CCI Channel上方にクロスすると、価格を上回る買いストップが準備されます。
      • +CCI Channel下方にクロスすると、価格よりも低い売りストップが準備されます。
  2. 保留中の注文
    • 逆指値注文はローソク足付近から Entry Indent (pips) だけオフセットされ、商品ステップに丸められます。
    • 一度にアクティブにできる未決注文は 1 つだけです。新規作成すると反対側がキャンセルされます。
    • 市場が Cancel Distance (pips) を超えて離れると、価格の追跡を避けるために未決注文がキャンセルされます。
  3. ポジション管理
    • 埋められたポジションは、元のストップロス距離を継承します。
    • 取引で少なくとも Break Even (pips) の利益が得られると、保護ストップはエントリー価格に移動します。
    • 利益が Trailing Stop (pips) を超えると、設定されたギャップを維持しながらストップが価格を追跡します。
    • 反対側の CCI クロスオーバーはポジションを強制的に終了し、新しい方向に新しい逆指値注文を出します。

パラメーター

パラメータ 説明 デフォルト 最適化可能
CandleType CCI の計算に使用されるローソク足シリーズ (デフォルトは H4)。 4時間枠 いいえ
CciPeriod CCI の平均期間。 73 はい
CciChannel チャネル境界を形成する絶対 CCI レベル。 120 はい
EntryIndentPips 市場価格と保留中の逆指値注文の間の距離 (ピップ単位)。 30 はい
StopLossPips 初期ストップロス距離 (pips)。 95 はい
CancelDistancePips 未決注文をキャンセルするまでの最大ギャップ。 30 はい
TrailingStopPips 作動後のトレーリングストップ距離。 110 はい
BreakEvenPips ストップがエントリーレベルに移動される前に必要な利益。 60 はい

すべてのピップ距離は、商品 PriceStep および Decimals を使用して価格オフセットに変換されます。 3/5 桁の外国為替シンボルの場合、pip は 10 価格ステップに等しく、それ以外の場合は 1 ステップに等しくなります。

使用上の注意

  1. 戦略を USD/CHF 証券 (またはピップベースのリスク管理が関連する金融商品) に添付します。
  2. 基本の Strategy.Volume プロパティを通じて希望の取引量を設定します。
  3. 必要に応じて、ブローカーのコントラクト仕様に一致するように pip ベースのパラメーターを調整します。
  4. Designer/Tester でバックテストを実行して、本番稼働前に動作を検証します。

変換メモ

  • MetaTrader の専門家は、生の注文プールを繰り返し調べました。 StockSharp では、ストラテジーはアクティブな未決注文への参照を保存し、代わりに高レベルのキャンセル ヘルパーを使用します。
  • ブローカー側の注文の変更は高レベルの API の一部ではないため、ストップロス、ブレークイーブン、トレーリングは明示的な市場出口を通じて実装されます。
  • すべてのインライン コメントは英語に翻訳され、わかりやすくするために拡張されました。
using System;

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

namespace StockSharp.Samples.Strategies;

public class UsdChfNewStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public UsdChfNewStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevFast = fast;
		_prevSlow = slow;
	}
}