feat(family-12): add 13 Statistik/Regression indicators (#51)

* feat(family-12): add 13 Statistik/Regression indicators

Brings the Price Statistics family to 20 indicators (7 → 20) and the
total catalogue to 84 (71 → 84). Every indicator ships in the Rust
core plus Python, Node, and WASM bindings with full streaming ↔ batch
parity, fuzz coverage, and benches.

Scalar (f64 → f64):
- Variance, CoefficientOfVariation: rolling population variance and
  its dimensionless ratio with the mean. O(1) updates.
- Skewness, Kurtosis: rolling Pearson skewness and excess kurtosis,
  derived from running sums of x, x², x³, x⁴ via the binomial
  identities — also O(1) per bar.
- StandardError, DetrendedStdDev: standard error of estimate (n − 2)
  and population StdDev (n) of OLS residuals, sharing the LinReg
  O(1) sliding sums.
- RSquared: coefficient of determination of the rolling OLS fit; the
  trend-quality filter, clamped to [0, 1].
- MedianAbsoluteDeviation: robust dispersion estimator; O(period log
  period) per emission via two in-place sorts of a reusable scratch
  buffer.
- Autocorrelation(period, lag): rolling lag-k Pearson autocorrelation.
- HurstExponent(period, chunks): R/S-analysis trend-persistence
  estimator clamped to [0, 1].

Pair indicators (Input = (f64, f64)):
- PearsonCorrelation: rolling cross-series Pearson, O(1).
- Beta: rolling OLS slope of asset vs. benchmark (CAPM).
- SpearmanCorrelation: rolling rank correlation with mid-rank tie
  handling; O(period log period).

Touchpoints:
- crates/wickra-core: 13 new indicator modules + mod.rs / lib.rs
  re-exports.
- bindings/python: pyclasses + add_class registration + __init__.py
  import & __all__ updates. The pair indicators expose
  update(x, y) and batch(x, y) over two equally-sized numpy arrays.
- bindings/node: scalar indicators via node_scalar_indicator! macro;
  pair indicators via new node_pair_indicator! macro; explicit
  structs for Autocorrelation and HurstExponent (two-arg ctors).
  index.js extended with the new exports.
- bindings/wasm: scalar wrappers via wasm_scalar_indicator!; pair
  wrappers via new wasm_pair_indicator! macro.
- fuzz: every scalar drove through the generic helper; pair
  indicators stress-tested by pairing adjacent samples of the fuzz
  input.
- Python tests (test_new_indicators.py): added to SCALAR
  parametrisation, plus algebraic reference values
  (variance of [2,4,6] = 8/3, MAD ignoring outlier = 0, monotone
  non-linear Spearman = 1, two-to-one Beta = 2, etc.) and a
  streaming-vs-batch test for the pair indicators.
- Node tests (indicators.test.js): extended the scalar factories
  map and added a pair-indicator section with the same algebraic
  reference values.
- crates/wickra/benches: bench_scalar entries for all 10 single-
  input new indicators.
- README: counter 71 → 84; Price Statistics family-table row
  expanded with the 13 new indicators.
- CHANGELOG: Unreleased section documents the family addition.

Wiki drafts (ghost-ignored, manual sync to wickra.wiki at release
time): indicator-ideas/families/wiki/family-12-statistik-regression/
contains 13 deep-dive pages plus _Sidebar / Indicators-Overview /
Warmup-Periods / Home fragments for the curator merge.

cargo check --workspace --all-features: clean.

* fix(family-12): remove unreachable defensive guards in hurst_exponent

The three guards (m < 2 continue, end > buf.len() break, denom == 0.0
return) are by-construction unreachable given the constructor invariant
period >= 2 * chunks: m = period / k for k in 1..=chunks always
satisfies m >= 2 and end = (c+1) * m <= k * m <= period = buf.len(),
and m_1 = period and m_2 = period / 2 are always distinct so the slope
denominator is strictly positive. Removing them brings codecov/patch
back to 100%.
This commit is contained in:
kingchenc
2026-05-25 23:42:05 +02:00
committed by GitHub
parent 5aa0949bce
commit 05fcdd9a5e
26 changed files with 4303 additions and 42 deletions
+26
View File
@@ -20,9 +20,11 @@ mod aroon_oscillator;
mod atr;
mod atr_bands;
mod atr_trailing_stop;
mod autocorrelation;
mod awesome_oscillator;
mod awesome_oscillator_histogram;
mod balance_of_power;
mod beta;
mod bollinger;
mod bollinger_bandwidth;
mod camarilla_pivots;
@@ -37,6 +39,7 @@ mod choppiness_index;
mod classic_pivots;
mod cmf;
mod cmo;
mod coefficient_of_variation;
mod connors_rsi;
mod coppock;
mod cybernetic_cycle;
@@ -45,6 +48,7 @@ mod decycler_oscillator;
mod dema;
mod demand_index;
mod demark_pivots;
mod detrended_std_dev;
mod donchian;
mod donchian_stop;
mod double_bollinger;
@@ -68,6 +72,7 @@ mod hilo_activator;
mod historical_volatility;
mod hma;
mod hurst_channel;
mod hurst_exponent;
mod ichimoku;
mod inertia;
mod instantaneous_trendline;
@@ -76,6 +81,7 @@ mod jma;
mod kama;
mod keltner;
mod kst;
mod kurtosis;
mod kvo;
mod laguerre_rsi;
mod linreg;
@@ -88,6 +94,7 @@ mod mama;
mod market_facilitation_index;
mod mass_index;
mod mcginley_dynamic;
mod median_absolute_deviation;
mod median_price;
mod mfi;
mod mom;
@@ -95,6 +102,7 @@ mod natr;
mod nvi;
mod obv;
mod parkinson;
mod pearson_correlation;
mod percent_b;
mod percentage_trailing_stop;
mod pgo;
@@ -102,6 +110,7 @@ mod pmo;
mod ppo;
mod psar;
mod pvi;
mod r_squared;
mod renko_trailing_stop;
mod roc;
mod rogers_satchell;
@@ -111,9 +120,12 @@ mod rvi;
mod rvi_volatility;
mod rwi;
mod sine_wave;
mod skewness;
mod sma;
mod smi;
mod smma;
mod spearman_correlation;
mod standard_error;
mod standard_error_bands;
mod starc_bands;
mod stc;
@@ -147,6 +159,7 @@ mod ttm_squeeze;
mod typical_price;
mod ulcer_index;
mod ultimate_oscillator;
mod variance;
mod vertical_horizontal_filter;
mod vidya;
mod volty_stop;
@@ -186,9 +199,11 @@ pub use aroon_oscillator::AroonOscillator;
pub use atr::Atr;
pub use atr_bands::{AtrBands, AtrBandsOutput};
pub use atr_trailing_stop::AtrTrailingStop;
pub use autocorrelation::Autocorrelation;
pub use awesome_oscillator::AwesomeOscillator;
pub use awesome_oscillator_histogram::AwesomeOscillatorHistogram;
pub use balance_of_power::BalanceOfPower;
pub use beta::Beta;
pub use bollinger::{BollingerBands, BollingerOutput};
pub use bollinger_bandwidth::BollingerBandwidth;
pub use camarilla_pivots::{Camarilla, CamarillaPivotsOutput};
@@ -203,6 +218,7 @@ pub use choppiness_index::ChoppinessIndex;
pub use classic_pivots::{ClassicPivots, ClassicPivotsOutput};
pub use cmf::ChaikinMoneyFlow;
pub use cmo::Cmo;
pub use coefficient_of_variation::CoefficientOfVariation;
pub use connors_rsi::ConnorsRsi;
pub use coppock::Coppock;
pub use cybernetic_cycle::CyberneticCycle;
@@ -211,6 +227,7 @@ pub use decycler_oscillator::DecyclerOscillator;
pub use dema::Dema;
pub use demand_index::DemandIndex;
pub use demark_pivots::{DemarkPivots, DemarkPivotsOutput};
pub use detrended_std_dev::DetrendedStdDev;
pub use donchian::{Donchian, DonchianOutput};
pub use donchian_stop::{DonchianStop, DonchianStopOutput};
pub use double_bollinger::{DoubleBollinger, DoubleBollingerOutput};
@@ -234,6 +251,7 @@ pub use hilo_activator::HiLoActivator;
pub use historical_volatility::HistoricalVolatility;
pub use hma::Hma;
pub use hurst_channel::{HurstChannel, HurstChannelOutput};
pub use hurst_exponent::HurstExponent;
pub use ichimoku::{Ichimoku, IchimokuOutput};
pub use inertia::Inertia;
pub use instantaneous_trendline::InstantaneousTrendline;
@@ -242,6 +260,7 @@ pub use jma::Jma;
pub use kama::Kama;
pub use keltner::{Keltner, KeltnerOutput};
pub use kst::{Kst, KstOutput};
pub use kurtosis::Kurtosis;
pub use kvo::Kvo;
pub use laguerre_rsi::LaguerreRsi;
pub use linreg::LinearRegression;
@@ -254,6 +273,7 @@ pub use mama::{Mama, MamaOutput};
pub use market_facilitation_index::MarketFacilitationIndex;
pub use mass_index::MassIndex;
pub use mcginley_dynamic::McGinleyDynamic;
pub use median_absolute_deviation::MedianAbsoluteDeviation;
pub use median_price::MedianPrice;
pub use mfi::Mfi;
pub use mom::Mom;
@@ -261,6 +281,7 @@ pub use natr::Natr;
pub use nvi::Nvi;
pub use obv::Obv;
pub use parkinson::ParkinsonVolatility;
pub use pearson_correlation::PearsonCorrelation;
pub use percent_b::PercentB;
pub use percentage_trailing_stop::PercentageTrailingStop;
pub use pgo::Pgo;
@@ -268,6 +289,7 @@ pub use pmo::Pmo;
pub use ppo::Ppo;
pub use psar::Psar;
pub use pvi::Pvi;
pub use r_squared::RSquared;
pub use renko_trailing_stop::RenkoTrailingStop;
pub use roc::Roc;
pub use rogers_satchell::RogersSatchellVolatility;
@@ -277,9 +299,12 @@ pub use rvi::Rvi;
pub use rvi_volatility::RviVolatility;
pub use rwi::{Rwi, RwiOutput};
pub use sine_wave::SineWave;
pub use skewness::Skewness;
pub use sma::Sma;
pub use smi::Smi;
pub use smma::Smma;
pub use spearman_correlation::SpearmanCorrelation;
pub use standard_error::StandardError;
pub use standard_error_bands::{StandardErrorBands, StandardErrorBandsOutput};
pub use starc_bands::{StarcBands, StarcBandsOutput};
pub use stc::Stc;
@@ -313,6 +338,7 @@ pub use ttm_squeeze::{TtmSqueeze, TtmSqueezeOutput};
pub use typical_price::TypicalPrice;
pub use ulcer_index::UlcerIndex;
pub use ultimate_oscillator::UltimateOscillator;
pub use variance::Variance;
pub use vertical_horizontal_filter::VerticalHorizontalFilter;
pub use vidya::Vidya;
pub use volty_stop::VoltyStop;