feat(family-10): add 16 Ehlers / Cycle (DSP) indicators (#49)
Implements Family 10 (Ehlers / Cycle) end-to-end across Rust core,
Python / Node / WASM bindings, fuzz, tests, benches and docs. This
is an entirely new family covering John Ehlers' digital-signal-
processing school of cycle analytics — a strong differentiator
versus TA-Lib and pandas-ta, which ship only fragments.
Indicators:
- MAMA (Mesa Adaptive MA) — multi-output { mama, fama }
- FAMA (Following Adaptive MA) — scalar wrapper around MAMA's slow line
- Fisher Transform — Gaussian-normalising price transform
- Inverse Fisher Transform — bounded oscillator (tanh-based)
- SuperSmoother — 2-pole Butterworth lowpass
- Roofing Filter — high-pass + SuperSmoother bandpass
- Decycler — price minus 2-pole high-pass (lag-free trend)
- Decycler Oscillator — fast / slow Decycler difference (MACD-like)
- Hilbert Dominant Cycle — phase-derived period estimator [6, 50]
- Sine Wave Indicator — sin(phase) with 45° lead companion
- Adaptive Cycle Indicator — half-period driver for adaptive oscillators
- Center of Gravity Oscillator — weighted-mass momentum
- Cybernetic Cycle Component — EasyLanguage classic
- Empirical Mode Decomposition — bandpass + envelope mean
- Ehlers Stochastic — Stochastic on Roofing Filter input, [-1, +1]
- Instantaneous Trendline — Ehlers 2-pole lag-free trend
Indicator count rises 71 -> 87 across nine families (was eight).
All sixteen pass batch == streaming equivalence, expose the standard
Indicator surface (update / batch / reset / is_ready / warmup_period
/ name), are fuzz-tested, benchmarked against the checked-in BTCUSDT
1-minute dataset and reach across all four bindings.
Wiki deep-dive drafts for every indicator + Sidebar / Overview /
Home / Warmup updates are staged under indicator-ideas/families/
wiki/family-10-ehlers-cycle/ in the main repo (ghost-ignored) for
the maintainer to publish to the wiki repo manually.
This commit is contained in:
@@ -15,13 +15,16 @@
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use wickra_core::{
|
||||
Alma, Apo, BatchExt, BollingerBands, Cfo, Cmo, ConnorsRsi, Coppock, Dema, DoubleBollinger, Dpo,
|
||||
ElderImpulse, Ema, Frama, HistoricalVolatility, Hma, Indicator, Jma, Kama, Kst, LaguerreRsi,
|
||||
LinRegAngle, LinRegChannel, LinRegSlope, LinearRegression, MaEnvelope, MacdIndicator,
|
||||
McGinleyDynamic, Mom, PercentageTrailingStop, Pmo, Ppo, RenkoTrailingStop, Roc, Rsi,
|
||||
RviVolatility, Sma, Smma, StandardErrorBands, Stc, StdDev, StepTrailingStop, StochRsi, T3, Tema,
|
||||
Tii, Trima, Trix, Tsi, UlcerIndex, VerticalHorizontalFilter, Vidya, Wma, ZScore, ZeroLagMacd,
|
||||
Zlema,
|
||||
AdaptiveCycle, Alma, Apo, BatchExt, BollingerBands, CenterOfGravity, Cfo, Cmo, ConnorsRsi,
|
||||
Coppock, CyberneticCycle, Decycler, DecyclerOscillator, Dema, DoubleBollinger, Dpo,
|
||||
EhlersStochastic, ElderImpulse, Ema, EmpiricalModeDecomposition, Fama, FisherTransform,
|
||||
Frama, HilbertDominantCycle, HistoricalVolatility, Hma, Indicator, InstantaneousTrendline,
|
||||
InverseFisherTransform, Jma, Kama, Kst, LaguerreRsi, LinRegAngle, LinRegChannel,
|
||||
LinRegSlope, LinearRegression, MaEnvelope, MacdIndicator, Mama, McGinleyDynamic, Mom,
|
||||
PercentageTrailingStop, Pmo, Ppo, RenkoTrailingStop, Roc, RoofingFilter, Rsi, RviVolatility,
|
||||
SineWave, Sma, Smma, StandardErrorBands, Stc, StdDev, StepTrailingStop, StochRsi,
|
||||
SuperSmoother, T3, Tema, Tii, Trima, Trix, Tsi, UlcerIndex, VerticalHorizontalFilter, Vidya,
|
||||
Wma, ZScore, ZeroLagMacd, Zlema,
|
||||
};
|
||||
|
||||
/// Drive a single streaming + batch run through one scalar indicator. Marked
|
||||
@@ -112,8 +115,26 @@ fuzz_target!(|data: Vec<f64>| {
|
||||
drive(|| StepTrailingStop::new(1.0).unwrap(), &data);
|
||||
drive(|| RenkoTrailingStop::new(1.0).unwrap(), &data);
|
||||
|
||||
// MACD and Bollinger Bands have non-`f64` outputs, so they cannot use the
|
||||
// generic `drive` helper above. Streaming + batch are still both exercised.
|
||||
// Family 10 — Ehlers / Cycle scalar indicators.
|
||||
drive(|| SuperSmoother::new(10).unwrap(), &data);
|
||||
drive(|| FisherTransform::new(10).unwrap(), &data);
|
||||
drive(|| InverseFisherTransform::new(1.0).unwrap(), &data);
|
||||
drive(|| Decycler::new(20).unwrap(), &data);
|
||||
drive(|| DecyclerOscillator::new(10, 30).unwrap(), &data);
|
||||
drive(|| RoofingFilter::new(10, 48).unwrap(), &data);
|
||||
drive(|| CenterOfGravity::new(10).unwrap(), &data);
|
||||
drive(|| CyberneticCycle::new(10).unwrap(), &data);
|
||||
drive(|| InstantaneousTrendline::new(20).unwrap(), &data);
|
||||
drive(|| EhlersStochastic::new(20).unwrap(), &data);
|
||||
drive(|| EmpiricalModeDecomposition::new(20, 0.5).unwrap(), &data);
|
||||
drive(HilbertDominantCycle::new, &data);
|
||||
drive(AdaptiveCycle::new, &data);
|
||||
drive(SineWave::new, &data);
|
||||
drive(|| Fama::new(0.5, 0.05).unwrap(), &data);
|
||||
|
||||
// MACD, Bollinger Bands and MAMA have non-`f64` outputs, so they cannot
|
||||
// use the generic `drive` helper above. Streaming + batch are still both
|
||||
// exercised.
|
||||
{
|
||||
let mut macd = MacdIndicator::new(12, 26, 9).unwrap();
|
||||
for &x in &data {
|
||||
@@ -128,6 +149,13 @@ fuzz_target!(|data: Vec<f64>| {
|
||||
}
|
||||
let _ = BollingerBands::new(20, 2.0).unwrap().batch(&data);
|
||||
}
|
||||
{
|
||||
let mut mama = Mama::new(0.5, 0.05).unwrap();
|
||||
for &x in &data {
|
||||
let _ = mama.update(x);
|
||||
}
|
||||
let _ = Mama::new(0.5, 0.05).unwrap().batch(&data);
|
||||
}
|
||||
|
||||
// --- Family 05: scalar-input band/channel indicators (multi-output) ---
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user