GitHub で見る

シンボルスワップ戦略

シンボル スワップ ストラテジー は、MetaTrader 5 ユーティリティ「シンボル スワップ」の StockSharp ポートです。オリジナルの MQL5 プログラムは、トレーダーが任意のティッカーを入力できるパネルを開き、現在のチャートをそのシンボルに即座に切り替え、最新の時間、OHLC 価格、ティックボリューム、スプレッドを含むコンパクトなデータウィンドウを監視します。この C# 変換は、StockSharp の高レベルのサブスクリプション API にのみ依存しながら、同じ責任を維持します。

行動

  1. 戦略の開始時に、監視する銘柄が決定されます。最初に WatchedSecurityId を試行します。フィールドが空の場合は、ランチャーで設定されている Strategy.Security に戻ります。
  2. 選択した CandleType のローソク足データは、SubscribeCandles(...) を通じてストリーミングされます。完成したバーは、パネルに表示される始値、高値、安値、終値、およびティックのボリュームを提供します。
  3. リアルタイムの最良買値/売値は SubscribeLevel1(...) 経由で届きます。スプレッドは、MQL データ ウィンドウを反映するために、相場が更新されるたびに再計算されます。
  4. フォーマットされたブロックは戦略ログ (OutputMode = Log) に書き込まれるか、DrawText(...) を使用してチャート (OutputMode = Chart) にレンダリングされ、MetaTrader からフローティング パネルが再作成されます。
  5. 実行中に SwapSecurity("TICKER") を呼び出すと、SecurityProvider.LookupById を通じて新しいセキュリティが解決され、ローソク足とレベル 1 フィードの両方が要求された商品にシームレスに再サブスクライブされます。

この戦略は情報提供のみを目的としています。注文はしません。マーケットダッシュボードとしてスタンドアロンで実行することも、他の取引ボットと並行して実行することもできます。

パラメーター

名前 説明 デフォルト
CandleType OHLC とティックボリュームデータの構築に使用されるローソク足のサブスクリプションを定義する時間枠。 TimeFrame(1 minute)
WatchedSecurityId オプションの機器識別子。 Strategy.Security を使用するには、空のままにしておきます。
OutputMode 情報ブロックのレンダリング先。 Chart (価格付近のオーバーレイ) または Log (戦略ログ) のいずれかを選択します。 Chart

パブリックメソッド

方法 説明
SwapSecurity(string securityId) アクティブな SecurityProvider を通じて提供されたティッカーを解決し、すぐにパネルをそのシンボルに切り替えます。このメソッドは複数回呼び出すことができます。各呼び出しでは、新しいフィードを追加する前に、以前のキャンドル/レベル 1 サブスクリプションがクリアされます。

使用上の注意

  • コネクタが要求された識別子を公開していることを確認してください。それ以外の場合、SecurityProvider.LookupById は例外をスローします。
  • OutputMode = Chart の場合、ストラテジーは自動的にチャート領域を作成し、登録されたローソク足を描画し、ステータス ブロックをオーバーレイします。ログ モードの場合は、テキスト更新のみが生成されます。
  • ティックの量はローソク足の TotalVolume と等しくなります。これにより、MetaTrader はバーごとのティック数を報告します。
  • スプレッドは、ベストビッドとベストアスクの両方が利用可能な場合にのみ表示されます。それ以外の場合、フィールドには n/a が表示されます。

変換の詳細

  • MetaTrader タイマー ループは StockSharp サブスクリプションに置き換えられます。ローソク足は完成したバーごとに 1 回トリガーされ、レベル 1 相場はスプレッドをリアルタイムで更新します。
  • MQL パネルのラベルは、単一の複数行のテキスト ブロックで表されます。テキストでは、元のツールの正確な順序 (時間、期間、シンボル、終値、始値、高値、安値、ティックボリューム、スプレッド) が使用されています。
  • ランタイム シンボル スワップでは、手動による Market Watch 管理はもう必要ありません。この戦略は、StockSharp セキュリティ プロバイダーを介して商品を直接解決します。
  • 高レベルの API 呼び出しのみが使用されます (SubscribeCandlesSubscribeLevel1DrawTextAddInfo)。リポジトリのコーディング ルールを満たすため、手動のインジケーターの計算や直接のコネクタ操作はありません。
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Market monitoring strategy that tracks price metrics and trades on significant
/// spread changes. Simplified from the MetaTrader "Symbol Swap" display panel.
/// </summary>
public class SymbolSwapStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<decimal> _spreadThreshold;

	private SimpleMovingAverage _sma;
	private decimal _entryPrice;

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

	/// <summary>
	/// SMA period for trend detection.
	/// </summary>
	public int SmaPeriod
	{
		get => _smaPeriod.Value;
		set => _smaPeriod.Value = value;
	}

	/// <summary>
	/// Price deviation threshold for entry signals.
	/// </summary>
	public decimal SpreadThreshold
	{
		get => _spreadThreshold.Value;
		set => _spreadThreshold.Value = value;
	}

	/// <summary>
	/// Initializes strategy parameters.
	/// </summary>
	public SymbolSwapStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle series for signals", "General");

		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "Moving average period", "Indicators");

		_spreadThreshold = Param(nameof(SpreadThreshold), 3m)
			.SetGreaterThanZero()
			.SetDisplay("Spread Threshold", "Price deviation from SMA to trigger entry", "Signals");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_sma = null;
		_entryPrice = 0m;
	}

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

		_sma = new SimpleMovingAverage { Length = SmaPeriod };

		SubscribeCandles(CandleType)
			.Bind(_sma, ProcessCandle)
			.Start();
	}

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

		if (!IsFormed)
			return;

		var price = candle.ClosePrice;

		// Exit on mean reversion
		if (Position != 0 && _entryPrice > 0m)
		{
			var pnl = Position > 0
				? price - _entryPrice
				: _entryPrice - price;

			// Exit on profit or loss threshold
			if (pnl >= SpreadThreshold || pnl <= -SpreadThreshold * 2m)
			{
				if (Position > 0)
					SellMarket(Math.Abs(Position));
				else
					BuyMarket(Math.Abs(Position));

				_entryPrice = 0m;
				return;
			}
		}

		// Entry on deviation
		if (Position == 0)
		{
			var deviation = price - smaValue;

			if (deviation > SpreadThreshold)
			{
				SellMarket();
				_entryPrice = price;
			}
			else if (deviation < -SpreadThreshold)
			{
				BuyMarket();
				_entryPrice = price;
			}
		}
	}
}