Line data Source code
1 : /**
2 : * @file matching_engine.cpp
3 : * @brief 撮合引擎实现
4 : *
5 : * 实现行情驱动撮合模式:用户订单与CTP行情盘口比对撮合。
6 : */
7 :
8 : #include "app/engine/matching_engine.hpp"
9 : #include "app/manager/risk_manager.hpp"
10 : #include "app/manager/instrument_manager.hpp"
11 : #include "base/logger.hpp"
12 : #include <sstream>
13 : #include <iomanip>
14 : #include <algorithm>
15 :
16 : namespace fix40 {
17 :
18 : namespace {
19 :
20 6 : const char* sideToString(OrderSide side) {
21 6 : return side == OrderSide::BUY ? "Buy" : "Sell";
22 : }
23 :
24 6 : const char* ordTypeToString(OrderType type) {
25 6 : return type == OrderType::MARKET ? "Market" : "Limit";
26 : }
27 :
28 6 : const char* tifToString(TimeInForce tif) {
29 6 : switch (tif) {
30 6 : case TimeInForce::DAY: return "Day";
31 0 : case TimeInForce::GTC: return "GTC";
32 0 : case TimeInForce::IOC: return "IOC";
33 0 : case TimeInForce::FOK: return "FOK";
34 0 : default: return "Unknown";
35 : }
36 : }
37 :
38 : } // anonymous namespace
39 :
40 : // =============================================================================
41 : // 辅助函数:构建拒绝单 ExecutionReport
42 : // =============================================================================
43 :
44 1 : ExecutionReport buildRejectReport(const Order& order, RejectReason reason, const std::string& text) {
45 1 : ExecutionReport report;
46 1 : report.orderID = order.orderID;
47 1 : report.clOrdID = order.clOrdID;
48 1 : report.execID = ""; // 调用方需要设置
49 1 : report.symbol = order.symbol;
50 1 : report.side = order.side;
51 1 : report.orderQty = order.orderQty;
52 1 : report.price = order.price;
53 1 : report.ordType = order.ordType;
54 1 : report.ordStatus = OrderStatus::REJECTED;
55 1 : report.ordRejReason = static_cast<int>(reason);
56 1 : report.text = text;
57 1 : report.transactTime = std::chrono::system_clock::now();
58 1 : report.execTransType = ExecTransType::NEW;
59 1 : return report;
60 0 : }
61 :
62 535 : MatchingEngine::MatchingEngine() = default;
63 :
64 535 : MatchingEngine::~MatchingEngine() {
65 535 : stop();
66 535 : }
67 :
68 15 : void MatchingEngine::start() {
69 15 : if (running_.exchange(true)) {
70 0 : return; // 已经在运行
71 : }
72 :
73 30 : worker_thread_ = std::thread([this]() { run(); });
74 15 : LOG() << "[MatchingEngine] Started";
75 : }
76 :
77 570 : void MatchingEngine::stop() {
78 570 : if (!running_.exchange(false)) {
79 555 : return; // 已经停止
80 : }
81 :
82 : // 提交一个空事件唤醒阻塞的 wait_dequeue
83 15 : event_queue_.enqueue(OrderEvent{});
84 :
85 15 : if (worker_thread_.joinable()) {
86 15 : worker_thread_.join();
87 : }
88 :
89 15 : LOG() << "[MatchingEngine] Stopped";
90 : }
91 :
92 0 : void MatchingEngine::submit(const OrderEvent& event) {
93 0 : event_queue_.enqueue(event);
94 0 : }
95 :
96 11 : void MatchingEngine::submit(OrderEvent&& event) {
97 11 : event_queue_.enqueue(std::move(event));
98 11 : }
99 :
100 15 : void MatchingEngine::run() {
101 26 : while (running_.load()) {
102 : // 先处理行情数据
103 23 : MarketData md;
104 49 : while (marketDataQueue_.try_dequeue(md)) {
105 3 : if (!running_.load()) break;
106 : try {
107 3 : handleMarketData(md);
108 0 : } catch (const std::exception& e) {
109 0 : LOG() << "[MatchingEngine] Exception processing market data: " << e.what();
110 0 : } catch (...) {
111 0 : LOG() << "[MatchingEngine] Unknown exception processing market data";
112 0 : }
113 : }
114 :
115 : // 处理订单事件
116 23 : OrderEvent event;
117 23 : if (event_queue_.wait_dequeue_timed(event, std::chrono::milliseconds(10))) {
118 20 : if (!running_.load()) break;
119 :
120 : try {
121 8 : process_event(event);
122 0 : } catch (const std::exception& e) {
123 0 : LOG() << "[MatchingEngine] Exception processing event: " << e.what();
124 0 : } catch (...) {
125 0 : LOG() << "[MatchingEngine] Unknown exception processing event";
126 0 : }
127 : }
128 23 : }
129 15 : }
130 :
131 8 : void MatchingEngine::process_event(const OrderEvent& event) {
132 8 : switch (event.type) {
133 6 : case OrderEventType::NEW_ORDER:
134 6 : handle_new_order(event);
135 6 : break;
136 1 : case OrderEventType::CANCEL_REQUEST:
137 1 : handle_cancel_request(event);
138 1 : break;
139 0 : case OrderEventType::SESSION_LOGON:
140 0 : handle_session_logon(event);
141 0 : break;
142 1 : case OrderEventType::SESSION_LOGOUT:
143 1 : handle_session_logout(event);
144 1 : break;
145 0 : default:
146 0 : LOG() << "[MatchingEngine] Unknown event type";
147 0 : break;
148 : }
149 8 : }
150 :
151 6 : void MatchingEngine::handle_new_order(const OrderEvent& event) {
152 6 : const Order* orderPtr = event.getOrder();
153 6 : if (!orderPtr) {
154 0 : LOG() << "[MatchingEngine] Invalid NEW_ORDER event: no order data";
155 1 : return;
156 : }
157 :
158 : // 复制订单
159 6 : Order order = *orderPtr;
160 6 : order.orderID = generateOrderID();
161 6 : order.leavesQty = order.orderQty;
162 6 : order.status = OrderStatus::PENDING_NEW;
163 :
164 6 : LOG() << "[MatchingEngine] Processing NewOrderSingle from " << event.sessionID.to_string();
165 6 : LOG() << " ClOrdID: " << order.clOrdID;
166 6 : LOG() << " Symbol: " << order.symbol;
167 6 : LOG() << " Side: " << sideToString(order.side);
168 6 : LOG() << " OrderQty: " << order.orderQty;
169 6 : LOG() << " Price: " << order.price;
170 6 : LOG() << " OrdType: " << ordTypeToString(order.ordType);
171 6 : LOG() << " TimeInForce: " << tifToString(order.timeInForce);
172 :
173 : // userId 由上层 Application 在收到业务消息时完成身份绑定与校验。
174 : // 撮合引擎仍做一次防御性检查,避免产生无法路由或无法归属的订单状态。
175 6 : if (event.userId.empty()) {
176 1 : LOG() << "[MatchingEngine] Order rejected: empty userId";
177 1 : order.status = OrderStatus::REJECTED;
178 1 : auto report = buildRejectReport(order, RejectReason::NONE, "Invalid user identity");
179 1 : report.execID = generateExecID();
180 1 : sendExecutionReport(event.sessionID, report);
181 1 : return;
182 1 : }
183 :
184 : // 记录订单与会话的映射
185 5 : orderSessionMap_[order.clOrdID] = event.sessionID;
186 : // 记录订单与用户ID的映射(用于日志/追踪;资金与持仓更新由上层处理)
187 5 : orderUserMap_[order.clOrdID] = event.userId;
188 :
189 : // 获取行情快照
190 5 : auto snapshotIt = marketSnapshots_.find(order.symbol);
191 5 : MarketDataSnapshot snapshot;
192 5 : if (snapshotIt != marketSnapshots_.end()) {
193 1 : snapshot = snapshotIt->second;
194 : } else {
195 4 : snapshot.instrumentId = order.symbol;
196 : }
197 :
198 : // 尝试立即撮合
199 5 : bool matched = false;
200 5 : double fillPrice = 0.0;
201 :
202 5 : if (order.ordType == OrderType::MARKET) {
203 : // 市价单处理
204 0 : if (order.side == OrderSide::BUY) {
205 0 : if (snapshot.hasAsk()) {
206 0 : matched = true;
207 0 : fillPrice = snapshot.askPrice1;
208 : } else {
209 : // 无对手盘,拒绝市价单
210 0 : LOG() << "[MatchingEngine] Market order rejected: no ask side";
211 0 : order.status = OrderStatus::REJECTED;
212 :
213 0 : auto report = buildRejectReport(order, RejectReason::NO_COUNTER_PARTY, "No counter party (ask side empty)");
214 0 : report.execID = generateExecID();
215 :
216 0 : sendExecutionReport(event.sessionID, report);
217 0 : orderSessionMap_.erase(order.clOrdID); orderUserMap_.erase(order.clOrdID);
218 0 : return;
219 0 : }
220 : } else {
221 0 : if (snapshot.hasBid()) {
222 0 : matched = true;
223 0 : fillPrice = snapshot.bidPrice1;
224 : } else {
225 : // 无对手盘,拒绝市价单
226 0 : LOG() << "[MatchingEngine] Market order rejected: no bid side";
227 0 : order.status = OrderStatus::REJECTED;
228 :
229 0 : auto report = buildRejectReport(order, RejectReason::NO_COUNTER_PARTY, "No counter party (bid side empty)");
230 0 : report.execID = generateExecID();
231 :
232 0 : sendExecutionReport(event.sessionID, report);
233 0 : orderSessionMap_.erase(order.clOrdID); orderUserMap_.erase(order.clOrdID);
234 0 : return;
235 0 : }
236 : }
237 : } else {
238 : // 限价单处理
239 5 : if (order.side == OrderSide::BUY) {
240 5 : if (canMatchBuyOrder(order, snapshot)) {
241 1 : matched = true;
242 1 : fillPrice = snapshot.askPrice1;
243 : }
244 : } else {
245 0 : if (canMatchSellOrder(order, snapshot)) {
246 0 : matched = true;
247 0 : fillPrice = snapshot.bidPrice1;
248 : }
249 : }
250 : }
251 :
252 5 : if (matched) {
253 : // 立即成交
254 1 : order.status = OrderStatus::NEW; // 先设为NEW,executeFill会更新为FILLED
255 1 : executeFill(order, fillPrice, order.orderQty);
256 1 : orderSessionMap_.erase(order.clOrdID); orderUserMap_.erase(order.clOrdID);
257 : } else {
258 : // 挂单等待
259 4 : order.status = OrderStatus::NEW;
260 4 : order.updateTime = std::chrono::system_clock::now();
261 :
262 : // 发送订单确认
263 4 : ExecutionReport report;
264 4 : report.orderID = order.orderID;
265 4 : report.clOrdID = order.clOrdID;
266 4 : report.execID = generateExecID();
267 4 : report.symbol = order.symbol;
268 4 : report.side = order.side;
269 4 : report.orderQty = order.orderQty;
270 4 : report.price = order.price;
271 4 : report.ordType = order.ordType;
272 4 : report.ordStatus = OrderStatus::NEW;
273 4 : report.cumQty = 0;
274 4 : report.avgPx = 0.0;
275 4 : report.leavesQty = order.leavesQty;
276 4 : report.transactTime = order.updateTime;
277 4 : report.execTransType = ExecTransType::NEW;
278 :
279 4 : LOG() << "[MatchingEngine] Order " << order.clOrdID << " acknowledged, pending for market data";
280 4 : sendExecutionReport(event.sessionID, report);
281 :
282 : // 添加到挂单列表
283 4 : addToPendingOrders(order);
284 4 : }
285 6 : }
286 :
287 1 : void MatchingEngine::handle_cancel_request(const OrderEvent& event) {
288 1 : const CancelRequest* req = event.getCancelRequest();
289 1 : if (!req) {
290 0 : LOG() << "[MatchingEngine] Invalid CANCEL_REQUEST event: no request data";
291 0 : return;
292 : }
293 :
294 1 : LOG() << "[MatchingEngine] Processing OrderCancelRequest from " << event.sessionID.to_string();
295 1 : LOG() << " ClOrdID: " << req->clOrdID;
296 1 : LOG() << " OrigClOrdID: " << req->origClOrdID;
297 1 : LOG() << " Symbol: " << req->symbol;
298 :
299 1 : ExecutionReport report;
300 1 : report.clOrdID = req->clOrdID;
301 1 : report.origClOrdID = req->origClOrdID;
302 1 : report.execID = generateExecID();
303 1 : report.symbol = req->symbol;
304 1 : report.transactTime = std::chrono::system_clock::now();
305 :
306 : // 首先尝试从挂单列表中撤单(行情驱动模式)
307 1 : auto canceledOrder = removeFromPendingOrders(req->symbol, req->origClOrdID);
308 :
309 1 : if (!canceledOrder) {
310 : // 如果挂单列表中没有,尝试从传统订单簿中撤单(兼容模式)
311 0 : auto bookIt = orderBooks_.find(req->symbol);
312 0 : if (bookIt != orderBooks_.end()) {
313 0 : canceledOrder = bookIt->second->cancelOrder(req->origClOrdID);
314 : }
315 : }
316 :
317 1 : if (canceledOrder) {
318 : // 撤单成功
319 1 : report.orderID = canceledOrder->orderID;
320 1 : report.side = canceledOrder->side;
321 1 : report.orderQty = canceledOrder->orderQty;
322 1 : report.price = canceledOrder->price;
323 1 : report.ordType = canceledOrder->ordType;
324 1 : report.ordStatus = OrderStatus::CANCELED;
325 1 : report.cumQty = canceledOrder->cumQty;
326 1 : report.avgPx = canceledOrder->avgPx;
327 1 : report.leavesQty = 0;
328 1 : report.execTransType = ExecTransType::NEW; // FIX 4.0: NEW + CANCELED status
329 :
330 1 : LOG() << "[MatchingEngine] Order " << req->origClOrdID << " canceled";
331 :
332 : // 清理映射
333 1 : orderSessionMap_.erase(req->origClOrdID); orderUserMap_.erase(req->origClOrdID);
334 : } else {
335 : // 撤单失败(订单不存在或已成交)
336 0 : report.ordStatus = OrderStatus::REJECTED;
337 0 : report.execTransType = ExecTransType::NEW;
338 0 : report.text = "Order not found or already filled";
339 :
340 0 : LOG() << "[MatchingEngine] Cancel rejected: order " << req->origClOrdID << " not found";
341 : }
342 :
343 1 : sendExecutionReport(event.sessionID, report);
344 1 : }
345 :
346 0 : void MatchingEngine::handle_session_logon(const OrderEvent& event) {
347 0 : LOG() << "[MatchingEngine] Session logged on: " << event.sessionID.to_string();
348 : // 会话登录时可以初始化交易状态
349 0 : }
350 :
351 1 : void MatchingEngine::handle_session_logout(const OrderEvent& event) {
352 1 : LOG() << "[MatchingEngine] Session logged out: " << event.sessionID.to_string();
353 :
354 : // 清理该会话的订单映射(可选:也可以保留用于重连恢复)
355 : // 这里简单处理,不主动撤单
356 1 : }
357 :
358 0 : OrderBook& MatchingEngine::getOrCreateOrderBook(const std::string& symbol) {
359 0 : auto it = orderBooks_.find(symbol);
360 0 : if (it == orderBooks_.end()) {
361 0 : auto [newIt, inserted] = orderBooks_.emplace(
362 0 : symbol, std::make_unique<OrderBook>(symbol));
363 0 : LOG() << "[MatchingEngine] Created OrderBook for " << symbol;
364 0 : return *newIt->second;
365 : }
366 0 : return *it->second;
367 : }
368 :
369 0 : const OrderBook* MatchingEngine::getOrderBook(const std::string& symbol) const {
370 0 : auto it = orderBooks_.find(symbol);
371 0 : if (it != orderBooks_.end()) {
372 0 : return it->second.get();
373 : }
374 0 : return nullptr;
375 : }
376 :
377 8 : void MatchingEngine::sendExecutionReport(const SessionID& sessionID, const ExecutionReport& report) {
378 8 : if (execReportCallback_) {
379 : try {
380 7 : execReportCallback_(sessionID, report);
381 0 : } catch (const std::exception& e) {
382 0 : LOG() << "[MatchingEngine] Exception in ExecutionReport callback: " << e.what();
383 0 : } catch (...) {
384 0 : LOG() << "[MatchingEngine] Unknown exception in ExecutionReport callback";
385 0 : }
386 : } else {
387 1 : LOG() << "[MatchingEngine] No ExecutionReport callback set, report dropped";
388 : }
389 8 : }
390 :
391 8 : std::string MatchingEngine::generateExecID() {
392 8 : std::ostringstream oss;
393 8 : oss << "EXEC-" << std::setfill('0') << std::setw(10) << nextExecID_++;
394 16 : return oss.str();
395 8 : }
396 :
397 6 : std::string MatchingEngine::generateOrderID() {
398 6 : std::ostringstream oss;
399 6 : oss << "ORD-" << std::setfill('0') << std::setw(10) << nextOrderID_++;
400 12 : return oss.str();
401 6 : }
402 :
403 : // =============================================================================
404 : // 行情驱动撮合实现
405 : // =============================================================================
406 :
407 3 : void MatchingEngine::submitMarketData(const MarketData& md) {
408 3 : marketDataQueue_.enqueue(md);
409 3 : }
410 :
411 8 : const MarketDataSnapshot* MatchingEngine::getMarketSnapshot(const std::string& instrumentId) const {
412 8 : auto it = marketSnapshots_.find(instrumentId);
413 8 : if (it != marketSnapshots_.end()) {
414 4 : return &it->second;
415 : }
416 4 : return nullptr;
417 : }
418 :
419 3 : const std::list<Order>* MatchingEngine::getPendingOrders(const std::string& instrumentId) const {
420 3 : auto it = pendingOrders_.find(instrumentId);
421 3 : if (it != pendingOrders_.end()) {
422 3 : return &it->second;
423 : }
424 0 : return nullptr;
425 : }
426 :
427 2 : size_t MatchingEngine::getTotalPendingOrderCount() const {
428 2 : size_t count = 0;
429 4 : for (const auto& [instrumentId, orders] : pendingOrders_) {
430 2 : count += orders.size();
431 : }
432 2 : return count;
433 : }
434 :
435 3 : void MatchingEngine::handleMarketData(const MarketData& md) {
436 3 : std::string instrumentId = md.getInstrumentID();
437 :
438 : // 1. 更新行情快照
439 3 : MarketDataSnapshot& snapshot = marketSnapshots_[instrumentId];
440 3 : snapshot.instrumentId = instrumentId;
441 3 : snapshot.lastPrice = md.lastPrice;
442 3 : snapshot.bidPrice1 = md.bidPrice1;
443 3 : snapshot.bidVolume1 = md.bidVolume1;
444 3 : snapshot.askPrice1 = md.askPrice1;
445 3 : snapshot.askVolume1 = md.askVolume1;
446 3 : snapshot.upperLimitPrice = md.upperLimitPrice;
447 3 : snapshot.lowerLimitPrice = md.lowerLimitPrice;
448 3 : snapshot.updateTime = std::chrono::system_clock::now();
449 :
450 : // 2. 更新合约管理器中的涨跌停价格
451 3 : if (instrumentManager_) {
452 2 : instrumentManager_->updateLimitPrices(instrumentId, md.upperLimitPrice, md.lowerLimitPrice);
453 : }
454 :
455 : // 3. 触发行情更新回调(用于账户价值重算)
456 3 : if (marketDataUpdateCallback_ && md.lastPrice > 0) {
457 2 : marketDataUpdateCallback_(instrumentId, md.lastPrice);
458 : }
459 :
460 : // 4. 遍历该合约的挂单,检查是否可成交
461 3 : auto it = pendingOrders_.find(instrumentId);
462 3 : if (it == pendingOrders_.end() || it->second.empty()) {
463 2 : return;
464 : }
465 :
466 1 : auto& orders = it->second;
467 1 : auto orderIt = orders.begin();
468 :
469 2 : while (orderIt != orders.end()) {
470 1 : Order& order = *orderIt;
471 :
472 : // 尝试撮合
473 1 : if (tryMatch(order, snapshot)) {
474 : // 成交后移除订单
475 1 : orderSessionMap_.erase(order.clOrdID); orderUserMap_.erase(order.clOrdID);
476 1 : orderIt = orders.erase(orderIt);
477 : } else {
478 0 : ++orderIt;
479 : }
480 : }
481 3 : }
482 :
483 1 : bool MatchingEngine::tryMatch(Order& order, const MarketDataSnapshot& snapshot) {
484 1 : bool canMatch = false;
485 1 : double fillPrice = 0.0;
486 :
487 1 : if (order.side == OrderSide::BUY) {
488 1 : canMatch = canMatchBuyOrder(order, snapshot);
489 1 : if (canMatch) {
490 1 : fillPrice = snapshot.askPrice1; // 买单以卖一价成交
491 : }
492 : } else {
493 0 : canMatch = canMatchSellOrder(order, snapshot);
494 0 : if (canMatch) {
495 0 : fillPrice = snapshot.bidPrice1; // 卖单以买一价成交
496 : }
497 : }
498 :
499 1 : if (canMatch) {
500 1 : executeFill(order, fillPrice, order.leavesQty);
501 1 : return true;
502 : }
503 :
504 0 : return false;
505 : }
506 :
507 312 : bool MatchingEngine::canMatchBuyOrder(const Order& order, const MarketDataSnapshot& snapshot) const {
508 : // 买单成交条件:买价 >= CTP卖一价,且卖盘非空
509 312 : if (!snapshot.hasAsk()) {
510 6 : return false;
511 : }
512 :
513 306 : if (order.ordType == OrderType::MARKET) {
514 : // 市价单只要有卖盘就可成交
515 101 : return true;
516 : }
517 :
518 : // 限价单:买价 >= 卖一价
519 205 : return order.price >= snapshot.askPrice1;
520 : }
521 :
522 306 : bool MatchingEngine::canMatchSellOrder(const Order& order, const MarketDataSnapshot& snapshot) const {
523 : // 卖单成交条件:卖价 <= CTP买一价,且买盘非空
524 306 : if (!snapshot.hasBid()) {
525 2 : return false;
526 : }
527 :
528 304 : if (order.ordType == OrderType::MARKET) {
529 : // 市价单只要有买盘就可成交
530 101 : return true;
531 : }
532 :
533 : // 限价单:卖价 <= 买一价
534 203 : return order.price <= snapshot.bidPrice1;
535 : }
536 :
537 2 : void MatchingEngine::executeFill(Order& order, double fillPrice, int64_t fillQty) {
538 : // 计算加权平均成交价(在更新cumQty之前计算)
539 2 : int64_t prevCumQty = order.cumQty;
540 2 : double prevAvgPx = order.avgPx;
541 :
542 : // 更新订单状态
543 2 : order.cumQty += fillQty;
544 2 : order.leavesQty = order.orderQty - order.cumQty;
545 :
546 : // 计算加权平均成交价
547 2 : if (order.cumQty > 0) {
548 : // 加权平均:(旧均价 * 旧数量 + 新价格 * 新数量) / 总数量
549 2 : order.avgPx = (prevAvgPx * prevCumQty + fillPrice * fillQty) / order.cumQty;
550 : }
551 :
552 : // 更新订单状态
553 2 : if (order.leavesQty == 0) {
554 2 : order.status = OrderStatus::FILLED;
555 : } else {
556 0 : order.status = OrderStatus::PARTIALLY_FILLED;
557 : }
558 :
559 2 : order.updateTime = std::chrono::system_clock::now();
560 :
561 : // =========================================================================
562 : // 更新账户和持仓(如果设置了管理器)
563 : // =========================================================================
564 2 : auto sessionIt = orderSessionMap_.find(order.clOrdID);
565 2 : auto userIt = orderUserMap_.find(order.clOrdID);
566 2 : std::string accountId;
567 2 : if (userIt != orderUserMap_.end()) {
568 2 : accountId = userIt->second; // 使用真实的用户ID
569 : }
570 :
571 : // 注意:持仓和保证金的处理由 SimulationApp::handleFill 统一处理
572 : // MatchingEngine 只负责撮合,不直接操作持仓
573 : // 这样可以正确处理开平仓逻辑(买入平空、卖出平多)
574 :
575 : // 发送 ExecutionReport
576 2 : if (sessionIt != orderSessionMap_.end()) {
577 2 : ExecutionReport report;
578 2 : report.orderID = order.orderID;
579 2 : report.clOrdID = order.clOrdID;
580 2 : report.execID = generateExecID();
581 2 : report.symbol = order.symbol;
582 2 : report.side = order.side;
583 2 : report.orderQty = order.orderQty;
584 2 : report.price = order.price;
585 2 : report.ordType = order.ordType;
586 2 : report.ordStatus = order.status;
587 2 : report.cumQty = order.cumQty;
588 2 : report.avgPx = order.avgPx;
589 2 : report.leavesQty = order.leavesQty;
590 2 : report.lastShares = fillQty;
591 2 : report.lastPx = fillPrice;
592 2 : report.transactTime = order.updateTime;
593 2 : report.execTransType = ExecTransType::NEW;
594 :
595 4 : LOG() << "[MatchingEngine] Order " << order.clOrdID << " filled: "
596 2 : << fillQty << " @ " << fillPrice
597 2 : << " (cumQty=" << order.cumQty << "/" << order.orderQty << ")";
598 :
599 2 : sendExecutionReport(sessionIt->second, report);
600 2 : }
601 2 : }
602 :
603 4 : void MatchingEngine::addToPendingOrders(const Order& order) {
604 4 : pendingOrders_[order.symbol].push_back(order);
605 4 : LOG() << "[MatchingEngine] Order " << order.clOrdID << " added to pending orders for " << order.symbol;
606 4 : }
607 :
608 1 : std::optional<Order> MatchingEngine::removeFromPendingOrders(const std::string& instrumentId,
609 : const std::string& clOrdID) {
610 1 : auto it = pendingOrders_.find(instrumentId);
611 1 : if (it == pendingOrders_.end()) {
612 0 : return std::nullopt;
613 : }
614 :
615 1 : auto& orders = it->second;
616 1 : for (auto orderIt = orders.begin(); orderIt != orders.end(); ++orderIt) {
617 1 : if (orderIt->clOrdID == clOrdID) {
618 1 : Order removedOrder = *orderIt;
619 1 : orders.erase(orderIt);
620 1 : return removedOrder;
621 1 : }
622 : }
623 :
624 0 : return std::nullopt;
625 : }
626 :
627 : } // namespace fix40
|