1use std::{
19 fmt::{Debug, Display},
20 hash::{Hash, Hasher},
21};
22
23use nautilus_core::serialization::Serializable;
24use serde::{Deserialize, Serialize};
25
26use crate::{
27 enums::OrderSide,
28 orderbook::{BookIntegrityError, BookPrice},
29 types::{Price, Quantity},
30};
31
32pub type OrderId = u64;
33
34pub const NULL_ORDER: BookOrder = BookOrder {
36 side: OrderSide::NoOrderSide,
37 price: Price {
38 raw: 0,
39 precision: 0,
40 },
41 size: Quantity {
42 raw: 0,
43 precision: 0,
44 },
45 order_id: 0,
46};
47
48#[repr(C)]
50#[derive(Clone, Copy, Eq, Serialize, Deserialize)]
51#[cfg_attr(
52 feature = "python",
53 pyo3::pyclass(module = "posei_trader.core.nautilus_pyo3.model")
54)]
55pub struct BookOrder {
56 pub side: OrderSide,
58 pub price: Price,
60 pub size: Quantity,
62 pub order_id: OrderId,
64}
65
66impl BookOrder {
67 #[must_use]
69 pub fn new(side: OrderSide, price: Price, size: Quantity, order_id: OrderId) -> Self {
70 Self {
71 side,
72 price,
73 size,
74 order_id,
75 }
76 }
77
78 #[must_use]
80 pub fn to_book_price(&self) -> BookPrice {
81 BookPrice::new(self.price, self.side.as_specified())
82 }
83
84 #[must_use]
86 pub fn exposure(&self) -> f64 {
87 self.price.as_f64() * self.size.as_f64()
88 }
89
90 #[must_use]
96 pub fn signed_size(&self) -> f64 {
97 match self.side {
98 OrderSide::Buy => self.size.as_f64(),
99 OrderSide::Sell => -(self.size.as_f64()),
100 _ => panic!("{}", BookIntegrityError::NoOrderSide),
101 }
102 }
103}
104
105impl Default for BookOrder {
106 fn default() -> Self {
108 NULL_ORDER
109 }
110}
111
112impl PartialEq for BookOrder {
113 fn eq(&self, other: &Self) -> bool {
114 self.order_id == other.order_id
115 }
116}
117
118impl Hash for BookOrder {
119 fn hash<H: Hasher>(&self, state: &mut H) {
120 self.order_id.hash(state);
121 }
122}
123
124impl Debug for BookOrder {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 write!(
127 f,
128 "{}(side={}, price={}, size={}, order_id={})",
129 stringify!(BookOrder),
130 self.side,
131 self.price,
132 self.size,
133 self.order_id,
134 )
135 }
136}
137
138impl Display for BookOrder {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 write!(
141 f,
142 "{},{},{},{}",
143 self.side, self.price, self.size, self.order_id,
144 )
145 }
146}
147
148impl Serializable for BookOrder {}
149
150#[cfg(test)]
154mod tests {
155 use rstest::rstest;
156
157 use super::*;
158
159 #[rstest]
160 fn test_new() {
161 let price = Price::from("100.00");
162 let size = Quantity::from("10");
163 let side = OrderSide::Buy;
164 let order_id = 123_456;
165
166 let order = BookOrder::new(side, price, size, order_id);
167
168 assert_eq!(order.price, price);
169 assert_eq!(order.size, size);
170 assert_eq!(order.side, side);
171 assert_eq!(order.order_id, order_id);
172 }
173
174 #[rstest]
175 fn test_to_book_price() {
176 let price = Price::from("100.00");
177 let size = Quantity::from("10");
178 let side = OrderSide::Buy;
179 let order_id = 123_456;
180
181 let order = BookOrder::new(side, price, size, order_id);
182 let book_price = order.to_book_price();
183
184 assert_eq!(book_price.value, price);
185 assert_eq!(book_price.side, side.as_specified());
186 }
187
188 #[rstest]
189 fn test_exposure() {
190 let price = Price::from("100.00");
191 let size = Quantity::from("10");
192 let side = OrderSide::Buy;
193 let order_id = 123_456;
194
195 let order = BookOrder::new(side, price, size, order_id);
196 let exposure = order.exposure();
197
198 assert_eq!(exposure, 100.00 * 10.0);
199 }
200
201 #[rstest]
202 fn test_signed_size() {
203 let price = Price::from("100.00");
204 let size = Quantity::from("10");
205 let order_id = 123_456;
206
207 let order_buy = BookOrder::new(OrderSide::Buy, price, size, order_id);
208 let signed_size_buy = order_buy.signed_size();
209 assert_eq!(signed_size_buy, 10.0);
210
211 let order_sell = BookOrder::new(OrderSide::Sell, price, size, order_id);
212 let signed_size_sell = order_sell.signed_size();
213 assert_eq!(signed_size_sell, -10.0);
214 }
215
216 #[rstest]
217 fn test_debug() {
218 let price = Price::from("100.00");
219 let size = Quantity::from(10);
220 let side = OrderSide::Buy;
221 let order_id = 123_456;
222 let order = BookOrder::new(side, price, size, order_id);
223 let result = format!("{order:?}");
224 let expected = "BookOrder(side=BUY, price=100.00, size=10, order_id=123456)";
225 assert_eq!(result, expected);
226 }
227
228 #[rstest]
229 fn test_display() {
230 let price = Price::from("100.00");
231 let size = Quantity::from(10);
232 let side = OrderSide::Buy;
233 let order_id = 123_456;
234 let order = BookOrder::new(side, price, size, order_id);
235 let result = format!("{order}");
236 let expected = "BUY,100.00,10,123456";
237 assert_eq!(result, expected);
238 }
239}