Hard refactor — no shims, no compat layers. Candle removed from Cargo.toml and all source files in 6 crates: - ml-core: MlDevice enum, checkpoint.rs (safetensors direct), cudarc imports fixed from candle re-export to direct, AdamWConfig lr_decay, cuda_compat gutted. Net -7,341 lines. - ml-ppo: All 16 files rewritten. LSTM→CudaLSTM, VarMap→GpuVarStore, PPOAgent 2306→700 lines, checkpoint→binary format. - ml-ensemble: GPU-resident sigmoid via custom CUDA kernel. - ml-explainability: Integrated gradients via GPU finite-difference kernels. - ml-labeling: Device→MlDevice. - ml-hyperopt: Cargo.toml only. Remaining: ml-dqn (24 files), ml-supervised (4 files), ml crate (104 files). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
160 lines
5.2 KiB
Rust
160 lines
5.2 KiB
Rust
//! # ML Labeling Module for Foxhunt HFT System
|
|
//!
|
|
//! This module provides high-performance machine learning labeling algorithms
|
|
//! optimized for ultra-low latency financial applications. All implementations
|
|
//! use `FixedPoint` arithmetic for financial precision and target sub-microsecond
|
|
//! performance.
|
|
//!
|
|
//! ## Core Features
|
|
//!
|
|
//! - **Triple Barrier Engine**: <80us latency for event labeling
|
|
//! - **Meta-Labeling**: Separates direction prediction from confidence/bet sizing
|
|
//! - **Fractional Differentiation**: Streaming transforms with <1us latency
|
|
//! - **Sample Weighting**: Volatility/return/time-based weighting algorithms
|
|
//! - **GPU Acceleration**: Batch processing with CUDA via cudarc integration
|
|
//! - **Concurrent Processing**: Lock-free barrier tracking with `DashMap`
|
|
//!
|
|
//! ## Performance Targets
|
|
//!
|
|
//! - Triple barrier labeling: <80us per event
|
|
//! - Meta-labeling: <50us per prediction
|
|
//! - Fractional differentiation: <1us per transform
|
|
//! - Sample weighting: <10us per sample
|
|
//! - Batch processing: 10K+ labels/second
|
|
//!
|
|
//! ## Architecture
|
|
//!
|
|
//! All components use integer arithmetic (cents, nanoseconds, basis points)
|
|
//! for financial precision, matching the Python reference implementation
|
|
//! patterns from the `HFTTrendfollowing` project.
|
|
|
|
#![deny(clippy::unwrap_used, clippy::expect_used)]
|
|
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
|
|
#![allow(clippy::module_name_repetitions)]
|
|
#![allow(clippy::integer_division)]
|
|
// Overrides of workspace deny → allow (labeling code uses these patterns)
|
|
#![allow(clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated)]
|
|
#![allow(clippy::non_ascii_literal, clippy::str_to_string)]
|
|
#![allow(clippy::partial_pub_fields, clippy::multiple_inherent_impl)]
|
|
#![allow(clippy::same_name_method, clippy::indexing_slicing)]
|
|
|
|
// Re-export MLError so internal modules can use `crate::MLError`
|
|
pub use ml_core::MLError;
|
|
|
|
pub mod benchmarks;
|
|
pub mod concurrent_tracking;
|
|
pub mod fractional_diff;
|
|
pub mod gpu_acceleration;
|
|
|
|
// Meta-labeling engine (legacy interface)
|
|
pub mod meta_labeling_engine;
|
|
|
|
// New meta-labeling module with secondary model
|
|
pub mod meta_labeling;
|
|
|
|
pub mod sample_weights;
|
|
pub mod triple_barrier;
|
|
pub mod types;
|
|
|
|
// DO NOT RE-EXPORT - Use explicit imports at usage sites
|
|
|
|
// DO NOT RE-EXPORT - Benchmarks should be imported explicitly
|
|
|
|
/// Labeling module constants matching Python reference precision
|
|
pub mod constants {
|
|
/// Cents per dollar for `price` precision
|
|
pub const CENTS_PER_DOLLAR: i64 = 100;
|
|
|
|
/// Basis points per dollar for return precision
|
|
pub const BASIS_POINTS_PER_DOLLAR: i64 = 10_000;
|
|
|
|
/// Nanoseconds per second for time precision
|
|
pub const NANOSECONDS_PER_SECOND: i64 = 1_000_000_000;
|
|
|
|
/// Microseconds per second
|
|
pub const MICROSECONDS_PER_SECOND: i64 = 1_000_000;
|
|
|
|
/// Maximum latency target for triple barrier labeling (80us)
|
|
pub const MAX_TRIPLE_BARRIER_LATENCY_US: u64 = 80;
|
|
|
|
/// Maximum latency target for meta-labeling (50us)
|
|
pub const MAX_META_LABELING_LATENCY_US: u64 = 50;
|
|
|
|
/// Maximum latency target for fractional differentiation (1us)
|
|
pub const MAX_FRACTIONAL_DIFF_LATENCY_US: u64 = 1;
|
|
|
|
/// Minimum throughput for batch processing (labels/second)
|
|
pub const MIN_BATCH_THROUGHPUT_LPS: u64 = 10_000;
|
|
}
|
|
|
|
/// Utility functions for labeling operations
|
|
pub mod utils {
|
|
use super::constants::{CENTS_PER_DOLLAR, BASIS_POINTS_PER_DOLLAR, NANOSECONDS_PER_SECOND};
|
|
|
|
/// Convert price to cents
|
|
pub fn price_to_cents(price: f64) -> u64 {
|
|
(price * CENTS_PER_DOLLAR as f64) as u64
|
|
}
|
|
|
|
/// Convert cents to price
|
|
pub fn cents_to_price(cents: u64) -> f64 {
|
|
cents as f64 / CENTS_PER_DOLLAR as f64
|
|
}
|
|
|
|
/// Convert ratio to basis points
|
|
pub fn ratio_to_bps(ratio: f64) -> i32 {
|
|
(ratio * BASIS_POINTS_PER_DOLLAR as f64) as i32
|
|
}
|
|
|
|
/// Convert basis points to ratio
|
|
pub fn bps_to_ratio(bps: i32) -> f64 {
|
|
bps as f64 / BASIS_POINTS_PER_DOLLAR as f64
|
|
}
|
|
|
|
/// Convert timestamp to nanoseconds
|
|
pub fn timestamp_to_ns(timestamp: f64) -> u64 {
|
|
(timestamp * NANOSECONDS_PER_SECOND as f64) as u64
|
|
}
|
|
|
|
/// Convert nanoseconds to timestamp
|
|
pub fn ns_to_timestamp(ns: u64) -> f64 {
|
|
ns as f64 / NANOSECONDS_PER_SECOND as f64
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[allow(clippy::excessive_precision)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_price_conversions() {
|
|
let price = 123.45;
|
|
let cents = utils::price_to_cents(price);
|
|
let converted_back = utils::cents_to_price(cents);
|
|
|
|
assert_eq!(cents, 12345);
|
|
assert!((converted_back - price).abs() < 1e-10);
|
|
}
|
|
|
|
#[test]
|
|
fn test_ratio_conversions() {
|
|
let ratio = 0.0250; // 2.5%
|
|
let bps = utils::ratio_to_bps(ratio);
|
|
let converted_back = utils::bps_to_ratio(bps);
|
|
|
|
assert_eq!(bps, 250);
|
|
assert!((converted_back - ratio).abs() < 1e-10);
|
|
}
|
|
|
|
#[test]
|
|
fn test_timestamp_conversions() {
|
|
let timestamp = 1692000000.123456789; // Example timestamp with nanosecond precision
|
|
let ns = utils::timestamp_to_ns(timestamp);
|
|
let converted_back = utils::ns_to_timestamp(ns);
|
|
|
|
// Should preserve millisecond precision
|
|
assert!((converted_back - timestamp).abs() < 1e-6);
|
|
}
|
|
}
|