rust_order_book/
order.rs

1//! This module defines the public API for submitting market and limit orders
2//! via [`MarketOrderOptions`] and [`LimitOrderOptions`].
3//!
4//! Users will not need to interact with internal structs like [`MarketOrder`]
5//! or [`LimitOrder`] directly.
6
7use crate::{
8    utils::{current_timestamp_millis, safe_add, safe_sub},
9    OrderStatus, OrderType, Side, TimeInForce,
10};
11use serde::{Deserialize, Serialize};
12use std::{
13    iter::Sum,
14    ops::{Add, AddAssign, Div, Sub},
15};
16
17#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)]
18pub struct OrderId(pub u64);
19impl AddAssign<u64> for OrderId {
20    fn add_assign(&mut self, rhs: u64) {
21        self.0 += rhs;
22    }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, PartialOrd, Ord)]
26pub struct Price(pub u64);
27impl Price {
28    pub fn value(self) -> u64 {
29        self.0
30    }
31}
32impl Add for Price {
33    type Output = Price;
34
35    fn add(self, rhs: Price) -> Price {
36        Price(safe_add(self.0, rhs.0))
37    }
38}
39
40impl Sub for Price {
41    type Output = Price;
42
43    fn sub(self, rhs: Price) -> Price {
44        Price(safe_sub(self.0, rhs.0))
45    }
46}
47
48impl Div for Price {
49    type Output = Price;
50
51    fn div(self, rhs: Price) -> Price {
52        Price(self.0.saturating_div(rhs.0))
53    }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, PartialOrd)]
57pub struct Quantity(pub u64);
58impl Quantity {
59    pub fn value(self) -> u64 {
60        self.0
61    }
62}
63impl Add for Quantity {
64    type Output = Quantity;
65
66    fn add(self, rhs: Quantity) -> Quantity {
67        Quantity(safe_add(self.0, rhs.0))
68    }
69}
70impl Sub for Quantity {
71    type Output = Quantity;
72
73    fn sub(self, rhs: Quantity) -> Quantity {
74        Quantity(safe_sub(self.0, rhs.0))
75    }
76}
77impl AddAssign<u64> for Quantity {
78    fn add_assign(&mut self, rhs: u64) {
79        self.0 += rhs;
80    }
81}
82impl Sum for Quantity {
83    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
84        Quantity(iter.map(|q| q.0).sum())
85    }
86}
87
88/// Options for submitting a market order to the order book.
89///
90/// Market orders are matched immediately against the best available prices,
91/// consuming liquidity.
92///
93/// # Fields
94/// - `side`: Buy or Sell
95/// - `quantity`: The total amount to trade
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub struct MarketOrderOptions {
98    pub side: Side,
99    pub quantity: Quantity,
100}
101impl MarketOrderOptions {
102    pub fn new(side: Side, quantity: u64) -> Self {
103        Self { side, quantity: Quantity(quantity) }
104    }
105}
106
107#[derive(Debug)]
108pub(crate) struct MarketOrder {
109    pub(crate) id: OrderId,
110    pub(crate) side: Side,
111    pub(crate) orig_qty: Quantity,
112    pub(crate) executed_qty: Quantity,
113    pub(crate) status: OrderStatus,
114}
115
116impl MarketOrder {
117    pub(crate) fn new(id: OrderId, options: MarketOrderOptions) -> MarketOrder {
118        MarketOrder {
119            id,
120            side: options.side,
121            orig_qty: options.quantity,
122            executed_qty: Quantity(0),
123            status: OrderStatus::New,
124        }
125    }
126    pub(crate) fn remaining_qty(&self) -> Quantity {
127        self.orig_qty.sub(self.executed_qty)
128    }
129}
130
131/// Options for submitting a limit order to the order book.
132///
133/// Limit orders rest at a specific price level unless matched immediately.
134/// Time-in-force and post-only logic can be configured.
135///
136/// # Fields
137/// - `side`: Buy or Sell
138/// - `quantity`: Order size
139/// - `price`: Limit price
140/// - `time_in_force`: Optional TIF setting (default: GTC)
141/// - `post_only`: Optional post-only flag (default: false)
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub struct LimitOrderOptions {
144    pub side: Side,
145    pub quantity: Quantity,
146    pub price: Price,
147    pub time_in_force: Option<TimeInForce>,
148    pub post_only: Option<bool>,
149}
150impl LimitOrderOptions {
151    pub fn new(
152        side: Side,
153        quantity: u64,
154        price: u64,
155        time_in_force: Option<TimeInForce>,
156        post_only: Option<bool>,
157    ) -> Self {
158        Self { side, quantity: Quantity(quantity), price: Price(price), time_in_force, post_only }
159    }
160}
161
162/// `LimitOrder` is `pub` so that it can be exposed in public APIs such as
163/// [`crate::OrderBook::get_order`] and included in [`crate::Snapshot`]. Even though the type
164/// is public, its internal fields are private and read-only, so users
165/// can inspect orders and snapshots without being able to mutate the order
166/// book state directly. This ensures safety while allowing serializable
167/// snapshots and journal replay functionality.
168#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
169pub struct LimitOrder {
170    pub(crate) id: OrderId,
171    pub(crate) side: Side,
172    pub(crate) orig_qty: Quantity,
173    pub(crate) executed_qty: Quantity,
174    pub(crate) price: Price,
175    pub(crate) order_type: OrderType,
176    pub(crate) time: i64,
177    pub(crate) time_in_force: TimeInForce,
178    pub(crate) post_only: bool,
179    pub(crate) taker_qty: Quantity,
180    pub(crate) maker_qty: Quantity,
181    pub(crate) status: OrderStatus,
182}
183
184impl LimitOrder {
185    pub(crate) fn new(id: OrderId, options: LimitOrderOptions) -> LimitOrder {
186        LimitOrder {
187            id,
188            side: options.side,
189            orig_qty: options.quantity,
190            executed_qty: Quantity(0),
191            price: options.price,
192            order_type: OrderType::Limit,
193            time: current_timestamp_millis(),
194            time_in_force: get_order_time_in_force(options.time_in_force),
195            post_only: options.post_only.unwrap_or(false),
196            taker_qty: Quantity(0),
197            maker_qty: Quantity(0),
198            status: OrderStatus::New,
199        }
200    }
201
202    pub(crate) fn remaining_qty(&self) -> Quantity {
203        self.orig_qty.sub(self.executed_qty)
204    }
205}
206
207pub(crate) fn get_order_time_in_force(time_in_force: Option<TimeInForce>) -> TimeInForce {
208    time_in_force.unwrap_or(TimeInForce::GTC)
209}