Commit Graph

177 Commits

Author SHA1 Message Date
kingchenc 36dc951f1b test(ohlcv): cover Candle::new_unchecked skip-validation constructor
Codecov flagged lines 86-102 in crates/wickra-core/src/ohlcv.rs as missed
(file at 90.00%) — the entire body of `Candle::new_unchecked`. Every
existing test routes through the validating `Candle::new`, so the unchecked
constructor (intended for callers like the aggregator and parsed-payload
paths that have already validated upstream) was dead.

Add candle_new_unchecked_preserves_fields_verbatim:
  - first assertion builds a candle with six distinct field values and
    verifies each reads back exactly.
  - second assertion feeds an OHLC combination (high < low) that the
    checked constructor rejects with Error::InvalidCandle, then proves
    Candle::new_unchecked still builds the struct as-is. This documents
    and enforces the API contract that the unchecked variant performs
    no validation.

ohlcv.rs is now at 170/170 lines, no behavioural change.
2026-05-23 23:28:26 +02:00
kingchenc 0abc5f71c1 test(vwap): cover Vwap value()/zero-volume/metadata + RollingVwap getters
Codecov flagged 17 uncovered lines in
crates/wickra-core/src/indicators/vwap.rs (file at 87.94%):

  - Vwap::value() Some branch (line 53) — the only test calling value()
    did so after reset() when sum_v == 0, exercising only the None branch
  - Vwap::update zero-volume early-return `return None;` (line 67) — all
    existing candles carried strictly positive volume
  - Vwap::warmup_period body returning 1 (79-81), Vwap::name body
    returning "VWAP" (87-89) — metadata never queried
  - RollingVwap::period accessor (134-136), RollingVwap::warmup_period
    body (165-167), RollingVwap::name body returning "RollingVWAP"
    (173-175) — same metadata gap on the rolling variant

Add four new tests:

  - cumulative_value_some_branch_after_update drives a single
    non-zero-volume candle then asserts value() == Some(typical_price).
  - cumulative_zero_volume_first_candle_returns_none feeds a candle
    with volume == 0.0, asserts update returns None and is_ready stays
    false, then adds a real candle to confirm the indicator still works.
  - cumulative_metadata asserts warmup_period() == 1 and name() == "VWAP".
  - rolling_accessors_and_metadata asserts period() == 7,
    warmup_period() == 7, name() == "RollingVWAP" on a RollingVwap::new(7).

vwap.rs is now at 141/141 lines, no behavioural change.
2026-05-23 23:27:15 +02:00
kingchenc 404fd29c31 test(percent_b): cover accessors, kill dead arm, fix flaky middle test
Codecov flagged 17 uncovered lines in
crates/wickra-core/src/indicators/percent_b.rs (file at 81.11%):

  - const accessors period (53-55), multiplier (58-60), value (63-65)
  - Indicator-impl bodies warmup_period (90-92) and name (98-100)
  - the unreachable `_ => panic!("warmup mismatch at {i}")` arm in
    matches_bands_definition (line 141)
  - the inner `assert_relative_eq!(*pv, 0.5, …)` (line 158) inside
    price_at_middle_is_half, gated by `(prices[i] - bv.middle).abs()
    < 1e-9` over a sin-based oscillation that, with period=20 over 60
    samples, never lands within 1e-9 of the rolling SMA — so the
    assertion was silently dead and the test made no checks.

Add accessors_and_metadata covering the five getter bodies, refactor
matches_bands_definition to assert the warmup-shape invariant via
assert_eq!(p.is_some(), b.is_some()) + if let (kills the panic arm),
and replace price_at_middle_is_half with a deterministic construction:
PercentB::new(3, 2.0) on [1.0, 5.0, 3.0] gives SMA=3.0 at index 2
which equals the third price exactly, stddev=√(8/3)≈1.633 keeps the
width strictly positive so the divide path runs, and %b lands on
exactly 0.5 because price sits on the centre line of symmetric bands.

percent_b.rs is now at 90/90 lines, no behavioural change.
2026-05-23 23:25:35 +02:00
kingchenc 050e5b74b8 test(bollinger_bandwidth): cover accessors, zero-middle branch, kill dead arm
Codecov flagged 17 uncovered lines in
crates/wickra-core/src/indicators/bollinger_bandwidth.rs (file at 79.51%):

  - the const accessors period (54-56), multiplier (59-61), value (64-66)
  - the zero-middle defensive fallback 0.0 (line 77) inside update
  - the Indicator-impl bodies warmup_period (90-92) and name (98-100)
  - the unreachable `_ => panic!("warmup mismatch")` arm (line 140) in
    the existing matches_bands_definition test

None of the existing tests inspected the metadata surface — every test
fed numeric updates and asserted on bandwidth values, leaving the five
getter bodies dead. The zero-middle path was unreachable because all
existing tests used positive price levels ≈100, so the rolling SMA was
always strictly positive and the divide-by-zero guard never fired.
The panic arm in matches_bands_definition was an invariant guard that
by design cannot fire when the two streams share a warmup period; that
invariant is now asserted directly with assert_eq!(w.is_some(),
b.is_some()), and the catch-all arm is gone.

Add two new tests and refactor one existing:

  - accessors_and_metadata asserts period == 20, multiplier == 2.0,
    value() == None before warmup, warmup_period == 20, name ==
    "BollingerBandwidth", then drives 20 updates so value() also
    exercises the Some branch.

  - zero_middle_band_yields_zero_bandwidth feeds [-2, -1, 0, 1, 2] so
    the 5-bar SMA lands on exactly 0.0 at the fifth input, and asserts
    the emitted bandwidth is exactly 0.0 (rather than inf/nan from the
    would-be divide-by-zero).

  - matches_bands_definition now uses an explicit assert_eq! on
    is_some() agreement plus an if let for the numeric compare,
    removing the unreachable panic arm without weakening the
    invariant check.

bollinger_bandwidth.rs is now at 83/83 lines, no behavioural change.
2026-05-23 23:22:54 +02:00
kingchenc 62fe7a81aa test(traits): cover Chain accessors + Identity/Doubler helper surface
Codecov flagged 30 uncovered lines in crates/wickra-core/src/traits.rs (file at
75.60%): the const borrow accessors Chain::first / Chain::second (140-147), the
Chain::warmup_period + Chain::name Indicator-impl bodies (167-178), the full
Identity test-helper Indicator surface — reset, warmup_period, is_ready, name
(198-209), and Doubler's warmup_period + name (228-236).

None of the existing tests touched those code paths: every chain test invoked
update/reset/is_ready through the Chain wrapper without ever inspecting the
borrow accessors, querying chain.warmup_period(), or asking for chain.name(),
and the Identity helper was only ever driven by batch (which calls update
only). Doubler's warmup_period and name were similarly dead because
Chain::warmup_period and Chain::name themselves were dead.

Add two new tests at the end of the Chain section in mod tests, immediately
before the parallel-feature-gated test:

  - chain_accessors_and_metadata exercises chain.first(), chain.second(),
    chain.warmup_period(), chain.name(), and pulls Doubler::warmup_period
    + Doubler::name in via the borrowed accessors.

  - identity_helper_full_indicator_surface asserts warmup_period == 0,
    name == "Identity", and walks is_ready through both seen=false and
    seen=true via an update/reset cycle.

traits.rs is now at 123/123 lines, no behavioural change.
2026-05-23 23:19:24 +02:00
kingchenc 3fcf2094f1 ci(wasm): install wasm-pack via taiki-e prebuilt instead of jetli's stale 0.10
jetli/wasm-pack-action@v0.4.0 with no version: input installs whatever
wasm-pack the action's bundled installer fetches — currently a ~0.10.x
release whose 'build' subcommand does not yet accept --features. Our
build invocation 'wasm-pack build … --features panic-hook' now fails
with

    error: Found argument '--features' which wasn't expected, or isn't
    valid in this context
    USAGE: wasm-pack build --release --target <target>

even though that exact command worked on past runs where the action
happened to install a newer wasm-pack. (The bundler-target release.yml
job passed for v0.2.1 only because it shared the same cached install
on that runner.)

wasm-pack's --features top-level flag has been stable since 0.12.0, so
the fix is to install a fresh wasm-pack each run. Switch both the ci.yml
'WASM build' step and the release.yml 'wasm-publish' job to the same
taiki-e/install-action prebuilt-binary installer we already use for
cargo-llvm-cov and cargo-fuzz. taiki-e tracks the latest wasm-pack
release and the install is a single binary download — no compile, no
shell installer.

The wasm-pack invocations themselves are unchanged.
2026-05-23 23:00:13 +02:00
kingchenc a2ccd202aa test(resample): cover RolledBar::absorb low-update branch
Codecov flagged a single uncovered line in crates/wickra-data/src/resample.rs:
line 46, the `self.low = c.low;` assignment inside RolledBar::absorb.
None of the existing resampler tests fed a follow-up candle with a strictly
lower low than the first candle in the bucket, so the `c.low < self.low`
branch never fired. Coverage stayed at 122/123.

Add a small dedicated test that pushes a 10.0-low candle into bucket 0, then
a 8.0-low candle into the same bucket, and asserts the rolled bar's low
reflects the dip. Resample file is now at 123/123 lines, no behavioural change.
2026-05-23 22:56:40 +02:00
kingchenc 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.
2026-05-23 22:48:48 +02:00
kingchenc e6375746d3 docs: unify README across crates.io / PyPI / npm / GitHub
Three separate README files (root, bindings/node, bindings/python) had
been drifting independently — each registry showed a different project
page, which is exactly the consistency debt I want to avoid.

Single source of truth: /README.md. The three binding READMEs are
overwritten with the root README content as a baseline, and release.yml
gets a one-line cp step right before every publishing call so future
edits to /README.md propagate automatically:

- python-wheels job: cp README.md bindings/python/README.md before
  PyO3/maturin-action runs the wheel build
- python-sdist job: same, before the sdist build
- node-publish job: cp ../../README.md README.md (working-directory
  bindings/node) before the main 'npm publish wickra'
- wasm-publish job: cp README.md bindings/wasm/README.md before
  wasm-pack build (which copies the crate README into pkg/ on its own)

Cargo crates (wickra, wickra-core, wickra-data) already inherit
readme.workspace = true pointing at /README.md, so crates.io was already
correct — no change needed there.

The per-platform npm subpackages (bindings/node/npm/<target>/) keep
their tiny package.json with no README; they are install-time
optionalDependencies that the loader reads through, never user-facing
on the registry.

Effect: same README on github.com/kingchenc/wickra, crates.io/crates/wickra,
pypi.org/project/wickra, and npmjs.com/package/wickra. Will be live on
the registries with the next tag-push.
2026-05-23 22:45:16 +02:00
kingchenc a876b145b0 chore: trigger CI to upload first Codecov coverage report
CODECOV_TOKEN was just added as a repository secret; the existing
Coverage job in .github/workflows/ci.yml will pick it up on the next
run. This empty commit fires that run.
2026-05-23 22:38:49 +02:00
kingchenc 5a573650d2 Merge pull request #18 from kingchenc/release/0.2.1
release(0.2.1): bump to 0.2.1, Windows ARM64 skipped this cycle
v0.2.1
2026-05-23 22:24:47 +02:00
kingchenc 8aa74cb638 release(0.2.1): bump to 0.2.1, skipping Windows ARM64 this cycle
The 0.2.0 release left wickra@npm stuck at 0.1.4 and never created a
GitHub Release entry because the brand-new `wickra-win32-arm64-msvc`
sub-package name was caught by npm's spam-detection filter on its first
publish attempt (same situation that affected `wickra-win32-x64-msvc`
through 0.1.4 until npm Support unblocked it). A support ticket is open;
until it is resolved, ship 0.2.1 for the five platforms whose
sub-packages are already on npm and re-add Windows ARM64 in a follow-up
release.

Changes for this cycle:
- bindings/node/package.json: remove "wickra-win32-arm64-msvc" from
  optionalDependencies and "aarch64-pc-windows-msvc" from
  napi.triples.additional.
- bindings/node/npm/win32-arm64-msvc/: removed (will be restored fresh
  once the npm name is unblocked).
- .github/workflows/release.yml: comment out the
  aarch64-pc-windows-msvc entry of the node-build matrix with a
  TODO/restore note.
- Bump every workspace and binding version to 0.2.1 (Cargo.toml,
  pyproject.toml, bindings/node/package.json, five npm/<target>
  templates, the wiki version table). Cargo.lock regenerated.
- CHANGELOG: new [0.2.1] block consolidating every fix that has landed
  on main since 0.2.0 (HV epsilon, examples CI step, fuzz cargo-fuzz
  install, MSRV 1.85 -> 1.86 / 1.77 -> 1.88, criterion 0.5 -> 0.8,
  tokio-tungstenite 0.24 -> 0.29, tick_aggregator gap-fill cap, every
  GitHub Action SHA-pin bump). Compare-link added.

The arm64 loader branch in bindings/node/index.js is left untouched: a
Windows ARM64 user installing 0.2.1 will get the standard
`Cannot find module 'wickra-win32-arm64-msvc'` error from the loader,
which is accurate. PyPI's win-arm64 wheel is unaffected.

Verified locally:
  cargo fmt/clippy/test --workspace --all-features -> 630 passed / 0 failed
  cargo build -p wickra-examples --bins -> clean
  cargo build -p wickra-node -> clean
2026-05-23 22:20:20 +02:00
kingchenc aea17a87af Merge pull request #16 from kingchenc/fix/criterion-0.8
deps: criterion 0.5 → 0.8 (replaces #10)
2026-05-23 21:43:28 +02:00
kingchenc 23c649aca9 Merge pull request #17 from kingchenc/fix/tokio-tungstenite-0.29
deps: tokio-tungstenite 0.24 → 0.29 (replaces #13)
2026-05-23 21:41:04 +02:00
kingchenc 57d3b785c2 Merge pull request #9 from kingchenc/dependabot/github_actions/actions/download-artifact-8.0.1
deps(actions): bump actions/download-artifact from 4.3.0 to 8.0.1
2026-05-23 21:37:55 +02:00
kingchenc d94dc43fb2 Merge pull request #5 from kingchenc/dependabot/github_actions/actions/upload-artifact-7.0.1
deps(actions): bump actions/upload-artifact from 4.6.2 to 7.0.1
2026-05-23 21:37:51 +02:00
kingchenc ed57632576 build: lift workspace MSRV to 1.86 to satisfy criterion 0.8.2
criterion 0.8.2 raised its MSRV from 1.85 to 1.86 (rustc 1.85.1 is now
explicitly rejected by its Cargo.toml `rust-version`). One more notch
on the same upward drift that already took us from 1.75 -> 1.80 (rayon)
-> 1.85 (clap_lex/edition2024).

Updated:
- Cargo.toml workspace rust-version 1.85 -> 1.86
- .github/workflows/ci.yml MSRV matrix name + toolchain
- ci.yml comment refreshed to reflect the new driving dep
2026-05-23 21:36:56 +02:00
kingchenc 64faa707a4 deps: bump tokio-tungstenite 0.24 -> 0.29 (replaces #13)
Dependabot opened #13 to bump tokio-tungstenite from 0.24 to 0.29 but
the bare-version bump fails to compile: WebSocketConfig became
#[non_exhaustive] starting with 0.27, so the existing struct-literal
construction

    let ws_config = WebSocketConfig {
        max_message_size: Some(MAX_MESSAGE_SIZE),
        max_frame_size: Some(MAX_FRAME_SIZE),
        ..WebSocketConfig::default()
    };

produces

    error[E0639]: cannot create non-exhaustive struct using struct expression

Switch to the builder-style setters that 0.29 exposes on the default
value. Semantics are unchanged; both fields still carry the
MAX_MESSAGE_SIZE / MAX_FRAME_SIZE caps from the original config and the
rest of the WebSocketConfig defaults are preserved by starting from
WebSocketConfig::default().

This supersedes #13 — same target version, plus the code change
Dependabot can't make on its own.

Verified locally:
  cargo check -p wickra-data --features live-binance  # clean
  cargo test --workspace --all-features  # 630 passed / 0 failed
  cargo clippy --workspace --all-targets --all-features -- -D warnings
2026-05-23 21:31:57 +02:00
kingchenc 1011fa2bbd deps: bump criterion 0.5 -> 0.8 and switch to std::hint::black_box
Dependabot opened #10 to bump criterion from 0.5.1 to 0.8.2 but the
straight version bump fails to build: criterion::black_box was
deprecated in 0.6 and removed/marked deny-warn in 0.8, so the existing
`use criterion::{black_box, ...}` produces

    error: use of deprecated function `criterion::black_box`: use
    `std::hint::black_box()` instead

across every bench callsite. Switch the import to std::hint::black_box
(stable since Rust 1.66, well under our MSRV of 1.85) and drop the
criterion re-export.

This supersedes #10 — same target version, plus the code change
Dependabot can't make on its own.

Verified locally:
  cargo bench -p wickra --no-run  # builds clean
  cargo clippy --workspace --all-targets --all-features -- -D warnings
  cargo test --workspace  # 630 passed / 0 failed
2026-05-23 21:30:09 +02:00
dependabot[bot] 7a501a39cf deps(actions): bump actions/download-artifact from 4.3.0 to 8.0.1
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.3.0 to 8.0.1.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/d3f86a106a0bac45b974a628896c90dbdf5c8093...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 19:26:58 +00:00
dependabot[bot] 4acb2c7d68 deps(actions): bump actions/upload-artifact from 4.6.2 to 7.0.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 19:26:45 +00:00
kingchenc 7ba4380693 Merge pull request #1 from kingchenc/dependabot/github_actions/actions/checkout-6.0.2
deps(actions): bump actions/checkout from 4.3.1 to 6.0.2
2026-05-23 21:21:32 +02:00
dependabot[bot] 862a130d8c deps(actions): bump actions/checkout from 4.3.1 to 6.0.2
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.1 to 6.0.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/34e114876b0b11c390a56381ad16ebd13914f8d5...de0fac2e4500dabe0009e67214ff5f5447ce83dd)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 19:21:27 +00:00
kingchenc c009ecc7f9 Merge pull request #8 from kingchenc/dependabot/github_actions/actions/setup-python-6.2.0
deps(actions): bump actions/setup-python from 5.6.0 to 6.2.0
2026-05-23 21:19:29 +02:00
kingchenc bf4faddf0f Merge pull request #6 from kingchenc/dependabot/github_actions/actions/setup-node-6.4.0
deps(actions): bump actions/setup-node from 4.4.0 to 6.4.0
2026-05-23 21:19:26 +02:00
kingchenc 0112693ec3 Merge pull request #4 from kingchenc/dependabot/github_actions/softprops/action-gh-release-3.0.0
deps(actions): bump softprops/action-gh-release from 2.6.2 to 3.0.0
2026-05-23 21:19:23 +02:00
kingchenc 4dd36953c3 Merge pull request #2 from kingchenc/dependabot/github_actions/codecov/codecov-action-6.0.1
deps(actions): bump codecov/codecov-action from 5.5.4 to 6.0.1
2026-05-23 21:19:20 +02:00
dependabot[bot] 9b34c84d86 deps(actions): bump actions/setup-python from 5.6.0 to 6.2.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.6.0 to 6.2.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/a26af69be951a213d495a4c3e4e4022e16d87065...a309ff8b426b58ec0e2a45f0f869d46889d02405)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 18:54:30 +00:00
dependabot[bot] 08928c5b17 deps(actions): bump actions/setup-node from 4.4.0 to 6.4.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.4.0 to 6.4.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/49933ea5288caeca8642d1e84afbd3f7d6820020...48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 18:54:20 +00:00
dependabot[bot] 86b4f73ec7 deps(actions): bump softprops/action-gh-release from 2.6.2 to 3.0.0
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.6.2 to 3.0.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/3bb12739c298aeb8a4eeaf626c5b8d85266b0e65...b4309332981a82ec1c5618f44dd2e27cc8bfbfda)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 18:54:12 +00:00
dependabot[bot] 246d982e93 deps(actions): bump codecov/codecov-action from 5.5.4 to 6.0.1
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.5.4 to 6.0.1.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/75cd11691c0faa626561e295848008c8a7dddffe...e79a6962e0d4c0c17b229090214935d2e33f8354)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 18:53:50 +00:00
kingchenc 3d2e58c531 Merge pull request #14 from kingchenc/dependabot/cargo/serde_json-1.0.150
deps(cargo): bump serde_json from 1.0.149 to 1.0.150
2026-05-23 20:52:11 +02:00
kingchenc f966841ced Merge pull request #3 from kingchenc/dependabot/github_actions/taiki-e/install-action-2.79.5
deps(actions): bump taiki-e/install-action from 2.79.4 to 2.79.5
2026-05-23 20:51:56 +02:00
dependabot[bot] 99490f8604 deps(cargo): bump serde_json from 1.0.149 to 1.0.150
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.149 to 1.0.150.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.149...v1.0.150)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.150
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 18:49:27 +00:00
dependabot[bot] 4d8c0ce1a5 deps(actions): bump taiki-e/install-action from 2.79.4 to 2.79.5
Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.79.4 to 2.79.5.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/e0eafa9a0d485c37f97c0f7beb930a58a2facbac...6c1f7cf125e42770ff087ea443901b487cc5471a)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.79.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-23 18:49:22 +00:00
kingchenc d063555cd1 Merge pull request #15 from kingchenc/fix/ci-and-deps
fix(ci): green up the matrix — HV epsilon, examples step, fuzz install, MSRV bump
2026-05-23 20:47:41 +02:00
kingchenc df179fa579 fix(aggregator): cap gap-fill at 1_000_000 candles per push (fuzz finding)
The tick_aggregator fuzz target found that TickAggregator::fill_between
allocates one placeholder Candle per skipped bucket without bounding the
gap size. An adversarial input (a clock-glitch tick years in the future)
produced an OOM on libFuzzer after malloc(~3 GB):

    SUMMARY: libFuzzer: out-of-memory (malloc(3221225472))

A real-world failure mode too: a single bad timestamp from a flaky feed
could OOM the host process even though every individual tick passed
Tick::new validation.

Fix:
- Compute the gap size up-front via saturating arithmetic, before any
  allocation, and refuse with Error::Malformed when it exceeds the new
  MAX_GAP_FILL_CANDLES = 1_000_000 cap (≈ 1.9 years of contiguous
  one-minute bars, well above any realistic missing-data window).
- Reserve the right Vec capacity in advance once we know the gap fits,
  avoiding intermediate reallocations.
- Add two regression tests: gap_fill_rejects_runaway_timestamp_jump
  (the fuzz scenario) and gap_fill_at_the_cap_succeeds (exact-cap input
  still works).

The cap is exposed as pub const so callers can pre-validate their input
without relying on the error string.
2026-05-23 20:41:03 +02:00
kingchenc d52ddeaccb fix(core): use f64::midpoint and stable %2 to satisfy newer toolchains
Two unrelated newer-toolchain breakages bundled because they hit on the
same CI run and have the same shape (newer Rust got stricter about
patterns we used):

1. clippy 1.95 added the manual_midpoint lint which fires on every
   instance of (a + b) / 2.0 with a help suggesting f64::midpoint.
   CI runs with -D warnings so it became a hard error. Twelve sites
   were affected — three real call sites in src/ohlcv.rs (median_price),
   src/indicators/donchian.rs (DonchianOutput.middle),
   src/indicators/ease_of_movement.rs (mid), and
   src/indicators/super_trend.rs (hl2); plus eight test-helper
   Candle::new constructions across accelerator_oscillator,
   atr_trailing_stop, chaikin_volatility, chandelier_exit,
   chande_kroll_stop, choppiness_index, super_trend, true_range.
   All twelve switched to f64::midpoint (stable since Rust 1.85,
   our workspace MSRV).

2. usize::is_multiple_of is still unstable (rust-lang/rust#128101) and
   only stabilizes in Rust 1.87, but the MSRV CI job uses 1.85. The
   two call sites in bollinger.rs and sma.rs (added with the R7
   periodic-reseed tests) switched back to i % 2 == 0.
2026-05-23 20:37:35 +02:00
kingchenc 3f9429dd2c build: lift workspace MSRV further to 1.85 for criterion's clap_lex
The first MSRV bump to 1.80 fixed the rayon-core floor but ran into a
second transitive-dep floor on the same CI run:

    error: failed to parse manifest at clap_lex-1.1.0/Cargo.toml
    Caused by: feature `edition2024` is required
    The package requires the Cargo feature called `edition2024`, but
    that feature is not stabilized in this version of Cargo (1.80.1).

clap_lex 1.1.0 is pulled in by criterion (dev-dep on the wickra crate)
via clap 4.6 -> clap_builder 4.6 -> clap_lex 1.1. edition2024 was
stabilized in Rust 1.85, so lift the workspace MSRV one more step. The
1.85 floor subsumes the rayon-core 1.80 requirement; bindings/node
stays at 1.88 (napi-build) which already covers everything below it.

Also fix the fuzz job: cargo-fuzz defaulted to building for
x86_64-unknown-linux-musl, which is not installed on the GitHub-hosted
ubuntu runner. Pass --target x86_64-unknown-linux-gnu explicitly on
every cargo fuzz run invocation so it builds for the actual host
target.
2026-05-23 20:30:46 +02:00
kingchenc 30444ce296 build: lift MSRV to 1.80 workspace / 1.88 node binding
The previous MSRV pins were below what current transitive dependencies
need:

  - rayon-core 1.13.0 (pulled in by the optional `parallel` feature on
    wickra-core via rayon) requires rustc >= 1.80; under the old 1.75
    workspace MSRV the CI MSRV job broke with "package `rayon-core
    v1.13.0` cannot be built because it requires rustc 1.80 or newer".
  - napi-build 2.3.2 (the build-script crate that napi-derive 2.x calls
    into) requires rustc >= 1.88; under the old 1.77 node-binding MSRV
    the CI MSRV-node job broke with "package `napi-build v2.3.2` cannot
    be built because it requires rustc 1.88 or newer".

Pinning the deps backwards would have frozen us out of upstream
security/fix releases for both crates. Lifting the MSRV is the cleaner
path for a young 0.x library — downstream consumers on older toolchains
can stay on the already-published 0.2.0.

Updated:
  - Cargo.toml workspace rust-version 1.75 -> 1.80
  - bindings/node/Cargo.toml rust-version 1.77 -> 1.88
  - .github/workflows/ci.yml MSRV matrix names + toolchain values + comment
  - CHANGELOG.md [Unreleased] documents the bump
2026-05-23 20:22:35 +02:00
kingchenc 90d8a299c3 ci(fuzz): install cargo-fuzz from a prebuilt binary
The previous `cargo install cargo-fuzz --locked` resolved against
cargo-fuzz's own Cargo.lock which pins to rustix 0.36.5. That rustix
version still annotates its source with internal #[rustc_*] attributes,
and the current nightly compiler rejects those attributes from
out-of-tree crates, so cargo-fuzz never finished compiling on CI:

    error: attributes starting with `rustc` are reserved for use by the
    `rustc` compiler
      --> rustix-0.36.5/src/backend/linux_raw/io/errno.rs:28
    error: could not compile `rustix` (lib) due to 4 previous errors
    error: failed to compile `cargo-fuzz v0.13.1`

Switch the install to taiki-e/install-action, the same prebuilt-binary
provider we already use for cargo-llvm-cov. That skips the full
transitive-dependency compile and lets the fuzz-smoke job actually run.
2026-05-23 20:21:03 +02:00
kingchenc 73f8da49bd ci: build wickra-examples bins instead of removed cargo examples
The Z5 reorganisation moved every runnable example out of the per-crate
examples/ folders and into a dedicated wickra-examples crate at
examples/rust/, with the binaries living under src/bin/<name>.rs. The
old ci.yml Compile-examples step still pointed at the now-deleted
cargo example targets backtest (wickra) and live_binance (wickra-data),
which is why Rust windows-latest failed with 'no example target named
backtest in wickra package' and 'no example target named live_binance
in wickra-data package'.

Replace both calls with a single cargo build -p wickra-examples --bins.
That covers backtest, live_binance, fetch_btcusdt, multi_timeframe,
parallel_assets and streaming in one shot, and the wickra-examples
crate already enables the live-binance feature on its wickra-data dep
so no extra --features flag is needed.
2026-05-23 20:19:14 +02:00
kingchenc ae8fcd9051 test(hv): widen geometric_series_yields_zero tolerance to 1e-6
The mathematical result of HistoricalVolatility on a perfectly geometric
price series is exactly zero — but the underlying 1.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 Windows result happened
to round closer to zero, which is why the test passed locally and on the
Windows CI runner but failed on Linux and macOS).

Bump the tolerance from 1e-9 to 1e-6. That stays four decimal places
below any realistic annualised volatility value while comfortably
absorbing the observed cross-platform drift.

Also extend the comment to document the rationale so the next person
who reads the test does not tighten it back down.
2026-05-23 20:18:24 +02:00
kingchenc 39a252ea66 release(0.2.0): bump version from 0.1.5 to 0.2.0
This release carries the full post-audit work — 46 new indicators
(25 → 71), an eight-family taxonomy restructure, new bindings for
RollingVWAP, the WASM streaming-update parity, the pyo3/numpy CVE
fix, the SMA/Bollinger drift bound, the O(1) LinearRegression
refactor, the UlcerIndex deque and the PSAR is_ready/reset fixes
plus a refreshed example suite and wiki. The earlier 0.1.5 number
was never published; jumping straight to 0.2.0 is the cleaner signal
for the scope of the change.

Bumped:
- Cargo.toml workspace + wickra-core workspace-dep version
- bindings/python/pyproject.toml
- bindings/node/package.json + optionalDependencies (six platform pins)
- 6 x bindings/node/npm/<target>/package.json
- Cargo.lock regenerated
- CHANGELOG.md [0.2.0] header + compare-link
- docs/wiki/Home.md published-versions table
- docs/wiki/Quickstart-{Rust,Node,WASM}.md + Warmup-Periods.md
  version-pinned narrative lines

Verified locally:
- cargo fmt/clippy/test (628 passed, 0 failed)
- cargo deny check (no suppression)
- bindings/node node --test (92/92)
- bindings/python pytest (118/118)
- import wickra reports 0.2.0 with 72 indicator classes
v0.2.0
2026-05-23 19:58:02 +02:00
kingchenc 11c52b8e86 release(0.1.5): stamp the CHANGELOG date
Replace the TBD placeholder under ## [0.1.5] with today's date so the
release header is complete. The compare-link at v0.1.4...v0.1.5 is
already in place and points at the right pair.
2026-05-23 19:12:11 +02:00
kingchenc c6d2030103 chore(python): add canonical authors metadata to pyproject.toml
Every other manifest in the repo carries the author string
kingchenc <kingchencp@gmail.com> — workspace Cargo.toml,
bindings/node/package.json, all per-platform npm package.jsons,
release.yml. pyproject.toml had neither authors nor maintainers, so
the PyPI listing fell back to the implicit empty value. Align with
the rest of the repo.
2026-05-23 19:11:53 +02:00
kingchenc a10bda188f docs(wiki): align RollingVwap count with Home and README
Indicators-Overview.md listed RollingVwap as its own row in the Volume
table (count = 9, total = 72), but Home.md and README.md treat it as
a sub-variant of Vwap (count = 8, total = 71). Drop the standalone row
in Indicators-Overview and fold the rolling variant into the Vwap row.
Warmup-Periods.md keeps both constructors (Vwap::new() and
RollingVwap::new(n) have different warmup periods, which is the whole
purpose of that page) but adds a note explaining that the row count
exceeds the 71 canonical indicators by one.
2026-05-23 19:11:34 +02:00
kingchenc c4ffcc2138 docs(node): correct doc-comment package name to wickra
The module doc-comment in bindings/node/src/lib.rs still pointed at
@wickra/wickra. The package is published as bare "wickra" — every
README, Quickstart and example already uses that name. Align the
inline doc with the published name.
2026-05-23 19:10:18 +02:00
kingchenc f3ad0940c3 docs(wiki): correct Node warmupPeriod() coverage note (R3, R8)
The Quickstart-Node API-surface table claimed `warmupPeriod()` was
"not exposed on every multi-output class". After the B-series fixes
in `todo-detailed.md` and the R3/R8 pass on this branch, every Node
indicator class — single- and multi-output, scalar- and candle-input —
exposes `warmupPeriod()`. Updated the note accordingly.
2026-05-23 11:04:15 +02:00
kingchenc a32719d709 docs(wiki): expand WASM Quickstart for the full multi-output surface (R3)
The Quickstart-WASM page only mentioned `MACD` and `BollingerBands` as
multi-output indicators. After R3 (this branch) every candle-input
WASM class also exposes a structured `update`: `Stochastic`, `ADX`,
`Keltner`, `Donchian`, `Aroon` (plus `SuperTrend`, which has always
been there).

The "Multi-output indicators" section now lists every multi-output
shape in a table, and a short note at the end calls out the 0.1.5
parity: every candle-input indicator ships `update` / `batch` /
`reset` / `isReady` / `warmupPeriod`, so browser code doesn't need
to replay `batch` on each tick anymore.
2026-05-23 11:03:53 +02:00