1#include "lob/matching/matching_engine.hpp"
15 : orderBook(orderBook) {}
19 std::vector<Execution> out;
28 case OrderEventType::NEW: {
29 const NewOrder& order =
event.getNewOrder();
34 case OrderEventType::CANCEL:
36 throw std::invalid_argument(
"Invalid cancel order ID");
40 case OrderEventType::REDUCE: {
41 const ReduceOrder& reduction =
event.getReduceOrder();
43 throw std::invalid_argument(
"Invalid reduce order ID");
52 throw std::logic_error(
"Unknown order event type");
63 OrderSide orderSide, OrderType orderType) {
64 std::vector<Execution> out;
65 processOrder(orderId, price, quantity, timestamp, orderSide, orderType, out);
71 OrderSide orderSide, OrderType orderType, std::vector<Execution>& out) {
73 matchOrder(orderId, price, quantity, timestamp, orderSide, orderType, out);
90void MatchingEngine::matchOrder(
92 OrderSide orderSide, OrderType orderType, std::vector<Execution>& out) {
94 throw std::invalid_argument(
"Invalid incoming order value");
96 if (orderSide != OrderSide::BUY && orderSide != OrderSide::SELL) {
97 throw std::invalid_argument(
"Invalid incoming order side");
99 if (orderType != OrderType::LIMIT && orderType != OrderType::MARKET) {
100 throw std::invalid_argument(
"Invalid incoming order type");
102 if (orderType == OrderType::LIMIT && !price.
isValid()) {
103 throw std::invalid_argument(
"Limit order requires a valid price");
105 if (orderType == OrderType::MARKET && price.
isValid()) {
106 throw std::invalid_argument(
"Market order must not specify a price");
108 if (orderBook.findOrder(orderId) !=
nullptr) {
109 throw std::logic_error(
"Order with the same OrderId already exists");
112 const SequenceNumber sequenceNumber = sequenceNumberGenerator.generate();
113 const Quantity originalQuantity = quantity;
118 while (remaining > 0) {
119 PriceLevel* level = orderSide == OrderSide::BUY
120 ? orderBook.getBestAsk()
121 : orderBook.getBestBid();
122 if (level ==
nullptr) {
126 const Price bestPrice = level->getPrice();
127 if (orderType == OrderType::LIMIT) {
128 if (orderSide == OrderSide::BUY && price < bestPrice) {
131 if (orderSide == OrderSide::SELL && price > bestPrice) {
136 Order* restingOrder = level->getHeadOrder();
137 if (restingOrder ==
nullptr) {
138 throw std::logic_error(
"Non-empty price level has no head order");
141 const std::uint64_t restingRemaining =
142 restingOrder->getRemainingQuantity().getQuantity();
143 const std::uint64_t executionValue =
144 std::min(remaining, restingRemaining);
145 const Quantity executionQuantity{executionValue};
147 out.emplace_back(orderId, restingOrder->getOrderId(),
148 restingOrder->getPrice(), executionQuantity);
150 remaining -= executionValue;
151 restingOrder->reduceRemainingQuantity(executionQuantity);
156 if (restingOrder->isFullyFilled()) {
157 orderBook.removeOrder(restingOrder);
159 level->reduceTotalQuantity(executionQuantity);
163 if (remaining > 0 && orderType == OrderType::LIMIT) {
164 orderBook.addRestingRemainder(
165 orderId, price, originalQuantity, Quantity{remaining}, timestamp,
166 orderSide, OrderType::LIMIT, sequenceNumber);
MatchingEngine(OrderBook &orderBook)
Creates an engine that operates on the supplied book.
std::vector< Execution > processOrder(OrderId orderId, Price price, Quantity quantity, Timestamp timestamp, OrderSide orderSide, OrderType orderType)
Processes an incoming order and returns generated executions.
std::vector< Execution > processEvent(const OrderEvent &event)
Dispatches an event before interpreting its payload.
Owns resting limit orders and maintains their book indexes.
Type-safe event-first command for the matching engine.
const CancelOrder & getCancelOrder() const
Returns the CANCEL payload or throws when this is not a CANCEL event.
OrderEventType getEventType() const
Returns the operation represented by the active payload.
Type-safe identifier for an order; zero is reserved as invalid.
bool isValid() const
Returns whether the identifier is nonzero.
Type-safe nonzero price value used for price ordering.
bool isValid() const
Returns whether the price is nonzero.
Type-safe unsigned order quantity; zero represents a filled state.
bool isValid() const
Returns whether the quantity is valid for a submitted order.
std::uint64_t getQuantity() const
Returns the underlying numeric quantity.
Nanoseconds since the Unix epoch; zero is reserved as invalid.
bool isValid() const
Returns whether the timestamp is nonzero.
OrderId orderId
Identifier of the order to remove.
Payload for accepting a new order.
Quantity quantity
Quantity submitted by the caller.
OrderType orderType
Limit or market execution behavior.
OrderSide orderSide
Buy or sell direction.
Timestamp timestamp
Timestamp assigned to the order.
OrderId orderId
Unique identifier for the new order.
Price price
Limit price, or an invalid price for a market order.
Payload for shrinking a resting order without losing priority.
Quantity newQuantity
Replacement remaining quantity; nonzero and not above the current one.
OrderId orderId
Identifier of the order to shrink.