GitHub で見る
TCP ピボット反転制限戦略
概要
TCP ピボット制限戦略は、古典的な MetaTrader 4 エキスパート gpfTCPivotLimit.mq4 を変換したものです。オリジナルの専門家は毎日のピボットレベルを計算し、時間足のローソク足を使用してこれらのレベルの周りで誤ったブレイクアウトを検索します。ブレイクアウトが失敗すると、戦略はすぐに反対のピボットレベルをターゲットとした反転トレードに入ります。この実装は、StockSharp の高レベル戦略 API を使用して同じロジックを再現します。
この戦略は時間足ローソク足で動作し、常に 1 つのオープン ポジションのみを保持します。新しい取引日ごとに、前日の高値、安値、終値からピボット グリッドが再計算されます。これらのレベルは、エントリートリガー、ストップロス、テイクプロフィット、およびオプションのトレーリング管理をガイドします。
取引ロジック
ピボット計算
- 新しい取引日の最初のローソク足で、この戦略は前日の高値、安値、およびそれに近い値を集計し、古典的なフロア トレーダーのピボット レベル (ピボット、R1 ~ R3、S1 ~ S3) を計算します。
- 新しいレベルが生成されるたびにログ エントリが生成されるため、グリッドがどのように進化するかを追跡できます。
エントリー条件
- 終了した時間ごとのローソク足ごとに、戦略は最後の 2 つの完了したローソク足をチェックします。
- ショート ポジションは、2 期間前のローソク足が抵抗レベルを上回ってスパイク (または抵抗レベル/上でクローズ) しながら下でオープンし、最新のローソク足がそのレベルを下回ってクローズしたときにオープンされます。これはブレイクアウトが失敗したことを示しており、反転下落が期待されます。
- ロング ポジションは、市場がサポート レベルを下回ったものの、次のローソク足がサポート レベルを上回って戻ったときに対称的にオープンされます。
- 一度にアクティブにできるポジションは 1 つだけです。注文量は、
OrderVolume パラメータによって定義されます。
出口管理
- 各エントリは、選択した
TargetMode プリセットによって定義されたストップロスとテイクプロフィットのレベルを使用します。プリセットは、元のエキスパート アドバイザーの TgtProfit オプションを反映し、さまざまなピボット レベルを組み合わせています。
| モード |
ショートエントリー |
ショートストップ |
ショートターゲット |
ロングエントリー |
ロングストップ |
ロングターゲット |
| 1 |
R1 |
R2 |
S1 |
S1 |
S2 |
R1 |
| 2 |
R1 |
R2 |
S2 |
S1 |
S2 |
R2 |
| 3 |
R2 |
R3 |
S1 |
S2 |
S3 |
R1 |
| 4 |
R2 |
R3 |
S2 |
S2 |
S3 |
R2 |
| 5 |
R2 |
R3 |
S3 |
S2 |
S3 |
R3 |
IntradayTrading が有効な場合、一晩保持されることを避けるために、オープン ポジションは 23:00 のローソク終値でクローズされます。
- オプションのポイント単位のトレーリング ストップ (商品価格ステップの倍数) は、MetaTrader の動作をエミュレートします。トレーリングは、設定された距離だけ動きが進んだ後にのみ有効になり、価格が同じ量だけリトレースしたときに取引を終了します。
パラメーター
| パラメータ |
説明 |
OrderVolume |
成行注文の買いと売りの両方に使用されるボリューム。 |
TargetMode |
エントリー、ストップ、ターゲットに使用するレジスタンス/サポートの組み合わせを選択する 1 ~ 5 の整数。 |
TrailingPoints |
トレーリング ストップの距離は価格ポイントで測定されます。末尾を無効にするには、ゼロに設定します。 |
IntradayTrading |
true の場合、ポジションは 23:00 にクローズされ、日中の取引が継続されます。 |
CandleType |
キャンドルのデータ型。デフォルトの時間枠は、元の専門家と一致する 1 時間です。 |
注意事項
- この戦略では、1 時間ごとのローソク足の継続的な流れが予想されます。他の時間枠に適用すると動作が変わるため、バックテストする必要があります。
- ストップロスとテイクプロフィットのレベルはローソク足の極値を使用して評価されるため、レベル間のギャップにより、MetaTrader バージョンと同様に、より悪い価格でエグジットが発生する可能性があります。
- トレーリング管理はローソク足の終値と安値/高値で実行され、元のティックベースのロジックと厳密に一致しながら、StockSharp 環境での効率性を維持します。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class TcpPivotReversalLimitStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi;
private bool _hasPrev;
private int _cooldown;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TcpPivotReversalLimitStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetDisplay("RSI Period", "RSI lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsi;
return;
}
if (_prevRsi <= 30 && rsi > 30 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevRsi >= 70 && rsi < 70 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevRsi = rsi;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class tcp_pivot_reversal_limit_strategy(Strategy):
def __init__(self):
super(tcp_pivot_reversal_limit_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetDisplay("RSI Period", "RSI lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_rsi = 0.0
self._has_prev = False
self._cooldown = 0
@property
def rsi_period(self): return self._rsi_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(tcp_pivot_reversal_limit_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(tcp_pivot_reversal_limit_strategy, self).OnStarted2(time)
self._has_prev = False
self._cooldown = 0
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self.process_candle).Start()
def process_candle(self, candle, rsi):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi)
if not self._has_prev:
self._prev_rsi = rsi_val
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_rsi = rsi_val
return
if self._prev_rsi <= 30 and rsi_val > 30 and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = 2
elif self._prev_rsi >= 70 and rsi_val < 70 and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = 2
self._prev_rsi = rsi_val
def CreateClone(self):
return tcp_pivot_reversal_limit_strategy()