GitHub で見る
VirtPO TestBed スカルプ戦略
この戦略は、VirtPOTestBed_ScalpM1 MetaTrader 4 エキスパート アドバイザーを StockSharp の高レベル API に移植します。これは、Stochastic オシレーターのクロスオーバーによって武装され、価格の勢いが動きを確認したら実行される 仮想指値注文 を作成するという元のアイデアを維持しています。 MQL バージョンのすべてのフィルター、資金管理ルール、スケジュール制御は、StockSharp のインジケーターと注文方法で複製されました。
中核ロジック
- 仮想保留注文 – オープンなポジションがない場合、ストラテジーは完了したすべてのローソク足のフィルター ブロックをチェックします。
- スプレッドは
SpreadMaxPips (レベル 1 から取得した最高の買値/売値) を下回る必要があります。
- 最後の 3 つのバーの平均ティック ボリュームは
VolumeLimit を超える必要があります。
- 絶対的な価格ボラティリティ(
VolatilityPeriod バーの平均実体サイズ)は、VolatilityLimit を超える必要があります。
- Bollinger バンド幅 (期間
BollingerPeriod、幅 2) は BollingerLowerLimit から BollingerUpperLimit の間にある必要があります。
- 取引時間は、設定されたウィンドウ (
EntryHour + OpenHours) 内で、無効な平日 (Day1、Day2、金曜日の締め切り) の外である必要があります。
- SMA トレンド フィルター – ピップ単位での高速 (
SmaFastPeriod) と低速 (SmaSlowPeriod) の差 SMA は、どちらの方向でも SmaDifferencePips を超える必要があります。
- 長いローソク足を追いかけることを避けるために、前のバーの実体は
LastBarLimitPips より小さくなければなりません。
フィルターが成功すると、Stochastic クロスオーバーが評価されます。
StochasticSetLevel を介した強気のクロスオーバーにより、PoThresholdPips による入札を上回る 仮想買いストップが可能になります。
100 - StochasticSetLevel を通過する弱気のクロスオーバーは、入札値を同じしきい値で下回って 仮想売りストップを発動します。
各仮想指値注文は、その有効期限 (PoTimeLimitMinutes) と、StopLossPips と TakeProfitPips から取得したストップロス/テイクプロフィットの距離を記憶します。
実行フェーズ – TickLevel が有効な場合、戦略は受信取引をリッスンして、最後の価格がしきい値に達するとすぐに仮想注文を実行します。 TickLevel が無効になっている場合、トリガー チェックは終了したローソク足の終値ごとに実行されます。価格が仮想ストップを超えると、成行注文が送信され、仮想注文は決済されます。
リスク管理 – フィル後、戦略は次のように追跡します。
- エントリー価格からのピップ単位で測定される最初のストップロスとテイクプロフィットのレベル。
- エントリー以降の極端な価格に続くオプションのトレーリングストップ (
TrailingStopPips)。
- 最大保持時間 (
CloseTimeMinutes)。 ProfitType に応じて、タイマーが切れたときにすべてのポジション (0)、利益のあるポジションのみ (1)、または損失のあるポジションのみ (2) を閉じることができます。
すべての価格距離は、セキュリティ PriceStep と桁乗数を使用してピップから変換され、MQL 実装での 5 桁のブローカー処理を再現します。デフォルトの OrderVolume はすべての成行注文に適用されます。このストラテジーは、ポジションが横ばいになると内部状態を自動的にリセットします。
重要な注意事項
- スプレッドとトリガーレベルを正確に計算するには、レベル 1 データが必要です。最良の買値/売値の更新がなければ、フィルターは取引をブロックします。
- ティックレベルの実行は、元の EA の
TickLevel フラグを反映します。無効にすると、実行はローソク足が閉じるまで待機します。これはより保守的ですが、バックテストが容易になります。
- この戦略は、アクティブな成行注文の数を制限した MQL バージョンと同様に、単一のネット ポジションのみを維持します。
パラメーター
| グループ |
名前 |
説明 |
| 一般 |
キャンドルの種類 |
キャンドルのサブスクリプションに使用される時間枠 (デフォルト: 1 分)。 |
| 実行 |
ティックレベル |
取引ティックを使用して、仮想注文を即座に実行します。 |
| 実行 |
PO しきい値 (pips) |
入札価格と仮想ストップレベルの間の距離 (ピップ単位)。 |
| 実行 |
PO の有効期間 (分) |
各仮想指値注文の有効期限。 |
| フィルター |
最大スプレッド (pips) |
オーダーを準備する前に許可される最大スプレッド。 |
| フィルター |
音量制限 |
最後の 3 つのバーの最小平均ティック ボリューム。 |
| フィルター |
変動期間 |
ローソク足の絶対実体を平均するために使用されるバーの数。 |
| フィルター |
ボラティリティ制限 |
最小平均キャンドル本体サイズ (pips 単位)。 |
| フィルター |
Bollinger 期間 |
Bollinger バンド計算期間。 |
| フィルター |
Bollinger 下位/上位 |
許可されるバンド幅の範囲 (ピップ単位)。 |
| フィルター |
最後のバーリミット |
前のローソク足の最大実体サイズ (ピップ単位)。 |
| トレンド |
速い SMA / 遅い SMA |
移動平均トレンドフィルターの期間。 |
| トレンド |
SMA の差 |
傾向を確認するための最小の SMA 距離 (ピップ単位)。 |
| Stochastic |
%K / %D / スムーズ |
標準の Stochastic オシレーター周期。 |
| Stochastic |
Stochastic セット |
仮想指値注文を準備するために使用されるレベル。 |
| Stochastic |
Stochastic 行きます |
武装命令を実行するために使用されるしきい値。 |
| 取引 |
注文量 |
基本市場注文量。 |
| リスク |
利益確定 / ストップロス / トレーリングストップ |
出口距離 (pips)。 |
| スケジュール |
無効日、最初/2 番目の取引禁止日 |
平日フィルター (無効にするには 99 を使用します)。 |
| スケジュール |
入場時間・開館時間 |
取引ウィンドウの開始と期間。 |
| スケジュール |
金曜締め切り |
金曜日の取引が停止するまでの時間。 |
| リスク |
最大寿命 |
分単位の時間ベースの終了 (無効にするには ≥5000 に設定します)。 |
| リスク |
利益フィルター |
0 – 関係なくクローズ、1 – 勝者のみクローズ、2 – タイマーが作動したときに敗者のみクローズ。 |
オリジナルの EA との違い
- MQL
CPO ヘルパー クラスは、価格が仮想レベルを超えると、BuyMarket / SellMarket を直接呼び出す内部状態変数に置き換えられます。
- ストップロスとテイクプロフィットの実行では、ローソク足の高値/安値 (バックテスト用) または可能な場合はティックの更新を使用します。元の MT4 環境からの部分的な約定またはヘッジされたポジションはサポートされていません。
- アカウントベースの資金管理 (
GLots) は移植されません。 StockSharp 戦略では、固定の OrderVolume パラメータが使用されます。
これらの適応により、StockSharp の単一ポジションの高レベル プログラミング モデルに適合しながら、取引のアイデアが維持されます。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Virtual Pending Order Scalp strategy: ATR-based breakout scalper.
/// Buys when price breaks above recent high + ATR offset. Sells on break below low - ATR.
/// </summary>
public class VirtPoTestBedScalpStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
public VirtPoTestBedScalpStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for breakout offset", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var atr = new AverageTrueRange { Length = AtrPeriod };
decimal? prevHigh = null;
decimal? prevLow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, (candle, atrVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (prevHigh.HasValue && prevLow.HasValue)
{
if (close > prevHigh.Value + atrVal * 0.5m && Position <= 0)
BuyMarket();
else if (close < prevLow.Value - atrVal * 0.5m && Position >= 0)
SellMarket();
}
prevHigh = candle.HighPrice;
prevLow = candle.LowPrice;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
}
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 AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class virt_po_test_bed_scalp_strategy(Strategy):
def __init__(self):
super(virt_po_test_bed_scalp_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period for breakout offset", "Indicators")
self._atr = None
self._prev_high = None
self._prev_low = None
@property
def atr_period(self):
return self._atr_period.Value
def OnReseted(self):
super(virt_po_test_bed_scalp_strategy, self).OnReseted()
self._atr = None
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(virt_po_test_bed_scalp_strategy, self).OnStarted2(time)
self._atr = AverageTrueRange()
self._atr.Length = self.atr_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromHours(1)))
subscription.Bind(self._atr, self._process_candle)
subscription.Start()
def _process_candle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
if not self._atr.IsFormed:
return
close = float(candle.ClosePrice)
atr_val = float(atr_value)
if self._prev_high is not None and self._prev_low is not None:
if close > self._prev_high + atr_val * 0.5 and self.Position <= 0:
self.BuyMarket()
elif close < self._prev_low - atr_val * 0.5 and self.Position >= 0:
self.SellMarket()
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
def CreateClone(self):
return virt_po_test_bed_scalp_strategy()