feat(family-08): Pivots & Support/Resistance (7 indicators) (#47)

* feat(family-08): add Classic, Fibonacci, Camarilla, Woodie and DeMark pivots + Williams Fractals + ZigZag

Seven new indicators land the previously empty Pivots & S/R family
(family 08), each implemented in wickra-core with the full Indicator
trait surface (update / reset / warmup_period / is_ready / name),
exposed across Python (PyO3), Node (napi-rs) and WASM (wasm-bindgen)
with the standard streaming + batch APIs, and covered by Rust unit
tests, Python streaming-vs-batch + reference-value tests, Node
streaming-vs-batch tests, the candle-input fuzz target and Rust
microbenchmarks.

- ClassicPivots (7 levels): PP = (H+L+C)/3, three R/S tiers per the
  floor-trader formulas.
- FibonacciPivots (7 levels): PP plus R/S spaced by 0.382 / 0.618 /
  1.000 of the prior range.
- Camarilla (9 levels): Nick Stott's four-tier `C +/- (H - L) * 1.1 /
  {12, 6, 4, 2}` levels.
- WoodiePivots (5 levels): close-weighted PP = (H + L + 2*C) / 4 plus
  two R/S tiers.
- DemarkPivots (3 levels): conditional X sum based on the previous
  bar's open-vs-close relationship.
- WilliamsFractals: five-bar swing detector emitting optional up/down
  fractal prices at the centre of each window.
- ZigZag: percent-threshold swing tracker, non-repainting; emits the
  just-completed extreme and direction on confirmed reversals only.

README family table updated to nine families / 78 indicators;
CHANGELOG records the family-08 addition under [Unreleased].

* fix(family-08 tests): unify MULTI dict to 3-tuple (factory, batch_call, k)

The HEAD-side family-08 test parametrised MULTI[name] as
`(factory, batch_call, output_arity)` so that pivots with arity 3/5/7/9
fit the same harness. Main's entries arrived as 2-tuples; convert them
all to the 3-tuple shape so `make, batch_call, k = MULTI[name]` unpacks
cleanly. Lifecycle test now indexes the tuple instead of destructuring.

* test(zig_zag): tighten flat-oscillation test (drop dead counter branch)

The previous version of `small_oscillations_yield_no_swings` counted
emitted swings, but the assertion proves the counter never increments
so codecov flagged `emitted += 1` as uncovered. Switch to a per-bar
`assert!(...is_none())` — same coverage of the no-swing path, no dead
branch.
This commit is contained in:
kingchenc
2026-05-25 20:06:46 +02:00
committed by GitHub
parent f10b8c2e2d
commit 7e1e988596
19 changed files with 3379 additions and 45 deletions
+14
View File
@@ -24,6 +24,7 @@ mod awesome_oscillator_histogram;
mod balance_of_power;
mod bollinger;
mod bollinger_bandwidth;
mod camarilla_pivots;
mod cci;
mod cfo;
mod chaikin_oscillator;
@@ -31,12 +32,14 @@ mod chaikin_volatility;
mod chande_kroll_stop;
mod chandelier_exit;
mod choppiness_index;
mod classic_pivots;
mod cmf;
mod cmo;
mod connors_rsi;
mod coppock;
mod dema;
mod demand_index;
mod demark_pivots;
mod donchian;
mod donchian_stop;
mod double_bollinger;
@@ -45,6 +48,7 @@ mod ease_of_movement;
mod elder_impulse;
mod ema;
mod evwma;
mod fibonacci_pivots;
mod force_index;
mod fractal_chaos_bands;
mod frama;
@@ -125,12 +129,15 @@ mod vwma;
mod vzo;
mod wave_trend;
mod weighted_close;
mod williams_fractals;
mod williams_r;
mod wma;
mod woodie_pivots;
mod yang_zhang;
mod yoyo_exit;
mod z_score;
mod zero_lag_macd;
mod zig_zag;
mod zlema;
pub use acceleration_bands::{AccelerationBands, AccelerationBandsOutput};
@@ -153,6 +160,7 @@ pub use awesome_oscillator_histogram::AwesomeOscillatorHistogram;
pub use balance_of_power::BalanceOfPower;
pub use bollinger::{BollingerBands, BollingerOutput};
pub use bollinger_bandwidth::BollingerBandwidth;
pub use camarilla_pivots::{Camarilla, CamarillaPivotsOutput};
pub use cci::Cci;
pub use cfo::Cfo;
pub use chaikin_oscillator::ChaikinOscillator;
@@ -160,12 +168,14 @@ pub use chaikin_volatility::ChaikinVolatility;
pub use chande_kroll_stop::{ChandeKrollStop, ChandeKrollStopOutput};
pub use chandelier_exit::{ChandelierExit, ChandelierExitOutput};
pub use choppiness_index::ChoppinessIndex;
pub use classic_pivots::{ClassicPivots, ClassicPivotsOutput};
pub use cmf::ChaikinMoneyFlow;
pub use cmo::Cmo;
pub use connors_rsi::ConnorsRsi;
pub use coppock::Coppock;
pub use dema::Dema;
pub use demand_index::DemandIndex;
pub use demark_pivots::{DemarkPivots, DemarkPivotsOutput};
pub use donchian::{Donchian, DonchianOutput};
pub use donchian_stop::{DonchianStop, DonchianStopOutput};
pub use double_bollinger::{DoubleBollinger, DoubleBollingerOutput};
@@ -174,6 +184,7 @@ pub use ease_of_movement::EaseOfMovement;
pub use elder_impulse::ElderImpulse;
pub use ema::Ema;
pub use evwma::Evwma;
pub use fibonacci_pivots::{FibonacciPivots, FibonacciPivotsOutput};
pub use force_index::ForceIndex;
pub use fractal_chaos_bands::{FractalChaosBands, FractalChaosBandsOutput};
pub use frama::Frama;
@@ -254,10 +265,13 @@ pub use vwma::Vwma;
pub use vzo::Vzo;
pub use wave_trend::{WaveTrend, WaveTrendOutput};
pub use weighted_close::WeightedClose;
pub use williams_fractals::{WilliamsFractals, WilliamsFractalsOutput};
pub use williams_r::WilliamsR;
pub use wma::Wma;
pub use woodie_pivots::{WoodiePivots, WoodiePivotsOutput};
pub use yang_zhang::YangZhangVolatility;
pub use yoyo_exit::YoyoExit;
pub use z_score::ZScore;
pub use zero_lag_macd::{ZeroLagMacd, ZeroLagMacdOutput};
pub use zig_zag::{ZigZag, ZigZagOutput};
pub use zlema::Zlema;