WAVE 21: Core type definitions and trainer configs updated Files Modified (13 files): - ml/src/features/extraction.rs: FeatureVector = [f64; 54] - common/src/features/types.rs: Added FeatureVector54 - ml/src/trainers/dqn.rs: state_dim 225→54 - ml/src/trainers/ppo.rs: state_dim 225→54 - ml/src/dqn/dqn.rs, config.rs, replay_buffer.rs: Updated configs - ml/src/hyperopt/adapters/: All adapters updated to 54-dim - ml/src/features/unified.rs: Struct fields updated - ml/src/trainers/tft_parquet.rs: Return types updated Agents Deployed: 5 parallel agents Test Results: cargo check --package ml --lib PASSING Next: Wave 2 (examples), Wave 3 (tests), Wave 4 (OFI integration) Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
158 lines
4.9 KiB
Rust
158 lines
4.9 KiB
Rust
//! OFI Features Demo
|
|
//!
|
|
//! Demonstrates how to use the OFI (Order Flow Imbalance) calculator
|
|
//! with MBP-10 order book snapshots.
|
|
|
|
use data::providers::databento::mbp10::{BidAskPair, Mbp10Snapshot};
|
|
use ml::features::ofi_calculator::{OFICalculator, OFIFeatures};
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
println!("=== OFI Features Demo ===\n");
|
|
|
|
// Create OFI calculator
|
|
let mut calculator = OFICalculator::new();
|
|
|
|
// Create sample MBP-10 snapshots (simulating real market data)
|
|
let snapshots = create_sample_snapshots();
|
|
|
|
println!("Processing {} snapshots...\n", snapshots.len());
|
|
|
|
for (i, snapshot) in snapshots.iter().enumerate() {
|
|
// Calculate OFI features
|
|
let features = calculator.calculate(snapshot)?;
|
|
|
|
// Display results
|
|
println!("Snapshot #{}", i + 1);
|
|
println!(" Mid Price: ${:.2}", snapshot.mid_price());
|
|
println!(" Spread: ${:.4}", snapshot.spread());
|
|
println!("\n OFI Features:");
|
|
println!(" OFI Level 1 (normalized): {:>8.3}", features.ofi_level1);
|
|
println!(" OFI Level 5 (weighted): {:>8.3}", features.ofi_level5);
|
|
println!(" Depth Imbalance: {:>8.3}", features.depth_imbalance);
|
|
println!(" VPIN: {:>8.3}", features.vpin);
|
|
println!(" Kyle's Lambda: {:>8.6}", features.kyle_lambda);
|
|
println!(" Bid Slope: {:>8.1}", features.bid_slope);
|
|
println!(" Ask Slope: {:>8.1}", features.ask_slope);
|
|
println!(" Trade Imbalance: {:>8.3}", features.trade_imbalance);
|
|
|
|
// Validate features
|
|
if !features.is_valid() {
|
|
println!(" ⚠️ WARNING: Invalid features detected!");
|
|
} else {
|
|
println!(" ✓ All features valid (finite)");
|
|
}
|
|
|
|
println!();
|
|
}
|
|
|
|
// Convert to array format (for ML model input)
|
|
let final_snapshot = snapshots.last().unwrap();
|
|
let final_features = calculator.calculate(final_snapshot)?;
|
|
let feature_array = final_features.to_array();
|
|
|
|
println!("Feature Array (for ML models):");
|
|
println!("{:?}", feature_array);
|
|
println!("\nArray length: {} (indices 226-233)", feature_array.len());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Create sample MBP-10 snapshots for demonstration
|
|
fn create_sample_snapshots() -> Vec<Mbp10Snapshot> {
|
|
vec![
|
|
// Snapshot 1: Balanced book
|
|
create_snapshot(
|
|
1640995200000000000,
|
|
5000_000_000_000_000, // $5000.00 bid
|
|
5000_100_000_000_000, // $5000.01 ask
|
|
100,
|
|
100,
|
|
),
|
|
// Snapshot 2: Bid rises (bullish signal)
|
|
create_snapshot(
|
|
1640995201000000000,
|
|
5000_050_000_000_000, // $5000.05 bid (rises)
|
|
5000_100_000_000_000, // $5000.01 ask
|
|
120,
|
|
90,
|
|
),
|
|
// Snapshot 3: Ask falls (bullish signal)
|
|
create_snapshot(
|
|
1640995202000000000,
|
|
5000_050_000_000_000,
|
|
5000_075_000_000_000, // $5000.075 ask (falls)
|
|
130,
|
|
80,
|
|
),
|
|
// Snapshot 4: Bid-heavy book
|
|
create_snapshot(
|
|
1640995203000000000,
|
|
5000_075_000_000_000, // Bid continues rising
|
|
5000_100_000_000_000,
|
|
200, // Large bid size
|
|
100,
|
|
),
|
|
// Snapshot 5: Reversal - Ask rises (bearish signal)
|
|
create_snapshot(
|
|
1640995204000000000,
|
|
5000_050_000_000_000, // Bid falls back
|
|
5000_150_000_000_000, // Ask jumps up
|
|
100,
|
|
150,
|
|
),
|
|
]
|
|
}
|
|
|
|
fn create_snapshot(
|
|
timestamp: u64,
|
|
bid_px: i64,
|
|
ask_px: i64,
|
|
bid_sz: u32,
|
|
ask_sz: u32,
|
|
) -> Mbp10Snapshot {
|
|
let levels = vec![
|
|
BidAskPair {
|
|
bid_px,
|
|
bid_sz,
|
|
bid_ct: 5,
|
|
ask_px,
|
|
ask_sz,
|
|
ask_ct: 6,
|
|
},
|
|
BidAskPair {
|
|
bid_px: bid_px - 10_000_000_000,
|
|
bid_sz: bid_sz * 2,
|
|
bid_ct: 8,
|
|
ask_px: ask_px + 10_000_000_000,
|
|
ask_sz: ask_sz * 2,
|
|
ask_ct: 7,
|
|
},
|
|
BidAskPair {
|
|
bid_px: bid_px - 20_000_000_000,
|
|
bid_sz: bid_sz * 3,
|
|
bid_ct: 10,
|
|
ask_px: ask_px + 20_000_000_000,
|
|
ask_sz: ask_sz * 3,
|
|
ask_ct: 9,
|
|
},
|
|
BidAskPair {
|
|
bid_px: bid_px - 30_000_000_000,
|
|
bid_sz: bid_sz * 4,
|
|
bid_ct: 12,
|
|
ask_px: ask_px + 30_000_000_000,
|
|
ask_sz: ask_sz * 4,
|
|
ask_ct: 11,
|
|
},
|
|
BidAskPair {
|
|
bid_px: bid_px - 40_000_000_000,
|
|
bid_sz: bid_sz * 5,
|
|
bid_ct: 15,
|
|
ask_px: ask_px + 40_000_000_000,
|
|
ask_sz: ask_sz * 5,
|
|
ask_ct: 13,
|
|
},
|
|
];
|
|
|
|
Mbp10Snapshot::new("ES.FUT".to_string(), timestamp, levels, 0, 100)
|
|
}
|