Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a573650d2 | |||
| 8aa74cb638 | |||
| aea17a87af | |||
| 23c649aca9 | |||
| 57d3b785c2 | |||
| d94dc43fb2 | |||
| ed57632576 | |||
| 64faa707a4 | |||
| 1011fa2bbd | |||
| 7a501a39cf | |||
| 4acb2c7d68 | |||
| 7ba4380693 | |||
| 862a130d8c | |||
| c009ecc7f9 | |||
| bf4faddf0f | |||
| 0112693ec3 | |||
| 4dd36953c3 | |||
| 9b34c84d86 | |||
| 08928c5b17 | |||
| 86b4f73ec7 | |||
| 246d982e93 | |||
| 3d2e58c531 | |||
| f966841ced | |||
| 99490f8604 | |||
| 4d8c0ce1a5 | |||
| d063555cd1 | |||
| df179fa579 | |||
| d52ddeaccb | |||
| 3f9429dd2c | |||
| 30444ce296 | |||
| 90d8a299c3 | |||
| 73f8da49bd | |||
| ae8fcd9051 |
@@ -30,14 +30,14 @@ jobs:
|
||||
name: Cross-library benchmark report
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
| tee benchmark.txt
|
||||
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: cross-library-bench
|
||||
path: bindings/python/benchmark.txt
|
||||
|
||||
+45
-28
@@ -19,7 +19,7 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
@@ -48,14 +48,22 @@ jobs:
|
||||
run: cargo build -p wickra --benches --verbose
|
||||
|
||||
- name: Compile examples
|
||||
run: |
|
||||
cargo build -p wickra --example backtest
|
||||
cargo build -p wickra-data --example live_binance --features live-binance
|
||||
# All runnable examples now live in the dedicated wickra-examples crate
|
||||
# (examples/rust/src/bin/*.rs) which enables the live-binance feature
|
||||
# on its wickra-data dep, so a single --bins build covers backtest,
|
||||
# live_binance, fetch_btcusdt, multi_timeframe, parallel_assets and
|
||||
# streaming.
|
||||
run: cargo build -p wickra-examples --bins
|
||||
|
||||
# Verify the crates still build and test on their declared minimum supported
|
||||
# Rust version. The workspace pins rust-version = "1.75"; bindings/node needs
|
||||
# 1.77 because napi-build emits `cargo::` directives. Without this job an
|
||||
# accidental use of a newer API would only surface for downstream users.
|
||||
# Rust version. The workspace pins rust-version = "1.86" — that floor is
|
||||
# set by criterion 0.8.2 (the bench dev-dep), which itself rolled past the
|
||||
# clap_lex 1.1.0 / edition2024 / Rust 1.85 floor and now needs 1.86; the
|
||||
# earlier rayon-core 1.13.0 (1.80) and clap_lex (1.85) requirements are
|
||||
# subsumed. bindings/node pins rust-version = "1.88" because napi-build
|
||||
# 2.3.2 requires it (and that subsumes the older 1.77 floor needed for
|
||||
# `cargo::` directives). Without this job an accidental use of a newer
|
||||
# API would only surface for downstream users.
|
||||
msrv:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ubuntu-latest
|
||||
@@ -63,14 +71,14 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: MSRV workspace (Rust 1.75)
|
||||
toolchain: "1.75"
|
||||
- name: MSRV workspace (Rust 1.86)
|
||||
toolchain: "1.86"
|
||||
packages: "-p wickra-core -p wickra -p wickra-data"
|
||||
- name: MSRV node binding (Rust 1.77)
|
||||
toolchain: "1.77"
|
||||
- name: MSRV node binding (Rust 1.88)
|
||||
toolchain: "1.88"
|
||||
packages: "-p wickra-node"
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install Rust ${{ matrix.toolchain }}
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
@@ -91,7 +99,7 @@ jobs:
|
||||
name: Coverage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
@@ -102,7 +110,7 @@ jobs:
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
|
||||
- name: Install cargo-llvm-cov
|
||||
uses: taiki-e/install-action@e0eafa9a0d485c37f97c0f7beb930a58a2facbac # v2.79.4
|
||||
uses: taiki-e/install-action@6c1f7cf125e42770ff087ea443901b487cc5471a # v2.79.5
|
||||
with:
|
||||
tool: cargo-llvm-cov
|
||||
|
||||
@@ -114,7 +122,7 @@ jobs:
|
||||
--lcov --output-path lcov.info
|
||||
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
with:
|
||||
files: lcov.info
|
||||
fail_ci_if_error: false
|
||||
@@ -127,7 +135,7 @@ jobs:
|
||||
name: Supply-chain (cargo-deny)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: cargo-deny
|
||||
uses: EmbarkStudios/cargo-deny-action@a531616d8ce3b9177443e48a1159bc945a099823 # v2.0.19
|
||||
@@ -143,7 +151,7 @@ jobs:
|
||||
name: Fuzz (smoke)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install nightly Rust
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
@@ -156,26 +164,35 @@ jobs:
|
||||
workspaces: fuzz
|
||||
|
||||
- name: Install cargo-fuzz
|
||||
run: cargo install cargo-fuzz --locked
|
||||
# Use the prebuilt binary from taiki-e/install-action instead of
|
||||
# `cargo install cargo-fuzz --locked`. The latter resolves the
|
||||
# version graph from cargo-fuzz's own Cargo.lock, which pins to
|
||||
# rustix 0.36.5 — a version that still uses internal `rustc_*`
|
||||
# attributes the modern nightly compiler rejects, so the install
|
||||
# never gets off the ground. The prebuilt binary avoids the entire
|
||||
# transitive-dep compile.
|
||||
uses: taiki-e/install-action@6c1f7cf125e42770ff087ea443901b487cc5471a # v2.79.5
|
||||
with:
|
||||
tool: cargo-fuzz
|
||||
|
||||
- name: Fuzz csv_reader (30 s)
|
||||
run: cargo +nightly fuzz run csv_reader -- -max_total_time=30
|
||||
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu csv_reader -- -max_total_time=30
|
||||
working-directory: fuzz
|
||||
|
||||
- name: Fuzz binance_envelope (30 s)
|
||||
run: cargo +nightly fuzz run binance_envelope -- -max_total_time=30
|
||||
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu binance_envelope -- -max_total_time=30
|
||||
working-directory: fuzz
|
||||
|
||||
- name: Fuzz indicator_update (30 s)
|
||||
run: cargo +nightly fuzz run indicator_update -- -max_total_time=30
|
||||
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu indicator_update -- -max_total_time=30
|
||||
working-directory: fuzz
|
||||
|
||||
- name: Fuzz indicator_update_candle (30 s)
|
||||
run: cargo +nightly fuzz run indicator_update_candle -- -max_total_time=30
|
||||
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu indicator_update_candle -- -max_total_time=30
|
||||
working-directory: fuzz
|
||||
|
||||
- name: Fuzz tick_aggregator (30 s)
|
||||
run: cargo +nightly fuzz run tick_aggregator -- -max_total_time=30
|
||||
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu tick_aggregator -- -max_total_time=30
|
||||
working-directory: fuzz
|
||||
|
||||
python:
|
||||
@@ -187,7 +204,7 @@ jobs:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
python-version: ["3.9", "3.11", "3.12", "3.13"]
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
@@ -196,7 +213,7 @@ jobs:
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
@@ -222,7 +239,7 @@ jobs:
|
||||
name: WASM build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install Rust toolchain (with wasm target)
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
@@ -256,7 +273,7 @@ jobs:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
node-version: ["18", "20"]
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
@@ -265,7 +282,7 @@ jobs:
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
# Settings -> Environments.
|
||||
environment: release
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
cargo package -p wickra
|
||||
|
||||
- name: Upload .crate files
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: crate-files
|
||||
path: target/package/*.crate
|
||||
@@ -102,8 +102,8 @@ jobs:
|
||||
- { os: windows-11-arm, target: aarch64, manylinux: auto }
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
args: --release --strip --out dist
|
||||
manylinux: ${{ matrix.manylinux }}
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
# Include manylinux in the name so the glibc and musl x86_64/aarch64
|
||||
# builds do not collide on the same artifact name.
|
||||
@@ -123,13 +123,13 @@ jobs:
|
||||
name: Build Python sdist
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
|
||||
with:
|
||||
working-directory: bindings/python
|
||||
command: sdist
|
||||
args: --out dist
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: wheels-sdist
|
||||
path: bindings/python/dist/*
|
||||
@@ -140,7 +140,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
steps:
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
path: dist
|
||||
pattern: wheels-*
|
||||
@@ -168,12 +168,20 @@ jobs:
|
||||
- { host: macos-latest, target: x86_64-apple-darwin }
|
||||
- { host: macos-latest, target: aarch64-apple-darwin }
|
||||
- { host: windows-latest, target: x86_64-pc-windows-msvc }
|
||||
- { host: windows-11-arm, target: aarch64-pc-windows-msvc }
|
||||
# NOTE: aarch64-pc-windows-msvc is temporarily skipped for 0.2.1.
|
||||
# The wickra-win32-arm64-msvc npm subpackage name is blocked by the
|
||||
# npm spam-detection filter for new accounts (same situation that
|
||||
# affected wickra-win32-x64-msvc through 0.1.4 until npm Support
|
||||
# unblocked it). A support ticket is open; once the new arm64 name
|
||||
# is unblocked this matrix entry will be restored alongside the
|
||||
# corresponding optionalDependencies / napi.triples / npm/<target>
|
||||
# entries in a follow-up release.
|
||||
# - { host: windows-11-arm, target: aarch64-pc-windows-msvc }
|
||||
runs-on: ${{ matrix.host }}
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
@@ -192,7 +200,7 @@ jobs:
|
||||
run: npx napi build --platform --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: bindings-${{ matrix.target }}
|
||||
path: bindings/node/wickra.*.node
|
||||
@@ -204,9 +212,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: "20"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
@@ -216,7 +224,7 @@ jobs:
|
||||
run: npm install
|
||||
|
||||
- name: Download all platform binaries
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
path: bindings/node/artifacts
|
||||
pattern: bindings-*
|
||||
@@ -323,7 +331,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Upload Node tarballs
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: node-tarballs
|
||||
path: |
|
||||
@@ -338,9 +346,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: "20"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
@@ -373,7 +381,7 @@ jobs:
|
||||
run: npm pack
|
||||
|
||||
- name: Upload WASM tarball
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: wasm-tarball
|
||||
path: bindings/wasm/pkg/wickra-wasm-*.tgz
|
||||
@@ -397,7 +405,7 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -418,7 +426,7 @@ jobs:
|
||||
echo "::notice::attaching assets to release $tag"
|
||||
|
||||
- name: Download all build artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
@@ -439,7 +447,7 @@ jobs:
|
||||
echo "asset-count=$(ls release-assets/ | wc -l)"
|
||||
|
||||
- name: Create / update GitHub Release with assets
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
tag_name: ${{ steps.tag.outputs.tag }}
|
||||
name: Wickra ${{ steps.tag.outputs.tag }}
|
||||
|
||||
+82
-1
@@ -7,6 +7,86 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [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,
|
||||
and `napi-build >= 2.3.2` requires 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 `criterion` from 0.5 to 0.8 and migrated
|
||||
`bindings/wickra/benches/indicators.rs` from the deprecated
|
||||
`criterion::black_box` re-export to the stable `std::hint::black_box`.
|
||||
- Bumped `tokio-tungstenite` from 0.24 to 0.29. `WebSocketConfig` became
|
||||
`#[non_exhaustive]` upstream, so the struct-literal construction in
|
||||
`crates/wickra-data/src/live/binance.rs` is rewritten to the
|
||||
builder-style `WebSocketConfig::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/checkout` 4 → 6, `actions/setup-node` 4 → 6,
|
||||
`actions/setup-python` 5 → 6, `actions/upload-artifact` 4 → 7,
|
||||
`actions/download-artifact` 4 → 8, `softprops/action-gh-release` 2 → 3,
|
||||
`codecov/codecov-action` 5 → 6, `taiki-e/install-action` patch.
|
||||
|
||||
### Fixed
|
||||
- `tick_aggregator` gap-fill no longer allocates an unbounded number of
|
||||
placeholder candles. The new `MAX_GAP_FILL_CANDLES = 1_000_000` cap
|
||||
surfaces an adversarial timestamp jump (e.g. a clock-glitch tick years
|
||||
in the future) as `Error::Malformed` instead of an OOM panic. Found by
|
||||
the new `tick_aggregator` fuzz target.
|
||||
- `HistoricalVolatility::geometric_series_yields_zero` now uses an `1e-6`
|
||||
tolerance instead of `1e-9`. The mathematical result 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 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.0` test-helper and three real call
|
||||
sites (`Ohlcv::median_price`, `Donchian.middle`, `EaseOfMovement.mid`,
|
||||
`SuperTrend.hl2`) with `f64::midpoint(high, low)`. The change satisfies
|
||||
clippy 1.95's new `manual_midpoint` lint without affecting values
|
||||
(`f64::midpoint` matches the naive average to better than 1 ULP for the
|
||||
inputs used here).
|
||||
- Replaced `i.is_multiple_of(2)` (unstable on Rust 1.85) with `i % 2 == 0`
|
||||
in the SMA / Bollinger long-stream-drift tests so the workspace MSRV
|
||||
job builds cleanly on Rust 1.86.
|
||||
- The `Compile examples` CI step now invokes
|
||||
`cargo build -p wickra-examples --bins` instead of the now-deleted
|
||||
`cargo build -p wickra --example backtest` / `-p wickra-data --example
|
||||
live_binance` (the Z5 reorganisation moved every runnable example into
|
||||
the dedicated `wickra-examples` crate, but the CI step had not been
|
||||
updated).
|
||||
- The `Fuzz (smoke)` CI job installs `cargo-fuzz` from a prebuilt binary
|
||||
via `taiki-e/install-action` instead of `cargo install cargo-fuzz`.
|
||||
The source install resolved against `rustix 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 to
|
||||
`x86_64-unknown-linux-musl`, which is not installed on the standard
|
||||
GitHub-hosted Ubuntu runner.
|
||||
|
||||
### Removed
|
||||
- **`wickra-win32-arm64-msvc` is temporarily omitted from this release.**
|
||||
The npm spam-detection filter blocks the first publish of this brand-new
|
||||
package name (same situation that affected `wickra-win32-x64-msvc`
|
||||
through 0.1.4 until npm Support unblocked it). A support ticket is open;
|
||||
once the new name is unblocked the
|
||||
`aarch64-pc-windows-msvc` triple will be restored in
|
||||
`bindings/node/package.json` (`napi.triples.additional` +
|
||||
`optionalDependencies`), in the `release.yml` `node-build` matrix, and
|
||||
as a fresh `bindings/node/npm/win32-arm64-msvc/` template. Until then,
|
||||
`npm install wickra@0.2.1` on Windows ARM64 will surface the loader's
|
||||
standard `Cannot 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
|
||||
@@ -249,7 +329,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
optional Binance live feed.
|
||||
- Bindings for Python, Node.js, and WebAssembly.
|
||||
|
||||
[Unreleased]: https://github.com/kingchenc/wickra/compare/v0.2.0...HEAD
|
||||
[Unreleased]: https://github.com/kingchenc/wickra/compare/v0.2.1...HEAD
|
||||
[0.2.1]: https://github.com/kingchenc/wickra/compare/v0.2.0...v0.2.1
|
||||
[0.2.0]: https://github.com/kingchenc/wickra/compare/v0.1.4...v0.2.0
|
||||
[0.1.4]: https://github.com/kingchenc/wickra/compare/v0.1.3...v0.1.4
|
||||
[0.1.3]: https://github.com/kingchenc/wickra/compare/v0.1.2...v0.1.3
|
||||
|
||||
Generated
+73
-125
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
@@ -11,6 +11,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloca"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
@@ -91,12 +100,6 @@ version = "3.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.11.1"
|
||||
@@ -223,25 +226,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.5.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||
checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3"
|
||||
dependencies = [
|
||||
"alloca",
|
||||
"anes",
|
||||
"cast",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"is-terminal",
|
||||
"itertools",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"oorandom",
|
||||
"page_size",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
@@ -249,9 +251,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.5.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||
checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools",
|
||||
@@ -479,17 +481,6 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
@@ -547,12 +538,6 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.4.0"
|
||||
@@ -690,22 +675,11 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
@@ -1008,6 +982,16 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "page_size"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
@@ -1116,8 +1100,8 @@ dependencies = [
|
||||
"bit-vec",
|
||||
"bitflags",
|
||||
"num-traits",
|
||||
"rand 0.9.4",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand_xorshift",
|
||||
"regex-syntax",
|
||||
"rusty-fork",
|
||||
@@ -1210,35 +1194,14 @@ version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1248,16 +1211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1275,7 +1229,7 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
|
||||
dependencies = [
|
||||
"rand_core 0.9.5",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1466,9 +1420,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.149"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -1563,33 +1517,13 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1661,9 +1595,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.24.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9"
|
||||
checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
@@ -1675,21 +1609,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.24.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
|
||||
checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rand 0.8.6",
|
||||
"rand",
|
||||
"sha1",
|
||||
"thiserror 1.0.69",
|
||||
"utf-8",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1734,12 +1666,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
@@ -1941,7 +1867,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"criterion",
|
||||
@@ -1952,17 +1878,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-core"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"proptest",
|
||||
"rayon",
|
||||
"thiserror 2.0.18",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wickra-data"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"csv",
|
||||
@@ -1970,7 +1896,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"url",
|
||||
@@ -1989,7 +1915,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-node"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"napi",
|
||||
"napi-build",
|
||||
@@ -1999,7 +1925,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-python"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"numpy",
|
||||
"pyo3",
|
||||
@@ -2008,7 +1934,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-wasm"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
@@ -2019,6 +1945,22 @@ dependencies = [
|
||||
"wickra-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
@@ -2028,6 +1970,12 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
|
||||
+4
-4
@@ -12,10 +12,10 @@ members = [
|
||||
exclude = ["fuzz"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
authors = ["kingchenc <kingchencp@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.75"
|
||||
rust-version = "1.86"
|
||||
license = "PolyForm-Noncommercial-1.0.0"
|
||||
repository = "https://github.com/kingchenc/wickra"
|
||||
homepage = "https://github.com/kingchenc/wickra"
|
||||
@@ -24,7 +24,7 @@ keywords = ["finance", "trading", "indicators", "technical-analysis", "ta"]
|
||||
categories = ["finance", "mathematics", "science"]
|
||||
|
||||
[workspace.dependencies]
|
||||
wickra-core = { path = "crates/wickra-core", version = "0.2.0" }
|
||||
wickra-core = { path = "crates/wickra-core", version = "0.2.1" }
|
||||
|
||||
thiserror = "2"
|
||||
rayon = "1.10"
|
||||
@@ -32,7 +32,7 @@ rayon = "1.10"
|
||||
# Testing
|
||||
proptest = "1.5"
|
||||
approx = "0.5"
|
||||
criterion = { version = "0.5", features = ["html_reports"] }
|
||||
criterion = { version = "0.8", features = ["html_reports"] }
|
||||
|
||||
# Python binding
|
||||
pyo3 = { version = "0.28", features = ["extension-module", "abi3-py39"] }
|
||||
|
||||
@@ -4,9 +4,11 @@ description = "Node.js bindings for the Wickra streaming-first technical indicat
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
# napi-build emits `cargo::` directives that require Rust >= 1.77; the rest of
|
||||
# the workspace stays at 1.75 because the core crate has no such dependency.
|
||||
rust-version = "1.77"
|
||||
# napi-build 2.3.2 requires Rust >= 1.88 (newer than the workspace 1.80
|
||||
# minimum, which itself was lifted to satisfy rayon-core 1.13.0). napi-build
|
||||
# also emits `cargo::` directives that require >= 1.77 — that older floor is
|
||||
# subsumed by the 1.88 requirement now.
|
||||
rust-version = "1.88"
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-darwin-arm64",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "Native binding for wickra (macOS Apple Silicon). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.darwin-arm64.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-darwin-x64",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "Native binding for wickra (macOS Intel). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.darwin-x64.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-linux-arm64-gnu",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "Native binding for wickra (linux arm64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.linux-arm64-gnu.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-linux-x64-gnu",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "Native binding for wickra (linux x64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.linux-x64-gnu.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "wickra-win32-arm64-msvc",
|
||||
"version": "0.2.0",
|
||||
"description": "Native binding for wickra (Windows arm64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.win32-arm64-msvc.node",
|
||||
"files": [
|
||||
"wickra.win32-arm64-msvc.node"
|
||||
],
|
||||
"license": "PolyForm-Noncommercial-1.0.0",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kingchenc/wickra"
|
||||
},
|
||||
"homepage": "https://github.com/kingchenc/wickra"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-win32-x64-msvc",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "Native binding for wickra (Windows x64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.win32-x64-msvc.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"description": "Streaming-first technical indicators: incremental, fast, install-free. Node bindings powered by Rust.",
|
||||
"author": "kingchenc <kingchencp@gmail.com>",
|
||||
"main": "index.js",
|
||||
@@ -38,8 +38,7 @@
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"x86_64-apple-darwin",
|
||||
"aarch64-apple-darwin",
|
||||
"x86_64-pc-windows-msvc",
|
||||
"aarch64-pc-windows-msvc"
|
||||
"x86_64-pc-windows-msvc"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -47,12 +46,11 @@
|
||||
"node": ">= 18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wickra-linux-x64-gnu": "0.2.0",
|
||||
"wickra-linux-arm64-gnu": "0.2.0",
|
||||
"wickra-darwin-x64": "0.2.0",
|
||||
"wickra-darwin-arm64": "0.2.0",
|
||||
"wickra-win32-x64-msvc": "0.2.0",
|
||||
"wickra-win32-arm64-msvc": "0.2.0"
|
||||
"wickra-linux-x64-gnu": "0.2.1",
|
||||
"wickra-linux-arm64-gnu": "0.2.1",
|
||||
"wickra-darwin-x64": "0.2.1",
|
||||
"wickra-darwin-arm64": "0.2.1",
|
||||
"wickra-win32-x64-msvc": "0.2.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "napi build --platform --release",
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "wickra"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
description = "Streaming-first technical indicators: incremental, fast, install-free."
|
||||
readme = "README.md"
|
||||
license = { text = "PolyForm-Noncommercial-1.0.0" }
|
||||
|
||||
@@ -108,7 +108,7 @@ mod tests {
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -139,7 +139,7 @@ mod tests {
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -294,7 +294,7 @@ mod tests {
|
||||
let n_updates = 16 * period * 5;
|
||||
let mut last = None;
|
||||
for i in 0..n_updates {
|
||||
let v = if i.is_multiple_of(2) { 1e6 } else { 1.0 };
|
||||
let v = if i % 2 == 0 { 1e6 } else { 1.0 };
|
||||
last = bb.update(v);
|
||||
if window.len() == period {
|
||||
window.pop_front();
|
||||
|
||||
@@ -108,7 +108,7 @@ mod tests {
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -173,7 +173,7 @@ mod tests {
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -137,7 +137,7 @@ mod tests {
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -134,7 +134,7 @@ mod tests {
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -83,7 +83,7 @@ impl Indicator for Donchian {
|
||||
.fold(f64::INFINITY, f64::min);
|
||||
Some(DonchianOutput {
|
||||
upper,
|
||||
middle: (upper + lower) / 2.0,
|
||||
middle: f64::midpoint(upper, lower),
|
||||
lower,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ impl Indicator for EaseOfMovement {
|
||||
type Output = f64;
|
||||
|
||||
fn update(&mut self, candle: Candle) -> Option<f64> {
|
||||
let mid = (candle.high + candle.low) / 2.0;
|
||||
let mid = f64::midpoint(candle.high, candle.low);
|
||||
let Some(prev_mid) = self.prev_mid else {
|
||||
// The first candle only establishes the previous midpoint.
|
||||
self.prev_mid = Some(mid);
|
||||
|
||||
@@ -205,11 +205,17 @@ mod tests {
|
||||
#[test]
|
||||
fn geometric_series_yields_zero() {
|
||||
// A constant growth factor gives a constant log return -> zero stddev.
|
||||
// The mathematical result is exactly zero, but `1.01_f64.powi(i)` and
|
||||
// the subsequent log / std-dev cascade accumulate platform-sensitive
|
||||
// floating-point drift on the order of 1e-7 (observed on x86_64 Linux
|
||||
// and macOS; Windows happens to round closer to zero). The 1e-6
|
||||
// tolerance stays four decimal places below any realistic volatility
|
||||
// value while absorbing this drift across every supported platform.
|
||||
let mut hv = HistoricalVolatility::new(10, 252).unwrap();
|
||||
let prices: Vec<f64> = (0..40).map(|i| 100.0 * 1.01_f64.powi(i)).collect();
|
||||
let out = hv.batch(&prices);
|
||||
for v in out.iter().skip(10).flatten() {
|
||||
assert_relative_eq!(*v, 0.0, epsilon = 1e-9);
|
||||
assert_relative_eq!(*v, 0.0, epsilon = 1e-6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ mod tests {
|
||||
// `RECOMPUTE_EVERY * period * 5` updates → recompute fires 5+ times.
|
||||
let n_updates = 16 * period * 5;
|
||||
for i in 0..n_updates {
|
||||
let v = if i.is_multiple_of(2) { 1e9 } else { 1.0 };
|
||||
let v = if i % 2 == 0 { 1e9 } else { 1.0 };
|
||||
sma.update(v);
|
||||
if window.len() == period {
|
||||
window.pop_front();
|
||||
|
||||
@@ -107,7 +107,7 @@ impl Indicator for SuperTrend {
|
||||
|
||||
fn update(&mut self, candle: Candle) -> Option<SuperTrendOutput> {
|
||||
let atr = self.atr.update(candle)?;
|
||||
let hl2 = (candle.high + candle.low) / 2.0;
|
||||
let hl2 = f64::midpoint(candle.high, candle.low);
|
||||
let basic_upper = hl2 + self.multiplier * atr;
|
||||
let basic_lower = hl2 - self.multiplier * atr;
|
||||
|
||||
@@ -184,7 +184,7 @@ mod tests {
|
||||
use crate::traits::BatchExt;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -82,7 +82,7 @@ mod tests {
|
||||
use approx::assert_relative_eq;
|
||||
|
||||
fn c(high: f64, low: f64, close: f64, ts: i64) -> Candle {
|
||||
Candle::new((high + low) / 2.0, high, low, close, 1.0, ts).unwrap()
|
||||
Candle::new(f64::midpoint(high, low), high, low, close, 1.0, ts).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -110,7 +110,7 @@ impl Candle {
|
||||
/// The mid price `(high + low) / 2`.
|
||||
#[inline]
|
||||
pub fn median_price(&self) -> f64 {
|
||||
(self.high + self.low) / 2.0
|
||||
f64::midpoint(self.high, self.low)
|
||||
}
|
||||
|
||||
/// The weighted close `(high + low + 2*close) / 4`.
|
||||
|
||||
@@ -30,7 +30,7 @@ serde_json = "1"
|
||||
|
||||
# Async / live feeds are opt-in: only pulled when a `live-*` feature is requested.
|
||||
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "net", "time", "io-util"], optional = true }
|
||||
tokio-tungstenite = { version = "0.24", optional = true, features = ["native-tls"] }
|
||||
tokio-tungstenite = { version = "0.29", optional = true, features = ["native-tls"] }
|
||||
futures-util = { version = "0.3", optional = true }
|
||||
url = { version = "2", optional = true }
|
||||
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
use crate::error::{Error, Result};
|
||||
use wickra_core::{Candle, Tick};
|
||||
|
||||
/// Hard cap on the number of placeholder candles a single
|
||||
/// [`TickAggregator::push`] call may emit when gap-fill is enabled. One
|
||||
/// million minute-candles is roughly 1.9 years of contiguous one-minute bars
|
||||
/// — orders of magnitude beyond any realistic missing-data window in
|
||||
/// production while still keeping the resulting `Vec<Candle>` to well under
|
||||
/// 50 MB. Any larger gap is treated as malformed input rather than allowed
|
||||
/// to OOM the process.
|
||||
pub const MAX_GAP_FILL_CANDLES: i64 = 1_000_000;
|
||||
|
||||
/// A candle bucket size measured in the same unit as the tick timestamps.
|
||||
///
|
||||
/// Wickra is unit-agnostic about timestamps: choose whichever makes sense for
|
||||
@@ -133,7 +142,11 @@ impl Timeframe {
|
||||
/// the next non-empty bar — the skipped buckets produce no candle, so the
|
||||
/// output series can have time holes. Enable [`TickAggregator::with_gap_fill`]
|
||||
/// to instead emit a flat placeholder candle for every skipped bucket, giving
|
||||
/// downstream indicators an unbroken, evenly spaced series.
|
||||
/// downstream indicators an unbroken, evenly spaced series. To bound memory
|
||||
/// against an adversarial timestamp jump, gap-filling refuses to emit more
|
||||
/// than [`MAX_GAP_FILL_CANDLES`] placeholders in a single step; a larger gap
|
||||
/// surfaces as an `Error::Malformed` so the caller can decide how to handle
|
||||
/// the discontinuity.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TickAggregator {
|
||||
timeframe: Timeframe,
|
||||
@@ -279,19 +292,47 @@ impl TickAggregator {
|
||||
|
||||
/// Append a flat placeholder candle for every empty bucket strictly between
|
||||
/// the just-closed bar and the next bucket that received a tick.
|
||||
///
|
||||
/// Returns `Error::Malformed` when the gap would exceed
|
||||
/// [`MAX_GAP_FILL_CANDLES`] — an adversarial timestamp jump (a clock-glitch
|
||||
/// tick years in the future) must surface as a defined error, not as an
|
||||
/// out-of-memory panic from allocating millions of placeholder candles.
|
||||
fn fill_between(&self, prev: Candle, next_bucket: i64, out: &mut Vec<Candle>) -> Result<()> {
|
||||
let step = self.timeframe.bucket();
|
||||
let mut start = prev
|
||||
let start = prev
|
||||
.timestamp
|
||||
.checked_add(step)
|
||||
.ok_or_else(|| Error::Malformed("timestamp overflow while gap-filling".to_string()))?;
|
||||
while start < next_bucket {
|
||||
if start >= next_bucket {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Compute the gap size up-front so an adversarial timestamp delta
|
||||
// is refused before we allocate. `step > 0` by `Timeframe::new`'s
|
||||
// invariant, so the divisor is safe. Saturating the subtraction
|
||||
// makes the arithmetic infallible; an overflowed-saturated span is
|
||||
// still far above the cap so the limit check below catches it.
|
||||
let span = next_bucket.saturating_sub(start);
|
||||
let gap_count = span / step + i64::from(span % step != 0);
|
||||
|
||||
if gap_count > MAX_GAP_FILL_CANDLES {
|
||||
return Err(Error::Malformed(format!(
|
||||
"gap-fill between bucket {} and {next_bucket} would emit {gap_count} \
|
||||
flat candles at step {step}, exceeding the {MAX_GAP_FILL_CANDLES} \
|
||||
cap; reject the discontinuity instead of allocating",
|
||||
prev.timestamp
|
||||
)));
|
||||
}
|
||||
|
||||
out.reserve(gap_count as usize);
|
||||
let mut t = start;
|
||||
while t < next_bucket {
|
||||
// `prev.close` is finite (it came from a validated bar), so this
|
||||
// flat candle always passes `Candle::new`'s checks.
|
||||
out.push(Candle::new(
|
||||
prev.close, prev.close, prev.close, prev.close, 0.0, start,
|
||||
prev.close, prev.close, prev.close, prev.close, 0.0, t,
|
||||
)?);
|
||||
start = start.checked_add(step).ok_or_else(|| {
|
||||
t = t.checked_add(step).ok_or_else(|| {
|
||||
Error::Malformed("timestamp overflow while gap-filling".to_string())
|
||||
})?;
|
||||
}
|
||||
@@ -477,6 +518,37 @@ mod tests {
|
||||
assert_eq!(closed[0].timestamp, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gap_fill_rejects_runaway_timestamp_jump() {
|
||||
// An adversarial clock-glitch tick years in the future must surface
|
||||
// as an Error::Malformed rather than allocating millions of flat
|
||||
// candles and OOMing. Found by the `tick_aggregator` fuzz target.
|
||||
let mut agg = TickAggregator::new(Timeframe::new(60).unwrap()).with_gap_fill(true);
|
||||
agg.push(t(10.0, 0)).unwrap();
|
||||
// Two-billion-second jump = ~63 years of minute bars = ~33 million
|
||||
// candles, well above the 1_000_000 cap.
|
||||
let err = agg.push(t(20.0, 2_000_000_000)).unwrap_err();
|
||||
let msg = err.to_string();
|
||||
assert!(
|
||||
msg.contains("gap-fill") && msg.contains("cap"),
|
||||
"expected a malformed-gap error, got: {msg}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gap_fill_at_the_cap_succeeds() {
|
||||
// Exactly one million minute-buckets between the two ticks (one real
|
||||
// bar + one million flat fillers + the third tick's open bar) — the
|
||||
// limit is inclusive, so this must succeed.
|
||||
let mut agg = TickAggregator::new(Timeframe::new(60).unwrap()).with_gap_fill(true);
|
||||
agg.push(t(10.0, 0)).unwrap();
|
||||
// bucket 0 closes; jump straight to bucket 60_000_060 (1_000_001 buckets
|
||||
// away). fill_between emits 1_000_000 flat candles between them, then
|
||||
// the new tick opens its own bucket. Output: 1 real bar + 1_000_000 fillers.
|
||||
let out = agg.push(t(20.0, 60_000_060)).unwrap();
|
||||
assert_eq!(out.len(), 1 + MAX_GAP_FILL_CANDLES as usize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gap_fill_emits_flat_candles_for_skipped_buckets() {
|
||||
let mut agg = TickAggregator::new(Timeframe::new(60).unwrap()).with_gap_fill(true);
|
||||
|
||||
@@ -181,11 +181,12 @@ impl BinanceKlineStream {
|
||||
streams.join("/")
|
||||
);
|
||||
let url = url::Url::parse(&url).map_err(|e| Error::Malformed(e.to_string()))?;
|
||||
let ws_config = WebSocketConfig {
|
||||
max_message_size: Some(MAX_MESSAGE_SIZE),
|
||||
max_frame_size: Some(MAX_FRAME_SIZE),
|
||||
..WebSocketConfig::default()
|
||||
};
|
||||
// tokio-tungstenite 0.29's WebSocketConfig is #[non_exhaustive],
|
||||
// so the only way to set fields is via the builder-style methods on
|
||||
// a fresh `default()` value.
|
||||
let ws_config = WebSocketConfig::default()
|
||||
.max_message_size(Some(MAX_MESSAGE_SIZE))
|
||||
.max_frame_size(Some(MAX_FRAME_SIZE));
|
||||
let (socket, _) =
|
||||
tokio_tungstenite::connect_async_with_config(url.as_str(), Some(ws_config), false)
|
||||
.await?;
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
//! cargo run -p wickra-examples --bin fetch_btcusdt
|
||||
//! ```
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
use std::hint::black_box;
|
||||
use wickra::{
|
||||
Atr, BatchExt, BollingerBands, Candle, Ema, Indicator, MacdIndicator, Obv, Rsi, Sma,
|
||||
Stochastic, Wma,
|
||||
|
||||
+7
-7
@@ -26,12 +26,12 @@ open an issue on GitHub to discuss a separate license.
|
||||
|
||||
| Registry | Package | Version |
|
||||
|-----------|----------------|---------|
|
||||
| crates.io | `wickra` | 0.2.0 |
|
||||
| crates.io | `wickra-core` | 0.2.0 |
|
||||
| crates.io | `wickra-data` | 0.2.0 |
|
||||
| PyPI | `wickra` | 0.2.0 |
|
||||
| npm | `wickra` | 0.2.0 |
|
||||
| npm | `wickra-wasm` | 0.2.0 |
|
||||
| crates.io | `wickra` | 0.2.1 |
|
||||
| crates.io | `wickra-core` | 0.2.1 |
|
||||
| crates.io | `wickra-data` | 0.2.1 |
|
||||
| PyPI | `wickra` | 0.2.1 |
|
||||
| npm | `wickra` | 0.2.1 |
|
||||
| npm | `wickra-wasm` | 0.2.1 |
|
||||
|
||||
Release notes and tagged builds:
|
||||
<https://github.com/kingchenc/wickra/releases>.
|
||||
@@ -47,7 +47,7 @@ Release notes and tagged builds:
|
||||
- [Quickstart: Node](Quickstart-Node.md) — `npm install wickra`, basic
|
||||
`SMA` and `MACD` calls, and the install surface. Windows x64 was
|
||||
previously blocked by an npm spam filter on `wickra-win32-x64-msvc`;
|
||||
that was resolved with npm Support, and 0.2.0 is the first release in
|
||||
that was resolved with npm Support, and 0.2.1 is the first release in
|
||||
which `npm install wickra` works end-to-end on Windows.
|
||||
- [Quickstart: WASM](Quickstart-WASM.md) — `npm install wickra-wasm`,
|
||||
building with `wasm-pack`, and running indicators client-side in a
|
||||
|
||||
@@ -10,12 +10,12 @@ slow JS reimplementation.
|
||||
npm install wickra
|
||||
```
|
||||
|
||||
> **Windows install (0.2.0+).** Earlier patch releases were blocked on
|
||||
> **Windows install (0.2.1+).** Earlier patch releases were blocked on
|
||||
> Windows x64 because the platform-specific sub-package
|
||||
> `wickra-win32-x64-msvc` was held back by npm's automated spam filter, so
|
||||
> `require('wickra')` threw `Error: Cannot find module
|
||||
> 'wickra-win32-x64-msvc'` after a successful `npm install`. npm Support
|
||||
> released the name on 2026-05-22; 0.2.0 is the first version in which
|
||||
> released the name on 2026-05-22; 0.2.1 is the first version in which
|
||||
> Windows x64 installs cleanly end-to-end (version numbers `0.1.1`–`0.1.4`
|
||||
> of that sub-package remain burned and cannot be republished — see the
|
||||
> npm registry page for `wickra-win32-x64-msvc`). Linux x64, Linux arm64
|
||||
@@ -135,7 +135,7 @@ The complete TypeScript definitions live at
|
||||
| `batch(...)` | Single-output: flat `Array<number>` with `NaN` warmup.<br>Multi-output: flat interleaved `Array<number>`. |
|
||||
| `reset()` | Returns to a freshly-constructed state. |
|
||||
| `isReady()` | `true` once the first value has been emitted. |
|
||||
| `warmupPeriod()` | Present on every indicator class (single- and multi-output, scalar- and candle-input) since `0.2.0`. |
|
||||
| `warmupPeriod()` | Present on every indicator class (single- and multi-output, scalar- and candle-input) since `0.2.1`. |
|
||||
|
||||
A complete reference run lives in `bindings/node/__tests__/smoke.test.js`:
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ build. The `wickra` crate is a thin façade that re-exports everything from
|
||||
`wickra-core`; you can also depend on `wickra-core` directly if you want to
|
||||
skip the façade.
|
||||
|
||||
The published crate is at version `0.2.0` on
|
||||
The published crate is at version `0.2.1` on
|
||||
[crates.io](https://crates.io/crates/wickra).
|
||||
|
||||
## The `Indicator` trait in 30 seconds
|
||||
|
||||
@@ -111,7 +111,7 @@ console.log(last);
|
||||
their fields per row (e.g. MACD: `[macd0, signal0, hist0, macd1, ...]`). The
|
||||
exact layout is documented in the generated `pkg/wickra_wasm.d.ts`.
|
||||
|
||||
> Since `wickra-wasm@0.2.0`, every candle-input indicator (ATR, ADX,
|
||||
> Since `wickra-wasm@0.2.1`, every candle-input indicator (ATR, ADX,
|
||||
> WilliamsR, CCI, MFI, PSAR, Keltner, Donchian, VWAP, RollingVWAP,
|
||||
> AwesomeOscillator, Aroon, Stochastic, OBV, and the rest of the
|
||||
> volume / volatility / trailing-stop / price-statistics families) exposes
|
||||
|
||||
@@ -160,7 +160,7 @@ const sma = new wickra.SMA(20);
|
||||
console.log(sma.warmupPeriod()); // -> 20
|
||||
```
|
||||
|
||||
(Since `wickra@0.2.0`, `warmupPeriod()` is exposed on every Node and
|
||||
(Since `wickra@0.2.1`, `warmupPeriod()` is exposed on every Node and
|
||||
WASM class — single- and multi-output — alongside `update()`, `reset()`
|
||||
and `isReady()`. Consult `bindings/node/index.d.ts` for the
|
||||
authoritative TypeScript surface.)
|
||||
|
||||
Reference in New Issue
Block a user