mirror of
https://github.com/0xShay/rust-orderbook.git
synced 2026-01-11 13:13:24 +00:00
add individual order logic
This commit is contained in:
@@ -3,6 +3,7 @@ use std::str::SplitWhitespace;
|
|||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
pub mod orderbook;
|
pub mod orderbook;
|
||||||
|
pub mod order;
|
||||||
|
|
||||||
use crate::orderbook::Orderbook;
|
use crate::orderbook::Orderbook;
|
||||||
|
|
||||||
|
|||||||
24
src/order.rs
Normal file
24
src/order.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub enum OrderType {
|
||||||
|
BUY,
|
||||||
|
SELL,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Order {
|
||||||
|
pub order_type: OrderType,
|
||||||
|
pub size: i32,
|
||||||
|
pub filled: i32,
|
||||||
|
pub price: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Order {
|
||||||
|
pub fn new(order_type: OrderType, size: i32, filled: i32, price: i32) -> Order {
|
||||||
|
Order {
|
||||||
|
order_type,
|
||||||
|
size,
|
||||||
|
filled,
|
||||||
|
price
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,15 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use crate::order::Order;
|
||||||
|
use crate::order::OrderType;
|
||||||
|
|
||||||
pub struct Orderbook {
|
pub struct Orderbook {
|
||||||
// both of these maps map a price to a quantity
|
// both of these maps map a price to a quantity
|
||||||
pub bids: BTreeMap<i32, i32>,
|
bids: BTreeMap<i32, i32>,
|
||||||
pub asks: BTreeMap<i32, i32>,
|
asks: BTreeMap<i32, i32>,
|
||||||
|
buy_orders: BTreeMap<i32, VecDeque<Order>>,
|
||||||
|
sell_orders: BTreeMap<i32, VecDeque<Order>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_hashtag_loop(n: usize) -> String {
|
fn gen_hashtag_loop(n: usize) -> String {
|
||||||
@@ -16,6 +22,8 @@ impl Orderbook {
|
|||||||
Orderbook {
|
Orderbook {
|
||||||
bids: BTreeMap::new(),
|
bids: BTreeMap::new(),
|
||||||
asks: BTreeMap::new(),
|
asks: BTreeMap::new(),
|
||||||
|
buy_orders: BTreeMap::new(),
|
||||||
|
sell_orders: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,16 +38,26 @@ impl Orderbook {
|
|||||||
for _ in 0..(5 - self.asks.len()) { println!(); };
|
for _ in 0..(5 - self.asks.len()) { println!(); };
|
||||||
};
|
};
|
||||||
|
|
||||||
for ask in self.asks.iter().take(5).rev() {
|
for ask in self.asks.iter().take(3).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.")));
|
||||||
|
print!("(");
|
||||||
|
for order in self.sell_orders.get(ask.0).unwrap() {
|
||||||
|
print!("{}, ", order.size - order.filled);
|
||||||
|
};
|
||||||
|
println!(")");
|
||||||
};
|
};
|
||||||
println!("-------------------------------");
|
println!("-------------------------------");
|
||||||
|
|
||||||
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!("{:.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 self.bids.iter().rev().take(5) {
|
for bid in self.bids.iter().rev().take(3) {
|
||||||
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.")));
|
||||||
|
print!("(");
|
||||||
|
for order in self.buy_orders.get(bid.0).unwrap() {
|
||||||
|
print!("{}, ", order.size - order.filled);
|
||||||
|
};
|
||||||
|
println!(")");
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.bids.len() < 5 {
|
if self.bids.len() < 5 {
|
||||||
@@ -61,6 +79,14 @@ impl Orderbook {
|
|||||||
self.bids.insert(price, quantity);
|
self.bids.insert(price, quantity);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
match self.buy_orders.get_mut(&price) {
|
||||||
|
Some(vd) => {
|
||||||
|
vd.push_back(Order::new(OrderType::BUY, quantity, 0, price));
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.buy_orders.insert(price, VecDeque::from([Order::new(OrderType::BUY, quantity, 0, price)]));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_sell_order(&mut self, quantity: i32, price: i32) {
|
fn create_sell_order(&mut self, quantity: i32, price: i32) {
|
||||||
@@ -75,6 +101,30 @@ impl Orderbook {
|
|||||||
self.asks.insert(price, quantity);
|
self.asks.insert(price, quantity);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
match self.sell_orders.get_mut(&price) {
|
||||||
|
Some(vd) => {
|
||||||
|
vd.push_back(Order::new(OrderType::SELL, quantity, 0, price));
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.sell_orders.insert(price, VecDeque::from([Order::new(OrderType::SELL, quantity, 0, price)]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_orders_of_quantity(queue: &mut VecDeque<Order>, quantity: i32) {
|
||||||
|
let mut remaining = quantity;
|
||||||
|
while remaining > 0 {
|
||||||
|
let front_order = queue.front_mut().unwrap();
|
||||||
|
let to_fill = front_order.size - front_order.filled;
|
||||||
|
if remaining >= to_fill {
|
||||||
|
queue.pop_front();
|
||||||
|
remaining -= to_fill;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
front_order.filled += remaining;
|
||||||
|
remaining = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn market_buy(&mut self, quantity: i32) {
|
pub fn market_buy(&mut self, quantity: i32) {
|
||||||
@@ -91,6 +141,9 @@ impl Orderbook {
|
|||||||
// increase total_value
|
// increase total_value
|
||||||
total_value += left_to_buy * p;
|
total_value += left_to_buy * p;
|
||||||
|
|
||||||
|
// update orders
|
||||||
|
Self::clear_orders_of_quantity(self.sell_orders.get_mut(&p).unwrap(), left_to_buy);
|
||||||
|
|
||||||
println!("Bought {} @ ${:.2}", left_to_buy, p);
|
println!("Bought {} @ ${:.2}", left_to_buy, p);
|
||||||
|
|
||||||
// reduce left_to_buy
|
// reduce left_to_buy
|
||||||
@@ -102,6 +155,9 @@ impl Orderbook {
|
|||||||
// reduce left_to_buy
|
// reduce left_to_buy
|
||||||
left_to_buy -= q;
|
left_to_buy -= q;
|
||||||
|
|
||||||
|
// clear orders
|
||||||
|
self.sell_orders.insert(p, VecDeque::new());
|
||||||
|
|
||||||
println!("Bought {} @ ${:.2}", q, p);
|
println!("Bought {} @ ${:.2}", q, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,6 +183,9 @@ impl Orderbook {
|
|||||||
// increase total_value
|
// increase total_value
|
||||||
total_value += left_to_sell * p;
|
total_value += left_to_sell * p;
|
||||||
|
|
||||||
|
// update orders
|
||||||
|
Self::clear_orders_of_quantity(self.buy_orders.get_mut(&p).unwrap(), left_to_sell);
|
||||||
|
|
||||||
println!("Sold {} @ ${:.2}", left_to_sell, p);
|
println!("Sold {} @ ${:.2}", left_to_sell, p);
|
||||||
|
|
||||||
// reduce left_to_sell
|
// reduce left_to_sell
|
||||||
@@ -138,6 +197,9 @@ impl Orderbook {
|
|||||||
// reduce left_to_sell
|
// reduce left_to_sell
|
||||||
left_to_sell -= q;
|
left_to_sell -= q;
|
||||||
|
|
||||||
|
// clear orders
|
||||||
|
self.buy_orders.insert(p, VecDeque::new());
|
||||||
|
|
||||||
println!("Sold {} @ ${:.2}", q, p);
|
println!("Sold {} @ ${:.2}", q, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,6 +238,9 @@ impl Orderbook {
|
|||||||
total_value += left_to_buy * p;
|
total_value += left_to_buy * p;
|
||||||
total_quantity += left_to_buy;
|
total_quantity += left_to_buy;
|
||||||
|
|
||||||
|
// update orders
|
||||||
|
Self::clear_orders_of_quantity(self.sell_orders.get_mut(&p).unwrap(), left_to_buy);
|
||||||
|
|
||||||
println!("Bought {} @ ${:.2}", left_to_buy, p);
|
println!("Bought {} @ ${:.2}", left_to_buy, p);
|
||||||
|
|
||||||
// reduce left_to_buy
|
// reduce left_to_buy
|
||||||
@@ -188,6 +253,9 @@ impl Orderbook {
|
|||||||
// reduce left_to_buy
|
// reduce left_to_buy
|
||||||
left_to_buy -= q;
|
left_to_buy -= q;
|
||||||
|
|
||||||
|
// clear orders
|
||||||
|
self.sell_orders.insert(p, VecDeque::new());
|
||||||
|
|
||||||
println!("Bought {} @ ${:.2}", q, p);
|
println!("Bought {} @ ${:.2}", q, p);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -233,6 +301,9 @@ impl Orderbook {
|
|||||||
total_value += left_to_sell * p;
|
total_value += left_to_sell * p;
|
||||||
total_quantity += left_to_sell;
|
total_quantity += left_to_sell;
|
||||||
|
|
||||||
|
// update orders
|
||||||
|
Self::clear_orders_of_quantity(self.buy_orders.get_mut(&p).unwrap(), left_to_sell);
|
||||||
|
|
||||||
println!("Sold {} @ ${:.2}", left_to_sell, p);
|
println!("Sold {} @ ${:.2}", left_to_sell, p);
|
||||||
|
|
||||||
// reduce left_to_sell
|
// reduce left_to_sell
|
||||||
@@ -245,6 +316,9 @@ impl Orderbook {
|
|||||||
// reduce left_to_sell
|
// reduce left_to_sell
|
||||||
left_to_sell -= q;
|
left_to_sell -= q;
|
||||||
|
|
||||||
|
// clear orders
|
||||||
|
self.buy_orders.insert(p, VecDeque::new());
|
||||||
|
|
||||||
println!("Sold {} @ ${:.2}", q, p);
|
println!("Sold {} @ ${:.2}", q, p);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user