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] > 0OSMA[1] > OSMA[2]) はロングになります。 OSMAがマイナスの場合はショートする そして落ちる。
    • レンジ体制: Stochastic 本線が信号の上を横切る場合はロング、信号の下を横切る場合はショートになります。
    • ボラティリティ ガード: シグナルが受け入れられる前に、以前の標準偏差が StdDevMinimum を超える必要があります。
  • 価格アクションフィルター – 最も最近完了したローソク足はドージ (DojiDivisor 比率) を形成してはならず、 方向(ロングの場合は強気、ショートの場合は弱気)。逆の飲み込みパターンまたはスターパターンは、即時清算を引き起こします。 それぞれの側。
  • ポジション制限 – オープン注文の総数は、トレンド市場では MaxTrendOrders に制限され、また MaxRangeOrders に制限されます レンジ相場で。
  • リスク管理 – すべての注文には固定のストップロスおよびテイクプロフィットレベル(StopLossPipsTakeProfitPips)が適用されます。後続 変動利益が 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を使用してください。

使用法

  1. 戦略を EURJPY の日次データに添付するか、別の時間枠が必要な場合は CandleType を更新します。
  2. pip サイズが正しく検出されていることを確認します。必要に応じて PipSizeOverride を調整します。
  3. アカウントの制約に合わせて資金管理パラメータ (LotSizeRiskBoost) を構成します。
  4. 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();
				}
			}
		}
	}
}