pub mod cyber_cycle;
pub mod ehlers_autocorrelation;
pub mod griffiths_dominant_cycle;
pub mod hurst;
pub mod instantaneous_trendline;
pub mod regime;
pub mod regime_probs;
pub mod trendflex;
pub use cyber_cycle::{CyberCycleFeatureExtractor, CyberCycleFeatures};
pub use ehlers_autocorrelation::{EhlersAutocorrelationFeatureExtractor, EhlersAutocorrelationFeatures};
pub use griffiths_dominant_cycle::{GriffithsDominantCycleFeatureExtractor, GriffithsDominantCycleFeatures};
pub use hurst::{HurstFeatureExtractor, HurstFeatures};
pub use instantaneous_trendline::{InstantaneousTrendlineFeatureExtractor, InstantaneousTrendlineFeatures};
pub use regime::{regime_to_features, RegimeFeatures};
pub use regime_probs::{regime_to_prob_features, RegimeProbFeatures};
pub use trendflex::{TrendflexFeatureExtractor, TrendflexFeatures};
#[cfg(test)]
mod proptest_parity {
use super::*;
use crate::traits::Next;
use proptest::prelude::*;
proptest! {
#[test]
fn hurst_streaming_is_deterministic(data in prop::collection::vec(-100f64..100.0, 5..100)) {
let mut ext1 = HurstFeatureExtractor::new(20);
let mut ext2 = HurstFeatureExtractor::new(20);
for &val in &data {
let f1 = ext1.next(val);
let f2 = ext2.next(val);
prop_assert_eq!(f1.persistence, f2.persistence);
}
}
#[test]
fn cybercycle_streaming_deterministic_and_momentum_sane(data in prop::collection::vec(-50f64..50.0, 10..80)) {
let mut ext = CyberCycleFeatureExtractor::new(14);
let mut prev_mom = 0.0;
for &val in &data {
let f = ext.next(val);
if !f.cycle_momentum.is_nan() {
prop_assert!(f.cycle_momentum.abs() < 100.0);
}
}
}
#[test]
fn autocorrelation_streaming_deterministic(data in prop::collection::vec(-100f64..100.0, 20..120)) {
let mut ext1 = EhlersAutocorrelationFeatureExtractor::new(30, 10);
let mut ext2 = EhlersAutocorrelationFeatureExtractor::new(30, 10);
for &val in &data {
let f1 = ext1.next(val);
let f2 = ext2.next(val);
prop_assert_eq!(f1.dominant_lag, f2.dominant_lag);
prop_assert_eq!(f1.max_correlation, f2.max_correlation);
}
}
#[test]
fn griffiths_and_regime_prob_streaming_stable(data in prop::collection::vec(-80f64..80.0, 30..150)) {
let mut g1 = GriffithsDominantCycleFeatureExtractor::new(8, 50, 40);
let mut g2 = GriffithsDominantCycleFeatureExtractor::new(8, 50, 40);
for &val in &data {
let gf1 = g1.next(val);
let gf2 = g2.next(val);
prop_assert_eq!(gf1.dominant_cycle, gf2.dominant_cycle);
let rf = regime_probs::regime_to_prob_features(crate::regimes::MarketRegime::Steady);
prop_assert!(rf.probs.iter().sum::<f64>() > 0.99);
}
}
}
}
pub trait AsFeatures {
fn as_features(&self) -> &[f64];
}