VmMatrix ダブルゼロ
概要
VmMatrix Double Zero は、MetaTrader 4 Expert Advisor vMATRIXDoubleZero の StockSharp ポートです。オリジナルのロボットは、前のローソク足を小数点第 2 位近くで四捨五入し、価格がその四捨五入されたレベルを超えたときに取引を開始することで、「ダブル ゼロ」のブレイクアウトを探します。このポートは、EA の階層化フィルター構造を維持します。つまり、構成可能なマルチバー バイアス比較、オプションのボリュームとレンジ チェック、ATR 加速ゲート、および二次スイング強度フィルターです。この戦略では、方向性を確認するために日次コモディティ チャネル インデックス (CCI) を必要とすることもでき、時間ごとの ATR 統計から導出される適応型利益確定コンポーネントを提供します。
取引はユーザー定義のターミナル時間ウィンドウに制限され、個別のトグルで長いセットアップを行うか短いセットアップを行うかを制御します。ストップとターゲットは、トレーリングが有効になるたびにテイクプロフィットレベルを拡大する元のトレーリングストップ動作の近似を含め、内部で管理されます。
戦略ロジック
バイアス検出
- 四捨五入ブレイクアウト – コアトリガーは、終了した最後の 2 つのローソク足の終値と、小数点第 2 位に四捨五入された前の終値とを比較します。長い信号には
Close[2] < round(Close[1], 2) と Close[1] > round(Close[1], 2) が必要です。短い信号は不等式を逆転させます。
- マトリックス フィルター (オプション) – 有効にすると、パラメーター
LongK1…LongK6 (ロングの場合) または ShortK1…ShortK6 (ショートの場合) で定義された 6 つの過去のローソク足が中間点偏差を使用して比較されます。各偏差は Close - (High + Low) / 2 として計算されます。比較は元の EA を反映しており、最初の偏差が 2 番目の偏差を上回り、3 番目の偏差が乗数スケールの 4 番目 (LongQc/ShortQc) を超え、5 番目の偏差が 2 番目の乗数スケールの 6 番目 (LongQg/ShortQg) を超える必要があります。
追加のフィルター
- セッション フィルター – 取引は、処理されたローソク足の終了時間が
StartHour と EndHour (両端を含む) の間にある場合にのみ評価されます。
- ボリュームフィルター – 有効にした場合、前のローソク足の合計ボリュームは
MinimumVolume を超える必要があります。
- 範囲圧縮 – 最後の
RangeBars ローソク足の最高値と最低値は RangeThresholdPips ピップ以内である必要があります。
- ATR の加速 – 最新の ATR 値(稼働時間枠での
AtrPeriod の長さ)を AtrShift バー前の ATR 値と比較します。信号は、現在の ATR が高い場合にのみ受け入れられ、EA の VSA トグルを模倣します。
- 二次スイング フィルター – アクティブな場合、
SecondaryPivot ルックバックから構築された高値と安値の差の加重合計は、ロングの場合は正、ショートの場合は負である必要があります。重み (Xb2、Xs2、Yb2、Ys2) は元のパラメーター スキームに従い、50 は中立性を表します。
- 毎日の CCI 確認 – 最新の毎日の CCI 値 (期間
DailyCciPeriod) がロングの場合はゼロより大きく、ショートの場合はゼロ未満であることを必要とするオプションのゲートです。
注文管理
- エントリー サイズ – 注文では、証券の出来高ステップに合わせて調整された
OrderVolume が使用されます。反対のポジションがすでにオープンしている場合、ストラテジーはオプションでそれを最初にクローズします (CloseOnBiasFlip が true である必要があります)。それ以外の場合、ポートはネッティング環境で実行されるため、新しいエントリはスキップされます。
- 初期ストップ – ストップロス距離は、
LongStopLossPips/ShortStopLossPips までのピップ単位で表され、検出されたピップ サイズを使用して変換されます。テイクプロフィットディスタンスは LongTakeProfitPips/ShortTakeProfitPips を使用し、以下の動的コンポーネントによって拡張される場合があります。
- 動的テイクプロフィット –
UseDynamicTakeProfit が有効な場合、戦略は時間ごとの ATR 統計とスイングの差の重み付けされた組み合わせを基本テイクプロフィットディスタンスに追加します。この寄与度は、EA の TPb() 関数を反映しています。これは、時間ごとの変化 ATR(1)、最新の時間ごとの変化 ATR(1)、時間ごとの ATR(25)、および SwingPivot バーで区切られた高値の差をブレンドします。すべてのウェイトは 50 を中心としており、元のインターフェイスと一致しています。
- トレーリング ストップ –
UseTrailingStop を有効にすると、現在のストップを超えて設定されたストップ距離の約 2 倍の価格が移動するたびにストップ レベルを上げる (または下げる) ステップ スタイルのトレーリング ストップが有効になります。 MQL バージョンと同様に、テイリング ディスタンスは 10 倍され、トレーリングがアクティブな間、トレードを効果的にオープンに保ちます。
- 保護的出口 – 終了したローソク足ごとに、戦略はストップロスまたはテイクプロフィットを突破したかどうかをチェックします。これに応じてポジションは市場でクローズされます。逆の信号が検出された場合、バイアス フリップ (
CloseOnBiasFlip) も現在の位置を閉じます。
パラメーター
次の表は、公開されているパラメータをまとめたものです (注記がない限り、すべてが最適化に使用できます)。
| グループ |
パラメータ |
説明 |
| 一般 |
StartHour / EndHour |
ターミナルタイムにおける包括的な取引ウィンドウ。 |
| 一般 |
OrderVolume |
楽器の音量ステップに正規化された基本注文サイズ。 |
| 一般 |
UseTrailingStop |
トレーリングストップ近似を有効にし、テイクプロフィットファクターを拡大して、EA をエミュレートします。 |
| 一般 |
CloseOnBiasFlip |
true の場合、新しい取引を開始する前に反対のエクスポージャーをクローズします。 |
| ロング/ショート |
EnableLongs / EnableShorts |
長い信号処理と短い信号処理を切り替えます。 |
| ロング/ショート |
LongStopLossPips, LongTakeProfitPips, ShortStopLossPips, ShortTakeProfitPips |
ピップ単位で測定されるストップロスとテイクプロフィットの距離。 |
| フィルター |
UseBiasFilter with LongK1…LongK6, ShortK1…ShortK6, LongQc, LongQg, ShortQc, ShortQg |
ロング信号とショート信号のマトリックス形式の偏差比較を設定します。 |
| フィルター |
UseRangeFilter, RangeBars, RangeThresholdPips |
最近の価格範囲がピップのしきい値を超える場合、取引を拒否します。 |
| フィルター |
UseVolumeFilter, MinimumVolume |
以前のローソク足の量がしきい値を超える必要があります。 |
| フィルター |
UseVsaFilter, AtrPeriod, AtrShift |
ATR の需要は、AtrShift バー前と比較して増加しました。 |
| フィルター |
UseSecondaryFilter, Xb2, Xs2, Yb2, Ys2, SecondaryPivot |
高音と低音に基づいて重み付けされたスイング強度フィルター。 |
| フィルター |
UseDailyCciFilter, DailyCciPeriod |
毎日の CCI ゲート;ロングには正の CCI、ショートには負の CCI が必要です。 |
| 利食い |
UseDynamicTakeProfit, WeightSn1…WeightSn4, SwingPivot |
時間ごとの ATR 指標とスイング距離をブレンドする適応型テイクプロフィットコンポーネントを制御します。 |
| 一般 |
CandleType |
すべての信号計算を駆動する主要なタイムフレーム。 |
追加の注意事項
- Pip サイズは
Security.PriceStep から推測されます。 5 桁および 3 桁の FX シンボルは、Digits および Point の MQL 処理を反映して、10 倍の乗数に自動的にマッピングされます。
- ポートは、作業時間枠、時間足ローソク足 (ATR の計算用)、および日足ローソク足 (CCI の場合) の 3 つのデータ ストリームをサブスクライブします。データプロバイダーが要求されたすべての時間枠を提供できることを確認してください。
- StockSharp 戦略はネット ポジションで動作するため、同じ商品を両方向で同時にヘッジすることはサポートされていません。
CloseOnBiasFlip を有効にすると、EA の素早く閉じて反転する機能を模倣できます。
- トレーリングストップの動作はおおよその値です。 EA は生のスプレッド値を使用して後続ステップを決定しました。ポートでは、ストップを進める前にストップ距離の約 2 倍の移動料金が必要ですが、明示的なスプレッド情報がなくても同様の結果が生じます。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// VmMatrix DoubleZero: Dual EMA crossover with RSI confirmation and ATR stops.
/// </summary>
public class VmMatrixDoubleZeroStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public VmMatrixDoubleZeroStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 12)
.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 26)
.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fastEma, slowEma, rsi, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fastEma); DrawIndicator(area, slowEma); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
var close = candle.ClosePrice;
if (Position > 0)
{
if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50) { _entryPrice = close; SellMarket(); }
}
_prevFast = fastVal; _prevSlow = slowVal;
}
}
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 ExponentialMovingAverage, RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class vm_matrix_double_zero_strategy(Strategy):
"""Dual EMA crossover with RSI confirmation and ATR-based stop loss."""
def __init__(self):
super(vm_matrix_double_zero_strategy, self).__init__()
self._fast_len = self.Param("FastEmaLength", 12).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_len = self.Param("SlowEmaLength", 26).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._rsi_len = self.Param("RsiLength", 14).SetDisplay("RSI Length", "RSI period", "Indicators")
self._atr_len = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(vm_matrix_double_zero_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
def OnStarted2(self, time):
super(vm_matrix_double_zero_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_len.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_len.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_len.Value
atr = AverageTrueRange()
atr.Length = self._atr_len.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast_ema, slow_ema, rsi, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
fv = float(fast_val)
sv = float(slow_val)
rv = float(rsi_val)
av = float(atr_val)
close = float(candle.ClosePrice)
if self._prev_fast == 0 or self._prev_slow == 0 or av <= 0:
self._prev_fast = fv
self._prev_slow = sv
return
# Exit conditions
if self.Position > 0:
if (fv < sv and self._prev_fast >= self._prev_slow) or close <= self._entry_price - av * 2:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0:
if (fv > sv and self._prev_fast <= self._prev_slow) or close >= self._entry_price + av * 2:
self.BuyMarket()
self._entry_price = 0
# Entry conditions
if self.Position == 0:
if fv > sv and self._prev_fast <= self._prev_slow and rv > 50:
self._entry_price = close
self.BuyMarket()
elif fv < sv and self._prev_fast >= self._prev_slow and rv < 50:
self._entry_price = close
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return vm_matrix_double_zero_strategy()