rusty_model/memory/
order_trade_pools.rs1use crate::{
7 data::market_trade::MarketTrade,
8 enums::{OrderSide, OrderType},
9 instruments::InstrumentId,
10 trading_order::Order,
11 types::ClientId,
12 venues::Venue,
13};
14use rust_decimal::Decimal;
15use rusty_common::memory::object_pool::{
16 LocalObjectPool, PooledObject, ThreadSafeObjectPool, ThreadSafePooledObject,
17};
18use smartstring::alias::String;
19
20thread_local! {
22 static ORDER_POOL: LocalObjectPool<Order, 256> = LocalObjectPool::new(
24 || Order::new(
25 Venue::Test,
26 String::new(),
27 OrderSide::Buy,
28 OrderType::Limit,
29 Decimal::ZERO,
30 Some(Decimal::ZERO),
31 ClientId::from("default"),
32 ),
33 );
34
35 static TRADE_POOL: LocalObjectPool<MarketTrade, 1024> = LocalObjectPool::new(
37 || MarketTrade {
38 timestamp: quanta::Instant::now(),
39 exchange_time_ns: 0,
40 price: Decimal::ZERO,
41 quantity: Decimal::ZERO,
42 direction: OrderSide::Buy,
43 instrument_id: InstrumentId::new(String::new(), Venue::Test),
44 },
45 );
46}
47
48static GLOBAL_ORDER_POOL: std::sync::LazyLock<ThreadSafeObjectPool<Order>> =
50 std::sync::LazyLock::new(|| {
51 ThreadSafeObjectPool::new(1024, || {
52 Order::new(
53 Venue::Test,
54 String::new(),
55 OrderSide::Buy,
56 OrderType::Limit,
57 Decimal::ZERO,
58 Some(Decimal::ZERO),
59 ClientId::from("default"),
60 )
61 })
62 });
63
64static GLOBAL_TRADE_POOL: std::sync::LazyLock<ThreadSafeObjectPool<MarketTrade>> =
65 std::sync::LazyLock::new(|| {
66 ThreadSafeObjectPool::new(4096, || MarketTrade {
67 timestamp: quanta::Instant::now(),
68 exchange_time_ns: 0,
69 price: Decimal::ZERO,
70 quantity: Decimal::ZERO,
71 direction: OrderSide::Buy,
72 instrument_id: InstrumentId::new(String::new(), Venue::Test),
73 })
74 });
75
76#[inline]
81#[must_use]
82pub fn get_pooled_order() -> PooledObject<Order, 256> {
83 ORDER_POOL.with(|pool| pool.get())
84}
85
86#[inline]
88#[must_use]
89pub fn get_pooled_trade() -> PooledObject<MarketTrade, 1024> {
90 TRADE_POOL.with(|pool| pool.get())
91}
92
93#[inline]
97pub fn get_pooled_order_global() -> ThreadSafePooledObject<Order> {
98 GLOBAL_ORDER_POOL.get()
99}
100
101#[inline]
103pub fn get_pooled_trade_global() -> ThreadSafePooledObject<MarketTrade> {
104 GLOBAL_TRADE_POOL.get()
105}
106
107pub struct PooledOrderBuilder<'a> {
109 order: PooledObject<Order, 256>,
110 _phantom: std::marker::PhantomData<&'a ()>,
111}
112
113impl PooledOrderBuilder<'_> {
114 #[inline]
116 #[must_use]
117 pub fn new() -> Self {
118 Self {
119 order: get_pooled_order(),
120 _phantom: std::marker::PhantomData,
121 }
122 }
123
124 #[inline]
126 #[must_use]
127 pub fn venue(mut self, venue: Venue) -> Self {
128 self.order.venue = venue;
129 self
130 }
131
132 #[inline]
134 #[must_use]
135 pub fn symbol(mut self, symbol: impl Into<String>) -> Self {
136 self.order.symbol = symbol.into();
137 self
138 }
139
140 #[inline]
142 #[must_use]
143 pub fn order_type(mut self, order_type: OrderType) -> Self {
144 self.order.order_type = order_type;
145 self
146 }
147
148 #[inline]
150 #[must_use]
151 pub fn side(mut self, side: OrderSide) -> Self {
152 self.order.side = side;
153 self
154 }
155
156 #[inline]
158 #[must_use]
159 pub fn quantity(mut self, quantity: Decimal) -> Self {
160 self.order.quantity = quantity;
161 self
162 }
163
164 #[inline]
166 #[must_use]
167 pub fn price(mut self, price: Decimal) -> Self {
168 self.order.price = Some(price);
169 self
170 }
171
172 #[inline]
174 #[must_use]
175 pub fn client_id(mut self, client_id: ClientId) -> Self {
176 self.order.client_id = client_id;
177 self
178 }
179
180 #[inline]
182 #[must_use]
183 pub fn build(self) -> Order {
184 self.order.take()
185 }
186
187 #[inline]
189 #[must_use]
190 pub fn order_ref(&self) -> &Order {
191 &self.order
192 }
193}
194
195impl Default for PooledOrderBuilder<'_> {
196 fn default() -> Self {
197 Self::new()
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_order_pool() {
207 let mut order = get_pooled_order();
209 order.symbol = "BTC-USDT".into();
210 order.quantity = Decimal::from(1);
211 order.price = Some(Decimal::from(50000));
212
213 assert_eq!(order.symbol.as_str(), "BTC-USDT");
214
215 drop(order);
216
217 let order2 = get_pooled_order();
219 assert_eq!(order2.symbol.as_str(), "BTC-USDT"); }
221
222 #[test]
223 fn test_order_builder() {
224 let order = PooledOrderBuilder::new()
225 .venue(Venue::Binance)
226 .symbol("ETH-USDT")
227 .order_type(OrderType::Market)
228 .side(OrderSide::Sell)
229 .quantity(Decimal::from(10))
230 .client_id(ClientId::from("test-123"))
231 .build();
232
233 assert_eq!(order.venue, Venue::Binance);
234 assert_eq!(order.symbol.as_str(), "ETH-USDT");
235 assert_eq!(order.order_type, OrderType::Market);
236 assert_eq!(order.side, OrderSide::Sell);
237 assert_eq!(order.quantity, Decimal::from(10));
238 }
239
240 #[test]
241 fn test_trade_pool() {
242 let mut trade = get_pooled_trade();
243 trade.price = Decimal::from(42000);
244 trade.quantity = Decimal::from(5);
245 trade.direction = OrderSide::Sell;
246
247 assert_eq!(trade.price, Decimal::from(42000));
248
249 drop(trade);
250
251 let trade2 = get_pooled_trade();
253 assert_eq!(trade2.price, Decimal::from(42000));
254 }
255
256 #[test]
257 fn test_global_pools() {
258 use std::thread;
259
260 let handles: Vec<_> = (0..4)
261 .map(|i| {
262 thread::spawn(move || {
263 let mut order = get_pooled_order_global();
264 order.symbol = format!("TEST-{i}").into();
265
266 let mut trade = get_pooled_trade_global();
267 trade.price = Decimal::from(i);
268 })
269 })
270 .collect();
271
272 for h in handles {
273 h.join().unwrap();
274 }
275 }
276}