1use nautilus_core::UnixNanos;
19use rstest::fixture;
20
21use super::{
22 Bar, BarSpecification, BarType, InstrumentStatus, OrderBookDelta, OrderBookDeltas,
23 OrderBookDepth10, QuoteTick, TradeTick, DEPTH10_LEN,
24};
25use crate::{
26 data::order::BookOrder,
27 enums::{
28 AggregationSource, AggressorSide, BarAggregation, BookAction, MarketStatusAction,
29 OrderSide, PriceType,
30 },
31 identifiers::{InstrumentId, Symbol, TradeId, Venue},
32 types::{Price, Quantity},
33};
34
35impl Default for QuoteTick {
36 fn default() -> Self {
38 Self {
39 instrument_id: InstrumentId::from("AUDUSD.SIM"),
40 bid_price: Price::from("1.00000"),
41 ask_price: Price::from("1.00000"),
42 bid_size: Quantity::from(100_000),
43 ask_size: Quantity::from(100_000),
44 ts_event: UnixNanos::default(),
45 ts_init: UnixNanos::default(),
46 }
47 }
48}
49
50impl Default for TradeTick {
51 fn default() -> Self {
53 TradeTick {
54 instrument_id: InstrumentId::from("AUDUSD.SIM"),
55 price: Price::from("1.00000"),
56 size: Quantity::from(100_000),
57 aggressor_side: AggressorSide::Buyer,
58 trade_id: TradeId::new("123456789"),
59 ts_event: UnixNanos::default(),
60 ts_init: UnixNanos::default(),
61 }
62 }
63}
64
65impl Default for Bar {
66 fn default() -> Self {
68 Self {
69 bar_type: BarType::from("AUDUSD.SIM-1-MINUTE-LAST-INTERNAL"),
70 open: Price::from("1.00010"),
71 high: Price::from("1.00020"),
72 low: Price::from("1.00000"),
73 close: Price::from("1.00010"),
74 volume: Quantity::from(100_000),
75 ts_event: UnixNanos::default(),
76 ts_init: UnixNanos::default(),
77 }
78 }
79}
80
81#[fixture]
82pub fn stub_delta() -> OrderBookDelta {
83 let instrument_id = InstrumentId::from("AAPL.XNAS");
84 let action = BookAction::Add;
85 let price = Price::from("100.00");
86 let size = Quantity::from("10");
87 let side = OrderSide::Buy;
88 let order_id = 123_456;
89 let flags = 0;
90 let sequence = 1;
91 let ts_event = 1;
92 let ts_init = 2;
93
94 let order = BookOrder::new(side, price, size, order_id);
95 OrderBookDelta::new(
96 instrument_id,
97 action,
98 order,
99 flags,
100 sequence,
101 ts_event.into(),
102 ts_init.into(),
103 )
104}
105
106#[fixture]
107pub fn stub_deltas() -> OrderBookDeltas {
108 let instrument_id = InstrumentId::from("AAPL.XNAS");
109 let flags = 32; let sequence = 0;
111 let ts_event = 1;
112 let ts_init = 2;
113
114 let delta0 = OrderBookDelta::clear(instrument_id, sequence, ts_event.into(), ts_init.into());
115 let delta1 = OrderBookDelta::new(
116 instrument_id,
117 BookAction::Add,
118 BookOrder::new(
119 OrderSide::Sell,
120 Price::from("102.00"),
121 Quantity::from("300"),
122 1,
123 ),
124 flags,
125 sequence,
126 ts_event.into(),
127 ts_init.into(),
128 );
129 let delta2 = OrderBookDelta::new(
130 instrument_id,
131 BookAction::Add,
132 BookOrder::new(
133 OrderSide::Sell,
134 Price::from("101.00"),
135 Quantity::from("200"),
136 2,
137 ),
138 flags,
139 sequence,
140 ts_event.into(),
141 ts_init.into(),
142 );
143 let delta3 = OrderBookDelta::new(
144 instrument_id,
145 BookAction::Add,
146 BookOrder::new(
147 OrderSide::Sell,
148 Price::from("100.00"),
149 Quantity::from("100"),
150 3,
151 ),
152 flags,
153 sequence,
154 ts_event.into(),
155 ts_init.into(),
156 );
157 let delta4 = OrderBookDelta::new(
158 instrument_id,
159 BookAction::Add,
160 BookOrder::new(
161 OrderSide::Buy,
162 Price::from("99.00"),
163 Quantity::from("100"),
164 4,
165 ),
166 flags,
167 sequence,
168 ts_event.into(),
169 ts_init.into(),
170 );
171 let delta5 = OrderBookDelta::new(
172 instrument_id,
173 BookAction::Add,
174 BookOrder::new(
175 OrderSide::Buy,
176 Price::from("98.00"),
177 Quantity::from("200"),
178 5,
179 ),
180 flags,
181 sequence,
182 ts_event.into(),
183 ts_init.into(),
184 );
185 let delta6 = OrderBookDelta::new(
186 instrument_id,
187 BookAction::Add,
188 BookOrder::new(
189 OrderSide::Buy,
190 Price::from("97.00"),
191 Quantity::from("300"),
192 6,
193 ),
194 flags,
195 sequence,
196 ts_event.into(),
197 ts_init.into(),
198 );
199
200 let deltas = vec![delta0, delta1, delta2, delta3, delta4, delta5, delta6];
201
202 OrderBookDeltas::new(instrument_id, deltas)
203}
204
205#[fixture]
206pub fn stub_depth10() -> OrderBookDepth10 {
207 let instrument_id = InstrumentId::from("AAPL.XNAS");
208 let flags = 0;
209 let sequence = 0;
210 let ts_event = 1;
211 let ts_init = 2;
212
213 let mut bids: [BookOrder; DEPTH10_LEN] = [BookOrder::default(); DEPTH10_LEN];
214 let mut asks: [BookOrder; DEPTH10_LEN] = [BookOrder::default(); DEPTH10_LEN];
215
216 let mut price = 99.00;
218 let mut quantity = 100.0;
219 let mut order_id = 1;
220
221 #[allow(clippy::needless_range_loop)]
222 for i in 0..DEPTH10_LEN {
223 let order = BookOrder::new(
224 OrderSide::Buy,
225 Price::new(price, 2),
226 Quantity::new(quantity, 0),
227 order_id,
228 );
229
230 bids[i] = order;
231
232 price -= 1.0;
233 quantity += 100.0;
234 order_id += 1;
235 }
236
237 let mut price = 100.00;
239 let mut quantity = 100.0;
240 let mut order_id = 11;
241
242 #[allow(clippy::needless_range_loop)]
243 for i in 0..DEPTH10_LEN {
244 let order = BookOrder::new(
245 OrderSide::Sell,
246 Price::new(price, 2),
247 Quantity::new(quantity, 0),
248 order_id,
249 );
250
251 asks[i] = order;
252
253 price += 1.0;
254 quantity += 100.0;
255 order_id += 1;
256 }
257
258 let bid_counts: [u32; DEPTH10_LEN] = [1; DEPTH10_LEN];
259 let ask_counts: [u32; DEPTH10_LEN] = [1; DEPTH10_LEN];
260
261 OrderBookDepth10::new(
262 instrument_id,
263 bids,
264 asks,
265 bid_counts,
266 ask_counts,
267 flags,
268 sequence,
269 ts_event.into(),
270 ts_init.into(),
271 )
272}
273
274#[fixture]
275pub fn stub_book_order() -> BookOrder {
276 let price = Price::from("100.00");
277 let size = Quantity::from("10");
278 let side = OrderSide::Buy;
279 let order_id = 123_456;
280
281 BookOrder::new(side, price, size, order_id)
282}
283
284#[fixture]
285pub fn quote_ethusdt_binance() -> QuoteTick {
286 QuoteTick {
287 instrument_id: InstrumentId::from("ETHUSDT-PERP.BINANCE"),
288 bid_price: Price::from("10000.0000"),
289 ask_price: Price::from("10001.0000"),
290 bid_size: Quantity::from("1.00000000"),
291 ask_size: Quantity::from("1.00000000"),
292 ts_event: UnixNanos::default(),
293 ts_init: UnixNanos::from(1),
294 }
295}
296
297#[fixture]
298pub fn quote_audusd() -> QuoteTick {
299 QuoteTick {
300 instrument_id: InstrumentId::from("AUD/USD.SIM"),
301 bid_price: Price::from("100.0000"),
302 ask_price: Price::from("101.0000"),
303 bid_size: Quantity::from("1.00000000"),
304 ask_size: Quantity::from("1.00000000"),
305 ts_event: UnixNanos::default(),
306 ts_init: UnixNanos::from(1),
307 }
308}
309
310#[fixture]
311pub fn stub_trade_ethusdt_buyer() -> TradeTick {
312 TradeTick {
313 instrument_id: InstrumentId::from("ETHUSDT-PERP.BINANCE"),
314 price: Price::from("10000.0000"),
315 size: Quantity::from("1.00000000"),
316 aggressor_side: AggressorSide::Buyer,
317 trade_id: TradeId::new("123456789"),
318 ts_event: UnixNanos::default(),
319 ts_init: UnixNanos::from(1),
320 }
321}
322
323#[fixture]
324pub fn stub_bar() -> Bar {
325 let instrument_id = InstrumentId {
326 symbol: Symbol::new("AUD/USD"),
327 venue: Venue::new("SIM"),
328 };
329 let bar_spec = BarSpecification::new(1, BarAggregation::Minute, PriceType::Bid);
330 let bar_type = BarType::Standard {
331 instrument_id,
332 spec: bar_spec,
333 aggregation_source: AggregationSource::External,
334 };
335 Bar {
336 bar_type,
337 open: Price::from("1.00002"),
338 high: Price::from("1.00004"),
339 low: Price::from("1.00001"),
340 close: Price::from("1.00003"),
341 volume: Quantity::from("100000"),
342 ts_event: UnixNanos::default(),
343 ts_init: UnixNanos::from(1),
344 }
345}
346
347#[fixture]
348pub fn stub_instrument_status() -> InstrumentStatus {
349 let instrument_id = InstrumentId::from("MSFT.XNAS");
350 InstrumentStatus::new(
351 instrument_id,
352 MarketStatusAction::Trading,
353 UnixNanos::from(1),
354 UnixNanos::from(2),
355 None,
356 None,
357 None,
358 None,
359 None,
360 )
361}
362
363pub struct OrderBookDeltaTestBuilder {
364 instrument_id: InstrumentId,
365 action: Option<BookAction>,
366 book_order: Option<BookOrder>,
367 flags: Option<u8>,
368 sequence: Option<u64>,
369}
370
371impl OrderBookDeltaTestBuilder {
372 pub fn new(instrument_id: InstrumentId) -> Self {
373 Self {
374 instrument_id,
375 action: None,
376 book_order: None,
377 flags: None,
378 sequence: None,
379 }
380 }
381
382 pub fn book_action(&mut self, action: BookAction) -> &mut Self {
383 self.action = Some(action);
384 self
385 }
386
387 fn get_book_action(&self) -> BookAction {
388 self.action.unwrap_or(BookAction::Add)
389 }
390
391 pub fn book_order(&mut self, book_order: BookOrder) -> &mut Self {
392 self.book_order = Some(book_order);
393 self
394 }
395
396 fn get_book_order(&self) -> BookOrder {
397 self.book_order.unwrap_or(BookOrder::new(
398 OrderSide::Sell,
399 Price::from("1500.00"),
400 Quantity::from("1"),
401 1,
402 ))
403 }
404
405 pub fn flags(&mut self, flags: u8) -> &mut Self {
406 self.flags = Some(flags);
407 self
408 }
409
410 fn get_flags(&self) -> u8 {
411 self.flags.unwrap_or(0)
412 }
413
414 pub fn sequence(&mut self, sequence: u64) -> &mut Self {
415 self.sequence = Some(sequence);
416 self
417 }
418
419 fn get_sequence(&self) -> u64 {
420 self.sequence.unwrap_or(1)
421 }
422
423 pub fn build(&self) -> OrderBookDelta {
424 OrderBookDelta::new(
425 self.instrument_id,
426 self.get_book_action(),
427 self.get_book_order(),
428 self.get_flags(),
429 self.get_sequence(),
430 UnixNanos::from(1),
431 UnixNanos::from(2),
432 )
433 }
434}