From 7ee5eedb48559a8f0c961568cdcf07e647c60036 Mon Sep 17 00:00:00 2001 From: IFFranciscoME Date: Sun, 22 Sep 2024 21:44:02 -0600 Subject: [PATCH 1/8] TOB data --- atelier/examples/ob_metrics.rs | 5 ++++ atelier/src/data/market.rs | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/atelier/examples/ob_metrics.rs b/atelier/examples/ob_metrics.rs index e8e083e..474756d 100644 --- a/atelier/examples/ob_metrics.rs +++ b/atelier/examples/ob_metrics.rs @@ -12,6 +12,10 @@ fn main() { // Generate a synthetic orderbook for testing let i_ob = Orderbook::synthetize(bid_price, ask_price, tick_size, n_levels, n_orders); + // get the TOB + let tob_data = i_ob.get_tob(); + println!("TOB: {:?}", tob_data); + // extract tob values let tob_bid: f64 = i_ob.bids[0].price; let tob_ask: f64 = i_ob.asks[0].price; @@ -46,4 +50,5 @@ fn main() { // Compute the VWAP let vwap_value = VWAP::compute(&iter_bids.clone(), &iter_asks.clone(), 1); println!("VWAP: {:?}", vwap_value); + } diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index 9e3340c..88fb38d 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -193,6 +193,52 @@ impl Orderbook { } } + // ------------------------------------------------------ Get the TOB -- // + // ------------------------------------------------------ ----------- -- // + + pub fn get_tob(&self) -> Vec<&f64> { + + let bid_volume = self.bids.get(0).map(|bid| &bid.volume); + let bid_price = self.bids.get(0).map(|bid| &bid.price); + + let ask_price = self.asks.get(0).map(|ask| &ask.price); + let ask_volume = self.asks.get(0).map(|ask| &ask.volume); + + vec![&bid_volume.unwrap_or(&0.0), + &bid_price.unwrap_or(&0.0), + &ask_price.unwrap_or(&0.0), + &ask_volume.unwrap_or(&0.0) + ] + } + + // ----------------------------------------------------- Find a Level -- // + // ----------------------------------------------------- ------------ -- // + + //pub fn find_level(&self, target_price: f64) -> f64 { + // 1.0 + //} + + // --------------------------------------- Retrieve an Existing Level -- // + // --------------------------------------- -------------------------- -- // + + // ----------------------------------------- Delete an Existing Level -- // + // ----------------------------------------- ------------------------ -- // + + // ----------------------------------------------- Insert a New Level -- // + // --------------------------------------------------- -------------- -- // + + // ---------------------------------------------------- Find an Order -- // + // ---------------------------------------------------- ------------- -- // + + // --------------------------------------- Retrieve an Existing Order -- // + // --------------------------------------- -------------------------- -- // + + // ----------------------------------------- Delete an Existing Order -- // + // ----------------------------------------- ------------------------ -- // + + // ----------------------------------------------- Insert a New Order -- // + // ----------------------------------------------- ------------------ -- // + // ---------------------------------------------- Synthetic Orderbook -- // // ------------------------------------------------------------------ -- // From 68db815c783e33ca7d1cba8eaf355a5dab3dd3fc Mon Sep 17 00:00:00 2001 From: IFFranciscoME Date: Mon, 23 Sep 2024 18:18:32 -0600 Subject: [PATCH 2/8] Progress on Orderbook Impl --- atelier/examples/ob_metrics.rs | 64 ++++++++++++++++------------- atelier/src/data/market.rs | 74 +++++++++++++++++++++++++--------- 2 files changed, 91 insertions(+), 47 deletions(-) diff --git a/atelier/examples/ob_metrics.rs b/atelier/examples/ob_metrics.rs index 474756d..5c25bb0 100644 --- a/atelier/examples/ob_metrics.rs +++ b/atelier/examples/ob_metrics.rs @@ -1,4 +1,4 @@ -use atelier::data::market::Orderbook; +use atelier::data::market::{Orderbook, Side}; use atelier::metrics::market::{MarketMetric, Midprice, Spread, VolumeImbalance, VWAP}; fn main() { @@ -6,49 +6,57 @@ fn main() { let bid_price = 50_000.00; let ask_price = 50_100.00; let tick_size = 100.0; - let n_levels = 5; - let n_orders = 2; + let n_levels = 2; + let n_orders = 1; // Generate a synthetic orderbook for testing let i_ob = Orderbook::synthetize(bid_price, ask_price, tick_size, n_levels, n_orders); + // Generated Orderbook + println!("{:?}", i_ob); + + // let find_ob_level = i_ob.find_level(50_200.0); + // println!("{:?}", new_ob_level); + + let content_ob_level = i_ob.retrieve_level(50_200.0); + println!("found:\n {:?}", content_ob_level); + // get the TOB - let tob_data = i_ob.get_tob(); - println!("TOB: {:?}", tob_data); + // let tob_data = i_ob.get_tob(); + // println!("TOB: {:?}", tob_data); // extract tob values - let tob_bid: f64 = i_ob.bids[0].price; - let tob_ask: f64 = i_ob.asks[0].price; + // let tob_bid: f64 = i_ob.bids[0].price; + // let tob_ask: f64 = i_ob.asks[0].price; // Compute the Spread - let spread_value = Spread::compute(&tob_bid, &tob_ask, 0); - println!("Spread: {:?}", spread_value); + // let spread_value = Spread::compute(&tob_bid, &tob_ask, 0); + // println!("Spread: {:?}", spread_value); // Compute the Midprice - let midprice_value = Midprice::compute(&tob_bid, &tob_ask, 0); - println!("Midprice: {}", midprice_value); + // let midprice_value = Midprice::compute(&tob_bid, &tob_ask, 0); + // println!("Midprice: {}", midprice_value); // Compute the Volume Imbalance - let iter_bids: Vec = i_ob.bids.clone().into_iter().map(|x| x.volume).collect(); - let iter_asks: Vec = i_ob.asks.clone().into_iter().map(|x| x.volume).collect(); + // let iter_bids: Vec = i_ob.bids.clone().into_iter().map(|x| x.volume).collect(); + // let iter_asks: Vec = i_ob.asks.clone().into_iter().map(|x| x.volume).collect(); - let obimb_value = VolumeImbalance::compute(&iter_bids, &iter_asks, 1); - println!("Volume Imbalance: {:?}", obimb_value); + // let obimb_value = VolumeImbalance::compute(&iter_bids, &iter_asks, 1); + // println!("Volume Imbalance: {:?}", obimb_value); // Compute the Volume-Weighted Average Price - let iter_bids: Vec<_> = i_ob - .bids - .into_iter() - .map(|x| vec![x.price, x.volume]) - .collect(); - let iter_asks: Vec<_> = i_ob - .asks - .into_iter() - .map(|x| vec![x.price, x.volume]) - .collect(); + //let iter_bids: Vec<_> = i_ob + // .bids + // .into_iter() + // .map(|x| vec![x.price, x.volume]) + // .collect(); + // let iter_asks: Vec<_> = i_ob + // .asks + // .into_iter() + // .map(|x| vec![x.price, x.volume]) + // .collect(); // Compute the VWAP - let vwap_value = VWAP::compute(&iter_bids.clone(), &iter_asks.clone(), 1); - println!("VWAP: {:?}", vwap_value); - + // let vwap_value = VWAP::compute(&iter_bids.clone(), &iter_asks.clone(), 1); + // println!("VWAP: {:?}", vwap_value); } diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index 88fb38d..6f7ada9 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -1,3 +1,5 @@ +use rand_distr::num_traits::ToPrimitive; + use crate::simulation::randomizer::randomize_order; #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] @@ -11,7 +13,7 @@ pub enum OrderType { Market, Limit, } - +use std::any::type_name_of_val; // ---------------------------------------------------------------- ORDER -- // // ------------------------------------------------------------------------- // @@ -195,32 +197,66 @@ impl Orderbook { // ------------------------------------------------------ Get the TOB -- // // ------------------------------------------------------ ----------- -- // - + pub fn get_tob(&self) -> Vec<&f64> { - - let bid_volume = self.bids.get(0).map(|bid| &bid.volume); - let bid_price = self.bids.get(0).map(|bid| &bid.price); - - let ask_price = self.asks.get(0).map(|ask| &ask.price); - let ask_volume = self.asks.get(0).map(|ask| &ask.volume); - - vec![&bid_volume.unwrap_or(&0.0), - &bid_price.unwrap_or(&0.0), - &ask_price.unwrap_or(&0.0), - &ask_volume.unwrap_or(&0.0) - ] + let bid_volume = self.bids.get(0).map(|bid| &bid.volume).unwrap_or(&0.0); + let bid_price = self.bids.get(0).map(|bid| &bid.price).unwrap_or(&0.0); + let ask_price = self.asks.get(0).map(|ask| &ask.price).unwrap_or(&0.0); + let ask_volume = self.asks.get(0).map(|ask| &ask.volume).unwrap_or(&0.0); + vec![&bid_volume, &bid_price, &ask_price, &ask_volume] } - + // ----------------------------------------------------- Find a Level -- // // ----------------------------------------------------- ------------ -- // - - //pub fn find_level(&self, target_price: f64) -> f64 { - // 1.0 - //} + + pub fn find_level(&self, level_price: f64) -> Result { + // -1 : -n for indexes within the bid side + // +1 : +n for indexes within the ask side + // 0 : level does not exist + + if level_price <= self.bids[0].price { + let mut i_level: i32 = 0; + + for i_bid in &self.bids { + i_level -= 1; + if level_price == i_bid.price { + return Ok(i_level); + } + } + } + + if level_price >= self.asks[0].price { + let mut i_level: i32 = 0; + + for i_ask in &self.asks { + i_level += 1; + if level_price == i_ask.price { + return Ok(i_level); + } + } + } + Ok(0) + } // --------------------------------------- Retrieve an Existing Level -- // // --------------------------------------- -------------------------- -- // + pub fn retrieve_level(&self, level_price: f64) -> Result { + // Call previous function to see if a Level exists. + let i_level = self.find_level(level_price).unwrap(); + + if i_level < 0 { + let i_level = i_level.abs() - 1; + return Ok(self.bids[i_level as usize].clone()); + } + if i_level > 0 { + let i_level = i_level - 1; + return Ok(self.asks[i_level as usize].clone()); + } else { + Err(0) + } + } + // ----------------------------------------- Delete an Existing Level -- // // ----------------------------------------- ------------------------ -- // From 261a971658ebaddf1a129f9404df4c66aef95ac1 Mon Sep 17 00:00:00 2001 From: IFFranciscoME Date: Mon, 30 Sep 2024 20:56:10 -0600 Subject: [PATCH 3/8] progress on orderbook impl --- atelier/src/data/market.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index 6f7ada9..1102b11 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -1,4 +1,3 @@ -use rand_distr::num_traits::ToPrimitive; use crate::simulation::randomizer::randomize_order; @@ -13,7 +12,7 @@ pub enum OrderType { Market, Limit, } -use std::any::type_name_of_val; + // ---------------------------------------------------------------- ORDER -- // // ------------------------------------------------------------------------- // @@ -242,13 +241,16 @@ impl Orderbook { // --------------------------------------- -------------------------- -- // pub fn retrieve_level(&self, level_price: f64) -> Result { - // Call previous function to see if a Level exists. + // Validate the existence of the level. let i_level = self.find_level(level_price).unwrap(); + // On the Bid side if i_level < 0 { let i_level = i_level.abs() - 1; return Ok(self.bids[i_level as usize].clone()); } + + // On the Ask side if i_level > 0 { let i_level = i_level - 1; return Ok(self.asks[i_level as usize].clone()); @@ -292,7 +294,8 @@ impl Orderbook { /// /// # Returns /// - /// Returns a new `Orderbook` instance populated with synthetic bid and ask levels. + /// Returns a new `Orderbook` instance populated with synthetic bid and + /// ask levels. pub fn synthetize( bid_price: f64, ask_price: f64, From ae90de7f917cc09ffbd78ec99aa9ccb4b7e4d1e6 Mon Sep 17 00:00:00 2001 From: IFFranciscoME Date: Mon, 7 Oct 2024 22:23:54 -0600 Subject: [PATCH 4/8] Progress on Order, Level functionality and Docs --- atelier/examples/ob_metrics.rs | 13 +- atelier/src/data/market.rs | 229 ++++++++++++++++++++++++++++----- tests/test_orderbook.rs | 3 + 3 files changed, 211 insertions(+), 34 deletions(-) diff --git a/atelier/examples/ob_metrics.rs b/atelier/examples/ob_metrics.rs index 5c25bb0..dce9924 100644 --- a/atelier/examples/ob_metrics.rs +++ b/atelier/examples/ob_metrics.rs @@ -1,5 +1,4 @@ -use atelier::data::market::{Orderbook, Side}; -use atelier::metrics::market::{MarketMetric, Midprice, Spread, VolumeImbalance, VWAP}; +use atelier::data::market::{Level, Order, OrderType, Orderbook, Side}; fn main() { // Parameters for synthetic orderbook generation @@ -18,8 +17,14 @@ fn main() { // let find_ob_level = i_ob.find_level(50_200.0); // println!("{:?}", new_ob_level); - let content_ob_level = i_ob.retrieve_level(50_200.0); - println!("found:\n {:?}", content_ob_level); + // let content_ob_level = i_ob.retrieve_level(50_200.0); + // println!("found:\n {:?}", content_ob_level); + + let new_order: Order = Order::new(123, 123, OrderType::Limit, Side::Bids, 50_000.00, 123.123); + + let insert_new = i_ob.insert_level(Side::Bids, 49_900.0, 123.123, vec![new_order]); + + // println!("{:?}", insert_new); // get the TOB // let tob_data = i_ob.get_tob(); diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index 223fe69..d93a965 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -1,11 +1,7 @@ -<<<<<<< HEAD - -use crate::simulation::randomizer::randomize_order; -======= use crate::generators::randomizer::randomize_order; -use rand::distributions::Uniform; +use crate::messages::errors::{OrderError, LevelError}; +use core::f64; use std::time::{SystemTime, UNIX_EPOCH}; ->>>>>>> origin/main #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] pub enum Side { @@ -246,20 +242,27 @@ impl Orderbook { let bid_price = self.bids.get(0).map(|bid| &bid.price).unwrap_or(&0.0); let ask_price = self.asks.get(0).map(|ask| &ask.price).unwrap_or(&0.0); let ask_volume = self.asks.get(0).map(|ask| &ask.volume).unwrap_or(&0.0); + vec![&bid_volume, &bid_price, &ask_price, &ask_volume] } // ----------------------------------------------------- Find a Level -- // // ----------------------------------------------------- ------------ -- // - pub fn find_level(&self, level_price: f64) -> Result { - // -1 : -n for indexes within the bid side - // +1 : +n for indexes within the ask side - // 0 : level does not exist + /// If a level exists, either within the Bids, or, the Asks, + /// it will return the index of it, positive for asks, negative for bids. + /// + /// ## Parameters + /// level_price: f64 = The Level's price to be used as index. + /// + /// ## Returns + /// Ok(i32): Index of the Level (sign encodes the side) + /// Err(LevelError): with LevelNotFound + /// + pub fn find_level(&self, level_price: f64) -> Result { + let mut i_level: i32 = 0; if level_price <= self.bids[0].price { - let mut i_level: i32 = 0; - for i_bid in &self.bids { i_level -= 1; if level_price == i_bid.price { @@ -269,8 +272,6 @@ impl Orderbook { } if level_price >= self.asks[0].price { - let mut i_level: i32 = 0; - for i_ask in &self.asks { i_level += 1; if level_price == i_ask.price { @@ -278,49 +279,217 @@ impl Orderbook { } } } - Ok(0) + Err(LevelError::LevelNotFound) } // --------------------------------------- Retrieve an Existing Level -- // // --------------------------------------- -------------------------- -- // - pub fn retrieve_level(&self, level_price: f64) -> Result { - // Validate the existence of the level. - let i_level = self.find_level(level_price).unwrap(); - - // On the Bid side - if i_level < 0 { - let i_level = i_level.abs() - 1; - return Ok(self.bids[i_level as usize].clone()); - } + /// If a Level exists, either within the Bids, or, the Asks, it will + /// return a _cloned()_ version of it. + /// + /// ## Parameters + /// level_price: f64 : The level's price to be used as index. + /// + /// ## Returns + /// Ok(Level) : A cloned version of the founded Level. \ + /// Err(LevelError): A custom error type as LevelError:LevelNotFound + /// + pub fn get_level(&self, level_price: f64) -> Result { + // return the level_price if it exists, or, LevelError::LevelNotFound + if let Ok(i_level) = self.find_level(level_price) { + // Level is on the Bid side + if i_level < 0 { + let i_level = i_level.abs() - 1; + return Ok(self.bids[i_level as usize].clone()); + + // Level is on the Ask side + } else if i_level > 0 { + let i_level = i_level - 1; + return Ok(self.asks[i_level as usize].clone()); + + // level is not present + } else { + return Err(LevelError::LevelInfoNotAvailable); + } - // On the Ask side - if i_level > 0 { - let i_level = i_level - 1; - return Ok(self.asks[i_level as usize].clone()); + // find_level returned err in the first place } else { - Err(0) + return Err(LevelError::LevelNotFound); } } // ----------------------------------------- Delete an Existing Level -- // // ----------------------------------------- ------------------------ -- // + pub fn delete_level(&self) -> Result<(), LevelError> { + Ok(()) + } + // ----------------------------------------------- Insert a New Level -- // // --------------------------------------------------- -------------- -- // + /// Inserts a new level. If the level already exists, the new level over + /// rides the existing one, if it does not exists, the new level is inserted + /// in its corresponding slot within the Vec for the corresponding + /// side. + /// + /// ## Parameters + /// side: Side = {Side::Bids, Side::Asks} + /// level_price: f64 = The Level's price to be used as index. + /// volume: f64 = a single quantity for an empty `Vec`, the sum of + /// all the order's amount. + /// orders: Vec = The vector of `Order` structs. + /// + /// ## Returns + /// Ok(Level) + /// Err(LevelError): Custom Error Type of LevelInsertionFailed. + /// + pub fn insert_level( + mut self, + side: Side, + level_price: f64, + volume: f64, + orders: Vec, + ) -> Result<(), LevelError> { + // return the level_price if it exists, or, LevelError::LevelNotFound + if let Ok(i_level) = self.find_level(level_price) { + // Level is on the Bid side + if i_level < 0 { + // updated counter to this side + let i_level = i_level.abs() - 1; + // override existing level with the new one + let same_level_id = &self.bids[i_level as usize].level_id; + self.bids[i_level as usize] = + Level::new(*same_level_id, side, level_price, volume, orders); + + Ok(()) + + // Level is on the Ask side + } else if i_level > 0 { + // update counter to this side + let i_level = i_level - 1; + // override existing level with new one + let same_level_id = &self.asks[i_level as usize].level_id; + self.asks[i_level as usize] = + Level::new(*same_level_id, side, level_price, volume, orders); + + Ok(()) + + // level is not present + } else { + + // find the right position within the vector and insert new Level there + return Err(LevelError::LevelNotFound); + + } + } else { + return Err(LevelError::LevelNotFound); + } + } + // ---------------------------------------------------- Find an Order -- // // ---------------------------------------------------- ------------- -- // + /// To find whether an `Order` exists or not. + /// + /// ## Parameters + /// side: Side = {Side::Bids, Side::Asks} + /// price: f64 = the order's price, which is the same as the Level's price + /// order_id: u32 = Order's unique ID + /// order_ts: u64 = Order's timestamp + /// + /// Take the following sequence for validation of existence + /// + /// 1) side: + /// use it as the Side::Bids or Side::Asks, to find whether the side + /// exists. + /// + /// 2) price: + /// use it as the level_price, to find whether a level already exists. + /// + /// 3) timestamp: + /// use it as the order index to find whether the order exists. + /// + /// ## Results + /// + + pub fn find_order( + &self, + side: Side, + price: f64, + order_id: u32, + order_ts: u64 + ) -> Result<(), OrderError> { + + // Find if side exists + let order_found = match side { + + Side::Bids => { + + if self.bids.len() > 0 { + return Ok(()) + + } else { + return Err(OrderError::OrderNotFound); + } + }, + + Side::Asks => { + + if self.asks.len() > 0 { + return Ok(()) + + } else { + return Err(OrderError::OrderNotFound); + } + } + }; + + } + // --------------------------------------- Retrieve an Existing Order -- // // --------------------------------------- -------------------------- -- // + /// To retrieve info about an existing `Order`. + /// + /// ## Parameters + /// + /// ## Results + /// + + pub fn get_order() -> Result<(), OrderError> { + Ok(()) + } + // ----------------------------------------- Delete an Existing Order -- // // ----------------------------------------- ------------------------ -- // + /// To delete an existing `Order`. + /// + /// ## Parameters + /// + /// ## Results + /// + + pub fn delete_order() -> Result<(), OrderError> { + Ok(()) + } + // ----------------------------------------------- Insert a New Order -- // // ----------------------------------------------- ------------------ -- // + /// To insert a new `Order`. + /// + /// ## Parameters + /// + /// ## Results + /// + + pub fn insert_order() -> Result<(), OrderError> { + Ok(()) + } + // ---------------------------------------------- Synthetic Orderbook -- // // ------------------------------------------------------------------ -- // @@ -338,7 +507,7 @@ impl Orderbook { /// /// # Returns /// - /// Returns a new `Orderbook` instance populated with synthetic bid and + /// Returns a new `Orderbook` instance populated with synthetic bid and /// ask levels. pub fn synthetize( bid_price: f64, diff --git a/tests/test_orderbook.rs b/tests/test_orderbook.rs index 1b9928a..a98f1f9 100644 --- a/tests/test_orderbook.rs +++ b/tests/test_orderbook.rs @@ -3,6 +3,9 @@ mod tests { use atelier::data::market::Orderbook; use atelier::generators::brownian; + #[test] + fn new_order() {} + #[test] fn symmetric_sides() { let bid_price = 50_000.00; From 58cc660677f879856241d8f02994f94102a17012 Mon Sep 17 00:00:00 2001 From: IFFranciscoME Date: Tue, 29 Oct 2024 19:17:03 -0600 Subject: [PATCH 5/8] Progress on implementations --- atelier/examples/ob_metrics.rs | 121 ++++++++++++-- atelier/src/data/market.rs | 153 ++++++++++++------ atelier/src/lib.rs | 1 + tests/Cargo.toml | 20 ++- tests/README.md | 10 ++ tests/orderbook/implementations.rs | 94 +++++++++++ .../progressions.rs} | 0 tests/process/brownian.rs | 17 ++ .../{test_processes.rs => process/hawkes.rs} | 16 +- 9 files changed, 348 insertions(+), 84 deletions(-) create mode 100644 tests/README.md create mode 100644 tests/orderbook/implementations.rs rename tests/{test_orderbook.rs => orderbook/progressions.rs} (100%) create mode 100644 tests/process/brownian.rs rename tests/{test_processes.rs => process/hawkes.rs} (55%) diff --git a/atelier/examples/ob_metrics.rs b/atelier/examples/ob_metrics.rs index dce9924..6f51865 100644 --- a/atelier/examples/ob_metrics.rs +++ b/atelier/examples/ob_metrics.rs @@ -1,28 +1,121 @@ use atelier::data::market::{Level, Order, OrderType, Orderbook, Side}; fn main() { + // Parameters for synthetic orderbook generation let bid_price = 50_000.00; let ask_price = 50_100.00; let tick_size = 100.0; - let n_levels = 2; - let n_orders = 1; + let n_levels = 10; + let n_orders = 2; // Generate a synthetic orderbook for testing - let i_ob = Orderbook::synthetize(bid_price, ask_price, tick_size, n_levels, n_orders); + let mut i_ob = Orderbook::synthetize( + bid_price, + ask_price, + tick_size, + n_levels, + n_orders); // Generated Orderbook - println!("{:?}", i_ob); - - // let find_ob_level = i_ob.find_level(50_200.0); - // println!("{:?}", new_ob_level); - - // let content_ob_level = i_ob.retrieve_level(50_200.0); - // println!("found:\n {:?}", content_ob_level); - - let new_order: Order = Order::new(123, 123, OrderType::Limit, Side::Bids, 50_000.00, 123.123); - - let insert_new = i_ob.insert_level(Side::Bids, 49_900.0, 123.123, vec![new_order]); + // println!("{:?}", i_ob); + + // ------------------------------------------------------- Find Level -- // + // ------------------------------------------------------- ---------- -- // + + let price_level = 50_200.0; + let find_level_ob = i_ob.find_level(price_level); + + println!("\n -- Find Level --"); + + match find_level_ob { + + Ok(n) if n < 0 => { + + let bid_found = find_level_ob.unwrap().abs() as usize -1; + + println!(" + The search price: {:?} is in the bid side, + with an index: {:?}, + with a price level: {:?}, + with {:?} orders.", + &price_level, + i_ob.bids[bid_found].level_id, + i_ob.bids[bid_found].price, + i_ob.bids[bid_found].orders.len()) + }, + + Ok(n) if n > 0 => { + + let ask_found = find_level_ob.unwrap() as usize -1 ; + + println!(" + The price: {:?} is in the ask side, + with an index: {:?}, + with a price level: {:?}, + with {:?} orders", + &price_level, + i_ob.asks[ask_found].level_id, + i_ob.asks[ask_found].price, + i_ob.asks[ask_found].orders.len()) + }, + Err(e) => println!("Error encountered : {:?}", e), + Ok(_) => println!("Error not mapped"), + } + + // --------------------------------------------------- Retrieve Level -- // + // --------------------------------------------------- -------------- -- // + + let find_this: f64 = 50_200.0; + let content_ob_level = i_ob.retrieve_level(find_this).unwrap(); + + println!("\n -- Retrieve Level --"); + println!(" + level to be retrieved: {:?}, + retrieved Level index: {:?}, + retrieved Level price: {:?}, + retrieved Level orders: {:?}", + find_this, + content_ob_level.level_id, + content_ob_level.price, + content_ob_level.orders.len(), + ); + + // ----------------------------------------------------- Delete Level -- // + // ----------------------------------------------------- ------------ -- // + + let delete_this: f64 = 50_200.0; + i_ob.delete_level(delete_this).unwrap(); + + // ----------------------------------------------------- Insert Level -- // + // ----------------------------------------------------- ------------ -- // + + let new_order = Order { + order_id: 123, + order_ts: 456, + order_type: OrderType::Limit, + side: Side::Asks, + price: 50_200.0, + amount: 0.123, + }; + + let new_level = Level { + level_id: 123, + side: Side::Asks, + price: 50_200.0, + volume: 0.123, + orders: vec![new_order], + }; + + /* + let new_order: Order = Order::new(123, 123, OrderType::Limit, + Side::Bids, 50_000.00, 123.123); + let insert_new = i_ob.insert_level(Side::Bids, 49_900.0, 123.123, + vec![new_order]); + */ + + // let r_result = i_ob.delete_level(50_000.01); + // println!("{:?}", r_result); // println!("{:?}", insert_new); diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index d93a965..3afc8a4 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -1,5 +1,5 @@ use crate::generators::randomizer::randomize_order; -use crate::messages::errors::{OrderError, LevelError}; +use crate::messages::errors::{LevelError, OrderError}; use core::f64; use std::time::{SystemTime, UNIX_EPOCH}; @@ -192,6 +192,11 @@ impl Level { /// 1) Has both bids and asks sides (aham....) /// 2) for each side, another Level struct with price, volume, etc (hemm ...) /// 3) and for each Level, a queue (vector) of Order structs, (now we are talking) + +/// ## Defaults +/// non-empty vectors : The default decision is to have empty vectors even +/// if there is no further to fill them with. e.g. for the bids/asks + #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct Orderbook { pub orderbook_id: u32, @@ -234,18 +239,6 @@ impl Orderbook { } } - // ------------------------------------------------------ Get the TOB -- // - // ------------------------------------------------------ ----------- -- // - - pub fn get_tob(&self) -> Vec<&f64> { - let bid_volume = self.bids.get(0).map(|bid| &bid.volume).unwrap_or(&0.0); - let bid_price = self.bids.get(0).map(|bid| &bid.price).unwrap_or(&0.0); - let ask_price = self.asks.get(0).map(|ask| &ask.price).unwrap_or(&0.0); - let ask_volume = self.asks.get(0).map(|ask| &ask.volume).unwrap_or(&0.0); - - vec![&bid_volume, &bid_price, &ask_price, &ask_volume] - } - // ----------------------------------------------------- Find a Level -- // // ----------------------------------------------------- ------------ -- // @@ -253,10 +246,11 @@ impl Orderbook { /// it will return the index of it, positive for asks, negative for bids. /// /// ## Parameters - /// level_price: f64 = The Level's price to be used as index. + /// level_price: f64 = The Level's price to be found. /// /// ## Returns - /// Ok(i32): Index of the Level (sign encodes the side) + /// Ok(i32): Index of the Level found (if it exists), + /// the sign encodes the side, negative (bids) and positive (asks) /// Err(LevelError): with LevelNotFound /// pub fn find_level(&self, level_price: f64) -> Result { @@ -279,6 +273,7 @@ impl Orderbook { } } } + Err(LevelError::LevelNotFound) } @@ -295,12 +290,13 @@ impl Orderbook { /// Ok(Level) : A cloned version of the founded Level. \ /// Err(LevelError): A custom error type as LevelError:LevelNotFound /// - pub fn get_level(&self, level_price: f64) -> Result { + pub fn retrieve_level(&self, level_price: f64) -> Result { // return the level_price if it exists, or, LevelError::LevelNotFound if let Ok(i_level) = self.find_level(level_price) { + // Level is on the Bid side if i_level < 0 { - let i_level = i_level.abs() - 1; + let i_level = i_level.abs() + 1; return Ok(self.bids[i_level as usize].clone()); // Level is on the Ask side @@ -322,8 +318,35 @@ impl Orderbook { // ----------------------------------------- Delete an Existing Level -- // // ----------------------------------------- ------------------------ -- // - pub fn delete_level(&self) -> Result<(), LevelError> { - Ok(()) + /// To delete an existing level + /// + /// + + pub fn delete_level(&mut self, level_price: f64) -> Result<(), LevelError> { + + // see if level exists + let find_level_ob = self.find_level(level_price); + + match find_level_ob { + + Ok(n) if n < 0 => { + + let bid_found = find_level_ob.unwrap().abs() as usize -1; + self.bids.remove(bid_found); + Ok(()) + }, + + Ok(n) if n > 0 => { + let ask_found = find_level_ob.unwrap() as usize -1 ; + self.asks.remove(ask_found); + Ok(()) + }, + + Err(e) => Err(LevelError::LevelDeletionFailed), + + Ok(_) => Err(LevelError::LevelInfoNotAvailable), + } + } // ----------------------------------------------- Insert a New Level -- // @@ -354,7 +377,8 @@ impl Orderbook { ) -> Result<(), LevelError> { // return the level_price if it exists, or, LevelError::LevelNotFound if let Ok(i_level) = self.find_level(level_price) { - // Level is on the Bid side + + // -- Level exist on the Bid side (to be replaced) if i_level < 0 { // updated counter to this side let i_level = i_level.abs() - 1; @@ -365,7 +389,7 @@ impl Orderbook { Ok(()) - // Level is on the Ask side + // -- Level exist on the Ask side (to be replaced) } else if i_level > 0 { // update counter to this side let i_level = i_level - 1; @@ -376,31 +400,51 @@ impl Orderbook { Ok(()) - // level is not present + // A response was produced but with an error on level index } else { - - // find the right position within the vector and insert new Level there + + // find the right position within the vector + // and insert new Level there + return Err(LevelError::LevelNotFound); - } + + // Level not found, so insert a new one } else { + + match side { + + Side::Bids => { + + }, + + Side::Asks => { + + }, + + } + + // insert into the vector + self.asks.insert(1); + return Err(LevelError::LevelNotFound); + } } // ---------------------------------------------------- Find an Order -- // // ---------------------------------------------------- ------------- -- // - /// To find whether an `Order` exists or not. + /// To find if a given `Order` exists. /// /// ## Parameters /// side: Side = {Side::Bids, Side::Asks} /// price: f64 = the order's price, which is the same as the Level's price - /// order_id: u32 = Order's unique ID /// order_ts: u64 = Order's timestamp + /// order_id: u32 = Order's unique ID /// /// Take the following sequence for validation of existence - /// + /// /// 1) side: /// use it as the Side::Bids or Side::Asks, to find whether the side /// exists. @@ -413,39 +457,34 @@ impl Orderbook { /// /// ## Results /// - + pub fn find_order( - &self, - side: Side, - price: f64, - order_id: u32, - order_ts: u64 - ) -> Result<(), OrderError> { - + &self, + side: Side, + price: f64, + order_id: u32, + order_ts: u64, + ) -> Result<(), OrderError> { // Find if side exists - let order_found = match side { - + let order_search = match side { + // Side::Bids => { - + // if self.bids.len() > 0 { - return Ok(()) - + return Ok(()); } else { return Err(OrderError::OrderNotFound); } - }, + } Side::Asks => { - if self.asks.len() > 0 { - return Ok(()) - + return Ok(()); } else { return Err(OrderError::OrderNotFound); } } }; - } // --------------------------------------- Retrieve an Existing Order -- // @@ -457,8 +496,8 @@ impl Orderbook { /// /// ## Results /// - - pub fn get_order() -> Result<(), OrderError> { + + pub fn retrieve_order() -> Result<(), OrderError> { Ok(()) } @@ -471,7 +510,7 @@ impl Orderbook { /// /// ## Results /// - + pub fn delete_order() -> Result<(), OrderError> { Ok(()) } @@ -485,11 +524,25 @@ impl Orderbook { /// /// ## Results /// - + pub fn insert_order() -> Result<(), OrderError> { Ok(()) } + // -------------------------------------------------- Modify an Order -- // + // -------------------------------------------------- --------------- -- // + + /// To modify an existing `Order`. + /// + /// ## Parameters + /// + /// ## Results + /// + + pub fn modify_order() -> Result<(), OrderError> { + Ok(()) + } + // ---------------------------------------------- Synthetic Orderbook -- // // ------------------------------------------------------------------ -- // diff --git a/atelier/src/lib.rs b/atelier/src/lib.rs index b87e640..403c982 100644 --- a/atelier/src/lib.rs +++ b/atelier/src/lib.rs @@ -5,6 +5,7 @@ //! * **Market Replay**: A high-fidelity reproduction of what actually happened, all the way down to the data granularity that is provided. #![allow(dead_code)] +#![allow(warnings)] /// Data structures and core datatypes. pub mod data; diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 39c1d48..041ed14 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -8,8 +8,18 @@ publish = false atelier = { path = "../atelier" } [[test]] -name = "test_orderbook" -path = "test_orderbook.rs" -[[test]] -name = "test_processes" -path = "test_processes.rs" +name = "tests_orderbook_implementations" +path = "orderbook/implementations.rs" + +# [[test]] +# name = "tests_orderbook_progressions" +# path = "orderbook/progressions.rs" + +# [[test]] +# name = "tests_process_brownian" +# path = "process/brownian.rs" + +# [[test]] +# name = "tests_process_hawkes" +# path = "process/hawkes.rs" + diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..84fecf9 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,10 @@ +# Test-Driven Development + +Run a single test with the `--test` flag + +```shell +cargo test --test tests_process_brownian +``` + +the above command `--test tests_process_brownian` specifies which test file to run. It corresponds to the `[[test]]` section in the `tests/Cargo.toml`, where it is defined the `tests_process_brownian` as a test that points to the `process/brownian.rs` file. Thus, by using this command, only the tests defined in `brownian.rs` will be executed, and all other tests in the `tests/` directory will be skipped. + diff --git a/tests/orderbook/implementations.rs b/tests/orderbook/implementations.rs new file mode 100644 index 0000000..a056eee --- /dev/null +++ b/tests/orderbook/implementations.rs @@ -0,0 +1,94 @@ + +#[cfg(test)] +mod tests { + + use atelier::data::market::Orderbook; + + const BID_PRICE: f64 = 50_000.00; + const ASK_PRICE: f64 = 50_100.00; + const TICK_SIZE: f64 = 100.0; + const N_LEVELS: u32 = 10; + const N_ORDERS: u32 = 5; + + // ------------------------------------------------------------------ FIND_LEVEL -- / + // ------------------------------------------------------------------ ---------- -- / + + #[test] + fn find_level() { + + let test_ob = Orderbook::synthetize( + BID_PRICE, + ASK_PRICE, + TICK_SIZE, + N_LEVELS, + N_ORDERS); + + // the price of the level to be searched. + + let t_level_price = 50_300.00; + let level_found = test_ob.find_level(t_level_price).unwrap(); + + // println!("level_found content: {:?}", level_found); + + assert_eq!(level_found, 1); + + } +} + // -------------------------------------------------------------- RETRIEVE_LEVEL -- / + // -------------------------------------------------------------- -------------- -- / + + // #[test] + // fn retrieve_level() { + // } + + // ---------------------------------------------------------------- DELETE_LEVEL -- / + // ---------------------------------------------------------------- ------------ -- / + + // #[test] + // fn delete_level() { + // } + + // ---------------------------------------------------------------- INSERT_LEVEL -- / + // ---------------------------------------------------------------- ------------ -- / + + // #[test] + // fn insert_level() { + // } + + // ------------------------------------------------------------------ FIND_ORDER -- / + // ------------------------------------------------------------------ ---------- -- / + + // #[test] + // fn find_order() { + // } + + // -------------------------------------------------------------- RETRIEVE_ORDER -- / + // -------------------------------------------------------------- -------------- -- / + + // #[test] + // fn retrieve_order() { + // } + + // ---------------------------------------------------------------- DELETE_ORDER -- / + // ---------------------------------------------------------------- ------------ -- / + + // #[test] + // fn delete_order() { + // } + + // ---------------------------------------------------------------- INSERT_ORDER -- / + // ---------------------------------------------------------------- ------------ -- / + + // #[test] + // fn insert_order() { + // } + + // ---------------------------------------------------------------- MODIFY_ORDER -- / + // ---------------------------------------------------------------- ------------ -- / + + // #[test] + // fn modify_order() { + // } + +//} + diff --git a/tests/test_orderbook.rs b/tests/orderbook/progressions.rs similarity index 100% rename from tests/test_orderbook.rs rename to tests/orderbook/progressions.rs diff --git a/tests/process/brownian.rs b/tests/process/brownian.rs new file mode 100644 index 0000000..816bcfa --- /dev/null +++ b/tests/process/brownian.rs @@ -0,0 +1,17 @@ +#[cfg(test)] +mod tests { + use atelier::generators::brownian; + + #[test] + fn single_process() { + let gbm_s0: f64 = 55_000.0; + let gbm_mu: f64 = 0.1; + let gbm_sigma: f64 = 0.2; + let gbm_t: f64 = 2.0; + + // A naive test for the name and route + let gbm_events = brownian::gbm_return(gbm_s0, gbm_mu, gbm_sigma, gbm_t); + + assert!(gbm_events.is_ok()); + } +} diff --git a/tests/test_processes.rs b/tests/process/hawkes.rs similarity index 55% rename from tests/test_processes.rs rename to tests/process/hawkes.rs index 406dea4..64942ed 100644 --- a/tests/test_processes.rs +++ b/tests/process/hawkes.rs @@ -1,10 +1,9 @@ #[cfg(test)] mod tests { - use atelier::generators::brownian; use atelier::generators::hawkes; #[test] - fn hawkes_process() { + fn single_process() { let hawkes_mu: f64 = 0.85; let hawkes_alpha: f64 = 0.8; let hawkes_beta: f64 = 1.0; @@ -19,17 +18,4 @@ mod tests { let order_times = hawkes_events.generate_times(5); assert_eq!(order_times.len(), 5); } - - #[test] - fn gmb_process() { - let gbm_s0: f64 = 55_000.0; - let gbm_mu: f64 = 0.1; - let gbm_sigma: f64 = 0.2; - let gbm_t: f64 = 2.0; - - // A naive test for the name and route - let gbm_events = brownian::gbm_return(gbm_s0, gbm_mu, gbm_sigma, gbm_t); - - assert!(gbm_events.is_ok()); - } } From 8f118bbd9f9bc77531b1e8a5f0bd617d6d65186a Mon Sep 17 00:00:00 2001 From: IFFranciscoME Date: Wed, 30 Oct 2024 08:33:39 -0600 Subject: [PATCH 6/8] Level implementations --- atelier/examples/ob_metrics.rs | 48 +++++++++++-- atelier/src/data/market.rs | 124 ++++++++++++++++++++++----------- 2 files changed, 124 insertions(+), 48 deletions(-) diff --git a/atelier/examples/ob_metrics.rs b/atelier/examples/ob_metrics.rs index 6f51865..4f46591 100644 --- a/atelier/examples/ob_metrics.rs +++ b/atelier/examples/ob_metrics.rs @@ -6,10 +6,14 @@ fn main() { let bid_price = 50_000.00; let ask_price = 50_100.00; let tick_size = 100.0; - let n_levels = 10; - let n_orders = 2; + let n_levels = 2; + let n_orders = 1; // Generate a synthetic orderbook for testing + // this determines the order of the Level objects within + // the bids and asks vectors, and also, the order of each + // order within each level. + let mut i_ob = Orderbook::synthetize( bid_price, ask_price, @@ -24,7 +28,7 @@ fn main() { // ------------------------------------------------------- ---------- -- // let price_level = 50_200.0; - let find_level_ob = i_ob.find_level(price_level); + let find_level_ob = i_ob.find_level(&price_level); println!("\n -- Find Level --"); @@ -67,7 +71,7 @@ fn main() { // --------------------------------------------------- -------------- -- // let find_this: f64 = 50_200.0; - let content_ob_level = i_ob.retrieve_level(find_this).unwrap(); + let content_ob_level = i_ob.retrieve_level(&find_this).unwrap(); println!("\n -- Retrieve Level --"); println!(" @@ -84,12 +88,22 @@ fn main() { // ----------------------------------------------------- Delete Level -- // // ----------------------------------------------------- ------------ -- // + println!("\n -- Delete Level --"); let delete_this: f64 = 50_200.0; - i_ob.delete_level(delete_this).unwrap(); + println!(" + Delete the level with this price: {:?}", + &delete_this + ); + i_ob.delete_level(&delete_this).unwrap(); + println!("\nNew state of the OB.bids: \n{:?}", i_ob.bids); + println!("\nNew state of the OB.asks: \n{:?}", i_ob.asks); // ----------------------------------------------------- Insert Level -- // // ----------------------------------------------------- ------------ -- // + println!("\n -- Insert Level --"); + println!(""); + let new_order = Order { order_id: 123, order_ts: 456, @@ -103,9 +117,31 @@ fn main() { level_id: 123, side: Side::Asks, price: 50_200.0, - volume: 0.123, + volume: 0.987, orders: vec![new_order], }; + + let insert_this: &Level = &new_level; + println!(" + Level to be inserted: {:?}", + &insert_this + ); + + println!("\nResult of insertion: {:?}", i_ob.insert_level(new_level)); + + // let find_this: &f64 = &new_level.price; + println!("i_ob content: {:?}", i_ob); + + println!("\n -- Retrieve Level --"); + println!(" + NEW level to be retrieved: {:?}, + NEW retrieved Level index: {:?}, + NEW retrieved Level price: {:?}, + NEW retrieved Level orders: {:?}", + find_this, + content_ob_level.level_id, + content_ob_level.price, + content_ob_level.orders.len()); /* let new_order: Order = Order::new(123, 123, OrderType::Limit, diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index 3afc8a4..ef97005 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -253,22 +253,22 @@ impl Orderbook { /// the sign encodes the side, negative (bids) and positive (asks) /// Err(LevelError): with LevelNotFound /// - pub fn find_level(&self, level_price: f64) -> Result { + pub fn find_level(&self, level_price: &f64) -> Result { let mut i_level: i32 = 0; - if level_price <= self.bids[0].price { + if level_price <= &self.bids[0].price { for i_bid in &self.bids { i_level -= 1; - if level_price == i_bid.price { + if level_price == &i_bid.price { return Ok(i_level); } } } - if level_price >= self.asks[0].price { + if level_price >= &self.asks[0].price { for i_ask in &self.asks { i_level += 1; - if level_price == i_ask.price { + if level_price == &i_ask.price { return Ok(i_level); } } @@ -290,7 +290,7 @@ impl Orderbook { /// Ok(Level) : A cloned version of the founded Level. \ /// Err(LevelError): A custom error type as LevelError:LevelNotFound /// - pub fn retrieve_level(&self, level_price: f64) -> Result { + pub fn retrieve_level(&self, level_price: &f64) -> Result { // return the level_price if it exists, or, LevelError::LevelNotFound if let Ok(i_level) = self.find_level(level_price) { @@ -318,11 +318,12 @@ impl Orderbook { // ----------------------------------------- Delete an Existing Level -- // // ----------------------------------------- ------------------------ -- // - /// To delete an existing level - /// + /// Deletes an existing level /// + /// ## Parameters + /// level_price: &f64 - pub fn delete_level(&mut self, level_price: f64) -> Result<(), LevelError> { + pub fn delete_level(&mut self, level_price: &f64) -> Result<(), LevelError> { // see if level exists let find_level_ob = self.find_level(level_price); @@ -358,78 +359,117 @@ impl Orderbook { /// side. /// /// ## Parameters - /// side: Side = {Side::Bids, Side::Asks} - /// level_price: f64 = The Level's price to be used as index. - /// volume: f64 = a single quantity for an empty `Vec`, the sum of - /// all the order's amount. - /// orders: Vec = The vector of `Order` structs. + /// level: With a Level::new() /// /// ## Returns /// Ok(Level) /// Err(LevelError): Custom Error Type of LevelInsertionFailed. /// - pub fn insert_level( - mut self, - side: Side, - level_price: f64, - volume: f64, - orders: Vec, + pub fn insert_level(&mut self, level: Level, ) -> Result<(), LevelError> { + // return the level_price if it exists, or, LevelError::LevelNotFound - if let Ok(i_level) = self.find_level(level_price) { + if let Ok(i_level) = self.find_level(&level.price) { + + println!("i_level found: {:?}", &i_level); // -- Level exist on the Bid side (to be replaced) if i_level < 0 { // updated counter to this side let i_level = i_level.abs() - 1; - // override existing level with the new one + // use the same id for the level let same_level_id = &self.bids[i_level as usize].level_id; + // override existing level with the new one self.bids[i_level as usize] = - Level::new(*same_level_id, side, level_price, volume, orders); - - Ok(()) + Level::new( + *same_level_id, + Side::Bids, + level.price, + level.volume, + level.orders); + + return Ok(()) // -- Level exist on the Ask side (to be replaced) } else if i_level > 0 { // update counter to this side let i_level = i_level - 1; - // override existing level with new one + // use the same id for the level let same_level_id = &self.asks[i_level as usize].level_id; + // override existing level with new one self.asks[i_level as usize] = - Level::new(*same_level_id, side, level_price, volume, orders); - - Ok(()) - + Level::new( + *same_level_id, + level.side, + level.price, + level.volume, + level.orders); + + return Ok(()) + // A response was produced but with an error on level index } else { // find the right position within the vector // and insert new Level there + println!("i_level found: {:?}", &i_level); + return Err(LevelError::LevelNotFound); } - - // Level not found, so insert a new one + // Level not found. + // Localize index, insert into vector. } else { - match side { + match level.side { Side::Bids => { + // Get the level_price for all levels in the vector + let mut v_bids = self.bids.clone().into_iter(); + + // Find position : Start with the upper most position + // (given the ordering in orders) + let index_level = v_bids.position( + |existing_level| level.price > existing_level.price) + .unwrap_or(v_bids.len()); + + // Insert new Level into the existing vector of levels. + self.bids.insert(index_level, + Level::new(index_level as u32, + level.side, + level.price, + level.volume, + level.orders) + ); + return Ok(()) }, Side::Asks => { - }, - - } - - // insert into the vector - self.asks.insert(1); - - return Err(LevelError::LevelNotFound); - + // get the level_price for all levels in the vector + let mut v_asks = self.asks.clone().into_iter(); + + // Find position : Start with the lower and top most position + // (given the ordering in orders) + let index_level = v_asks.position( + |existing_level| level.price < existing_level.price) + .unwrap_or(v_asks.len()); + + // Insert the new level into the existing vector of levels. + self.asks.insert(index_level, + Level::new(index_level as u32, + level.side, + level.price, + level.volume, + level.orders)); + return Ok(()) + } + } } + + return Err(LevelError::LevelNotFound); + } // ---------------------------------------------------- Find an Order -- // From 8a3e60f45cdc99b01cc1438beffb42da86867c9e Mon Sep 17 00:00:00 2001 From: IFFranciscoME Date: Wed, 30 Oct 2024 21:52:56 -0600 Subject: [PATCH 7/8] Progress on Implementations for Orderbook --- atelier/examples/ob_metrics.rs | 109 +++++++++++++----------- atelier/src/data/market.rs | 128 +++++++++++++++++++++-------- tests/orderbook/implementations.rs | 2 +- 3 files changed, 153 insertions(+), 86 deletions(-) diff --git a/atelier/examples/ob_metrics.rs b/atelier/examples/ob_metrics.rs index 4f46591..a886ee1 100644 --- a/atelier/examples/ob_metrics.rs +++ b/atelier/examples/ob_metrics.rs @@ -142,55 +142,64 @@ fn main() { content_ob_level.level_id, content_ob_level.price, content_ob_level.orders.len()); + + // ------------------------------------------------------- Find Order -- // + // ------------------------------------------------------- ---------- -- // + + println!("\n -- Find Order --"); + let i_order = &i_ob.bids[0].orders[0]; + + let found_order = i_ob.find_order( + i_order.side, + i_order.price, + i_order.order_ts); + + println!(" + Order to be found, + side: {:?}, + price: {:?}, + order_ts: {:?}", + i_order.side, + i_order.price, + i_order.order_ts, + ); + + println!("\nOrder found: {:?}", found_order.unwrap()); + + // --------------------------------------------------- Retrieve Order -- // + // --------------------------------------------------- -------------- -- // + + println!("\n -- Retrieve Order --"); + let i_order = &i_ob.bids[0].orders[0]; + + let retrieved_order = i_ob.retrieve_order( + i_order.side, + i_order.price, + i_order.order_ts); + + println!(" + Order to be found, + side: {:?}, + price: {:?}, + order_ts: {:?}", + i_order.side, + i_order.price, + i_order.order_ts, + ); + + println!("Retrieved Order: {:?}", retrieved_order); + + // ----------------------------------------------------- Delete Order -- // + // ----------------------------------------------------- ------------ -- // + + - /* - let new_order: Order = Order::new(123, 123, OrderType::Limit, - Side::Bids, 50_000.00, 123.123); - let insert_new = i_ob.insert_level(Side::Bids, 49_900.0, 123.123, - vec![new_order]); - */ - - // let r_result = i_ob.delete_level(50_000.01); - // println!("{:?}", r_result); - - // println!("{:?}", insert_new); - - // get the TOB - // let tob_data = i_ob.get_tob(); - // println!("TOB: {:?}", tob_data); - - // extract tob values - // let tob_bid: f64 = i_ob.bids[0].price; - // let tob_ask: f64 = i_ob.asks[0].price; - - // Compute the Spread - // let spread_value = Spread::compute(&tob_bid, &tob_ask, 0); - // println!("Spread: {:?}", spread_value); - - // Compute the Midprice - // let midprice_value = Midprice::compute(&tob_bid, &tob_ask, 0); - // println!("Midprice: {}", midprice_value); - - // Compute the Volume Imbalance - // let iter_bids: Vec = i_ob.bids.clone().into_iter().map(|x| x.volume).collect(); - // let iter_asks: Vec = i_ob.asks.clone().into_iter().map(|x| x.volume).collect(); - - // let obimb_value = VolumeImbalance::compute(&iter_bids, &iter_asks, 1); - // println!("Volume Imbalance: {:?}", obimb_value); - - // Compute the Volume-Weighted Average Price - //let iter_bids: Vec<_> = i_ob - // .bids - // .into_iter() - // .map(|x| vec![x.price, x.volume]) - // .collect(); - // let iter_asks: Vec<_> = i_ob - // .asks - // .into_iter() - // .map(|x| vec![x.price, x.volume]) - // .collect(); - - // Compute the VWAP - // let vwap_value = VWAP::compute(&iter_bids.clone(), &iter_asks.clone(), 1); - // println!("VWAP: {:?}", vwap_value); + // ----------------------------------------------------- Insert Order -- // + // ----------------------------------------------------- ------------ -- // + + + + // ----------------------------------------------------- Modify Order -- // + // ----------------------------------------------------- ------------ -- // + } diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index ef97005..7150c79 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -481,50 +481,66 @@ impl Orderbook { /// side: Side = {Side::Bids, Side::Asks} /// price: f64 = the order's price, which is the same as the Level's price /// order_ts: u64 = Order's timestamp - /// order_id: u32 = Order's unique ID - /// - /// Take the following sequence for validation of existence - /// - /// 1) side: - /// use it as the Side::Bids or Side::Asks, to find whether the side - /// exists. - /// - /// 2) price: - /// use it as the level_price, to find whether a level already exists. - /// - /// 3) timestamp: - /// use it as the order index to find whether the order exists. /// /// ## Results + /// Ok: (level_index: usize, order_index: usize) + /// Err: OrderError /// pub fn find_order( &self, side: Side, price: f64, - order_id: u32, order_ts: u64, - ) -> Result<(), OrderError> { - // Find if side exists - let order_search = match side { - // - Side::Bids => { - // - if self.bids.len() > 0 { - return Ok(()); + ) -> Result<(i32, usize), OrderError> { + + // see if level exists + let find_level_ob = self.find_level(&price); + match find_level_ob { + + Ok(n) if n < 0 => { + + let level_found = find_level_ob.unwrap().abs() as usize -1; + let level_orders = &self.bids[level_found].orders; + + // Level has orders + if level_orders.len() > 0 { + + let r_level = level_orders + .binary_search_by(|order| order.order_ts.cmp(&order_ts)) + .unwrap(); + + Ok((n, r_level)) + + // Level is empty } else { - return Err(OrderError::OrderNotFound); + Err(OrderError::OrderNotFound) } - } + }, - Side::Asks => { - if self.asks.len() > 0 { - return Ok(()); + Ok(n) if n > 0 => { + + let level_found = find_level_ob.unwrap().abs() as usize -1; + let level_orders = &self.asks[level_found].orders; + + // Level has orders + if level_orders.len() > 0 { + + let r_level = level_orders + .binary_search_by(|order| order.order_ts.cmp(&order_ts)) + .unwrap(); + + Ok((n, r_level)) + + // Level is empty } else { - return Err(OrderError::OrderNotFound); + Err(OrderError::OrderNotFound) } - } - }; + }, + + Err(e) => Err(OrderError::OrderNotFound), + Ok(_) => Err(OrderError::OrderInfoNotAvailable), + } } // --------------------------------------- Retrieve an Existing Order -- // @@ -533,12 +549,30 @@ impl Orderbook { /// To retrieve info about an existing `Order`. /// /// ## Parameters + /// Order /// /// ## Results - /// + /// - pub fn retrieve_order() -> Result<(), OrderError> { - Ok(()) + pub fn retrieve_order( + &self, + side: Side, + price: f64, + order_ts: u64, + ) -> Result<(Order), OrderError> { + + if let Ok((found_level, found_order)) = self.find_order( + side, price, order_ts) { + + if found_level > 0 { + Ok(self.asks[found_level.abs() as usize].orders[found_order]) + } else { + Ok(self.bids[found_level.abs() as usize].orders[found_order]) + } + + } else { + Err(OrderError::OrderNotFound) + } } // ----------------------------------------- Delete an Existing Order -- // @@ -551,8 +585,32 @@ impl Orderbook { /// ## Results /// - pub fn delete_order() -> Result<(), OrderError> { - Ok(()) + pub fn delete_order( + &self, + side: Side, + price: f64, + order_ts: u64) -> Result<(), OrderError> { + + // find the order + // delete the order + + if let Ok((found_level, found_order)) = self.find_order( + side, price, order_ts) { + + if found_level > 0 { + + self.asks[found_level.abs() as usize].orders[found_order] + + } else { + + self.bids[found_level.abs() as usize].orders[found_order] + } + + } else { + Err(OrderError::OrderNotFound) + } + + } // ----------------------------------------------- Insert a New Order -- // diff --git a/tests/orderbook/implementations.rs b/tests/orderbook/implementations.rs index a056eee..5e6548d 100644 --- a/tests/orderbook/implementations.rs +++ b/tests/orderbook/implementations.rs @@ -26,7 +26,7 @@ mod tests { // the price of the level to be searched. let t_level_price = 50_300.00; - let level_found = test_ob.find_level(t_level_price).unwrap(); + let level_found = test_ob.find_level(&t_level_price).unwrap(); // println!("level_found content: {:?}", level_found); From 1ee62fbee836722c0dd06b60bc0804c2ab6e9cde Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 04:34:34 +0000 Subject: [PATCH 8/8] Format Rust code using rustfmt --- atelier/examples/ob_metrics.rs | 115 ++++++++---------- atelier/src/data/market.rs | 182 ++++++++++++----------------- tests/orderbook/implementations.rs | 131 ++++++++++----------- 3 files changed, 188 insertions(+), 240 deletions(-) diff --git a/atelier/examples/ob_metrics.rs b/atelier/examples/ob_metrics.rs index a886ee1..c086d2c 100644 --- a/atelier/examples/ob_metrics.rs +++ b/atelier/examples/ob_metrics.rs @@ -1,7 +1,6 @@ use atelier::data::market::{Level, Order, OrderType, Orderbook, Side}; fn main() { - // Parameters for synthetic orderbook generation let bid_price = 50_000.00; let ask_price = 50_100.00; @@ -10,35 +9,29 @@ fn main() { let n_orders = 1; // Generate a synthetic orderbook for testing - // this determines the order of the Level objects within + // this determines the order of the Level objects within // the bids and asks vectors, and also, the order of each // order within each level. - - let mut i_ob = Orderbook::synthetize( - bid_price, - ask_price, - tick_size, - n_levels, - n_orders); + + let mut i_ob = Orderbook::synthetize(bid_price, ask_price, tick_size, n_levels, n_orders); // Generated Orderbook // println!("{:?}", i_ob); - + // ------------------------------------------------------- Find Level -- // // ------------------------------------------------------- ---------- -- // - + let price_level = 50_200.0; let find_level_ob = i_ob.find_level(&price_level); println!("\n -- Find Level --"); match find_level_ob { - Ok(n) if n < 0 => { - - let bid_found = find_level_ob.unwrap().abs() as usize -1; + let bid_found = find_level_ob.unwrap().abs() as usize - 1; - println!(" + println!( + " The search price: {:?} is in the bid side, with an index: {:?}, with a price level: {:?}, @@ -46,27 +39,29 @@ fn main() { &price_level, i_ob.bids[bid_found].level_id, i_ob.bids[bid_found].price, - i_ob.bids[bid_found].orders.len()) - }, - + i_ob.bids[bid_found].orders.len() + ) + } + Ok(n) if n > 0 => { - - let ask_found = find_level_ob.unwrap() as usize -1 ; - - println!(" + let ask_found = find_level_ob.unwrap() as usize - 1; + + println!( + " The price: {:?} is in the ask side, with an index: {:?}, with a price level: {:?}, - with {:?} orders", + with {:?} orders", &price_level, i_ob.asks[ask_found].level_id, i_ob.asks[ask_found].price, - i_ob.asks[ask_found].orders.len()) - }, + i_ob.asks[ask_found].orders.len() + ) + } Err(e) => println!("Error encountered : {:?}", e), Ok(_) => println!("Error not mapped"), } - + // --------------------------------------------------- Retrieve Level -- // // --------------------------------------------------- -------------- -- // @@ -74,7 +69,8 @@ fn main() { let content_ob_level = i_ob.retrieve_level(&find_this).unwrap(); println!("\n -- Retrieve Level --"); - println!(" + println!( + " level to be retrieved: {:?}, retrieved Level index: {:?}, retrieved Level price: {:?}, @@ -87,10 +83,11 @@ fn main() { // ----------------------------------------------------- Delete Level -- // // ----------------------------------------------------- ------------ -- // - + println!("\n -- Delete Level --"); let delete_this: f64 = 50_200.0; - println!(" + println!( + " Delete the level with this price: {:?}", &delete_this ); @@ -100,10 +97,10 @@ fn main() { // ----------------------------------------------------- Insert Level -- // // ----------------------------------------------------- ------------ -- // - + println!("\n -- Insert Level --"); println!(""); - + let new_order = Order { order_id: 123, order_ts: 456, @@ -113,27 +110,29 @@ fn main() { amount: 0.123, }; - let new_level = Level { - level_id: 123, - side: Side::Asks, - price: 50_200.0, + let new_level = Level { + level_id: 123, + side: Side::Asks, + price: 50_200.0, volume: 0.987, - orders: vec![new_order], + orders: vec![new_order], }; let insert_this: &Level = &new_level; - println!(" + println!( + " Level to be inserted: {:?}", &insert_this ); println!("\nResult of insertion: {:?}", i_ob.insert_level(new_level)); - + // let find_this: &f64 = &new_level.price; println!("i_ob content: {:?}", i_ob); println!("\n -- Retrieve Level --"); - println!(" + println!( + " NEW level to be retrieved: {:?}, NEW retrieved Level index: {:?}, NEW retrieved Level price: {:?}, @@ -141,65 +140,53 @@ fn main() { find_this, content_ob_level.level_id, content_ob_level.price, - content_ob_level.orders.len()); + content_ob_level.orders.len() + ); // ------------------------------------------------------- Find Order -- // // ------------------------------------------------------- ---------- -- // println!("\n -- Find Order --"); let i_order = &i_ob.bids[0].orders[0]; - - let found_order = i_ob.find_order( - i_order.side, - i_order.price, - i_order.order_ts); - println!(" + let found_order = i_ob.find_order(i_order.side, i_order.price, i_order.order_ts); + + println!( + " Order to be found, side: {:?}, price: {:?}, order_ts: {:?}", - i_order.side, - i_order.price, - i_order.order_ts, + i_order.side, i_order.price, i_order.order_ts, ); println!("\nOrder found: {:?}", found_order.unwrap()); // --------------------------------------------------- Retrieve Order -- // // --------------------------------------------------- -------------- -- // - + println!("\n -- Retrieve Order --"); let i_order = &i_ob.bids[0].orders[0]; - - let retrieved_order = i_ob.retrieve_order( - i_order.side, - i_order.price, - i_order.order_ts); - println!(" + let retrieved_order = i_ob.retrieve_order(i_order.side, i_order.price, i_order.order_ts); + + println!( + " Order to be found, side: {:?}, price: {:?}, order_ts: {:?}", - i_order.side, - i_order.price, - i_order.order_ts, + i_order.side, i_order.price, i_order.order_ts, ); println!("Retrieved Order: {:?}", retrieved_order); // ----------------------------------------------------- Delete Order -- // // ----------------------------------------------------- ------------ -- // - - // ----------------------------------------------------- Insert Order -- // // ----------------------------------------------------- ------------ -- // - - // ----------------------------------------------------- Modify Order -- // // ----------------------------------------------------- ------------ -- // - } diff --git a/atelier/src/data/market.rs b/atelier/src/data/market.rs index 7150c79..405db6e 100644 --- a/atelier/src/data/market.rs +++ b/atelier/src/data/market.rs @@ -293,7 +293,6 @@ impl Orderbook { pub fn retrieve_level(&self, level_price: &f64) -> Result { // return the level_price if it exists, or, LevelError::LevelNotFound if let Ok(i_level) = self.find_level(level_price) { - // Level is on the Bid side if i_level < 0 { let i_level = i_level.abs() + 1; @@ -322,32 +321,28 @@ impl Orderbook { /// /// ## Parameters /// level_price: &f64 - + pub fn delete_level(&mut self, level_price: &f64) -> Result<(), LevelError> { - // see if level exists let find_level_ob = self.find_level(level_price); - - match find_level_ob { + match find_level_ob { Ok(n) if n < 0 => { - - let bid_found = find_level_ob.unwrap().abs() as usize -1; + let bid_found = find_level_ob.unwrap().abs() as usize - 1; self.bids.remove(bid_found); Ok(()) - }, - + } + Ok(n) if n > 0 => { - let ask_found = find_level_ob.unwrap() as usize -1 ; + let ask_found = find_level_ob.unwrap() as usize - 1; self.asks.remove(ask_found); Ok(()) - }, - + } + Err(e) => Err(LevelError::LevelDeletionFailed), - + Ok(_) => Err(LevelError::LevelInfoNotAvailable), } - } // ----------------------------------------------- Insert a New Level -- // @@ -365,14 +360,11 @@ impl Orderbook { /// Ok(Level) /// Err(LevelError): Custom Error Type of LevelInsertionFailed. /// - pub fn insert_level(&mut self, level: Level, - ) -> Result<(), LevelError> { - + pub fn insert_level(&mut self, level: Level) -> Result<(), LevelError> { // return the level_price if it exists, or, LevelError::LevelNotFound if let Ok(i_level) = self.find_level(&level.price) { - println!("i_level found: {:?}", &i_level); - + // -- Level exist on the Bid side (to be replaced) if i_level < 0 { // updated counter to this side @@ -380,15 +372,15 @@ impl Orderbook { // use the same id for the level let same_level_id = &self.bids[i_level as usize].level_id; // override existing level with the new one - self.bids[i_level as usize] = - Level::new( - *same_level_id, - Side::Bids, - level.price, - level.volume, - level.orders); - - return Ok(()) + self.bids[i_level as usize] = Level::new( + *same_level_id, + Side::Bids, + level.price, + level.volume, + level.orders, + ); + + return Ok(()); // -- Level exist on the Ask side (to be replaced) } else if i_level > 0 { @@ -397,79 +389,80 @@ impl Orderbook { // use the same id for the level let same_level_id = &self.asks[i_level as usize].level_id; // override existing level with new one - self.asks[i_level as usize] = - Level::new( - *same_level_id, - level.side, - level.price, - level.volume, - level.orders); - - return Ok(()) - + self.asks[i_level as usize] = Level::new( + *same_level_id, + level.side, + level.price, + level.volume, + level.orders, + ); + + return Ok(()); + // A response was produced but with an error on level index } else { - // find the right position within the vector // and insert new Level there - + println!("i_level found: {:?}", &i_level); - + return Err(LevelError::LevelNotFound); } // Level not found. // Localize index, insert into vector. } else { - match level.side { - Side::Bids => { - // Get the level_price for all levels in the vector let mut v_bids = self.bids.clone().into_iter(); - - // Find position : Start with the upper most position + + // Find position : Start with the upper most position // (given the ordering in orders) - let index_level = v_bids.position( - |existing_level| level.price > existing_level.price) + let index_level = v_bids + .position(|existing_level| level.price > existing_level.price) .unwrap_or(v_bids.len()); // Insert new Level into the existing vector of levels. - self.bids.insert(index_level, - Level::new(index_level as u32, - level.side, - level.price, - level.volume, - level.orders) - ); - return Ok(()) - }, + self.bids.insert( + index_level, + Level::new( + index_level as u32, + level.side, + level.price, + level.volume, + level.orders, + ), + ); + return Ok(()); + } Side::Asks => { - // get the level_price for all levels in the vector let mut v_asks = self.asks.clone().into_iter(); - // Find position : Start with the lower and top most position + // Find position : Start with the lower and top most position // (given the ordering in orders) - let index_level = v_asks.position( - |existing_level| level.price < existing_level.price) + let index_level = v_asks + .position(|existing_level| level.price < existing_level.price) .unwrap_or(v_asks.len()); // Insert the new level into the existing vector of levels. - self.asks.insert(index_level, - Level::new(index_level as u32, - level.side, - level.price, - level.volume, - level.orders)); - return Ok(()) + self.asks.insert( + index_level, + Level::new( + index_level as u32, + level.side, + level.price, + level.volume, + level.orders, + ), + ); + return Ok(()); } - } + } } - - return Err(LevelError::LevelNotFound); + return Err(LevelError::LevelNotFound); } // ---------------------------------------------------- Find an Order -- // @@ -493,51 +486,45 @@ impl Orderbook { price: f64, order_ts: u64, ) -> Result<(i32, usize), OrderError> { - // see if level exists let find_level_ob = self.find_level(&price); match find_level_ob { - Ok(n) if n < 0 => { - - let level_found = find_level_ob.unwrap().abs() as usize -1; + let level_found = find_level_ob.unwrap().abs() as usize - 1; let level_orders = &self.bids[level_found].orders; // Level has orders if level_orders.len() > 0 { - let r_level = level_orders .binary_search_by(|order| order.order_ts.cmp(&order_ts)) .unwrap(); - + Ok((n, r_level)) // Level is empty } else { Err(OrderError::OrderNotFound) } - }, + } Ok(n) if n > 0 => { - - let level_found = find_level_ob.unwrap().abs() as usize -1; + let level_found = find_level_ob.unwrap().abs() as usize - 1; let level_orders = &self.asks[level_found].orders; // Level has orders if level_orders.len() > 0 { - let r_level = level_orders .binary_search_by(|order| order.order_ts.cmp(&order_ts)) .unwrap(); - + Ok((n, r_level)) - + // Level is empty } else { Err(OrderError::OrderNotFound) } - }, - + } + Err(e) => Err(OrderError::OrderNotFound), Ok(_) => Err(OrderError::OrderInfoNotAvailable), } @@ -557,19 +544,15 @@ impl Orderbook { pub fn retrieve_order( &self, side: Side, - price: f64, + price: f64, order_ts: u64, ) -> Result<(Order), OrderError> { - - if let Ok((found_level, found_order)) = self.find_order( - side, price, order_ts) { - + if let Ok((found_level, found_order)) = self.find_order(side, price, order_ts) { if found_level > 0 { Ok(self.asks[found_level.abs() as usize].orders[found_order]) } else { Ok(self.bids[found_level.abs() as usize].orders[found_order]) } - } else { Err(OrderError::OrderNotFound) } @@ -585,32 +568,19 @@ impl Orderbook { /// ## Results /// - pub fn delete_order( - &self, - side: Side, - price: f64, - order_ts: u64) -> Result<(), OrderError> { - + pub fn delete_order(&self, side: Side, price: f64, order_ts: u64) -> Result<(), OrderError> { // find the order // delete the order - - if let Ok((found_level, found_order)) = self.find_order( - side, price, order_ts) { + if let Ok((found_level, found_order)) = self.find_order(side, price, order_ts) { if found_level > 0 { - self.asks[found_level.abs() as usize].orders[found_order] - } else { - self.bids[found_level.abs() as usize].orders[found_order] } - } else { Err(OrderError::OrderNotFound) } - - } // ----------------------------------------------- Insert a New Order -- // diff --git a/tests/orderbook/implementations.rs b/tests/orderbook/implementations.rs index 5e6548d..750156f 100644 --- a/tests/orderbook/implementations.rs +++ b/tests/orderbook/implementations.rs @@ -1,4 +1,3 @@ - #[cfg(test)] mod tests { @@ -12,83 +11,75 @@ mod tests { // ------------------------------------------------------------------ FIND_LEVEL -- / // ------------------------------------------------------------------ ---------- -- / - + #[test] fn find_level() { + let test_ob = Orderbook::synthetize(BID_PRICE, ASK_PRICE, TICK_SIZE, N_LEVELS, N_ORDERS); - let test_ob = Orderbook::synthetize( - BID_PRICE, - ASK_PRICE, - TICK_SIZE, - N_LEVELS, - N_ORDERS); - // the price of the level to be searched. - - let t_level_price = 50_300.00; + + let t_level_price = 50_300.00; let level_found = test_ob.find_level(&t_level_price).unwrap(); - + // println!("level_found content: {:?}", level_found); - - assert_eq!(level_found, 1); + assert_eq!(level_found, 1); } } - // -------------------------------------------------------------- RETRIEVE_LEVEL -- / - // -------------------------------------------------------------- -------------- -- / - - // #[test] - // fn retrieve_level() { - // } - - // ---------------------------------------------------------------- DELETE_LEVEL -- / - // ---------------------------------------------------------------- ------------ -- / - - // #[test] - // fn delete_level() { - // } - - // ---------------------------------------------------------------- INSERT_LEVEL -- / - // ---------------------------------------------------------------- ------------ -- / - - // #[test] - // fn insert_level() { - // } - - // ------------------------------------------------------------------ FIND_ORDER -- / - // ------------------------------------------------------------------ ---------- -- / - - // #[test] - // fn find_order() { - // } - - // -------------------------------------------------------------- RETRIEVE_ORDER -- / - // -------------------------------------------------------------- -------------- -- / - - // #[test] - // fn retrieve_order() { - // } - - // ---------------------------------------------------------------- DELETE_ORDER -- / - // ---------------------------------------------------------------- ------------ -- / - - // #[test] - // fn delete_order() { - // } - - // ---------------------------------------------------------------- INSERT_ORDER -- / - // ---------------------------------------------------------------- ------------ -- / - - // #[test] - // fn insert_order() { - // } - - // ---------------------------------------------------------------- MODIFY_ORDER -- / - // ---------------------------------------------------------------- ------------ -- / - - // #[test] - // fn modify_order() { - // } +// -------------------------------------------------------------- RETRIEVE_LEVEL -- / +// -------------------------------------------------------------- -------------- -- / -//} +// #[test] +// fn retrieve_level() { +// } + +// ---------------------------------------------------------------- DELETE_LEVEL -- / +// ---------------------------------------------------------------- ------------ -- / + +// #[test] +// fn delete_level() { +// } + +// ---------------------------------------------------------------- INSERT_LEVEL -- / +// ---------------------------------------------------------------- ------------ -- / + +// #[test] +// fn insert_level() { +// } +// ------------------------------------------------------------------ FIND_ORDER -- / +// ------------------------------------------------------------------ ---------- -- / + +// #[test] +// fn find_order() { +// } + +// -------------------------------------------------------------- RETRIEVE_ORDER -- / +// -------------------------------------------------------------- -------------- -- / + +// #[test] +// fn retrieve_order() { +// } + +// ---------------------------------------------------------------- DELETE_ORDER -- / +// ---------------------------------------------------------------- ------------ -- / + +// #[test] +// fn delete_order() { +// } + +// ---------------------------------------------------------------- INSERT_ORDER -- / +// ---------------------------------------------------------------- ------------ -- / + +// #[test] +// fn insert_order() { +// } + +// ---------------------------------------------------------------- MODIFY_ORDER -- / +// ---------------------------------------------------------------- ------------ -- / + +// #[test] +// fn modify_order() { +// } + +//}