GitHub で見る

受注安定化戦略

概要

注文安定化戦略は、MetaTrader エキスパート アドバイザー hjueiisyx8lp2o379e_www_forex-instruments_info.mq4 の転換です。元のロボットは、現在の価格付近で 2 つの逆指値注文を出し、ブレイクアウトを待ちます。ポジションがオープンされると、システムは最近のローソク体を監視して価格行動が停滞(「安定化」)したかどうかを判断し、市場の勢いが失われたとき、または事前に定義された利益しきい値に達したときに取引を終了します。

この C# ポートは、高レベルの StockSharp API を使用して同じロジックを維持します。生のティックではなく完成したローソク足に依存するため、バックテストやライブ取引中の動作が決定的になります。

取引ルール

  1. オープンポジションやアクティブな注文がない場合、この戦略は市場より上に買いストップを、市場より下に売りストップを送信します。距離は MetaTrader ポイント (通常は 1 ピップに等しい) で測定されます。
  2. 逆指値注文が実行された場合:
    • 約定された注文により、OrderVolume ロットのポジションがオープンされます。
    • 反対方向のブレイクアウトをキャッチするために、反対のストップ注文が保留されたままになります。
  3. ポジションがオープンしている間、戦略は直近に終了した 2 つのローソク足の実体サイズをチェックします。
    • 最新のローソク足本体が StabilizationPoints より小さく、変動利益が ProfitThreshold より高い場合、ポジションはクローズされ、反対の未決注文はキャンセルされます。
    • 2 つの連続するローソク足が StabilizationPoints より小さい場合、現在の利益に関係なく取引は終了します。
    • 利益が AbsoluteFixation に達した場合、取引は直ちに終了します。
  4. 保留中の注文は、値がゼロ (無期限) に設定されていない限り、ExpirationMinutes の後にキャンセルされ、再作成されます。

パラメーター

名前 説明 デフォルト
OrderVolume 両方のストップエントリーに使用されるロットの取引量。 0.1
OrderDistancePoints 現在の終値と各逆指値注文の間の距離。MetaTrader ポイントで表されます。 20
ProfitThreshold 安定化によるエグジットが許可される前に必要な最低変動利益(口座通貨)。 -2
AbsoluteFixation 即時退出を強制する利益レベル(口座通貨)。 30
StabilizationPoints 市場が横ばいであることを示すローソク足の最大サイズ(ポイント)。 25
ExpirationMinutes 保留中のストップ注文の存続期間 (分単位)。 0 は有効期限を無効にします。 20
CandleType 安定化の評価に使用されるローソクのタイプ (デフォルトは 5 分の時間枠)。 TimeFrame(5m)

変換メモ

  • 元のエキスパートアドバイザーはチャートティックに基づいて操作していました。このポートは完成したキャンドルのみを評価し、再現可能なバックテストを確保しながらロジックを維持します。
  • MetaTrader 個の「ポイント」は StockSharp PriceStep にマッピングされます。商品に価格ステップがない場合、1 のステップが想定されます。
  • 利益は、価格変動をアカウント通貨に換算するために PriceStepStepPrice を使用して概算されます。
  • すべてのコード コメントは英語で書き直され、パラメーターのメタデータにはグループ化されたわかりやすい説明が含まれています。

使用法

  1. 戦略を StockSharp ソリューションに追加し、必要なセキュリティとポートフォリオを割り当てます。
  2. パラメータ、特にローソク足の時間枠とポイント単位の距離を機器の特性に合わせて設定します。
  3. 戦略を開始します。ペアのストップ注文を発行し、上記の安定化ロジックに従ってポジションを管理します。

さらなるアイデア

  • 応答性とノイズ フィルターのバランスをとるために、さまざまなキャンドル間隔を試してください。
  • この戦略とボラティリティ フィルター (ATR、Bollinger バンド) を組み合わせて、非常に静かなセッションでの取引を回避します。
  • 絶対利益目標に近づいたら、トレーリング ストップまたは部分的なポジション エグジットを使用してロジックを拡張します。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Order stabilization strategy - trades breakouts after periods of low volatility.
/// When candle body is small (stabilization), waits for a directional breakout.
/// Goes long on bullish breakout candle after stabilization, short on bearish.
/// </summary>
public class OrderStabilizationStrategy : Strategy
{
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _stabilizationFactor;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevBody;
	private decimal _prevAtr;
	private bool _hasPrev;

	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public decimal StabilizationFactor { get => _stabilizationFactor.Value; set => _stabilizationFactor.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public OrderStabilizationStrategy()
	{
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetDisplay("ATR Period", "ATR period for volatility", "Indicators");

		_stabilizationFactor = Param(nameof(StabilizationFactor), 0.5m)
			.SetDisplay("Stabilization Factor", "Body must be less than ATR * factor for stabilization", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevBody = 0m;
		_prevAtr = 0m;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasPrev = false;

		var atr = new AverageTrueRange { Length = AtrPeriod };

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

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

		var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
		var threshold = atrValue * StabilizationFactor;

		if (!_hasPrev)
		{
			_prevBody = body;
			_prevAtr = atrValue;
			_hasPrev = true;
			return;
		}

		var prevThreshold = _prevAtr * StabilizationFactor;
		var wasStabilized = _prevBody < prevThreshold;

		// After stabilization, trade breakout candle
		if (wasStabilized && body > threshold)
		{
			var bullish = candle.ClosePrice > candle.OpenPrice;

			if (bullish && Position <= 0)
			{
				if (Position < 0)
					BuyMarket();
				BuyMarket();
			}
			else if (!bullish && Position >= 0)
			{
				if (Position > 0)
					SellMarket();
				SellMarket();
			}
		}

		_prevBody = body;
		_prevAtr = atrValue;
	}
}