move methods into Orderbook impl

This commit is contained in:
2025-08-15 08:50:14 +01:00
parent 68540f7c59
commit 8d621729b5
2 changed files with 256 additions and 251 deletions

View File

@@ -1,11 +1,10 @@
use std::io; use std::io;
use std::collections::BTreeMap;
use std::str::SplitWhitespace; use std::str::SplitWhitespace;
use std::time::SystemTime; use std::time::SystemTime;
pub mod orderbook; pub mod orderbook;
use crate::orderbook::*; use crate::orderbook::Orderbook;
fn read_in_quantity_and_price(split: &mut SplitWhitespace<'_>, quantity: &mut i32, price: &mut Option<i32>) { fn read_in_quantity_and_price(split: &mut SplitWhitespace<'_>, quantity: &mut i32, price: &mut Option<i32>) {
let quantity_opt_str: Option<&str> = split.next(); let quantity_opt_str: Option<&str> = split.next();
@@ -37,15 +36,12 @@ fn read_in_quantity_and_price(split: &mut SplitWhitespace<'_>, quantity: &mut i3
fn main() { fn main() {
let mut input_string = String::new(); let mut input_string = String::new();
let mut ob = Orderbook { let mut ob = Orderbook::new();
bids: BTreeMap::new(),
asks: BTreeMap::new(),
};
populate_orderbook(&mut ob); ob.populate_orderbook();
println!(); println!();
list_orders(&ob); ob.list_orders();
while input_string.trim() != "EXIT" { while input_string.trim() != "EXIT" {
input_string.clear(); input_string.clear();
@@ -73,10 +69,10 @@ fn main() {
match price_opt { match price_opt {
None => { None => {
market_buy(&mut ob, quantity); ob.market_buy(quantity);
}, },
Some(price) => { Some(price) => {
limit_buy(&mut ob, quantity, price); ob.limit_buy(quantity, price);
} }
}; };
}, },
@@ -87,10 +83,10 @@ fn main() {
match price_opt { match price_opt {
None => { None => {
market_sell(&mut ob, quantity); ob.market_sell(quantity);
}, },
Some(price) => { Some(price) => {
limit_sell(&mut ob, quantity, price); ob.limit_sell(quantity, price);
} }
}; };
}, },
@@ -105,7 +101,7 @@ fn main() {
println!("Executed in {}μs", difference.as_micros()); println!("Executed in {}μs", difference.as_micros());
println!(); println!();
list_orders(&ob); ob.list_orders();
} }
println!("Program terminating."); println!("Program terminating.");

View File

@@ -11,74 +11,82 @@ fn gen_hashtag_loop(n: usize) -> String {
return hashtags; return hashtags;
} }
pub fn list_orders(ob: &Orderbook) { impl Orderbook {
pub fn new() -> Orderbook {
Orderbook {
bids: BTreeMap::new(),
asks: BTreeMap::new(),
}
}
pub fn list_orders(&self) {
println!("==============================="); println!("===============================");
println!(); println!();
println!("{:<5} {:>13}", "PRICE", "QUANTITY"); println!("{:<5} {:>13}", "PRICE", "QUANTITY");
println!(); println!();
if ob.asks.len() < 5 { if self.asks.len() < 5 {
for _ in 0..(5 - ob.asks.len()) { println!(); }; for _ in 0..(5 - self.asks.len()) { println!(); };
}; };
for ask in ob.asks.iter().take(5).rev() { for ask in self.asks.iter().take(5).rev() {
println!("${:<4.2} {:>4} {}", ask.0, ask.1, gen_hashtag_loop((*ask.1).try_into().expect("Failed to format i32 as usize."))); println!("${:<4.2} {:>4} {}", ask.0, ask.1, gen_hashtag_loop((*ask.1).try_into().expect("Failed to format i32 as usize.")));
}; };
println!("-------------------------------"); println!("-------------------------------");
println!("{:.2}bps", (100.0 * ((*ob.asks.first_key_value().expect("One-sided order book.").0 as f32 / *ob.bids.last_key_value().expect("One-sided order book.").0 as f32) - 1.0))); println!("{:.2}bps", (100.0 * ((*self.asks.first_key_value().expect("One-sided order book.").0 as f32 / *self.bids.last_key_value().expect("One-sided order book.").0 as f32) - 1.0)));
println!("-------------------------------"); println!("-------------------------------");
for bid in ob.bids.iter().rev().take(5) { for bid in self.bids.iter().rev().take(5) {
println!("${:<4.2} {:>4} {}", bid.0, bid.1, gen_hashtag_loop((*bid.1).try_into().expect("Failed to format i32 as usize."))); println!("${:<4.2} {:>4} {}", bid.0, bid.1, gen_hashtag_loop((*bid.1).try_into().expect("Failed to format i32 as usize.")));
}; };
if ob.bids.len() < 5 { if self.bids.len() < 5 {
for _ in 0..(5 - ob.bids.len()) { println!(); }; for _ in 0..(5 - self.bids.len()) { println!(); };
}; };
println!(); println!();
} }
fn create_buy_order(ob: &mut Orderbook, quantity: i32, price: i32) { fn create_buy_order(&mut self, quantity: i32, price: i32) {
println!("Placed BUY order ({} @ ${})", quantity, price); println!("Placed BUY order ({} @ ${})", quantity, price);
match ob.bids.get(&price) { match self.bids.get(&price) {
Some(prev_quantity) => { Some(prev_quantity) => {
// add to existing order // add to existing order
ob.bids.insert(price, quantity + prev_quantity); self.bids.insert(price, quantity + prev_quantity);
}, },
None => { None => {
// create new order // create new order
ob.bids.insert(price, quantity); self.bids.insert(price, quantity);
} }
}; };
} }
fn create_sell_order(ob: &mut Orderbook, quantity: i32, price: i32) { fn create_sell_order(&mut self, quantity: i32, price: i32) {
println!("Placed SELL order ({} @ ${})", quantity, price); println!("Placed SELL order ({} @ ${})", quantity, price);
match ob.asks.get(&price) { match self.asks.get(&price) {
Some(prev_quantity) => { Some(prev_quantity) => {
// add to existing order // add to existing order
ob.asks.insert(price, quantity + prev_quantity); self.asks.insert(price, quantity + prev_quantity);
}, },
None => { None => {
// create new order // create new order
ob.asks.insert(price, quantity); self.asks.insert(price, quantity);
} }
}; };
} }
pub fn market_buy(ob: &mut Orderbook, quantity: i32) { pub fn market_buy(&mut self, quantity: i32) {
println!("Performing MARKET BUY: {} @ market price", quantity); println!("Performing MARKET BUY: {} @ market price", quantity);
println!(); println!();
let mut left_to_buy: i32 = quantity; let mut left_to_buy: i32 = quantity;
let mut total_value: i32 = 0; let mut total_value: i32 = 0;
while left_to_buy > 0 { while left_to_buy > 0 {
let (p, q) = ob.asks.pop_first().expect("Insufficient sell volume."); let (p, q) = self.asks.pop_first().expect("Insufficient sell volume.");
if q > left_to_buy { if q > left_to_buy {
// push back sell order with reduced quantity // push back sell order with reduced quantity
ob.asks.insert(p, q-left_to_buy); self.asks.insert(p, q-left_to_buy);
// increase total_value // increase total_value
total_value += left_to_buy * p; total_value += left_to_buy * p;
@@ -105,16 +113,16 @@ pub fn market_buy(ob: &mut Orderbook, quantity: i32) {
}; };
} }
pub fn market_sell(ob: &mut Orderbook, quantity: i32) { pub fn market_sell(&mut self, quantity: i32) {
println!("Performing MARKET SELL: {} @ market price", quantity); println!("Performing MARKET SELL: {} @ market price", quantity);
println!(); println!();
let mut left_to_sell: i32 = quantity; let mut left_to_sell: i32 = quantity;
let mut total_value: i32 = 0; let mut total_value: i32 = 0;
while left_to_sell > 0 { while left_to_sell > 0 {
let (p, q) = ob.bids.pop_last().expect("Insufficient buy volume."); let (p, q) = self.bids.pop_last().expect("Insufficient buy volume.");
if q > left_to_sell { if q > left_to_sell {
// push back buy order with reduced quantity // push back buy order with reduced quantity
ob.bids.insert(p, q-left_to_sell); self.bids.insert(p, q-left_to_sell);
// increase total_value // increase total_value
total_value += left_to_sell * p; total_value += left_to_sell * p;
@@ -141,7 +149,7 @@ pub fn market_sell(ob: &mut Orderbook, quantity: i32) {
}; };
} }
pub fn limit_buy(ob: &mut Orderbook, quantity: i32, price: i32) { pub fn limit_buy(&mut self, quantity: i32, price: i32) {
println!("Performing LIMIT BUY: {} @ ${}", quantity, price); println!("Performing LIMIT BUY: {} @ ${}", quantity, price);
println!(); println!();
let mut left_to_buy: i32 = quantity; let mut left_to_buy: i32 = quantity;
@@ -150,10 +158,10 @@ pub fn limit_buy(ob: &mut Orderbook, quantity: i32, price: i32) {
// check the cheapest sell order - if it doesn't exist, or it does but the price is too high, create a new buy order // check the cheapest sell order - if it doesn't exist, or it does but the price is too high, create a new buy order
while left_to_buy > 0 { while left_to_buy > 0 {
match ob.asks.pop_first() { match self.asks.pop_first() {
None => { None => {
// there are no sell orders, so create a new buy order // there are no sell orders, so create a new buy order
create_buy_order(ob, left_to_buy, price); self.create_buy_order(left_to_buy, price);
left_to_buy = 0; left_to_buy = 0;
}, },
Some((p, q)) => { Some((p, q)) => {
@@ -162,7 +170,7 @@ pub fn limit_buy(ob: &mut Orderbook, quantity: i32, price: i32) {
// cheap enough, fill order as much as possible // cheap enough, fill order as much as possible
if q > left_to_buy { if q > left_to_buy {
// push back sell order with reduced quantity // push back sell order with reduced quantity
ob.asks.insert(p, q-left_to_buy); self.asks.insert(p, q-left_to_buy);
// increase total_value // increase total_value
total_value += left_to_buy * p; total_value += left_to_buy * p;
@@ -183,8 +191,8 @@ pub fn limit_buy(ob: &mut Orderbook, quantity: i32, price: i32) {
println!("Bought {} @ ${:.2}", q, p); println!("Bought {} @ ${:.2}", q, p);
} }
} else { } else {
ob.asks.insert(p, q); self.asks.insert(p, q);
create_buy_order(ob, left_to_buy, price); self.create_buy_order(left_to_buy, price);
left_to_buy = 0; left_to_buy = 0;
} }
} }
@@ -198,7 +206,7 @@ pub fn limit_buy(ob: &mut Orderbook, quantity: i32, price: i32) {
}; };
} }
pub fn limit_sell(ob: &mut Orderbook, quantity: i32, price: i32) { pub fn limit_sell(&mut self, quantity: i32, price: i32) {
println!("Performing LIMIT SELL: {} @ ${}", quantity, price); println!("Performing LIMIT SELL: {} @ ${}", quantity, price);
println!(); println!();
let mut left_to_sell: i32 = quantity; let mut left_to_sell: i32 = quantity;
@@ -207,10 +215,10 @@ pub fn limit_sell(ob: &mut Orderbook, quantity: i32, price: i32) {
// check the most appealing buy order - if it doesn't exist, or it does but the price is too low, create a new sell order // check the most appealing buy order - if it doesn't exist, or it does but the price is too low, create a new sell order
while left_to_sell > 0 { while left_to_sell > 0 {
match ob.bids.pop_last() { match self.bids.pop_last() {
None => { None => {
// there are no buy orders, so create a new sell order // there are no buy orders, so create a new sell order
create_sell_order(ob, left_to_sell, price); self.create_sell_order(left_to_sell, price);
left_to_sell = 0; left_to_sell = 0;
}, },
Some((p, q)) => { Some((p, q)) => {
@@ -219,7 +227,7 @@ pub fn limit_sell(ob: &mut Orderbook, quantity: i32, price: i32) {
// fill order as much as possible // fill order as much as possible
if q > left_to_sell { if q > left_to_sell {
// push back buy order with reduced quantity // push back buy order with reduced quantity
ob.bids.insert(p, q-left_to_sell); self.bids.insert(p, q-left_to_sell);
// increase total_value // increase total_value
total_value += left_to_sell * p; total_value += left_to_sell * p;
@@ -240,8 +248,8 @@ pub fn limit_sell(ob: &mut Orderbook, quantity: i32, price: i32) {
println!("Sold {} @ ${:.2}", q, p); println!("Sold {} @ ${:.2}", q, p);
} }
} else { } else {
ob.bids.insert(p, q); self.bids.insert(p, q);
create_sell_order(ob, left_to_sell, price); self.create_sell_order(left_to_sell, price);
left_to_sell = 0; left_to_sell = 0;
} }
} }
@@ -255,26 +263,27 @@ pub fn limit_sell(ob: &mut Orderbook, quantity: i32, price: i32) {
}; };
} }
pub fn populate_orderbook(ob: &mut Orderbook) { pub fn populate_orderbook(&mut self) {
limit_buy(ob, 5, 8); self.limit_buy(5, 8);
limit_buy(ob, 4, 7); self.limit_buy(4, 7);
limit_buy(ob, 2, 3); self.limit_buy(2, 3);
limit_buy(ob, 6, 8); self.limit_buy(6, 8);
limit_buy(ob, 5, 15); self.limit_buy(5, 15);
limit_buy(ob, 10, 10); self.limit_buy(10, 10);
limit_buy(ob, 8, 9); self.limit_buy(8, 9);
limit_buy(ob, 1, 2); self.limit_buy(1, 2);
limit_buy(ob, 12, 14); self.limit_buy(12, 14);
limit_buy(ob, 7, 5); self.limit_buy(7, 5);
limit_sell(ob, 2, 15); self.limit_sell(2, 15);
limit_sell(ob, 3, 16); self.limit_sell(3, 16);
limit_sell(ob, 3, 17); self.limit_sell(3, 17);
limit_sell(ob, 4, 18); self.limit_sell(4, 18);
limit_sell(ob, 5, 20); self.limit_sell(5, 20);
limit_sell(ob, 6, 18); self.limit_sell(6, 18);
limit_sell(ob, 9, 21); self.limit_sell(9, 21);
limit_sell(ob, 15, 25); self.limit_sell(15, 25);
limit_sell(ob, 2, 19); self.limit_sell(2, 19);
limit_sell(ob, 11, 22); self.limit_sell(11, 22);
}
} }