Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3950bf31b | ||
|
|
a0a7bc4e62 | ||
|
|
0c925aa9d5 | ||
|
|
d9e6807ca0 | ||
|
|
eb50ae4e90 | ||
|
|
4a12f60a88 | ||
|
|
8003572d92 | ||
|
|
db5bd5e028 | ||
|
|
2ef60874b9 | ||
|
|
d59cd44043 | ||
|
|
ee5ee6980e | ||
|
|
60b4705d7e | ||
|
|
08b2e5abd3 | ||
|
|
495d9edcc3 | ||
|
|
c32b802461 | ||
|
|
7e3be0d1ac | ||
|
|
1a90de89ea | ||
|
|
bb901fbd25 | ||
|
|
692473452f | ||
|
|
2a5b012068 | ||
|
|
513e1111d2 | ||
|
|
4b0bdef7c6 | ||
|
|
3e4b6c7e22 | ||
|
|
dd6a4affb2 | ||
|
|
e5e094d370 | ||
|
|
97940046d1 | ||
|
|
f7f0bfbc48 | ||
|
|
8ccfd638b2 | ||
|
|
452f270b4d | ||
|
|
baffebd3da | ||
|
|
e631e55195 | ||
|
|
63949f6fc8 | ||
|
|
92210eb7b8 | ||
|
|
c3029f2548 | ||
|
|
806ae22abe | ||
|
|
fb9c39d4cd | ||
|
|
b1653e2107 | ||
|
|
32e18cb3a3 | ||
|
|
dc0c3d1736 | ||
|
|
ad1231cde1 | ||
|
|
7ebb60b60a | ||
|
|
d7cb771a28 | ||
|
|
3e5a19c94a | ||
|
|
8bfe24ac1d | ||
|
|
395a2289f4 | ||
|
|
9973d1a6bf | ||
|
|
cb216668ee | ||
|
|
20c0002f8e | ||
|
|
99497eb062 | ||
|
|
7e51f31f02 | ||
|
|
3ee3fb67ec | ||
|
|
3ebcb3f758 |
@@ -30,9 +30,9 @@ assignees: ""
|
|||||||
## Environment
|
## Environment
|
||||||
|
|
||||||
- Wickra version:
|
- Wickra version:
|
||||||
- Language / binding: <!-- Rust crate / Python / Node / WASM / C ABI / C# (.NET) / Go / Java / R -->
|
- Language / binding: <!-- Rust crate / Python / Node.js / WASM / C / C++ / C# / Go / Java / R -->
|
||||||
- OS and architecture:
|
- OS and architecture:
|
||||||
- Rust / Python / Node / .NET version (If relevant):
|
- Rust / Python / Node.js / .NET version (If relevant):
|
||||||
|
|
||||||
## Additional context
|
## Additional context
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ assignees: []
|
|||||||
- [ ] Rust crate (`wickra`)
|
- [ ] Rust crate (`wickra`)
|
||||||
- [ ] Python (`pip install wickra`)
|
- [ ] Python (`pip install wickra`)
|
||||||
- [ ] Node.js (`npm install wickra`)
|
- [ ] Node.js (`npm install wickra`)
|
||||||
- [ ] WebAssembly
|
- [ ] WASM
|
||||||
- [ ] C ABI (`bindings/c`)
|
- [ ] C ABI (`bindings/c`)
|
||||||
- [ ] C# / .NET (`Wickra` on NuGet)
|
- [ ] C# (`Wickra` on NuGet)
|
||||||
- [ ] Go (`bindings/go`)
|
- [ ] Go (`bindings/go`)
|
||||||
- [ ] Java (`org.wickra:wickra` on Maven Central)
|
- [ ] Java (`org.wickra:wickra` on Maven Central)
|
||||||
- [ ] R (`bindings/r`)
|
- [ ] R (`bindings/r`)
|
||||||
@@ -31,7 +31,7 @@ assignees: []
|
|||||||
| Binding version | `e.g. python 0.4.2 / node 0.4.2` |
|
| Binding version | `e.g. python 0.4.2 / node 0.4.2` |
|
||||||
| OS / arch | `e.g. Windows 11 x86_64, Linux glibc` |
|
| OS / arch | `e.g. Windows 11 x86_64, Linux glibc` |
|
||||||
| Rust toolchain | `rustc --version` (If building from source) |
|
| Rust toolchain | `rustc --version` (If building from source) |
|
||||||
| Python / Node / .NET version | `python --version` / `node --version` / `dotnet --version` |
|
| Python / Node.js / .NET version | `python --version` / `node --version` / `dotnet --version` |
|
||||||
|
|
||||||
## Minimal reproducer
|
## Minimal reproducer
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ assignees: ""
|
|||||||
- [ ] Should be exposed in the Node binding
|
- [ ] Should be exposed in the Node binding
|
||||||
- [ ] Should be exposed in the WASM binding
|
- [ ] Should be exposed in the WASM binding
|
||||||
- [ ] Should be exposed in the C ABI
|
- [ ] Should be exposed in the C ABI
|
||||||
- [ ] Should be exposed in the C# / .NET binding
|
- [ ] Should be exposed in the C# binding
|
||||||
- [ ] Should be exposed in the Go binding
|
- [ ] Should be exposed in the Go binding
|
||||||
- [ ] Should be exposed in the Java binding
|
- [ ] Should be exposed in the Java binding
|
||||||
- [ ] Should be exposed in the R binding
|
- [ ] Should be exposed in the R binding
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ assignees: []
|
|||||||
## Affected code path
|
## Affected code path
|
||||||
|
|
||||||
- Indicator / API: `e.g. EMA.update`
|
- Indicator / API: `e.g. EMA.update`
|
||||||
- Binding: `Rust / Python / Node / Wasm / C ABI / C# (.NET) / Go / Java / R`
|
- Binding: `Rust / Python / Node.js / WASM / C / C++ / C# / Go / Java / R`
|
||||||
- Hot loop or one-shot call?
|
- Hot loop or one-shot call?
|
||||||
|
|
||||||
## Versions compared
|
## Versions compared
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ import wickra as ta
|
|||||||
## Environment (Only if relevant)
|
## Environment (Only if relevant)
|
||||||
|
|
||||||
- Wickra version: `e.g. 0.4.2`
|
- Wickra version: `e.g. 0.4.2`
|
||||||
- Binding: `Rust / Python / Node / Wasm / C ABI / C# (.NET) / Go / Java / R`
|
- Binding: `Rust / Python / Node.js / WASM / C / C++ / C# / Go / Java / R`
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
- [ ] `cargo clippy --workspace --all-targets -- -D warnings` is clean.
|
- [ ] `cargo clippy --workspace --all-targets -- -D warnings` is clean.
|
||||||
- [ ] `cargo test --workspace` passes.
|
- [ ] `cargo test --workspace` passes.
|
||||||
- [ ] New behaviour has tests; bug fixes have a regression test.
|
- [ ] New behaviour has tests; bug fixes have a regression test.
|
||||||
- [ ] Public API changes are mirrored in the Python / Node / WASM bindings, and the C ABI + C# + Go + Java + R bindings are regenerated
|
- [ ] Public API changes are mirrored in the Python / Node.js / WASM bindings, and the C ABI + C# + Go + Java + R bindings are regenerated
|
||||||
and their type stubs (If applicable).
|
and their type stubs (If applicable).
|
||||||
- [ ] The relevant page on the [documentation site](https://docs.wickra.org)
|
- [ ] The relevant page on the [documentation site](https://docs.wickra.org)
|
||||||
and the `README.md` are updated (If applicable). Docs edits go to a
|
and the `README.md` are updated (If applicable). Docs edits go to a
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ Please fill in the sections below. Delete any that don't apply.
|
|||||||
- [ ] Rust crate (`crates/wickra`)
|
- [ ] Rust crate (`crates/wickra`)
|
||||||
- [ ] Python binding (`bindings/python`)
|
- [ ] Python binding (`bindings/python`)
|
||||||
- [ ] Node.js binding (`bindings/node`)
|
- [ ] Node.js binding (`bindings/node`)
|
||||||
- [ ] WebAssembly binding (`bindings/wasm`)
|
- [ ] WASM binding (`bindings/wasm`)
|
||||||
- [ ] C ABI (`bindings/c`)
|
- [ ] C ABI (`bindings/c`)
|
||||||
- [ ] C# / .NET binding (`bindings/csharp`)
|
- [ ] C# binding (`bindings/csharp`)
|
||||||
- [ ] Go binding (`bindings/go`)
|
- [ ] Go binding (`bindings/go`)
|
||||||
- [ ] Java binding (`bindings/java`)
|
- [ ] Java binding (`bindings/java`)
|
||||||
- [ ] R binding (`bindings/r`)
|
- [ ] R binding (`bindings/r`)
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ updates:
|
|||||||
default-days: 7
|
default-days: 7
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: "deps(cargo)"
|
prefix: "deps(cargo)"
|
||||||
|
groups:
|
||||||
|
cargo:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
# Node binding npm dependencies.
|
# Node binding npm dependencies.
|
||||||
- package-ecosystem: npm
|
- package-ecosystem: npm
|
||||||
@@ -21,6 +24,9 @@ updates:
|
|||||||
default-days: 7
|
default-days: 7
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: "deps(npm)"
|
prefix: "deps(npm)"
|
||||||
|
groups:
|
||||||
|
node-binding:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
# Python binding pip dependencies.
|
# Python binding pip dependencies.
|
||||||
- package-ecosystem: pip
|
- package-ecosystem: pip
|
||||||
@@ -32,6 +38,9 @@ updates:
|
|||||||
default-days: 7
|
default-days: 7
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: "deps(pip)"
|
prefix: "deps(pip)"
|
||||||
|
groups:
|
||||||
|
python-binding:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
# Hash-pinned CI/bench Python tooling under .github/requirements/. Each
|
# Hash-pinned CI/bench Python tooling under .github/requirements/. Each
|
||||||
# <name>.in is the loose source; the matching hash-locked <name>.txt is the
|
# <name>.in is the loose source; the matching hash-locked <name>.txt is the
|
||||||
@@ -47,6 +56,9 @@ updates:
|
|||||||
default-days: 7
|
default-days: 7
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: "deps(ci-pip)"
|
prefix: "deps(ci-pip)"
|
||||||
|
groups:
|
||||||
|
ci-pip:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
# GitHub Actions — keeps the SHA-pinned actions current (Dependabot reads
|
# GitHub Actions — keeps the SHA-pinned actions current (Dependabot reads
|
||||||
# the version comment after each pinned SHA and bumps both together).
|
# the version comment after each pinned SHA and bumps both together).
|
||||||
@@ -59,3 +71,73 @@ updates:
|
|||||||
default-days: 7
|
default-days: 7
|
||||||
commit-message:
|
commit-message:
|
||||||
prefix: "deps(actions)"
|
prefix: "deps(actions)"
|
||||||
|
groups:
|
||||||
|
github-actions:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
|
# Java binding + examples (Maven). Tracks the C-ABI binding's build plugins
|
||||||
|
# (e.g. central-publishing-maven-plugin) and the examples' jackson dependency,
|
||||||
|
# which had no Dependabot coverage before — a stale publishing plugin slipped
|
||||||
|
# through unnoticed until an OSV scan flagged it.
|
||||||
|
- package-ecosystem: maven
|
||||||
|
directories:
|
||||||
|
- "/bindings/java"
|
||||||
|
- "/bindings/java/benchmarks"
|
||||||
|
- "/examples/java"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
commit-message:
|
||||||
|
prefix: "deps(maven)"
|
||||||
|
groups:
|
||||||
|
maven:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
|
# C# binding (NuGet). The published Wickra.csproj is a thin C-ABI wrapper with
|
||||||
|
# no external packages, but the test and benchmark projects pull xunit,
|
||||||
|
# Microsoft.NET.Test.Sdk and BenchmarkDotNet.
|
||||||
|
- package-ecosystem: nuget
|
||||||
|
directories:
|
||||||
|
- "/bindings/csharp/Wickra.Tests"
|
||||||
|
- "/bindings/csharp/benchmarks"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
commit-message:
|
||||||
|
prefix: "deps(nuget)"
|
||||||
|
groups:
|
||||||
|
nuget:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
|
# Node examples (npm) — separate from the binding's own package.json.
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: "/examples/node"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
commit-message:
|
||||||
|
prefix: "deps(npm)"
|
||||||
|
groups:
|
||||||
|
node-examples:
|
||||||
|
patterns: ["*"]
|
||||||
|
|
||||||
|
# Go examples (Go modules). The binding's own go.mod has no external deps;
|
||||||
|
# the examples pull coder/websocket.
|
||||||
|
- package-ecosystem: gomod
|
||||||
|
directory: "/examples/go"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
cooldown:
|
||||||
|
default-days: 7
|
||||||
|
commit-message:
|
||||||
|
prefix: "deps(gomod)"
|
||||||
|
groups:
|
||||||
|
go-examples:
|
||||||
|
patterns: ["*"]
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
name: Cross-library benchmark report
|
name: Cross-library benchmark report
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ jobs:
|
|||||||
name: Rust cross-library benchmark report
|
name: Rust cross-library benchmark report
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|||||||
+70
-36
@@ -34,12 +34,13 @@ jobs:
|
|||||||
rust:
|
rust:
|
||||||
name: Rust ${{ matrix.os }}
|
name: Rust ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -104,8 +105,9 @@ jobs:
|
|||||||
examples-smoke:
|
examples-smoke:
|
||||||
name: Examples (syntax smoke)
|
name: Examples (syntax smoke)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -114,7 +116,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- name: Wait before Node retry
|
- name: Wait before Node retry
|
||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
@@ -127,7 +129,7 @@ jobs:
|
|||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
id: setup_python
|
id: setup_python
|
||||||
@@ -193,8 +195,9 @@ jobs:
|
|||||||
clippy-bindings:
|
clippy-bindings:
|
||||||
name: Clippy bindings
|
name: Clippy bindings
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -228,7 +231,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- name: Wait before Node retry
|
- name: Wait before Node retry
|
||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
@@ -241,7 +244,7 @@ jobs:
|
|||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- name: Cache cargo
|
- name: Cache cargo
|
||||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||||
@@ -276,6 +279,7 @@ jobs:
|
|||||||
msrv:
|
msrv:
|
||||||
name: ${{ matrix.name }}
|
name: ${{ matrix.name }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -287,7 +291,7 @@ jobs:
|
|||||||
toolchain: "1.88"
|
toolchain: "1.88"
|
||||||
packages: "-p wickra-node"
|
packages: "-p wickra-node"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -324,8 +328,9 @@ jobs:
|
|||||||
coverage:
|
coverage:
|
||||||
name: Coverage
|
name: Coverage
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -340,7 +345,7 @@ jobs:
|
|||||||
timeout-minutes: 6
|
timeout-minutes: 6
|
||||||
|
|
||||||
- name: Install cargo-llvm-cov
|
- name: Install cargo-llvm-cov
|
||||||
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6
|
||||||
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
||||||
with:
|
with:
|
||||||
tool: cargo-llvm-cov
|
tool: cargo-llvm-cov
|
||||||
@@ -365,8 +370,9 @@ jobs:
|
|||||||
supply-chain:
|
supply-chain:
|
||||||
name: Supply-chain (cargo-deny)
|
name: Supply-chain (cargo-deny)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -383,8 +389,9 @@ jobs:
|
|||||||
fuzz-smoke:
|
fuzz-smoke:
|
||||||
name: Fuzz (smoke)
|
name: Fuzz (smoke)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -408,7 +415,7 @@ jobs:
|
|||||||
# attributes the modern nightly compiler rejects, so the install
|
# attributes the modern nightly compiler rejects, so the install
|
||||||
# never gets off the ground. The prebuilt binary avoids the entire
|
# never gets off the ground. The prebuilt binary avoids the entire
|
||||||
# transitive-dep compile.
|
# transitive-dep compile.
|
||||||
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6
|
||||||
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
||||||
with:
|
with:
|
||||||
tool: cargo-fuzz
|
tool: cargo-fuzz
|
||||||
@@ -436,13 +443,14 @@ jobs:
|
|||||||
python:
|
python:
|
||||||
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
python-version: ["3.9", "3.11", "3.12", "3.13"]
|
python-version: ["3.9", "3.11", "3.12", "3.13"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -517,8 +525,9 @@ jobs:
|
|||||||
wasm:
|
wasm:
|
||||||
name: WASM build
|
name: WASM build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -540,7 +549,7 @@ jobs:
|
|||||||
# same taiki-e prebuilt-binary installer we already use for
|
# same taiki-e prebuilt-binary installer we already use for
|
||||||
# cargo-llvm-cov and cargo-fuzz; it tracks the latest wasm-pack
|
# cargo-llvm-cov and cargo-fuzz; it tracks the latest wasm-pack
|
||||||
# release, which has `--features` as a top-level flag (since 0.12).
|
# release, which has `--features` as a top-level flag (since 0.12).
|
||||||
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6
|
||||||
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
||||||
with:
|
with:
|
||||||
tool: wasm-pack
|
tool: wasm-pack
|
||||||
@@ -560,13 +569,14 @@ jobs:
|
|||||||
node:
|
node:
|
||||||
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
|
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
node-version: ["18", "20"]
|
node-version: ["22", "24"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -618,19 +628,28 @@ jobs:
|
|||||||
# exist yet for win32-x64-msvc).
|
# exist yet for win32-x64-msvc).
|
||||||
run: npx napi build --platform --release
|
run: npx napi build --platform --release
|
||||||
|
|
||||||
|
# The Node test process has wedged on macOS runners (the step hung for
|
||||||
|
# 1h+ while the same tests passed in ~1.5 min elsewhere). Wrap it so a
|
||||||
|
# hung attempt is killed after 6 min and retried once, rather than
|
||||||
|
# running up to the job-level backstop. A normal run is under a minute.
|
||||||
- name: Run Node tests
|
- name: Run Node tests
|
||||||
working-directory: bindings/node
|
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
|
||||||
run: node --test __tests__/
|
with:
|
||||||
|
timeout_minutes: 6
|
||||||
|
max_attempts: 2
|
||||||
|
command: cd bindings/node && node --test
|
||||||
|
shell: bash
|
||||||
|
|
||||||
c-abi:
|
c-abi:
|
||||||
name: C ABI on ${{ matrix.os }}
|
name: C ABI on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -643,7 +662,7 @@ jobs:
|
|||||||
timeout-minutes: 6
|
timeout-minutes: 6
|
||||||
|
|
||||||
- name: Install cbindgen
|
- name: Install cbindgen
|
||||||
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6
|
||||||
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
||||||
with:
|
with:
|
||||||
tool: cbindgen
|
tool: cbindgen
|
||||||
@@ -680,12 +699,13 @@ jobs:
|
|||||||
csharp:
|
csharp:
|
||||||
name: C# on ${{ matrix.os }}
|
name: C# on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -730,12 +750,13 @@ jobs:
|
|||||||
go:
|
go:
|
||||||
name: Go on ${{ matrix.os }}
|
name: Go on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -745,7 +766,7 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
id: setup-go
|
id: setup-go
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
|
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
cache: false
|
cache: false
|
||||||
@@ -759,7 +780,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up Go (retry)
|
- name: Set up Go (retry)
|
||||||
if: steps.setup-go.outcome == 'failure'
|
if: steps.setup-go.outcome == 'failure'
|
||||||
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
|
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
with:
|
with:
|
||||||
go-version: "stable"
|
go-version: "stable"
|
||||||
cache: false
|
cache: false
|
||||||
@@ -852,6 +873,7 @@ jobs:
|
|||||||
r:
|
r:
|
||||||
name: R on ${{ matrix.os }}
|
name: R on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -860,7 +882,7 @@ jobs:
|
|||||||
WICKRA_INCLUDE_DIR: ${{ github.workspace }}/bindings/c/include
|
WICKRA_INCLUDE_DIR: ${{ github.workspace }}/bindings/c/include
|
||||||
WICKRA_LIB_DIR: ${{ github.workspace }}/target/release
|
WICKRA_LIB_DIR: ${{ github.workspace }}/target/release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -904,6 +926,16 @@ jobs:
|
|||||||
R CMD INSTALL bindings/r
|
R CMD INSTALL bindings/r
|
||||||
Rscript -e 'library(testthat); library(wickra); test_dir("bindings/r/tests/testthat", stop_on_failure = TRUE)'
|
Rscript -e 'library(testthat); library(wickra); test_dir("bindings/r/tests/testthat", stop_on_failure = TRUE)'
|
||||||
|
|
||||||
|
- name: Build the vignette code
|
||||||
|
shell: bash
|
||||||
|
# The getting-started vignette runs at R CMD check time on r-universe /
|
||||||
|
# CRAN (with pandoc); this job only INSTALLs, so execute the vignette's R
|
||||||
|
# chunks here (knit, no pandoc needed) to catch a broken example before it
|
||||||
|
# reaches the published build.
|
||||||
|
run: |
|
||||||
|
Rscript -e 'install.packages("knitr", repos = Sys.getenv("RSPM", unset = "https://cloud.r-project.org"))'
|
||||||
|
Rscript -e 'knitr::knit("bindings/r/vignettes/getting-started.Rmd", output = tempfile(fileext = ".md"), quiet = TRUE); cat("vignette code OK\n")'
|
||||||
|
|
||||||
- name: Run the offline R examples
|
- name: Run the offline R examples
|
||||||
shell: bash
|
shell: bash
|
||||||
# No loader-path exports: the installed package is self-contained (bundled
|
# No loader-path exports: the installed package is self-contained (bundled
|
||||||
@@ -923,12 +955,13 @@ jobs:
|
|||||||
java:
|
java:
|
||||||
name: Java on ${{ matrix.os }}
|
name: Java on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 20 # backstop: cap a wedged job instead of GitHub's 6h default (slowest real job ~5 min)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -942,18 +975,19 @@ jobs:
|
|||||||
|
|
||||||
# The binding links the C ABI hub at runtime through the Java FFM API; build
|
# The binding links the C ABI hub at runtime through the Java FFM API; build
|
||||||
# it first so WickraNative's development fallback finds
|
# it first so WickraNative's development fallback finds
|
||||||
# target/release/wickra.{so,dylib,dll}. JDK 22+ is required for the final FFM
|
# target/release/wickra.{so,dylib,dll}. The FFM API is final since JDK 22; we
|
||||||
# API, so it is installed explicitly (runners ship 17/21).
|
# build on the 25 LTS (22 is EOL; the pom pins bytecode to release 22 so the
|
||||||
|
# runtime floor stays Java 22). Installed explicitly (runners ship 17/21).
|
||||||
- name: Build the C ABI library
|
- name: Build the C ABI library
|
||||||
run: cargo build -p wickra-c --release
|
run: cargo build -p wickra-c --release
|
||||||
|
|
||||||
- name: Set up JDK 22
|
- name: Set up JDK 25
|
||||||
id: setup-java
|
id: setup-java
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: "22"
|
java-version: "25"
|
||||||
cache: maven
|
cache: maven
|
||||||
|
|
||||||
- name: Retry JDK setup (CDN flake)
|
- name: Retry JDK setup (CDN flake)
|
||||||
@@ -963,12 +997,12 @@ jobs:
|
|||||||
echo "::warning::setup-java failed (likely CDN flake), waiting 30s before retry..."
|
echo "::warning::setup-java failed (likely CDN flake), waiting 30s before retry..."
|
||||||
sleep 30
|
sleep 30
|
||||||
|
|
||||||
- name: Set up JDK 22 (retry)
|
- name: Set up JDK 25 (retry)
|
||||||
if: steps.setup-java.outcome == 'failure'
|
if: steps.setup-java.outcome == 'failure'
|
||||||
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: "22"
|
java-version: "25"
|
||||||
cache: maven
|
cache: maven
|
||||||
|
|
||||||
- name: Java info
|
- name: Java info
|
||||||
|
|||||||
@@ -40,17 +40,17 @@ jobs:
|
|||||||
build-mode: none
|
build-mode: none
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # v3.36.0
|
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
build-mode: ${{ matrix.build-mode }}
|
build-mode: ${{ matrix.build-mode }}
|
||||||
|
|
||||||
- name: Perform CodeQL analysis
|
- name: Perform CodeQL analysis
|
||||||
uses: github/codeql-action/analyze@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # v3.36.0
|
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||||
with:
|
with:
|
||||||
category: "/language:${{ matrix.language }}"
|
category: "/language:${{ matrix.language }}"
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
# Settings -> Environments.
|
# Settings -> Environments.
|
||||||
environment: release
|
environment: release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||||
@@ -110,7 +110,7 @@ jobs:
|
|||||||
# consumers can audit the published dependency tree without
|
# consumers can audit the published dependency tree without
|
||||||
# re-resolving Cargo.lock.
|
# re-resolving Cargo.lock.
|
||||||
- name: Install cargo-cyclonedx
|
- name: Install cargo-cyclonedx
|
||||||
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6
|
||||||
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
||||||
with:
|
with:
|
||||||
tool: cargo-cyclonedx
|
tool: cargo-cyclonedx
|
||||||
@@ -157,7 +157,7 @@ jobs:
|
|||||||
- { os: windows-11-arm, target: aarch64, manylinux: auto }
|
- { os: windows-11-arm, target: aarch64, manylinux: auto }
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
@@ -197,7 +197,7 @@ jobs:
|
|||||||
name: Build Python sdist
|
name: Build Python sdist
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Sync root README into bindings/python so it ships in the sdist
|
- name: Sync root README into bindings/python so it ships in the sdist
|
||||||
@@ -249,7 +249,7 @@ jobs:
|
|||||||
- { host: windows-11-arm, target: aarch64-pc-windows-msvc }
|
- { host: windows-11-arm, target: aarch64-pc-windows-msvc }
|
||||||
runs-on: ${{ matrix.host }}
|
runs-on: ${{ matrix.host }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -258,7 +258,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- name: Wait before Node retry
|
- name: Wait before Node retry
|
||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
@@ -271,7 +271,7 @@ jobs:
|
|||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||||
with:
|
with:
|
||||||
@@ -310,7 +310,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- name: Wait before Node retry
|
- name: Wait before Node retry
|
||||||
@@ -333,7 +333,7 @@ jobs:
|
|||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- name: Install Node deps
|
- name: Install Node deps
|
||||||
@@ -479,7 +479,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -488,7 +488,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- name: Wait before Node retry
|
- name: Wait before Node retry
|
||||||
@@ -502,7 +502,7 @@ jobs:
|
|||||||
if: steps.setup_node.outcome == 'failure'
|
if: steps.setup_node.outcome == 'failure'
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||||
@@ -512,7 +512,7 @@ jobs:
|
|||||||
- name: Install wasm-pack (latest, via prebuilt binary)
|
- name: Install wasm-pack (latest, via prebuilt binary)
|
||||||
# See the matching note in ci.yml: jetli's default installs an old
|
# See the matching note in ci.yml: jetli's default installs an old
|
||||||
# 0.10.x wasm-pack whose build subcommand rejects --features.
|
# 0.10.x wasm-pack whose build subcommand rejects --features.
|
||||||
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6
|
||||||
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
||||||
with:
|
with:
|
||||||
tool: wasm-pack
|
tool: wasm-pack
|
||||||
@@ -588,7 +588,7 @@ jobs:
|
|||||||
- { host: windows-11-arm, target: aarch64-pc-windows-msvc }
|
- { host: windows-11-arm, target: aarch64-pc-windows-msvc }
|
||||||
runs-on: ${{ matrix.host }}
|
runs-on: ${{ matrix.host }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -638,7 +638,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
id-token: write # request the GitHub OIDC token for trusted publishing
|
id-token: write # request the GitHub OIDC token for trusted publishing
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -718,7 +718,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: release
|
environment: release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -757,11 +757,11 @@ jobs:
|
|||||||
|
|
||||||
# setup-java writes a settings.xml with the 'central' server credentials
|
# setup-java writes a settings.xml with the 'central' server credentials
|
||||||
# (mapped from the env vars below) and imports the GPG signing key.
|
# (mapped from the env vars below) and imports the GPG signing key.
|
||||||
- name: Set up JDK 22 + Maven Central credentials + GPG
|
- name: Set up JDK 25 + Maven Central credentials + GPG
|
||||||
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: "22"
|
java-version: "25"
|
||||||
server-id: central
|
server-id: central
|
||||||
server-username: CENTRAL_USERNAME
|
server-username: CENTRAL_USERNAME
|
||||||
server-password: CENTRAL_PASSWORD
|
server-password: CENTRAL_PASSWORD
|
||||||
@@ -788,7 +788,7 @@ jobs:
|
|||||||
needs: c-abi-build
|
needs: c-abi-build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -876,8 +876,9 @@ jobs:
|
|||||||
# bundle to this same release without re-resolving it.
|
# bundle to this same release without re-resolving it.
|
||||||
outputs:
|
outputs:
|
||||||
tag: ${{ steps.tag.outputs.tag }}
|
tag: ${{ steps.tag.outputs.tag }}
|
||||||
|
version: ${{ steps.tag.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
@@ -904,6 +905,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "version=${tag#v}" >> "$GITHUB_OUTPUT"
|
||||||
echo "::notice::attaching assets to release $tag"
|
echo "::notice::attaching assets to release $tag"
|
||||||
|
|
||||||
- name: Download all build artifacts
|
- name: Download all build artifacts
|
||||||
@@ -941,7 +943,7 @@ jobs:
|
|||||||
# the provenance bundle is attached (P24, immutability-ready).
|
# the provenance bundle is attached (P24, immutability-ready).
|
||||||
draft: true
|
draft: true
|
||||||
body: |
|
body: |
|
||||||
Wickra ${{ github.ref_name }} — streaming-first technical indicators across 4 language registries plus a C ABI.
|
Wickra ${{ github.ref_name }} — streaming-first technical indicators for 10 languages: native Rust, Python, Node.js, WASM plus a C ABI hub for C, C++, C#, Go, Java, R.
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|
||||||
@@ -950,21 +952,37 @@ jobs:
|
|||||||
pip install wickra
|
pip install wickra
|
||||||
npm install wickra
|
npm install wickra
|
||||||
npm install wickra-wasm
|
npm install wickra-wasm
|
||||||
|
dotnet add package Wickra
|
||||||
|
go get github.com/wickra-lib/wickra-go
|
||||||
|
```
|
||||||
|
|
||||||
|
Java (Gradle, Maven Central):
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
implementation("org.wickra:wickra:${{ steps.tag.outputs.version }}")
|
||||||
|
```
|
||||||
|
|
||||||
|
R (r-universe):
|
||||||
|
|
||||||
|
```r
|
||||||
|
install.packages("wickra", repos = "https://wickra-lib.r-universe.dev")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Attached assets
|
### Attached assets
|
||||||
|
|
||||||
Pre-built artefacts for every supported platform — the same files that
|
Pre-built artefacts for every supported platform — the same files this
|
||||||
were uploaded to crates.io, PyPI, and npm by this workflow run.
|
workflow run published to crates.io, PyPI, and npm. C# ships to NuGet,
|
||||||
|
Java to Maven Central, Go to the wickra-go module, and R to r-universe
|
||||||
|
via their own release jobs.
|
||||||
|
|
||||||
- `*.whl` / `wickra-*.tar.gz` — Python wheels + sdist (5 platforms, ABI3 ≥ 3.9)
|
- `*.whl` / `wickra-*.tar.gz` — Python wheels + sdist (5 platforms, ABI3 ≥ 3.9)
|
||||||
- `wickra.*.node` — native Node bindings (linux-x64-gnu, darwin-x64,
|
- `wickra.*.node` — native Node.js bindings (linux-x64-gnu, darwin-x64,
|
||||||
darwin-arm64, win32-x64-msvc)
|
darwin-arm64, win32-x64-msvc)
|
||||||
- `wickra-*.tgz` — npm-pack tarballs (main package + per-platform subpackages + WASM)
|
- `wickra-*.tgz` — npm-pack tarballs (main package + per-platform subpackages + WASM)
|
||||||
- `*.crate` — cargo source crates (wickra-core, wickra-data, wickra)
|
- `*.crate` — cargo source crates (wickra-core, wickra-data, wickra)
|
||||||
- `wickra-c-<target>.tar.gz` — C ABI: `include/wickra.h` + `wickra.hpp`
|
- `wickra-c-<target>.tar.gz` — C ABI: `include/wickra.h` + `wickra.hpp`
|
||||||
and the cdylib/staticlib per target (linux/macos/windows × x64/arm64),
|
and the cdylib/staticlib per target (linux/macos/windows × x64/arm64),
|
||||||
the hub for C / C++ / Go / C# / Java / R
|
the hub for C, C++, C#, Go, Java and R
|
||||||
|
|
||||||
### Auto-generated changelog
|
### Auto-generated changelog
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
id-token: write # OIDC token to publish results to the OpenSSF API
|
id-token: write # OIDC token to publish results to the OpenSSF API
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -51,6 +51,6 @@ jobs:
|
|||||||
retention-days: 5
|
retention-days: 5
|
||||||
|
|
||||||
- name: Upload SARIF to code-scanning
|
- name: Upload SARIF to code-scanning
|
||||||
uses: github/codeql-action/upload-sarif@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # v3.36.0
|
uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ jobs:
|
|||||||
# Fetching the now-gone `refs/heads/<branch>` then fails the run (exit 1).
|
# Fetching the now-gone `refs/heads/<branch>` then fails the run (exit 1).
|
||||||
# The head SHA stays reachable via `refs/pull/N/head` after the branch is
|
# The head SHA stays reachable via `refs/pull/N/head` after the branch is
|
||||||
# gone, so the checkout — and the run — survives an instant merge.
|
# gone, so the checkout — and the run — survives an instant merge.
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
@@ -341,13 +341,19 @@ jobs:
|
|||||||
# are never matched.
|
# are never matched.
|
||||||
sed -i -E "s/^(\| \[?(crates\.io|PyPI|npm|NuGet|Maven Central|Go|r-universe)\]?.*\| )[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" overview.md
|
sed -i -E "s/^(\| \[?(crates\.io|PyPI|npm|NuGet|Maven Central|Go|r-universe)\]?.*\| )[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" overview.md
|
||||||
sed -i -E "s/(published crate is at version .)[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" Quickstart-Rust.md
|
sed -i -E "s/(published crate is at version .)[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" Quickstart-Rust.md
|
||||||
|
# Quickstart-Java is the only quickstart whose install block pins a
|
||||||
|
# version (the Maven `<version>` tag and the `org.wickra:wickra:<v>`
|
||||||
|
# Gradle coordinate). Java publishes on every release, so it tracks the
|
||||||
|
# same ${version}.
|
||||||
|
sed -i -E "s|<version>[0-9]+\.[0-9]+\.[0-9]+</version>|<version>${version}</version>|" Quickstart-Java.md
|
||||||
|
sed -i -E "s|(org\.wickra:wickra:)[0-9]+\.[0-9]+\.[0-9]+|\1${version}|" Quickstart-Java.md
|
||||||
if git diff --quiet; then
|
if git diff --quiet; then
|
||||||
echo "Docs version already at ${version}."
|
echo "Docs version already at ${version}."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
git config user.name "wickra-bot"
|
git config user.name "wickra-bot"
|
||||||
git config user.email "wickra-bot@users.noreply.github.com"
|
git config user.email "wickra-bot@users.noreply.github.com"
|
||||||
git add overview.md Quickstart-Rust.md
|
git add overview.md Quickstart-Rust.md Quickstart-Java.md
|
||||||
git commit -m "chore: sync published version to ${version}"
|
git commit -m "chore: sync published version to ${version}"
|
||||||
if ! git push 2>/dev/null; then
|
if ! git push 2>/dev/null; then
|
||||||
echo "::warning::push to wickra-lib/wickra-docs failed — ABOUT_SYNC_TOKEN likely lacks write (findings P10.0a)."
|
echo "::warning::push to wickra-lib/wickra-docs failed — ABOUT_SYNC_TOKEN likely lacks write (findings P10.0a)."
|
||||||
@@ -433,6 +439,14 @@ jobs:
|
|||||||
sed -i -E "s/(Latest:\*\* \[.wickra(-wasm)? )[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" api/*.md
|
sed -i -E "s/(Latest:\*\* \[.wickra(-wasm)? )[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" api/*.md
|
||||||
sed -i -E "s/(text: .v)[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" .vitepress/config.ts
|
sed -i -E "s/(text: .v)[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" .vitepress/config.ts
|
||||||
sed -i -E "s/(.wickra-wasm.: .\^)[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" package.json
|
sed -i -E "s/(.wickra-wasm.: .\^)[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" package.json
|
||||||
|
# Java is the only target whose install snippet pins a version: the
|
||||||
|
# Maven `<version>` tag in the api/java.md dependency block and the
|
||||||
|
# home-page install tab in index.md, plus any `org.wickra:wickra:<v>`
|
||||||
|
# Gradle coordinate. Java publishes on every release, so it tracks the
|
||||||
|
# same ${version} as the rest. (Other languages' api/*.md carry a
|
||||||
|
# "Latest:" line handled above; Java uses the XML snippet instead.)
|
||||||
|
sed -i -E "s|<version>[0-9]+\.[0-9]+\.[0-9]+</version>|<version>${version}</version>|" api/java.md index.md
|
||||||
|
sed -i -E "s|(org\.wickra:wickra:)[0-9]+\.[0-9]+\.[0-9]+|\1${version}|" api/java.md index.md
|
||||||
# Keep package-lock.json in sync with the package.json bump. The site's
|
# Keep package-lock.json in sync with the package.json bump. The site's
|
||||||
# Cloudflare build runs `npm clean-install` (npm ci), which hard-fails
|
# Cloudflare build runs `npm clean-install` (npm ci), which hard-fails
|
||||||
# with EUSAGE if the lockfile still pins the previous wickra-wasm —
|
# with EUSAGE if the lockfile still pins the previous wickra-wasm —
|
||||||
@@ -451,7 +465,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
git config user.name "wickra-bot"
|
git config user.name "wickra-bot"
|
||||||
git config user.email "wickra-bot@users.noreply.github.com"
|
git config user.email "wickra-bot@users.noreply.github.com"
|
||||||
git add api/*.md .vitepress/config.ts package.json package-lock.json
|
git add api/*.md index.md .vitepress/config.ts package.json package-lock.json
|
||||||
git commit -m "chore: sync published version to ${version}"
|
git commit -m "chore: sync published version to ${version}"
|
||||||
if ! git push 2>/dev/null; then
|
if ! git push 2>/dev/null; then
|
||||||
echo "::warning::push to wickra-lib/webpage failed — ABOUT_SYNC_TOKEN likely lacks write (findings P10.0a)."
|
echo "::warning::push to wickra-lib/webpage failed — ABOUT_SYNC_TOKEN likely lacks write (findings P10.0a)."
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
name: metadata audit
|
name: metadata audit
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
actions: read # online audits resolve referenced actions
|
actions: read # online audits resolve referenced actions
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ bindings/node/npm-debug.log*
|
|||||||
|
|
||||||
# WASM build output
|
# WASM build output
|
||||||
bindings/wasm/pkg/
|
bindings/wasm/pkg/
|
||||||
|
bindings/wasm/pkg-node/
|
||||||
|
|
||||||
# Python venv
|
# Python venv
|
||||||
.venv/
|
.venv/
|
||||||
|
|||||||
+20
-17
@@ -7,7 +7,7 @@ for the day-to-day workflow.
|
|||||||
|
|
||||||
## Workspace layout
|
## Workspace layout
|
||||||
|
|
||||||
Wickra is a Cargo workspace of three Rust crates plus three binding crates.
|
Wickra is a Cargo workspace of three Rust crates plus four binding crates.
|
||||||
The split is deliberate: every concern that one user might want to disable
|
The split is deliberate: every concern that one user might want to disable
|
||||||
or replace lives behind a separate crate boundary.
|
or replace lives behind a separate crate boundary.
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ or replace lives behind a separate crate boundary.
|
|||||||
┌───────────▼──────────┐ ┌──────────▼─────────┐
|
┌───────────▼──────────┐ ┌──────────▼─────────┐
|
||||||
│ wickra-core │ │ wickra-data │
|
│ wickra-core │ │ wickra-data │
|
||||||
│ indicator engine │ │ i/o + aggregation │
|
│ indicator engine │ │ i/o + aggregation │
|
||||||
│ • 214 indicators │ │ • CSV reader │
|
│ • 514 indicators │ │ • CSV reader │
|
||||||
│ • Indicator trait │ │ • Tick aggregator │
|
│ • Indicator trait │ │ • Tick aggregator │
|
||||||
│ • BatchExt impl │ │ • Resampler │
|
│ • BatchExt impl │ │ • Resampler │
|
||||||
│ • OHLCV / Candle │ │ • Live feeds │
|
│ • OHLCV / Candle │ │ • Live feeds │
|
||||||
@@ -31,7 +31,7 @@ or replace lives behind a separate crate boundary.
|
|||||||
┌────────────┼────────────┬────────────────┐
|
┌────────────┼────────────┬────────────────┐
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
┌──▼───────┐ ┌──▼───────┐ ┌──▼───────────┐ ┌──▼──────────────────┐
|
┌──▼───────┐ ┌──▼───────┐ ┌──▼───────────┐ ┌──▼──────────────────┐
|
||||||
│ Python │ │ Node │ │ WASM │ │ C ABI (cbindgen) │
|
│ Python │ │ Node.js │ │ WASM │ │ C ABI (cbindgen) │
|
||||||
│ (PyO3) │ │ (napi-rs)│ │(wasm-bindgen)│ │ cdylib + header │
|
│ (PyO3) │ │ (napi-rs)│ │(wasm-bindgen)│ │ cdylib + header │
|
||||||
└──────────┘ └──────────┘ └──────────────┘ └─────────┬───────────┘
|
└──────────┘ └──────────┘ └──────────────┘ └─────────┬───────────┘
|
||||||
│ linked by
|
│ linked by
|
||||||
@@ -41,11 +41,11 @@ or replace lives behind a separate crate boundary.
|
|||||||
└─────────────────────┘
|
└─────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
Python, Node and WASM are *native* Rust bindings (PyO3 / napi-rs /
|
Python, Node.js and WASM are *native* Rust bindings (PyO3 / napi-rs /
|
||||||
wasm-bindgen). The C ABI is the *hub* every other C-capable language links
|
wasm-bindgen). The C ABI is the *hub* every other C-capable language links
|
||||||
against: it builds to a `cdylib`/`staticlib` plus a generated `wickra.h`, and
|
against: it builds to a `cdylib`/`staticlib` plus a generated `wickra.h`, and
|
||||||
downstream languages link that one artifact rather than each re-wrapping the
|
downstream languages link that one artifact rather than each re-wrapping the
|
||||||
core. C and C++ link it directly; the **C# / .NET** binding (`bindings/csharp`,
|
core. C and C++ link it directly; the **C#** binding (`bindings/csharp`,
|
||||||
on NuGet), the **Go** binding (`bindings/go`, cgo), the **R** binding
|
on NuGet), the **Go** binding (`bindings/go`, cgo), the **R** binding
|
||||||
(`bindings/r`, `.Call`) and the **Java** binding (`bindings/java`, the Java FFM
|
(`bindings/r`, `.Call`) and the **Java** binding (`bindings/java`, the Java FFM
|
||||||
API / Panama, on Maven Central) are all generated from `wickra.h`.
|
API / Panama, on Maven Central) are all generated from `wickra.h`.
|
||||||
@@ -57,7 +57,7 @@ API / Panama, on Maven Central) are all generated from `wickra.h`.
|
|||||||
| `wickra-data` | `crates/wickra-data` | CSV reader, tick aggregator, resampler, live exchange feeds (feature-gated) | `tokio`, `tokio-tungstenite` (live), `serde_json` |
|
| `wickra-data` | `crates/wickra-data` | CSV reader, tick aggregator, resampler, live exchange feeds (feature-gated) | `tokio`, `tokio-tungstenite` (live), `serde_json` |
|
||||||
| `wickra-python` | `bindings/python` | `_wickra` PyO3 module + Python package | `pyo3`, `numpy`, depends on `wickra-core` |
|
| `wickra-python` | `bindings/python` | `_wickra` PyO3 module + Python package | `pyo3`, `numpy`, depends on `wickra-core` |
|
||||||
| `wickra-node` | `bindings/node` | NAPI-RS native binding | `napi`, depends on `wickra-core` |
|
| `wickra-node` | `bindings/node` | NAPI-RS native binding | `napi`, depends on `wickra-core` |
|
||||||
| `wickra-wasm` | `bindings/wasm` | WebAssembly binding | `wasm-bindgen`, depends on `wickra-core` |
|
| `wickra-wasm` | `bindings/wasm` | WASM binding | `wasm-bindgen`, depends on `wickra-core` |
|
||||||
| `wickra-c` | `bindings/c` | C ABI hub — `cdylib`/`staticlib` + generated `wickra.h` (cbindgen) | depends on `wickra-core` |
|
| `wickra-c` | `bindings/c` | C ABI hub — `cdylib`/`staticlib` + generated `wickra.h` (cbindgen) | depends on `wickra-core` |
|
||||||
| `wickra-examples` | `examples/rust` | runnable binary examples | depends on `wickra`, `wickra-data` |
|
| `wickra-examples` | `examples/rust` | runnable binary examples | depends on `wickra`, `wickra-data` |
|
||||||
|
|
||||||
@@ -203,14 +203,17 @@ typed object arrays for Node/WASM).
|
|||||||
|
|
||||||
A handful of indicators need care beyond naive accumulation:
|
A handful of indicators need care beyond naive accumulation:
|
||||||
|
|
||||||
- **Welford's online variance** is used in `StdDev`, `Variance`, `ZScore`,
|
- **Rolling variance is running-sum, not Welford.** The sliding-window
|
||||||
`BollingerBands`, and several others. Standard sum-of-squares is
|
variance family — `StdDev`, `Variance`, `ZScore`, `Bollinger` — keeps
|
||||||
catastrophically lossy for low-variance inputs; Welford's recurrence
|
running `Σx` and `Σx²` over the window and reports `var = Σx²/n − mean²`,
|
||||||
keeps O(eps) error.
|
clamping to zero the tiny negative values floating-point cancellation can
|
||||||
- **Kahan summation** is used wherever rolling sums could span > 1e6
|
produce. `Bollinger` periodically reseeds its `Σx²` from the live window
|
||||||
elements without resetting — currently only Hurst-exponent's R/S
|
so error cannot accumulate over a long stream. Welford's online algorithm
|
||||||
chunks. Most rolling sums are bounded by the window size and don't need
|
(an incremental `M2` accumulator) does **not** transfer cleanly to a
|
||||||
it.
|
sliding window — removing the oldest point from `M2` is numerically
|
||||||
|
unstable — so it is used only where the statistic is *not* a fixed
|
||||||
|
window: `IntradayVolatilityProfile` and `SeasonalZScore` accumulate
|
||||||
|
per-bucket variance that way.
|
||||||
- **Logarithm bases** matter for some indicators (Hurst, MFI). Wickra
|
- **Logarithm bases** matter for some indicators (Hurst, MFI). Wickra
|
||||||
uses natural log everywhere unless the reference math explicitly
|
uses natural log everywhere unless the reference math explicitly
|
||||||
requires `log10` or `log2` — and then it documents the choice in the
|
requires `log10` or `log2` — and then it documents the choice in the
|
||||||
@@ -327,9 +330,9 @@ re-discovering them.
|
|||||||
- **`FAMILIES` (from PR #60) is hand-maintained.** Adding a new
|
- **`FAMILIES` (from PR #60) is hand-maintained.** Adding a new
|
||||||
indicator requires a separate entry in `FAMILIES`. The
|
indicator requires a separate entry in `FAMILIES`. The
|
||||||
`total_count_matches_expected` test will fail if you forget.
|
`total_count_matches_expected` test will fail if you forget.
|
||||||
- **WASM does not have automated tests yet.** Smoke-validated only
|
- **WASM is covered by `wasm-bindgen-test`.** `bindings/wasm/src/lib.rs`
|
||||||
through the manual examples. Adding `wasm-bindgen-test` coverage is
|
carries 21 in-crate tests (run under `wasm-pack test` in CI), in
|
||||||
on the roadmap.
|
addition to the manual browser examples.
|
||||||
|
|
||||||
For the high-level project goals see [`ROADMAP.md`](ROADMAP.md); for
|
For the high-level project goals see [`ROADMAP.md`](ROADMAP.md); for
|
||||||
day-to-day contribution mechanics see [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
day-to-day contribution mechanics see [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
||||||
|
|||||||
@@ -94,3 +94,75 @@ cargo bench -p wickra-bench # Rust core vs kand / ta-rs / yata
|
|||||||
pip install -e bindings/python[bench] # Python peers
|
pip install -e bindings/python[bench] # Python peers
|
||||||
python -m benchmarks.compare_libraries
|
python -m benchmarks.compare_libraries
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 3. Per-binding throughput — the cost of the boundary
|
||||||
|
|
||||||
|
The sections above compare Wickra against other libraries, which only exists for
|
||||||
|
Python and Rust (there is no comparable streaming TA library for C, C++, C#, Go, Java,
|
||||||
|
R or WASM to benchmark against). Every binding calls the **same** Rust
|
||||||
|
core, so these per-binding benchmarks are **not** a speed claim and **not** a
|
||||||
|
cross-library ratio — they document the raw cost of crossing each language's FFI
|
||||||
|
boundary, in million updates per second (Mupd/s).
|
||||||
|
|
||||||
|
Each binding ships a small `throughput` benchmark that feeds a synthetic OHLCV
|
||||||
|
series through three indicators chosen by call-signature archetype — `SMA(20)`
|
||||||
|
(1-in → 1-out), `ATR(14)` (multi-in → 1-out) and `MACD(12,26,9)` (1-in →
|
||||||
|
multi-out). Two things fall out of the numbers:
|
||||||
|
|
||||||
|
- **Batch converges.** A `batch` call crosses the boundary once and the Rust core
|
||||||
|
computes the whole series internally, so batch throughput is roughly the same
|
||||||
|
in every binding — close to the core speed.
|
||||||
|
- **Streaming reveals the boundary.** A per-tick `update` crosses the boundary
|
||||||
|
once per value, so streaming throughput is where the bindings differ: the raw C
|
||||||
|
ABI and P/Invoke-style calls are nearly free, while managed or interpreted
|
||||||
|
per-call marshalling (cgo, FFM, the R/WASM boundary) costs more per tick.
|
||||||
|
|
||||||
|
The Rust core ships the same benchmark with **no** FFI boundary
|
||||||
|
(`examples/rust/.../throughput.rs`) — it is the ceiling each binding is measured
|
||||||
|
against and the value the batch paths converge towards.
|
||||||
|
|
||||||
|
`SMA(20)`, 200 000 bars, median of 3 runs, on the reference machine (Windows 11,
|
||||||
|
AMD Ryzen 9 9950X):
|
||||||
|
|
||||||
|
| Target | streaming (Mupd/s) | batch (Mupd/s) |
|
||||||
|
|----------------------|-------------------:|---------------:|
|
||||||
|
| Rust core (no FFI) | 391 | 500 |
|
||||||
|
| C / C++ | 383 | 330 |
|
||||||
|
| C# | 337 | 244 |
|
||||||
|
| Python | 33 | 488 |
|
||||||
|
| Java | 28 | 175 |
|
||||||
|
| Go | 24 | 400 |
|
||||||
|
| WASM | 19 | 167 |
|
||||||
|
| Node.js | 17 | 10 |
|
||||||
|
| R | 0.1 | 193 |
|
||||||
|
|
||||||
|
Streaming spans more than three orders of magnitude — the raw C ABI (383) is
|
||||||
|
nearly the FFI-free Rust ceiling (391), while R's per-call interpreter overhead
|
||||||
|
(0.1) makes streaming ~2000× slower than its own batch. Batch converges near the
|
||||||
|
core speed for the zero-copy bindings (numpy, slices, typed arrays); the two
|
||||||
|
outliers are Node — whose napi `batch` boxes every element into a JS `Array` —
|
||||||
|
and R. These are machine-dependent and reflect FFI overhead, not algorithm
|
||||||
|
speed.
|
||||||
|
|
||||||
|
These are throughput numbers, not competitive numbers — the "Wickra is fast"
|
||||||
|
claim lives in sections 1 and 2 (Rust core + the Python/Rust cross-library runs).
|
||||||
|
|
||||||
|
Run any target's benchmark (build the C ABI library first where it links one):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo run -p wickra-examples --release --bin throughput # Rust core baseline (no FFI)
|
||||||
|
|
||||||
|
node bindings/node/benchmarks/throughput.js # native napi-rs
|
||||||
|
( cd bindings/python && python -m benchmarks.throughput ) # native PyO3
|
||||||
|
( cd bindings/wasm && wasm-pack build --target nodejs --out-dir pkg-node --release ) \
|
||||||
|
&& node bindings/wasm/benchmarks/throughput.mjs # wasm boundary
|
||||||
|
|
||||||
|
cargo build -p wickra-c --release # the C ABI hub
|
||||||
|
cmake -S bindings/c/benchmarks -B build/cbench && cmake --build build/cbench \
|
||||||
|
&& ./build/cbench/throughput # raw C ABI
|
||||||
|
dotnet run -c Release --project bindings/csharp/benchmarks # C# (P/Invoke)
|
||||||
|
( cd bindings/go/benchmarks && go run . ) # Go (cgo)
|
||||||
|
mvn -q -f bindings/java install -DskipTests \
|
||||||
|
&& mvn -q -f bindings/java/benchmarks exec:exec -Dexec.mainClass=org.wickra.benchmarks.Throughput
|
||||||
|
Rscript bindings/r/benchmarks/throughput.R # R (.Call)
|
||||||
|
```
|
||||||
|
|||||||
+179
-1
@@ -5,6 +5,175 @@ All notable changes to Wickra are documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.9.1] - 2026-06-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- C ABI hub: every indicator now exposes `wickra_<ind>_warmup_period` and
|
||||||
|
`wickra_<ind>_is_ready`, closing the gap with the native bindings (which
|
||||||
|
already had them). The C-ABI languages surface them idiomatically: C# `int
|
||||||
|
WarmupPeriod()` / `bool IsReady()`, Go `WarmupPeriod()` / `IsReady()`, Java
|
||||||
|
`int warmupPeriod()` / `boolean isReady()`, and R `warmup_period()` /
|
||||||
|
`is_ready()` generics. The alt-chart bar builders are excluded by design (a
|
||||||
|
candle can complete 0..n bars, so they have no warmup).
|
||||||
|
- Runnable rustdoc examples for 23 indicators that previously lacked one.
|
||||||
|
- A Requirements reference documenting the minimum supported version per
|
||||||
|
language — a new page in the documentation site plus README, marketing-site
|
||||||
|
and organization-profile sections.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Raised the minimum Node.js version to 20 — Node 18 reached end-of-life. The
|
||||||
|
prebuilt N-API addon is now tested on the active LTS lines (22 and 24).
|
||||||
|
- The Java binding now builds on the JDK 25 LTS in CI (JDK 22 reached
|
||||||
|
end-of-life); the published bytecode still targets Java 22, so the runtime
|
||||||
|
requirement is unchanged.
|
||||||
|
- Standardised programming-language naming and ordering across all docs, READMEs,
|
||||||
|
the documentation site, marketing site, organization profile and GitHub
|
||||||
|
repository descriptions. Canonical list:
|
||||||
|
`Rust, Python, Node.js, WASM, C, C++, C#, Go, Java, R`. Uses C# (not .NET) as
|
||||||
|
the language label, lists C and C++ separately, prefers `Node.js` and `WASM` in
|
||||||
|
prose, and frames the C ABI as a hub (`C ABI hub → …`) rather than a
|
||||||
|
language-list entry. Documentation only — no code or public API changes.
|
||||||
|
- Python binding: upgraded `pyo3` and `rust-numpy` from 0.28 to 0.29. No public
|
||||||
|
API changes; the full test suite passes unchanged.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Corrected the internal casing of the `RelativeStrengthAB` binding wrappers,
|
||||||
|
which used `...Ab` (`WasmRelativeStrengthAb` in the WASM crate,
|
||||||
|
`RelativeStrengthAbNode` in the Node crate) while every other surface uses the
|
||||||
|
acronym `AB`. The published JS/WASM class name was already `RelativeStrengthAB`
|
||||||
|
(set via `js_name`/`js_class`), so the runtime API is unchanged; the only
|
||||||
|
visible change is the auto-generated TypeScript type alias, renamed
|
||||||
|
`RelativeStrengthAbNode` → `RelativeStrengthABNode` in `index.d.ts`.
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Resolved the pyo3 advisories RUSTSEC-2026-0176 (out-of-bounds read in
|
||||||
|
`PyList`/`PyTuple` `nth`/`nth_back`) and RUSTSEC-2026-0177 (missing `Sync`
|
||||||
|
bound on `PyCFunction::new_closure`) by upgrading to pyo3 0.29, which fixes
|
||||||
|
both. The upgrade was previously blocked upstream by rust-numpy 0.28 pinning
|
||||||
|
pyo3 `^0.28`; rust-numpy 0.29 lifts that pin. The not-affected exceptions are
|
||||||
|
removed from `deny.toml` and `osv-scanner.toml`.
|
||||||
|
|
||||||
|
## [0.9.0] - 2026-06-13
|
||||||
|
|
||||||
|
Maintenance release: Java build-dependency updates and CI/Dependabot
|
||||||
|
housekeeping only. No library code or public API changes.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Java binding: upgraded the test framework to JUnit Jupiter 6.1.0 (from
|
||||||
|
5.10.2) and bumped the Maven build plugins — `maven-compiler-plugin`
|
||||||
|
3.13.0 → 3.15.0, `maven-surefire-plugin` 3.2.5 → 3.5.6, `maven-jar-plugin`
|
||||||
|
3.4.1 → 3.5.0, `maven-source-plugin` 3.3.1 → 3.4.0, `maven-javadoc-plugin`
|
||||||
|
3.7.0 → 3.12.0, and `maven-gpg-plugin` 3.2.4 → 3.2.8.
|
||||||
|
- Java benchmarks and examples: bumped `maven-compiler-plugin` to 3.15.0 and
|
||||||
|
`exec-maven-plugin` to 3.6.3; examples bumped `jackson-databind` 2.17.1 →
|
||||||
|
2.22.0.
|
||||||
|
- Grouped Dependabot updates per ecosystem into a single pull request and
|
||||||
|
extended tracking to the NuGet (C#) binding and the Node/Go examples.
|
||||||
|
|
||||||
|
|
||||||
|
## [0.8.9] - 2026-06-12
|
||||||
|
|
||||||
|
Maintenance release: supply-chain and CI housekeeping only. No library code or
|
||||||
|
public API changes.
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Triaged the pyo3 advisories RUSTSEC-2026-0176 (out-of-bounds read in
|
||||||
|
`PyList`/`PyTuple` `nth`/`nth_back`) and RUSTSEC-2026-0177 (missing `Sync`
|
||||||
|
bound on `PyCFunction::new_closure`) as **not affecting Wickra**: neither
|
||||||
|
vulnerable API is reachable from the Python binding. Both are fixed in pyo3
|
||||||
|
0.29, but rust-numpy 0.28 pins pyo3 `^0.28`, so the upgrade is blocked
|
||||||
|
upstream; the advisories are recorded with their not-affected rationale in
|
||||||
|
`deny.toml` and `osv-scanner.toml` and will be cleared once rust-numpy 0.29
|
||||||
|
ships.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Java binding: bumped `central-publishing-maven-plugin` 0.5.0 → 0.10.0 (the
|
||||||
|
Maven Central publishing plugin used at release time).
|
||||||
|
- Bumped the SHA-pinned GitHub Actions used in CI (`actions/checkout`,
|
||||||
|
`actions/setup-go`, `actions/setup-java`, `github/codeql-action`,
|
||||||
|
`taiki-e/install-action`) to their latest releases.
|
||||||
|
- Added a Maven ecosystem to Dependabot so the Java binding's build plugins and
|
||||||
|
dependencies are tracked going forward.
|
||||||
|
|
||||||
|
|
||||||
|
## [0.8.8] - 2026-06-11
|
||||||
|
### Fixed
|
||||||
|
- R binding: declare `Depends: R (>= 2.10)`, clearing the `R CMD check` warning
|
||||||
|
("package needs dependence on R (>= 2.10)") that the bundled, lazy-loaded
|
||||||
|
`sample_ohlcv` dataset triggers on r-universe / CRAN.
|
||||||
|
|
||||||
|
## [0.8.7] - 2026-06-11
|
||||||
|
### Added
|
||||||
|
- R binding: a *Getting started* vignette and a synthetic `sample_ohlcv` example
|
||||||
|
dataset, giving new users a runnable, self-contained walkthrough and populating
|
||||||
|
the R-universe Articles and Datasets tabs. The vignette's code is exercised in
|
||||||
|
CI so a broken example is caught before the published build.
|
||||||
|
|
||||||
|
## [0.8.6] - 2026-06-11
|
||||||
|
### Changed
|
||||||
|
- Package registry metadata for better discoverability:
|
||||||
|
- R (R-universe): added the R-universe URL and `X-schema.org-keywords` to the
|
||||||
|
R `DESCRIPTION`, plus a package logo at `bindings/r/man/figures/logo.png`
|
||||||
|
(pkgdown convention).
|
||||||
|
- Python (PyPI): added a `Documentation` project URL.
|
||||||
|
- C# (NuGet): added a package icon via `PackageIcon`.
|
||||||
|
|
||||||
|
## [0.8.5] - 2026-06-11
|
||||||
|
### Fixed
|
||||||
|
- The R binding's golden-fixture parity test now skips gracefully when the shared
|
||||||
|
`testdata/golden` fixtures are not bundled with the package — standalone
|
||||||
|
r-universe / CRAN builds package only `bindings/r`, so the repo-root fixtures
|
||||||
|
are unreachable there. The parity stays enforced by the repository CI, where
|
||||||
|
the fixtures are present.
|
||||||
|
|
||||||
|
## [0.8.4] - 2026-06-11
|
||||||
|
### Fixed
|
||||||
|
- A single non-finite (NaN/inf) tick no longer poisons indicator state.
|
||||||
|
The 16 pairwise running-sum/buffer indicators fixed first (`Beta`,
|
||||||
|
`BetaNeutralSpread`, `Cointegration`, `HasbrouckInformationShare`,
|
||||||
|
`PearsonCorrelation`, `RollingCorrelation`, `RollingCovariance`,
|
||||||
|
`DistanceSsd`, `GrangerCausality`, `KendallTau`, `LeadLagCrossCorrelation`,
|
||||||
|
`OuHalfLife`, `SpearmanCorrelation`, `SpreadAr1Coefficient`, `SpreadHurst`,
|
||||||
|
`VarianceRatio`) were joined by 38 more scalar/pairwise indicators the new
|
||||||
|
property harness surfaced (the linear-regression family, rolling quantiles
|
||||||
|
and IQR, `Variance`/`StdDev`-derived stats, `Kurtosis`/`Skewness`, the
|
||||||
|
trailing stops, `KalmanHedgeRatio`, `SpreadBollingerBands`, and more). Every
|
||||||
|
`f64` / `(f64, f64)` indicator now rejects non-finite input and returns
|
||||||
|
`None`, matching the streaming-robustness guarantee — and the harness enforces
|
||||||
|
it going forward.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Catalogue-wide property-based invariant harness
|
||||||
|
(`crates/wickra-core/tests/invariants.rs`) asserting `batch == streaming`,
|
||||||
|
`reset == fresh`, and non-finite-input rejection for every indicator and
|
||||||
|
bar-builder.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- CI: every job now has a runtime cap and the historically flaky Node test step
|
||||||
|
auto-retries, so a wedged runner fails fast instead of hanging for hours.
|
||||||
|
- Documentation accuracy fixes in `SECURITY.md`, `ARCHITECTURE.md`, and
|
||||||
|
`THREAT_MODEL.md` (supported version, indicator count, WASM test coverage,
|
||||||
|
numerical-stability notes, and the C-ABI panic strategy).
|
||||||
|
|
||||||
|
## [0.8.3] - 2026-06-10
|
||||||
|
### Added
|
||||||
|
- **Per-binding throughput benchmarks** — every target now ships a `throughput`
|
||||||
|
benchmark mirroring the Node `throughput.js`: streaming and batch
|
||||||
|
updates-per-second for `SMA(20)`, `ATR(14)` and `MACD(12,26,9)` over a
|
||||||
|
synthetic OHLCV series. New for Python (`bindings/python/benchmarks/`), C
|
||||||
|
(`bindings/c/benchmarks/`), C# (`bindings/csharp/benchmarks/`), Go
|
||||||
|
(`bindings/go/benchmarks/`), Java (`bindings/java/benchmarks/`), R
|
||||||
|
(`bindings/r/benchmarks/`), WebAssembly (`bindings/wasm/benchmarks/`) and the
|
||||||
|
Rust core baseline (`examples/rust/.../throughput.rs`, no FFI). They measure
|
||||||
|
each binding's FFI overhead — the same Rust core runs underneath all of them —
|
||||||
|
and are documented in [BENCHMARKS.md](BENCHMARKS.md) §3, not a cross-library
|
||||||
|
speed claim.
|
||||||
|
- **C ABI archetype test** — `examples/c/archetypes.c` exercises one indicator
|
||||||
|
per FFI archetype (scalar, multi-output, bars, profile, array input) through
|
||||||
|
the C boundary, matching the Go/R/Java suites.
|
||||||
|
|
||||||
## [0.8.2] - 2026-06-10
|
## [0.8.2] - 2026-06-10
|
||||||
### Fixed
|
### Fixed
|
||||||
- **R binding builds for WebAssembly** — `bindings/r/configure` now builds the
|
- **R binding builds for WebAssembly** — `bindings/r/configure` now builds the
|
||||||
@@ -1494,7 +1663,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
optional Binance live feed.
|
optional Binance live feed.
|
||||||
- Bindings for Python, Node.js, and WebAssembly.
|
- Bindings for Python, Node.js, and WebAssembly.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.8.2...HEAD
|
[Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.9.1...HEAD
|
||||||
|
[0.9.1]: https://github.com/wickra-lib/wickra/compare/v0.9.0...v0.9.1
|
||||||
|
[0.9.0]: https://github.com/wickra-lib/wickra/compare/v0.8.9...v0.9.0
|
||||||
|
[0.8.9]: https://github.com/wickra-lib/wickra/compare/v0.8.8...v0.8.9
|
||||||
|
[0.8.8]: https://github.com/wickra-lib/wickra/compare/v0.8.7...v0.8.8
|
||||||
|
[0.8.7]: https://github.com/wickra-lib/wickra/compare/v0.8.6...v0.8.7
|
||||||
|
[0.8.6]: https://github.com/wickra-lib/wickra/compare/v0.8.5...v0.8.6
|
||||||
|
[0.8.5]: https://github.com/wickra-lib/wickra/compare/v0.8.4...v0.8.5
|
||||||
|
[0.8.4]: https://github.com/wickra-lib/wickra/compare/v0.8.3...v0.8.4
|
||||||
|
[0.8.3]: https://github.com/wickra-lib/wickra/compare/v0.8.2...v0.8.3
|
||||||
[0.8.2]: https://github.com/wickra-lib/wickra/compare/v0.8.1...v0.8.2
|
[0.8.2]: https://github.com/wickra-lib/wickra/compare/v0.8.1...v0.8.2
|
||||||
[0.8.1]: https://github.com/wickra-lib/wickra/compare/v0.8.0...v0.8.1
|
[0.8.1]: https://github.com/wickra-lib/wickra/compare/v0.8.0...v0.8.1
|
||||||
[0.8.0]: https://github.com/wickra-lib/wickra/compare/v0.7.9...v0.8.0
|
[0.8.0]: https://github.com/wickra-lib/wickra/compare/v0.7.9...v0.8.0
|
||||||
|
|||||||
+2
-2
@@ -22,7 +22,7 @@ licensed as above, without any additional terms or conditions.
|
|||||||
| `bindings/node` | napi-rs bindings (`wickra` on npm). |
|
| `bindings/node` | napi-rs bindings (`wickra` on npm). |
|
||||||
| `bindings/wasm` | wasm-bindgen bindings (`wickra-wasm` on npm). |
|
| `bindings/wasm` | wasm-bindgen bindings (`wickra-wasm` on npm). |
|
||||||
| `bindings/c` | C ABI — `cdylib` + `staticlib` + generated `include/wickra.h`. The hub for C / C++ and any C-capable language. |
|
| `bindings/c` | C ABI — `cdylib` + `staticlib` + generated `include/wickra.h`. The hub for C / C++ and any C-capable language. |
|
||||||
| `bindings/csharp` | .NET binding over the C ABI (`Wickra` on NuGet) — `[LibraryImport]` P/Invoke generated from `wickra.h`. |
|
| `bindings/csharp` | C# binding over the C ABI (`Wickra` on NuGet) — `[LibraryImport]` P/Invoke generated from `wickra.h`. |
|
||||||
| `bindings/go` | Go binding over the C ABI via cgo (module tag `bindings/go/vX.Y.Z`) — wrappers generated from `wickra.h`. |
|
| `bindings/go` | Go binding over the C ABI via cgo (module tag `bindings/go/vX.Y.Z`) — wrappers generated from `wickra.h`. |
|
||||||
| `bindings/r` | R binding over the C ABI via `.Call` (R package) — C glue + R wrappers generated from `wickra.h`. |
|
| `bindings/r` | R binding over the C ABI via `.Call` (R package) — C glue + R wrappers generated from `wickra.h`. |
|
||||||
| `bindings/java` | Java binding over the C ABI via the FFM API (Panama, Maven Central) — wrappers generated from `wickra.h`. |
|
| `bindings/java` | Java binding over the C ABI via the FFM API (Panama, Maven Central) — wrappers generated from `wickra.h`. |
|
||||||
@@ -107,7 +107,7 @@ installed. Dependabot also keeps the `.github/requirements` pins current.
|
|||||||
- **Streaming parity.** An indicator's `batch` output must equal the sequence
|
- **Streaming parity.** An indicator's `batch` output must equal the sequence
|
||||||
of `update` calls.
|
of `update` calls.
|
||||||
- **Bindings.** A change to a public indicator API must be mirrored across the
|
- **Bindings.** A change to a public indicator API must be mirrored across the
|
||||||
Python, Node, and WASM bindings, including their type stubs / `.d.ts`. The C ABI
|
Python, Node.js, and WASM bindings, including their type stubs / `.d.ts`. The C ABI
|
||||||
(`bindings/c`) is generated from the core, so regenerate it from the core and
|
(`bindings/c`) is generated from the core, so regenerate it from the core and
|
||||||
commit `src/lib.rs` + `include/wickra.h`. The C# binding (`bindings/csharp`) is
|
commit `src/lib.rs` + `include/wickra.h`. The C# binding (`bindings/csharp`) is
|
||||||
generated from `wickra.h`, so regenerate and commit its `Generated/*.g.cs` too.
|
generated from `wickra.h`, so regenerate and commit its `Generated/*.g.cs` too.
|
||||||
|
|||||||
Generated
+21
-22
@@ -945,9 +945,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "778da78c64ddc928ebf5ad9df5edf0789410ff3bdbf3619aed51cd789a6af1e2"
|
checksum = "6a5b15d63a5ff39e378daed0e1340d3a5964703ea9712eb09a0dc66fade996f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"ndarray",
|
"ndarray",
|
||||||
@@ -1152,9 +1152,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3"
|
name = "pyo3"
|
||||||
version = "0.28.3"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12"
|
checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -1166,18 +1166,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-build-config"
|
name = "pyo3-build-config"
|
||||||
version = "0.28.3"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e"
|
checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-ffi"
|
name = "pyo3-ffi"
|
||||||
version = "0.28.3"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e"
|
checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
@@ -1185,9 +1185,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros"
|
name = "pyo3-macros"
|
||||||
version = "0.28.3"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813"
|
checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
@@ -1197,13 +1197,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros-backend"
|
name = "pyo3-macros-backend"
|
||||||
version = "0.28.3"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb"
|
checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
@@ -1944,7 +1943,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra"
|
name = "wickra"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx",
|
"approx",
|
||||||
"criterion",
|
"criterion",
|
||||||
@@ -1955,7 +1954,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-bench"
|
name = "wickra-bench"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
"kand",
|
"kand",
|
||||||
@@ -1967,14 +1966,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-c"
|
name = "wickra-c"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wickra-core",
|
"wickra-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-core"
|
name = "wickra-core"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx",
|
"approx",
|
||||||
"proptest",
|
"proptest",
|
||||||
@@ -1984,7 +1983,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-data"
|
name = "wickra-data"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx",
|
"approx",
|
||||||
"csv",
|
"csv",
|
||||||
@@ -2001,7 +2000,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-examples"
|
name = "wickra-examples"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -2011,7 +2010,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-node"
|
name = "wickra-node"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"napi",
|
"napi",
|
||||||
"napi-build",
|
"napi-build",
|
||||||
@@ -2021,7 +2020,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-python"
|
name = "wickra-python"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"numpy",
|
"numpy",
|
||||||
"pyo3",
|
"pyo3",
|
||||||
@@ -2030,7 +2029,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wickra-wasm"
|
name = "wickra-wasm"
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|||||||
+4
-4
@@ -14,7 +14,7 @@ members = [
|
|||||||
exclude = ["fuzz"]
|
exclude = ["fuzz"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.8.2"
|
version = "0.9.1"
|
||||||
authors = ["kingchenc <support@wickra.org>"]
|
authors = ["kingchenc <support@wickra.org>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.86"
|
rust-version = "1.86"
|
||||||
@@ -26,7 +26,7 @@ keywords = ["finance", "trading", "indicators", "technical-analysis", "ta"]
|
|||||||
categories = ["finance", "mathematics", "science"]
|
categories = ["finance", "mathematics", "science"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
wickra-core = { path = "crates/wickra-core", version = "0.8.2" }
|
wickra-core = { path = "crates/wickra-core", version = "0.9.1" }
|
||||||
|
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
rayon = "1.10"
|
rayon = "1.10"
|
||||||
@@ -37,8 +37,8 @@ approx = "0.5"
|
|||||||
criterion = { version = "0.8", features = ["html_reports"] }
|
criterion = { version = "0.8", features = ["html_reports"] }
|
||||||
|
|
||||||
# Python binding
|
# Python binding
|
||||||
pyo3 = { version = "0.28", features = ["extension-module", "abi3-py39"] }
|
pyo3 = { version = "0.29", features = ["extension-module", "abi3-py39"] }
|
||||||
numpy = "0.28"
|
numpy = "0.29"
|
||||||
|
|
||||||
[workspace.lints.rust]
|
[workspace.lints.rust]
|
||||||
unsafe_code = "forbid"
|
unsafe_code = "forbid"
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
**Streaming-first technical indicators. Install with `pip install wickra` — no system dependencies.**
|
**Streaming-first technical indicators. Install with `pip install wickra` — no system dependencies.**
|
||||||
|
|
||||||
Wickra is a multi-language technical-analysis library with a Rust core and
|
Wickra is a multi-language technical-analysis library with a Rust core and
|
||||||
native bindings for Python, Node.js and WebAssembly, plus a C ABI that C, C++,
|
native bindings for Python, Node.js and WASM, plus a C ABI that C, C++,
|
||||||
C# / .NET, Go, Java, R and any other C-capable language links against. Every indicator is a
|
C#, Go, Java, R and any other C-capable language links against. Every indicator is a
|
||||||
state machine that updates in O(1) per new data point, so live trading bots and
|
state machine that updates in O(1) per new data point, so live trading bots and
|
||||||
historical backtests share the exact same implementation.
|
historical backtests share the exact same implementation.
|
||||||
|
|
||||||
@@ -81,8 +81,8 @@ times to get there.
|
|||||||
breadth, Renko/Kagi/Point&Figure bars, Ehlers DSP cycles, risk/performance
|
breadth, Renko/Kagi/Point&Figure bars, Ehlers DSP cycles, risk/performance
|
||||||
metrics — every single one updating in **O(1) per tick**. TA-Lib ships ~150 and
|
metrics — every single one updating in **O(1) per tick**. TA-Lib ships ~150 and
|
||||||
none of them stream.
|
none of them stream.
|
||||||
- **One Rust core, five first-class targets.** Native **Python · Node.js ·
|
- **One Rust core, five first-class targets.** Native **Rust · Python · Node.js ·
|
||||||
WebAssembly · Rust** plus a **C ABI** for C / C++, C# / .NET, Go, Java, R and any other C-capable language —
|
WASM** plus a **C ABI** for C, C++, C#, Go, Java, R and any other C-capable language —
|
||||||
identical math, identical results, zero per-language reimplementation and zero
|
identical math, identical results, zero per-language reimplementation and zero
|
||||||
GIL bottleneck.
|
GIL bottleneck.
|
||||||
- **Correct by construction, not by hope.** Every `update` validates its input,
|
- **Correct by construction, not by hope.** Every `update` validates its input,
|
||||||
@@ -106,7 +106,7 @@ Every other library forces one of those compromises. Wickra doesn't:
|
|||||||
|
|
||||||
| Library | Install | Streaming | Languages | Indicators | Active |
|
| Library | Install | Streaming | Languages | Indicators | Active |
|
||||||
|------------------|-------------|-------------|-----------------------------|-----------:|--------|
|
|------------------|-------------|-------------|-----------------------------|-----------:|--------|
|
||||||
| **★ Wickra**| **clean** | **yes, O(1)** | **Rust · Python · Node · WASM · C · C# · Go · Java · R** | **514** | **yes** |
|
| **★ Wickra**| **clean** | **yes, O(1)** | **Rust · Python · Node.js · WASM · C · C++ · C# · Go · Java · R** | **514** | **yes** |
|
||||||
| kand | clean | yes | Python · WASM · Rust | ~60 | yes |
|
| kand | clean | yes | Python · WASM · Rust | ~60 | yes |
|
||||||
| ta-rs | clean | yes | Rust only | ~30 | stale |
|
| ta-rs | clean | yes | Rust only | ~30 | stale |
|
||||||
| yata | clean | partial | Rust only | ~35 | yes |
|
| yata | clean | partial | Rust only | ~35 | yes |
|
||||||
@@ -190,7 +190,7 @@ it — regenerate from the core).
|
|||||||
| Browser / WASM | `npm install wickra-wasm` | `examples/wasm/index.html` |
|
| Browser / WASM | `npm install wickra-wasm` | `examples/wasm/index.html` |
|
||||||
| Rust | `cargo add wickra` | `examples/rust/src/bin/backtest.rs` |
|
| Rust | `cargo add wickra` | `examples/rust/src/bin/backtest.rs` |
|
||||||
| C / C++ (C ABI) | header + library, see [`bindings/c`](bindings/c) | `examples/c/streaming.c` |
|
| C / C++ (C ABI) | header + library, see [`bindings/c`](bindings/c) | `examples/c/streaming.c` |
|
||||||
| C# / .NET (C ABI) | `dotnet add package Wickra`, see [`bindings/csharp`](bindings/csharp) | `examples/csharp/streaming` |
|
| C# (C ABI) | `dotnet add package Wickra`, see [`bindings/csharp`](bindings/csharp) | `examples/csharp/streaming` |
|
||||||
| Go (cgo, C ABI) | `go get github.com/wickra-lib/wickra/bindings/go`, see [`bindings/go`](bindings/go) | `examples/go/streaming` |
|
| Go (cgo, C ABI) | `go get github.com/wickra-lib/wickra/bindings/go`, see [`bindings/go`](bindings/go) | `examples/go/streaming` |
|
||||||
| Java (FFM, C ABI) | Maven Central `org.wickra:wickra`, see [`bindings/java`](bindings/java) | `examples/java` (`Streaming`) |
|
| Java (FFM, C ABI) | Maven Central `org.wickra:wickra`, see [`bindings/java`](bindings/java) | `examples/java` (`Streaming`) |
|
||||||
| R (`.Call`, C ABI) | `R CMD INSTALL bindings/r`, see [`bindings/r`](bindings/r) | `examples/r/streaming.R` |
|
| R (`.Call`, C ABI) | `R CMD INSTALL bindings/r`, see [`bindings/r`](bindings/r) | `examples/r/streaming.R` |
|
||||||
@@ -202,6 +202,29 @@ The wickra-core crate is `unsafe`-forbidden, so the native bindings are
|
|||||||
memory-safe end to end. The C ABI runs the same safe core; only its thin FFI
|
memory-safe end to end. The C ABI runs the same safe core; only its thin FFI
|
||||||
boundary uses `unsafe`, and the caller owns handle lifetimes (`_new` / `_free`).
|
boundary uses `unsafe`, and the caller owns handle lifetimes (`_new` / `_free`).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
The minimum supported version per language. Prebuilt packages (Rust, Python,
|
||||||
|
Node.js, WASM, C#) need only the runtime; the C-ABI bindings that compile on
|
||||||
|
install — Go (cgo) and R (`.Call`) — also need a C compiler, and Java runs with
|
||||||
|
`--enable-native-access=ALL-UNNAMED`.
|
||||||
|
|
||||||
|
| Language | Package | Minimum supported |
|
||||||
|
|-------------|--------------------------------------|----------------------------|
|
||||||
|
| Rust | crates.io · `wickra` | 1.86 (MSRV) |
|
||||||
|
| Python | PyPI · `wickra` (abi3 wheel) | 3.9 (tested through 3.13) |
|
||||||
|
| Node.js | npm · `wickra` (N-API 8) | 20 (tested on 22 · 24 LTS) |
|
||||||
|
| WASM | npm · `wickra-wasm` | any modern JS engine |
|
||||||
|
| C | `wickra.h` + library (releases) | C99 compiler |
|
||||||
|
| C++ | `wickra.hpp` over the C ABI | C++14 compiler |
|
||||||
|
| C# | NuGet · `Wickra` | .NET 8 (`net8.0`) |
|
||||||
|
| Go | module · `wickra-lib/wickra-go` | Go 1.23 (cgo) |
|
||||||
|
| Java | Maven Central · `org.wickra:wickra` | Java 22 (FFM / Panama) |
|
||||||
|
| R | source package | R ≥ 2.10 (Rtools on Win.) |
|
||||||
|
|
||||||
|
Full per-language detail (runtime vs. build-from-source) is on the
|
||||||
|
[Requirements page](https://docs.wickra.org/Requirements) in the docs.
|
||||||
|
|
||||||
## Rust API
|
## Rust API
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@@ -264,7 +287,7 @@ wickra/
|
|||||||
│ ├── node/ napi-rs (publishes on npm)
|
│ ├── node/ napi-rs (publishes on npm)
|
||||||
│ ├── wasm/ wasm-bindgen (browsers, bundlers, Node)
|
│ ├── wasm/ wasm-bindgen (browsers, bundlers, Node)
|
||||||
│ ├── c/ C ABI (cdylib + staticlib) + generated include/wickra.h
|
│ ├── c/ C ABI (cdylib + staticlib) + generated include/wickra.h
|
||||||
│ ├── csharp/ .NET binding over the C ABI (publishes on NuGet)
|
│ ├── csharp/ C# binding over the C ABI (publishes on NuGet)
|
||||||
│ ├── go/ Go binding over the C ABI via cgo (module tag)
|
│ ├── go/ Go binding over the C ABI via cgo (module tag)
|
||||||
│ ├── r/ R binding over the C ABI via .Call (R package)
|
│ ├── r/ R binding over the C ABI via .Call (R package)
|
||||||
│ └── java/ Java binding over the C ABI via the FFM API (Maven Central)
|
│ └── java/ Java binding over the C ABI via the FFM API (Maven Central)
|
||||||
@@ -312,7 +335,7 @@ cargo build -p wickra-c --release
|
|||||||
cmake -S examples/c -B examples/c/build -DWICKRA_LIB_DIR="$PWD/target/release"
|
cmake -S examples/c -B examples/c/build -DWICKRA_LIB_DIR="$PWD/target/release"
|
||||||
cmake --build examples/c/build && ctest --test-dir examples/c/build --output-on-failure
|
cmake --build examples/c/build && ctest --test-dir examples/c/build --output-on-failure
|
||||||
|
|
||||||
# C# / .NET binding (requires the .NET 8 SDK; links the C ABI above)
|
# C# binding (requires the .NET 8 SDK; links the C ABI above)
|
||||||
dotnet test bindings/csharp/Wickra.Tests/Wickra.Tests.csproj
|
dotnet test bindings/csharp/Wickra.Tests/Wickra.Tests.csproj
|
||||||
|
|
||||||
# Go binding (requires a C compiler for cgo; links the C ABI above)
|
# Go binding (requires a C compiler for cgo; links the C ABI above)
|
||||||
@@ -334,7 +357,10 @@ Every layer is covered; run the suites with the commands in
|
|||||||
|
|
||||||
- `wickra-core`: unit tests per indicator — textbook reference values
|
- `wickra-core`: unit tests per indicator — textbook reference values
|
||||||
(Wilder RSI, Bollinger Bands, MACD, ATR, Stochastic), `batch == streaming`
|
(Wilder RSI, Bollinger Bands, MACD, ATR, Stochastic), `batch == streaming`
|
||||||
equivalence, `reset` semantics, NaN/Inf handling, and property tests.
|
equivalence, `reset` semantics, NaN/Inf handling, and property tests. A
|
||||||
|
catalogue-wide property harness (`tests/invariants.rs`) additionally asserts
|
||||||
|
`batch == streaming`, `reset == fresh`, and non-finite-input rejection for
|
||||||
|
**every** indicator and bar-builder.
|
||||||
- `wickra-data`: unit tests for CSV decoding, the tick aggregator, the
|
- `wickra-data`: unit tests for CSV decoding, the tick aggregator, the
|
||||||
resampler, and the Binance payload parser.
|
resampler, and the Binance payload parser.
|
||||||
- `bindings/python`: pytest covering smoke checks, streaming/batch
|
- `bindings/python`: pytest covering smoke checks, streaming/batch
|
||||||
@@ -344,6 +370,10 @@ Every layer is covered; run the suites with the commands in
|
|||||||
values across all indicators.
|
values across all indicators.
|
||||||
- `bindings/wasm`: `wasm-bindgen-test` cases for constructors, equivalence,
|
- `bindings/wasm`: `wasm-bindgen-test` cases for constructors, equivalence,
|
||||||
and reference values.
|
and reference values.
|
||||||
|
- `bindings/c`: Rust unit tests over the FFI boundary, plus C and C++ smoke
|
||||||
|
tests and offline example `ctest`s run on the three OSes.
|
||||||
|
- `bindings/csharp`: `dotnet test` cases covering one indicator per FFI archetype
|
||||||
|
(scalar/batch, multi-output, bars, profile, array input) plus SMA reference values.
|
||||||
- `bindings/go`: `go test` cases covering one indicator per FFI archetype
|
- `bindings/go`: `go test` cases covering one indicator per FFI archetype
|
||||||
(scalar/batch, multi-output, bars, profile, array input), reset, and lifecycle.
|
(scalar/batch, multi-output, bars, profile, array input), reset, and lifecycle.
|
||||||
- `bindings/r`: `testthat` cases covering one indicator per FFI archetype
|
- `bindings/r`: `testthat` cases covering one indicator per FFI archetype
|
||||||
@@ -351,6 +381,12 @@ Every layer is covered; run the suites with the commands in
|
|||||||
- `bindings/java`: JUnit cases covering one indicator per FFI archetype
|
- `bindings/java`: JUnit cases covering one indicator per FFI archetype
|
||||||
(scalar/batch, multi-output, bars, profile, array input) plus batch equivalence.
|
(scalar/batch, multi-output, bars, profile, array input) plus batch equivalence.
|
||||||
|
|
||||||
|
The four C-ABI bindings (C#, Go, Java, R) additionally replay a shared,
|
||||||
|
language-neutral golden fixture (`testdata/golden/*.csv`, generated by
|
||||||
|
`cargo run -p wickra-examples --bin gen_golden`) and assert exact parity with the
|
||||||
|
Rust reference outputs across every archetype (SMA, EMA, RSI, ATR, MACD, ADX,
|
||||||
|
Beta), catching FFI wiring bugs the math-only core tests cannot see.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are very welcome — issues, bug reports, ideas, and pull requests
|
Contributions are very welcome — issues, bug reports, ideas, and pull requests
|
||||||
@@ -406,13 +442,13 @@ The library is provided **as is**, without warranty of any kind; see
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/wickra-lib/wickra/stargazers">
|
<a href="https://github.com/wickra-lib/wickra/stargazers">
|
||||||
<img alt="GitHub stars" src="https://img.shields.io/github/stars/wickra-lib/wickra?style=for-the-badge&logo=github&logoColor=white&color=ffd866">
|
<img alt="GitHub stars" src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/stars.svg">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/wickra-lib/wickra/network/members">
|
<a href="https://github.com/wickra-lib/wickra/network/members">
|
||||||
<img alt="GitHub forks" src="https://img.shields.io/github/forks/wickra-lib/wickra?style=for-the-badge&logo=github&logoColor=white&color=78dce8">
|
<img alt="GitHub forks" src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/forks.svg">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/wickra-lib/wickra/issues">
|
<a href="https://github.com/wickra-lib/wickra/issues">
|
||||||
<img alt="GitHub issues" src="https://img.shields.io/github/issues/wickra-lib/wickra?style=for-the-badge&logo=github&logoColor=white&color=ff6188">
|
<img alt="GitHub issues" src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/issues.svg">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -423,6 +459,6 @@ The library is provided **as is**, without warranty of any kind; see
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://star-history.com/#wickra-lib/wickra&Date">
|
<a href="https://star-history.com/#wickra-lib/wickra&Date">
|
||||||
<img alt="Wickra star history" width="640"
|
<img alt="Wickra star history" width="640"
|
||||||
src="https://api.star-history.com/svg?repos=wickra-lib/wickra&type=Date&theme=dark">
|
src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/star-history.svg">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
+2
-2
@@ -21,8 +21,8 @@ minor releases; breaking changes are called out in the changelog.
|
|||||||
versioning stability for a 1.0 release.
|
versioning stability for a 1.0 release.
|
||||||
- **Performance.** Keep per-tick updates O(1) and maintain the benchmark suite;
|
- **Performance.** Keep per-tick updates O(1) and maintain the benchmark suite;
|
||||||
investigate further allocation and cache improvements.
|
investigate further allocation and cache improvements.
|
||||||
- **Bindings parity.** Keep the Python, Node.js and WebAssembly bindings — plus
|
- **Bindings parity.** Keep the Python, Node.js and WASM bindings — plus
|
||||||
the C ABI and the C# / .NET, Go, Java and R bindings generated from it — in lockstep with the
|
the C ABI and the C#, Go, Java and R bindings generated from it — in lockstep with the
|
||||||
Rust core, including type stubs and platform coverage.
|
Rust core, including type stubs and platform coverage.
|
||||||
- **Documentation.** Maintain a deep-dive page per indicator on
|
- **Documentation.** Maintain a deep-dive page per indicator on
|
||||||
<https://docs.wickra.org>, plus quickstarts and cookbook material.
|
<https://docs.wickra.org>, plus quickstarts and cookbook material.
|
||||||
|
|||||||
+3
-3
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
## Supported versions
|
## Supported versions
|
||||||
|
|
||||||
Wickra is pre-1.0. Security fixes are applied to the latest released `0.5.x`
|
Wickra is pre-1.0. Security fixes are applied to the latest released `0.9.1`
|
||||||
version only; please upgrade to the newest release before reporting an issue.
|
version only; please upgrade to the newest release before reporting an issue.
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 0.5.x (latest) | :white_check_mark: |
|
| 0.9.1 (latest) | :white_check_mark: |
|
||||||
| older 0.5.x | :x: |
|
| < 0.9.1 | :x: |
|
||||||
|
|
||||||
## Reporting a vulnerability
|
## Reporting a vulnerability
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ Thanks for using Wickra! Here is where to get help, depending on what you need.
|
|||||||
Most questions are answered in the documentation:
|
Most questions are answered in the documentation:
|
||||||
|
|
||||||
- **Docs site:** <https://docs.wickra.org> — quickstarts for Rust, Python,
|
- **Docs site:** <https://docs.wickra.org> — quickstarts for Rust, Python,
|
||||||
Node.js, WebAssembly, C, C#, Go, Java and R, a per-indicator reference, warmup periods, the
|
Node.js, WASM, C, C++, C#, Go, Java and R, a per-indicator reference, warmup periods, the
|
||||||
data layer, and an FAQ.
|
data layer, and an FAQ.
|
||||||
- **README:** <https://github.com/wickra-lib/wickra#readme> — installation and a
|
- **README:** <https://github.com/wickra-lib/wickra#readme> — installation and a
|
||||||
quick overview.
|
quick overview.
|
||||||
|
|||||||
+3
-3
@@ -3,8 +3,8 @@
|
|||||||
This document describes Wickra's attack surface and the threats considered,
|
This document describes Wickra's attack surface and the threats considered,
|
||||||
together with their mitigations. It complements the security assurance case in
|
together with their mitigations. It complements the security assurance case in
|
||||||
[`SECURITY.md`](SECURITY.md). Wickra is a computational technical-analysis
|
[`SECURITY.md`](SECURITY.md). Wickra is a computational technical-analysis
|
||||||
library (a Rust core with Python, Node.js and WebAssembly bindings plus a C ABI
|
library (a Rust core with Python, Node.js and WASM bindings plus a C ABI
|
||||||
and the .NET, Go, Java and R bindings built on it),
|
and the C#, Go, Java and R bindings built on it),
|
||||||
not a network service or trading system; the attack surface is correspondingly
|
not a network service or trading system; the attack surface is correspondingly
|
||||||
small.
|
small.
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ small.
|
|||||||
| Threat | Mitigation |
|
| Threat | Mitigation |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Memory-safety exploit (buffer overflow, UAF) via crafted input | Pure safe Rust; `unsafe` is forbidden/minimised, so the compiler precludes these classes. |
|
| Memory-safety exploit (buffer overflow, UAF) via crafted input | Pure safe Rust; `unsafe` is forbidden/minimised, so the compiler precludes these classes. |
|
||||||
| Misuse of the C ABI FFI boundary (invalid/dangling handle, undersized batch buffer) | The C ABI (`bindings/c`) is the sole `unsafe` surface. Its shim adds no logic, NULL-checks every handle (returning `NaN`/no-op), writes only into caller-sized buffers, and catches panics so none cross the boundary. A caller passing a non-NULL but dangling pointer is undefined behaviour by C's own contract — out of scope, the same as any C library. |
|
| Misuse of the C ABI FFI boundary (invalid/dangling handle, undersized batch buffer) | The C ABI (`bindings/c`) is the sole `unsafe` surface. Its shim adds no logic, NULL-checks every handle (returning `NaN`/no-op), writes only into caller-sized buffers, and is built with `panic = "abort"` so a panic terminates the process deterministically instead of unwinding across the FFI boundary (which would be undefined behaviour). A caller passing a non-NULL but dangling pointer is undefined behaviour by C's own contract — out of scope, the same as any C library. |
|
||||||
| Denial of service via malformed/degenerate input (NaN, infinities, extreme magnitudes) | Indicators reject non-finite inputs and validate parameters at construction; update paths are exercised by coverage-guided fuzzing and unit tests for edge cases. |
|
| Denial of service via malformed/degenerate input (NaN, infinities, extreme magnitudes) | Indicators reject non-finite inputs and validate parameters at construction; update paths are exercised by coverage-guided fuzzing and unit tests for edge cases. |
|
||||||
| Silently incorrect results | 100% line coverage on the core crate; reference-value tests against known-good sources; streaming/batch parity tests. |
|
| Silently incorrect results | 100% line coverage on the core crate; reference-value tests against known-good sources; streaming/batch parity tests. |
|
||||||
| Integer overflow / panics | `clippy::pedantic` with `-D warnings`; debug assertions and overflow checks enabled in test/fuzz builds. |
|
| Integer overflow / panics | `clippy::pedantic` with `-D warnings`; debug assertions and overflow checks enabled in test/fuzz builds. |
|
||||||
|
|||||||
+25
-4
@@ -9,12 +9,12 @@
|
|||||||
library plus a generated `wickra.h` — no system dependencies.**
|
library plus a generated `wickra.h` — no system dependencies.**
|
||||||
|
|
||||||
Wickra is a multi-language technical-analysis library with a Rust core and
|
Wickra is a multi-language technical-analysis library with a Rust core and
|
||||||
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R and any
|
bindings for Python, Node.js and WASM, plus a C ABI for C, C++, C#, Go, Java, R and any
|
||||||
other C-capable language. Every indicator is an O(1)
|
other C-capable language. Every indicator is an O(1)
|
||||||
streaming state machine, so live trading bots and historical backtests share
|
streaming state machine, so live trading bots and historical backtests share
|
||||||
the exact same implementation. This package is the **C ABI hub**: it compiles the
|
the exact same implementation. This package is the **C ABI hub**: it compiles the
|
||||||
core to a C-compatible shared/static library plus a generated header, so any
|
core to a C-compatible shared/static library plus a generated header, so any
|
||||||
C-capable language (C, C++, Go, C#, Java, R) links against one artifact instead
|
C-capable language (C, C++, C#, Go, Java, R) links against one artifact instead
|
||||||
of re-wrapping every indicator natively.
|
of re-wrapping every indicator natively.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
@@ -54,6 +54,20 @@ Multi-output indicators (MACD, Bollinger, ADX, …) take a pointer to a `#[repr(
|
|||||||
struct and return a `bool`. The optional `wickra.hpp` wraps any handle in a
|
struct and return a `bool`. The optional `wickra.hpp` wraps any handle in a
|
||||||
move-only `wickra::Handle` for exception-safe C++ lifetimes.
|
move-only `wickra::Handle` for exception-safe C++ lifetimes.
|
||||||
|
|
||||||
|
## Benchmark
|
||||||
|
|
||||||
|
`benchmarks/throughput.c` reports streaming and batch updates-per-second for
|
||||||
|
`SMA`, `ATR` and `MACD`. As the thinnest binding it is the floor of the
|
||||||
|
per-binding FFI overhead — not a cross-library ratio (the same Rust core runs
|
||||||
|
under every binding); see the repository
|
||||||
|
[BENCHMARKS.md](https://github.com/wickra-lib/wickra/blob/main/BENCHMARKS.md) §3.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build -p wickra-c --release
|
||||||
|
cmake -S benchmarks -B build && cmake --build build
|
||||||
|
./build/throughput
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The full indicator catalogue, guides, quickstarts, and API reference live in
|
The full indicator catalogue, guides, quickstarts, and API reference live in
|
||||||
@@ -63,10 +77,17 @@ the main repository and documentation site:
|
|||||||
- **Docs** (C quickstart, cookbook, TA-Lib migration): <https://docs.wickra.org/Quickstart-C>
|
- **Docs** (C quickstart, cookbook, TA-Lib migration): <https://docs.wickra.org/Quickstart-C>
|
||||||
- **Runnable examples:** [`examples/c/`](https://github.com/wickra-lib/wickra/tree/main/examples/c)
|
- **Runnable examples:** [`examples/c/`](https://github.com/wickra-lib/wickra/tree/main/examples/c)
|
||||||
|
|
||||||
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus this
|
Wickra ships native bindings for Python, Node.js, WASM and Rust, plus this
|
||||||
C ABI hub that any C-capable language (C, C++, Go, C#, Java, R) links against —
|
C ABI hub that any C-capable language (C, C++, C#, Go, Java, R) links against —
|
||||||
all exposing the same indicators from the shared Rust core.
|
all exposing the same indicators from the shared Rust core.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Found a security issue? **Please don't open a public issue.** Report it privately
|
||||||
|
via the affected repository's *Security* tab (*"Report a vulnerability"*) or email
|
||||||
|
**support@wickra.org** with a subject line starting `[wickra security]`. Full
|
||||||
|
policy: <https://github.com/wickra-lib/wickra/blob/main/SECURITY.md>.
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Wickra is an indicator toolkit, not a trading system. The values it computes
|
Wickra is an indicator toolkit, not a trading system. The values it computes
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
project(wickra_c_benchmarks C)
|
||||||
|
|
||||||
|
# Directory holding the compiled Wickra C library (cargo output), e.g.
|
||||||
|
# <workspace>/target/release. Override with -DWICKRA_LIB_DIR=/path/to/target/release.
|
||||||
|
if(NOT DEFINED WICKRA_LIB_DIR)
|
||||||
|
set(WICKRA_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../target/release")
|
||||||
|
endif()
|
||||||
|
set(WICKRA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../include")
|
||||||
|
|
||||||
|
# Pick the right link target per platform/toolchain.
|
||||||
|
# - MSVC links the generated import library (wickra.dll.lib).
|
||||||
|
# - MinGW/gcc on Windows links the DLL directly.
|
||||||
|
# - Unix links the shared object / dylib.
|
||||||
|
if(WIN32)
|
||||||
|
set(WICKRA_RUNTIME "${WICKRA_LIB_DIR}/wickra.dll")
|
||||||
|
if(MSVC)
|
||||||
|
set(WICKRA_LINK_LIB "${WICKRA_LIB_DIR}/wickra.dll.lib")
|
||||||
|
else()
|
||||||
|
set(WICKRA_LINK_LIB "${WICKRA_LIB_DIR}/wickra.dll")
|
||||||
|
endif()
|
||||||
|
elseif(APPLE)
|
||||||
|
set(WICKRA_LINK_LIB "${WICKRA_LIB_DIR}/libwickra.dylib")
|
||||||
|
else()
|
||||||
|
set(WICKRA_LINK_LIB "${WICKRA_LIB_DIR}/libwickra.so")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(throughput throughput.c)
|
||||||
|
target_include_directories(throughput PRIVATE "${WICKRA_INCLUDE_DIR}")
|
||||||
|
target_link_libraries(throughput PRIVATE "${WICKRA_LINK_LIB}")
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
target_link_libraries(throughput PRIVATE m)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# On Windows copy the DLL next to the executable so the loader finds it.
|
||||||
|
if(WIN32)
|
||||||
|
add_custom_command(TARGET throughput POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${WICKRA_RUNTIME}" "$<TARGET_FILE_DIR:throughput>")
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Throughput benchmark for the Wickra C ABI.
|
||||||
|
*
|
||||||
|
* Measures how many indicator updates per second the C ABI sustains, both
|
||||||
|
* per-tick (streaming `_update`) and bulk (`_batch`), over a synthetic OHLCV
|
||||||
|
* series. It is the C counterpart of the Node throughput.js and the Rust
|
||||||
|
* criterion benches: it benchmarks Wickra's own O(1) streaming engine through
|
||||||
|
* the raw C boundary (there is no comparable streaming TA library to compare
|
||||||
|
* against), so the headline number is raw throughput, not a cross-library
|
||||||
|
* ratio. C is the thinnest binding, so these numbers are the floor of the
|
||||||
|
* per-binding FFI overhead the higher-level bindings build on.
|
||||||
|
*
|
||||||
|
* Three indicators are timed, chosen by call-signature archetype rather than
|
||||||
|
* algorithm: SMA (1-in -> 1-out), ATR (multi-in -> 1-out), and MACD
|
||||||
|
* (1-in -> multi-out). Streaming is timed for all three; batch only for the
|
||||||
|
* single-output SMA and ATR (the C ABI has no MACD batch entry point).
|
||||||
|
*
|
||||||
|
* Build the C ABI library first, then build and run the benchmark:
|
||||||
|
*
|
||||||
|
* cargo build -p wickra-c --release
|
||||||
|
* cmake -S bindings/c/benchmarks -B build/cbench -DCMAKE_BUILD_TYPE=Release
|
||||||
|
* cmake --build build/cbench
|
||||||
|
* ./build/cbench/throughput # 200k bars (default)
|
||||||
|
* ./build/cbench/throughput 1000000
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "wickra.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
static double now_ns(void) {
|
||||||
|
static LARGE_INTEGER freq;
|
||||||
|
static int init = 0;
|
||||||
|
LARGE_INTEGER counter;
|
||||||
|
if (!init) {
|
||||||
|
QueryPerformanceFrequency(&freq);
|
||||||
|
init = 1;
|
||||||
|
}
|
||||||
|
QueryPerformanceCounter(&counter);
|
||||||
|
return (double)counter.QuadPart * 1e9 / (double)freq.QuadPart;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <time.h>
|
||||||
|
static double now_ns(void) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (double)ts.tv_sec * 1e9 + (double)ts.tv_nsec;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static double median3(double a, double b, double c) {
|
||||||
|
if ((a <= b && b <= c) || (c <= b && b <= a)) return b;
|
||||||
|
if ((b <= a && a <= c) || (c <= a && a <= b)) return a;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run `body` once as warmup, then time three repetitions and store the median
|
||||||
|
* elapsed nanoseconds in `dst`. `body` is a brace-enclosed statement block. */
|
||||||
|
#define MEASURE(dst, body) \
|
||||||
|
do { \
|
||||||
|
body; \
|
||||||
|
double s0, s1, s2, t0; \
|
||||||
|
t0 = now_ns(); body; s0 = now_ns() - t0; \
|
||||||
|
t0 = now_ns(); body; s1 = now_ns() - t0; \
|
||||||
|
t0 = now_ns(); body; s2 = now_ns() - t0; \
|
||||||
|
(dst) = median3(s0, s1, s2); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
size_t bars = 200000;
|
||||||
|
if (argc > 1) {
|
||||||
|
long n = strtol(argv[1], NULL, 10);
|
||||||
|
if (n >= 1000) {
|
||||||
|
bars = (size_t)n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const size_t n = bars;
|
||||||
|
|
||||||
|
/* Deterministic synthetic OHLCV (no RNG, so runs are comparable). */
|
||||||
|
double *open = malloc(n * sizeof(double));
|
||||||
|
double *high = malloc(n * sizeof(double));
|
||||||
|
double *low = malloc(n * sizeof(double));
|
||||||
|
double *close = malloc(n * sizeof(double));
|
||||||
|
double *volume = malloc(n * sizeof(double));
|
||||||
|
int64_t *timestamp = malloc(n * sizeof(int64_t));
|
||||||
|
double *out = malloc(n * sizeof(double)); /* reused batch scratch buffer */
|
||||||
|
if (!open || !high || !low || !close || !volume || !timestamp || !out) {
|
||||||
|
fprintf(stderr, "allocation failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
double mid = 100 + sin((double)i * 0.001) * 20 + (double)i * 1e-4;
|
||||||
|
double c = mid + sin((double)i * 0.05) * 2;
|
||||||
|
close[i] = c;
|
||||||
|
open[i] = mid;
|
||||||
|
high[i] = fmax(c, mid) + 1.5;
|
||||||
|
low[i] = fmin(c, mid) - 1.5;
|
||||||
|
volume[i] = 1000 + (double)(i % 97) * 13;
|
||||||
|
timestamp[i] = (int64_t)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ns;
|
||||||
|
double sma_stream, sma_batch, atr_stream, atr_batch, macd_stream;
|
||||||
|
|
||||||
|
MEASURE(ns, {
|
||||||
|
struct Sma *ind = wickra_sma_new(20);
|
||||||
|
for (size_t i = 0; i < n; i++) wickra_sma_update(ind, close[i]);
|
||||||
|
wickra_sma_free(ind);
|
||||||
|
});
|
||||||
|
sma_stream = (double)n / (ns / 1e9) / 1e6;
|
||||||
|
|
||||||
|
MEASURE(ns, {
|
||||||
|
struct Sma *ind = wickra_sma_new(20);
|
||||||
|
wickra_sma_batch(ind, close, out, n);
|
||||||
|
wickra_sma_free(ind);
|
||||||
|
});
|
||||||
|
sma_batch = (double)n / (ns / 1e9) / 1e6;
|
||||||
|
|
||||||
|
MEASURE(ns, {
|
||||||
|
struct Atr *ind = wickra_atr_new(14);
|
||||||
|
for (size_t i = 0; i < n; i++)
|
||||||
|
wickra_atr_update(ind, open[i], high[i], low[i], close[i], volume[i], timestamp[i]);
|
||||||
|
wickra_atr_free(ind);
|
||||||
|
});
|
||||||
|
atr_stream = (double)n / (ns / 1e9) / 1e6;
|
||||||
|
|
||||||
|
MEASURE(ns, {
|
||||||
|
struct Atr *ind = wickra_atr_new(14);
|
||||||
|
wickra_atr_batch(ind, open, high, low, close, volume, timestamp, out, n);
|
||||||
|
wickra_atr_free(ind);
|
||||||
|
});
|
||||||
|
atr_batch = (double)n / (ns / 1e9) / 1e6;
|
||||||
|
|
||||||
|
MEASURE(ns, {
|
||||||
|
struct MacdIndicator *ind = wickra_macd_indicator_new(12, 26, 9);
|
||||||
|
struct WickraMacdOutput value;
|
||||||
|
for (size_t i = 0; i < n; i++) wickra_macd_indicator_update(ind, close[i], &value);
|
||||||
|
wickra_macd_indicator_free(ind);
|
||||||
|
});
|
||||||
|
macd_stream = (double)n / (ns / 1e9) / 1e6;
|
||||||
|
|
||||||
|
printf("Wickra C throughput - %zu bars (median of 3 runs)\n\n", n);
|
||||||
|
printf("%-22s%20s%18s\n", "Indicator", "streaming (Mupd/s)", "batch (Mupd/s)");
|
||||||
|
printf("------------------------------------------------------------\n");
|
||||||
|
printf("%-22s%20.1f%18.1f\n", "SMA(20)", sma_stream, sma_batch);
|
||||||
|
printf("%-22s%20.1f%18.1f\n", "ATR(14)", atr_stream, atr_batch);
|
||||||
|
printf("%-22s%20.1f%18s\n", "MACD(12,26,9)", macd_stream, "-");
|
||||||
|
|
||||||
|
printf("\nMupd/s = million indicator updates per second. Streaming is the per-tick\n"
|
||||||
|
"`_update` path (one C call per value); batch is the bulk array path (one\n"
|
||||||
|
"C call). Higher is better. Numbers are machine-dependent - use them for\n"
|
||||||
|
"relative comparison, not as a speed claim.\n");
|
||||||
|
|
||||||
|
free(open);
|
||||||
|
free(high);
|
||||||
|
free(low);
|
||||||
|
free(close);
|
||||||
|
free(volume);
|
||||||
|
free(timestamp);
|
||||||
|
free(out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
+13710
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,18 @@
|
|||||||
# Wickra — .NET
|
# Wickra — C#
|
||||||
|
|
||||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||||
[](https://www.nuget.org/packages/Wickra)
|
[](https://www.nuget.org/packages/Wickra)
|
||||||
[](https://github.com/wickra-lib/wickra#license)
|
[](https://github.com/wickra-lib/wickra#license)
|
||||||
|
|
||||||
**Streaming-first technical indicators for .NET. `dotnet add package Wickra` —
|
**Streaming-first technical indicators for C#. `dotnet add package Wickra` —
|
||||||
prebuilt native library, no system dependencies.**
|
prebuilt native library, no system dependencies.**
|
||||||
|
|
||||||
Wickra is a multi-language technical-analysis library with a Rust core and
|
Wickra is a multi-language technical-analysis library with a Rust core and
|
||||||
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R and any
|
bindings for Python, Node.js and WASM, plus a C ABI for C, C++, C#, Go, Java, R and any
|
||||||
other C-capable language. Every indicator is an O(1)
|
other C-capable language. Every indicator is an O(1)
|
||||||
streaming state machine, so live trading bots and historical backtests share
|
streaming state machine, so live trading bots and historical backtests share
|
||||||
the exact same implementation. This package is the .NET binding; it consumes the
|
the exact same implementation. This package is the C# binding; it consumes the
|
||||||
C ABI hub through `[LibraryImport]` P/Invoke and exposes all 514 streaming-first
|
C ABI hub through `[LibraryImport]` P/Invoke and exposes all 514 streaming-first
|
||||||
indicators as idiomatic `IDisposable` classes.
|
indicators as idiomatic `IDisposable` classes.
|
||||||
|
|
||||||
@@ -52,6 +52,18 @@ foreach (var price in liveFeed)
|
|||||||
values — the equivalence is enforced by the test suite. Multi-output indicators
|
values — the equivalence is enforced by the test suite. Multi-output indicators
|
||||||
(MACD, Bollinger, ADX, …) return a nullable `record struct`, `null` while warming up.
|
(MACD, Bollinger, ADX, …) return a nullable `record struct`, `null` while warming up.
|
||||||
|
|
||||||
|
## Benchmark
|
||||||
|
|
||||||
|
`benchmarks/` reports streaming and batch updates-per-second for `SMA`, `ATR`
|
||||||
|
and `MACD`. It measures this binding's FFI overhead, not a cross-library ratio
|
||||||
|
(the same Rust core runs under every binding) — see the repository
|
||||||
|
[BENCHMARKS.md](https://github.com/wickra-lib/wickra/blob/main/BENCHMARKS.md) §3.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build -p wickra-c --release
|
||||||
|
dotnet run -c Release --project benchmarks
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The full indicator catalogue, guides, quickstarts, and API reference live in
|
The full indicator catalogue, guides, quickstarts, and API reference live in
|
||||||
@@ -61,10 +73,17 @@ the main repository and documentation site:
|
|||||||
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
||||||
- **Runnable examples:** [`examples/csharp/`](https://github.com/wickra-lib/wickra/tree/main/examples/csharp)
|
- **Runnable examples:** [`examples/csharp/`](https://github.com/wickra-lib/wickra/tree/main/examples/csharp)
|
||||||
|
|
||||||
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus a
|
Wickra ships native bindings for Python, Node.js, WASM and Rust, plus a
|
||||||
C ABI hub that any C-capable language (C, C++, Go, C#, Java, R) links against —
|
C ABI hub that any C-capable language (C, C++, C#, Go, Java, R) links against —
|
||||||
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
|
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Found a security issue? **Please don't open a public issue.** Report it privately
|
||||||
|
via the affected repository's *Security* tab (*"Report a vulnerability"*) or email
|
||||||
|
**support@wickra.org** with a subject line starting `[wickra security]`. Full
|
||||||
|
policy: <https://github.com/wickra-lib/wickra/blob/main/SECURITY.md>.
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Wickra is an indicator toolkit, not a trading system. The values it computes
|
Wickra is an indicator toolkit, not a trading system. The values it computes
|
||||||
|
|||||||
@@ -34,6 +34,21 @@ public class ArchetypeTests
|
|||||||
Assert.InRange(last, 1.0, 10.0);
|
Assert.InRange(last, 1.0, 10.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Query_WarmupPeriodAndIsReady()
|
||||||
|
{
|
||||||
|
using var sma = new Sma(3);
|
||||||
|
Assert.Equal(3, sma.WarmupPeriod());
|
||||||
|
Assert.False(sma.IsReady());
|
||||||
|
sma.Update(1.0);
|
||||||
|
sma.Update(2.0);
|
||||||
|
Assert.False(sma.IsReady());
|
||||||
|
sma.Update(3.0);
|
||||||
|
Assert.True(sma.IsReady());
|
||||||
|
sma.Reset();
|
||||||
|
Assert.False(sma.IsReady());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Candle_Atr_IsFinitePositive()
|
public void Candle_Atr_IsFinitePositive()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Wickra;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Wickra.Tests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Golden-fixture parity: replay the shared <c>testdata/golden</c> input series
|
||||||
|
/// through the C# FFI and assert every value matches the Rust reference output.
|
||||||
|
/// Where the archetype tests only check finiteness, this pins exact values, so a
|
||||||
|
/// wiring bug (swapped parameter, wrong multi-output field) is caught.
|
||||||
|
/// Fixtures are generated by <c>cargo run -p wickra-examples --bin gen_golden</c>.
|
||||||
|
/// </summary>
|
||||||
|
public class GoldenTests
|
||||||
|
{
|
||||||
|
private const double Tol = 1e-6;
|
||||||
|
|
||||||
|
private static string GoldenDir([CallerFilePath] string file = "") =>
|
||||||
|
Path.GetFullPath(Path.Combine(Path.GetDirectoryName(file)!, "..", "..", "..", "testdata", "golden"));
|
||||||
|
|
||||||
|
private static List<string[]> ReadCsv(string name)
|
||||||
|
{
|
||||||
|
var path = Path.Combine(GoldenDir(), name + ".csv");
|
||||||
|
return File.ReadAllLines(path)
|
||||||
|
.Skip(1) // header
|
||||||
|
.Where(l => l.Length > 0)
|
||||||
|
.Select(l => l.Split(','))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double[][] Input()
|
||||||
|
{
|
||||||
|
return ReadCsv("input")
|
||||||
|
.Select(r => r.Select(c => double.Parse(c, CultureInfo.InvariantCulture)).ToArray())
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double Cell(string s) =>
|
||||||
|
s == "nan" ? double.NaN : double.Parse(s, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
private static void AssertClose(double got, double want, int row, string field)
|
||||||
|
{
|
||||||
|
if (double.IsNaN(want))
|
||||||
|
{
|
||||||
|
Assert.True(double.IsNaN(got), $"row {row} {field}: expected warmup/NaN, got {got}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var tol = Tol * Math.Max(1.0, Math.Abs(want));
|
||||||
|
Assert.True(Math.Abs(got - want) <= tol, $"row {row} {field}: got {got}, want {want}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- scalar (close-driven) ------------------------------------------------
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("sma")]
|
||||||
|
[InlineData("ema")]
|
||||||
|
[InlineData("rsi")]
|
||||||
|
public void Scalar_MatchesGolden(string name)
|
||||||
|
{
|
||||||
|
var input = Input();
|
||||||
|
var expected = ReadCsv(name);
|
||||||
|
using var ind = (IDisposable)(name switch
|
||||||
|
{
|
||||||
|
"sma" => new Sma(14),
|
||||||
|
"ema" => new Ema(14),
|
||||||
|
"rsi" => new Rsi(14),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(name)),
|
||||||
|
});
|
||||||
|
for (var i = 0; i < input.Length; i++)
|
||||||
|
{
|
||||||
|
var close = input[i][3];
|
||||||
|
double got = ind switch
|
||||||
|
{
|
||||||
|
Sma s => s.Update(close),
|
||||||
|
Ema e => e.Update(close),
|
||||||
|
Rsi r => r.Update(close),
|
||||||
|
_ => double.NaN,
|
||||||
|
};
|
||||||
|
AssertClose(got, Cell(expected[i][0]), i, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- candle, single output ------------------------------------------------
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Candle_Atr_MatchesGolden()
|
||||||
|
{
|
||||||
|
var input = Input();
|
||||||
|
var expected = ReadCsv("atr");
|
||||||
|
using var atr = new Atr(14);
|
||||||
|
for (var i = 0; i < input.Length; i++)
|
||||||
|
{
|
||||||
|
var (o, h, l, c, v) = (input[i][0], input[i][1], input[i][2], input[i][3], input[i][4]);
|
||||||
|
AssertClose(atr.Update(o, h, l, c, v, i), Cell(expected[i][0]), i, "atr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- pairwise -------------------------------------------------------------
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pairwise_Beta_MatchesGolden()
|
||||||
|
{
|
||||||
|
var input = Input();
|
||||||
|
var expected = ReadCsv("beta");
|
||||||
|
using var beta = new Beta(20);
|
||||||
|
for (var i = 0; i < input.Length; i++)
|
||||||
|
{
|
||||||
|
// generator fed (close, open)
|
||||||
|
AssertClose(beta.Update(input[i][3], input[i][0]), Cell(expected[i][0]), i, "beta");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- scalar multi-output: MACD -------------------------------------------
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MultiOutput_Macd_MatchesGolden()
|
||||||
|
{
|
||||||
|
var input = Input();
|
||||||
|
var expected = ReadCsv("macd");
|
||||||
|
using var macd = new MacdIndicator(12, 26, 9);
|
||||||
|
for (var i = 0; i < input.Length; i++)
|
||||||
|
{
|
||||||
|
MacdOutput? got = macd.Update(input[i][3]);
|
||||||
|
var e = expected[i];
|
||||||
|
if (e[0] == "nan")
|
||||||
|
{
|
||||||
|
Assert.Null(got);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Assert.NotNull(got);
|
||||||
|
AssertClose(got!.Value.Macd, Cell(e[0]), i, "macd.macd");
|
||||||
|
AssertClose(got.Value.Signal, Cell(e[1]), i, "macd.signal");
|
||||||
|
AssertClose(got.Value.Histogram, Cell(e[2]), i, "macd.histogram");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- candle multi-output: ADX --------------------------------------------
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MultiOutput_Adx_MatchesGolden()
|
||||||
|
{
|
||||||
|
var input = Input();
|
||||||
|
var expected = ReadCsv("adx");
|
||||||
|
using var adx = new Adx(14);
|
||||||
|
for (var i = 0; i < input.Length; i++)
|
||||||
|
{
|
||||||
|
var (o, h, l, c, v) = (input[i][0], input[i][1], input[i][2], input[i][3], input[i][4]);
|
||||||
|
AdxOutput? got = adx.Update(o, h, l, c, v, i);
|
||||||
|
var e = expected[i];
|
||||||
|
if (e[0] == "nan")
|
||||||
|
{
|
||||||
|
Assert.Null(got);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Assert.NotNull(got);
|
||||||
|
AssertClose(got!.Value.PlusDi, Cell(e[0]), i, "adx.plus_di");
|
||||||
|
AssertClose(got.Value.MinusDi, Cell(e[1]), i, "adx.minus_di");
|
||||||
|
AssertClose(got.Value.Adx, Cell(e[2]), i, "adx.adx");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<!-- NuGet package metadata -->
|
<!-- NuGet package metadata -->
|
||||||
<PackageId>Wickra</PackageId>
|
<PackageId>Wickra</PackageId>
|
||||||
<Version>0.8.2</Version>
|
<Version>0.9.1</Version>
|
||||||
<Authors>kingchenc</Authors>
|
<Authors>kingchenc</Authors>
|
||||||
<Description>High-performance streaming technical-analysis indicators (514 indicators) for .NET, backed by the native Rust core via the Wickra C ABI.</Description>
|
<Description>High-performance streaming technical-analysis indicators (514 indicators) for .NET, backed by the native Rust core via the Wickra C ABI.</Description>
|
||||||
<PackageLicenseExpression>MIT OR Apache-2.0</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT OR Apache-2.0</PackageLicenseExpression>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageTags>technical-analysis;indicators;trading;finance;streaming;ffi;native</PackageTags>
|
<PackageTags>technical-analysis;indicators;trading;finance;streaming;ffi;native</PackageTags>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
||||||
|
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<!-- Standalone throughput benchmark for the Wickra C# binding.
|
||||||
|
See Program.cs for run instructions. Requires the C ABI library; the
|
||||||
|
binding's dev DllImportResolver falls back to target/release. -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<AssemblyName>Wickra.Benchmarks</AssemblyName>
|
||||||
|
<RootNamespace>Wickra.Benchmarks</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Wickra\Wickra.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
// Throughput benchmark for the Wickra C# binding.
|
||||||
|
//
|
||||||
|
// Measures how many indicator updates per second the binding sustains, both
|
||||||
|
// per-tick (streaming Update) and bulk (Batch), over a synthetic OHLCV series.
|
||||||
|
// It is the C# counterpart of the Node throughput.js and the Rust criterion
|
||||||
|
// benches: it benchmarks Wickra's own O(1) streaming engine across the
|
||||||
|
// managed<->C-ABI boundary (there is no comparable streaming TA library on
|
||||||
|
// NuGet to compare against), so the headline number is raw per-binding
|
||||||
|
// throughput / FFI overhead, not a cross-library ratio.
|
||||||
|
//
|
||||||
|
// Three indicators are timed, chosen by FFI call-signature archetype rather
|
||||||
|
// than algorithm: SMA (1-in -> 1-out), ATR (multi-in -> 1-out), and MACD
|
||||||
|
// (1-in -> multi-out). Streaming is timed for all three; batch only for the
|
||||||
|
// single-output SMA and ATR (multi-output batch is not exposed uniformly).
|
||||||
|
//
|
||||||
|
// cargo build -p wickra-c --release
|
||||||
|
// dotnet run -c Release --project bindings/csharp/benchmarks # 200k bars
|
||||||
|
// dotnet run -c Release --project bindings/csharp/benchmarks -- --bars 1000000
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using Wickra;
|
||||||
|
|
||||||
|
// Deterministic, locale-independent number formatting for the report.
|
||||||
|
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
|
int bars = 200_000;
|
||||||
|
for (int i = 0; i < args.Length - 1; i++)
|
||||||
|
{
|
||||||
|
if (args[i] == "--bars" && int.TryParse(args[i + 1], out var n) && n >= 1000)
|
||||||
|
{
|
||||||
|
bars = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic synthetic OHLCV (no RNG, so runs are comparable).
|
||||||
|
var open = new double[bars];
|
||||||
|
var high = new double[bars];
|
||||||
|
var low = new double[bars];
|
||||||
|
var close = new double[bars];
|
||||||
|
var volume = new double[bars];
|
||||||
|
var timestamp = new long[bars];
|
||||||
|
for (int i = 0; i < bars; i++)
|
||||||
|
{
|
||||||
|
double mid = 100 + Math.Sin(i * 0.001) * 20 + i * 1e-4;
|
||||||
|
double c = mid + Math.Sin(i * 0.05) * 2;
|
||||||
|
close[i] = c;
|
||||||
|
open[i] = mid;
|
||||||
|
high[i] = Math.Max(c, mid) + 1.5;
|
||||||
|
low[i] = Math.Min(c, mid) - 1.5;
|
||||||
|
volume[i] = 1000 + (i % 97) * 13;
|
||||||
|
timestamp[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Mups(double ns) => bars / (ns / 1e9) / 1e6;
|
||||||
|
|
||||||
|
// Median elapsed-ns over a few repetitions, after one warmup pass.
|
||||||
|
double TimeNs(Action fn, int reps = 3)
|
||||||
|
{
|
||||||
|
fn(); // warmup (JIT + cache)
|
||||||
|
var samples = new double[reps];
|
||||||
|
for (int r = 0; r < reps; r++)
|
||||||
|
{
|
||||||
|
long t0 = Stopwatch.GetTimestamp();
|
||||||
|
fn();
|
||||||
|
samples[r] = (Stopwatch.GetTimestamp() - t0) * (1e9 / Stopwatch.Frequency);
|
||||||
|
}
|
||||||
|
Array.Sort(samples);
|
||||||
|
return samples[reps / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// SMA (scalar 1-in/1-out), ATR (multi-in/1-out), MACD (1-in/multi-out).
|
||||||
|
var indicators = new (string Name, Action Stream, Action? Batch)[]
|
||||||
|
{
|
||||||
|
("SMA(20)",
|
||||||
|
() => { using var ind = new Sma(20); for (int i = 0; i < bars; i++) ind.Update(close[i]); },
|
||||||
|
() => { using var ind = new Sma(20); ind.Batch(close); }),
|
||||||
|
("ATR(14)",
|
||||||
|
() => { using var ind = new Atr(14); for (int i = 0; i < bars; i++) ind.Update(open[i], high[i], low[i], close[i], volume[i], timestamp[i]); },
|
||||||
|
() => { using var ind = new Atr(14); ind.Batch(open, high, low, close, volume, timestamp); }),
|
||||||
|
("MACD(12,26,9)",
|
||||||
|
() => { using var ind = new MacdIndicator(12, 26, 9); for (int i = 0; i < bars; i++) ind.Update(close[i]); },
|
||||||
|
null), // multi-output: streaming only
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine($"Wickra C# throughput - {bars:N0} bars (median of 3 runs)\n");
|
||||||
|
Console.WriteLine($"{"Indicator",-22}{"streaming (Mupd/s)",20}{"batch (Mupd/s)",18}");
|
||||||
|
Console.WriteLine(new string('-', 60));
|
||||||
|
|
||||||
|
foreach (var (name, stream, batch) in indicators)
|
||||||
|
{
|
||||||
|
string streamMups = Mups(TimeNs(stream)).ToString("F1");
|
||||||
|
string batchMups = batch is null ? "-" : Mups(TimeNs(batch)).ToString("F1");
|
||||||
|
Console.WriteLine($"{name,-22}{streamMups,20}{batchMups,18}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(
|
||||||
|
"\nMupd/s = million indicator updates per second. Streaming is the per-tick\n" +
|
||||||
|
"Update path crossing the managed<->C-ABI boundary once per value; batch is\n" +
|
||||||
|
"the bulk array path (one boundary crossing). Higher is better. Numbers are\n" +
|
||||||
|
"machine-dependent - use them for relative comparison, not as a speed claim.");
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
+20
-2
@@ -8,7 +8,7 @@
|
|||||||
**Streaming-first technical indicators for Go, over the Wickra C ABI hub via cgo.**
|
**Streaming-first technical indicators for Go, over the Wickra C ABI hub via cgo.**
|
||||||
|
|
||||||
Wickra is a multi-language technical-analysis library with a Rust core and
|
Wickra is a multi-language technical-analysis library with a Rust core and
|
||||||
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R and
|
bindings for Python, Node.js and WASM, plus a C ABI for C, C++, C#, Go, Java, R and
|
||||||
any other C-capable language. Every indicator is an O(1) streaming state machine,
|
any other C-capable language. Every indicator is an O(1) streaming state machine,
|
||||||
so live trading bots and historical backtests share the exact same
|
so live trading bots and historical backtests share the exact same
|
||||||
implementation. This package is the Go binding; it consumes the C ABI hub through
|
implementation. This package is the Go binding; it consumes the C ABI hub through
|
||||||
@@ -88,6 +88,17 @@ values — the equivalence is enforced by the test suite. Multi-output indicator
|
|||||||
Every indicator owns a native handle freed by `Close()`; a finalizer is wired as
|
Every indicator owns a native handle freed by `Close()`; a finalizer is wired as
|
||||||
a backstop, but call `Close()` (e.g. with `defer`) to release memory promptly.
|
a backstop, but call `Close()` (e.g. with `defer`) to release memory promptly.
|
||||||
|
|
||||||
|
## Benchmark
|
||||||
|
|
||||||
|
`benchmarks/throughput.go` reports streaming and batch updates-per-second for
|
||||||
|
`SMA`, `ATR` and `MACD`. It measures this binding's FFI overhead, not a
|
||||||
|
cross-library ratio (the same Rust core runs under every binding) — see the
|
||||||
|
repository [BENCHMARKS.md](https://github.com/wickra-lib/wickra/blob/main/BENCHMARKS.md) §3.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd benchmarks && go run .
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The full indicator catalogue, guides, quickstarts, and API reference live in the
|
The full indicator catalogue, guides, quickstarts, and API reference live in the
|
||||||
@@ -97,10 +108,17 @@ main repository and documentation site:
|
|||||||
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
||||||
- **Runnable examples:** [`examples/go/`](https://github.com/wickra-lib/wickra/tree/main/examples/go)
|
- **Runnable examples:** [`examples/go/`](https://github.com/wickra-lib/wickra/tree/main/examples/go)
|
||||||
|
|
||||||
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus a
|
Wickra ships native bindings for Python, Node.js, WASM and Rust, plus a
|
||||||
C ABI hub that any C-capable language (C, C++, C#, Go, Java, R) links against —
|
C ABI hub that any C-capable language (C, C++, C#, Go, Java, R) links against —
|
||||||
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
|
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Found a security issue? **Please don't open a public issue.** Report it privately
|
||||||
|
via the affected repository's *Security* tab (*"Report a vulnerability"*) or email
|
||||||
|
**support@wickra.org** with a subject line starting `[wickra security]`. Full
|
||||||
|
policy: <https://github.com/wickra-lib/wickra/blob/main/SECURITY.md>.
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Wickra is an indicator toolkit, not a trading system. The values it computes are
|
Wickra is an indicator toolkit, not a trading system. The values it computes are
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
// Throughput benchmark for the Wickra Go bindings.
|
||||||
|
//
|
||||||
|
// Measures how many indicator updates per second the cgo binding sustains,
|
||||||
|
// both per-tick (streaming Update) and bulk (Batch), over a synthetic OHLCV
|
||||||
|
// series. It is the Go counterpart of the Node throughput.js and the Rust
|
||||||
|
// criterion benches: it benchmarks Wickra's own O(1) streaming engine across
|
||||||
|
// the Go<->C-ABI boundary (there is no comparable streaming TA library to
|
||||||
|
// compare against), so the headline number is raw per-binding throughput /
|
||||||
|
// FFI overhead, not a cross-library ratio.
|
||||||
|
//
|
||||||
|
// Three indicators are timed, chosen by FFI call-signature archetype rather
|
||||||
|
// than algorithm: SMA (1-in -> 1-out), ATR (multi-in -> 1-out), and MACD
|
||||||
|
// (1-in -> multi-out). Streaming is timed for all three; batch only for the
|
||||||
|
// single-output SMA and ATR (multi-output batch is not exposed uniformly).
|
||||||
|
//
|
||||||
|
// Provision the C ABI library first (see bindings/go/README.md), then run:
|
||||||
|
//
|
||||||
|
// cd bindings/go/benchmarks
|
||||||
|
// go run . # 200k bars (default)
|
||||||
|
// go run . -bars 1000000
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
wickra "github.com/wickra-lib/wickra/bindings/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
bars := flag.Int("bars", 200_000, "number of synthetic bars to feed")
|
||||||
|
flag.Parse()
|
||||||
|
n := *bars
|
||||||
|
if n < 1000 {
|
||||||
|
fmt.Println("-bars must be >= 1000")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic synthetic OHLCV (no RNG, so runs are comparable).
|
||||||
|
open := make([]float64, n)
|
||||||
|
high := make([]float64, n)
|
||||||
|
low := make([]float64, n)
|
||||||
|
closeP := make([]float64, n)
|
||||||
|
volume := make([]float64, n)
|
||||||
|
timestamp := make([]int64, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
mid := 100 + math.Sin(float64(i)*0.001)*20 + float64(i)*1e-4
|
||||||
|
c := mid + math.Sin(float64(i)*0.05)*2
|
||||||
|
closeP[i] = c
|
||||||
|
open[i] = mid
|
||||||
|
high[i] = math.Max(c, mid) + 1.5
|
||||||
|
low[i] = math.Min(c, mid) - 1.5
|
||||||
|
volume[i] = 1000 + float64(i%97)*13
|
||||||
|
timestamp[i] = int64(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
mups := func(d time.Duration) float64 {
|
||||||
|
return float64(n) / d.Seconds() / 1e6
|
||||||
|
}
|
||||||
|
|
||||||
|
// Median elapsed over a few repetitions, after one warmup pass.
|
||||||
|
timeFn := func(fn func()) time.Duration {
|
||||||
|
fn() // warmup
|
||||||
|
const reps = 3
|
||||||
|
samples := make([]time.Duration, reps)
|
||||||
|
for r := 0; r < reps; r++ {
|
||||||
|
t0 := time.Now()
|
||||||
|
fn()
|
||||||
|
samples[r] = time.Since(t0)
|
||||||
|
}
|
||||||
|
sort.Slice(samples, func(a, b int) bool { return samples[a] < samples[b] })
|
||||||
|
return samples[reps/2]
|
||||||
|
}
|
||||||
|
|
||||||
|
type indicator struct {
|
||||||
|
name string
|
||||||
|
stream func()
|
||||||
|
batch func() // nil -> streaming only
|
||||||
|
}
|
||||||
|
|
||||||
|
indicators := []indicator{
|
||||||
|
{
|
||||||
|
name: "SMA(20)",
|
||||||
|
stream: func() {
|
||||||
|
ind, _ := wickra.NewSma(20)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
ind.Update(closeP[i])
|
||||||
|
}
|
||||||
|
ind.Close()
|
||||||
|
},
|
||||||
|
batch: func() {
|
||||||
|
ind, _ := wickra.NewSma(20)
|
||||||
|
ind.Batch(closeP)
|
||||||
|
ind.Close()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ATR(14)",
|
||||||
|
stream: func() {
|
||||||
|
ind, _ := wickra.NewAtr(14)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
ind.Update(open[i], high[i], low[i], closeP[i], volume[i], timestamp[i])
|
||||||
|
}
|
||||||
|
ind.Close()
|
||||||
|
},
|
||||||
|
batch: func() {
|
||||||
|
ind, _ := wickra.NewAtr(14)
|
||||||
|
ind.Batch(open, high, low, closeP, volume, timestamp)
|
||||||
|
ind.Close()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "MACD(12,26,9)",
|
||||||
|
stream: func() {
|
||||||
|
ind, _ := wickra.NewMacdIndicator(12, 26, 9)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
ind.Update(closeP[i])
|
||||||
|
}
|
||||||
|
ind.Close()
|
||||||
|
},
|
||||||
|
batch: nil, // multi-output: streaming only
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Wickra Go throughput - %d bars (median of 3 runs)\n\n", n)
|
||||||
|
fmt.Printf("%-22s%20s%18s\n", "Indicator", "streaming (Mupd/s)", "batch (Mupd/s)")
|
||||||
|
fmt.Println("------------------------------------------------------------")
|
||||||
|
|
||||||
|
for _, ind := range indicators {
|
||||||
|
streamMups := fmt.Sprintf("%.1f", mups(timeFn(ind.stream)))
|
||||||
|
batchMups := "-"
|
||||||
|
if ind.batch != nil {
|
||||||
|
batchMups = fmt.Sprintf("%.1f", mups(timeFn(ind.batch)))
|
||||||
|
}
|
||||||
|
fmt.Printf("%-22s%20s%18s\n", ind.name, streamMups, batchMups)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("\nMupd/s = million indicator updates per second. Streaming is the per-tick\n",
|
||||||
|
"Update path crossing the Go<->C-ABI boundary once per value; batch is the\n",
|
||||||
|
"bulk slice path (one boundary crossing). Higher is better. Numbers are\n",
|
||||||
|
"machine-dependent - use them for relative comparison, not as a speed claim.\n")
|
||||||
|
}
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
package wickra
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Golden-fixture parity: replay the shared testdata/golden input series through
|
||||||
|
// the Go FFI and assert every value matches the Rust reference output. Where the
|
||||||
|
// archetype test only checks finiteness, this pins exact values, catching wiring
|
||||||
|
// bugs (swapped params, wrong multi-output field). Fixtures are generated by
|
||||||
|
// `cargo run -p wickra-examples --bin gen_golden`.
|
||||||
|
|
||||||
|
const goldenTol = 1e-6
|
||||||
|
|
||||||
|
func readGolden(t *testing.T, name string) [][]string {
|
||||||
|
t.Helper()
|
||||||
|
f, err := os.Open("../../testdata/golden/" + name + ".csv")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("open %s: %v", name, err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
var rows [][]string
|
||||||
|
sc := bufio.NewScanner(f)
|
||||||
|
first := true
|
||||||
|
for sc.Scan() {
|
||||||
|
line := sc.Text()
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rows = append(rows, strings.Split(line, ","))
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
func goldenCell(s string) float64 {
|
||||||
|
if s == "nan" {
|
||||||
|
return math.NaN()
|
||||||
|
}
|
||||||
|
v, _ := strconv.ParseFloat(s, 64)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func goldenInput(t *testing.T) [][]float64 {
|
||||||
|
rows := readGolden(t, "input")
|
||||||
|
out := make([][]float64, len(rows))
|
||||||
|
for i, r := range rows {
|
||||||
|
vals := make([]float64, len(r))
|
||||||
|
for j, c := range r {
|
||||||
|
vals[j] = goldenCell(c)
|
||||||
|
}
|
||||||
|
out[i] = vals
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertGoldenClose(t *testing.T, got, want float64, row int, field string) {
|
||||||
|
t.Helper()
|
||||||
|
if math.IsNaN(want) {
|
||||||
|
if !math.IsNaN(got) {
|
||||||
|
t.Errorf("row %d %s: expected warmup/NaN, got %v", row, field, got)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tol := goldenTol * math.Max(1.0, math.Abs(want))
|
||||||
|
if math.Abs(got-want) > tol {
|
||||||
|
t.Errorf("row %d %s: got %v want %v", row, field, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoldenScalar(t *testing.T) {
|
||||||
|
input := goldenInput(t)
|
||||||
|
sma, err := NewSma(14)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer sma.Close()
|
||||||
|
ema, err := NewEma(14)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer ema.Close()
|
||||||
|
rsi, err := NewRsi(14)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer rsi.Close()
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
upd func(close float64) float64
|
||||||
|
}{
|
||||||
|
{"sma", sma.Update},
|
||||||
|
{"ema", ema.Update},
|
||||||
|
{"rsi", rsi.Update},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
exp := readGolden(t, tc.name)
|
||||||
|
for i := range input {
|
||||||
|
assertGoldenClose(t, tc.upd(input[i][3]), goldenCell(exp[i][0]), i, tc.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoldenAtr(t *testing.T) {
|
||||||
|
input := goldenInput(t)
|
||||||
|
exp := readGolden(t, "atr")
|
||||||
|
atr, err := NewAtr(14)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer atr.Close()
|
||||||
|
for i := range input {
|
||||||
|
got := atr.Update(input[i][0], input[i][1], input[i][2], input[i][3], input[i][4], int64(i))
|
||||||
|
assertGoldenClose(t, got, goldenCell(exp[i][0]), i, "atr")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoldenBeta(t *testing.T) {
|
||||||
|
input := goldenInput(t)
|
||||||
|
exp := readGolden(t, "beta")
|
||||||
|
beta, err := NewBeta(20)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer beta.Close()
|
||||||
|
for i := range input {
|
||||||
|
// generator fed (close, open)
|
||||||
|
assertGoldenClose(t, beta.Update(input[i][3], input[i][0]), goldenCell(exp[i][0]), i, "beta")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoldenMacd(t *testing.T) {
|
||||||
|
input := goldenInput(t)
|
||||||
|
exp := readGolden(t, "macd")
|
||||||
|
macd, err := NewMacdIndicator(12, 26, 9)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer macd.Close()
|
||||||
|
for i := range input {
|
||||||
|
out, ok := macd.Update(input[i][3])
|
||||||
|
if exp[i][0] == "nan" {
|
||||||
|
if ok {
|
||||||
|
t.Errorf("row %d macd: expected warmup, got %+v", i, out)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("row %d macd: expected value, got warmup", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
assertGoldenClose(t, out.Macd, goldenCell(exp[i][0]), i, "macd.macd")
|
||||||
|
assertGoldenClose(t, out.Signal, goldenCell(exp[i][1]), i, "macd.signal")
|
||||||
|
assertGoldenClose(t, out.Histogram, goldenCell(exp[i][2]), i, "macd.histogram")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoldenAdx(t *testing.T) {
|
||||||
|
input := goldenInput(t)
|
||||||
|
exp := readGolden(t, "adx")
|
||||||
|
adx, err := NewAdx(14)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer adx.Close()
|
||||||
|
for i := range input {
|
||||||
|
out, ok := adx.Update(input[i][0], input[i][1], input[i][2], input[i][3], input[i][4], int64(i))
|
||||||
|
if exp[i][0] == "nan" {
|
||||||
|
if ok {
|
||||||
|
t.Errorf("row %d adx: expected warmup, got %+v", i, out)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("row %d adx: expected value, got warmup", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
assertGoldenClose(t, out.PlusDi, goldenCell(exp[i][0]), i, "adx.plus_di")
|
||||||
|
assertGoldenClose(t, out.MinusDi, goldenCell(exp[i][1]), i, "adx.minus_di")
|
||||||
|
assertGoldenClose(t, out.Adx, goldenCell(exp[i][2]), i, "adx.adx")
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,34 @@ func TestScalarKnownValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWarmupPeriodAndIsReady(t *testing.T) {
|
||||||
|
s, err := NewSma(3)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewSma: %v", err)
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
if got := s.WarmupPeriod(); got != 3 {
|
||||||
|
t.Fatalf("sma(3) WarmupPeriod = %d, want 3", got)
|
||||||
|
}
|
||||||
|
if s.IsReady() {
|
||||||
|
t.Fatal("sma is ready before any update")
|
||||||
|
}
|
||||||
|
s.Update(1)
|
||||||
|
s.Update(2)
|
||||||
|
if s.IsReady() {
|
||||||
|
t.Fatal("sma is ready mid-warmup")
|
||||||
|
}
|
||||||
|
s.Update(3)
|
||||||
|
if !s.IsReady() {
|
||||||
|
t.Fatal("sma is not ready after the warmup period")
|
||||||
|
}
|
||||||
|
s.Reset()
|
||||||
|
if s.IsReady() {
|
||||||
|
t.Fatal("sma is ready after reset")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestScalarBatchMatchesStreaming(t *testing.T) {
|
func TestScalarBatchMatchesStreaming(t *testing.T) {
|
||||||
input := []float64{1, 2, 3, 4, 5, 6, 7, 8}
|
input := []float64{1, 2, 3, 4, 5, 6, 7, 8}
|
||||||
|
|
||||||
|
|||||||
+25
-5
@@ -9,7 +9,7 @@
|
|||||||
& Memory API — prebuilt native library, no JNI, no system dependencies.**
|
& Memory API — prebuilt native library, no JNI, no system dependencies.**
|
||||||
|
|
||||||
Wickra is a multi-language technical-analysis library with a Rust core and
|
Wickra is a multi-language technical-analysis library with a Rust core and
|
||||||
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R
|
bindings for Python, Node.js and WASM, plus a C ABI for C, C++, C#, Go, Java, R
|
||||||
and any other C-capable language. Every indicator is an O(1) streaming state
|
and any other C-capable language. Every indicator is an O(1) streaming state
|
||||||
machine, so live trading bots and historical backtests share the exact same
|
machine, so live trading bots and historical backtests share the exact same
|
||||||
implementation. This package is the Java binding; it consumes the C ABI hub
|
implementation. This package is the Java binding; it consumes the C ABI hub
|
||||||
@@ -30,14 +30,14 @@ Maven:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.wickra</groupId>
|
<groupId>org.wickra</groupId>
|
||||||
<artifactId>wickra</artifactId>
|
<artifactId>wickra</artifactId>
|
||||||
<version>0.8.2</version>
|
<version>0.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
Gradle:
|
Gradle:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
implementation("org.wickra:wickra:0.8.2")
|
implementation("org.wickra:wickra:0.9.1")
|
||||||
```
|
```
|
||||||
|
|
||||||
The native library ships prebuilt per platform (Linux, macOS, Windows — x64 and
|
The native library ships prebuilt per platform (Linux, macOS, Windows — x64 and
|
||||||
@@ -76,6 +76,19 @@ values — the equivalence is enforced by the test suite. Multi-output indicator
|
|||||||
indicator owns a native handle freed by a `Cleaner`; `close()` releases it
|
indicator owns a native handle freed by a `Cleaner`; `close()` releases it
|
||||||
eagerly (use try-with-resources).
|
eagerly (use try-with-resources).
|
||||||
|
|
||||||
|
## Benchmark
|
||||||
|
|
||||||
|
`benchmarks/` reports streaming and batch updates-per-second for `SMA`, `ATR`
|
||||||
|
and `MACD`. It measures this binding's FFI overhead, not a cross-library ratio
|
||||||
|
(the same Rust core runs under every binding) — see the repository
|
||||||
|
[BENCHMARKS.md](https://github.com/wickra-lib/wickra/blob/main/BENCHMARKS.md) §3.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build -p wickra-c --release
|
||||||
|
mvn -q install -DskipTests
|
||||||
|
mvn -q -f benchmarks exec:exec -Dexec.mainClass=org.wickra.benchmarks.Throughput
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
The full indicator catalogue, guides, quickstarts, and API reference live in
|
The full indicator catalogue, guides, quickstarts, and API reference live in
|
||||||
@@ -85,10 +98,17 @@ the main repository and documentation site:
|
|||||||
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
||||||
- **Runnable examples:** [`examples/java/`](https://github.com/wickra-lib/wickra/tree/main/examples/java)
|
- **Runnable examples:** [`examples/java/`](https://github.com/wickra-lib/wickra/tree/main/examples/java)
|
||||||
|
|
||||||
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus a
|
Wickra ships native bindings for Python, Node.js, WASM and Rust, plus a
|
||||||
C ABI hub that any C-capable language (C, C++, Go, C#, Java, R) links against —
|
C ABI hub that any C-capable language (C, C++, C#, Go, Java, R) links against —
|
||||||
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
|
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Found a security issue? **Please don't open a public issue.** Report it privately
|
||||||
|
via the affected repository's *Security* tab (*"Report a vulnerability"*) or email
|
||||||
|
**support@wickra.org** with a subject line starting `[wickra security]`. Full
|
||||||
|
policy: <https://github.com/wickra-lib/wickra/blob/main/SECURITY.md>.
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
Wickra is an indicator toolkit, not a trading system. The values it computes
|
Wickra is an indicator toolkit, not a trading system. The values it computes
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.wickra.benchmarks</groupId>
|
||||||
|
<artifactId>wickra-benchmarks</artifactId>
|
||||||
|
<version>0.8.2</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Wickra Java benchmarks</name>
|
||||||
|
<description>Throughput benchmark for the Wickra Java binding.</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.release>22</maven.compiler.release>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wickra</groupId>
|
||||||
|
<artifactId>wickra</artifactId>
|
||||||
|
<version>0.8.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.15.0</version>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Run the benchmark in a forked JVM with native access granted:
|
||||||
|
mvn exec:exec -Dexec.mainClass=org.wickra.benchmarks.Throughput
|
||||||
|
Requires the C ABI library and the installed binding; see Throughput.java.
|
||||||
|
-->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<version>3.6.3</version>
|
||||||
|
<configuration>
|
||||||
|
<executable>${java.home}/bin/java</executable>
|
||||||
|
<arguments>
|
||||||
|
<argument>--enable-native-access=ALL-UNNAMED</argument>
|
||||||
|
<argument>-classpath</argument>
|
||||||
|
<classpath/>
|
||||||
|
<argument>${exec.mainClass}</argument>
|
||||||
|
</arguments>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package org.wickra.benchmarks;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
import org.wickra.Atr;
|
||||||
|
import org.wickra.MacdIndicator;
|
||||||
|
import org.wickra.Sma;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throughput benchmark for the Wickra Java binding.
|
||||||
|
*
|
||||||
|
* <p>Measures how many indicator updates per second the binding sustains, both
|
||||||
|
* per-tick (streaming {@code update}) and bulk ({@code batch}), over a synthetic
|
||||||
|
* OHLCV series. It is the Java counterpart of the Node {@code throughput.js} and
|
||||||
|
* the Rust criterion benches: it benchmarks Wickra's own O(1) streaming engine
|
||||||
|
* across the Java FFM <-> C-ABI boundary (there is no comparable streaming
|
||||||
|
* TA library on Maven Central to compare against), so the headline number is raw
|
||||||
|
* per-binding throughput / FFI overhead, not a cross-library ratio.
|
||||||
|
*
|
||||||
|
* <p>Three indicators are timed, chosen by FFI call-signature archetype rather
|
||||||
|
* than algorithm: SMA (1-in -> 1-out), ATR (multi-in -> 1-out), and MACD
|
||||||
|
* (1-in -> multi-out). Streaming is timed for all three; batch only for the
|
||||||
|
* single-output SMA and ATR (multi-output batch is not exposed uniformly).
|
||||||
|
*
|
||||||
|
* <p>Install the binding and build the C ABI library first, then run from the
|
||||||
|
* repo root:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* cargo build -p wickra-c --release
|
||||||
|
* mvn -q -f bindings/java install -DskipTests
|
||||||
|
* mvn -q -f bindings/java/benchmarks exec:exec -Dexec.mainClass=org.wickra.benchmarks.Throughput
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final class Throughput {
|
||||||
|
private Throughput() {}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int bars = 200_000;
|
||||||
|
for (int i = 0; i < args.length - 1; i++) {
|
||||||
|
if (args[i].equals("--bars")) {
|
||||||
|
try {
|
||||||
|
int n = Integer.parseInt(args[i + 1]);
|
||||||
|
if (n >= 1000) {
|
||||||
|
bars = n;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
// keep default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic synthetic OHLCV (no RNG, so runs are comparable).
|
||||||
|
double[] open = new double[bars];
|
||||||
|
double[] high = new double[bars];
|
||||||
|
double[] low = new double[bars];
|
||||||
|
double[] close = new double[bars];
|
||||||
|
double[] volume = new double[bars];
|
||||||
|
double[] timestamp = new double[bars];
|
||||||
|
for (int i = 0; i < bars; i++) {
|
||||||
|
double mid = 100 + Math.sin(i * 0.001) * 20 + i * 1e-4;
|
||||||
|
double c = mid + Math.sin(i * 0.05) * 2;
|
||||||
|
close[i] = c;
|
||||||
|
open[i] = mid;
|
||||||
|
high[i] = Math.max(c, mid) + 1.5;
|
||||||
|
low[i] = Math.min(c, mid) - 1.5;
|
||||||
|
volume[i] = 1000 + (i % 97) * 13;
|
||||||
|
timestamp[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int n = bars;
|
||||||
|
|
||||||
|
// SMA (scalar 1-in/1-out), ATR (multi-in/1-out), MACD (1-in/multi-out).
|
||||||
|
Indicator[] indicators = {
|
||||||
|
new Indicator("SMA(20)",
|
||||||
|
() -> {
|
||||||
|
try (Sma ind = new Sma(20)) {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
ind.update(close[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
try (Sma ind = new Sma(20)) {
|
||||||
|
ind.batch(close);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new Indicator("ATR(14)",
|
||||||
|
() -> {
|
||||||
|
try (Atr ind = new Atr(14)) {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
ind.update(open[i], high[i], low[i], close[i], volume[i], (long) timestamp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
try (Atr ind = new Atr(14)) {
|
||||||
|
ind.batch(open, high, low, close, volume, timestamp);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new Indicator("MACD(12,26,9)",
|
||||||
|
() -> {
|
||||||
|
try (MacdIndicator ind = new MacdIndicator(12, 26, 9)) {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
ind.update(close[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null), // multi-output: streaming only
|
||||||
|
};
|
||||||
|
|
||||||
|
System.out.printf(Locale.ROOT, "Wickra Java throughput - %,d bars (median of 3 runs)%n%n", bars);
|
||||||
|
System.out.printf(Locale.ROOT, "%-22s%20s%18s%n", "Indicator", "streaming (Mupd/s)", "batch (Mupd/s)");
|
||||||
|
System.out.println("------------------------------------------------------------");
|
||||||
|
|
||||||
|
for (Indicator ind : indicators) {
|
||||||
|
String streamMups = String.format(Locale.ROOT, "%.1f", mups(bars, timeNs(ind.stream)));
|
||||||
|
String batchMups = ind.batch == null
|
||||||
|
? "-"
|
||||||
|
: String.format(Locale.ROOT, "%.1f", mups(bars, timeNs(ind.batch)));
|
||||||
|
System.out.printf(Locale.ROOT, "%-22s%20s%18s%n", ind.name, streamMups, batchMups);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(
|
||||||
|
"\nMupd/s = million indicator updates per second. Streaming is the per-tick\n"
|
||||||
|
+ "update path crossing the Java FFM<->C-ABI boundary once per value; batch is\n"
|
||||||
|
+ "the bulk array path (one boundary crossing). Higher is better. Numbers are\n"
|
||||||
|
+ "machine-dependent - use them for relative comparison, not as a speed claim.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double mups(int bars, double ns) {
|
||||||
|
return bars / (ns / 1e9) / 1e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Median elapsed-ns over a few repetitions, after one warmup pass.
|
||||||
|
private static double timeNs(Runnable fn) {
|
||||||
|
fn.run(); // warmup (JIT + cache)
|
||||||
|
final int reps = 3;
|
||||||
|
double[] samples = new double[reps];
|
||||||
|
for (int r = 0; r < reps; r++) {
|
||||||
|
long t0 = System.nanoTime();
|
||||||
|
fn.run();
|
||||||
|
samples[r] = System.nanoTime() - t0;
|
||||||
|
}
|
||||||
|
Arrays.sort(samples);
|
||||||
|
return samples[reps / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Indicator(String name, Runnable stream, Runnable batch) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# OSV-Scanner suppression for this Maven manifest. OSV-Scanner looks for an
|
||||||
|
# osv-scanner.toml next to each manifest it scans, and the repo-root config does
|
||||||
|
# not cover Maven sub-directory scans — so the jackson finding is suppressed
|
||||||
|
# here as well. See the root osv-scanner.toml and the SECURITY.md VEX section.
|
||||||
|
#
|
||||||
|
# tools.jackson.core:jackson-core 3.x is NOT a dependency of this project. Full
|
||||||
|
# Maven resolution (the publishing plugin tree and the project dependency tree)
|
||||||
|
# resolves only jackson 2.16.1 / 2.17.1; tools.jackson 3.x appears nowhere.
|
||||||
|
# OSV-Scanner's own resolver flags it as a false positive.
|
||||||
|
[[IgnoredVulns]]
|
||||||
|
id = "GHSA-72hv-8253-57qq"
|
||||||
|
reason = "tools.jackson.core:jackson-core 3.x is not a dependency; only jackson 2.x resolves. Not affected."
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>org.wickra</groupId>
|
<groupId>org.wickra</groupId>
|
||||||
<artifactId>wickra</artifactId>
|
<artifactId>wickra</artifactId>
|
||||||
<version>0.8.2</version>
|
<version>0.9.1</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Wickra</name>
|
<name>Wickra</name>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.release>22</maven.compiler.release>
|
<maven.compiler.release>22</maven.compiler.release>
|
||||||
<junit.version>5.10.2</junit.version>
|
<junit.version>6.1.0</junit.version>
|
||||||
<!-- The FFM API is restricted; grant native access to the unnamed module so
|
<!-- The FFM API is restricted; grant native access to the unnamed module so
|
||||||
tests and examples run without warnings. Consumers pass the same flag. -->
|
tests and examples run without warnings. Consumers pass the same flag. -->
|
||||||
<native.access.arg>--enable-native-access=ALL-UNNAMED</native.access.arg>
|
<native.access.arg>--enable-native-access=ALL-UNNAMED</native.access.arg>
|
||||||
@@ -64,13 +64,13 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.13.0</version>
|
<version>3.15.0</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>3.2.5</version>
|
<version>3.5.6</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<argLine>${native.access.arg}</argLine>
|
<argLine>${native.access.arg}</argLine>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>3.4.1</version>
|
<version>3.5.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifestEntries>
|
<manifestEntries>
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
<version>3.3.1</version>
|
<version>3.4.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>attach-sources</id>
|
<id>attach-sources</id>
|
||||||
@@ -119,7 +119,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.12.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- Generated members are self-descriptive; do not fail on doclint. -->
|
<!-- Generated members are self-descriptive; do not fail on doclint. -->
|
||||||
<doclint>none</doclint>
|
<doclint>none</doclint>
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
<version>3.2.4</version>
|
<version>3.2.8</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>sign-artifacts</id>
|
<id>sign-artifacts</id>
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.sonatype.central</groupId>
|
<groupId>org.sonatype.central</groupId>
|
||||||
<artifactId>central-publishing-maven-plugin</artifactId>
|
<artifactId>central-publishing-maven-plugin</artifactId>
|
||||||
<version>0.5.0</version>
|
<version>0.10.0</version>
|
||||||
<extensions>true</extensions>
|
<extensions>true</extensions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<publishingServerId>central</publishingServerId>
|
<publishingServerId>central</publishingServerId>
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class AbandonedBaby implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ABANDONED_BABY_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ABANDONED_BABY_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class Abcd implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ABCD_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ABCD_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -57,6 +57,26 @@ public final class AbsoluteBreadthIndex implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ABSOLUTE_BREADTH_INDEX_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ABSOLUTE_BREADTH_INDEX_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -47,6 +47,26 @@ public final class AccelerationBands implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ACCELERATION_BANDS_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ACCELERATION_BANDS_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -80,6 +80,26 @@ public final class AcceleratorOscillator implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ACCELERATOR_OSCILLATOR_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ACCELERATOR_OSCILLATOR_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class AdOscillator implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AD_OSCILLATOR_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AD_OSCILLATOR_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -57,6 +57,26 @@ public final class AdVolumeLine implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AD_VOLUME_LINE_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AD_VOLUME_LINE_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -74,6 +74,26 @@ public final class AdaptiveCci implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADAPTIVE_CCI_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADAPTIVE_CCI_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -51,6 +51,26 @@ public final class AdaptiveCycle implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADAPTIVE_CYCLE_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADAPTIVE_CYCLE_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -54,6 +54,26 @@ public final class AdaptiveLaguerreFilter implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADAPTIVE_LAGUERRE_FILTER_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADAPTIVE_LAGUERRE_FILTER_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -54,6 +54,26 @@ public final class AdaptiveRsi implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADAPTIVE_RSI_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADAPTIVE_RSI_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class Adl implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADL_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADL_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class AdvanceBlock implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADVANCE_BLOCK_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADVANCE_BLOCK_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -57,6 +57,26 @@ public final class AdvanceDecline implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADVANCE_DECLINE_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADVANCE_DECLINE_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -57,6 +57,26 @@ public final class AdvanceDeclineRatio implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADVANCE_DECLINE_RATIO_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADVANCE_DECLINE_RATIO_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -47,6 +47,26 @@ public final class Adx implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADX_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADX_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -74,6 +74,26 @@ public final class Adxr implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ADXR_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ADXR_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -53,6 +53,26 @@ public final class Alligator implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ALLIGATOR_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ALLIGATOR_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -54,6 +54,26 @@ public final class Alma implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ALMA_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ALMA_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -58,6 +58,26 @@ public final class Alpha implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ALPHA_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ALPHA_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -39,6 +39,26 @@ public final class AmihudIlliquidity implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AMIHUD_ILLIQUIDITY_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AMIHUD_ILLIQUIDITY_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -51,6 +51,26 @@ public final class AnchoredRsi implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ANCHORED_RSI_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ANCHORED_RSI_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class AnchoredVwap implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ANCHORED_VWAP_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ANCHORED_VWAP_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -47,6 +47,26 @@ public final class AndrewsPitchfork implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ANDREWS_PITCHFORK_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ANDREWS_PITCHFORK_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -57,6 +57,26 @@ public final class Apo implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_APO_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_APO_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -46,6 +46,26 @@ public final class Aroon implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AROON_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AROON_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -74,6 +74,26 @@ public final class AroonOscillator implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AROON_OSCILLATOR_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AROON_OSCILLATOR_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -74,6 +74,26 @@ public final class Atr implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ATR_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ATR_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -47,6 +47,26 @@ public final class AtrBands implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ATR_BANDS_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ATR_BANDS_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -46,6 +46,26 @@ public final class AtrRatchet implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ATR_RATCHET_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ATR_RATCHET_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -74,6 +74,26 @@ public final class AtrTrailingStop implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_ATR_TRAILING_STOP_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_ATR_TRAILING_STOP_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -48,6 +48,26 @@ public final class AutoFib implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AUTO_FIB_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AUTO_FIB_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -57,6 +57,26 @@ public final class Autocorrelation implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AUTOCORRELATION_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AUTOCORRELATION_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -57,6 +57,26 @@ public final class AutocorrelationPeriodogram implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AUTOCORRELATION_PERIODOGRAM_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AUTOCORRELATION_PERIODOGRAM_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -74,6 +74,26 @@ public final class AverageDailyRange implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AVERAGE_DAILY_RANGE_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AVERAGE_DAILY_RANGE_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -54,6 +54,26 @@ public final class AverageDrawdown implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AVERAGE_DRAWDOWN_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AVERAGE_DRAWDOWN_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class AvgPrice implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AVG_PRICE_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AVG_PRICE_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -77,6 +77,26 @@ public final class AwesomeOscillator implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AWESOME_OSCILLATOR_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AWESOME_OSCILLATOR_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -80,6 +80,26 @@ public final class AwesomeOscillatorHistogram implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_AWESOME_OSCILLATOR_HISTOGRAM_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_AWESOME_OSCILLATOR_HISTOGRAM_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class BalanceOfPower implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BALANCE_OF_POWER_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BALANCE_OF_POWER_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -54,6 +54,26 @@ public final class BandpassFilter implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BANDPASS_FILTER_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BANDPASS_FILTER_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class Bat implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BAT_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BAT_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -71,6 +71,26 @@ public final class BeltHold implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BELT_HOLD_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BELT_HOLD_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -58,6 +58,26 @@ public final class Beta implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BETA_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BETA_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -58,6 +58,26 @@ public final class BetaNeutralSpread implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BETA_NEUTRAL_SPREAD_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BETA_NEUTRAL_SPREAD_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -74,6 +74,26 @@ public final class BetterVolume implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BETTER_VOLUME_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BETTER_VOLUME_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -54,6 +54,26 @@ public final class BipowerVariation implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Number of updates required before update() yields a value. */
|
||||||
|
public int warmupPeriod() {
|
||||||
|
try {
|
||||||
|
long n = (long) NativeMethods.WICKRA_BIPOWER_VARIATION_WARMUP_PERIOD.invokeExact(handle);
|
||||||
|
return (int) n;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether the indicator has consumed enough input to emit a value. */
|
||||||
|
public boolean isReady() {
|
||||||
|
try {
|
||||||
|
byte r = (byte) NativeMethods.WICKRA_BIPOWER_VARIATION_IS_READY.invokeExact(handle);
|
||||||
|
return r != 0;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw WickraNative.rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset to the just-constructed state. */
|
/** Reset to the just-constructed state. */
|
||||||
public void reset() {
|
public void reset() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user