├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src ├── .main.rs.swp ├── main.rs └── matching_engine ├── engine.rs ├── mod.rs └── orderbook.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "rust-trading-engine" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-trading-engine" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /src/.main.rs.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anthdm/rust-trading-engine/03b67b6aaa724091a9c14c73598ff0864dcc642e/src/.main.rs.swp -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod matching_engine; 2 | use matching_engine::engine::{MatchingEngine, TradingPair}; 3 | use matching_engine::orderbook::{BidOrAsk, Order, Orderbook}; 4 | 5 | fn main() { 6 | let buy_order_from_alice = Order::new(BidOrAsk::Bid, 5.5); 7 | let buy_order_from_bob = Order::new(BidOrAsk::Bid, 2.45); 8 | 9 | let mut orderbook = Orderbook::new(); 10 | orderbook.add_order(4.4, buy_order_from_alice); 11 | orderbook.add_order(4.4, buy_order_from_bob); 12 | 13 | let sell_order = Order::new(BidOrAsk::Ask, 6.5); 14 | orderbook.add_order(20.0, sell_order); 15 | 16 | // println!("{:?}", orderbook); 17 | 18 | let mut engine = MatchingEngine::new(); 19 | let pair = TradingPair::new("BTC".to_string(), "USD".to_string()); 20 | engine.add_new_market(pair.clone()); 21 | 22 | let buy_order = Order::new(BidOrAsk::Bid, 6.5); 23 | engine.place_limit_order(pair, 10.000, buy_order).unwrap(); 24 | } 25 | -------------------------------------------------------------------------------- /src/matching_engine/engine.rs: -------------------------------------------------------------------------------- 1 | use super::orderbook::{Order, Orderbook}; 2 | use std::collections::HashMap; 3 | 4 | // BTCUSD 5 | // BTC => BASE 6 | // USD => QUOTE 7 | #[derive(Debug, Eq, PartialEq, Hash, Clone)] 8 | pub struct TradingPair { 9 | base: String, 10 | quote: String, 11 | } 12 | 13 | impl TradingPair { 14 | pub fn new(base: String, quote: String) -> TradingPair { 15 | TradingPair { base, quote } 16 | } 17 | 18 | pub fn to_string(self) -> String { 19 | format!("{}_{}", self.base, self.quote) 20 | } 21 | } 22 | 23 | pub struct MatchingEngine { 24 | orderbooks: HashMap, 25 | } 26 | 27 | impl MatchingEngine { 28 | pub fn new() -> MatchingEngine { 29 | MatchingEngine { 30 | orderbooks: HashMap::new(), 31 | } 32 | } 33 | 34 | pub fn add_new_market(&mut self, pair: TradingPair) { 35 | self.orderbooks.insert(pair.clone(), Orderbook::new()); 36 | 37 | println!("opening new orderbook for market {:?}", pair.to_string()); 38 | } 39 | 40 | pub fn place_limit_order( 41 | &mut self, 42 | pair: TradingPair, 43 | price: f64, 44 | order: Order, 45 | ) -> Result<(), String> { 46 | match self.orderbooks.get_mut(&pair) { 47 | Some(orderbook) => { 48 | orderbook.add_order(price, order); 49 | 50 | println!("placed limit order at price level {}", price); 51 | 52 | Ok(()) 53 | } 54 | None => Err(format!( 55 | "the orderbook for the given trading pair ({}) does not exist", 56 | pair.to_string() 57 | )), 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/matching_engine/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod engine; 2 | pub mod orderbook; 3 | -------------------------------------------------------------------------------- /src/matching_engine/orderbook.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | #[derive(Debug)] 4 | pub enum BidOrAsk { 5 | Bid, 6 | Ask, 7 | } 8 | 9 | #[derive(Debug)] 10 | pub struct Orderbook { 11 | asks: HashMap, 12 | bids: HashMap, 13 | } 14 | 15 | impl Orderbook { 16 | pub fn new() -> Orderbook { 17 | Orderbook { 18 | asks: HashMap::new(), 19 | bids: HashMap::new(), 20 | } 21 | } 22 | 23 | pub fn fill_market_order(&mut self, market_order: &mut Order) { 24 | match market_order.bid_or_ask { 25 | BidOrAsk::Bid => { 26 | for limit_order in self.ask_limits() { 27 | limit_order.fill_order(market_order); 28 | 29 | if market_order.is_filled() { 30 | break; 31 | } 32 | } 33 | } 34 | BidOrAsk::Ask => {} 35 | } 36 | } 37 | 38 | // TODO: Sorting!! 39 | pub fn ask_limits(&mut self) -> Vec<&mut Limit> { 40 | self.asks.values_mut().collect::>() 41 | } 42 | 43 | pub fn bid_limits(&mut self) -> Vec<&mut Limit> { 44 | self.bids.values_mut().collect::>() 45 | } 46 | 47 | pub fn add_order(&mut self, price: f64, order: Order) { 48 | let price = Price::new(price); 49 | 50 | match order.bid_or_ask { 51 | BidOrAsk::Bid => match self.bids.get_mut(&price) { 52 | Some(limit) => limit.add_order(order), 53 | None => { 54 | let mut limit = Limit::new(price); 55 | limit.add_order(order); 56 | self.bids.insert(price, limit); 57 | } 58 | }, 59 | BidOrAsk::Ask => match self.asks.get_mut(&price) { 60 | Some(limit) => limit.add_order(order), 61 | None => { 62 | let mut limit = Limit::new(price); 63 | limit.add_order(order); 64 | self.asks.insert(price, limit); 65 | } 66 | }, 67 | } 68 | } 69 | } 70 | 71 | #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] 72 | pub struct Price { 73 | integral: u64, 74 | fractional: u64, 75 | scalar: u64, 76 | } 77 | 78 | impl Price { 79 | pub fn new(price: f64) -> Price { 80 | let scalar = 100000; 81 | let integral = price as u64; 82 | let fractional = ((price % 1.0) * scalar as f64) as u64; 83 | Price { 84 | scalar, 85 | integral, 86 | fractional, 87 | } 88 | } 89 | } 90 | 91 | #[derive(Debug)] 92 | pub struct Limit { 93 | price: Price, 94 | orders: Vec, 95 | } 96 | 97 | impl Limit { 98 | pub fn new(price: Price) -> Limit { 99 | Limit { 100 | price, 101 | orders: Vec::new(), 102 | } 103 | } 104 | 105 | fn total_volume(&self) -> f64 { 106 | self.orders 107 | .iter() 108 | .map(|order| order.size) 109 | .reduce(|a, b| a + b) 110 | .unwrap() 111 | } 112 | 113 | fn fill_order(&mut self, market_order: &mut Order) { 114 | for limit_order in self.orders.iter_mut() { 115 | match market_order.size >= limit_order.size { 116 | true => { 117 | market_order.size -= limit_order.size; 118 | limit_order.size = 0.0 119 | } 120 | false => { 121 | limit_order.size -= market_order.size; 122 | market_order.size = 0.0 123 | } 124 | } 125 | 126 | if market_order.is_filled() { 127 | break; 128 | } 129 | } 130 | } 131 | 132 | fn add_order(&mut self, order: Order) { 133 | self.orders.push(order); 134 | } 135 | } 136 | 137 | #[derive(Debug)] 138 | pub struct Order { 139 | size: f64, 140 | bid_or_ask: BidOrAsk, 141 | } 142 | 143 | impl Order { 144 | pub fn new(bid_or_ask: BidOrAsk, size: f64) -> Order { 145 | Order { bid_or_ask, size } 146 | } 147 | 148 | pub fn is_filled(&self) -> bool { 149 | self.size == 0.0 150 | } 151 | } 152 | 153 | #[cfg(test)] 154 | pub mod tests { 155 | use super::*; 156 | 157 | #[test] 158 | fn limit_total_volume() { 159 | let price = Price::new(10000.0); 160 | let mut limit = Limit::new(price); 161 | let buy_limit_order_a = Order::new(BidOrAsk::Bid, 100.0); 162 | let buy_limit_order_b = Order::new(BidOrAsk::Bid, 100.0); 163 | 164 | limit.add_order(buy_limit_order_a); 165 | limit.add_order(buy_limit_order_b); 166 | 167 | assert_eq!(limit.total_volume(), 200.0) 168 | } 169 | 170 | #[test] 171 | fn limit_order_multi_fill() { 172 | let price = Price::new(10000.0); 173 | let mut limit = Limit::new(price); 174 | let buy_limit_order_a = Order::new(BidOrAsk::Bid, 100.0); 175 | let buy_limit_order_b = Order::new(BidOrAsk::Bid, 100.0); 176 | limit.add_order(buy_limit_order_a); 177 | limit.add_order(buy_limit_order_b); 178 | 179 | let mut market_sell_order = Order::new(BidOrAsk::Ask, 199.0); 180 | limit.fill_order(&mut market_sell_order); 181 | 182 | assert_eq!(market_sell_order.is_filled(), true); 183 | assert_eq!(limit.orders.get(0).unwrap().is_filled(), true); 184 | assert_eq!(limit.orders.get(1).unwrap().is_filled(), false); 185 | assert_eq!(limit.orders.get(1).unwrap().size, 1.0); 186 | } 187 | 188 | #[test] 189 | fn limit_order_single_fill() { 190 | let price = Price::new(10000.0); 191 | let mut limit = Limit::new(price); 192 | let buy_limit_order = Order::new(BidOrAsk::Bid, 100.0); 193 | limit.add_order(buy_limit_order); 194 | 195 | let mut market_sell_order = Order::new(BidOrAsk::Ask, 99.0); 196 | limit.fill_order(&mut market_sell_order); 197 | 198 | assert_eq!(market_sell_order.is_filled(), true); 199 | assert_eq!(limit.orders.get(0).unwrap().size, 1.0); 200 | } 201 | } 202 | --------------------------------------------------------------------------------