GitHub で見る
Tunnel Method 戦略
Tunnel Method戦略は、MetaTrader 5向けに元々公開された「Tunnel Method」エキスパートアドバイザーのStockSharpポートです。3つのシフトされた単純移動平均(SMA)を使用して方向性のブレイクアウトを検出します。高速平均は設定可能なインデントを持つ遅い平均と中間平均によって作られた価格「トンネル」を貫通して取引を確認する必要があります。戦略は、固定pip基準のストップロスとテイクプロフィットレベル、ステップフィルターで利益をロックするトレーリングストップ、エントリー評価間の最小待機時間を含む、MQLバージョンと同一のポジション管理ルールを含みます。
戦略ロジック
- インジケーター: 同じインストゥルメントと時間軸の3つの単純移動平均。
- 第1 SMA(遅い線): ゼロシフトの長い期間。強気トンネルの下限と弱気トンネルの上限を定義します。
- 第2 SMA(中間線): 正のシフトの中程度の期間。主にショートシグナルに使用され、前向きに投影されたバリアを作ります。
- 第3 SMA(速い線): 最大の正のシフトを持つ短い期間。この線がトンネルを突き抜けることで注文がトリガーされます。
- インデント: 不安定な条件を避けるために、移動平均は少なくとも
IndentPips(価格単位に変換)分離している必要があります。速い平均は遅い平均プラスインデントの半分を下から上に交差してロングを開く必要があり、中間平均マイナスインデントの半分を上から下に交差してショートを開く必要があります。
- エントリーリズム: 新しいシグナルは前の評価から
PauseSecondsが経過した場合にのみ評価されます。これはノイズを減らすためにOnTick処理をスロットルする元のEAを反映しています。
- シングルポジションモード: 戦略は一度に1つのポジションのみを保持します。別のポジションがすでにオープンしている場合、新しい注文は無視されます。
リスク管理
- ストップロス:
StopLossPipsを通じてエントリー価格の下(ロングの場合)または上(ショートの場合)のオプションの固定距離(pips単位)。
- テイクプロフィット:
TakeProfitPipsを通じたオプションの固定目標(pips)。
- トレーリングストップ:
TrailingStopPipsとTrailingStepPipsの両方が正の場合に有効。価格がTrailingStopPips + TrailingStepPips分トレードに有利に動くと、ストップは現在の終値からTrailingStopPips後ろに引かれます。トレーリングストップは価格が少なくともトレーリングステップ分進んだ場合にのみ更新され、過度に頻繁な調整を防ぎます。
- ポジション終了: 戦略はストップ、テイクプロフィット、またはトレーリングレベルが違反された時にポジションを市場でクローズします。これはブローカーが保護注文を実行した後に元のEAがどのように反応するかを複製します。
パラメーター
| パラメーター |
デフォルト |
説明 |
TradeVolume |
1 |
取引ごとの注文ボリューム。 |
StopLossPips |
50 |
pipsでのストップロス距離。無効にするには0を使用。 |
TakeProfitPips |
50 |
pipsでのテイクプロフィット距離。無効にするには0を使用。 |
TrailingStopPips |
5 |
pipsでのベーストレーリング距離。TrailingStepPips > 0が必要。 |
TrailingStepPips |
5 |
トレーリングストップが動く前の最小インクリメンタル利益。 |
FirstMaPeriod |
160 |
遅いSMAの期間。 |
FirstMaShift |
0 |
遅いSMAの前向きシフト。 |
SecondMaPeriod |
80 |
ショートシグナルに使用する中間SMAの期間。 |
SecondMaShift |
1 |
中間SMAの前向きシフト。 |
ThirdMaPeriod |
20 |
速いSMAの期間。 |
ThirdMaShift |
2 |
速いSMAの前向きシフト。 |
IndentPips |
1 |
ブレイクアウトを確認するための平均間の最小ギャップ。 |
PauseSeconds |
45 |
連続するエントリーチェック間の遅延。 |
CandleType |
5分時間軸 |
インジケーター計算に使用するローソク足シリーズ。 |
すべてのpipベースのパラメーターは、MetaTraderバージョンと同様に3桁および5桁のFXシンボルの特別な処理を行い、インストゥルメントのPriceStepと小数精度を使用して自動的に価格単位に変換されます。
実践的なノート
- インストゥルメント設定: 戦略に割り当てられた
Securityが正しいPriceStepとDecimalsを持っていることを確認してください。そうでなければ、変換されたpip距離が不正確になります。
- 時間軸の整合: デフォルトの
CandleTypeは5分ローソク足を使用しますが、パラメーターを変更することでMetaTraderで使用された時間軸(例えばM1)と整合させることができます。
- ボリューム処理:
TradeVolumeはエントリーあたりの合計サイズを定義します。戦略は対称的なマーケット注文でポジションをクローズするので、ポジションサイズは一貫して保たれます。
- トレーリング要件: コンストラクターは元のEAのルールを強制します—
TrailingStopPipsが正の場合にTrailingStepPipsがゼロの場合、戦略は不整合な設定を防ぐために初期化エラーをスローします。
- 最適化: パラメーター設計はStockSharpの規則に従います。各パラメーターはDesignerでUIコントロールに最適化またはバインドできるため、期間、インデント、またはトレーリング値の調整が容易です。
ファイル
CS/TunnelMethodStrategy.cs – コア戦略実装。
README.md – 英語のドキュメント(このファイル)。
README_ru.md – ロシア語のドキュメント。
README_zh.md – 中国語のドキュメント。
Pythonの翻訳は意図的に省略されており、この段階でC#バージョンのみを提供するという要求に一致しています。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class TunnelMethodStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevHigh, _prevLow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public TunnelMethodStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 18).SetGreaterThanZero().SetDisplay("Channel Period", "Lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = null;
_prevLow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = null; _prevLow = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevHigh = high; _prevLow = low; return; }
if (_prevHigh == null || _prevLow == null) { _prevHigh = high; _prevLow = low; return; }
var close = candle.ClosePrice;
if (close > _prevHigh.Value && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (close < _prevLow.Value && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevHigh = high; _prevLow = low;
}
}
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 tunnel_method_strategy(Strategy):
def __init__(self):
super(tunnel_method_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 18) \
.SetDisplay("Channel Period", "Lookback", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(tunnel_method_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(tunnel_method_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if self._prev_high is None or self._prev_low is None:
self._prev_high = hv
self._prev_low = lv
return
close = float(candle.ClosePrice)
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return tunnel_method_strategy()