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分の時間枠 |
— |
取引ロジック
- 設定されたローソク足シリーズをサブスクライブし、3 つのインジケーター
Highest、Lowest、および ATR をフィードします。
- すべてのインジケーターが完全に形成されるまで待ちます。最初に完了した値はチャネル状態を初期化し、そのローソク足では取引は行われません。
- 新しい完成したキャンドルごとに:
- チャネル境界を更新し、ピボット
(resistance + support + close) / 3 を計算します。
- 抵抗(またはサポート)が前のローソク足と比較して変化していないかどうかを確認します。フラットな抵抗により短いセットアップが可能になり、フラットなサポートにより長いセットアップが可能になります。
- ショートエントリー: 抵抗が横ばいで かつ ローソク足が抵抗の高値に触れる、またはピボットと抵抗の間で閉じる場合、成行売り注文を送信します。
- ロングエントリー: サポートがフラットで かつ ローソク足がサポートに安値で接触するか、サポートとピボットの間で閉じる場合、成行買い注文を送信します。
- 一度に許可されるポジションは 1 つだけです。この戦略は、取引が行われていない間、フラットチャネルシグナルを待ちます。
- 入場時:
- エントリー価格を保存します。
- 最初のストップをショートの場合は
resistance + ATR、ロングの場合は support − ATR に設定します。
- オープンポジションを管理:
- ロングの終了条件:
- 価格は横ばいのまま、チャネルの上部境界線に接触します。
- ローソク足はトレーリング/イニシャルストップレベルを下回ります。
- ショートの終了条件:
- 価格は横ばいのまま、チャネルの下限境界に接触します。
- ローソク足の高値はトレーリング/イニシャルストップレベルを上回ります。
- トレーリングストップ (
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class trade_channel_breakout_strategy(Strategy):
def __init__(self):
super(trade_channel_breakout_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 20).SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0; self._prev_mid = 0.0; self._has_prev = False
@property
def channel_period(self): return self._channel_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(trade_channel_breakout_strategy, self).OnReseted()
self._prev_close = 0.0; self._prev_mid = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(trade_channel_breakout_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest(); highest.Length = self.channel_period
lowest = Lowest(); lowest.Length = self.channel_period
sub = self.SubscribeCandles(self.candle_type)
sub.Bind(highest, lowest, self.process_candle).Start()
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished: return
close = float(candle.ClosePrice); mid = (float(highest) + float(lowest)) / 2.0
if not self._has_prev: self._prev_close = close; self._prev_mid = mid; self._has_prev = True; return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_close = close; self._prev_mid = mid
def CreateClone(self): return trade_channel_breakout_strategy()