GitHub で見る

手動位置追跡パネル戦略

概要

オリジナルの MQL5 エキスパート アドバイザーは、トレーダーが最大 5 つのロング ポジションと 5 つのショート ポジションを手動で管理できる視覚的なコントロール パネルを提供していました。パネル内のボタンは、既存のテイクプロフィットレベルを削除したり、エントリーから新しいテイクプロフィット価格を再計算したり、選択したチケットの損益分岐点に移動したりすることができます。 StockSharp ポートは、視覚的なインターフェースを使用せずにこれらの保護アクションを自動化します。この戦略は、設定されたシンボルの集約ポジションを監視し、パネルのワークフローを反映する保護的なテイクプロフィット注文を動的に維持します。

主要な自動化手順:

  • ポジションが表示されたときに、エントリー価格に設定可能な MetaTrader ピップ距離をプラス/マイナスした値でテイクプロフィットを置きます。
  • 必要に応じて、市場が要求されたピップス数だけ有利な方向に動いたら、テイクプロフィットを平均エントリー価格まで押し上げ、実質的に損益分岐点の出口をロックします。
  • ブローカーのフリーズ/停止距離がレベル 1 データ経由で公開される場合は、それらを尊重するか、現在のスプレッドとユーザー制御の乗数を使用して近似します。
  • 管理が無効になっている場合、またはポジションがクローズされている場合は必ず保護注文をキャンセルし、パネルの「TP 削除」ボタンと動作の一貫性を保ちます。

このクラスは、高レベルの StockSharp API メソッド (SubscribeLevel1SellLimitBuyLimitReRegisterOrder など) のみに依存し、自動ボリューム/価格正規化を使用するため、コネクタでサポートされているあらゆる商品に接続できます。

パラメーター

パラメータ 説明
利益確定距離 (pips) 保護的なテイクプロフィットを作成するときに、エントリー価格に MetaTrader ピップ距離が追加されました。
エントリーベースのテイクプロフィットを有効にする エントリー価格から導出されたテイクプロフィットの自動配置を有効にします。無効にすると、戦略は損益分岐点リクエストにのみ反応します。
損益分岐点を有効にする 損益分岐点トリガーが満たされると、テイクプロフィットを平均エントリー価格に戻します。
損益分岐点トリガー (pips) 損益分岐点が適用される前に、最小限の有利な動き (MetaTrader ピップ単位) が必要です。 0 の値はすぐに適用されます。
ロングポジションの管理 true の場合、集約位置の長辺が処理されます。
ショートポジションを管理 true の場合、集約ポジションの短辺が処理されます。
無効な場合はテイクプロフィットを削除 管理条件が満たされない場合、保護命令をキャンセルします(元の TP 削除ボタンと同様)。
ログ管理アクション アルゴリズムによって実行されるすべての作成、変更、またはキャンセルアクションの情報ログを有効にします。
凍結距離乗数 取引所が明示的なレベルを公開していない場合に、現在のスプレッドからフリーズ/ストップ距離を概算するために使用される乗数。

シグナルと実行ルール

  1. 開始時に、戦略は、最良の買値/売値と、ゲートウェイによって公開されるオプションのフリーズおよびストップ レベルを追跡するために、レベル 1 の更新をサブスクライブします。
  2. 新しい取引が出現するたびに、全体的なポジションが変化するか、新しいレベル 1 データが到着するたびに、戦略は保護ロジックを再評価します。
  3. オープンなポジションがない場合、既存の利益確定注文はキャンセルされます。
  4. ポジションがアクティブで、対応するサイドが有効な場合:
    • 基本ターゲットは、構成された利食い距離 (有効な場合) によってシフトされたエントリー価格です。
    • 損益分岐点が有効で、現在の市場価格が十分に変動している場合、ターゲットは平均エントリー価格に固定されます。
    • 目標は、現在の市場相場と比較することにより、フリーズ/ストップ距離を考慮するように調整されます。
    • 価格と出来高は PriceStep/VolumeStep を介して正規化され、反対側で指値注文が登録または再登録されます。
  5. 設定により検出された側の管理が無効になっている場合、無効時のテイクプロフィットの削除true の場合、既存のテイクプロフィットは削除されます。

リスク管理に関する注意事項

  • このアルゴリズムは利益確定注文のみを管理します。ストップロスレベル、トレーリングロジック、または部分的なエグジットは範囲外です。
  • 元のパネルは MetaTrader "pips" (ポイント) で動作したため、ストラテジーは、外国為替シンボルとの互換性を維持するために、PriceStep と金融商品の精度からピップ サイズを自動的に計算します。
  • レベル 1 のフリーズ/停止距離が利用可能な場合は尊重されます。ブローカーがそれらを送信しない場合、ユーザーは乗数パラメーターを使用してライブ スプレッドから安全バッファを作成し、変更が拒否されるのを防ぎます。
  • この戦略は新たな市場参入を生み出すものではありません。これは、すでに注文執行を管理している裁量取引システムまたは外部取引システムに接続するように設計されています。

使用のヒント

  1. 監視する機器にストラテジを接続し、コネクタがレベル 1 情報を提供することを確認します。
  2. 以前に MetaTrader 内で使用した保護ターゲットと一致するように pip 距離を構成します。
  3. ポジションが有利になったときに利益をロックする保護が必要な場合は、損益分岐点モジュールを有効にします。即座に損益分岐点を得るには、トリガーをゼロのままにしておきます。
  4. サイド (ロングまたはショート) の方向を自由に制御したい場合は、そのサイドの管理を無効にします。
  5. ログ管理アクションがアクティブなときにログ出力を監視し、注文が期待どおりに作成または調整されていることを確認します。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Manual Position Tracking Panel strategy: MFI crossover.
/// Buys when MFI crosses above 20 (oversold exit), sells when crosses below 80 (overbought exit).
/// </summary>
public class ManualPositionTrackingPanelStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _prevMfi;
	private int _candlesSinceTrade;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int Period { get => _period.Value; set => _period.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public ManualPositionTrackingPanelStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_period = Param(nameof(Period), 14)
			.SetGreaterThanZero()
			.SetDisplay("Period", "MFI period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevMfi = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevMfi = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrev = false;
		var mfi = new MoneyFlowIndex { Length = Period };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(mfi, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_hasPrev)
		{
			if (_prevMfi < 15 && mfiValue >= 15 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (_prevMfi > 85 && mfiValue <= 85 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevMfi = mfiValue;
		_hasPrev = true;
	}
}