quantwave 0.4.0__tar.gz → 0.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quantwave-0.4.0 → quantwave-0.5.1}/Cargo.lock +21 -6
- {quantwave-0.4.0 → quantwave-0.5.1}/Cargo.toml +5 -4
- {quantwave-0.4.0 → quantwave-0.5.1}/PKG-INFO +1 -1
- {quantwave-0.4.0 → quantwave-0.5.1}/python/quantwave/__init__.py +15 -1
- quantwave-0.5.1/quantwave-core/README.md +101 -0
- quantwave-0.5.1/quantwave-core/proptest-regressions/features/mod.txt +7 -0
- quantwave-0.5.1/quantwave-core/src/features/cyber_cycle.rs +76 -0
- quantwave-0.5.1/quantwave-core/src/features/ehlers_autocorrelation.rs +63 -0
- quantwave-0.5.1/quantwave-core/src/features/griffiths_dominant_cycle.rs +53 -0
- quantwave-0.5.1/quantwave-core/src/features/hurst.rs +108 -0
- quantwave-0.5.1/quantwave-core/src/features/instantaneous_trendline.rs +39 -0
- quantwave-0.5.1/quantwave-core/src/features/mod.rs +135 -0
- quantwave-0.5.1/quantwave-core/src/features/regime.rs +50 -0
- quantwave-0.5.1/quantwave-core/src/features/regime_probs.rs +48 -0
- quantwave-0.5.1/quantwave-core/src/features/trendflex.rs +51 -0
- quantwave-0.5.1/quantwave-core/src/indicators/kinematic_kalman.rs +207 -0
- quantwave-0.5.1/quantwave-core/src/indicators/market_structure.rs +410 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/mod.rs +2 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/lib.rs +4 -0
- quantwave-0.5.1/quantwave-core/tests/test_ml_feature_validation.rs +318 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-python/src/lib.rs +239 -0
- quantwave-0.4.0/quantwave-python/README.md +0 -62
- {quantwave-0.4.0 → quantwave-0.5.1}/LICENSE +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/README.md +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/pyproject.toml +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/python/quantwave/polars.py +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/Cargo.toml +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/proptest-regressions/indicators/bandpass.txt +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/proptest-regressions/indicators/oc_price_rsi.txt +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/proptest-regressions/indicators/overlap.txt +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/proptest-regressions/indicators/rocket_rsi.txt +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/bin/bench_complex.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/bin/bench_ema.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/bin/bench_rust.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/bin/bench_sma.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/adaptive_ema.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/alligator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/alma.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/amfm.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/atr_ts.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/autotune.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/bandpass.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/butterworth.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/cg.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/channel_cycle.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/choppiness_index.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/classic_laguerre.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/continuation_index.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/correlation_cycle.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/correlation_trend.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/cyber_cycle.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/cybernetic_oscillator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/cycle.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/cycle_trend_analytics.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/dmh.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/donchian.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/dsma.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ehlers_autocorrelation.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ehlers_filter.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ehlers_loops.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ehlers_stochastic.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ehlers_ultimate_oscillator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/emd.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/exp_dev_bands.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/fisher.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/fisher_high_pass.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/fourier_series.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/fourier_transform.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/fractals.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/frama.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/gap_momentum.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/gaussian.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/generalized_laguerre.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/griffiths_dominant_cycle.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/griffiths_predictor.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/griffiths_spectrum.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/hamming.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/hann.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/harrington_adx.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/heikin_ashi.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/high_pass.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/hilbert_transform.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/hma.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/homodyne_discriminator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/hurst.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ichimoku.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/instantaneous_trendline.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/inverse_fisher.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/just_ignore_them.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/kalman.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/kama.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/keltner.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/laguerre_filter.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/laguerre_oscillator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/laguerre_rsi.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/mad.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/madh.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/mama.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/market_state.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/math.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/mesa_stochastic.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/metadata.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/momentum.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/my_rsi.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/noise_elimination.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/obvm.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/oc_price_rsi.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/one_euro_filter.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/overlap.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/pairs_rotation.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/pattern.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/phasor.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/pivot_points.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/pma.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/precision_trend.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/price_transform.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/recursive_median.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/reflex.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/reverse_ema.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/reversion_index.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/robustness.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/rocket_rsi.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/rodc.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/roofing_filter.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/rsih.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/rsmk.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/sdo.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/simple_predictor.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/sine_wave.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/smoothing.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/statistics.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/stc.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/super_smoother.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/supertrend.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/sve_volatility_bands.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/swiss_army_knife.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/synthetic_oscillator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/system_evaluator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/talib_wrapper.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/tema.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/tradj_ema.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/trendflex.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/triangle.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/truncated_bandpass.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ttm_squeeze.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ultimate_bands.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ultimate_channel.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/ultimate_smoother.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/universal_oscillator.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/usi.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/vfi.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/volatility.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/volume.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/volume_profile.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/vortex.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/voss_predictor.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/vpn.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/vwap.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/wavetrend.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/indicators/zero_lag.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/options_india/black_scholes.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/options_india/chain_analytics.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/options_india/india.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/options_india/iv_solver.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/options_india/mod.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/analytics.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/ensemble.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/gmm.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/hmm.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/hmm_gas.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/hsmm.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/india.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/mod.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/ms_garch.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/multi_asset.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/pelt.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/tar.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/regimes/volatility_clustering.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/test_utils.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/src/traits.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/alma_9_085_6.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/atr_ts_14_25.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/cycle_trend_analytics.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/donchian_5.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/ehlers_autocorrelation.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/ehlers_loops.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/ehlers_stochastic.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/fractals.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/heikin_ashi.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/hma_14.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/ichimoku.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/keltner_20_20_15.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/mad.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/mesa_stochastic.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/oc_price_rsi.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/pivot_points.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/rsih.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/sma_5.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/supertrend_10_3.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/tema_14.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/ttm_squeeze_20_2_15.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/vortex_14.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/voss_predictor.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/gold_standard/wavetrend_10_21_4.json +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-core/tests/test_wrapper.rs +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-python/.gitignore +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-python/Cargo.toml +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-python/LICENSE +0 -0
- {quantwave-0.4.0/quantwave-core → quantwave-0.5.1/quantwave-python}/README.md +0 -0
- {quantwave-0.4.0 → quantwave-0.5.1}/quantwave-python/build.rs +0 -0
|
@@ -2125,15 +2125,30 @@ dependencies = [
|
|
|
2125
2125
|
|
|
2126
2126
|
[[package]]
|
|
2127
2127
|
name = "quantwave"
|
|
2128
|
-
version = "0.
|
|
2128
|
+
version = "0.5.1"
|
|
2129
2129
|
dependencies = [
|
|
2130
2130
|
"quantwave-core",
|
|
2131
2131
|
"quantwave-polars",
|
|
2132
2132
|
]
|
|
2133
2133
|
|
|
2134
|
+
[[package]]
|
|
2135
|
+
name = "quantwave-backtest"
|
|
2136
|
+
version = "0.5.1"
|
|
2137
|
+
dependencies = [
|
|
2138
|
+
"approx",
|
|
2139
|
+
"chrono",
|
|
2140
|
+
"polars",
|
|
2141
|
+
"proptest",
|
|
2142
|
+
"quantwave-core",
|
|
2143
|
+
"rand 0.8.6",
|
|
2144
|
+
"serde",
|
|
2145
|
+
"serde_json",
|
|
2146
|
+
"thiserror 1.0.69",
|
|
2147
|
+
]
|
|
2148
|
+
|
|
2134
2149
|
[[package]]
|
|
2135
2150
|
name = "quantwave-core"
|
|
2136
|
-
version = "0.
|
|
2151
|
+
version = "0.5.1"
|
|
2137
2152
|
dependencies = [
|
|
2138
2153
|
"approx",
|
|
2139
2154
|
"chrono",
|
|
@@ -2151,7 +2166,7 @@ dependencies = [
|
|
|
2151
2166
|
|
|
2152
2167
|
[[package]]
|
|
2153
2168
|
name = "quantwave-plugins"
|
|
2154
|
-
version = "0.
|
|
2169
|
+
version = "0.5.1"
|
|
2155
2170
|
dependencies = [
|
|
2156
2171
|
"polars",
|
|
2157
2172
|
"polars-arrow",
|
|
@@ -2162,7 +2177,7 @@ dependencies = [
|
|
|
2162
2177
|
|
|
2163
2178
|
[[package]]
|
|
2164
2179
|
name = "quantwave-polars"
|
|
2165
|
-
version = "0.
|
|
2180
|
+
version = "0.5.1"
|
|
2166
2181
|
dependencies = [
|
|
2167
2182
|
"polars",
|
|
2168
2183
|
"quantwave-core",
|
|
@@ -2172,7 +2187,7 @@ dependencies = [
|
|
|
2172
2187
|
|
|
2173
2188
|
[[package]]
|
|
2174
2189
|
name = "quantwave-python"
|
|
2175
|
-
version = "0.
|
|
2190
|
+
version = "0.5.1"
|
|
2176
2191
|
dependencies = [
|
|
2177
2192
|
"paste",
|
|
2178
2193
|
"quantwave-core",
|
|
@@ -2181,7 +2196,7 @@ dependencies = [
|
|
|
2181
2196
|
|
|
2182
2197
|
[[package]]
|
|
2183
2198
|
name = "quantwave-xtask"
|
|
2184
|
-
version = "0.
|
|
2199
|
+
version = "0.5.1"
|
|
2185
2200
|
dependencies = [
|
|
2186
2201
|
"anyhow",
|
|
2187
2202
|
"quick-xml",
|
|
@@ -3,7 +3,7 @@ members = ["quantwave-core", "quantwave-python"]
|
|
|
3
3
|
resolver = "2"
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.5.1"
|
|
7
7
|
edition = "2024"
|
|
8
8
|
license = "MIT"
|
|
9
9
|
repository = "https://github.com/lavs9/quantwave"
|
|
@@ -30,9 +30,10 @@ thiserror = "1.0"
|
|
|
30
30
|
chrono = { version = "0.4", features = ["serde"] }
|
|
31
31
|
nalgebra = { version = "0.33", features = ["serde-serialize"] }
|
|
32
32
|
statrs = "0.18"
|
|
33
|
-
quantwave-core = { path = "quantwave-core", version = "0.
|
|
34
|
-
quantwave-polars = { path = "quantwave-polars", version = "0.
|
|
35
|
-
quantwave-plugins = { path = "quantwave-plugins", version = "0.
|
|
33
|
+
quantwave-core = { path = "quantwave-core", version = "0.5.1" }
|
|
34
|
+
quantwave-polars = { path = "quantwave-polars", version = "0.5.1" }
|
|
35
|
+
quantwave-plugins = { path = "quantwave-plugins", version = "0.5.1" }
|
|
36
|
+
quantwave-backtest = { path = "quantwave-backtest", version = "0.5.1" }
|
|
36
37
|
|
|
37
38
|
[profile.dev]
|
|
38
39
|
opt-level = 0
|
|
@@ -125,6 +125,16 @@ class ta:
|
|
|
125
125
|
rocket_rsi = rocketrsi
|
|
126
126
|
trendflex = trendflex
|
|
127
127
|
truncated_bandpass = truncatedbandpass
|
|
128
|
+
# ML features (gw7s notebook + harness + 4ps/gwx cross-epic deliverable)
|
|
129
|
+
cyber_cycle_feature_extractor = CyberCycleFeatureExtractor
|
|
130
|
+
hurst_feature_extractor = HurstFeatureExtractor
|
|
131
|
+
instantaneous_trendline_feature_extractor = InstantaneousTrendlineFeatureExtractor
|
|
132
|
+
trendflex_feature_extractor = TrendflexFeatureExtractor
|
|
133
|
+
regime_to_features = regime_to_features
|
|
134
|
+
# Newly wired for the E2E notebook (trivial parallel to above; completes the locked .ta.features.* surface in Python)
|
|
135
|
+
griffiths_dominant_cycle_feature_extractor = GriffithsDominantCycleFeatureExtractor
|
|
136
|
+
bull_bear_hmm = BullBearHMM
|
|
137
|
+
griffiths_dominant_cycle_features = griffiths_dominant_cycle_features # batch helper
|
|
128
138
|
volume_profile = volumeprofile
|
|
129
139
|
|
|
130
140
|
class options_india:
|
|
@@ -170,5 +180,9 @@ __all__ = [
|
|
|
170
180
|
"HtDcPeriod", "HtPhasor", "HtDcPhase", "HtSine", "HtTrendMode",
|
|
171
181
|
"HurstExponent", "KalmanFilter", "MarketState", "RecursiveMedian",
|
|
172
182
|
"RecursiveMedianOscillator", "Reflex", "RocketRsi", "Trendflex",
|
|
173
|
-
"TruncatedBandpass", "VolumeProfile"
|
|
183
|
+
"TruncatedBandpass", "VolumeProfile",
|
|
184
|
+
# ML feature toolkit (quantwave-gw7s)
|
|
185
|
+
"CyberCycleFeatureExtractor", "HurstFeatureExtractor",
|
|
186
|
+
"InstantaneousTrendlineFeatureExtractor", "TrendflexFeatureExtractor",
|
|
187
|
+
"regime_to_features"
|
|
174
188
|
]
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# QuantWave
|
|
2
|
+
|
|
3
|
+
**High-performance, Polars-native technical analysis — in Python and Rust**
|
|
4
|
+
|
|
5
|
+
150+ indicators · Full Ehlers DSP suite · Regime Detection · Complete Options India stack · Bit-identical streaming & batch
|
|
6
|
+
|
|
7
|
+
**Python** `pip install quantwave` **Rust** `cargo add quantwave`
|
|
8
|
+
|
|
9
|
+
[📖 Documentation](https://lavs9.github.io/quantwave/) • [⭐ GitHub](https://github.com/lavs9/quantwave) • [](https://deepwiki.com/lavs9/quantwave)
|
|
10
|
+
|
|
11
|
+
**150+ indicators • Polars-native • Streaming & batch parity • MIT licensed**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Why QuantWave?
|
|
16
|
+
|
|
17
|
+
Most quantitative libraries force an uncomfortable compromise.
|
|
18
|
+
|
|
19
|
+
**Python-first libraries** (pandas-ta, TA-Lib Python wrappers, etc.) are convenient but fall apart on large datasets, recursive indicators, or live streaming — often becoming 10-100x slower than native code.
|
|
20
|
+
|
|
21
|
+
**Pure Rust libraries** are fast, but they rarely integrate cleanly with modern Polars-based research pipelines and lack the breadth of advanced techniques (Ehlers DSP, regime detection, full Options India analytics).
|
|
22
|
+
|
|
23
|
+
**QuantWave removes the tradeoff.**
|
|
24
|
+
|
|
25
|
+
It delivers **institutional-grade Rust performance** through zero-copy Polars expressions, while offering a first-class, productive experience in both Python and Rust. Every indicator is built on a single mathematical source of truth — the `Next<T>` trait — guaranteeing that batch results (Polars) and real-time streaming results are **bit-identical**.
|
|
26
|
+
|
|
27
|
+
### How We Compare
|
|
28
|
+
|
|
29
|
+
| Approach | Speed on large data | Polars-native | Streaming parity | Breadth (Ehlers + Regimes + Options) |
|
|
30
|
+
|---------------------------|---------------------|---------------|------------------|--------------------------------------|
|
|
31
|
+
| pandas-ta / TA-Lib (Python) | Poor–Average | Partial | Rare | Limited |
|
|
32
|
+
| Other Rust TA crates | Excellent | Poor | Rare | Limited |
|
|
33
|
+
| **QuantWave** | **Excellent** | **Native** | **Guaranteed** | **Strong** |
|
|
34
|
+
|
|
35
|
+
## What We’ve Built
|
|
36
|
+
|
|
37
|
+
QuantWave is no longer early-stage. It ships with production-ready depth across several domains:
|
|
38
|
+
|
|
39
|
+
- **150+ Technical Indicators** with TA-Lib parity and extensive Ehlers DSP coverage
|
|
40
|
+
- **Full Regime Detection Suite** (HMM, GMM, PELT, clustering, conditioned risk metrics)
|
|
41
|
+
- **Complete Options India Stack** — Black-Scholes Greeks, IV solvers, chain analytics (Max Pain, PCR, GEX, OI Zones), and NSE utilities, all exposed as native Polars expressions
|
|
42
|
+
- **Streaming & Batch Parity** — The same mathematical logic powers both high-speed Polars pipelines and low-latency streaming via the universal `Next<T>` trait
|
|
43
|
+
- **Gold-Standard Validation** — Every indicator is tested against reference implementations for correctness
|
|
44
|
+
|
|
45
|
+
## Core Strengths
|
|
46
|
+
|
|
47
|
+
- **Performance** — Rust core with zero-copy Polars expressions
|
|
48
|
+
- **Correctness** — Validated against gold-standard reference vectors
|
|
49
|
+
- **Parity** — Bit-identical results between batch and streaming
|
|
50
|
+
- **Breadth** — Classic indicators + advanced Ehlers DSP + regime detection + Options India
|
|
51
|
+
- **Developer Experience** — Clean Python API (`from quantwave import ta`) and idiomatic Rust
|
|
52
|
+
|
|
53
|
+
## Real-World Performance
|
|
54
|
+
|
|
55
|
+
We don’t just claim to be fast — here’s what the numbers show on 1 million rows of realistic OHLCV data:
|
|
56
|
+
|
|
57
|
+
- **SuperTrend**: 7.4 ms (QuantWave) vs >200 ms (Pandas) → **~27× faster**
|
|
58
|
+
- **CyberCycle** (Ehlers): 5.0 ms vs >500 ms (Pandas) → **~100× faster**
|
|
59
|
+
- **Instantaneous Trendline**: 74 ms vs >2,000 ms (Pandas) → **~27× faster**
|
|
60
|
+
- **Memory footprint** on realistic multi-ticker data: **2–5× lower** than Pandas
|
|
61
|
+
|
|
62
|
+
Complex recursive indicators (the ones that matter most for real strategies) are where the gap becomes dramatic.
|
|
63
|
+
|
|
64
|
+
→ [Full benchmarks & methodology](https://lavs9.github.io/quantwave/benchmarks/)
|
|
65
|
+
|
|
66
|
+
## Quickstart (Python)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install quantwave
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import polars as pl
|
|
74
|
+
from quantwave import ta
|
|
75
|
+
|
|
76
|
+
df = pl.read_parquet("ohlcv.parquet")
|
|
77
|
+
|
|
78
|
+
df = df.with_columns(
|
|
79
|
+
ta.rsi("close", 14).alias("rsi"),
|
|
80
|
+
ta.mama("close").alias("mama"),
|
|
81
|
+
ta.supertrend("high", "low", "close", period=10, multiplier=3.0).alias("supertrend"),
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
[More examples → Documentation](https://lavs9.github.io/quantwave/examples/batch-streaming/)
|
|
86
|
+
|
|
87
|
+
## Get Started
|
|
88
|
+
|
|
89
|
+
**Primary paths**
|
|
90
|
+
- [Get Started with Python](https://lavs9.github.io/quantwave/getting-started/python/)
|
|
91
|
+
- [Get Started with Rust](https://lavs9.github.io/quantwave/getting-started/rust/)
|
|
92
|
+
|
|
93
|
+
**Explore further**
|
|
94
|
+
- [Browse All Indicators](https://lavs9.github.io/quantwave/guides/indicators/)
|
|
95
|
+
- [See Real Benchmarks](https://lavs9.github.io/quantwave/benchmarks/)
|
|
96
|
+
- [v0.4.0 Release Notes](https://github.com/lavs9/quantwave/releases/tag/v0.4.0)
|
|
97
|
+
- [Ask DeepWiki](https://deepwiki.com/lavs9/quantwave)
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
**Made with ❤️ for the quant community.**
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Seeds for failure cases proptest has generated in the past. It is
|
|
2
|
+
# automatically read and these particular cases re-run before any
|
|
3
|
+
# novel cases are generated.
|
|
4
|
+
#
|
|
5
|
+
# It is recommended to check this file in to source control so that
|
|
6
|
+
# everyone who runs the test benefits from these saved cases.
|
|
7
|
+
cc 572d6eab56f4d50d39de44b76ecc8fd7a47740a359e835979a56784a3afd2818 # shrinks to data = [0.0, 0.0, 0.0, 0.0, 0.0]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//! Cyber Cycle feature extractor wrapper.
|
|
2
|
+
//!
|
|
3
|
+
//! Wraps the existing `CyberCycle` to expose both the cycle value and trigger line
|
|
4
|
+
//! plus a few derived features useful for ML (momentum, zero-cross signal, etc.).
|
|
5
|
+
//!
|
|
6
|
+
//! Primary source: quantwave-core/src/indicators/cyber_cycle.rs:35
|
|
7
|
+
//! (returns (CyberCycle, Trigger) per Ehlers "Cybernetic Analysis for Stocks and Futures")
|
|
8
|
+
|
|
9
|
+
use crate::indicators::cyber_cycle::CyberCycle;
|
|
10
|
+
use crate::traits::Next;
|
|
11
|
+
|
|
12
|
+
/// Rich multi-dimensional output for Cyber Cycle features.
|
|
13
|
+
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
14
|
+
pub struct CyberCycleFeatures {
|
|
15
|
+
pub cycle: f64,
|
|
16
|
+
pub trigger: f64,
|
|
17
|
+
/// Simple momentum of the cycle (cycle - previous cycle)
|
|
18
|
+
pub cycle_momentum: f64,
|
|
19
|
+
/// Sign of (cycle - trigger) as a basic oscillator signal
|
|
20
|
+
pub trigger_signal: f64,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#[derive(Debug, Clone)]
|
|
24
|
+
pub struct CyberCycleFeatureExtractor {
|
|
25
|
+
inner: CyberCycle,
|
|
26
|
+
prev_cycle: f64,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
impl CyberCycleFeatureExtractor {
|
|
30
|
+
pub fn new(length: usize) -> Self {
|
|
31
|
+
Self {
|
|
32
|
+
inner: CyberCycle::new(length),
|
|
33
|
+
prev_cycle: 0.0,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
impl Next<f64> for CyberCycleFeatureExtractor {
|
|
39
|
+
type Output = CyberCycleFeatures;
|
|
40
|
+
|
|
41
|
+
fn next(&mut self, input: f64) -> Self::Output {
|
|
42
|
+
let (cycle, trigger) = self.inner.next(input);
|
|
43
|
+
|
|
44
|
+
let momentum = if self.prev_cycle == 0.0 { 0.0 } else { cycle - self.prev_cycle };
|
|
45
|
+
let trigger_signal = (cycle - trigger).signum();
|
|
46
|
+
|
|
47
|
+
self.prev_cycle = cycle;
|
|
48
|
+
|
|
49
|
+
CyberCycleFeatures {
|
|
50
|
+
cycle,
|
|
51
|
+
trigger,
|
|
52
|
+
cycle_momentum: momentum,
|
|
53
|
+
trigger_signal,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
#[cfg(test)]
|
|
59
|
+
mod tests {
|
|
60
|
+
use super::*;
|
|
61
|
+
use approx::assert_relative_eq;
|
|
62
|
+
|
|
63
|
+
#[test]
|
|
64
|
+
fn test_cyber_cycle_features_basic() {
|
|
65
|
+
let mut extractor = CyberCycleFeatureExtractor::new(14);
|
|
66
|
+
|
|
67
|
+
// Feed some oscillatory data
|
|
68
|
+
for i in 0..50 {
|
|
69
|
+
let val = 100.0 + 5.0 * (i as f64 * 0.3).sin();
|
|
70
|
+
let f = extractor.next(val);
|
|
71
|
+
if !f.cycle.is_nan() {
|
|
72
|
+
assert!(f.cycle.abs() < 20.0); // sanity
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//! Ehlers Autocorrelation feature extractor wrapper.
|
|
2
|
+
//!
|
|
3
|
+
//! Wraps the lag correlation vector. For ML, we expose the full vector (or top lags)
|
|
4
|
+
//! plus a "dominant lag" summary – excellent cycle feature.
|
|
5
|
+
//!
|
|
6
|
+
//! Source: quantwave-core/src/indicators/ehlers_autocorrelation.rs (returns Vec<f64> correlations)
|
|
7
|
+
|
|
8
|
+
use crate::indicators::ehlers_autocorrelation::EhlersAutocorrelation;
|
|
9
|
+
use crate::traits::Next;
|
|
10
|
+
|
|
11
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
12
|
+
pub struct EhlersAutocorrelationFeatures {
|
|
13
|
+
pub correlations: Vec<f64>,
|
|
14
|
+
pub dominant_lag: usize,
|
|
15
|
+
pub max_correlation: f64,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[derive(Debug, Clone)]
|
|
19
|
+
pub struct EhlersAutocorrelationFeatureExtractor {
|
|
20
|
+
inner: EhlersAutocorrelation,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl EhlersAutocorrelationFeatureExtractor {
|
|
24
|
+
pub fn new(length: usize, num_lags: usize) -> Self {
|
|
25
|
+
Self {
|
|
26
|
+
inner: EhlersAutocorrelation::new(length, num_lags),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
impl Next<f64> for EhlersAutocorrelationFeatureExtractor {
|
|
32
|
+
type Output = EhlersAutocorrelationFeatures;
|
|
33
|
+
|
|
34
|
+
fn next(&mut self, input: f64) -> Self::Output {
|
|
35
|
+
let corrs = self.inner.next(input);
|
|
36
|
+
let (dominant_lag, &max_correlation) = corrs
|
|
37
|
+
.iter()
|
|
38
|
+
.enumerate()
|
|
39
|
+
.max_by(|a, b| a.1.partial_cmp(b.1).unwrap_or(std::cmp::Ordering::Equal))
|
|
40
|
+
.unwrap_or((0, &0.0));
|
|
41
|
+
|
|
42
|
+
EhlersAutocorrelationFeatures {
|
|
43
|
+
correlations: corrs,
|
|
44
|
+
dominant_lag,
|
|
45
|
+
max_correlation,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[cfg(test)]
|
|
51
|
+
mod tests {
|
|
52
|
+
use super::*;
|
|
53
|
+
|
|
54
|
+
#[test]
|
|
55
|
+
fn test_autocorr_wrapper_basic() {
|
|
56
|
+
let mut ext = EhlersAutocorrelationFeatureExtractor::new(30, 10);
|
|
57
|
+
for i in 0..100 {
|
|
58
|
+
let val = 100.0 + 5.0 * (i as f64 * 0.2).sin();
|
|
59
|
+
let f = ext.next(val);
|
|
60
|
+
assert_eq!(f.correlations.len(), 10);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//! Griffiths Dominant Cycle feature extractor wrapper.
|
|
2
|
+
//!
|
|
3
|
+
//! Wraps the Griffiths spectral estimation dominant cycle detector.
|
|
4
|
+
//! Returns the estimated dominant cycle length — a high-value stationary cycle feature for ML.
|
|
5
|
+
//!
|
|
6
|
+
//! Source: quantwave-core/src/indicators/griffiths_dominant_cycle.rs (returns f64 dominant cycle estimate)
|
|
7
|
+
|
|
8
|
+
use crate::indicators::griffiths_dominant_cycle::GriffithsDominantCycle;
|
|
9
|
+
use crate::traits::Next;
|
|
10
|
+
|
|
11
|
+
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
12
|
+
pub struct GriffithsDominantCycleFeatures {
|
|
13
|
+
pub dominant_cycle: f64,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#[derive(Debug, Clone)]
|
|
17
|
+
pub struct GriffithsDominantCycleFeatureExtractor {
|
|
18
|
+
inner: GriffithsDominantCycle,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl GriffithsDominantCycleFeatureExtractor {
|
|
22
|
+
pub fn new(lower_bound: usize, upper_bound: usize, length: usize) -> Self {
|
|
23
|
+
Self {
|
|
24
|
+
inner: GriffithsDominantCycle::new(lower_bound, upper_bound, length),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
impl Next<f64> for GriffithsDominantCycleFeatureExtractor {
|
|
30
|
+
type Output = GriffithsDominantCycleFeatures;
|
|
31
|
+
|
|
32
|
+
fn next(&mut self, input: f64) -> Self::Output {
|
|
33
|
+
let dc = self.inner.next(input);
|
|
34
|
+
GriffithsDominantCycleFeatures { dominant_cycle: dc }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#[cfg(test)]
|
|
39
|
+
mod tests {
|
|
40
|
+
use super::*;
|
|
41
|
+
|
|
42
|
+
#[test]
|
|
43
|
+
fn test_griffiths_wrapper_basic() {
|
|
44
|
+
let mut ext = GriffithsDominantCycleFeatureExtractor::new(10, 40, 30);
|
|
45
|
+
for i in 0..100 {
|
|
46
|
+
let val = 100.0 + 5.0 * (i as f64 * 0.25).sin();
|
|
47
|
+
let f = ext.next(val);
|
|
48
|
+
if !f.dominant_cycle.is_nan() {
|
|
49
|
+
assert!(f.dominant_cycle > 5.0 && f.dominant_cycle < 50.0);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
//! Hurst Exponent feature extractor wrapper.
|
|
2
|
+
//!
|
|
3
|
+
//! Wraps the existing `HurstExponent` to provide a clean ML feature interface
|
|
4
|
+
//! (persistence value + optional regime classification).
|
|
5
|
+
//!
|
|
6
|
+
//! This is one of the highest-ROI single features for ML/regime work:
|
|
7
|
+
//! - H < 0.5 → mean-reverting (anti-persistent)
|
|
8
|
+
//! - H ≈ 0.5 → random walk
|
|
9
|
+
//! - H > 0.5 → trending (persistent)
|
|
10
|
+
//!
|
|
11
|
+
//! Source: quantwave-core/src/indicators/hurst.rs (Rescaled Range implementation)
|
|
12
|
+
|
|
13
|
+
use crate::indicators::hurst::HurstExponent;
|
|
14
|
+
use crate::traits::Next;
|
|
15
|
+
|
|
16
|
+
/// Rich output for Hurst-based features.
|
|
17
|
+
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
18
|
+
pub struct HurstFeatures {
|
|
19
|
+
pub persistence: f64,
|
|
20
|
+
/// Optional discrete regime label for convenience in ML pipelines.
|
|
21
|
+
/// -1 = mean-reverting, 0 = random, +1 = trending (thresholds configurable later).
|
|
22
|
+
pub regime_label: Option<i8>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
impl HurstFeatures {
|
|
26
|
+
pub fn new(persistence: f64, regime_label: Option<i8>) -> Self {
|
|
27
|
+
Self { persistence, regime_label }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Wrapper that turns the existing HurstExponent into a feature-rich extractor.
|
|
32
|
+
#[derive(Debug, Clone)]
|
|
33
|
+
pub struct HurstFeatureExtractor {
|
|
34
|
+
inner: HurstExponent,
|
|
35
|
+
/// Thresholds for regime classification (can be made configurable later).
|
|
36
|
+
mean_reverting_threshold: f64,
|
|
37
|
+
trending_threshold: f64,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
impl HurstFeatureExtractor {
|
|
41
|
+
pub fn new(period: usize) -> Self {
|
|
42
|
+
Self {
|
|
43
|
+
inner: HurstExponent::new(period),
|
|
44
|
+
mean_reverting_threshold: 0.45,
|
|
45
|
+
trending_threshold: 0.55,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn with_thresholds(mut self, mean_rev: f64, trending: f64) -> Self {
|
|
50
|
+
self.mean_reverting_threshold = mean_rev;
|
|
51
|
+
self.trending_threshold = trending;
|
|
52
|
+
self
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
impl Next<f64> for HurstFeatureExtractor {
|
|
57
|
+
type Output = HurstFeatures;
|
|
58
|
+
|
|
59
|
+
fn next(&mut self, input: f64) -> Self::Output {
|
|
60
|
+
let persistence = self.inner.next(input);
|
|
61
|
+
|
|
62
|
+
let regime_label = if persistence.is_nan() {
|
|
63
|
+
None
|
|
64
|
+
} else if persistence < self.mean_reverting_threshold {
|
|
65
|
+
Some(-1)
|
|
66
|
+
} else if persistence > self.trending_threshold {
|
|
67
|
+
Some(1)
|
|
68
|
+
} else {
|
|
69
|
+
Some(0)
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
HurstFeatures::new(persistence, regime_label)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#[cfg(test)]
|
|
77
|
+
mod tests {
|
|
78
|
+
use super::*;
|
|
79
|
+
use approx::assert_relative_eq;
|
|
80
|
+
|
|
81
|
+
#[test]
|
|
82
|
+
fn test_hurst_feature_basic() {
|
|
83
|
+
let mut extractor = HurstFeatureExtractor::new(20);
|
|
84
|
+
|
|
85
|
+
// Feed trending data
|
|
86
|
+
for i in 0..30 {
|
|
87
|
+
let val = 100.0 + (i as f64) * 0.5;
|
|
88
|
+
let f = extractor.next(val);
|
|
89
|
+
if !f.persistence.is_nan() {
|
|
90
|
+
assert!(f.persistence > 0.5, "Expected trending persistence, got {}", f.persistence);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#[test]
|
|
96
|
+
fn test_hurst_feature_regime_labels() {
|
|
97
|
+
let mut extractor = HurstFeatureExtractor::new(10)
|
|
98
|
+
.with_thresholds(0.4, 0.6);
|
|
99
|
+
|
|
100
|
+
// Force a high persistence value via dummy (real impl will vary)
|
|
101
|
+
// This is a smoke test for the wrapper logic
|
|
102
|
+
let f = extractor.next(100.0);
|
|
103
|
+
// After warmup it should produce a label
|
|
104
|
+
if !f.persistence.is_nan() {
|
|
105
|
+
assert!(f.regime_label.is_some());
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//! Instantaneous Trendline feature extractor wrapper.
|
|
2
|
+
//!
|
|
3
|
+
//! Wraps the zero-lag trendline. For richer ML use we expose the trend value
|
|
4
|
+
//! + a simple derived "trend strength" (placeholder for phase/power in future).
|
|
5
|
+
//!
|
|
6
|
+
//! Source: quantwave-core/src/indicators/instantaneous_trendline.rs (returns f64 trend)
|
|
7
|
+
|
|
8
|
+
use crate::indicators::instantaneous_trendline::InstantaneousTrendline;
|
|
9
|
+
use crate::traits::Next;
|
|
10
|
+
|
|
11
|
+
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
12
|
+
pub struct InstantaneousTrendlineFeatures {
|
|
13
|
+
pub trend: f64,
|
|
14
|
+
/// Placeholder for future phase/power derived features (0.0 for now)
|
|
15
|
+
pub strength: f64,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[derive(Debug, Clone)]
|
|
19
|
+
pub struct InstantaneousTrendlineFeatureExtractor {
|
|
20
|
+
inner: InstantaneousTrendline,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl InstantaneousTrendlineFeatureExtractor {
|
|
24
|
+
pub fn new() -> Self {
|
|
25
|
+
Self {
|
|
26
|
+
inner: InstantaneousTrendline::new(),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
impl Next<f64> for InstantaneousTrendlineFeatureExtractor {
|
|
32
|
+
type Output = InstantaneousTrendlineFeatures;
|
|
33
|
+
|
|
34
|
+
fn next(&mut self, input: f64) -> Self::Output {
|
|
35
|
+
let trend = self.inner.next(input);
|
|
36
|
+
// For MVP, strength is 0.0. Real phase/power can be added later from the indicator internals if exposed.
|
|
37
|
+
InstantaneousTrendlineFeatures { trend, strength: 0.0 }
|
|
38
|
+
}
|
|
39
|
+
}
|