GitHub で見る

DeMarker Pending 2 戦略

概要

この戦略は、StockSharp の高レベルの API を使用して、MetaTrader のエキスパート「DeMarker Pending 2」のコア ロジックを複製します。動作時間枠で DeMarker オシレーターを評価し、インジケーターが設定可能なしきい値を超えたときに保留中の買いまたは売りエントリーを準備します。注文は、現在の市場価格から追加のインデントを使用して、ストップまたはリミットリクエストとして作成できます。セッション フィルター、スプレッド ガード、距離チェックにより、新しいエントリが制御されます。

取引ロジック

  1. 構成されたローソク足シリーズをサブスクライブし、選択した期間で DeMarker インジケーターを計算します。
  2. 以前の値が下位レベルを上回り、現在の値が下限レベルを下回った場合、長い指値注文をキューに入れます。以前の値が上限レベルを下回り、現在の値が上限レベルを超えた場合、短い未決注文をキューに入れます。キャンドルごとに 1 つの信号のみが処理されます。
  3. 未決注文は、ポイントで表されるインデント距離を使用してストップ注文または指値注文として発注されます。交換オプションが有効になっている場合、新しいリクエストの前に既存の注文をキャンセルできます。この戦略は、オープンポジションと未決注文の合計数を制限し、現在の平均ポジション価格からの最小距離を強制します。
  4. ロングポジションとショートポジションは、オプションのストップロス、テイクプロフィット、トレーリングロジックを使用します。保護レベルは価格ポイントで計算され、閉じたキャンドルごとに監視されます。ポジションがアクティベーション利益と追加のトレーリングステップ距離を獲得すると、トレーリングストップが調整されます。
  5. スプレッドフィルターは、最適な買い/売りスプレッドが設定されたしきい値を超えた場合、新しい注文を防ぎます。オプションのセッション境界により、許可された取引ウィンドウ外の新しいエントリーを無効にすることができます。

パラメーター

名前 説明
ワーキングキャンドル 信号と保護チェックに使用される時間枠。
注文量 未決注文のデフォルトの数量。
ストップロス (ポイント) 価格ポイントでの最初のストップロス距離。
テイクプロフィット(ポイント) 価格ポイントでの最初の利食い距離。
後続のアクティブ化 (ポイント) トレーリングストップがかかる前に利益が必要です。
トレーリングストップ (ポイント) 価格とトレーリングストップ間の距離。
トレーリングステップ (ポイント) トレーリングストップを移動するには追加のゲインが必要です。
トレイル・オン・クローズ 有効になっている場合、終了したローソク足のトレーリングストップのみを更新します。
最大ポジション数 オープンポジションと未決注文の最大数。ゼロはキャップを無効にします。
最小距離 (ポイント) 現在のポジション価格から新しい未決エントリまでの最小距離。
逆指値注文を使用する true の場合はストップ注文を出し、それ以外の場合は指値注文が使用されます。
シングル保留中 一度に許可されるアクティブな未決注文は 1 つだけです。
保留中の置換 新しい注文を発注する前に、未処理の保留中の注文をキャンセルしてください。
保留中のオフセット (ポイント) 市場に対する新しい保留価格をインデントします。
最大スプレッド (ポイント) 注文の発注をスキップする前の最大許容スプレッド。
セッションフィルターを使用する 取引ウィンドウフィルターを有効または無効にします。
開始時/分、終了時/分 セッション フィルターがアクティブな場合のセッション境界。
デマーカー期間 DeMarker オシレーターの平均化期間。
アッパーレベル 短いセットアップをトリガーするしきい値。
下位レベル 長いセットアップをトリガーするしきい値。

注意事項

  • 元の専門家による注文の有効期限と資金管理リスクのサイジングは移植されません。代わりに、固定ボリュームパラメータが使用されます。
  • ストップロスとテイクプロフィットのレベルは、高値/安値を使用して閉じたローソク足で評価されます。これは、MetaTrader におけるバー内執行とは異なる場合があります。
  • トレーリング ロジックは閉じたローソク足でのみ評価されます。リアルタイムのティックベースのトレーリングは再現されません。
  • 未決注文は、データ ソースから提供される最良の買値/売値に依存します。レベル 1 のサブスクリプションが利用可能であることを確認します。
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Pending order strategy driven by the DeMarker oscillator.
/// Simplified from "DeMarker Pending 2" to use market orders on threshold crossovers.
/// </summary>
public class DeMarkerPending2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _demarkerPeriod;
	private readonly StrategyParam<decimal> _demarkerUpperLevel;
	private readonly StrategyParam<decimal> _demarkerLowerLevel;

	private RelativeStrengthIndex _rsi;
	private decimal? _prevOscillator;

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

	/// <summary>
	/// DeMarker oscillator period.
	/// </summary>
	public int DemarkerPeriod
	{
		get => _demarkerPeriod.Value;
		set => _demarkerPeriod.Value = value;
	}

	/// <summary>
	/// Upper DeMarker threshold for sell signal.
	/// </summary>
	public decimal DemarkerUpperLevel
	{
		get => _demarkerUpperLevel.Value;
		set => _demarkerUpperLevel.Value = value;
	}

	/// <summary>
	/// Lower DeMarker threshold for buy signal.
	/// </summary>
	public decimal DemarkerLowerLevel
	{
		get => _demarkerLowerLevel.Value;
		set => _demarkerLowerLevel.Value = value;
	}

	public DeMarkerPending2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations", "General");

		_demarkerPeriod = Param(nameof(DemarkerPeriod), 14)
			.SetDisplay("DeMarker Period", "DeMarker oscillator period", "Indicator")
			.SetGreaterThanZero();

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

		_demarkerLowerLevel = Param(nameof(DemarkerLowerLevel), 0.3m)
			.SetDisplay("Lower Level", "Oversold threshold", "Indicator");
	}

	/// <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;
		}

		if (_prevOscillator is not decimal prev)
		{
			_prevOscillator = rsiValue / 100m;
			return;
		}

		var oscillatorValue = rsiValue / 100m;
		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// Cross above lower level from below => buy
		if (prev < DemarkerLowerLevel && oscillatorValue >= DemarkerLowerLevel)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		// Cross below upper level from above => sell
		else if (prev > DemarkerUpperLevel && oscillatorValue <= DemarkerUpperLevel)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevOscillator = oscillatorValue;
	}

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

		base.OnReseted();
	}
}