GitHub で見る

貿易チャネル

概要

Trade Channel は、MetaTrader「TradeChannel」エキスパート アドバイザーから変換されたチャネル回帰戦略です。このシステムは、設定可能な数の完成したローソク足の最高値と最低値から価格チャネルを描画します。チャネルの拡大が止まり、価格がその境界線の1つを再テストすると、戦略は反対方向にポジションをオープンし、レンジ内への戻りを期待します。

核となるアイデア

  • 最高最低のインジケーターを使用して、Donchian のようなチャネルを形成します。
  • 取引を開始する前に、チャネルがフラットであること(新たな高値や安値がないこと)を要求します。
  • ショートポジションでは抵抗感が薄れ、ロングポジションではサポート感が薄れます。
  • 最初の保護ストップをブレークアウト ポイントから平均トゥルー レンジ (ATR) 1 つ離れたところに配置します。
  • トレードがポジションに有利に動いたら、オプションでストップを追跡します。

パラメーター

名前 説明 デフォルト 最適化
Volume ロット/契約の取引量。 1 有効 (0.1 → 2.0、ステップ 0.1)
ChannelLength チャネル境界の計算に使用される完成したキャンドルの数。 20 有効 (10 → 60、ステップ 5)
AtrPeriod ストップ配置の ATR インジケーターの期間。 4 有効 (2 → 20、ステップ 2)
TrailingPoints 商品価格ステップで測定されるトレーリングストップオフセット。末尾を無効にするには、0 に設定します。 30 有効 (0 → 100、ステップ 10)
CandleType 計算に使用されるローソク足の種類と時間枠。 30分の時間枠

取引ロジック

  1. 設定されたローソク足シリーズをサブスクライブし、3 つのインジケーター HighestLowest、および ATR をフィードします。
  2. すべてのインジケーターが完全に形成されるまで待ちます。最初に完了した値はチャネル状態を初期化し、そのローソク足では取引は行われません。
  3. 新しい完成したキャンドルごとに:
    • チャネル境界を更新し、ピボット (resistance + support + close) / 3 を計算します。
    • 抵抗(またはサポート)が前のローソク足と比較して変化していないかどうかを確認します。フラットな抵抗により短いセットアップが可能になり、フラットなサポートにより長いセットアップが可能になります。
    • ショートエントリー: 抵抗が横ばいで かつ ローソク足が抵抗の高値に触れる、またはピボットと抵抗の間で閉じる場合、成行売り注文を送信します。
    • ロングエントリー: サポートがフラットで かつ ローソク足がサポートに安値で接触するか、サポートとピボットの間で閉じる場合、成行買い注文を送信します。
    • 一度に許可されるポジションは 1 つだけです。この戦略は、取引が行われていない間、フラットチャネルシグナルを待ちます。
  4. 入場時:
    • エントリー価格を保存します。
    • 最初のストップをショートの場合は resistance + ATR、ロングの場合は support − ATR に設定します。
  5. オープンポジションを管理:
    • ロングの終了条件:
      • 価格は横ばいのまま、チャネルの上部境界線に接触します。
      • ローソク足はトレーリング/イニシャルストップレベルを下回ります。
    • ショートの終了条件:
      • 価格は横ばいのまま、チャネルの下限境界に接触します。
      • ローソク足の高値はトレーリング/イニシャルストップレベルを上回ります。
  6. トレーリングストップ (TrailingPoints > 0 の場合):
    • 商品の Security.Step を使用して、入力を価格単位に変換します (ステップが使用できない場合は生の値に戻ります)。
    • ロングの場合、終値がトレーリングオフセット分エントリー価格を超えたら、ストップを close − offset に移動します。
    • ショートの場合、終値がエントリー価格をオフセット分下回ったら、ストップを close + offset に移動します。
    • トレーリングストップは決して後退しません。保護レベルが強化されるだけです。

注意事項

  • すべての決定は、High[1]Low[1]、および Close[1] を使用した元の MQL ロジックとの整合性を維持するために、完成したキャンドルに対して行われます。
  • 現在のチャネル境界と前のチャネル境界の間の等価性チェックは、浮動小数点のグリッチを回避するために、商品の価格ステップを許容します。
  • トレーリングストップは正しい Security.Step メタデータに依存します。取引所がそれを提供しない場合は、代わりに生のポイント値が使用されます。
  • これらの機能は MQL 実装ではプラットフォーム固有であったため、この戦略では電子メールを送信したり、ポジション サイズを動的に調整したりすることはありません。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trade Channel Breakout strategy - Highest/Lowest channel breakout.
/// Buys when close crosses above channel midpoint.
/// Sells when close crosses below channel midpoint.
/// </summary>
public class TradeChannelBreakoutStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevMid;
	private bool _hasPrev;

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

	public TradeChannelBreakoutStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 20)
			.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevMid = 0m; _hasPrev = false; }

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;

		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(highest, lowest, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;
		var mid = (highest + lowest) / 2;

		if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }

		if (_prevClose <= _prevMid && close > mid && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (_prevClose >= _prevMid && close < mid && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevClose = close; _prevMid = mid;
	}
}