Commit Graph
5 Commits
Author SHA1 Message Date
kingchenc d37fbd10f6 feat(frama): add Fractal Adaptive Moving Average
Ehlers' FRAMA adapts its smoothing constant to the fractal dimension of
the recent window: tight tracking in trends, heavy smoothing in chop.
Uses the close-only variant where max/min over each window half drive
the dimension estimate. Period must be even (default 16).

Reference: Ehlers, Fractal Adaptive Moving Average, 2005.

Touchpoints:
- crates/wickra-core: frama.rs + mod.rs + lib.rs re-export
- bindings/python: PyFrama + __init__.py + test_new_indicators +
  test_known_values reference (constant series + uptrend tracking)
- bindings/node: FramaNode (scalar macro) + index.d.ts/index.js +
  indicators.test.js factory + reference value
- bindings/wasm: wasm_scalar_indicator! macro
- fuzz: indicator_update target covers Frama(16)
- crates/wickra/benches: bench_scalar entry
- README + CHANGELOG: Moving Averages row + Unreleased entry
2026-05-24 12:31:34 +02:00
kingchenc 3287146f44 feat(mcginley): add McGinley Dynamic moving average
John McGinley's self-adjusting moving average with the recurrence
MD + (price - MD) / (0.6 * period * (price / MD)^4). Speeds up when
price falls below the indicator and damps when price runs above the
indicator. Seeded with the simple average of the first period inputs.

Reference: McGinley, Technical Analysis of Stocks & Commodities, 1990.

Touchpoints:
- crates/wickra-core: mcginley_dynamic.rs + mod.rs + lib.rs re-export
- bindings/python: PyMcGinleyDynamic + __init__.py + test_new_indicators
  + test_known_values reference
- bindings/node: McGinleyDynamicNode (scalar macro) + index.d.ts/index.js
  + indicators.test.js factory + reference value
- bindings/wasm: wasm_scalar_indicator! macro
- fuzz: indicator_update target covers McGinleyDynamic(10)
- crates/wickra/benches: bench_scalar entry
- README + CHANGELOG: Moving Averages row + Unreleased entry
2026-05-24 12:26:08 +02:00
kingchenc 2454d7cf92 feat(alma): add Arnaud Legoux Moving Average
Gaussian-weighted moving average with configurable centre (offset in
[0, 1]) and kernel width (sigma > 0). Pre-computes normalised weights
at construction so each update is a single rolling window dot product.

Reference: Arnaud Legoux and Dimitrios Kouzis-Loukas, 2009.

Touchpoints:
- crates/wickra-core: alma.rs + mod.rs + lib.rs re-export
- bindings/python: PyAlma + __init__.py + test_new_indicators +
  test_known_values reference
- bindings/node: AlmaNode + index.d.ts/index.js + indicators.test.js
  factory + reference value
- bindings/wasm: wasm_scalar_indicator! macro
- fuzz: indicator_update target covers ALMA(9, 0.85, 6.0)
- crates/wickra/benches: bench_scalar entry
- README + CHANGELOG: Moving Averages row + Unreleased entry
2026-05-24 12:21:18 +02:00
kingchenc b003321562 test(fuzz): cover every indicator, scalar and candle inputs (R9)
The fuzz suite previously covered only `Rsi(14)` and `Ema(20)` — 2 of
71 indicators, no OHLCV coverage at all. Audit finding R9 asked for
ATR/ADX/Stochastic/PSAR as a minimum; this commit goes further and
brings every indicator under fuzz.

- `indicator_update` (rewritten): drives every scalar-input indicator
  through one streaming pass + one batch call per iteration. Covers
  SMA, EMA, WMA, RSI, DEMA, TEMA, HMA, ROC, TRIX, SMMA, TRIMA, ZLEMA,
  KAMA, T3, MOM, CMO, TSI, PMO, StochRSI, DPO, PPO, Coppock, StdDev,
  UlcerIndex, HistoricalVolatility, LinearRegression, LinRegSlope,
  LinRegAngle, VHF, ZScore, MACD, BollingerBands. A `drive` helper
  marked `#[inline(never)]` keeps each indicator on its own panic
  backtrace frame.

- `indicator_update_candle` (new): chunks the fuzz `f64` stream into
  `[open, high, low, close, volume]` tuples, builds candles via
  `Candle::new` (skipping ones that fail OHLCV validation — that path
  is fuzz-tested separately), then drives every candle-input indicator
  through streaming + batch. Covers ATR, NATR, TrueRange,
  ChaikinVolatility, Keltner, Donchian, PSAR, SuperTrend,
  ChandelierExit, ChandeKrollStop, ATRTrailingStop, ADX, Aroon,
  AroonOscillator, Vortex, MassIndex, ChoppinessIndex, CCI, WilliamsR,
  AwesomeOscillator, AcceleratorOscillator, UltimateOscillator,
  BalanceOfPower, OBV, MFI, VWAP, RollingVWAP, VWMA, ADL, VPT, CMF,
  ChaikinOscillator, ForceIndex, EaseOfMovement, TypicalPrice,
  MedianPrice, WeightedClose, Stochastic.

- `fuzz/Cargo.toml` registers the new target; `fuzz/README.md`
  describes both expanded targets.

- A `fuzz-smoke` CI job runs each of the five targets for 30 s on
  every push and pull-request — enough to catch a regression in the
  harness without slowing CI to a crawl. Long fuzz campaigns belong
  on dedicated infrastructure with persistent corpora.
2026-05-23 10:33:05 +02:00
kingchenc 78c31d1bed E16: add a cargo-fuzz harness
The repository had no fuzzing setup despite several natural targets —
the CSV parser, the Binance envelope deserializer, and the stateful
indicator/aggregator update paths.

Add a fuzz/ cargo-fuzz crate (detached from the workspace via its own
[workspace] table and the parent's exclude) with four targets:

- csv_reader      — CandleReader over arbitrary bytes
- binance_envelope — RawWsEnvelope deserialization from arbitrary strings
- indicator_update — RSI/EMA streaming + batch over arbitrary f64 series
- tick_aggregator — TickAggregator over arbitrary tick triples

Each target asserts the no-panic contract: malformed input must surface
as an Err. fuzz/README.md documents running them (nightly + cargo-fuzz).
2026-05-22 16:44:19 +02:00