feat: Family 07 Volume - 6 new volume-flow indicators (#45)
* feat(kvo): add Klinger Volume Oscillator
Stephen J. Klinger's trend-aware volume-force MACD. Each bar produces a 'volume force' (vf) signed by the local trend (+1 / -1 / carry) and scaled by the ratio of the current accumulation horizon to its previous trend. KVO = EMA(vf, fast) - EMA(vf, slow), classic (34, 55).
Rust core (Kvo) with 7 unit tests (rejects zero / fast>=slow, accessors, constant series collapses to 0, warmup lands at slow+1, batch == streaming, reset clears state), plus Python (PyKvo + KVO export), Node (KvoNode), and WASM (WasmKvo) bindings. Fuzz target adds Kvo to the candle-input sweep, bench adds the candle-input KVO benchmark, README counter 71 -> 72 + family table row, CHANGELOG [Unreleased].
* feat(volume-oscillator): add Volume Oscillator (VO)
Percent difference between a fast and a slow SMA of the bar volume: 100 * (SMA(vol, fast) - SMA(vol, slow)) / SMA(vol, slow). Default (14, 28). The line stays near zero in stable conditions; positive readings show rising short-term participation, negative readings show waning interest.
Rust core (VolumeOscillator) with 8 unit tests (period validation, accessors, constant volume == 0, zero-volume window defensive branch, two reference values verified algebraically, batch == streaming, reset), plus Python (PyVolumeOscillator + VolumeOscillator export), Node (VolumeOscillatorNode), and WASM (WasmVolumeOscillator) bindings. Fuzz target adds VolumeOscillator to the candle-input sweep, bench adds the volume_oscillator benchmark, README counter 72 -> 73 + family table row, CHANGELOG [Unreleased].
* feat(nvi-pvi): add Negative & Positive Volume Index
Paul Dysart's cumulative volume-flow indices, popularised by Norman Fosback in 'Stock Market Logic'. Both run from a 1000.0 baseline and only update on a specific direction of volume change:
- NVI updates on volume-contraction bars (volume_t < volume_{t-1}), absorbing the percent close change. Tracks the 'smart money' leg per Fosback.
- PVI updates on volume-expansion bars (volume_t > volume_{t-1}). Tracks the 'crowd' leg.
Both expose with_baseline(f64) for custom starting indexes. The NVI/PVI pair is listed as a single line in indicator-ideas/families/07-volume.md and shares the same lifecycle/test/binding surface, so they ship as one commit.
Rust core (Nvi, Pvi) with 9 unit tests each (accessors, baseline seed, volume direction branches, zero-prev-close guard, custom baseline, batch == streaming, reset), plus Python (PyNvi/PyPvi + NVI/PVI exports), Node (NviNode/PviNode), and WASM (WasmNvi/WasmPvi) bindings. Fuzz target adds Nvi+Pvi to the candle-input sweep, bench adds nvi+pvi entries, README counter 73 -> 75 + family table row, CHANGELOG [Unreleased].
* feat(family-07): add Williams A/D, Anchored VWAP, Demand Index, TSV, VZO, Market Facilitation Index
Finishes the volume-flow family with the remaining (new) entries from
indicator-ideas/families/07-volume.md.
Indicators added:
- Williams A/D (`WilliamsAD`): Larry Williams' volume-less cumulative
accumulation/distribution line. Anchors each bar's contribution to
the previous close via true-high/true-low (gap-aware).
- Anchored VWAP (`AnchoredVwap`): cumulative VWAP whose accumulation
starts at a user-chosen anchor bar. Exposes `set_anchor()` (queued
to the next `update`) for click-to-anchor workflows. Reset clears
both state and pending-anchor flag.
- Demand Index (`DemandIndex`): James Sibbet's smoothed buying-vs-
selling pressure, in the streaming-friendly textbook form
`EMA(volume * close-return * (1 + range/close), period)`.
- Time Segmented Volume (`Tsv`): Don Worden's rolling window-sum of
`(close_t - close_{t-1}) * volume_t`. Default `period = 18`.
- Volume Zone Oscillator (`Vzo`): Walid Khalil's normalised volume-flow
oscillator bounded in `[-100, +100]`, defined as
`100 * EMA(signed_volume) / EMA(volume)`.
- Market Facilitation Index (`MarketFacilitationIndex`): Bill Williams'
per-bar `(high - low) / volume`. Returns `None` on zero-volume bars.
All six indicators ship with unit tests (`rejects_zero_period` where
applicable, `accessors_and_metadata`, constant-series behaviour,
batch == streaming equivalence, reset semantics, and reference-value
or saturation-extreme tests), Python / Node / WASM bindings, fuzz
coverage in `indicator_update_candle`, a `bench_candle_input` line per
indicator, README + CHANGELOG entries, and Python reference-value
tests in `test_new_indicators.py`.
The README indicator counter advances 75 -> 81.
* test(family-07): cover defensive cold paths + Default impls
- ad_oscillator: exercise `value()` after first emission.
- kvo: cover the `cm == 0.0` zero-OHLC defensive branch.
- nvi / pvi: exercise the Default impls.
This commit is contained in:
@@ -6,11 +6,13 @@
|
||||
|
||||
mod acceleration_bands;
|
||||
mod accelerator_oscillator;
|
||||
mod ad_oscillator;
|
||||
mod adl;
|
||||
mod adx;
|
||||
mod adxr;
|
||||
mod alligator;
|
||||
mod alma;
|
||||
mod anchored_vwap;
|
||||
mod apo;
|
||||
mod aroon;
|
||||
mod aroon_oscillator;
|
||||
@@ -34,6 +36,7 @@ mod cmo;
|
||||
mod connors_rsi;
|
||||
mod coppock;
|
||||
mod dema;
|
||||
mod demand_index;
|
||||
mod donchian;
|
||||
mod double_bollinger;
|
||||
mod dpo;
|
||||
@@ -53,6 +56,7 @@ mod jma;
|
||||
mod kama;
|
||||
mod keltner;
|
||||
mod kst;
|
||||
mod kvo;
|
||||
mod laguerre_rsi;
|
||||
mod linreg;
|
||||
mod linreg_angle;
|
||||
@@ -60,12 +64,14 @@ mod linreg_channel;
|
||||
mod linreg_slope;
|
||||
mod ma_envelope;
|
||||
mod macd;
|
||||
mod market_facilitation_index;
|
||||
mod mass_index;
|
||||
mod mcginley_dynamic;
|
||||
mod median_price;
|
||||
mod mfi;
|
||||
mod mom;
|
||||
mod natr;
|
||||
mod nvi;
|
||||
mod obv;
|
||||
mod parkinson;
|
||||
mod percent_b;
|
||||
@@ -73,6 +79,7 @@ mod pgo;
|
||||
mod pmo;
|
||||
mod ppo;
|
||||
mod psar;
|
||||
mod pvi;
|
||||
mod roc;
|
||||
mod rogers_satchell;
|
||||
mod rsi;
|
||||
@@ -96,17 +103,20 @@ mod trima;
|
||||
mod trix;
|
||||
mod true_range;
|
||||
mod tsi;
|
||||
mod tsv;
|
||||
mod ttm_squeeze;
|
||||
mod typical_price;
|
||||
mod ulcer_index;
|
||||
mod ultimate_oscillator;
|
||||
mod vertical_horizontal_filter;
|
||||
mod vidya;
|
||||
mod volume_oscillator;
|
||||
mod vortex;
|
||||
mod vpt;
|
||||
mod vwap;
|
||||
mod vwap_stddev_bands;
|
||||
mod vwma;
|
||||
mod vzo;
|
||||
mod wave_trend;
|
||||
mod weighted_close;
|
||||
mod williams_r;
|
||||
@@ -118,11 +128,13 @@ mod zlema;
|
||||
|
||||
pub use acceleration_bands::{AccelerationBands, AccelerationBandsOutput};
|
||||
pub use accelerator_oscillator::AcceleratorOscillator;
|
||||
pub use ad_oscillator::AdOscillator;
|
||||
pub use adl::Adl;
|
||||
pub use adx::{Adx, AdxOutput};
|
||||
pub use adxr::Adxr;
|
||||
pub use alligator::{Alligator, AlligatorOutput};
|
||||
pub use alma::Alma;
|
||||
pub use anchored_vwap::AnchoredVwap;
|
||||
pub use apo::Apo;
|
||||
pub use aroon::{Aroon, AroonOutput};
|
||||
pub use aroon_oscillator::AroonOscillator;
|
||||
@@ -146,6 +158,7 @@ pub use cmo::Cmo;
|
||||
pub use connors_rsi::ConnorsRsi;
|
||||
pub use coppock::Coppock;
|
||||
pub use dema::Dema;
|
||||
pub use demand_index::DemandIndex;
|
||||
pub use donchian::{Donchian, DonchianOutput};
|
||||
pub use double_bollinger::{DoubleBollinger, DoubleBollingerOutput};
|
||||
pub use dpo::Dpo;
|
||||
@@ -165,6 +178,7 @@ pub use jma::Jma;
|
||||
pub use kama::Kama;
|
||||
pub use keltner::{Keltner, KeltnerOutput};
|
||||
pub use kst::{Kst, KstOutput};
|
||||
pub use kvo::Kvo;
|
||||
pub use laguerre_rsi::LaguerreRsi;
|
||||
pub use linreg::LinearRegression;
|
||||
pub use linreg_angle::LinRegAngle;
|
||||
@@ -172,12 +186,14 @@ pub use linreg_channel::{LinRegChannel, LinRegChannelOutput};
|
||||
pub use linreg_slope::LinRegSlope;
|
||||
pub use ma_envelope::{MaEnvelope, MaEnvelopeOutput};
|
||||
pub use macd::{MacdIndicator, MacdOutput};
|
||||
pub use market_facilitation_index::MarketFacilitationIndex;
|
||||
pub use mass_index::MassIndex;
|
||||
pub use mcginley_dynamic::McGinleyDynamic;
|
||||
pub use median_price::MedianPrice;
|
||||
pub use mfi::Mfi;
|
||||
pub use mom::Mom;
|
||||
pub use natr::Natr;
|
||||
pub use nvi::Nvi;
|
||||
pub use obv::Obv;
|
||||
pub use parkinson::ParkinsonVolatility;
|
||||
pub use percent_b::PercentB;
|
||||
@@ -185,6 +201,7 @@ pub use pgo::Pgo;
|
||||
pub use pmo::Pmo;
|
||||
pub use ppo::Ppo;
|
||||
pub use psar::Psar;
|
||||
pub use pvi::Pvi;
|
||||
pub use roc::Roc;
|
||||
pub use rogers_satchell::RogersSatchellVolatility;
|
||||
pub use rsi::Rsi;
|
||||
@@ -208,17 +225,20 @@ pub use trima::Trima;
|
||||
pub use trix::Trix;
|
||||
pub use true_range::TrueRange;
|
||||
pub use tsi::Tsi;
|
||||
pub use tsv::Tsv;
|
||||
pub use ttm_squeeze::{TtmSqueeze, TtmSqueezeOutput};
|
||||
pub use typical_price::TypicalPrice;
|
||||
pub use ulcer_index::UlcerIndex;
|
||||
pub use ultimate_oscillator::UltimateOscillator;
|
||||
pub use vertical_horizontal_filter::VerticalHorizontalFilter;
|
||||
pub use vidya::Vidya;
|
||||
pub use volume_oscillator::VolumeOscillator;
|
||||
pub use vortex::{Vortex, VortexOutput};
|
||||
pub use vpt::VolumePriceTrend;
|
||||
pub use vwap::{RollingVwap, Vwap};
|
||||
pub use vwap_stddev_bands::{VwapStdDevBands, VwapStdDevBandsOutput};
|
||||
pub use vwma::Vwma;
|
||||
pub use vzo::Vzo;
|
||||
pub use wave_trend::{WaveTrend, WaveTrendOutput};
|
||||
pub use weighted_close::WeightedClose;
|
||||
pub use williams_r::WilliamsR;
|
||||
|
||||
Reference in New Issue
Block a user