-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathengine.cpp
More file actions
144 lines (133 loc) · 4.61 KB
/
engine.cpp
File metadata and controls
144 lines (133 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "engine.hpp"
#include <functional>
#include <optional>
#include <stdexcept>
// This is an example correct implementation
// It is INTENTIONALLY suboptimal
// You are encouraged to rewrite as much or as little as you'd like
// Templated helper to process matching orders.
// The Condition predicate takes the price level and the incoming order price
// and returns whether the level qualifies.
template <typename OrderMap, typename Condition>
uint32_t process_orders(Order &order, OrderMap &ordersMap, Condition cond) {
uint32_t matchCount = 0;
auto it = ordersMap.begin();
while (it != ordersMap.end() && order.quantity > 0 &&
(it->first == order.price || cond(it->first, order.price))) {
auto &ordersAtPrice = it->second;
for (auto orderIt = ordersAtPrice.begin();
orderIt != ordersAtPrice.end() && order.quantity > 0;) {
QuantityType trade = std::min(order.quantity, orderIt->quantity);
order.quantity -= trade;
orderIt->quantity -= trade;
++matchCount;
if (orderIt->quantity == 0)
orderIt = ordersAtPrice.erase(orderIt);
else
++orderIt;
}
if (ordersAtPrice.empty())
it = ordersMap.erase(it);
else
++it;
}
return matchCount;
}
uint32_t match_order(Orderbook &orderbook, const Order &incoming) {
uint32_t matchCount = 0;
Order order = incoming; // Create a copy to modify the quantity
if (order.side == Side::BUY) {
// For a BUY, match with sell orders priced at or below the order's price.
matchCount = process_orders(order, orderbook.sellOrders, std::less<>());
if (order.quantity > 0)
orderbook.buyOrders[order.price].push_back(order);
} else { // Side::SELL
// For a SELL, match with buy orders priced at or above the order's price.
matchCount = process_orders(order, orderbook.buyOrders, std::greater<>());
if (order.quantity > 0)
orderbook.sellOrders[order.price].push_back(order);
}
return matchCount;
}
// Templated helper to cancel an order within a given orders map.
template <typename OrderMap>
bool modify_order_in_map(OrderMap &ordersMap, IdType order_id,
QuantityType new_quantity) {
for (auto it = ordersMap.begin(); it != ordersMap.end();) {
auto &orderList = it->second;
for (auto orderIt = orderList.begin(); orderIt != orderList.end();) {
if (orderIt->id == order_id) {
if (new_quantity == 0)
orderIt = orderList.erase(orderIt);
else {
orderIt->quantity = new_quantity;
return true;
}
} else {
++orderIt;
}
}
if (orderList.empty())
it = ordersMap.erase(it);
else
++it;
}
return false;
}
void modify_order_by_id(Orderbook &orderbook, IdType order_id,
QuantityType new_quantity) {
if (modify_order_in_map(orderbook.buyOrders, order_id, new_quantity))
return;
if (modify_order_in_map(orderbook.sellOrders, order_id, new_quantity))
return;
}
template <typename OrderMap>
std::optional<Order> lookup_order_in_map(OrderMap &ordersMap, IdType order_id) {
for (const auto &[price, orderList] : ordersMap) {
for (const auto &order : orderList) {
if (order.id == order_id) {
return order;
}
}
}
return std::nullopt;
}
uint32_t get_volume_at_level(Orderbook &orderbook, Side side,
PriceType quantity) {
uint32_t total = 0;
if (side == Side::BUY) {
auto buy_orders = orderbook.buyOrders.find(quantity);
if (buy_orders == orderbook.buyOrders.end()) {
return 0;
}
for (const auto &order : buy_orders->second) {
total += order.quantity;
}
} else if (side == Side::SELL) {
auto sell_orders = orderbook.sellOrders.find(quantity);
if (sell_orders == orderbook.sellOrders.end()) {
return 0;
}
for (const auto &order : sell_orders->second) {
total += order.quantity;
}
}
return total;
}
// Functions below here don't need to be performant. Just make sure they're
// correct
Order lookup_order_by_id(Orderbook &orderbook, IdType order_id) {
auto order1 = lookup_order_in_map(orderbook.buyOrders, order_id);
auto order2 = lookup_order_in_map(orderbook.sellOrders, order_id);
if (order1.has_value())
return *order1;
if (order2.has_value())
return *order2;
throw std::runtime_error("Order not found");
}
bool order_exists(Orderbook &orderbook, IdType order_id) {
auto order1 = lookup_order_in_map(orderbook.buyOrders, order_id);
auto order2 = lookup_order_in_map(orderbook.sellOrders, order_id);
return (order1.has_value() || order2.has_value());
}
Orderbook *create_orderbook() { return new Orderbook; }