* 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
* 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
* 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
* feat(vidya): add Variable Index Dynamic Average
Chande's VIDYA — an EMA whose alpha scales with |CMO(cmo_period)| / 100.
Strong directional momentum lifts the smoothing constant toward the
EMA-of-period rate; flat or choppy windows shrink it toward zero so
VIDYA coasts on its previous value. Two parameters: period (14) and
cmo_period (9). Reuses the existing wickra-core Cmo internally.
Reference: Chande, Stocks & Commodities, 1992.
Also fixes a silent gap from d37fbd1 (feat(frama)): the PyFrama Python
class wrapper and its add_class registration were dropped because the
two edits hit "File has not been read yet" errors that scrolled past
in a batch. Adds them here alongside VIDYA's bindings.
Touchpoints (VIDYA): vidya.rs + mod.rs + lib.rs re-export, PyVidya +
__init__.py + test_new_indicators + test_known_values reference,
VidyaNode (manual two-param binding) + index.d.ts/index.js +
indicators.test.js factory + reference, wasm_scalar_indicator! macro,
fuzz target, bench, README + CHANGELOG.
* feat(jma): add Jurik Moving Average
Three-stage filter reconstruction of Mark Jurik's adaptive MA (the
algorithm is proprietary; this is the form used by most open-source
ports since the 1999 TASC article). Parameters: period (14), phase in
[-100, 100] (0), power in 1..=4 (2). State is seeded by setting
e0 = JMA = first input so a constant input stream is reproduced exactly.
Touchpoints: jma.rs + mod.rs + lib.rs re-export, PyJma + __init__.py +
test_new_indicators + test_known_values reference, JmaNode (manual
three-param binding) + index.d.ts/index.js + indicators.test.js factory
+ reference, wasm_scalar_indicator! macro, fuzz target, bench, README +
CHANGELOG.
* feat(alligator): add Bill Williams Alligator
Three SMMA lines (Jaw / Teeth / Lips) over the median price
(high + low) / 2 with default periods 13 / 8 / 5. Multi-output
indicator returning AlligatorOutput { jaw, teeth, lips }. The
original chart variant shifts each line forward for display; we
publish the unshifted SMMA values and leave the visual shift to
the consumer.
Reference: Bill Williams, Trading Chaos, 1995.
Touchpoints: alligator.rs + mod.rs + lib.rs re-export, PyAlligator
(Candle input, returns 3-tuple, ndarray (n, 3) batch) + __init__.py
+ test_new_indicators + test_known_values reference, AlligatorNode +
AlligatorValue + index.d.ts/index.js + indicators.test.js multi
factory + reference, WasmAlligator (manual JsValue object) +
candle-fuzz target + README + CHANGELOG.
* feat(evwma): add Elastic Volume-Weighted Moving Average
Christian P. Fries' elastic recurrence where the smoothing weight is the
bar's volume relative to the running window total:
V_sum_t = sum of volumes over the last period candles
EVWMA_t = ((V_sum_t - v_t) * EVWMA_{t-1} + v_t * close_t) / V_sum_t
A bar whose volume is small barely moves the average; a bar that
dominates the window pulls it strongly toward that bar's close. Seeded
with the close of the first full window; holds its previous value if
the entire window has zero volume.
Reference: Fries, Wilmott Magazine, 2001.
Touchpoints: evwma.rs + mod.rs + lib.rs re-export, PyEvwma (close +
volume batch) + __init__.py + test_new_indicators CANDLE_SCALAR +
test_known_values reference, EvwmaNode + index.d.ts/index.js +
indicators.test.js candleScalar factory + reference, WasmEvwma,
candle-fuzz target + README + CHANGELOG.
* ci: Force local wheel install in Python jobs
Use --no-index --no-deps so the Python matrix installs the freshly
built wheel from dist/ and never falls back to PyPI. Previously pip
sometimes picked the released 0.2.x wheel on macOS / Windows when its
platform tag was a wider match than the local build, which made the
job test the released package and miss any new symbols added in the
PR (e.g. AttributeError: module 'wickra' has no attribute 'ALMA').
numpy is already installed by the preceding pip step, so --no-deps
is safe.
25 KiB
25 KiB
Changelog
All notable changes to Wickra are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
Added
- Family 01 — Moving Averages.
ALMA(Arnaud Legoux Moving Average): Gaussian-weighted moving average with configurable centre (offsetin[0, 1]) and kernel width (sigma > 0). Community-standard defaults(period = 9, offset = 0.85, sigma = 6.0)available viaAlma::classic(). Exposed in all four bindings (Rust, Python, Node, WASM). - Family 01 — Moving Averages.
EVWMA(Elastic Volume-Weighted Moving Average, Fries 2001): an "elastic" recurrence whose smoothing weight is the bar's volume relative to the running window-volume. Candle input (uses close + volume), single parameterperiod(default 20). Holds its previous value if the entire window has zero volume. Exposed in all four bindings. - Family 01 — Moving Averages.
Alligator(Bill Williams): three SMMA lines (Jaw / Teeth / Lips) of the median price(high + low) / 2with default periods 13 / 8 / 5. Multi-output indicator emittingAlligatorOutput { jaw, teeth, lips }. Visual chart shift is left to the consumer. Exposed in all four bindings. - Family 01 — Moving Averages.
JMA(Jurik Moving Average): three-stage filter reconstruction of Mark Jurik's adaptive MA. Three parameters:period(14),phasein[-100, 100](0),powerin1..=4(2). State is seeded to the first input so a constant series is reproduced exactly. Exposed in all four bindings. - Family 01 — Moving Averages.
VIDYA(Variable Index Dynamic Average, Chande 1992): EMA whose smoothing factor is scaled by the absolute Chande Momentum Oscillator. Two parametersperiodandcmo_period(defaults 14 / 9). Exposed in all four bindings. - Family 01 — Moving Averages.
FRAMA(Fractal Adaptive Moving Average, Ehlers 2005): adapts its smoothing constant to the fractal dimension of the recent window — fast in trends, slow in chop. Single parameterperiod(must be even, default 16). Exposed in all four bindings. - Family 01 — Moving Averages.
McGinleyDynamic: John McGinley's self-adjusting MA. Single parameterperiod; the recurrenceMD + (price - MD) / (0.6 * period * (price / MD)^4)speeds up when price falls below the indicator and damps when price runs above. Seeded with the simple average of the firstperiodinputs. Exposed in all four bindings.
0.2.7 - 2026-05-24
Added
- Windows ARM64 is back. npm Support unblocked the
wickra-win32-arm64-msvcsub-package name (same pathwickra-win32-x64-msvctook through 0.1.4) and transferred write access to @kingchenc. 0.2.7 ships the binding foraarch64-pc-windows-msvcalongside the existing five platforms: thenapi.triples.additionalentry, theoptionalDependenciespin, thebindings/node/npm/win32-arm64-msvc/sub-package and thewindows-11-armrow of the release.yml node-build matrix are all restored from8aa74cb.npm install wickraon Windows ARM64 now resolves to a native build instead of failing the loader's optional-dep lookup. PyPI'swin_arm64wheel was unaffected and carries through as before.
Changed
- Benchmark CPU renamed. The "Reproduced on" line in every README listed an AMD Ryzen 9 7950X3D; the canonical machine is actually a Ryzen 9 9950X. Speedup ratios in the tables are unchanged (they're relative across libraries on the same machine), only the labelling is corrected. The performance-regression issue template's CPU example was updated for consistency.
0.2.6 - 2026-05-24
Fixed
- docs.rs build. Rust 1.92 removed the
doc_auto_cfgfeature gate and folded it back intodoc_cfg(rust-lang/rust#138907). docs.rs builds against the latest nightly and sets--cfg docsrs, so every published 0.2.x failed with E0557 on the#![cfg_attr(docsrs, feature(doc_auto_cfg))]line at the top ofwickra,wickra-core, andwickra-data. GitHub CI didn't see this — stable rustc never enables thedocsrscfg. The three library crates now gate ondoc_cfg(same intent, same rendered output on docs.rs, builds again on nightly).
Changed
- README — Wickra is now the top row of every comparison table. The "Why Wickra exists" library matrix and the per-indicator benchmark tables previously placed Wickra at the bottom; a reader landing on the README is here to compare against Wickra, so the pivot row belongs at the top with a ★ marker. Same column data, same winner annotations — only row order changed. Mirrored across the umbrella README and every binding README so crates.io / PyPI / npm landing pages stay in sync.
0.2.5 - 2026-05-24
Added
BinanceConfigplusBinanceKlineStream::connect_with_config(symbols, interval, config)inwickra-data'slive::binancemodule.connect()keeps its previous signature and now forwards to the new entry-point with the defaults, so the public API is backwards-compatible. The config lets callers point the stream at Binance Testnet (wss://testnet.binance.vision) or tune the read timeout, reconnect attempt count, initial / capped backoff and frame size limits without rewriting the connector.- README Disclaimer section clarifying that Wickra is an indicator toolkit (not a trading system) and that any production-trading use is at the caller's own risk. The legal terms in LICENSE are unchanged.
Changed
BinanceKlineStream::next_eventnow writes the Pong reply to a serverPingon a best-effort basis. A failed write means the connection is already dead, so the existing timeout / read-error reconnect arm one loop iteration later picks it up — the previous explicit reconnect on Pong-write failure is gone. Observable behaviour is unchanged for every healthy connection.
0.2.1 - 2026-05-23
Changed
- MSRV bumped. Workspace minimum supported Rust version is now 1.86
(was 1.75) and the Node binding (
wickra-node) is now 1.88 (was 1.77). The bumps are driven by transitive-dependency floors that were lifted in recent updates:criterion 0.8.2(the bench dev-dep) requires Rust 1.86, andnapi-build >= 2.3.2requires Rust 1.88. Pinning those deps to the older versions would have frozen us out of future security fixes from those upstreams, so lifting the MSRV is the cleaner path for a young 0.x library. Downstream consumers on older Rust toolchains can stay on Wickra 0.2.0. - Bumped the bench dev-dep
criterionfrom 0.5 to 0.8 and migratedbindings/wickra/benches/indicators.rsfrom the deprecatedcriterion::black_boxre-export to the stablestd::hint::black_box. - Bumped
tokio-tungstenitefrom 0.24 to 0.29.WebSocketConfigbecame#[non_exhaustive]upstream, so the struct-literal construction incrates/wickra-data/src/live/binance.rsis rewritten to the builder-styleWebSocketConfig::default().max_message_size(..).max_frame_size(..). Same caps, same semantics, same default carry-over. - Bumped every committed CI/release GitHub Action to its latest pinned
SHA:
actions/checkout4 → 6,actions/setup-node4 → 6,actions/setup-python5 → 6,actions/upload-artifact4 → 7,actions/download-artifact4 → 8,softprops/action-gh-release2 → 3,codecov/codecov-action5 → 6,taiki-e/install-actionpatch.
Fixed
tick_aggregatorgap-fill no longer allocates an unbounded number of placeholder candles. The newMAX_GAP_FILL_CANDLES = 1_000_000cap surfaces an adversarial timestamp jump (e.g. a clock-glitch tick years in the future) asError::Malformedinstead of an OOM panic. Found by the newtick_aggregatorfuzz target.HistoricalVolatility::geometric_series_yields_zeronow uses an1e-6tolerance instead of1e-9. The mathematical result on a perfectly geometric price series is exactly zero, but the underlying1.01_f64.powi(i)+ log-return + std-dev cascade accumulates platform-sensitive FP drift on the order of 1e-7 on x86_64 Linux and macOS. The widened tolerance stays four decimal places below any realistic annualised volatility value while absorbing the drift across every supported platform.- Replaced every
(high + low) / 2.0test-helper and three real call sites (Ohlcv::median_price,Donchian.middle,EaseOfMovement.mid,SuperTrend.hl2) withf64::midpoint(high, low). The change satisfies clippy 1.95's newmanual_midpointlint without affecting values (f64::midpointmatches the naive average to better than 1 ULP for the inputs used here). - Replaced
i.is_multiple_of(2)(unstable on Rust 1.85) withi % 2 == 0in the SMA / Bollinger long-stream-drift tests so the workspace MSRV job builds cleanly on Rust 1.86. - The
Compile examplesCI step now invokescargo build -p wickra-examples --binsinstead of the now-deletedcargo build -p wickra --example backtest/-p wickra-data --example live_binance(the Z5 reorganisation moved every runnable example into the dedicatedwickra-examplescrate, but the CI step had not been updated). - The
Fuzz (smoke)CI job installscargo-fuzzfrom a prebuilt binary viataiki-e/install-actioninstead ofcargo install cargo-fuzz. The source install resolved againstrustix 0.36.5, which uses internal#[rustc_*]attributes the current nightly compiler rejects. - The fuzz targets now build with an explicit
--target x86_64-unknown-linux-gnu; cargo-fuzz was defaulting tox86_64-unknown-linux-musl, which is not installed on the standard GitHub-hosted Ubuntu runner.
Removed
wickra-win32-arm64-msvcis temporarily omitted from this release. The npm spam-detection filter blocks the first publish of this brand-new package name (same situation that affectedwickra-win32-x64-msvcthrough 0.1.4 until npm Support unblocked it). A support ticket is open; once the new name is unblocked theaarch64-pc-windows-msvctriple will be restored inbindings/node/package.json(napi.triples.additional+optionalDependencies), in therelease.ymlnode-buildmatrix, and as a freshbindings/node/npm/win32-arm64-msvc/template. Until then,npm install wickra@0.2.1on Windows ARM64 will surface the loader's standardCannot find module 'wickra-win32-arm64-msvc'error; every other platform (Linux x64 / Linux ARM64 / macOS x64 / macOS ARM64 / Windows x64) ships normally. The PyPI wheel for Windows ARM64 is unaffected and still published.
0.2.0 - 2026-05-23
Fixed
HistoricalVolatility::updateno longer substitutes a0.0log-return on non-positive prices (audit finding R13). Negative or zero prices are semantically invalid for a log-return calculation; silently treating them as "no movement" underreported realised volatility. They are now skipped — the previous valid value is returned and the indicator's state (prev_price, window, sums) is left untouched — matching how every other indicator handles invalid inputs.Tick::newnow returns the newError::InvalidTickvariant for negative volume instead ofError::InvalidCandle(audit finding R14). A tick is not a candle, and downstream tick-stream pipelines should be able to match on a semantically-correct error. The Python binding'smap_errwas extended to forward the new variant as aValueError; the Node and WASM bindings format viaError::to_string()and pick the new variant up automatically.Psar::is_readynow matches the convention shared by every other indicator:is_ready() == trueiff a real value has been produced (audit finding R6). The previous implementation returnedself.initialised, which flipped totrueafter the seed candle even though the seed candle itself returnsNone. A streaming consumer that wroteif ind.is_ready() { use(ind.update(c)?) }would hit an unexpectedNoneon the first post-seed update. The fix introduces ahas_emittedgate set when the firstSomevalue is returned.Psar::resetnow restores the compute fields (prev_high,prev_low,sar,ep) tof64::NANsentinels instead of0.0(audit Opus-Bonus 1). The fields are gated byinitialisedtoday, so the0.0sentinel never leaked into output — but a future refactor that read them pre-init would have silently treated0.0as a real price. Adebug_assert!at the read site makes the invariant explicit.
Changed
SmaandBollingerBandsnow reseed their incrementalsum(andsum_sqfor Bollinger) from the live window every16 · periodfinite updates, capping floating-point drift on long-running streams (audit findings R7 and L2-Rust). Previously the incremental single-subtractsum -= oldcould accumulate catastrophic-cancellation error on streams with alternating large/small magnitudes; the misleadingsma.rscomment that claimed the drift was already bounded "by recomputing the sum after each pop" is replaced with an accurate description of the new reseed strategy. Amortised cost stays at O(1) (O(period)work amortised overO(period)updates), values are bit-identical on inputs that did not drift to begin with, and two newlong_stream_drift_stays_boundedtests stress the recompute by alternating1e9/1.0(SMA) and1e6/1.0(Bollinger) for several recompute cycles and verify the reported values track a fresh from-scratch computation over the live window.LinearRegression,LinRegSlopeandLinRegAngle(via composition overLinRegSlope) now run their rolling ordinary-least-squares fit incrementally in O(1) per update (audit finding R2). Previously every tick refit the line from scratch in O(period). The OLS denominators (ΣxandΣxx) depend only onperiod, so they were already precomputed; this release adds runningΣyandΣxyaccumulators and slides them in closed form via the identitynew_Σxy = old_Σxy − old_Σy + popped_y₀(thenΣxy += (n − 1) · new_valueandΣy += new_value). New per-bar equivalence tests compare the O(1) output against a fresh O(n) refit on noisy ramps, step functions, and constants — values agree to within 1e-9.- Fuzz suite expanded from 2 indicators to the full catalogue (audit finding
R9). The existing
indicator_updatetarget now exercises every scalar-input indicator (~33 classes including MACD and Bollinger Bands); a newindicator_update_candletarget exercises every candle-input indicator (~37 classes, including ATR, ADX, Stochastic, PSAR, Keltner, SuperTrend, ChandelierExit, AwesomeOscillator, OBV, MFI, VWAP, RollingVWAP, and the rest of the volume / volatility / trailing-stop / price-statistics families). Each iteration sweeps every indicator through both the streamingupdateloop and a fullbatchcall so any state-mutation bug surfaces on either path. CI gains afuzz-smokejob that runs each of the five targets for 30 s on every push and pull-request. UlcerIndex::updatenow tracks the trailing maximum with a monotonically- decreasing deque of(index, price)pairs instead of scanning the whole trailing window on every tick. The indicator now honours theIndicatortrait's O(1)-per-tick contract; values and warmup semantics are unchanged (verified by a new adversarial-input test that compares the deque output bar-by-bar against a naive O(n) trailing-max scan on strictly increasing, strictly decreasing, constant, and sawtooth inputs). The doc comment onwarmup_period()is also corrected: the two windows overlap by one bar, so the formula is2 * period - 1.
Added
RollingVWAPis now exposed in Python, Node and WASM under that name (previously the rolling-window VWAP existed only in the Rust core, even though the README's volume-family table already advertisedVWAP (cumulative + rolling)). All four bindings now ship the same cumulativeVWAPplus the finite-windowRollingVWAP(period). The wiki pageIndicator-Vwap.mdadds Python, Node and WASM examples and drops the "Rust-only" caveat.- WASM binding now exposes the streaming
update()method on every candle-input indicator:Adx,WilliamsR,Cci,Mfi,Psar,Keltner,Donchian,Vwap,AwesomeOscillator,Aroon,Stochastic, andObv. Multi-output indicators (Adx,Keltner,Donchian,Aroon,Stochastic) return a named JS object ({ plusDi, minusDi, adx },{ upper, middle, lower },{ up, down },{ k, d }) once warm, ornullduring warmup — matching the existingSuperTrendconvention. Each class also gainsreset(),isReady()andwarmupPeriod(), bringing the WASM surface to full parity with Python and Node so browser-side streaming code no longer has to replaybatch()on every tick.WasmKamagains the previously missingwarmupPeriod(). - New
wasm-bindgenintegration test exercisesupdate == batchplus the full lifecycle (reset/isReady/warmupPeriod) for all twelve newly wired classes against a deterministic 40-bar synthetic OHLCV stream.
Security
- Upgrade
pyo3(0.22 → 0.28) andnumpy(0.22 → 0.28) in the Python binding. Fixes RUSTSEC-2025-0020 — a buffer overflow inPyString::from_objectthat affected the published Python wheels. Thecargo-denyignore entry that previously suppressed the advisory has been removed;cargo deny checkis now clean without suppression. Migratedinto_pyarray_boundtointo_pyarray,downcast::<PyDict>tocast::<PyDict>, and opted every#[pyclass]out of the deprecated automaticFromPyObjectderive viaskip_from_py_object.
Added
- 46 new technical indicators, taking the library from 25 to 71 and
reorganising the catalogue into eight families, each with at least five
members. Every indicator is implemented once in the Rust core and wired
through the Python, Node and WASM bindings, with reference-value tests and a
dedicated wiki page:
- Moving Averages:
Smma,Trima,Zlema,T3,Vwma. - Momentum Oscillators:
Mom,Cmo,Tsi,Pmo,StochRsi,UltimateOscillator. - Trend & Directional:
AroonOscillator,Vortex,MassIndex,ChoppinessIndex,VerticalHorizontalFilter. - Price Oscillators:
Ppo,Dpo,Coppock,AcceleratorOscillator,BalanceOfPower. - Volatility & Bands:
Natr,StdDev,UlcerIndex,HistoricalVolatility,BollingerBandwidth,PercentB,TrueRange,ChaikinVolatility. - Trailing Stops:
SuperTrend,ChandelierExit,ChandeKrollStop,AtrTrailingStop. - Volume:
Adl,VolumePriceTrend,ChaikinMoneyFlow,ChaikinOscillator,ForceIndex,EaseOfMovement. - Price Statistics:
TypicalPrice,MedianPrice,WeightedClose,LinearRegression,LinRegSlope,ZScore,LinRegAngle.
- Moving Averages:
TickAggregator::with_gap_fill— opt-in mode that emits a flat placeholder candle for every empty bucket between two ticks, keeping the candle series evenly spaced for downstream indicators.- CSV reader: a leading UTF-8 byte-order mark is stripped, fields are trimmed, and the header is validated against the required OHLCV columns.
- CI: an
msrvjob that builds and tests the workspace on Rust 1.75 and the node binding on Rust 1.77. - Community health files:
CONTRIBUTING.md,SECURITY.md,CODE_OF_CONDUCT.md, issue / pull-request templates,CODEOWNERS, and a Dependabot configuration. - Seven example OHLCV datasets under
examples/data/, one per timeframe (1m / 5m / 15m / 1h / 12h / 1d / 1month), holding real BTCUSDT spot klines, alongside thefetch_btcusdtexample that regenerates them from the Binance REST API. Timeframe::minutes,Timeframe::hoursandTimeframe::daysconvenience constructors, each building on seconds with a checked-multiplication overflow guard.
Changed
- The indicator wiki is reorganised into eight family folders under
docs/wiki/indicators/(moving-averages/,momentum-oscillators/,trend-directional/,price-oscillators/,volatility-bands/,trailing-stops/,volume/,price-statistics/);Indicators-Overview.md,Home.mdand the README indicator table follow the same eight families. TickAggregator::pushreturnsResult<Vec<Candle>>(wasResult<Option<Candle>>) so a single tick can yield a closed bar plus gap fillers.Resampler::pushreturnsResult<Option<Candle>>: a candle in a bucket earlier than the open bar is now rejected as out of order.- Aggregated candles are finalised through the validating
Candle::new, so a volume that overflows to a non-finite value is surfaced as an error instead of producing a poisoned candle. - All GitHub Actions are pinned to commit SHAs; the four publish jobs run in a
protected
releaseenvironment. - The indicator benchmarks (
crates/wickra/benches/indicators.rs) now run against the checked-in real BTCUSDT 1-minute dataset instead of a synthetic price series. - Every language's examples now live under a uniform
examples/<lang>/tree: Rust moved into a newexamples/rust/workspace member crate (wickra-examples, run viacargo run -p wickra-examples --bin <name>), Node intoexamples/node/with its ownpackage.jsonlinkingwickraviafile:../../bindings/node, and the WASM browser demos intoexamples/wasm/. The bundled BTCUSDT datasets move alongside them atexamples/data/. Six new examples close the cross-language parity matrix: streaming demos for Python and Rust; multi-timeframe and parallel-assets demos for both Rust and Node. - Cross-language data-generator parity:
examples/python/fetch_btcusdt.py(stdlib only:urllib+json+csv) andexamples/node/fetch_btcusdt.js(Node 18+ built-infetch) mirror the Rustfetch_btcusdtbinary — byte-for-byte identical CSV output on the same Binance snapshot. - Four additional WebAssembly browser demos under
examples/wasm/alongside the originalindex.html:backtest.html(fetch + basket of indicators),live_trading.html(browser-nativeWebSocketto Binance),multi_timeframe.html(in-page resample) andparallel_assets.html+parallel_worker.js(module-Worker pool with serial-vs-parallel speedup). The cross-language matrix is now closed for every cell where the pattern makes sense. - Three new wiki pages:
TA-Lib-Migration.md(full mapping table fromtalib.X(...)calls to Wickra),Cookbook.md(seven concrete strategy recipes — RSI mean reversion, MACD crossover, Bollinger breakout, ADX-gated trend, multi-timeframe confirmation, SuperTrend, chained indicators) andFAQ.md. All three linked fromHome.md.
Fixed
Timeframe::floorno longer overflows for timestamps neari64::MIN.- The aggregator rejects same-bucket ticks that arrive out of order instead of silently overwriting the bar's close with a stale price.
- The Binance live stream reconnects with exponential backoff, skips non-kline frames, applies a read timeout and message-size limits, and tracks a closed flag.
- Example scripts:
live_trading.pyskips non-kline frames and validates the symbol/interval;backtest.pyandmulti_timeframe.pyreport clear errors for malformed CSV input.
0.1.4 - 2026-05-21
Added
- GitHub Release runs now attach every built artefact (wheels, sdist, native
Node binaries, npm-pack tarballs, cargo
.cratefiles) to the tag's release page.
0.1.3 - 2026-05-21
Fixed
- npm package ships the napi-generated loader and is built with
--platformso the per-platform binary is resolved correctly.
0.1.2 - 2026-05-21
Fixed
- Release pipeline: per-platform idempotent npm publishing with a spam-filter
retry, and committed
npm/<platform>/package templates.
0.1.1 - 2026-05-21
Fixed
- Node publish step and coordinated version bump across all bindings.
0.1.0 - 2026-05-21
Added
- Initial release: a streaming-first technical-analysis library with 25 indicators (SMA, EMA, WMA, DEMA, TEMA, HMA, KAMA, RSI, MACD, ROC, Stochastic, CCI, Williams %R, ADX, MFI, TRIX, Aroon, Awesome Oscillator, Bollinger Bands, ATR, Keltner Channels, Donchian Channels, Parabolic SAR, OBV, VWAP).
- Rust core (
wickra-core), umbrella crate (wickra), and a data layer (wickra-data) with a CSV reader, tick aggregator, resampler, and an optional Binance live feed. - Bindings for Python, Node.js, and WebAssembly.