1use std::collections::{BTreeMap, btree_map::{Entry}};
2use anyhow::anyhow;
3use tracing::instrument;
4use crate::order_book::types::{BookDepth, EngineCancelOrder, EngineModifyOrder, ModifyOutcome, OrderNode, PriceLevel, PriceLevelDepth};
5
6#[derive(Debug)]
7pub struct OrderBook{
8 pub ask : HalfBook,
9 pub bid : HalfBook
10}
11impl OrderBook {
12 pub fn new () -> Self{
13 Self { ask : HalfBook::new(), bid : HalfBook::new() }
14 }
15
16 #[instrument( name = "create_buy_order",
18 skip(self),
19 fields(
20 order_id = %order_id,
21 price = resting_order.market_limit
22 ),
23 err
24 )]
25 pub fn create_buy_order(&mut self, order_id : u64, resting_order : OrderNode) -> Result<usize, anyhow::Error>{
26
27 let mut order = resting_order;
28 let order_quantity = order.current_quantity;
29 let price = order.market_limit;
30
31 match self.bid.price_map.entry(price){ Entry::Occupied(mut entry) => {
33 let price_level = entry.get_mut();
34 if price_level.total_quantity == 0 || price_level.head == None || price_level.tail == None{
35 entry.remove();
36 } else {
37 order.prev = price_level.tail;
38 if let Some(free_index) = self.bid.free_list.pop(){
39 self.bid.order_pool[free_index] = Some(order);
40 let prev_tail_idx = price_level.tail.unwrap();
41 price_level.tail = Some(free_index);
42 price_level.total_quantity += order_quantity;
43 price_level.order_count += 1;
44 if let Some(prev_order) = self.bid.order_pool.get_mut(prev_tail_idx).unwrap(){
45 prev_order.next = Some(free_index);
46 };
47 return Ok(free_index);
48 }
49 else {
50 self.bid.order_pool.push(Some(order));
51 let new_tail = self.bid.order_pool.len() - 1;
52 let pre_tail_idx = price_level.tail.unwrap();
53 price_level.tail = Some(new_tail);
54 price_level.total_quantity += order_quantity;
55 price_level.order_count += 1;
56 if let Some(prev_order) = self.bid.order_pool.get_mut(pre_tail_idx).unwrap(){
57 prev_order.next = Some(new_tail);
58 };
59 return Ok(new_tail);
60 }
61 }
62 }
63 Entry::Vacant(_) => {
64 }
66 }
67
68 let mut new_price_level = PriceLevel{
69 head : None,
70 tail : None,
71 order_count : 0,
72 total_quantity : 0
73 };
74 if let Some(free_index) = self.bid.free_list.pop(){
75 self.bid.order_pool[free_index] = Some(order);
76 new_price_level.head = Some(free_index);
77 new_price_level.tail = Some(free_index);
78 new_price_level.order_count += 1;
79 new_price_level.total_quantity += order_quantity;
80 self.bid.price_map.entry(price).or_insert(new_price_level);
81 return Ok(free_index)
82 }
83 self.bid.order_pool.push(Some(order));
84 let new_index = self.bid.order_pool.len()-1;
85 new_price_level.head = Some(new_index);
86 new_price_level.tail = Some(new_index);
87 new_price_level.order_count += 1;
88 new_price_level.total_quantity += order_quantity;
89 self.bid.price_map.entry(price).or_insert(new_price_level);
90
91 Ok(new_index)
92 }
93
94 #[instrument(
95 name = "create_sell_order",
96 skip(self),
97 fields(
98 order_id = %order_id,
99 price = resting_order.market_limit
100 ),
101 err
102 )]
103 pub fn create_sell_order(&mut self, order_id : u64, resting_order : OrderNode) -> Result<usize, anyhow::Error>{
104 let mut order = resting_order;
105 let order_quantity = order.current_quantity;
106 let price = order.market_limit;
107
108 match self.ask.price_map.entry(price){
109 Entry::Occupied(mut entry) => {
110 let price_level = entry.get_mut();
111 if price_level.total_quantity == 0 || price_level.head == None || price_level.tail == None{
112 entry.remove();
113 }else {
114 order.prev = price_level.tail;
115 if let Some(free_index) = self.ask.free_list.pop(){
116 self.ask.order_pool[free_index] = Some(order);
117 let prev_tail_idx = price_level.tail.unwrap();
118 price_level.tail = Some(free_index);
119 price_level.total_quantity += order_quantity;
120 price_level.order_count += 1;
121 if let Some(prev_order) = self.ask.order_pool.get_mut(prev_tail_idx).unwrap(){
122 prev_order.next = Some(free_index);
123 };
124 return Ok(free_index);
125 }
126 else {
127 self.ask.order_pool.push(Some(order));
128 let new_tail = self.ask.order_pool.len() - 1;
129 let prev_tail_idx = price_level.tail.unwrap();
130 price_level.tail = Some(new_tail);
131 price_level.total_quantity += order_quantity;
132 price_level.order_count += 1;
133 if let Some(prev_order) = self.ask.order_pool.get_mut(prev_tail_idx).unwrap(){
134 prev_order.next = Some(new_tail);
135 };
136 return Ok(new_tail);
137 }
138 }
139 }
140 Entry::Vacant(_) => {
141 }
143 }
144
145 let mut new_price_level = PriceLevel{
146 head : None,
147 tail : None,
148 order_count : 0,
149 total_quantity : 0
150 };
151 if let Some(free_index) = self.ask.free_list.pop(){
152 self.ask.order_pool[free_index] = Some(order);
153 new_price_level.head = Some(free_index);
154 new_price_level.tail = Some(free_index);
155 new_price_level.order_count += 1;
156 new_price_level.total_quantity += order_quantity;
157 self.ask.price_map.entry(price).or_insert(new_price_level);
158 return Ok(free_index)
159 }
160 self.ask.order_pool.push(Some(order));
161 let new_index = self.ask.order_pool.len()-1;
162 new_price_level.head = Some(new_index);
163 new_price_level.tail = Some(new_index);
164 new_price_level.order_count += 1;
165 new_price_level.total_quantity += order_quantity;
166 self.ask.price_map.entry(price).or_insert(new_price_level);
167
168 Ok(new_index)
169 }
170
171 #[instrument(
172 name = "cancel_order",
173 skip(self),
174 fields(
175 order_id = %order_id
176 ),
177 err
178 )]
179 pub fn cancel_order(&mut self, order_id : u64, order : EngineCancelOrder) -> Result<(), anyhow::Error>{
180 if order.is_buy_side {
181 let (prev, next, old_price, old_quantity) = {
182 match self.bid.order_pool[order.order_index].as_ref(){
183 Some(node) => {
184 (node.prev, node.next, node.market_limit, node.current_quantity)
185 }
186 None => {
187 return Err(anyhow!("order node doesn't exist at index for cancellation"));
188 }
189 }
190 };
191 if let Some(price_level) = self.bid.price_map.get_mut(&old_price){
192
193 if price_level.head.is_some() && price_level.tail.is_some(){
194 if order.order_index == price_level.head.unwrap() && order.order_index == price_level.tail.unwrap(){
195 self.bid.order_pool[order.order_index] = None;
196 price_level.head = None;
197 price_level.tail = None;
198 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
199 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
200 self.bid.free_list.push(order.order_index);
201 return Ok(());
202 }
203 else if order.order_index == price_level.tail.unwrap() {
204 if let Some(prev_index) = prev{
205 if let Some(possible_prev_node) = self.bid.order_pool.get_mut(prev_index){
206 if let Some(prev_node) = possible_prev_node{
207 prev_node.next = None;
208 price_level.tail = Some(prev_index);
209 }
210 }
211 self.bid.order_pool[order.order_index] = None;
212 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
213 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
214 self.bid.free_list.push(order.order_index);
215 return Ok(());
216 } else {
217 return Err(anyhow!("no prev node found for deletion of tail node"));
218 }
219 }
220 else if order.order_index == price_level.head.unwrap() {
221 if let Some(next_index) = next{
222 if let Some(possible_next_node) = self.bid.order_pool.get_mut(next_index){
223 if let Some(next_node) = possible_next_node{
224 next_node.prev = None;
225 price_level.head = Some(next_index);
226 }
227 }
228 self.bid.order_pool[order.order_index] = None;
229 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
230 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
231 self.bid.free_list.push(order.order_index);
232 return Ok(());
233 } else {
234 return Err(anyhow!("no next node found for deletion of head node"));
235 }
236 }
237 else {
238 if let Some(prev_index) = prev{
239 if let Some(possible_prev_node) = self.bid.order_pool.get_mut(prev_index){
240 if let Some(prev_node) = possible_prev_node{
241 prev_node.next = next
242 }
243 }
244 }
245 else {
246 return Err(anyhow!("no prev node found for deletion of middle node"));
247 }
248 if let Some(next_index) = next{
249 if let Some(possible_next_node) = self.bid.order_pool.get_mut(next_index){
250 if let Some(next_node) = possible_next_node{
251 next_node.prev = prev
252 }
253 }
254 }
255 else {
256 return Err(anyhow!("no next node found for deletion of middle node"));
257 }
258 self.bid.order_pool[order.order_index] = None;
259 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
260 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
261 self.bid.free_list.push(order.order_index);
262 return Ok(());
263 }
264 } else {
265 self.bid.price_map.remove(&old_price);
266 return Err(anyhow::anyhow!("head and tail corrupted so deleted"));
267 }
268 } else {
269 return Err(anyhow!("unable to get old price node to perform cancellation"));
270 }
271 } else {
272 let (prev, next, old_price, old_quantity) = {
273 match self.ask.order_pool[order.order_index].as_ref(){
274 Some(node) => {
275 (node.prev, node.next, node.market_limit, node.current_quantity)
276 }
277 None => {
278 return Err(anyhow!("order node doesn't exist at index for cancellation"));
279 }
280 }
281 };
282 if let Some(price_level) = self.ask.price_map.get_mut(&old_price){
283
284 if price_level.head.is_some() && price_level.tail.is_some(){
285 if order.order_index == price_level.head.unwrap() && order.order_index == price_level.tail.unwrap(){
286 self.ask.order_pool[order.order_index] = None;
287 price_level.head = None;
288 price_level.tail = None;
289 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
290 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
291 self.ask.free_list.push(order.order_index);
292 return Ok(());
293 }
294 else if order.order_index == price_level.tail.unwrap() {
295 if let Some(prev_index) = prev{
296 if let Some(possible_prev_node) = self.ask.order_pool.get_mut(prev_index){
297 if let Some(prev_node) = possible_prev_node{
298 prev_node.next = None;
299 price_level.tail = Some(prev_index);
300 }
301 }
302 self.ask.order_pool[order.order_index] = None;
303 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
304 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
305 self.ask.free_list.push(order.order_index);
306 return Ok(());
307 } else {
308 return Err(anyhow!("no prev node found for deletion of tail node"));
309 }
310 }
311 else if order.order_index == price_level.head.unwrap() {
312 if let Some(next_index) = next{
313 if let Some(possible_next_node) = self.ask.order_pool.get_mut(next_index){
314 if let Some(next_node) = possible_next_node{
315 next_node.prev = None;
316 price_level.head = Some(next_index);
317 }
318 }
319 self.ask.order_pool[order.order_index] = None;
320 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
321 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
322 self.ask.free_list.push(order.order_index);
323 return Ok(());
324 } else {
325 return Err(anyhow!("no next node found for deletion of head node"));
326 }
327 }
328 else {
329 if let Some(prev_index) = prev{
330 if let Some(possible_prev_node) = self.ask.order_pool.get_mut(prev_index){
331 if let Some(prev_node) = possible_prev_node{
332 prev_node.next = next
333 }
334 }
335 }
336 else {
337 return Err(anyhow!("no prev node found for deletion of middle node"));
338 }
339 if let Some(next_index) = next{
340 if let Some(possible_next_node) = self.ask.order_pool.get_mut(next_index){
341 if let Some(next_node) = possible_next_node{
342 next_node.prev = prev
343 }
344 }
345 }
346 else {
347 return Err(anyhow!("no next node found for deletion of middle node"));
348 }
349 self.ask.order_pool[order.order_index] = None;
350 price_level.total_quantity = price_level.total_quantity.checked_sub(old_quantity).ok_or(anyhow!("error in subtracting total qty in order cancellation"))?;
351 price_level.order_count = price_level.order_count.checked_sub(1).ok_or(anyhow!("error is subtracting order qty in cancellation"))?;
352 self.ask.free_list.push(order.order_index);
353 return Ok(());
354 }
355 } else {
356 self.ask.price_map.remove(&old_price);
357 return Err(anyhow::anyhow!("head and tail corrupted so deleted"));
358 }
359 } else {
360 return Err(anyhow!("unable to get old price node to perform cancellation"));
361 }
362 }
363 }
364
365 #[instrument(
366 name = "modify_order",
367 skip(self),
368 fields(
369 order_id = %order_id,
370 ),
371 err
372 )]
373 pub fn modify_order(&mut self, order_id : u64, order : EngineModifyOrder) -> Result<Option<ModifyOutcome>, anyhow::Error>{
374 if order.is_buy_side{
375 let (old_initial_qty, old_current_qty, old_price) = {
376 match self.bid.order_pool[order.order_index].as_ref(){
377 Some(node) => {
378 (node.initial_quantity, node.current_quantity, node.market_limit)
379 }
380 None => {
381 return Err(anyhow!("order node not found at index for modification (buy)"));
382 }
383 }
384 };
385 if let Some(new_price) = order.new_price && let Some(new_qty) = order.new_quantity{
386 if new_price != old_price{
387 if let Ok(_) = self.cancel_order(order_id ,EngineCancelOrder { order_index : order.order_index, is_buy_side: order.is_buy_side,}){
388 return Ok(Some(ModifyOutcome::Both {new_price, new_initial_qty: new_qty, old_current_qty }));
389 }
390 }
391 return Ok(None);
392 } else if let Some(new_qty) = order.new_quantity {
393 if new_qty > old_initial_qty{
394 if let Ok(_) = self.cancel_order(order_id ,EngineCancelOrder { order_index : order.order_index, is_buy_side: order.is_buy_side,}){
395 return Ok(Some(ModifyOutcome::Requantized {old_price, new_initial_qty: new_qty, old_current_qty }))
396 }
397 return Ok(None);
398 }
399 else {
400 match self.bid.order_pool[order.order_index].as_mut(){
401 Some(order_node) => {
402 order_node.initial_quantity = new_qty;
403 return Ok(Some(ModifyOutcome::Inplace));
404 }
405 None => {
406 return Err(anyhow!("couldn't find order node to modify qty in-place (buy)"));
407 }
408 }
409 }
410 } else {
411 if let Ok(_) = self.cancel_order(order_id ,EngineCancelOrder { order_index : order.order_index, is_buy_side: order.is_buy_side,}){
412 return Ok(Some(ModifyOutcome::Repriced {new_price : order.new_price.unwrap(), old_initial_qty, old_current_qty }));
413 }
414 return Ok(None);
415 }
416 } else {
417 let (old_initial_qty, old_current_qty, old_price) = {
418 match self.ask.order_pool[order.order_index].as_ref(){
419 Some(node) => {
420 (node.initial_quantity, node.current_quantity, node.market_limit)
421 }
422 None => {
423 return Err(anyhow!("order node not found at index for modification (sell)"));
424 }
425 }
426 };
427
428 if let Some(new_price) = order.new_price && let Some(new_qty) = order.new_quantity{
429 if new_price != old_price{
430 if let Ok(_) = self.cancel_order(order_id ,EngineCancelOrder { order_index : order.order_index, is_buy_side: order.is_buy_side,}){
431 return Ok(Some(ModifyOutcome::Requantized {old_price, new_initial_qty: new_qty, old_current_qty }))
432 }
433 }
434 return Ok(None);
435 } else if let Some(new_qty) = order.new_quantity {
436 if new_qty > old_initial_qty{
437 if let Ok(_) = self.cancel_order(order_id ,EngineCancelOrder { order_index : order.order_index, is_buy_side: order.is_buy_side,}){
438 return Ok(Some(ModifyOutcome::Requantized { old_price, new_initial_qty: new_qty, old_current_qty }))
439 }
440 return Ok(None);
441 }
442 else {
443 match self.ask.order_pool[order.order_index].as_mut(){
444 Some(order_node) => {
445 order_node.initial_quantity = new_qty;
446 return Ok(Some(ModifyOutcome::Inplace));
447 }
448 None => {
449 return Err(anyhow!("couldn't find order node to modify qty in-place (sell)"));
450 }
451 }
452 }
453 }else {
454 if let Ok(_) = self.cancel_order(order_id ,EngineCancelOrder { order_index : order.order_index, is_buy_side: order.is_buy_side,}){
455 return Ok(Some(ModifyOutcome::Repriced { new_price : order.new_price.unwrap(), old_initial_qty, old_current_qty }));
456 }
457 return Ok(None);
458 }
459 }
460 }
461
462 #[instrument(
463 name = "book_depth",
464 skip(self),
465 err
466 )]
467 pub fn depth(&self, levels_count : Option<u32>) -> Result<BookDepth, anyhow::Error>{
468
469 let ask_iter = self.ask.price_map.iter().rev();
470 let bid_iter = self.bid.price_map.iter();
471
472 let ask_depth : Vec<_> = match levels_count {
473 Some(n) => ask_iter.take(n as usize)
474 .map(|(price, price_level)| PriceLevelDepth {
475 price_level : *price,
476 quantity : price_level.total_quantity
477 })
478 .collect(),
479 None => ask_iter.map(|(price, price_level)| PriceLevelDepth {
480 price_level : *price,
481 quantity : price_level.total_quantity
482 }).collect()
483 };
484 let bid_depth = match levels_count {
485 Some(n) => bid_iter.take(n as usize)
486 .map(|(price, price_level)| PriceLevelDepth {
487 price_level : *price,
488 quantity : price_level.total_quantity
489 })
490 .collect(),
491 None => bid_iter.map(|(price, price_level)| PriceLevelDepth {
492 price_level : *price,
493 quantity : price_level.total_quantity
494 }).collect()
495 };
496 Ok(BookDepth { bid_depth, ask_depth })
497 }
498}
499
500#[derive(Debug)]
501pub struct HalfBook{
502 pub price_map : BTreeMap<u32, PriceLevel>,
503 pub order_pool : Vec<Option<OrderNode>>,
504 pub free_list : Vec<usize>, }
506
507impl HalfBook {
508 pub fn new() -> Self{
509 Self { price_map: BTreeMap::new(), order_pool: Vec::new(), free_list: Vec::new()}
510 }
511}