GitHub で見る

ティックベース銘柄監視戦略

概要

ティックベース銘柄監視戦略はMetaTraderスクリプトscOnTickMarketWatch.mq5の動作を再現します。元のスクリプトはMarket Watchリストを継続的にスキャンし、どの銘柄にも新しいティックが到着するたびにカスタムイベントを発生させ、買値とスプレッド情報を出力します。このC#ポートはその動作をStockSharpの高レベル戦略に変換し、Level1更新をリッスンして戦略ロガーを通じてティック情報をログに記録します。

この戦略は意図的に非取引です。その目的は、同じコネクターに接続された複数の銘柄にわたる受信ティックデータの診断または監視を提供することです。StockSharpのデータサブスクリプションに依存するため、ソリューションはイベント駆動型であり、MQLバージョンのような手動遅延やループを必要としません。

主な機能

  • 戦略のメイン銘柄と、カンマ区切りリストで定義された追加銘柄を監視します。
  • 各銘柄のLevel1データをサブスクライブして、買い/売り更新を取得します。
  • 両側が利用可能な場合にスプレッド(ask - bid)を計算し、詳細情報を英語でログに記録します。
  • ユーザーが指定したリストと同一の内部順序を維持することでMarket Watchインデックスを反映します。
  • 構成されたSecurityProviderでシンボルが解決できない場合に、わかりやすい警告を提供します。

パラメーター

名前 タイプ デフォルト 説明
SymbolsList string "" メインのStrategy.Securityに加えて監視すべき追加銘柄識別子のカンマ区切りリスト(例:AAPL@NASDAQ,MSFT@NASDAQ)。各識別子は現在のSecurityProviderに存在する必要があります。

動作の仕組み

  1. OnStarted中、戦略はすべてのシンボルを解決します。メインのStrategy.Securityは常に最初に追加され、その後にSymbolsListを通じて提供された追加シンボルが続きます。
  2. 解決された各銘柄について、戦略はSubscribeLevel1を呼び出し、Level1ChangeMessage更新を受け取るコールバックをアタッチします。
  3. 各コールバックは更新に関連する価格フィールド(LastTradePriceBestBidPrice、またはBestAskPrice)の少なくとも1つが含まれていることを確認します。
  4. bidはBestBidPriceから取得されます(最良bidが欠落している場合はLastTradePriceにフォールバック)、askはBestAskPriceから取得され、両方の値が存在する場合にスプレッドが計算されます。
  5. ロガーは元のスクリプトと一致するメッセージを出力します:New tick on the symbol <id> index in the list=<index> bid=<bid> spread=<spread>。askが利用できない場合、spreadn/aとして報告されます。
  6. StockSharpがSecurityProviderで要求されたシンボルを見つけられない場合、警告メッセージが発行されてシンボルがスキップされます。

使用手順

  1. 戦略設定UIまたはコードを通じてメイン銘柄(Strategy.Security)を割り当てます。
  2. オプションでSymbolsListパラメーターに追加のカンマ区切り識別子を設定します。順序はログ出力で報告されるインデックスを決定します。
  3. 選択した銘柄のLevel1情報を配信できるデータソースに戦略を接続します。
  4. 戦略を開始します。すぐにLevel1データをサブスクライブし、ティックメッセージのログ記録を開始します。
  5. 戦略ログを確認して受信市場データと計算されたスプレッドを検証します。

MQLバージョンとの注意点と相違点

  • StockSharpバージョンは完全にイベント駆動型です。手動ループやSleep呼び出しはありません;プラットフォームはデータが到着するとコールバックを呼び出します。
  • MQLのSymbolsTotal(true)は、銘柄が監視リストに追加される順序を保持することでエミュレートされます。報告されるインデックスはメイン戦略銘柄のゼロから始まります。
  • MetaTraderのスプレッド値はポイントベースの整数です。StockSharpではスプレッドは小数の価格差として計算されます。
  • カスタムチャートイベントはログエントリに置き換えられます。StockSharp戦略にはすでに柔軟なログサブシステムが含まれているためです。
  • 現在の更新でシンボルにask価格がない場合、スプレッドはn/aとして報告され、不完全なLevel1情報についての明確さを提供します。
  • 戦略は厳密に監視のために設計されており、注文を送信しません。

ログ出力例

New tick on the symbol AAPL@NASDAQ index in the list=0 bid=171.25 spread=0.02
New tick on the symbol MSFT@NASDAQ index in the list=1 bid=324.10 spread=n/a

これらのエントリは、Market Watchリスト内の各追跡銘柄のbidおよびスプレッド情報がどのように報告されるかを示しています。

using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// On Tick Market Watch strategy (simplified).
/// Uses simple price momentum for entries.
/// </summary>
public class OnTickMarketWatchStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public OnTickMarketWatchStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_emaLength = Param(nameof(EmaLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "EMA period", "Indicators");
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, (ICandleMessage candle, decimal emaValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (close > emaValue && Position <= 0)
					BuyMarket();
				else if (close < emaValue && Position >= 0)
					SellMarket();
			})
			.Start();

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