GitHub で見る
Twenty200 タイムブレイクアウト
この戦略は、MetaTrader エキスパート アドバイザー 20/200 エキスパート v4.2 (AntS) の StockSharp 移植です。取引日の特定の時間を待機し、過去の 2 つの時間ごとの始値 (デフォルト設定では 6 バーと 2 バー) を比較します。遠い始値が近い始値よりも Short Delta ピップ以上高い場合、戦略は売りになりますが、逆ギャップが Long Delta ピップを超えるとロングポジションがオープンします。
取引ロジック
- この戦略は時間足ローソク足をサブスクライブします (
Candle Type を通じて設定可能)。
- 1日に許可される取引は1回のみです。注文は、時間が
Trade Hour に等しいローソク足がアクティブになったときに発注されます。
- シグナルは、現在のローソク足から遡った始値の
LookbackFar バーと LookbackNear バーを使用します。
- 簡単なセットアップ:
Open[t1] - Open[t2] > Short Delta × pip。
- 長いセットアップ:
Open[t2] - Open[t1] > Long Delta × pip。
- 計算された数量で成行注文が送信されます。ストップロスとテイクプロフィットの距離は、MetaTrader バージョンから取得され、ピップで表され、
Security.PriceStep を介して価格に自動的に変換されます。
- 一度に存在できるポジションは 1 つだけです。毎日の取引は次の暦日に再開されます。
ポジション管理
- ストップロスとテイクプロフィットは、ローソク足の高値/安値の極値を使用して、ローソク足の更新ごとに評価されます。
Max Open Hours は、ポジションの有効期間が設定された時間数 (デフォルトでは 504 時間) を超えると強制的に市場から撤退します。セーフティタイマーを無効にするには、パラメータをゼロに設定します。
お金の管理
Fixed Volume は、Use Auto Lot が無効になっている場合、または残高情報が利用できない場合に使用されるフォールバック コントラクト サイズを定義します。
Use Auto Lot が有効な場合、ロットサイズはエキスパートアドバイザーからの巨大なステップテーブルに従います。 StockSharp では、テーブルはデフォルトの係数 0.000038 を使用して volume = round(balance × Auto Lot Factor, 2) によって近似され、文書化された範囲 (300 USD ~ 270,000 USD+) の出来高 1 ピップ以内の MT4 値を再現します。
- 現在のポートフォリオの値が最後に記録された残高を下回ると、次の取引に
Big Lot Multiplier が乗算され、元のコードの「Big Lot」リカバリ取引を模倣します。
- ボリュームは
Security.VolumeStep に調整され、利用可能な場合は MinVolume/MaxVolume の間にクランプされます。
- MT4 スクリプトには、1,000 を超える手動しきい値行が保存されていました。 StockSharp バージョンでは、同じ階段に適合する線形係数 (
Auto Lot Factor) が使用されます。別のブローカーの正確なレプリカが必要な場合は、係数を調整します。
- ストップロス/テイクプロフィット注文は、ローソク足の極値での市場出口を通じてシミュレートされます。これにより、取引所側の逆指値注文のサポートに依存することなく、バックテストとライブ取引全体で動作の一貫性が維持されます。
- グローバル変数 (
globalBalans、globalPosic) はメモリ内の状態に置き換えられます。ファイル システムや端末状態は必要ありません。
パラメーター
| パラメータ |
説明 |
| ロング/ショートテイクプロフィット |
利益目標までの距離 (pips)。 |
| ロング/ショートストップロス |
ストップロスのピップ単位の距離。 |
| 取引時間 |
シグナルがトリガーされるセッションの時間 (0 ~ 23)。 |
| 遠近のルックバック |
2 つの始値を検査するために戻るバーの数。 |
| ロング/ショート デルタ |
ポジションをオープンするために必要なピップギャップ。 |
| 最大営業時間 |
位置の最大存続期間 (時間単位) (0 はガードを無効にします)。 |
| 固定ボリューム |
自動サイジングが無効になっている場合のベースライン契約ボリューム。 |
| 自動ロットを使用する |
勘定科目値からのロットサイジングを有効にします。 |
| 自動ロット係数 |
MT4 ステップ テーブルをエミュレートするためにポートフォリオ値に適用される乗数。 |
| ビッグロットマルチプライヤー |
株価下落後に適用される出来高乗数。 |
| キャンドルの種類 |
シグナルキャンドルに使用される時間枠。 |
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Twenty200TimeBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _shortPeriod;
private readonly StrategyParam<int> _longPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevShort;
private decimal _prevLong;
private bool _hasPrev;
private int _cooldownRemaining;
public int ShortPeriod { get => _shortPeriod.Value; set => _shortPeriod.Value = value; }
public int LongPeriod { get => _longPeriod.Value; set => _longPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Twenty200TimeBreakoutStrategy()
{
_shortPeriod = Param(nameof(ShortPeriod), 20).SetDisplay("Short SMA", "Short SMA period", "Indicators");
_longPeriod = Param(nameof(LongPeriod), 200).SetDisplay("Long SMA", "Long SMA 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();
_prevShort = default;
_prevLong = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevShort = 0;
_prevLong = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var shortSma = new SimpleMovingAverage { Length = ShortPeriod };
var longSma = new SimpleMovingAverage { Length = LongPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(shortSma, longSma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal shortSma, decimal longSma)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev) { _prevShort = shortSma; _prevLong = longSma; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevShort = shortSma;
_prevLong = longSma;
return;
}
if (_prevShort <= _prevLong && shortSma > longSma && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevShort >= _prevLong && shortSma < longSma && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevShort = shortSma;
_prevLong = longSma;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class twenty_200_time_breakout_strategy(Strategy):
def __init__(self):
super(twenty_200_time_breakout_strategy, self).__init__()
self._short_period = self.Param("ShortPeriod", 20) \
.SetDisplay("Short SMA", "Short SMA period", "Indicators")
self._long_period = self.Param("LongPeriod", 200) \
.SetDisplay("Long SMA", "Long SMA period", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 100) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_short = 0.0
self._prev_long = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def short_period(self):
return self._short_period.Value
@property
def long_period(self):
return self._long_period.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(twenty_200_time_breakout_strategy, self).OnReseted()
self._prev_short = 0.0
self._prev_long = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(twenty_200_time_breakout_strategy, self).OnStarted2(time)
self._prev_short = 0.0
self._prev_long = 0.0
self._has_prev = False
self._cooldown_remaining = 0
short_sma = SimpleMovingAverage()
short_sma.Length = self.short_period
long_sma = SimpleMovingAverage()
long_sma.Length = self.long_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(short_sma, long_sma, self.process_candle).Start()
def process_candle(self, candle, short_sma, long_sma):
if candle.State != CandleStates.Finished:
return
short_val = float(short_sma)
long_val = float(long_sma)
if not self._has_prev:
self._prev_short = short_val
self._prev_long = long_val
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_short = short_val
self._prev_long = long_val
return
if self._prev_short <= self._prev_long and short_val > long_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif self._prev_short >= self._prev_long and short_val < long_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_short = short_val
self._prev_long = long_val
def CreateClone(self):
return twenty_200_time_breakout_strategy()