测试设置

本节描述了用于测试交易策略的 HistoryEmulationConnector 的主要设置。

基本模拟器设置

市场数据订阅

为了进行正确的策略测试,有必要订阅所需的市场数据类型。即使策略是在K线上测试的,为了正确的交易模拟,也需要订阅逐笔交易数据:

// 创建 tick 成交订阅
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个价位的点差,以免从K线生成时,点差过大:
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 };

// 创建 K线订阅
var candleSubscription = new Subscription(
	DataType.TimeFrame(TimeSpan.FromMinutes(5)),
	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)
{
	// 处理收到的K线
	Console.WriteLine($"K线: {candle.OpenTime}, 开:{candle.OpenPrice}, 高:{candle.HighPrice}, 低:{candle.LowPrice}, 收:{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); // or Sides.Sell, or null for the middle of the spread

在处理 Level1 数据时,你也可以获取买卖价差的中间值:

// 从 Level1 消息获取价差中点
var spreadMiddle = level1.GetSpreadMiddle(Security.PriceStep);

这些扩展方法简化了对订单簿数据的访问,并且在处理交易所报价时可以让你的代码更清晰、更易理解。