GitHub で見る

DeMarker ポジション獲得ボリューム 2 戦略

この戦略は、StockSharp のハイレベル API を使用して、MetaTrader 5 エキスパート アドバイザー 「DeMarker のポジション獲得ボリューム 2」 を再現します。 DeMarker オシレーターを使用して設定可能なローソク足シリーズを分析し、値が極端なゾーンに入ると反応します。この実装では、固定ロット サイズ設定、オプションのシグナル反転、組み込みのストップロス/テイクプロフィット処理、オプションの取引セッション フィルターなど、元の資金管理の特徴が維持されています。

専門家の本来の動作

  • プラットフォーム: MetaTrader 5.
  • インジケーター: クラシック DeMarker オシレーター (DEM)、デフォルト期間 14。
  • エントリー: DeMarker が下限しきい値を下回るとロングがオープンし、上限しきい値を上回るとショートがオープンします。
  • リスクコントロール: ポイントで表現される固定ストップロス/テイクプロフィット、オプションのステップ付きトレーリングストップ、オプションの時間枠。
  • ポジション管理: バーごとに 1 つのトレードのみを保証し、方向を反転する前に反対側をクローズします。

StockSharp 変換も同じ原則に従います。プロテクション注文は StartProtection で実装されるため、ポジションがオープンされるとストップロス、テイクプロフィット、トレーリングが自動的に管理されます。

取引ロジック

  1. 構成されたローソク足タイプ (CandleType、デフォルトでは 5 分足ローソク足) をサブスクライブし、選択した期間 (DeMarkerPeriod) で DeMarker 値を計算します。
  2. ローソク足が閉じたら、オシレーターを評価します。
    • ReverseSignalsfalse の場合 (デフォルト):
      • 長いセットアップDeMarker <= LowerLevel
      • 簡単なセットアップDeMarker >= UpperLevel
    • ReverseSignalstrue の場合、ロング/ショート ルールが入れ替わります。
  3. UseTimeFilter が有効な場合は、SessionStart/SessionEnd で定義されたオプションのセッション ウィンドウ内でのみ取引します。夜間のセッションもサポートされています。
  4. キャンドルごとに最大 1 つの新しいエントリを実行します。新しいポジションを開く前に、この戦略は MT5 ロジックを反映するために反対の保有をすべて閉じます。
  5. 音量は TradeVolume パラメータによって固定されます。戦略がすでに部分的に望ましい方向に進んでいる場合は、要求されたボリュームまで補充されます。

リスク管理

  • StopLossPointsTakeProfitPoints (価格ステップ内) は、エキスパートのポイントベースのストップ距離とテイクプロフィット距離にマッピングされます。
  • EnableTrailing を有効にすると、停止距離が TrailingStopPoints に切り替わり、調整ステップとして TrailingStepPoints を使用して内蔵のトレーリング エンジンが有効になります。
  • StartProtectionuseMarketOrders = true で構成されているため、MT5 の取引終了動作と同様に、保護注文がすぐに実行されます。

パラメーター

パラメータ 説明
DeMarkerPeriod DeMarker インジケーターの平均期間。
UpperLevel / LowerLevel 買われすぎ/売られすぎの閾値によりショート/ロングが引き起こされます。
ReverseSignals ロング条件とショート条件を入れ替えます。
StopLossPoints 価格ステップで測定される初期保護停止距離。
TakeProfitPoints 価格ステップで測定される利食い距離。
EnableTrailing トレーリングストップブロックを有効にします。
TrailingStopPoints トレーリングがアクティブになった後のトレーリング ストップの距離。
TrailingStepPoints トレーリングストップが前進する前の最小限の有利な動き。
UseTimeFilter 取引を SessionStartSessionEnd ウィンドウに制限します。
SessionStart / SessionEnd 包括的/排他的セッション境界 (ラップアラウンドをサポート)。
TradeVolume 各成行注文で送信する数量。
CandleType 分析するローソク足シリーズ (デフォルトは 5 分)。

実装メモ

  • MT5 エキスパートには、「トレーリング アクティベーション」のしきい値が含まれていました。 StockSharp の標準のトレーリング保護は同じパラメータを公開しないため、EnableTrailing が true の場合、トレーリングはすぐにアクティブになります。
  • 無効なロットサイズ、凍結レベル、入札/売値更新ロジックのエラー処理は、StockSharp のインフラストラクチャによって処理されるため、変換から省略されます。
  • ロギングは、基本クラス Strategy を介して実行されます (追加のトレースが必要な場合は、LogInfo/LogError を呼び出します)。
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

/// <summary>
/// Strategy converted from "DeMarker gaining position volume 2" expert advisor.
/// Uses DeMarker oscillator thresholds for entry signals.
/// </summary>
public class DeMarkerGainingPositionVolume2Strategy : Strategy
{
	private readonly StrategyParam<int> _deMarkerPeriod;
	private readonly StrategyParam<decimal> _upperLevel;
	private readonly StrategyParam<decimal> _lowerLevel;
	private readonly StrategyParam<DataType> _candleType;

	private RelativeStrengthIndex _rsi;
	private decimal? _prevOscillator;

	/// <summary>
	/// DeMarker averaging period.
	/// </summary>
	public int DeMarkerPeriod
	{
		get => _deMarkerPeriod.Value;
		set => _deMarkerPeriod.Value = value;
	}

	/// <summary>
	/// Upper DeMarker threshold.
	/// </summary>
	public decimal UpperLevel
	{
		get => _upperLevel.Value;
		set => _upperLevel.Value = value;
	}

	/// <summary>
	/// Lower DeMarker threshold.
	/// </summary>
	public decimal LowerLevel
	{
		get => _lowerLevel.Value;
		set => _lowerLevel.Value = value;
	}

	/// <summary>
	/// Candle type for DeMarker calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public DeMarkerGainingPositionVolume2Strategy()
	{
		_deMarkerPeriod = Param(nameof(DeMarkerPeriod), 14)
			.SetDisplay("DeMarker Period", "Number of bars used by the oscillator.", "Indicator");

		_upperLevel = Param(nameof(UpperLevel), 0.7m)
			.SetDisplay("Upper Level", "Overbought threshold.", "Indicator");

		_lowerLevel = Param(nameof(LowerLevel), 0.3m)
			.SetDisplay("Lower Level", "Oversold threshold.", "Indicator");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations.", "Data");
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevOscillator = null;
		_rsi = new RelativeStrengthIndex { Length = DeMarkerPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_rsi, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_rsi.IsFormed)
		{
			_prevOscillator = rsiValue / 100m;
			return;
		}

		var oscillatorValue = rsiValue / 100m;

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// Cross below lower level => oversold => buy
		if (_prevOscillator is decimal prev)
		{
			var crossBelow = prev >= LowerLevel && oscillatorValue < LowerLevel;
			var crossAbove = prev <= UpperLevel && oscillatorValue > UpperLevel;

			if (crossBelow)
			{
				if (Position <= 0)
					BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
			}
			else if (crossAbove)
			{
				if (Position >= 0)
					SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
			}
		}

		_prevOscillator = oscillatorValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_rsi = null;
		_prevOscillator = null;

		base.OnReseted();
	}
}