nautilus_testkit/
common.rs1use std::{
17 fs::File,
18 path::{Path, PathBuf},
19 sync::OnceLock,
20};
21
22use nautilus_core::paths::get_test_data_path;
23use nautilus_model::{
24 data::OrderBookDelta,
25 instruments::{InstrumentAny, stubs::equity_aapl_itch},
26 types::fixed::PRECISION_BYTES,
27};
28use nautilus_serialization::arrow::DecodeFromRecordBatch;
29use parquet::arrow::arrow_reader::ParquetRecordBatchReaderBuilder;
30
31use crate::files::ensure_file_exists_or_download_http;
32
33#[must_use]
39pub fn get_test_data_file_path(path: &str) -> String {
40 get_test_data_path()
41 .join(path)
42 .to_str()
43 .unwrap()
44 .to_string()
45}
46
47#[must_use]
53pub fn get_nautilus_test_data_file_path(filename: &str) -> String {
54 let precision_directory = format!("{}-bit", PRECISION_BYTES * 8);
55 let path = get_test_data_path()
56 .join("nautilus")
57 .join(precision_directory);
58
59 path.join(filename).to_str().unwrap().to_string()
60}
61
62#[must_use]
64pub fn get_test_data_large_checksums_filepath() -> PathBuf {
65 get_test_data_path().join("large").join("checksums.json")
66}
67
68#[must_use]
74pub fn ensure_test_data_exists(filename: &str, url: &str) -> PathBuf {
75 let filepath = get_test_data_path().join("large").join(filename);
76 let checksums_filepath = get_test_data_large_checksums_filepath();
77 ensure_file_exists_or_download_http(&filepath, url, Some(&checksums_filepath), None).unwrap();
78 filepath
79}
80
81#[must_use]
87pub fn ensure_itch_aapl_deltas_parquet() -> PathBuf {
88 ensure_test_data_exists(
89 "itch_AAPL.XNAS_2019-01-30_deltas.parquet",
90 "https://test-data.nautechsystems.io/large/itch_AAPL.XNAS_2019-01-30_deltas.parquet",
91 )
92}
93
94#[must_use]
100pub fn ensure_tardis_deribit_deltas_parquet() -> PathBuf {
101 ensure_test_data_exists(
102 "tardis_BTC-PERPETUAL.DERIBIT_2020-04-01_deltas.parquet",
103 "https://test-data.nautechsystems.io/large/tardis_BTC-PERPETUAL.DERIBIT_2020-04-01_deltas.parquet",
104 )
105}
106
107#[must_use]
114pub fn ensure_histdata_eurusd_quotes_parquet() -> PathBuf {
115 ensure_test_data_exists(
116 "histdata_EURUSD.SIM_2020-01_quotes.parquet",
117 "https://test-data.nautechsystems.io/large/histdata_EURUSD.SIM_2020-01_quotes.parquet",
118 )
119}
120
121#[must_use]
128pub fn ensure_histdata_eurusd_instrument_parquet() -> PathBuf {
129 ensure_test_data_exists(
130 "histdata_EURUSD.SIM_2020-01_instrument.parquet",
131 "https://test-data.nautechsystems.io/large/histdata_EURUSD.SIM_2020-01_instrument.parquet",
132 )
133}
134
135#[must_use]
137pub fn get_tardis_deribit_book_l2_path() -> PathBuf {
138 get_test_data_path()
139 .join("tardis")
140 .join("deribit_incremental_book_L2_BTC-PERPETUAL.csv")
141}
142
143#[must_use]
145pub fn get_tardis_binance_snapshot5_path() -> PathBuf {
146 get_test_data_path()
147 .join("tardis")
148 .join("binance-futures_book_snapshot_5_BTCUSDT.csv")
149}
150
151#[must_use]
153pub fn get_tardis_binance_snapshot25_path() -> PathBuf {
154 get_test_data_path()
155 .join("tardis")
156 .join("binance-futures_book_snapshot_25_BTCUSDT.csv")
157}
158
159#[must_use]
161pub fn get_tardis_huobi_quotes_path() -> PathBuf {
162 get_test_data_path()
163 .join("tardis")
164 .join("huobi-dm-swap_quotes_BTC-USD.csv")
165}
166
167#[must_use]
169pub fn get_tardis_bitmex_trades_path() -> PathBuf {
170 get_test_data_path()
171 .join("tardis")
172 .join("bitmex_trades_XBTUSD.csv")
173}
174
175#[must_use]
178pub fn itch_aapl_equity() -> InstrumentAny {
179 InstrumentAny::Equity(equity_aapl_itch())
180}
181
182#[must_use]
186pub fn load_itch_aapl_deltas(limit: Option<usize>) -> Vec<OrderBookDelta> {
187 static PATH: OnceLock<PathBuf> = OnceLock::new();
188 let filepath = PATH.get_or_init(ensure_itch_aapl_deltas_parquet);
189 load_deltas_from_parquet(filepath, limit)
190}
191
192#[must_use]
196pub fn load_tardis_deribit_deltas(limit: Option<usize>) -> Vec<OrderBookDelta> {
197 static PATH: OnceLock<PathBuf> = OnceLock::new();
198 let filepath = PATH.get_or_init(ensure_tardis_deribit_deltas_parquet);
199 load_deltas_from_parquet(filepath, limit)
200}
201
202fn load_deltas_from_parquet(filepath: &Path, limit: Option<usize>) -> Vec<OrderBookDelta> {
203 let file = File::open(filepath).unwrap();
204 let mut builder = ParquetRecordBatchReaderBuilder::try_new(file).unwrap();
205 let metadata = builder.schema().metadata().clone();
206
207 if let Some(limit) = limit {
208 builder = builder.with_limit(limit);
209 }
210 let reader = builder.build().unwrap();
211
212 let mut deltas = Vec::new();
213
214 for batch_result in reader {
215 let batch = batch_result.unwrap();
216 let batch_deltas = OrderBookDelta::decode_batch(&metadata, batch).unwrap();
217 deltas.extend(batch_deltas);
218 }
219 deltas
220}