文章目录
交易系统:FeatureEngine 交易系统:FeatureEngine 交易系统:FeatureEngine
先来总结一下,交易所侧和客户端侧分别有多少线程
| 进程 | 业务工作线程 | Logger 线程 | 主线程 | 总计 |
|---|---|---|---|---|
交易所 exchange_main | 4 | 5 | 1 | 10 |
每个客户端 trading_main | 3 | 4 | 1 | 8 |
交易所侧的业务工作线程:
| 线程 | 职责 |
|---|---|
OrderServer | 通过 TCPServer 接收客户端订单请求,由 FIFOSequencer 按接收时间排序后送入撮合请求队列;从响应队列读取撮合结果,发送给对应客户端。 |
MatchingEngine | 消费订单请求,维护交易所订单簿并执行撮合;生成客户端订单响应和公开市场行情,写入各自的输出队列。 |
MarketDataPublisher | 消费撮合引擎生成的市场行情,添加行情序号并通过组播发布增量行情;同时将行情转交给快照合成线程。 |
SnapshotSynthesizer | 消费增量行情并维护当前订单簿状态,定期通过组播发布完整快照,供客户端启动或丢包后恢复同步。 |
客户端侧的业务工作线程:
| 线程 | 职责 |
|---|---|
MarketDataConsumer | 接收、处理市场行情,交给交易线程 |
TradeEngine | 更新本地订单簿、计算特征、运行策略,处理订单响应 |
OrderGateway | 向交易所发送订单请求,接收订单响应 |
FeatureEngine 的成员对象
class FeatureEngine {
private:
std::string time_str_;
Common::Logger *logger_ = nullptr;
// 以下全部是本 feature engine 要采用的 feature
double mkt_price_ = Feature_INVALID;
double agg_trade_qty_ratio_ = Feature_INVALID;
}
feature engine 要采用哪些 feature 是和具体策略内容关系很大的事情。书中为了演示,采用 mkt_price 和 agg_trade_qty_ratio_ 两个 feature。这里的 mkt_price 采取了 “fair market price” 的一种算法:
$$mkt_price = \frac{bid_price \times ask_qty + ask_price \times bid_qty} {bid_qty + ask_qty}$$
//??:而生产级交易系统这里是用因子?生产级的流式因子计算引擎就是对于 feature engine 的扩充是不是?
有两种事件可能触发 FeatureEngine 的 feature 计算:订单簿更新和交易,这两种事件分别触发以下的两种回调函数:onOrderBookUpdate 和 onTradeUpdate
onOrderBookUpdate
这个方法在 TradeEngine 持有的订单簿发生变化时调用,计算受到订单簿订单影响的 feature。在本书定义的两个 feature 当中,只有 mkt_price 是受到订单簿影响的(准确点说是只受到 bbo_ 的影响),因此此处只计算 mkt_price 这一个 feature。
auto FeatureEngine::onOrderBookUpdate(TickerId ticker_id, Price price, Side side, MarketOrderBook* book) noexcept {
const auto bbo = book->getBBO();
if (LIKELY(bbo->bid_price_ != Price_INVALID && bbo->ask_price_ != Price_INVALID)) { // bbo 当中的价格有意义
mkt_price_ = (bbo->bid_price_ * bbo->ask_qty_ + bbo->ask_price_ * bbo->bid_qty_) / (bbo->ask_qty_ + bbo->bid_qty_);
}
}
onTradeUpdate
与上面的方法相对,当前方法在发生交易的时候调用。
auto FeatureEngine::onTradeUpdate(const Exchange::MEMarketUpdate* market_update, MarketOrderBook* book) noexcept {
const bbo = book->getBBO();
if (LIKELY(bbo->bid_price_ != Price_INVALID && bbo->ask_price != Price_INVALID)) { // bbo 当中的价格有意义
agg_trade_qty_ratio_ = static_cast<double>(market_update->qty_) / (market_update->side_ == Side::BUY ? bbo->bid_qty_ : bbo->ask_qty_);
}
}
FeatureEngine 可能的扩展
- 独立计算服务
不同的因子对计算量、延迟有不同的要求时,可以按需求分配计算:
| 方式 | 分工 | 适用情况 |
|---|---|---|
| 同步计算 | 交易线程更新订单簿、计算特征、执行策略 | 计算轻、要求严格事件顺序和低延迟 |
| 异步计算 | 计算线程或外部服务更新因子,交易线程接收结果 | 计算较重、跨标的、可容忍一定延迟 |
| 混合计算 | 快速盘口特征同步算,较慢的统计或模型异步算 | 不同特征有不同更新频率和延迟要求 |
- 扩展因子
- 可以使用更多元的数据来计算因子,包括历史数据、订单簿数据
- 引入机器学习评分
- 由独立的线程采取已经训练好参数的机器学习/深度学习模型,直接加载参数
- 加载 FeatureEngine 算好的因子,得到评分
- 管理计算依赖
- 将因子拆成算子,按 DAG 顺序更新,共享中间结果,避免重复计算
- 也就是,计算引擎保持由状态,维护
还有很多。我想这一块“计算什么因子、用什么模型来评分”就是量化研究的重点