83e34c6f714f195e1440ba3a1410ecfb0e331f42
32 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
67feec598a |
feat(indicators): add B6 Bands & Channels family (429 -> 434) (#191)
Adds the **B6 Bands & Channels** batch — five band/channel indicators, taking the catalogue from 429 to 434.
| Indicator | Input → Output | Summary |
|-----------|----------------|---------|
| `ProjectionBands` | `Candle` → `{upper,middle,lower}` | Widner forward-projected high/low regression envelope |
| `ProjectionOscillator` | `Candle` → `f64` | Close position inside the projection bands, scaled 0..100 |
| `QuartileBands` | `f64` → `{upper,middle,lower}` | Rolling 25th/50th/75th-percentile (Q1/median/Q3) envelope |
| `BomarBands` | `f64` → `{upper,middle,lower}` | Adaptive percentage bands containing a target coverage fraction of recent closes |
| `MedianChannel` | `f64` → `{upper,middle,lower}` | Robust median ± multiplier·MAD envelope |
All five are distinct from existing indicators (verified against the core: `LinRegChannel`, `StandardErrorBands`, `Donchian`, `RollingQuantile`, `HurstChannel`). SKIPped from the roadmap: Price Channel (= `Donchian`) and Moving-Average Channel (≈ `MaEnvelope`/`Keltner`).
Each ships:
- Core indicator with per-branch unit tests (Codecov-strict 100%).
- python / node / wasm bindings (struct outputs are hand-written; `ProjectionOscillator` uses the generated candle→f64 path).
- Fuzz drives, python (`MULTI`/`SCALAR_MULTI`/`CANDLE_SCALAR`) + node test registries, README + CHANGELOG counter bump to 434.
Verified locally: `cargo fmt`, `clippy --workspace --all-targets --all-features -D warnings` (clean), `wickra-core` 3511 lib + 392 doc tests, node 509 tests, pytest 840.
|
||
|
|
6b8c6a0e7f |
B5 volatility & bands batch (423 -> 429) (#189)
Adds six **Volatility & Bands** indicators (Part B5 of the expansion roadmap), 423 → 429. | Indicator | Input → Output | Summary | |-----------|----------------|---------| | `EwmaVolatility` | `f64` → `f64` | RiskMetrics exponentially-weighted volatility (λ decay) | | `Garch11` | `f64` → `f64` | GARCH(1,1) conditional volatility with a long-run-variance anchor | | `BipowerVariation` | `f64` → `f64` | jump-robust realized bipower variation (π/2 · Σ\|rₜ\|\|rₜ₋₁\|) | | `VolatilityRatio` | `Candle` → `f64` | Schwager's true range over the EMA of prior true ranges (>2 = wide-ranging day) | | `VolatilityCone` | `Candle` → `VolatilityConeOutput` | current realized volatility within its min/median/max envelope + percentile | | `VolatilityOfVolatility` | `f64` → `f64` | sample stddev of a rolling realized-volatility series | ### Notes - Two B5 roadmap items were dropped as duplicates/by-construction: `RealizedVolatility` already ships (v0.5.4); `Downside Semi-Deviation` is internal to Sortino. `Bipower Variation` confirmed distinct from `JumpIndicator` (a ±1 flag, not a variance measure). - `VolatilityRatio` implements the widely-charted EMA-of-true-range convention (denominator excludes the current bar so the 2.0 threshold means "twice typical"), distinct from the existing pairwise `variance_ratio`. - `Garch11` mean-reverts to `ω/(1−β)` on a flat series (does not decay to 0 like EWMA) — pinned by a dedicated test. ### Coverage / verification - Full core + Python/Node/WASM bindings, fuzz drivers (scalar + candle), registries, CHANGELOG, README + docs counter sync. - 100% unit-test coverage per indicator (every branch). - Green locally: `cargo clippy --workspace --all-targets --all-features -D warnings`, core lib (3479) + doc (387), node (504), python (830). Deep-dive docs for all six are staged for `wickra-docs` and pushed after release (gated). |
||
|
|
1f4bf9e3a6 |
feat(core): B4 price oscillators (TsfOscillator, MacdHistogram, PpoHistogram) (#184)
Adds three **Price Oscillators** family indicators (420 → 423). ## Indicators - **TsfOscillator** — `100·(close − TSF)/close`, the percentage gap of the close to the **one-bar-ahead** time-series forecast. Close-relative companion to `Cfo`, which measures the same gap against the regression value at the *current* bar; the two differ by exactly the slope term `100·b/close`. - **MacdHistogram** — the standalone `macd − signal` bar of MACD exposed as a plain `f64` series. - **PpoHistogram** — the Percentage Price Oscillator with its 9-period signal EMA and the resulting scale-free, zero-centered histogram (PPO itself only emits the line). All three are scalar `f64` indicators wrapping existing, already-tested building blocks (`MacdIndicator`, `Ppo` + `Ema`, `Tsf`). ## Scope notes (VORAB-CHECK) The B4 roadmap listed six items; three were dropped to avoid duplicates: - *Forecast Oscillator* already ships as `Cfo`. - *Derivative Oscillator* already ships (`DerivativeOscillator`, B2). - *Detrended Synthetic Price* deferred — no citable formula distinct from the existing `Apo`/`Dpo`. ## Touchpoints Core (`tsf_oscillator.rs`, `macd_histogram.rs`, `ppo_histogram.rs`) with full per-branch unit tests, `mod.rs`/`lib.rs`, python/node/wasm bindings (wasm via typed-arg macro, python/node hand-written for the multi-arg histograms), fuzz drivers, python reference + streaming-vs-batch tests, node factories, README family row + counter, CHANGELOG. Local verify: `cargo test --workspace` green, `clippy -D warnings` clean, node 498 tests, full python suite green. |
||
|
|
13bc801f89 |
feat(indicators): B3 Trend & Directional batch (413 -> 420) (#181)
Adds the **B3 — Trend & Directional** batch: seven new indicators, taking the catalog from 413 to 420 (Trend & Directional family). | Indicator | Input → Output | Summary | |-----------|----------------|---------| | `Qstick` | candle → f64 | Chande's SMA of the candle body (close − open) | | `TtmTrend` | candle → f64 (±1) | John Carter close-vs-median-SMA trend filter | | `TrendStrengthIndex` | f64 → f64 | signed r² of an OLS regression of price vs time | | `PolarizedFractalEfficiency` | f64 → f64 | Hannula directional trend efficiency | | `WavePm` | f64 → f64 | Kase variance-normalised peak-momentum statistic (reconstruction) | | `GatorOscillator` | candle → struct | Bill Williams Alligator convergence/divergence histogram | | `KasePermissionStochastic` | candle → struct | double-smoothed stochastic permission filter | Note: the roadmap's "Directional Indicator +DI/−DI" item is already covered by the existing standalone `PlusDi` / `MinusDi` / `Dx`, so it is intentionally not re-added. All touchpoints wired: core (every-branch unit tests), Python/Node/WASM bindings, fuzz drivers, Python test registries + reference tests, Node factories, README/CHANGELOG counters. Local verify: `cargo test -p wickra-core` (lib 3389 + doc 378), `cargo clippy --workspace --all-targets --all-features -- -D warnings`, node build + 495 tests, maturin + 815 pytest, counter 420 == 420. |
||
|
|
4f81222aed |
Deepen Momentum Oscillators family with ten additions (#179)
Deepens the **Momentum Oscillators** family with ten widely-used oscillators (403 → 413 indicators), the second batch of Part B (family deepening). | Indicator | Binding | Input → Output | |-----------|---------|----------------| | `DisparityIndex` | `DisparityIndex` | scalar → scalar | | `FisherRsi` | `FisherRSI` | scalar → scalar | | `Rmi` | `RMI` | scalar (period, momentum) → scalar | | `DerivativeOscillator` | `DerivativeOscillator` | scalar (4 periods) → scalar | | `Rsx` | `RSX` | scalar → scalar | | `DynamicMomentumIndex` | `DynamicMomentumIndex` | scalar → scalar | | `IntradayMomentumIndex` | `IMI` | candle (open+close) → scalar | | `StochasticCci` | `StochasticCCI` | candle → scalar | | `ElderRay` | `ElderRay` | candle → struct (bull/bear) | | `Qqe` | `QQE` | scalar → struct (rsi_ma/trailing) | LSMA was dropped from the planned set: it already ships as `LinearRegression`. The single-period scalars use generated macro bindings; `Rmi` / `DerivativeOscillator` use hand node/python bindings with the typed wasm macro; `ElderRay`/`Qqe` use custom struct bindings; `IntradayMomentumIndex` uses custom candle bindings carrying the open. Full coverage: core modules with per-branch unit tests, mod/lib catalogue, FAMILIES + assert, README + docs counters, CHANGELOG, all three bindings (regenerated `index.d.ts`/`index.js`), fuzz drivers, and the python/node test registries. Local verification: `cargo test -p wickra-core` (lib 3335 + doc 371), `cargo clippy --workspace --all-targets --all-features -D warnings` clean, node `npm run build && npm test` (488), python `pytest` (802). |
||
|
|
b228a70d7d |
Deepen Moving Averages family with seven additions (#177)
Deepens the **Moving Averages** family with seven widely-used variants (396 → 403 indicators), the first batch of Part B (family deepening). All are scalar `f64 → f64`: | Indicator | Binding | Notes | |-----------|---------|-------| | `SineWeightedMa` | `SWMA` | symmetric half-cycle sine-weighted window | | `GeometricMa` | `GMA` | rolling geometric mean (log-space average) | | `Ehma` | `EHMA` | exponential Hull MA (Hull construction over EMAs) | | `MedianMa` | `MedianMA` | rolling median, robust to single outliers | | `AdaptiveLaguerreFilter` | `AdaptiveLaguerre` | Ehlers' adaptive Laguerre filter (median-of-normalised-error γ) | | `GeneralizedDema` | `GD` | Tillson's volume-factor double EMA; `v=1` is DEMA, `v=0` is EMA | | `HoltWinters` | `HoltWinters` | Holt's linear double exponential smoothing (level + trend) | LSMA was dropped from the planned set: it already ships as `LinearRegression` (TA-Lib `LINEARREG`, the rolling least-squares endpoint). The five single-period filters use the generated scalar macro bindings; `GeneralizedDema` (period, v) and `HoltWinters` (alpha, beta) use hand-written node/python bindings with the typed wasm macro (precedent `T3` / `Alma`). Full coverage: core modules with per-branch unit tests (100% intent), mod/lib catalogue, FAMILIES group + assert, README + docs counters, CHANGELOG, all three bindings (regenerated `index.d.ts` / `index.js`), fuzz drivers, and the python/node test registries. Local verification: `cargo test -p wickra-core` (lib 3255 + doc 361), `cargo clippy --workspace --all-targets --all-features -D warnings` clean, node `npm run build && npm test` (478), python `pytest` (791). |
||
|
|
fcb221ec03 |
feat: add 19 indicators for external feature-extractor coverage (377 -> 396) (#175)
Adds 19 streaming indicators so an external trading-bot feature extractor can replace its hand-built features with native, batch/streaming-equivalent ones. Each is a real gap (verified against the existing catalogue), production-only, with full Python/Node/WASM bindings, fuzz drivers, and tests. Five commits, one per family group; counter 377 -> 396. ## What's added **Price Statistics (6)** — `LogReturn`, `RealizedVolatility` (raw quadratic variation, the un-annualised counterpart to `HistoricalVolatility`), `RollingQuantile`, `RollingIqr`, `RollingPercentileRank`, `SpreadAr1Coefficient` (pairwise AR(1) rho of the spread; complements `OuHalfLife`). **Price Action (4)** — `CloseVsOpen`, `BodySizePct`, `WickRatio`, `HighLowRange` (stateless per-bar OHLC transforms). **Regime / Trend / Jump labels (3)** — `TrendLabel` (sign of the rolling OLS slope), `JumpIndicator` (return outliers vs trailing volatility, measured as deviation from the trailing mean so steady drift is not flagged), `RegimeLabel` (volatility-quantile regime split). **Risk / Performance (2)** — `WinRate`, `Expectancy` (R-multiple). **Microstructure (4)** — `OrderFlowImbalance` (Cont-Kukanov-Stoikov OFI), `Vpin`, `AmihudIlliquidity`, `RollMeasure`. These reuse the existing `OrderBook` / `Trade` inputs (no new input type). ## Intentionally NOT added (already present, would be duplicates) - **Population skew / kurtosis** — `skewness.rs` / `kurtosis.rs` are already population moments (divisor n). - **Hurst R/S** — `hurst_exponent.rs` already uses rescaled-range (R/S) analysis. - **Queue Imbalance** — exactly `OrderBookImbalanceTop1` ((bidSize - askSize) / (bidSize + askSize)). ## Verification `cargo test -p wickra-core` (lib 3187 + doc 354), `cargo clippy --workspace --all-targets --all-features -D warnings` clean, node `npm run build && npm test` (471), python `pytest` (784). Counter consistent across `mod.rs`, lib block, README, and docs/README at 396. |
||
|
|
5a1d607807 |
feat(indicators): A5b Fibonacci tools (geometric) (#172)
Completes the **Fibonacci** family with the four geometric/time tools (catalogue 373 -> 377). All extend the internal `pattern_swing` ZigZag tracker with a per-pivot bar index and a current-bar counter (additive — the chart/harmonic detectors are unaffected), and emit `Candle -> struct` outputs via custom Python/Node/WASM bindings. | Tool | Output | |------|--------| | `FibFan` | three trendlines fanning from a swing start through its 38.2/50/61.8% retracement levels, extended to the current bar | | `FibArcs` | semicircular retracement levels centred on the swing end, normalised by the leg's bar-width (chart-scale-free) | | `FibChannel` | a sloped base trendline plus parallel lines at Fibonacci multiples of the channel width | | `FibTimeZones` | markers at Fibonacci bar-distances (1/2/3/5/8/...) from the latest swing pivot | The geometric tools are novel as streaming indicators; each normalises its geometry to the swing leg's bar-width so the output is chart-scale-free. Formulas are documented in each module and deep-dive. Fully wired: core (100% unit-tested branches incl. the new `pattern_swing` bar tracking), Python/Node/WASM struct bindings, fuzz, reference + streaming-vs-batch tests. Verification: `cargo test --workspace` green, clippy `-D warnings` clean, node 454 tests, python 768 tests. |
||
|
|
716eb40206 |
feat(indicators): A5a Fibonacci tools (price-level) (#171)
Adds the six price-level Fibonacci tools as a new **Fibonacci** family (catalogue 367 -> 373, twenty-four families). All build on the internal `pattern_swing` ZigZag tracker, are parameter-free (baked 5% swing threshold), and emit `Candle -> struct` outputs via custom Python/Node/WASM bindings. | Tool | Output | |------|--------| | `FibRetracement` | seven levels (0/23.6/38.2/50/61.8/78.6/100%) of the last swing leg | | `FibExtension` | five extension ratios (127.2/141.4/161.8/200/261.8%) projected beyond the leg | | `FibProjection` | A-B-C measured-move target zone (61.8/100/161.8/261.8%) | | `AutoFib` | retracement anchored on the dominant (largest-magnitude) recent leg | | `GoldenPocket` | the 0.618-0.65 optimal-trade-entry band (low/mid/high) | | `FibConfluence` | densest cluster of retracement levels across recent legs (price + strength) | Fully wired: core (100% unit-tested branches), Python/Node/WASM struct bindings, fuzz driver, reference + streaming-vs-batch tests, README/docs counter. The four geometric/time tools (Fan, Arcs, Channel, Time Zones) follow in A5b. Verification: `cargo test --workspace` green, clippy `-D warnings` clean, node 450 tests, python 760 tests. |
||
|
|
4250ed99f4 |
feat(patterns): add the Harmonic Patterns family (8 XABCD detectors) (#169)
## Summary Adds a new **Harmonic Patterns** indicator family (counter 359 → 367, families 22 → 23) — the second half of the A4 roadmap item, following the Chart Patterns family in #166. Eight Fibonacci-ratio detectors built on the shared swing-pivot tracker (`indicators::pattern_swing`) plus two new helpers there — `xabcd` (reads the last five pivots as X-A-B-C-D) and `ratios_in` (checks a list of `(value, low, high)` Fibonacci windows in one expression, no multi-line `&&` coverage gaps). Each consumes candles and emits the uniform pattern sign convention — `+1.0` bullish (terminal point D a swing low), `-1.0` bearish (D a swing high), `0.0` otherwise, never `None`. Parameter-free, with the Fibonacci windows documented as constants per detector. ## Detectors | Indicator | Defining ratio | |-----------|----------------| | `Abcd` | four-point AB=CD (BC retraces AB, CD ≈ AB) | | `Gartley` | AD/XA ≈ 0.786 | | `Butterfly` | AD/XA ∈ 1.27–1.618 (extended D) | | `Bat` | AD/XA ≈ 0.886, shallow B | | `Crab` | AD/XA ≈ 1.618 (deepest D) | | `Shark` | expansion AB, AD/XA 0.886–1.13 | | `Cypher` | BC on XA, CD/XC ≈ 0.786 | | `ThreeDrives` | two symmetric extension drives | ## Touchpoints Core modules + `FAMILIES` group/assert, crate root re-exports, Python/Node/WASM bindings via the candle-pattern macros (Node `index.d.ts`/`index.js` regenerated), the candle fuzz target (`// --- Harmonic Patterns ---` section), Python reference + `CANDLE_SCALAR` registry tests and the Node candle-scalar factory, README catalogue counter + banner cache-buster + family table row + family-count word, `docs/README.md` counter, and the changelog. ## Verification - `cargo test -p wickra-core --lib` — 2966 passed - `cargo test -p wickra-core --doc` — 335 passed - `cargo clippy --workspace --all-targets --all-features -- -D warnings` — clean - Node `npm run build && npm test` — 444 passed - Python `maturin develop --release` + `pytest` — 748 passed Every detector branch is unit-tested, including a bullish and a bearish match per pattern to cover both output arms, plus an out-of-ratio non-match. Fibonacci windows use standard harmonic-trading ranges with documented tolerance bands. |
||
|
|
995f119010 |
feat(patterns): add the Chart Patterns family (8 swing-based detectors) (#166)
## Summary Adds a new **Chart Patterns** indicator family (counter 351 → 359, families 21 → 22), the first half of the A4 roadmap item (the harmonic patterns follow in a second PR). All eight detectors are built on a shared, non-repainting swing-pivot tracker — the internal, **uncounted** `indicators::pattern_swing` module (declared `pub(crate) mod`, re-exported nowhere). Each consumes candles and emits the uniform pattern sign convention already used by the candlestick family — `+1.0` bullish / `-1.0` bearish / `0.0` otherwise, never `None`. They are parameter-free, baking the swing threshold (5%) and level tolerance (3%) in as documented constants, mirroring how candlestick patterns bake in their geometric thresholds. ## Detectors | Indicator | Signal | |-----------|--------| | `DoubleTopBottom` | twin-peak / twin-trough reversal | | `TripleTopBottom` | three matching extremes (stronger reversal) | | `HeadAndShoulders` | central head + matching shoulders + flat neckline (and inverse) | | `Triangle` | ascending (+1) / descending (-1) / symmetrical | | `Wedge` | rising wedge (-1) / falling wedge (+1) | | `FlagPennant` | shallow consolidation against a pole → continuation | | `RectangleRange` | flat support/resistance mean-reversion | | `CupAndHandle` | rounded base + shallow handle (and inverse) | ## Touchpoints Core modules + `FAMILIES` group and assert, crate root re-exports, Python/Node/WASM bindings via the candle-pattern macros (Node `index.d.ts`/`index.js` regenerated), the candle fuzz target, Python reference + `CANDLE_SCALAR` registry tests and the Node candle-scalar factory, README catalogue counter + banner cache-buster + family table row + family-count word, `docs/README.md` counter, and the changelog. ## Verification - `cargo test -p wickra-core --lib` — 2915 passed - `cargo test -p wickra-core --doc` — 335 passed - `cargo clippy --workspace --all-targets --all-features -- -D warnings` — clean - Node `npm run build && npm test` — 436 passed - Python `maturin develop --release` + `pytest` — 732 passed Every detector branch is unit-tested; multi-condition predicates were flattened to single-line precomputed booleans to keep patch coverage at 100%. |
||
|
|
3ab2d6ec2d |
feat(seasonality): add the Seasonality & Session family (12 indicators) (#161)
## Summary Adds the **Seasonality & Session** family — the first family that reads the wall-clock fields of `Candle::timestamp`. A new private `calendar` module decomposes an epoch-millisecond instant (shifted by a per-indicator `utc_offset_minutes`) into civil fields via Howard Hinnant's branch-light `civil_from_days` algorithm. Session / day / month rollovers are detected automatically, so callers never have to invoke `reset()` at a boundary. Indicator counter **339 → 351**; family count **20 → 21**. ## Indicators | Shape | Indicators | |-------|-----------| | Scalar (`f64`) | `SessionVwap`, `AverageDailyRange`, `OvernightGap`, `TurnOfMonth`, `SeasonalZScore` | | Struct | `SessionHighLow`, `SessionRange` (Asia/EU/US), `OvernightIntradayReturn` | | Profile (`Vec<f64>`) | `TimeOfDayReturnProfile`, `DayOfWeekProfile`, `IntradayVolatilityProfile`, `VolumeByTimeProfile` | ## Bindings The input is the **full** candle (`open, high, low, close, volume, timestamp`), not the `high/low/close` slice the value-indicator helper assumes, so the Python / Node / WASM bindings are custom full-candle implementations: - **Python** — `update((o,h,l,c,v,ts))`; `batch(open, high, low, close, volume, timestamp)` → `PyArray1` (scalar) / `PyArray2` (struct & profile), warmup rows `NaN`. - **Node** — `update(open, high, low, close, volume, timestamp)`; `batch(...)` → flat `Vec<f64>`; struct outputs as `#[napi(object)]` values. - **WASM** — `update` only (multi-input precedent); profiles as `Float64Array`, structs as camelCase objects, `timestamp` as `BigInt`. ## Verification - `wickra-core`: full per-branch unit tests, **100%** coverage target; 2852 lib tests + 334 doctests green. - `cargo clippy --workspace --all-targets --all-features -- -D warnings`: clean. - Node: 428 tests (dedicated `seasonality.test.js` streaming-vs-batch). - Python: full suite + dedicated `test_seasonality.py` streaming-vs-batch. - Counter check: mod-count == counted lib block == 351. |
||
|
|
c096943bdf |
feat(breadth): complete the Market Breadth family (14 indicators) (#157)
Completes expansion-roadmap block **A2 — Market Breadth**: the 14 indicators that remained after the `AdvanceDecline` bootstrap, all built on the existing `CrossSection` input. ## Indicators (all scalar `Indicator<Input = CrossSection, Output = f64>`) | Indicator | Reading | |-----------|---------| | `AdvanceDeclineRatio` | advancers / decliners | | `AdVolumeLine` | cumulative net advancing volume | | `McClellanOscillator` | 19/39 EMAs of ratio-adjusted net advances | | `McClellanSummationIndex` | running total of the oscillator | | `Trin` (Arms Index) | A/D ratio over up/down volume ratio | | `BreadthThrust` (Zweig) | SMA of the advancing-issues share | | `NewHighsNewLows` | new highs − new lows | | `HighLowIndex` | SMA of the record-high percent | | `PercentAboveMa` | % of the universe above its MA | | `UpDownVolumeRatio` | advancing / declining volume | | `BullishPercentIndex` | % on a point-and-figure buy signal | | `CumulativeVolumeIndex` | volume-normalised cumulative net advancing volume | | `AbsoluteBreadthIndex` | \|advancers − decliners\| | | `TickIndex` | instantaneous net advancers − decliners | ## Input model `AdVolumeLine` and `CumulativeVolumeIndex` are kept distinct (the latter normalises each tick's net advancing volume by total volume, so it stays comparable across volume regimes). `PercentAboveMa` and `BullishPercentIndex` need a per-symbol state signal that `Member` did not carry, so `Member` gains two additive flags (`above_ma`, `on_buy_signal`) via a new `Member::with_signals` constructor; the 4-arg `Member::new` leaves both cleared, so every existing caller and binding is unchanged. `CrossSection` gains volume / new-extreme / state aggregation helpers. ## Wiring Fully wired across the Rust core, the python/node/wasm bindings, the cross-section fuzz target, the README + docs indicator counters (325 → 339), and dedicated python/node streaming-vs-batch tests. `fmt` / `test --workspace --all-features` / `clippy --workspace -D warnings` / node build+test / pytest all green locally. |
||
|
|
a3a1ae4dba |
Add 10 pairwise stat-arb indicators to Price Statistics (#154)
Adds ten pairwise `(f64, f64)` indicators to the **Price Statistics** family, completing the A1 stat-arb expansion block.
## Indicators
**Scalar output:**
- **RollingCorrelation** — rolling Pearson correlation of period-over-period *returns* (distinct from level-based `PearsonCorrelation`).
- **RollingCovariance** — rolling covariance of returns.
- **OuHalfLife** — Ornstein–Uhlenbeck half-life of mean reversion of the spread `a − b`.
- **SpreadHurst** — Hurst exponent of the spread (variance-of-lagged-differences fit) for regime detection.
- **DistanceSsd** — Gatev sum-of-squared-deviations between two start-normalised series.
- **BetaNeutralSpread** — rolling OLS regression residual `a − (α + β·b)`.
- **VarianceRatio** — Lo–MacKinlay variance-ratio test on the spread (two params: `period`, `q`).
- **GrangerCausality** — F-statistic for whether `b` predicts `a` (two params: `period`, `lag`).
**Struct output (custom bindings):**
- **KalmanHedgeRatio** — dynamic hedge ratio via a Kalman filter → `{ hedgeRatio, intercept, spread }`.
- **SpreadBollingerBands** — Bollinger bands on the spread → `{ middle, upper, lower, percentB }`.
## Notes
- No new traits or input families: all use the native `Indicator<Input = (f64, f64)>` (precedent `Beta`, `Cointegration`).
- Adds `Error::InvalidParameter` for floating-point constructor parameters (Kalman `delta`/`observation_var`, `num_std`).
- Full Python/Node/WASM bindings; the two struct-output indicators are hand-written, the rest use the pair macros.
- Indicator count 315 → 325; README, family rows, `__init__`, fuzz target, and CHANGELOG updated.
## Verification
- `cargo test --workspace --all-features` — green (2676 core lib + 308 doc).
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` — clean.
- Node: `npm run build && npm test` — 410 passing (`index.d.ts`/`index.js` regenerated).
- Python: `pytest` — 684 passing.
|
||
|
|
53941b7b07 |
feat: add Market Breadth family with CrossSection input (#153)
## What Adds a new indicator input type and family for **market-breadth** analysis — indicators that aggregate the state of an entire universe of symbols at each tick, rather than a single instrument's price. This is the last open input-type on the expansion roadmap (S10) and unblocks the remaining breadth indicators (McClellan, TRIN, High-Low Index, ...). ## Core - **`CrossSection` input type** (`crates/wickra-core/src/cross_section.rs`) — one tick carrying the per-symbol state of the whole universe as a `Vec<Member>` + `timestamp`. Each `Member` precomputes a signed `change` (sign classifies advancing / declining / unchanged), a `volume`, and `new_high` / `new_low` extreme flags, so the breadth indicators stay stateless per tick. Both `Member` and `CrossSection` are `#[non_exhaustive]` for additive field growth. `CrossSection::new` validates the universe (non-empty, finite changes, finite non-negative volumes); `new_unchecked` skips validation for hot paths. `advancers()` / `decliners()` count by sign. - **`Error::InvalidCrossSection`** variant for the validation failures. - **`AdvanceDecline`** (`advance_decline.rs`) — the Advance/Decline Line: the running cumulative sum of net advancing-minus-declining issues. `Input = CrossSection`, `Output = f64`, ready after the first tick. - New **"Market Breadth"** `FAMILIES` group; indicator count **314 → 315**, family count nineteen → twenty. ## Bindings All custom (CrossSection is non-scalar, so no macros apply). The universe crosses each boundary as parallel arrays (`change`, `volume`, `new_high`, `new_low`): - **Python / Node** expose `update` + `batch` (one array group per tick). Node satisfies the completeness contract (`update`/`batch`/`reset`/`isReady`/`warmupPeriod`). - **WASM** exposes only `update` (the universe is ragged across ticks, matching the other multi-input wasm indicators) with numeric high/low flags. - Python `map_err` gains the new error arm; `__init__.py` gets a `# Market Breadth` section in both the import and `__all__` blocks. `index.d.ts` / `index.js` regenerated. ## Tests / Fuzz - Dedicated **streaming-vs-batch + reference-value + ragged-rejection** tests in Python (`test_new_indicators.py`) and Node (`indicators.test.js`) — kept out of the scalar/candle parametrize lists. - Rust unit tests cover every reject branch (empty / non-finite change / negative & non-finite volume) and every indicator branch. - New fuzz target `indicator_update_crosssection` drives `AdvanceDecline` over bounded ragged universes built with `new_unchecked`. ## Verify - `cargo fmt --all` clean - `cargo test -p wickra-core --lib` → 2593 passed; `--doc` → 298 passed - `cargo clippy --workspace --all-targets --all-features -- -D warnings` clean - `cd bindings/node && npm run build && npm test` → 398 passed - `maturin develop --release` + `pytest bindings/python/tests` → all passed - counter check: mod-count 315 == lib-block 315 |
||
|
|
9eb46f144a |
feat: TA-Lib parity — 19 standalone indicators (DM components, price transforms, ROC/LinReg/MACD/SAR variants, Hilbert outputs) (#148)
Closes the remaining TA-Lib function-name gap by shipping each missing or bundled-only function as a real, standalone, fully-covered indicator. 19 new indicators across 5 families; mod-count 295 -> 314. ### Trend & Directional — Directional Movement components - `PlusDm` (`PLUS_DM`), `MinusDm` (`MINUS_DM`) — Wilder-smoothed ±DM. - `PlusDi` (`PLUS_DI`), `MinusDi` (`MINUS_DI`) — `100·smoothed(±DM)/ATR`. - `Dx` (`DX`) — `100·|+DI−−DI|/(+DI+−DI)`. ### Price Statistics - `AvgPrice` (`AVGPRICE`) — `(O+H+L+C)/4`. - `MidPoint` (`MIDPOINT`) — `(max+min)/2` of a scalar series over N. - `MidPrice` (`MIDPRICE`) — `(highestHigh+lowestLow)/2` over N. - `LinRegIntercept` (`LINEARREG_INTERCEPT`) — OLS intercept. - `Tsf` (`TSF`) — time series forecast `a + b·period`. ### Momentum Oscillators - `Rocp` (`ROCP`), `Rocr` (`ROCR`), `Rocr100` (`ROCR100`) — ROC ratio forms. ### Trailing Stops - `SarExt` (`SAREXT`) — Parabolic SAR with start value, reversal offset, separate long/short acceleration, signed output. ### Trend & Directional — MACD variants - `MacdFix` (`MACDFIX`) — MACD fixed 12/26. - `MacdExt` (`MACDEXT`) — MACD with a selectable moving-average type per line (new public `MaType` enum: SMA/EMA/WMA/DEMA/TEMA/TRIMA). ### Ehlers / Cycle (DSP) — Hilbert transform outputs - `HtPhasor` (`HT_PHASOR`) — in-phase / quadrature components. - `HtDcPhase` (`HT_DCPHASE`) — dominant-cycle phase (degrees). - `HtTrendMode` (`HT_TRENDMODE`) — trend (1) vs cycle (0) classification. Each indicator ships the full chain: core + every-branch unit tests, Python / Node / WASM bindings, fuzz coverage, README counter + family rows, CHANGELOG. `cargo test`, doctests, `clippy -D warnings`, `npm test` and pytest all green locally; mod-count == lib-block == README counter (314), FAMILIES total 309. |
||
|
|
d4b3f9dbd1 |
feat: add Alt-Chart Bars (Renko, Kagi, Point & Figure) via a BarBuilder trait (#146)
Introduces a BarBuilder trait for price-driven chart constructors that emit a variable number of bars per candle (deliberately not Indicator). Adds Renko (box-size bricks, 2-box reversal), Kagi (reversal-amount segments) and Point & Figure (box-size X/O columns, N-box reversal) in a new Alt-Chart Bars family, with custom Python/Node/WASM bindings, a dedicated fuzz target, tests and docs. Indicator count 292 -> 295. |
||
|
|
f37eedd44e |
feat: add Volume Profile and TPO Profile to the market profile family (#145)
Volume Profile exposes the full per-bin volume histogram (price bounds plus raw distribution) that Value Area reduces to POC/VAH/VAL. TPO Profile is the volume-agnostic Time-Price-Opportunity letter count over a rolling window. Both candle-input, Vec-output, Market Profile family, with custom Python/Node/WASM bindings, fuzz, benches, tests and docs. Indicator count 290 -> 292. |
||
|
|
93097db482 |
feat: add Anchored RSI to the momentum oscillators family (#144)
Cumulative Relative Strength Index whose averaging begins at a runtime-chosen anchor bar (set_anchor), the momentum counterpart to Anchored VWAP. Scalar f64 input, 0..=100 output; wired through core, Python, Node and WASM bindings, fuzz, benches, tests and docs. Indicator count 289 -> 290. |
||
|
|
124efb4432 |
feat: TA-Lib candlestick patterns — tasuki-gap/unique-three-river/marubozu-pair/concealing-baby-swallow (part 9 of 9) (#141)
The final batch of the TA-Lib candlestick roadmap. Adds five patterns, each a streaming `Indicator<Input = Candle, Output = f64>` emitting the family's uniform `±1.0 / 0.0` sign convention, fully wired across the Rust core, Python / Node / WASM bindings, fuzz target and reference tests. - **Tasuki Gap** (`CDLTASUKIGAP`) — a 3-bar continuation: two same-coloured candles gap in the trend direction, then an opposite candle opens within the second body and closes back into the gap without filling it; upside +1, downside -1. - **Unique Three River** (`CDLUNIQUE3RIVER`) — a 3-bar bullish reversal: a long black candle, a black candle probing a new low with its body inside the first, then a small white candle held below it; bullish +1. - **Closing Marubozu** (`CDLCLOSINGMARUBOZU`) — a single long-bodied candle with no shadow on the close end; +1 (white, closes at the high) or -1 (black, closes at the low). - **Opening Marubozu** — a single long-bodied candle with no shadow on the open end; +1 (white, opens at the low) or -1 (black, opens at the high). No direct TA-Lib equivalent — completes the pair with the closing marubozu. - **Concealing Baby Swallow** (`CDLCONCEALBABYSWALL`) — a rare 4-bar bullish capitulation: two black marubozu, a black candle gapping down with an upper shadow into the second, then a large black candle engulfing it entirely; bullish +1. Body and shadow thresholds follow the geometric house style (fixed fractions of the bar range) rather than TA-Lib's rolling averages. Counter 284 → 289 (mod-count == lib counted block; FAMILIES total 279 → 284). Stacked on #140 (`feat/cdl-gap-methods`); base retargets to `main` as the stack merges down. |
||
|
|
4d0bc08efd |
feat: TA-Lib candlestick patterns — gap-three-methods/stalled/stick-sandwich/takuri (part 8 of 9) (#140)
Adds five TA-Lib candlestick patterns, each a streaming `Indicator<Input = Candle, Output = f64>` emitting the family's uniform `±1.0 / 0.0` sign convention, fully wired across the Rust core, Python / Node / WASM bindings, fuzz target and reference tests. - **Upside Gap Three Methods** (`CDLXSIDEGAP3METHODS`) — a 3-bar bullish continuation: two white candles gap up, then a black candle opens within the second body and closes within the first; bullish +1. - **Downside Gap Three Methods** (`CDLXSIDEGAP3METHODS`) — the bearish mirror: two black candles gap down, then a white candle opens within the second body and closes within the first; bearish -1. - **Stalled Pattern** (`CDLSTALLEDPATTERN`) — a 3-bar bearish reversal warning: two long white candles then a small white candle riding the shoulder, signalling the rally is stalling; bearish -1. - **Stick Sandwich** (`CDLSTICKSANDWICH`) — a 3-bar bullish reversal: two black candles closing at the same level sandwich a white candle, marking a support floor; bullish +1. - **Takuri** (`CDLTAKURI`) — a single-bar bullish reversal, a strict Dragonfly Doji with a negligible upper shadow and very long lower shadow; bullish +1. Body and shadow thresholds follow the geometric house style (fixed fractions of the bar range) rather than TA-Lib's rolling averages. Upside / Downside Gap Three Methods share the `CDLXSIDEGAP3METHODS` code, so the second carries a manual CHANGELOG entry (as with Rising / Falling Three Methods). Counter 279 → 284 (mod-count == lib counted block; FAMILIES total 274 → 279). Stacked on #139 (`feat/cdl-lines`); base retargets to `main` once the predecessor merges. |
||
|
|
c2c85c7ecf |
feat: TA-Lib candlestick patterns — matching-low/lines/three-methods (part 7 of 9) (#139)
Adds five TA-Lib candlestick patterns, all `Input = Candle`, `Output = f64` (`+1.0` bullish / `-1.0` bearish / `0.0` no pattern), wired across core, Python/Node/WASM bindings, fuzz, and tests. - **Matching Low** (`CDLMATCHINGLOW`) — 2-bar bullish reversal: two black candles in a decline share the same close, signalling selling pressure is exhausting; bullish +1. - **Long Line** (`CDLLONGLINE`) — a candle whose range beats a rolling average of recent ranges with a body-dominated range; bullish +1 (white) / bearish -1 (black). - **Short Line** (`CDLSHORTLINE`) — a compact candle whose range falls below the rolling average with a body-dominated range; bullish +1 (white) / bearish -1 (black). - **Rising Three Methods** (`CDLRISEFALL3METHODS`) — 5-bar bullish continuation: a long white candle, three small bars holding within its range, then a white breakout to new highs; bullish +1. - **Falling Three Methods** (`CDLRISEFALL3METHODS`) — the bearish mirror: a long black candle, three small bars within its range, then a black breakdown to new lows; bearish -1. Counter 274 → 279 (mod-count == lib counted block; FAMILIES total 269 → 274). Stacked on #138 (part 6 of 9); base retargets to `main` as the chain merges. |
||
|
|
04ae145126 | feat: TA-Lib candlestick patterns — separating/kicking/ladder/mat-hold (part 6 of 9) (#138) | ||
|
|
e4ca9c3f8f |
feat: TA-Lib candlestick patterns — hikkake-mod/pigeon/neck-lines (part 5 of 9) (#137)
* feat: add hikkake-modified, homing-pigeon and neck-line candlestick patterns Five patterns, all `Input = Candle`, `Output = f64`: - Modified Hikkake (CDLHIKKAKEMOD) — a close-confirmed Hikkake: an inside bar then a breakout that closes back inside the inside-bar range; bullish +1, bearish -1. - Homing Pigeon (CDLHOMINGPIGEON) — two black candles, the second a small body inside the first, a bullish reversal; +1. - On-Neck (CDLONNECK) — long black bar then a white bar closing at its low (the neckline), a bearish continuation; -1. - In-Neck (CDLINNECK) — long black bar then a white bar closing just into its body, a bearish continuation; -1. - Thrusting (CDLTHRUSTING) — long black bar then a white bar closing well into but below the midpoint of its body, a bearish continuation; -1. Counter 264 -> 269 (mod-count == lib counted block; FAMILIES total 259 -> 264). * chore: sync indicator count to 269 --------- Co-authored-by: wickra-bot <wickra-bot@users.noreply.github.com> |
||
|
|
d43bc9ddf3 |
feat: TA-Lib candlestick patterns — doji-star/gap/high-wave/hikkake (part 4 of 9) (#135)
* feat: add doji-star, gap, high-wave and hikkake candlestick patterns Five patterns, all `Input = Candle`, `Output = f64`: - Evening Doji Star (CDLEVENINGDOJISTAR) — bearish top reversal: long white bar, a doji gapping up, then a black bar closing deep into the first body; -1 (penetration configurable, default 0.3). - Morning Doji Star (CDLMORNINGDOJISTAR) — bullish bottom reversal mirror; +1. - Gap Side-by-Side White (CDLGAPSIDESIDEWHITE) — two similar white candles opening side by side after a gap, a continuation; gap up +1, gap down -1. - High-Wave (CDLHIGHWAVE) — a small body with very long shadows on both sides, an extreme indecision flag; +1 on detection. - Hikkake (CDLHIKKAKE) — an inside bar followed by a failed breakout (a trap); bullish +1, bearish -1. Counter 259 -> 264 (mod-count == lib counted block; FAMILIES total 254 -> 259). * chore: sync indicator count to 264 --------- Co-authored-by: wickra-bot <wickra-bot@users.noreply.github.com> |
||
|
|
244d754707 |
feat: TA-Lib candlestick patterns — Doji family (part 3 of 9) (#134)
* feat: add Doji-family candlestick patterns Five single-/two-bar Doji patterns, all `Input = Candle`, `Output = f64`: - Doji Star (CDLDOJISTAR) — a long body followed by a doji gapping away in the trend direction; bullish +1 (after a black bar), bearish -1 (after a white bar). - Dragonfly Doji (CDLDRAGONFLYDOJI) — a doji opening and closing at the high with a long lower shadow; bullish +1. - Gravestone Doji (CDLGRAVESTONEDOJI) — a doji opening and closing at the low with a long upper shadow; bearish -1. - Long-Legged Doji (CDLLONGLEGGEDDOJI) — a doji with long shadows on both sides; a non-directional indecision flag, +1 on detection. - Rickshaw Man (CDLRICKSHAWMAN) — a long-legged doji with the body centred in the range; a non-directional indecision flag, +1 on detection. Counter 254 -> 259 (mod-count == lib counted block; FAMILIES total 249 -> 254). * chore: sync indicator count to 259 --------- Co-authored-by: wickra-bot <wickra-bot@users.noreply.github.com> |
||
|
|
03ceac1f3b |
feat: TA-Lib candlestick patterns — abandoned/advance/belt/break/counter (part 2 of 9) (#132)
* feat: add Abandoned Baby candlestick pattern (CDLABANDONEDBABY) * feat: add Advance Block candlestick pattern (CDLADVANCEBLOCK) * feat: add Belt Hold candlestick pattern (CDLBELTHOLD) * feat: add Breakaway and Counterattack candlestick patterns (CDLBREAKAWAY, CDLCOUNTERATTACK) Breakaway is a 5-bar reversal: a trend gaps away on the second bar, drifts two more bars, then the fifth bar snaps back and closes inside the bar1/bar2 body gap (bullish +1, bearish -1). Counterattack is a 2-bar reversal where an opposite-coloured long second bar closes level with the first (the counterattack line; bullish +1, bearish -1). Also suppress libtest's spanless `large_stack_arrays` false positive in wickra-core test builds: the `#[test]` harness collects every test into a compiler-generated array of references that crosses clippy's 16 KB threshold once the suite passes ~2048 unit tests. The allow is scoped to `cfg(test)`, so library code is still linted for genuinely large stack arrays. * chore: sync indicator count to 254 --------- Co-authored-by: wickra-bot <wickra-bot@users.noreply.github.com> |
||
|
|
ad51dbc1a3 |
fix: keep docs/README indicator count in sync-about (#131)
* fix: keep docs/README indicator count in sync-about
The docs/README.md pointer prose names the indicator count
("**N indicators**") but was never part of the sync-about counter
pipeline, so it drifted to 214 while the real count (lib.rs) is 249.
Add docs/README.md to the PR-flow gate check, the patch sed, and the
fix-up commit so future count changes keep it in sync, and correct the
current stale value to 249.
* docs: fix stale Wiki reference in CONTRIBUTING layout table
The project-layout table still described docs/ as a "Pointer to the
project Wiki" even though the wiki was retired and the docs moved to
docs.wickra.org (wickra-lib/wickra-docs). Align the row with the
already-correct doc-site section further down the same file.
|
||
|
|
9309bf9d60 |
docs(P6.4): repoint all doc links from the GitHub wiki to docs.wickra.org (#86)
The documentation now lives in the wickra-lib/wickra-docs VitePress repo and
will deploy to docs.wickra.org. Rewrite every tracked, user-facing wiki link
in the main repo to the new canonical site:
- docs/README.md, CONTRIBUTING.md, PULL_REQUEST_TEMPLATE.md
- bindings/{node,python,wasm}/README.md, examples/wasm/README.md
- repo-metadata.toml: wiki_url/wiki_git -> docs_url/docs_git
Page paths map 1:1 to VitePress clean URLs (e.g. /wiki/Quickstart-Rust.md ->
docs.wickra.org/Quickstart-Rust). The sync-about.yml wiki-sync step is left
untouched on purpose: it stays until the docs site is live (tracked as P8.3).
The GitHub wiki itself is not deleted yet for the same reason.
|
||
|
|
62ab84c472 |
chore(migration): switch org to wickra-lib and maintainer email to wickra.lib@gmail.com (#59)
Introduce repo-metadata.toml as single source of truth for repo identity (org slug, maintainer email, canonical URLs) and add sync-metadata.yml workflow with a Python audit script that fails CI if any tracked file drifts back to pre-migration values. Bulk-replace across 24 tracked files: - kingchenc/wickra -> wickra-lib/wickra (URL segment) - kingchencp@gmail.com -> wickra.lib@gmail.com (maintainer email) - @kingchenc -> @wickra-lib (CODEOWNERS mention only) Person-name credits are preserved: LICENSE copyright holder, Cargo.toml authors handle, and CHANGELOG historical @kingchenc reference all remain unchanged. Crate / PyPI / npm package names also untouched. Merge this PR only after the kingchenc/wickra -> wickra-lib/wickra org transfer has happened on the GitHub side, otherwise all badges and repository links 404 until the transfer is performed. |
||
|
|
0f2ff9c3c7 |
chore(sync-about): count public indicator types, not module files (#70)
* chore(sync-about): count public indicator types, not module files
The sync-about workflow counted `mod xxx;` lines in
crates/wickra-core/src/indicators/mod.rs to derive the indicator count
that gets propagated to README, the GitHub About description, and the
wiki. That under-reported by one because `vwap.rs` exports two public
types — `Vwap` (cumulative) and `RollingVwap` (finite window) — from
the same module. The bindings reach both, so users see 214 indicators
even though there are only 213 source files.
Fix the count by parsing the canonical `pub use indicators::{ ... }`
block in lib.rs, dropping the `FAMILIES` constant and any `*Output`
companion structs, and counting the remaining public types. Pure-shell
implementation so the workflow doesn't grow a python dependency.
Sync README to the corrected count (213 -> 214) in the same commit so
the PR validates cleanly through the workflow's PR-flow.
* docs(bindings): sync per-binding READMEs and docs/ pointer to 214 / 16
The bindings/{node,python,wasm}/README.md files (which ship to
npm / PyPI / npm again) and docs/README.md (the pointer to the
wiki) all carried the stale '71 streaming-first indicators across
eight families' header from before the family expansion. Pull the
canonical 16-family table out of the main README into all three
binding READMEs and update docs/README.md to list every family by
name, so a user landing on PyPI / npm sees the current catalogue
shape.
|
||
|
|
4aec5d544c |
docs(wiki): migrate documentation out of repo into GitHub Wiki
The 84 markdown files under docs/wiki/ are now published to the project's GitHub Wiki at https://github.com/kingchenc/wickra/wiki — a separate git repository (https://github.com/kingchenc/wickra.wiki.git) that GitHub hosts natively with its own UI, search and history. The flat layout that the GitHub Wiki requires has been generated, all internal cross-links rewritten, and a _Sidebar.md groups the 71 indicators by their canonical 8 families. Effects: - docs/wiki/ is removed from the main repo (-84 files). docs/README.md now just points readers at the Wiki. - PR template + CONTRIBUTING text updated to point at the Wiki instead of the in-repo path. The Wiki repo is separately cloneable and editable via the GitHub web UI. - examples/wasm/README.md cross-link fixed to use the Wiki URL. - The (still in-repo) CHANGELOG keeps its historical references to docs/wiki/ paths — those describe what the tree looked like at past releases and stay accurate as history. - README.md, license, all source unaffected. The Wiki itself ships with _Sidebar.md / _Footer.md generated from the 8-families taxonomy and 503/503 cross-links resolved. |