1mod in_memory_order_book_side;
2
3use derive_more::derive::Display;
4use std::cmp::Ordering;
5
6use crate::{
7 __private::Sealed,
8 order::{Order, OrderSide, OrderType, Quantity},
9 prelude::*,
10};
11
12pub use in_memory_order_book_side::InMemoryOrderBookSide;
13
14#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Display)]
16pub enum BookSide {
17 Bids,
19 Asks,
21}
22
23pub trait OrderBookSide: Sealed {
28 fn try_cross(&mut self, order: &Order) -> Result<Matches>;
30
31 fn allocate(&mut self, order: Order);
33}
34
35#[derive(Debug)]
43pub enum Match {
44 FullPartial {
45 existing: FullFill,
46 incoming: PartialFill,
47 },
48 PartialFull {
49 existing: PartialFill,
50 incoming: FullFill,
51 },
52 FullFull {
53 existing: FullFill,
54 incoming: FullFill,
55 },
56}
57
58#[derive(Debug, Copy, Clone)]
60pub struct PartialFill(pub OrderId, Quantity);
61impl PartialFill {
62 pub fn leaves(&self) -> Quantity {
64 self.1
65 }
66}
67
68#[derive(Debug)]
70pub struct FullFill(pub OrderId);
71
72#[derive(Debug)]
74pub struct Matches {
75 pub matches: Vec<Match>,
77 pub remaining_incoming_order: Option<Quantity>,
80}
81
82impl Order {
83 pub fn with_quantity(&self, quantity: Quantity) -> Order {
84 let mut result = self.clone();
85 result.quantity = quantity;
86 result
87 }
88}
89
90impl PartialOrd for Order {
91 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
92 Some(self.cmp(other))
93 }
94}
95
96impl Ord for Order {
97 fn cmp(&self, other: &Self) -> Ordering {
98 use OrderType::*;
99 use Ordering::*;
100
101 match (&self.order_type, &other.order_type) {
102 (Limit(a), Limit(b)) => match self.side {
103 OrderSide::Buy => a.cmp(b),
104 OrderSide::Sell => a.cmp(b).reverse(),
105 }
106 .then_with(|| self.id.cmp(&other.id).reverse()),
107 (Limit(_), Market) => match self.side {
108 OrderSide::Buy => Less,
109 OrderSide::Sell => Greater,
110 },
111 (Market, Limit(_)) => match self.side {
112 OrderSide::Buy => Greater,
113 OrderSide::Sell => Less,
114 },
115 (Market, Market) => self.id.cmp(&other.id).reverse(),
116 }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::order::{OrderId, OrderSide, Symbol};
124 use std::{cmp::Ordering, collections::BinaryHeap, rc::Rc};
125
126 #[test]
127 fn limit_vs_limit_different_prices_orders_by_price() {
128 let low = {
129 let mut o = Order::new(
130 OrderType::Limit(Price::from(100)),
131 Quantity::from(100u64),
132 OrderSide::Buy,
133 Symbol::from("TEST"),
134 );
135 o.id = None;
136 o
137 };
138 let high = {
139 let mut o = Order::new(
140 OrderType::Limit(Price::from(200)),
141 Quantity::from(100u64),
142 OrderSide::Buy,
143 Symbol::from("TEST"),
144 );
145 o.id = None;
146 o
147 };
148
149 assert_eq!(low.cmp(&high), Ordering::Less);
150 assert_eq!(high.cmp(&low), Ordering::Greater);
151 }
152
153 #[test]
154 fn limit_vs_limit_same_price_orders_by_id() {
155 let first = Order::new(
156 OrderType::Limit(Price::from(100)),
157 Quantity::from(100u64),
158 OrderSide::Buy,
159 Symbol::from("TEST"),
160 )
161 .with_id();
162
163 let second = Order::new(
164 OrderType::Limit(Price::from(100)),
165 Quantity::from(100u64),
166 OrderSide::Buy,
167 Symbol::from("TEST"),
168 )
169 .with_id();
170
171 assert_eq!(first.cmp(&second), Ordering::Greater);
172 }
173
174 #[test]
175 fn limit_vs_market_limit_comes_first_on_buy_last_on_sell() {
176 {
177 let limit = Order::new(
178 OrderType::Limit(Price::from(100)),
179 Quantity::from(100u64),
180 OrderSide::Buy,
181 Symbol::from("TEST"),
182 )
183 .with_id();
184 let market = Order::new(
185 OrderType::Market,
186 Quantity::from(100u64),
187 OrderSide::Buy,
188 Symbol::from("TEST"),
189 )
190 .with_id();
191
192 assert_eq!(limit.cmp(&market), Ordering::Less);
193 assert_eq!(market.cmp(&limit), Ordering::Greater);
194 }
195
196 {
197 let limit = Order::new(
198 OrderType::Limit(Price::from(100)),
199 Quantity::from(100u64),
200 OrderSide::Sell,
201 Symbol::from("TEST"),
202 )
203 .with_id();
204 let market = Order::new(
205 OrderType::Market,
206 Quantity::from(100u64),
207 OrderSide::Sell,
208 Symbol::from("TEST"),
209 )
210 .with_id();
211
212 assert_eq!(limit.cmp(&market), Ordering::Greater);
213 assert_eq!(market.cmp(&limit), Ordering::Less);
214 }
215 }
216
217 #[test]
218 fn market_vs_market_orders_by_id_any_side() {
219 {
220 let first = Order::new(
221 OrderType::Market,
222 Quantity::from(100u64),
223 OrderSide::Buy,
224 Symbol::from("TEST"),
225 )
226 .with_id();
227 let second = Order::new(
228 OrderType::Market,
229 Quantity::from(100u64),
230 OrderSide::Buy,
231 Symbol::from("TEST"),
232 )
233 .with_id();
234
235 assert_eq!(first.cmp(&second), Ordering::Greater);
236 assert_eq!(second.cmp(&first), Ordering::Less);
237 }
238 {
239 let first = Order::new(
240 OrderType::Market,
241 Quantity::from(100u64),
242 OrderSide::Sell,
243 Symbol::from("TEST"),
244 )
245 .with_id();
246 let second = Order::new(
247 OrderType::Market,
248 Quantity::from(100u64),
249 OrderSide::Sell,
250 Symbol::from("TEST"),
251 )
252 .with_id();
253
254 assert_eq!(first.cmp(&second), Ordering::Greater);
255 assert_eq!(second.cmp(&first), Ordering::Less);
256 }
257 }
258
259 #[test]
260 fn identical_limit_orders_are_ordered_by_creation_time() {
261 let first = {
262 let mut o = Order::new(
263 OrderType::Limit(Price::from(100)),
264 Quantity::from(100u64),
265 OrderSide::Buy,
266 Symbol::from("TEST"),
267 );
268 o.id = Some(OrderId::default());
269 o
270 }
271 .with_id();
272 let second = {
273 let mut o = Order::new(
274 OrderType::Limit(Price::from(100)),
275 Quantity::from(100u64),
276 OrderSide::Buy,
277 Symbol::from("TEST"),
278 );
279 o.id = Some(OrderId::default());
280 o
281 }
282 .with_id();
283
284 let mut heap = BinaryHeap::new();
285 heap.push(Rc::new(second.clone()));
286 heap.push(Rc::new(first.clone()));
287
288 assert_eq!(first.get_id(), heap.pop().unwrap().get_id());
290 assert_eq!(second.get_id(), heap.pop().unwrap().get_id());
291
292 assert_eq!(first.cmp(&second), Ordering::Greater);
294 }
295
296 #[test]
297 fn identical_market_orders_are_ordered_by_id_creation_time() {
298 {
299 let first = Order::new(
300 OrderType::Market,
301 Quantity::from(100u64),
302 OrderSide::Buy,
303 Symbol::from("TEST"),
304 )
305 .with_id();
306 let second = Order::new(
307 OrderType::Market,
308 Quantity::from(100u64),
309 OrderSide::Buy,
310 Symbol::from("TEST"),
311 )
312 .with_id();
313
314 assert_eq!(first.cmp(&second), Ordering::Greater);
315 }
316
317 {
318 let first = Order::new(
319 OrderType::Market,
320 Quantity::from(100u64),
321 OrderSide::Sell,
322 Symbol::from("TEST"),
323 )
324 .with_id();
325 let second = Order::new(
326 OrderType::Market,
327 Quantity::from(100u64),
328 OrderSide::Sell,
329 Symbol::from("TEST"),
330 )
331 .with_id();
332
333 assert_eq!(first.cmp(&second), Ordering::Greater);
334 }
335 }
336
337 #[test]
338 fn partial_cmp_delegates_to_cmp() {
339 let limit = {
340 let mut o = Order::new(
341 OrderType::Limit(Price::from(100)),
342 Quantity::from(100u64),
343 OrderSide::Buy,
344 Symbol::from("TEST"),
345 );
346 o.id = None;
347 o
348 };
349 let market = {
350 let mut o = Order::new(
351 OrderType::Market,
352 Quantity::from(100u64),
353 OrderSide::Buy,
354 Symbol::from("TEST"),
355 );
356 o.id = None;
357 o
358 };
359
360 assert_eq!(limit.partial_cmp(&market), Some(Ordering::Less));
361 assert_eq!(market.partial_cmp(&limit), Some(Ordering::Greater));
362 }
363
364 #[test]
365 fn partial_cmp_transitivity_property() {
366 let order_a = {
368 let mut o = Order::new(
369 OrderType::Limit(Price::from(50)),
370 Quantity::from(100u64),
371 OrderSide::Buy,
372 Symbol::from("TEST"),
373 );
374 o.id = None;
375 o
376 };
377 let order_b = {
378 let mut o = Order::new(
379 OrderType::Limit(Price::from(100)),
380 Quantity::from(100u64),
381 OrderSide::Buy,
382 Symbol::from("TEST"),
383 );
384 o.id = None;
385 o
386 };
387 let order_c = {
388 let mut o = Order::new(
389 OrderType::Limit(Price::from(150)),
390 Quantity::from(100u64),
391 OrderSide::Buy,
392 Symbol::from("TEST"),
393 );
394 o.id = None;
395 o
396 };
397
398 assert!(order_a < order_b);
399 assert!(order_b < order_c);
400 assert!(order_a < order_c);
401 }
402
403 #[test]
404 fn partial_cmp_sorts_mixed_orders_correctly() {
405 let limit_low = {
406 let mut o = Order::new(
407 OrderType::Limit(Price::from(100)),
408 Quantity::from(100u64),
409 OrderSide::Buy,
410 Symbol::from("TEST"),
411 );
412 o.id = None;
413 o
414 };
415 let limit_high = {
416 let mut o = Order::new(
417 OrderType::Limit(Price::from(200)),
418 Quantity::from(100u64),
419 OrderSide::Buy,
420 Symbol::from("TEST"),
421 );
422 o.id = None;
423 o
424 };
425 let market = {
426 let mut o = Order::new(
427 OrderType::Market,
428 Quantity::from(100u64),
429 OrderSide::Buy,
430 Symbol::from("TEST"),
431 );
432 o.id = None;
433 o
434 };
435
436 let mut orders =
437 [market.clone(), limit_high.clone(), limit_low.clone()];
438 orders.sort_by(|a, b| a.partial_cmp(b).unwrap());
439
440 assert_eq!(orders[0], limit_low);
441 assert_eq!(orders[1], limit_high);
442 assert_eq!(orders[2], market);
443 }
444
445 #[test]
448 fn with_reduced_quantity_basic() {
449 let existing = Order::new(
450 OrderType::Limit(Price::from(100)),
451 Quantity::from(100u64),
452 OrderSide::Buy,
453 Symbol::from("TEST"),
454 );
455 let incoming = Order::new(
456 OrderType::Limit(Price::from(100)),
457 Quantity::from(30u64),
458 OrderSide::Sell,
459 Symbol::from("TEST"),
460 );
461
462 let result = existing.with_reduced_quantity(&incoming.quantity);
463
464 assert_eq!(result.quantity, Quantity::from(70u64));
465 assert_eq!(result.order_type, existing.order_type);
466 assert_eq!(result.side, existing.side);
467 assert_eq!(result.symbol, existing.symbol);
468 }
469}