Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions crates/openquant/src/microstructural_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,9 +649,13 @@ impl MicrostructuralFeaturesGenerator {
// Try multiple datetime formats (with/without fractional seconds)
let _ = parse_datetime(&rec[0]).map_err(|_| "column 0 not datetime".to_string())?;
}
// Take the first threshold *out of* the iterator. Peeking at it instead leaves
// it to be served again after the first bar closes, which emits a one-tick bar.
let mut tick_num_iter = tick_num_series.to_vec().into_iter();
let current_bar_tick = tick_num_iter.next().unwrap_or(0);
Ok(Self {
tick_num_iter: tick_num_series.to_vec().into_iter(),
current_bar_tick: tick_num_series.get(0).copied().unwrap_or(0),
tick_num_iter,
current_bar_tick,
price_diff: Vec::new(),
trade_size: Vec::new(),
tick_rule: Vec::new(),
Expand Down
27 changes: 27 additions & 0 deletions crates/openquant/tests/microstructural_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,30 @@ fn test_first_generation_features() {
assert!((mean(&bekker) - 0.001456).abs() < 1e-4);
assert!((bekker[25] - 0.000517).abs() < 1e-4);
}

#[test]
fn test_feature_generator_emits_one_row_per_tick_threshold() {
// 30 ticks; trade size is 1 for ticks 1-10, 2 for 11-20, 3 for 21-30. With bars
// closing at ticks 10, 20 and 30 the average tick size per bar is exactly 1, 2, 3.
let path = std::env::temp_dir()
.join(format!("openquant_ticks_{}_one_row_per_threshold.csv", std::process::id()));
let mut csv = String::from("Date and Time,Price,Volume\n");
for tick in 0..30 {
let price = 100.0 + (tick % 5) as f64 * 0.25;
csv.push_str(&format!("2011/07/31 23:31:{:02}.000,{price},{}\n", 10 + tick, tick / 10 + 1));
}
std::fs::write(&path, csv).unwrap();

let mut gen = MicrostructuralFeaturesGenerator::new_from_csv(
path.to_str().unwrap(),
&[10, 20, 30],
None,
None,
)
.unwrap();
let feats = gen.get_features_from_csv(path.to_str().unwrap()).unwrap();
std::fs::remove_file(&path).ok();

let avg_tick_sizes: Vec<f64> = feats.iter().map(|row| row[1]).collect();
assert_eq!(avg_tick_sizes, vec![1.0, 2.0, 3.0]);
}
Loading