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::data::OrderBookDelta;
24use nautilus_serialization::arrow::DecodeFromRecordBatch;
25use parquet::arrow::arrow_reader::ParquetRecordBatchReaderBuilder;
26
27use crate::files::ensure_file_exists_or_download_http;
28
29#[must_use]
35pub fn get_test_data_file_path(path: &str) -> String {
36 get_test_data_path()
37 .join(path)
38 .to_str()
39 .unwrap()
40 .to_string()
41}
42
43#[must_use]
49#[allow(unused_mut)]
50pub fn get_nautilus_test_data_file_path(filename: &str) -> String {
51 let mut path = get_test_data_path().join("nautilus");
52
53 #[cfg(feature = "high-precision")]
54 {
55 path = path.join("128-bit");
56 }
57 #[cfg(not(feature = "high-precision"))]
58 {
59 path = path.join("64-bit");
60 }
61
62 path.join(filename).to_str().unwrap().to_string()
63}
64
65#[must_use]
67pub fn get_test_data_large_checksums_filepath() -> PathBuf {
68 get_test_data_path().join("large").join("checksums.json")
69}
70
71#[must_use]
77pub fn ensure_test_data_exists(filename: &str, url: &str) -> PathBuf {
78 let filepath = get_test_data_path().join("large").join(filename);
79 let checksums_filepath = get_test_data_large_checksums_filepath();
80 ensure_file_exists_or_download_http(&filepath, url, Some(&checksums_filepath), None).unwrap();
81 filepath
82}
83
84#[must_use]
90pub fn ensure_itch_aapl_deltas_parquet() -> PathBuf {
91 ensure_test_data_exists(
92 "itch_AAPL.XNAS_2019-01-30_deltas.parquet",
93 "https://test-data.nautechsystems.io/large/itch_AAPL.XNAS_2019-01-30_deltas.parquet",
94 )
95}
96
97#[must_use]
103pub fn ensure_tardis_deribit_deltas_parquet() -> PathBuf {
104 ensure_test_data_exists(
105 "tardis_BTC-PERPETUAL.DERIBIT_2020-04-01_deltas.parquet",
106 "https://test-data.nautechsystems.io/large/tardis_BTC-PERPETUAL.DERIBIT_2020-04-01_deltas.parquet",
107 )
108}
109
110#[must_use]
112pub fn get_tardis_deribit_book_l2_path() -> PathBuf {
113 get_test_data_path()
114 .join("tardis")
115 .join("deribit_incremental_book_L2_BTC-PERPETUAL.csv")
116}
117
118#[must_use]
120pub fn get_tardis_binance_snapshot5_path() -> PathBuf {
121 get_test_data_path()
122 .join("tardis")
123 .join("binance-futures_book_snapshot_5_BTCUSDT.csv")
124}
125
126#[must_use]
128pub fn get_tardis_binance_snapshot25_path() -> PathBuf {
129 get_test_data_path()
130 .join("tardis")
131 .join("binance-futures_book_snapshot_25_BTCUSDT.csv")
132}
133
134#[must_use]
136pub fn get_tardis_huobi_quotes_path() -> PathBuf {
137 get_test_data_path()
138 .join("tardis")
139 .join("huobi-dm-swap_quotes_BTC-USD.csv")
140}
141
142#[must_use]
144pub fn get_tardis_bitmex_trades_path() -> PathBuf {
145 get_test_data_path()
146 .join("tardis")
147 .join("bitmex_trades_XBTUSD.csv")
148}
149
150#[must_use]
154pub fn load_itch_aapl_deltas(limit: Option<usize>) -> Vec<OrderBookDelta> {
155 static PATH: OnceLock<PathBuf> = OnceLock::new();
156 let filepath = PATH.get_or_init(ensure_itch_aapl_deltas_parquet);
157 load_deltas_from_parquet(filepath, limit)
158}
159
160#[must_use]
164pub fn load_tardis_deribit_deltas(limit: Option<usize>) -> Vec<OrderBookDelta> {
165 static PATH: OnceLock<PathBuf> = OnceLock::new();
166 let filepath = PATH.get_or_init(ensure_tardis_deribit_deltas_parquet);
167 load_deltas_from_parquet(filepath, limit)
168}
169
170fn load_deltas_from_parquet(filepath: &Path, limit: Option<usize>) -> Vec<OrderBookDelta> {
171 let file = File::open(filepath).unwrap();
172 let mut builder = ParquetRecordBatchReaderBuilder::try_new(file).unwrap();
173 let metadata = builder.schema().metadata().clone();
174 if let Some(limit) = limit {
175 builder = builder.with_limit(limit);
176 }
177 let reader = builder.build().unwrap();
178
179 let mut deltas = Vec::new();
180 for batch_result in reader {
181 let batch = batch_result.unwrap();
182 let batch_deltas = OrderBookDelta::decode_batch(&metadata, batch).unwrap();
183 deltas.extend(batch_deltas);
184 }
185 deltas
186}