GitHub で見る
SVOS ユーロ円 D1 戦略
概要
この戦略は、MetaTrader 4 Expert Advisor SVOS_EURJPY_D1 の C# 変換です。ユーロ円の毎日のローソク足で動作します。
レジーム分類器とパターン認識および指標フィルターを組み合わせます。垂直水平フィルタ (VHF) は、
トレンド市場状態とレンジ市場状態の間。市場がトレンドにあるとき、戦略は MACD ヒストグラム (OSMA) の傾きに依存します。
測距状態では、Stochastic 発振器に戻ります。巻き込みバーやローソク足パターンなど
朝/宵の明星は、不利な価格変動に対して積極的にポジションを決済するために使用されます。
取引ロジック
- 体制検出 – 前日の VHF 値が
VhfThreshold と比較されます。しきい値を超える値は、
トレンドフォローブロック、それ以外の場合はレンジブロックが使用されます。
- トレンドの確認 – 2 つの EMA (5 および 20 期間) が遅い EMA (130 期間、6 か月フィルターに一致) と比較されます。
元の EA) を使用して位置サイズをスケールします。上昇トレンドでは、購入量は
RiskBoost 倍になります。下降トレンドの売りボリュームは
乗算された。
- インジケーターフィルター:
- トレンド体制: OSMA がプラスで上昇している場合 (
OSMA[1] > 0 と OSMA[1] > OSMA[2]) はロングになります。 OSMAがマイナスの場合はショートする
そして落ちる。
- レンジ体制: Stochastic 本線が信号の上を横切る場合はロング、信号の下を横切る場合はショートになります。
- ボラティリティ ガード: シグナルが受け入れられる前に、以前の標準偏差が
StdDevMinimum を超える必要があります。
- 価格アクションフィルター – 最も最近完了したローソク足はドージ (
DojiDivisor 比率) を形成してはならず、
方向(ロングの場合は強気、ショートの場合は弱気)。逆の飲み込みパターンまたはスターパターンは、即時清算を引き起こします。
それぞれの側。
- ポジション制限 – オープン注文の総数は、トレンド市場では
MaxTrendOrders に制限され、また MaxRangeOrders に制限されます
レンジ相場で。
- リスク管理 – すべての注文には固定のストップロスおよびテイクプロフィットレベル(
StopLossPips、TakeProfitPips)が適用されます。後続
変動利益が TrailingStopPips を超えるとストップがアクティブになります。ろうそくの極値を使用して再計算され、
MetaTrader の動作。
インジケーターの使用法
- 指数移動平均 (5、20、130) – 方向の確認とボリュームのスケーリングに使用されます。
- 垂直水平フィルター – 正味の動きと累積終値間の比率を測定するカスタム指標
トレンドと範囲を検出するための変更。
- MACD (OSMA) – MACD とそのシグナルラインの差がトレンドのエントリーとエグジットを引き起こします。
- Stochastic オシレーター – %K および %D 値は、レンジ相場の平均回帰シグナルを提供します。
- 標準偏差 – 新しい取引を許可する前に、ボラティリティが十分に高いことを確認します。
注文管理
- 注文は
BuyMarket/SellMarket で実行され、内部に保存されるため、個々のストップとターゲットをシミュレートできます。
StockSharp のネット環境。
- ローソク足の範囲内でストップロスまたはテイクプロフィットのレベルに触れると、ポジションの対応する部分がクローズされます。
- トレーリングストップは、設定された距離を維持しながら、ローソク足の高値 (ロングの場合) またはローソク足の安値 (ショートの場合) に従います。
パラメーター
| パラメータ |
説明 |
デフォルト |
LotSize |
基本注文サイズはロットで表されます。 |
0.1 |
RiskBoost |
EMA トレンド フィルターが調整されている場合にロット サイズに適用される乗数。 |
3 |
TakeProfitPips |
利益確定距離 (pips)。 |
350 |
StopLossPips |
ピップス単位のストップロス距離。 |
90 |
TrailingStopPips |
トレーリングストップの距離 (ピップ単位) (常にアクティブ)。 |
150 |
StochKPeriod |
Stochastic オシレーターの %K 長。 |
8 |
StochDPeriod |
%D Stochastic オシレーターの長さ。 |
3 |
StochSlowing |
%K に適用される平滑化係数。 |
3 |
StdDevPeriod |
標準偏差フィルターのルックバック ウィンドウ。 |
20 |
StdDevMinimum |
新しい取引を開始するには、最小限の標準偏差が必要です。 |
0.3 |
VhfPeriod |
垂直水平フィルタの長さ。 |
20 |
VhfThreshold |
体制のしきい値。値が大きいほどトレンド市場を示します。 |
0.4 |
MaxTrendOrders |
トレンド中に同時にオープンされる注文の最大数。 |
4 |
MaxRangeOrders |
範囲内で同時にオープンする注文の最大数。 |
2 |
MacdFastLength |
MACD 内の高速な EMA の長さ。 |
10 |
MacdSlowLength |
MACD 内の EMA の長さが遅いです。 |
25 |
MacdSignalLength |
MACD の信号 EMA の長さ。 |
5 |
DojiDivisor |
doji キャンドルにフラグを立てるために使用される比率 (本体が範囲 / 除数よりも小さい)。 |
8.5 |
CandleType |
分析に使用されるローソク足のタイプ (デフォルトでは毎日)。 |
1 day |
PipSizeOverride |
オプションの pip サイズ オーバーライド。 0 は、Security.PriceStep からの自動検出を有効にします。 |
0 |
実装メモ
- 元の EA は、月単位の期間から 6 か月の EMA を参照していました。ポートは毎日の終値で 130 期間の EMA を計算します。
単一のデータ サブスクリプションを維持しながら、同じスムージングを再現します。
- StockSharp はデフォルトでポジションをネットしているため、ストップ、ターゲット、およびトレーリング ロジックはストラテジー内で再現されます。それぞれのエントリーは、
MetaTrader の動作を尊重するために個別に追跡されます。
- トレーリングストップの更新では、ローソク足の高値/安値を使用して日中の価格変動を概算します。結果はティックベースとは若干異なる場合があります
日中大幅な反転が発生した場合、MetaTrader で後続します。
- ピップサイズは
Security.PriceStep から計算されます。ブローカーがJPYペアに非標準のステップを使用する場合は、PipSizeOverrideを使用してください。
使用法
- 戦略を EURJPY の日次データに添付するか、別の時間枠が必要な場合は
CandleType を更新します。
- pip サイズが正しく検出されていることを確認します。必要に応じて
PipSizeOverride を調整します。
- アカウントの制約に合わせて資金管理パラメータ (
LotSize、RiskBoost) を構成します。
- StockSharp デザイナーまたは API ランナーで戦略を実行して、ライブ取引する前に動作を検証します。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Regime-switching strategy that uses ADX to detect trend vs range.
/// In trends, follows EMA direction; in ranges, trades mean reversion.
/// </summary>
public class SvosEurJpyD1Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _adxLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _adxThreshold;
private decimal _entryPrice;
public SvosEurJpyD1Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for analysis.", "General");
_adxLength = Param(nameof(AdxLength), 14)
.SetDisplay("ADX Length", "Period for ADX.", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Length", "Period for trend EMA.", "Indicators");
_adxThreshold = Param(nameof(AdxThreshold), 25m)
.SetDisplay("ADX Threshold", "ADX level to distinguish trend from range.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AdxLength
{
get => _adxLength.Value;
set => _adxLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public decimal AdxThreshold
{
get => _adxThreshold.Value;
set => _adxThreshold.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
var atr = new AverageTrueRange { Length = AdxLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal adxValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var isTrending = adxValue > AdxThreshold;
// Position management
if (Position > 0)
{
if (isTrending && close < emaValue)
{
SellMarket(); // Trend reversed
}
else if (!isTrending && close >= emaValue)
{
SellMarket(); // Mean reversion target hit
}
}
else if (Position < 0)
{
if (isTrending && close > emaValue)
{
BuyMarket();
}
else if (!isTrending && close <= emaValue)
{
BuyMarket();
}
}
// Entry
if (Position == 0)
{
if (isTrending)
{
// Trend following
if (close > emaValue)
{
_entryPrice = close;
BuyMarket();
}
else if (close < emaValue)
{
_entryPrice = close;
SellMarket();
}
}
else
{
// Mean reversion
var deviation = Math.Abs(close - emaValue);
if (deviation > 0 && close < emaValue)
{
_entryPrice = close;
BuyMarket();
}
else if (deviation > 0 && close > emaValue)
{
_entryPrice = close;
SellMarket();
}
}
}
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import AverageTrueRange, ExponentialMovingAverage
class svos_eur_jpy_d1_strategy(Strategy):
def __init__(self):
super(svos_eur_jpy_d1_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._adx_length = self.Param("AdxLength", 14) \
.SetDisplay("ADX Length", "Period for ADX", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Period for trend EMA", "Indicators")
self._adx_threshold = self.Param("AdxThreshold", 25.0) \
.SetDisplay("ADX Threshold", "ADX level to distinguish trend from range", "Indicators")
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def AdxLength(self):
return self._adx_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AdxThreshold(self):
return self._adx_threshold.Value
def OnStarted2(self, time):
super(svos_eur_jpy_d1_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._atr = AverageTrueRange()
self._atr.Length = self.AdxLength
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._atr, self._ema, self.ProcessCandle).Start()
def ProcessCandle(self, candle, adx_value, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
adx_val = float(adx_value)
ema_val = float(ema_value)
threshold = float(self.AdxThreshold)
is_trending = adx_val > threshold
# Position management
if self.Position > 0:
if is_trending and close < ema_val:
self.SellMarket()
elif not is_trending and close >= ema_val:
self.SellMarket()
elif self.Position < 0:
if is_trending and close > ema_val:
self.BuyMarket()
elif not is_trending and close <= ema_val:
self.BuyMarket()
# Entry
if self.Position == 0:
if is_trending:
if close > ema_val:
self._entry_price = close
self.BuyMarket()
elif close < ema_val:
self._entry_price = close
self.SellMarket()
else:
deviation = abs(close - ema_val)
if deviation > 0 and close < ema_val:
self._entry_price = close
self.BuyMarket()
elif deviation > 0 and close > ema_val:
self._entry_price = close
self.SellMarket()
def OnReseted(self):
super(svos_eur_jpy_d1_strategy, self).OnReseted()
self._entry_price = 0.0
def CreateClone(self):
return svos_eur_jpy_d1_strategy()