テスト設定

このセクションでは、取引ストラテジーをテストするための HistoryEmulationConnector の主な設定について説明します。

基本エミュレーター設定

市場データサブスクリプション

ストラテジーを正しくテストするには、必要な市場データ型へのサブスクリプションを設定する必要があります。ストラテジーをローソク足でテストする場合でも、正しい取引エミュレーションのためにはティック取引へのサブスクリプションが必要です。

// ティック取引へのサブスクリプションを作成
var tickSubscription = new Subscription(DataType.Ticks, security);
_connector.Subscribe(tickSubscription);

ストラテジーが板データを必要とする場合:

// 板へのサブスクリプションを作成
var depthSubscription = new Subscription(DataType.MarketDepth, security);
_connector.Subscribe(depthSubscription);

テスト用の板生成

履歴板が存在しないものの、ストラテジーテストに必要な場合は、板生成を有効にできます。

// トレンド挙動を持つ板ジェネレーターを作成
var mdGenerator = new TrendMarketDepthGenerator(security.ToSecurityId());

// ジェネレーターにサブスクリプションメッセージを送信
_connector.MarketDataAdapter.SendInMessage(new GeneratorMessage
{
	IsSubscribe = true,
	Generator = mdGenerator
});

板ジェネレーター設定

  • 板更新間隔(MarketDataGenerator.Interval) - 板は各取引の前に生成されるため、更新はティック取引の到着より頻繁にはできません。
mdGenerator.Interval = TimeSpan.FromSeconds(1);
mdGenerator.MaxAsksDepth = 1; 
mdGenerator.MaxBidsDepth = 1;
  • 板内の現実的なレベル数量を取得するには、MarketDepthGenerator.UseTradeVolume オプションを使用できます。このオプションは、生成される取引数量から最良気配の数量を取得します。
mdGenerator.UseTradeVolume = true;
mdGenerator.MinVolume = 1;
mdGenerator.MaxVolume = 1;
  • スプレッド設定 - 生成される最小スプレッドは Security.PriceStep に等しくなります。ローソク足から生成する際にスプレッドが広くなりすぎないよう、最良気配間のスプレッドを 5 価格ステップより大きく生成しないことをお勧めします。
mdGenerator.MinSpreadStepCount = 1;
mdGenerator.MaxSpreadStepCount = 5;

包括的なテスト設定例

// 履歴接続を作成
var connector = new HistoryEmulationConnector();

// 基本パラメーターを設定
connector.MarketTimeChangedInterval = TimeSpan.FromSeconds(10);
connector.EmulationAdapter.Emulator.Settings.Latency = TimeSpan.FromMilliseconds(100);
connector.EmulationAdapter.Emulator.Settings.MatchOnTouch = false;

// 履歴データを読み込む
var storage = new StorageRegistry();
var security = new Security { Id = "AAPL", PriceStep = 0.01m };

// ローソク足へのサブスクリプションを作成
var candleSubscription = new Subscription(
	TimeSpan.FromMinutes(5).TimeFrame(),
	security)
{
	MarketData =
	{
		From = DateTime.Today.Subtract(TimeSpan.FromDays(30)),
		To = DateTime.Today,
		BuildMode = MarketDataBuildModes.Load
	}
};
connector.Subscribe(candleSubscription);

// 正しいエミュレーションのためにティックへのサブスクリプションを作成
var tickSubscription = new Subscription(DataType.Ticks, security);
connector.Subscribe(tickSubscription);

// 板生成を設定
var mdGenerator = new TrendMarketDepthGenerator(security.ToSecurityId())
{
	Interval = TimeSpan.FromSeconds(1),
	MaxAsksDepth = 5,
	MaxBidsDepth = 5,
	UseTradeVolume = true,
	MinVolume = 1,
	MaxVolume = 100,
	MinSpreadStepCount = 1,
	MaxSpreadStepCount = 5
};

connector.MarketDataAdapter.SendInMessage(new GeneratorMessage
{
	IsSubscribe = true,
	Generator = mdGenerator
});

// データ受信を購読
connector.CandleReceived += OnCandleReceived;
connector.TickTradeReceived += OnTickReceived;
connector.OrderBookReceived += OnOrderBookReceived;

// テストを開始
connector.Connect();

イベント処理

private void OnCandleReceived(Subscription subscription, ICandleMessage candle)
{
	// 受信したローソク足を処理
	Console.WriteLine($"ローソク足: {candle.OpenTime}, O:{candle.OpenPrice}, H:{candle.HighPrice}, L:{candle.LowPrice}, C:{candle.ClosePrice}");
}

private void OnTickReceived(Subscription subscription, ITickTradeMessage tick)
{
	// 受信したティックを処理
	Console.WriteLine($"ティック: {tick.ServerTime}, 価格: {tick.Price}, 数量: {tick.Volume}");
}

private void OnOrderBookReceived(Subscription subscription, IOrderBookMessage orderBook)
{
	// IOrderBookMessage の拡張メソッドを使用
	var bestBid = orderBook.GetBestBid();
	var bestAsk = orderBook.GetBestAsk();
	var spreadMiddle = orderBook.GetSpreadMiddle(Security.PriceStep);
	
	// 受信した板を処理
	Console.WriteLine($"板: {orderBook.ServerTime}, 最良買い: {bestBid?.Price}, 最良売り: {bestAsk?.Price}, スプレッド中央: {spreadMiddle}");
	
	// 注文方向によって価格を取得
	var bidPrice = orderBook.GetPrice(Sides.Buy);
	var askPrice = orderBook.GetPrice(Sides.Sell);
	
	Console.WriteLine($"買値: {bidPrice}, 売値: {askPrice}");
}

板データの扱い

IOrderBookMessage として板を扱う場合、次の拡張メソッドを使用できます。

// 最良買気配を取得
var bestBid = orderBook.GetBestBid();

// 最良売気配を取得
var bestAsk = orderBook.GetBestAsk();

// スプレッドの中央を取得
var spreadMiddle = orderBook.GetSpreadMiddle(Security.PriceStep);

// 注文方向によって価格を取得
var price = orderBook.GetPrice(Sides.Buy); // または Sides.Sell、またはスプレッド中央の場合は null

Level1 データを扱う場合も、スプレッドの中央を取得できます。

// Level1 メッセージからスプレッドの中央を取得
var spreadMiddle = level1.GetSpreadMiddle(Security.PriceStep);

これらの拡張メソッドにより、板データへのアクセスが簡単になり、取引所の気配値を扱う際に、より明確で理解しやすいコードを書けるようになります。