Compare commits

..
11 Commits
Author SHA1 Message Date
kingchencandGitHub 96cd9b3f02 release: bump 0.9.6 -> 0.9.7 (#338) 2026-06-21 16:07:53 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
98bb57c868 deps(actions): bump the github-actions group with 4 updates (#336)
Bumps the github-actions group with 4 updates: [actions/setup-python](https://github.com/actions/setup-python), [actions/upload-artifact](https://github.com/actions/upload-artifact), [taiki-e/install-action](https://github.com/taiki-e/install-action) and [codecov/codecov-action](https://github.com/codecov/codecov-action).


Updates `actions/setup-python` from 5.6.0 to 6.2.0
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5.6.0...a309ff8b426b58ec0e2a45f0f869d46889d02405)

Updates `actions/upload-artifact` from 4.6.2 to 7.0.1
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4.6.2...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

Updates `taiki-e/install-action` from 2.81.6 to 2.81.10
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/59012be0884e296ca2da49b530610e72c49039ad...7a79fe8c3a13344501c80d99cae481c1c9085912)

Updates `codecov/codecov-action` from 6.0.1 to 7.0.0
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/e79a6962e0d4c0c17b229090214935d2e33f8354...fb8b3582c8e4def4969c97caa2f19720cb33a72f)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: taiki-e/install-action
  dependency-version: 2.81.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: codecov/codecov-action
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-21 15:30:13 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
be05eb26d5 deps(nuget): Bump the nuget group with 3 updates (#337)
Bumps Microsoft.NET.Test.Sdk from 17.11.1 to 18.6.0
Bumps xunit from 2.9.2 to 2.9.3
Bumps xunit.runner.visualstudio from 2.8.2 to 3.1.5

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.6.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: nuget
- dependency-name: xunit
  dependency-version: 2.9.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nuget
- dependency-name: xunit.runner.visualstudio
  dependency-version: 3.1.5
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: nuget
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-21 15:30:10 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
af59e6eec0 deps(maven): bump org.wickra:wickra (#333)
Bumps the maven group with 1 update in the /bindings/java/benchmarks directory: [org.wickra:wickra](https://github.com/wickra-lib/wickra).


Updates `org.wickra:wickra` from 0.8.2 to 0.8.8
- [Release notes](https://github.com/wickra-lib/wickra/releases)
- [Changelog](https://github.com/wickra-lib/wickra/blob/main/CHANGELOG.md)
- [Commits](https://github.com/wickra-lib/wickra/compare/v0.8.2...v0.8.8)

---
updated-dependencies:
- dependency-name: org.wickra:wickra
  dependency-version: 0.8.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-21 15:30:07 +02:00
kingchencandGitHub 96ae63799d fix(r): credit kingchenc as R package author/maintainer (#332)
Every other binding (Python, Node, Rust core) credits kingchenc; the R
DESCRIPTION was an outlier with "Wickra contributors" as the sole
aut/cre, introduced when the binding was added (#230). Use kingchenc to
match, regenerate the package .Rd, and align the LICENSE copyright holder
with the root LICENSE-MIT ("kingchenc and the Wickra contributors").
2026-06-18 04:49:24 +02:00
kingchencandGitHub d5f5e14dda release: bump 0.9.5 -> 0.9.6 (#331)
Documentation release for the R binding. The library API and every indicator are
unchanged from `0.9.5`; only the R package's help pages change.

### What's in 0.9.6
- **R package documentation** (landed in #330): the twelve undocumented data-layer
  exports now have full man pages, the stale `AwesomeOscillatorHistogram` codoc is
  fixed, and a broken `push()` example is corrected — clearing the two `R CMD check`
  warnings r-universe reported for `0.9.5`. CI now runs `R CMD check` so doc drift
  fails the PR instead of reaching r-universe.

Pure version-string bump on top — `bump_version.py` touched 19 files. `cargo fmt`
clean.

Tag/publish waits for explicit GO (irreversible publish to crates.io / PyPI / npm
/ NuGet / Maven / Go / r-universe).
2026-06-18 02:10:03 +02:00
kingchencandGitHub 7e5d394f2a fix(r): document the data-layer exports + add an R CMD check gate (#330)
Clears the R CMD check **WARNING**s r-universe surfaced when it finally built
0.9.5 (it was stuck on 0.9.2, before the data layer existed): 11/13 platform
builds reported the same two warnings.

### Warnings fixed
1. **Undocumented code objects** — the data layer added in 0.9.3 (`BinanceFeed`,
   `CandleReader`, `Resampler`, `TickAggregator`, `fetch_binance_klines` and the
   generics `name` / `is_ready` / `warmup_period` / `push` / `read`). The roxygen
   blocks existed in `methods.R`, but the `man/*.Rd` were never regenerated, and
   the constructors had only a title.
2. **Codoc mismatch** — `AwesomeOscillatorHistogram.Rd` still documented
   `sma_period` after the argument was renamed to `lookback`.

### Changes
- Full `@param`/`@return` roxygen on the seven data-layer constructors.
- Regenerated `man/*.Rd` + `NAMESPACE` with roxygen2: 13 new pages, the stale
  AwesomeOscillator usage refreshed, and `flush` registered on `base::flush`.
- Fixed the `push()` example (`TickAggregator(1000)` was missing the required
  `gap_fill`) — it only ran once `push()` got a generated `.Rd`.
- **New CI gate:** a ubuntu-only `R CMD check` in the `r` job that fails on doc
  WARNING/ERROR, so stale docs fail the PR instead of reaching r-universe.

Verified locally with `R CMD check` (R 4.6.0 + Rtools45): *missing documentation
entries* and *Rd \usage sections* now **OK**, examples **OK**, tests **OK**. This
PR's own CI exercises the new gate.

Follow-up: a separate `0.9.6` release ships these doc fixes to r-universe.
2026-06-18 01:38:44 +02:00
kingchencandGitHub ff268500ef release: bump 0.9.4 -> 0.9.5 (#329)
Maintenance release. The library API and every indicator are unchanged from
`0.9.4`; the only change that ships to users is the R package's build script.

### What's in 0.9.5
- **R package: retry the C ABI download** (`bindings/r/configure[.win]`). A freshly
  cut release can briefly 404 while assets propagate; the download is now retried
  with a ~2 min backoff instead of failing with `cannot open URL … 404`. Landed in
  #328; ships to r-universe / source installs with this release.
- The rest of #328 — CI/release-pipeline hardening (R/NuGet dependency caching,
  job timeouts 20→30 / release 45, network-install retries, wasm-publish cache) —
  is infrastructure and does not affect the published artifacts, but makes this
  release's own pipeline more robust.

Pure version-string bump on top — `bump_version.py` touched 19 files (Cargo +
Lock, pyproject, node package.json/locks + 6 platform stubs, pom + csproj +
DESCRIPTION, SECURITY, CHANGELOG `[0.9.5]` + compare URLs). `cargo fmt` clean.

Tag/publish waits for explicit GO (irreversible publish to crates.io / PyPI /
npm / NuGet / Maven / Go / r-universe).
2026-06-17 23:55:18 +02:00
kingchencandGitHub 929fc17127 ci: harden cache, timeouts and retries across CI and release (#328)
Hardens both workflows after the R-on-ubuntu job repeatedly hit the 20-minute
job cap and was cancelled (no R-package cache + no retry + a slow source build).
Each item below maps to the requested checklist.

### CI (`ci.yml`)
- **Timeouts 20 → 30 min** on every job (backstop only; real jobs finish well under).
- **R dependencies cached**: replace the manual `install.packages(testthat/knitr)`
  with `r-lib/actions/setup-r-dependencies` — restores a cached R library and pulls
  **RSPM binaries** instead of compiling from source (the slow/flaky path that blew
  the cap). This is the actual root-cause fix.
- **NuGet cache** for the C# job (`~/.nuget/packages`, keyed on the project files).
- **Retry** the network installs that had none — `npm ci`, `dotnet test`,
  `mvn install` — via `nick-fields/retry` (2–3 attempts, backoff). On top of the
  existing env-level retries (`CARGO_NET_RETRY`, `npm_config_fetch_retries`,
  `PIP_RETRIES`) and the setup-* CDN-flake retries.
- **Go stays `cache: false`** on purpose: the module has no `go.sum` / external
  deps, so there is nothing to cache (enabling it would only warn).

### Release (`release.yml`)
- **Per-job timeouts** added (there were none — only GitHub's 6h default): **45 min**,
  higher than CI's 30 because the wheel/build jobs compile from source incl.
  **vendored OpenSSL** and must not be killed mid-build.
- **wasm-publish** gets a `Swatinem/rust-cache` like the other Rust-build jobs.
- **Retry** the no-retry network installs (`npm ci` ×2, `dotnet pack`). The actual
  publish/deploy steps are left alone — they are already idempotent
  (skip-existing / skip-duplicate), so re-running the job is the safe recovery.

### R binding download (`bindings/r/configure[.win]`)
- A freshly cut release can 404 for 1–2 min while assets propagate, which broke
  the C ABI download (`cannot open URL … 404`). Add a `wickra_download` retry
  helper (6 × 20s ≈ 2 min backoff) for both the release-asset and wasm-source
  downloads. Note: the CI R job builds the C ABI **locally** (`WICKRA_*_DIR`), so
  it never downloads — this fix covers the real-world r-universe / end-user build.

This PR's own CI exercises the CI changes (the reworked R job, caches, retries,
timeouts) before merge; the release-only changes are validated on the next tag.
2026-06-17 23:42:06 +02:00
kingchencandGitHub 41d5a7dd25 fix: build Linux Python wheels with vendored OpenSSL (manylinux + musllinux) (#327)
Fixes the Linux Python wheel build that broke the `0.9.3` release (and would
have broken `0.9.4`), and adds a CI guard so it cannot regress silently.

### Root cause
The `live-binance` data layer links `native-tls` -> `openssl-sys`, which needs
OpenSSL at build time. Neither wheel container provides it:
- **manylinux** ships no OpenSSL headers, and
- **musllinux** cross-compiles against a musl sysroot that has no OpenSSL at all,
  so installing a host package (`yum`/`apk`) cannot reach the cross target.

The 3-OS Python CI jobs build natively on the runner, which already has system
OpenSSL, so CI stayed green while the release container build failed.

### Fix
- New opt-in **`vendored-tls`** feature on `wickra-data` and the Python binding:
  enables `native-tls/vendored`, compiling OpenSSL from source and linking it
  statically. No system OpenSSL needed on either libc. No-op on macOS/Windows
  (Security.framework / SChannel — `openssl-sys` is never in the graph there).
- `release.yml` builds the Linux wheels with `--features vendored-tls` (replaces
  the manylinux-only `before-script-linux` header install, which could not fix
  the musllinux cross build).
- CI gains a **`manylinux` + `musllinux` container build-smoke** matrix job, so
  both container builds run on every PR. This PR's own CI is the proof the fix
  works before any release re-attempt.

### Notes
- No version bump: `0.9.4` published nowhere (the release run was cancelled
  before any publish job ran), so this lands on `0.9.4` and the tag is re-pointed
  at the fixed commit.
- Adds checks to `ci.yml` (the smoke job is now a 2-entry matrix).
2026-06-17 22:26:21 +02:00
kingchencandGitHub e595ea8bfe release: bump 0.9.3 -> 0.9.4 (#326)
Packaging fix for the `0.9.3` data layer.

`0.9.3` published to crates.io, Maven Central, NuGet, npm, and the Go mirror, but
the **Linux Python wheels failed to build**, so `Publish to PyPI` was skipped and
no GitHub Release was attached. Root cause: the `live-binance` data layer links
`native-tls` -> `openssl-sys`, and the `manylinux` / `musllinux` wheel-build
containers do not ship the system OpenSSL headers. The native macOS and Windows
wheels were unaffected (system TLS), which is why CI — running Python natively on
the runners, where OpenSSL is present — stayed green.

### Changes
- **`ci`**: install the OpenSSL headers inside the wheel container via
  maturin-action's `before-script-linux` (`openssl-devel` on `manylinux`,
  `openssl-dev` on `musllinux`) before maturin compiles. No library code changed.
- **`release: bump 0.9.3 -> 0.9.4`**: version-string bump across the manual
  touchpoints + `CHANGELOG` `[0.9.4]`.

`0.9.4` is functionally identical to `0.9.3`; it exists only because the already-
published registries cannot re-release `0.9.3`. PyPI publishes for the first time
starting at `0.9.4` (it skips `0.9.3`).
2026-06-17 21:35:14 +02:00
49 changed files with 818 additions and 134 deletions
+142 -31
View File
@@ -34,7 +34,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -105,7 +105,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
@@ -195,7 +195,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
@@ -209,7 +209,7 @@ jobs:
- name: Set up Python - name: Set up Python
id: setup_python id: setup_python
continue-on-error: true continue-on-error: true
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.12" python-version: "3.12"
@@ -222,7 +222,7 @@ jobs:
- name: Set up Python (retry) - name: Set up Python (retry)
if: steps.setup_python.outcome == 'failure' if: steps.setup_python.outcome == 'failure'
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.12" python-version: "3.12"
@@ -279,7 +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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -328,7 +328,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
@@ -345,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@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
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
@@ -358,7 +358,7 @@ jobs:
--lcov --output-path lcov.info --lcov --output-path lcov.info
- name: Upload to Codecov - name: Upload to Codecov
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with: with:
files: lcov.info files: lcov.info
fail_ci_if_error: false fail_ci_if_error: false
@@ -370,7 +370,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
@@ -389,7 +389,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
@@ -415,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@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
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
@@ -443,7 +443,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -525,7 +525,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
@@ -549,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@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
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
@@ -575,7 +575,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -622,9 +622,17 @@ jobs:
cache: npm cache: npm
cache-dependency-path: bindings/node/package-lock.json cache-dependency-path: bindings/node/package-lock.json
# npm's own fetch-retry (npm_config_fetch_retries) rides out per-request
# blips; wrap the whole `npm ci` once more so a longer registry hiccup
# retries the install instead of failing the job.
- name: Install Node dependencies - name: Install Node dependencies
working-directory: bindings/node uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
run: npm ci with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 20
command: cd bindings/node && npm ci
shell: bash
- name: Build native module - name: Build native module
working-directory: bindings/node working-directory: bindings/node
@@ -649,7 +657,7 @@ jobs:
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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -668,7 +676,7 @@ jobs:
timeout-minutes: 6 timeout-minutes: 6
- name: Install cbindgen - name: Install cbindgen
uses: taiki-e/install-action@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
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
@@ -705,7 +713,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -723,6 +731,19 @@ jobs:
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
timeout-minutes: 6 timeout-minutes: 6
# Cache the restored NuGet packages so dotnet test/build resolve from the
# local store instead of hitting nuget.org every run. No packages.lock.json
# exists, so key on the project files; never block the job on a slow restore.
- name: Cache NuGet packages
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
continue-on-error: true
timeout-minutes: 6
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
# The binding links against the C ABI hub at runtime; build it first so the # The binding links against the C ABI hub at runtime; build it first so the
# DllImportResolver finds target/release/wickra.{dll,so,dylib}. .NET 8 SDK is # DllImportResolver finds target/release/wickra.{dll,so,dylib}. .NET 8 SDK is
# preinstalled on the GitHub runners, so no setup-dotnet step is needed. # preinstalled on the GitHub runners, so no setup-dotnet step is needed.
@@ -732,8 +753,17 @@ jobs:
- name: .NET info - name: .NET info
run: dotnet --info run: dotnet --info
# dotnet test restores from nuget.org first; retry so a transient restore
# blip retries instead of failing the job (the cached packages above make
# the retry cheap).
- name: Test the C# binding - name: Test the C# binding
run: dotnet test bindings/csharp/Wickra.Tests/Wickra.Tests.csproj -c Release uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 15
max_attempts: 2
retry_wait_seconds: 20
command: dotnet test bindings/csharp/Wickra.Tests/Wickra.Tests.csproj -c Release
shell: bash
- name: Build the C# examples - name: Build the C# examples
shell: bash shell: bash
@@ -756,7 +786,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -879,7 +909,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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -912,10 +942,17 @@ jobs:
r-version: "release" r-version: "release"
use-public-rspm: true use-public-rspm: true
# Use the repos configured by setup-r (use-public-rspm) so Linux installs # Install the R dependencies via setup-r-dependencies: it restores a cached
# binary packages — building testthat's deps from source is slow and flaky. # package library (actions/cache) and pulls RSPM *binaries* instead of
- name: Install test dependency # compiling testthat / knitr and their deps from source — the slow, flaky
run: Rscript -e 'install.packages("testthat")' # path that previously blew past the job timeout on the ubuntu runner.
- name: Install R dependencies (cached binaries)
uses: r-lib/actions/setup-r-dependencies@a51a8012b0aab7c32ef9d19bf54da93f3254335e # v2
with:
working-directory: bindings/r
extra-packages: |
any::testthat
any::knitr
- name: Install and test the R binding - name: Install and test the R binding
shell: bash shell: bash
@@ -932,14 +969,39 @@ 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)'
# Full R CMD check, gated on the documentation problems r-universe surfaces
# (undocumented exported objects, codoc mismatches) that R CMD INSTALL above
# does not catch — exactly what shipped stale to r-universe with the 0.9.3
# data layer. Ubuntu-only; these checks are platform-independent. Vignettes
# are skipped here (building them needs pandoc and the vignette is exercised
# in the next step), so the two --no-build-vignettes warnings are ignored.
- name: R CMD check (documentation & consistency, like r-universe)
if: matrix.os == 'ubuntu-latest'
shell: bash
run: |
export WICKRA_INCLUDE_DIR="${WICKRA_INCLUDE_DIR//\\//}"
export WICKRA_LIB_DIR="${WICKRA_LIB_DIR//\\//}"
R CMD build bindings/r --no-build-vignettes --no-manual
R CMD check wickra_*.tar.gz --no-manual --no-vignettes --no-tests || true
log=$(find . -maxdepth 2 -name 00check.log | head -1)
echo "::group::00check.log"; cat "$log"; echo "::endgroup::"
problems=$(grep -E '\.\.\. (WARNING|ERROR)' "$log" \
| grep -vE "checking (files in .vignettes.|package vignettes)" || true)
if [ -n "$problems" ]; then
echo "::error::R CMD check found problems (run roxygen2::roxygenise() in bindings/r if the docs are stale):"
echo "$problems"
exit 1
fi
echo "R CMD check: documentation and consistency clean."
- name: Build the vignette code - name: Build the vignette code
shell: bash shell: bash
# The getting-started vignette runs at R CMD check time on r-universe / # 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 # 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 # chunks here (knit, no pandoc needed) to catch a broken example before it
# reaches the published build. # reaches the published build.
# knitr is installed by the cached setup-r-dependencies step above.
run: | 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")' 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
@@ -961,7 +1023,7 @@ 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) timeout-minutes: 30 # backstop: cap a wedged job instead of GitHub's 6h default (headroom for slow registry/package installs)
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -1016,8 +1078,16 @@ jobs:
# `install` runs the archetype test suite (the real FFI boundary check) and # `install` runs the archetype test suite (the real FFI boundary check) and
# installs the binding to the local repo so the examples can resolve it. # installs the binding to the local repo so the examples can resolve it.
# Maven resolves plugins/deps from the network on a cache miss; retry so a
# transient Central blip retries instead of failing the job.
- name: Test and install the Java binding - name: Test and install the Java binding
run: mvn -B -f bindings/java install uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 20
max_attempts: 2
retry_wait_seconds: 20
command: mvn -B -f bindings/java install
shell: bash
- name: Build the Java examples - name: Build the Java examples
run: mvn -B -f examples/java compile run: mvn -B -f examples/java compile
@@ -1031,6 +1101,47 @@ jobs:
mvn -B -q -f examples/java exec:exec -Dexec.mainClass="org.wickra.examples.$cls" mvn -B -q -f examples/java exec:exec -Dexec.mainClass="org.wickra.examples.$cls"
done done
# Build a Python wheel inside both the manylinux and the musllinux container,
# mirroring the Linux wheel build in release.yml. The 3-OS Python jobs build
# natively on the runner, which already ships system OpenSSL, so they cannot
# catch a build-time gap that only exists inside the slim release containers —
# exactly what broke the 0.9.3 Linux wheels (the live-binance data layer links
# native-tls -> openssl-sys, and the containers provide no OpenSSL: manylinux
# lacks the headers, musllinux cross-compiles against a musl sysroot without
# OpenSSL at all). The wheels are built with the `vendored-tls` feature, which
# statically compiles OpenSSL from source. This job exercises both container
# builds on every PR, so the same class of breakage now fails CI, not release.
python-wheel-container-smoke:
name: Python wheel (${{ matrix.manylinux }} smoke)
runs-on: ubuntu-latest
timeout-minutes: 30 # backstop: vendored OpenSSL adds a from-source compile
strategy:
fail-fast: false
matrix:
manylinux: [auto, musllinux_1_2]
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Sync root README into bindings/python so the build matches release
run: cp README.md bindings/python/README.md
- uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
with:
working-directory: bindings/python
target: x86_64
# Keep in sync with release.yml: vendored OpenSSL for the Linux wheels.
args: --release --out dist --features vendored-tls
manylinux: ${{ matrix.manylinux }}
# Building OpenSSL from source needs Perl modules (IPC::Cmd,
# Time::Piece, ...) the minimal manylinux (CentOS 7) image lacks.
# perl-core pulls the full distribution; the explicit names document
# the ones OpenSSL's Configure has required. The musllinux cross image
# ships a complete Perl and has no yum, so this is a no-op there.
before-script-linux: |
if command -v yum >/dev/null 2>&1; then yum install -y perl-core perl-IPC-Cmd perl-Data-Dumper perl-Time-Piece; fi
# The cross-library benchmark has moved to a dedicated scheduled workflow # The cross-library benchmark has moved to a dedicated scheduled workflow
# (.github/workflows/bench.yml) — see audit finding R10. It runs nightly # (.github/workflows/bench.yml) — see audit finding R10. It runs nightly
# at 03:00 UTC and on-demand via `workflow_dispatch`, and is no longer on # at 03:00 UTC and on-demand via `workflow_dispatch`, and is no longer on
+60 -11
View File
@@ -36,6 +36,7 @@ jobs:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
cargo-publish: cargo-publish:
name: Publish to crates.io name: Publish to crates.io
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
runs-on: ubuntu-latest runs-on: ubuntu-latest
# The publish jobs run with long-lived registry tokens. Binding them to a # The publish jobs run with long-lived registry tokens. Binding them to a
# protected GitHub environment lets the org require a reviewer to approve # protected GitHub environment lets the org require a reviewer to approve
@@ -110,7 +111,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@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
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
@@ -139,6 +140,7 @@ jobs:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
python-wheels: python-wheels:
name: Build wheels (${{ matrix.target }}/${{ matrix.manylinux }} on ${{ matrix.os }}) name: Build wheels (${{ matrix.target }}/${{ matrix.manylinux }} on ${{ matrix.os }})
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -184,8 +186,22 @@ jobs:
with: with:
working-directory: bindings/python working-directory: bindings/python
target: ${{ matrix.target }} target: ${{ matrix.target }}
args: --release --strip --out dist # The live-binance data layer links native-tls -> openssl-sys, which
# needs OpenSSL at build time. The manylinux containers lack the headers
# and the musllinux build cross-compiles against a musl sysroot with no
# OpenSSL at all, so build the Linux wheels with vendored OpenSSL
# (compiled from source, linked statically). No-op on the native
# macOS/Windows runners, where native-tls never pulls openssl-sys. The
# CI `python-wheel-container-smoke` job exercises both containers on PRs.
args: --release --strip --out dist --features vendored-tls
manylinux: ${{ matrix.manylinux }} manylinux: ${{ matrix.manylinux }}
# Building OpenSSL from source needs Perl modules (IPC::Cmd,
# Time::Piece, ...) the minimal manylinux (CentOS 7) image lacks.
# perl-core pulls the full distribution; the explicit names document
# the ones OpenSSL's Configure has required. The musllinux cross image
# ships a complete Perl and has no yum, so this is a no-op there.
before-script-linux: |
if command -v yum >/dev/null 2>&1; then yum install -y perl-core perl-IPC-Cmd perl-Data-Dumper perl-Time-Piece; fi
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
# Include manylinux in the name so the glibc and musl x86_64/aarch64 # Include manylinux in the name so the glibc and musl x86_64/aarch64
@@ -195,6 +211,7 @@ jobs:
python-sdist: python-sdist:
name: Build Python sdist name: Build Python sdist
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
@@ -214,6 +231,7 @@ jobs:
python-publish: python-publish:
name: Publish to PyPI name: Publish to PyPI
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: [python-wheels, python-sdist] needs: [python-wheels, python-sdist]
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: release environment: release
@@ -237,6 +255,7 @@ jobs:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
node-build: node-build:
name: Node build (${{ matrix.target }}) name: Node build (${{ matrix.target }})
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -282,8 +301,13 @@ jobs:
timeout-minutes: 6 timeout-minutes: 6
- name: Install Node deps - name: Install Node deps
working-directory: bindings/node uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
run: npm ci with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 20
command: cd bindings/node && npm ci
shell: bash
- name: Build native module - name: Build native module
working-directory: bindings/node working-directory: bindings/node
@@ -298,6 +322,7 @@ jobs:
node-publish: node-publish:
name: Publish to npm name: Publish to npm
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: node-build needs: node-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: release environment: release
@@ -337,8 +362,13 @@ jobs:
registry-url: "https://registry.npmjs.org" registry-url: "https://registry.npmjs.org"
- name: Install Node deps - name: Install Node deps
working-directory: bindings/node uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
run: npm ci with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 20
command: cd bindings/node && npm ci
shell: bash
- name: Download all platform binaries - name: Download all platform binaries
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
@@ -470,6 +500,7 @@ jobs:
# which requires the `id-token: write` permission set at the job level. # which requires the `id-token: write` permission set at the job level.
wasm-publish: wasm-publish:
name: Publish wickra-wasm to npm name: Publish wickra-wasm to npm
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: release environment: release
# `id-token: write` lets npm publish embed a Sigstore provenance # `id-token: write` lets npm publish embed a Sigstore provenance
@@ -509,10 +540,14 @@ jobs:
with: with:
targets: wasm32-unknown-unknown targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
timeout-minutes: 6
- 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@59012be0884e296ca2da49b530610e72c49039ad # v2.81.6 uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
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
@@ -576,6 +611,7 @@ jobs:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
c-abi-build: c-abi-build:
name: C ABI library (${{ matrix.target }}) name: C ABI library (${{ matrix.target }})
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -631,6 +667,7 @@ jobs:
# workflow release.yml) exchanges the GitHub OIDC token for a short-lived key. # workflow release.yml) exchanges the GitHub OIDC token for a short-lived key.
csharp-publish: csharp-publish:
name: Publish to NuGet name: Publish to NuGet
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: c-abi-build needs: c-abi-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: release environment: release
@@ -675,11 +712,18 @@ jobs:
echo "staged ${RID[$target]}:"; ls -l "$dest" echo "staged ${RID[$target]}:"; ls -l "$dest"
done done
# dotnet pack restores from nuget.org first; retry so a transient restore
# blip retries instead of failing the release.
- name: Pack - name: Pack
shell: bash uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
run: | with:
version="${GITHUB_REF_NAME#v}" timeout_minutes: 15
dotnet pack bindings/csharp/Wickra/Wickra.csproj -c Release -p:Version="$version" -o nupkg max_attempts: 2
retry_wait_seconds: 20
shell: bash
command: |
version="${GITHUB_REF_NAME#v}"
dotnet pack bindings/csharp/Wickra/Wickra.csproj -c Release -p:Version="$version" -o nupkg
# Exchange the GitHub OIDC token for a short-lived (~1h) NuGet API key. # Exchange the GitHub OIDC token for a short-lived (~1h) NuGet API key.
# 'user' is the nuget.org profile name (the package owner), not an email. # 'user' is the nuget.org profile name (the package owner), not an email.
@@ -714,6 +758,7 @@ jobs:
# match the release tag (kept in sync by the version-bump checklist). # match the release tag (kept in sync by the version-bump checklist).
java-publish: java-publish:
name: Publish to Maven Central name: Publish to Maven Central
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: c-abi-build needs: c-abi-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: release environment: release
@@ -785,6 +830,7 @@ jobs:
# derived artifact, so its bot commit is intentionally unsigned. # derived artifact, so its bot commit is intentionally unsigned.
go-mirror: go-mirror:
name: Mirror the Go module to wickra-go name: Mirror the Go module to wickra-go
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: c-abi-build needs: c-abi-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -868,6 +914,7 @@ jobs:
github-release: github-release:
name: Attach assets to the draft GitHub Release name: Attach assets to the draft GitHub Release
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: [cargo-publish, python-publish, node-publish, wasm-publish, c-abi-build] needs: [cargo-publish, python-publish, node-publish, wasm-publish, c-abi-build]
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
@@ -993,6 +1040,7 @@ jobs:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
attestations: attestations:
name: Attest build provenance name: Attest build provenance
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: [cargo-publish, python-wheels, python-sdist, github-release] needs: [cargo-publish, python-wheels, python-sdist, github-release]
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Signed SLSA build-provenance attestations for the published crates and # Signed SLSA build-provenance attestations for the published crates and
@@ -1076,6 +1124,7 @@ jobs:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
publish-release: publish-release:
name: Publish the GitHub Release name: Publish the GitHub Release
timeout-minutes: 45 # backstop only: release build/publish jobs compile from source (vendored OpenSSL) and must not be killed mid-build; far above the ~10 min real runtime
needs: [github-release, attestations] needs: [github-release, attestations]
if: always() && needs.github-release.result == 'success' if: always() && needs.github-release.result == 'success'
runs-on: ubuntu-latest runs-on: ubuntu-latest
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
publish_results: true publish_results: true
- name: Upload SARIF artifact - name: Upload SARIF artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: SARIF file name: SARIF file
path: results.sarif path: results.sarif
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - 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@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.12" python-version: "3.12"
- name: Audit repo-metadata.toml drift - name: Audit repo-metadata.toml drift
+88 -1
View File
@@ -7,6 +7,89 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.9.7] - 2026-06-21
Maintenance release. The library API and every indicator are unchanged from
`0.9.6`; this release carries an R package metadata fix and routine dependency
and CI tooling updates.
### Fixed
- **R package: credit `kingchenc` as the package author and maintainer.** The R
`DESCRIPTION` was the only binding still listing "Wickra contributors" as the
sole `aut`/`cre` — an outlier introduced when the binding was added. It now
matches the Python, Node, and Rust core metadata, the package `.Rd` is
regenerated, and the binding `LICENSE` copyright holder is aligned with the
root `LICENSE-MIT`.
### Changed
- **Dependency and CI housekeeping.** Bump the C# test dependencies
(`Microsoft.NET.Test.Sdk`, `xunit`, `xunit.runner.visualstudio`), the GitHub
Actions used by CI (`setup-python`, `upload-artifact`, `codecov-action`,
`taiki-e/install-action`), and the Java benchmark's `org.wickra:wickra`
dependency. No runtime code changes.
## [0.9.6] - 2026-06-18
Documentation release for the R binding. The library API and every indicator
are unchanged from `0.9.5`; only the R package's help pages change.
### Fixed
- **R package: document the data-layer exports and refresh the man pages.**
r-universe's `R CMD check` reported two warnings against the `0.9.3` data layer
it built for the first time in `0.9.5`: twelve undocumented exported objects
(`BinanceFeed`, `CandleReader`, `Resampler`, `TickAggregator`,
`fetch_binance_klines` and the `name` / `is_ready` / `warmup_period` / `push` /
`read` generics) and a codoc mismatch on `AwesomeOscillatorHistogram` (its help
page still listed `sma_period` after the argument was renamed to `lookback`).
The roxygen sources existed but the `man/*.Rd` had never been regenerated; they
are now complete, and a `push()` example that constructed a `TickAggregator`
without its required `gap_fill` argument is fixed. CI now runs `R CMD check` so
documentation drift fails the pull request instead of surfacing on r-universe.
## [0.9.5] - 2026-06-17
Maintenance release. The library API and every indicator are unchanged from
`0.9.4`; the only change that ships to users is to the R package's build script.
The rest of the release is CI / release-pipeline hardening (dependency caching,
job timeouts, and network-install retries) that does not affect the artifacts.
### Fixed
- **R package: retry the C ABI download.** `configure` / `configure.win` fetch the
prebuilt `wickra-c-<triple>.tar.gz` from the matching GitHub release. A freshly
cut release can briefly return 404 while its assets propagate across the CDN
(and a transient network blip would also fail it), so the single-shot download
is now retried with a backoff (~2 min) before giving up. Fixes
`cannot open URL … 404 Not Found` on r-universe / source installs taken right
after a release.
## [0.9.4] - 2026-06-17
Packaging fix for the `0.9.3` data layer. The library is identical to `0.9.3` on
every platform that already published; the only additions are an opt-in
`vendored-tls` build feature and the Linux Python wheels, which `0.9.3` could not
build.
### Fixed
- **Linux Python wheels (`manylinux` / `musllinux`) now build.** The `live-binance`
data layer links `native-tls` -> `openssl-sys`, which needs OpenSSL at build
time. The `manylinux` wheel containers ship no OpenSSL headers and the
`musllinux` build cross-compiles against a musl sysroot that has no OpenSSL at
all, so the wheels failed to compile. The Linux wheels are now built with a new
opt-in `vendored-tls` feature that compiles OpenSSL from source and links it
statically (no system OpenSSL required, on either libc). The native macOS and
Windows wheels were unaffected (Security.framework / SChannel). As a result
`0.9.3` shipped to crates.io, Maven Central, NuGet, and npm but not to PyPI;
PyPI publishes starting with `0.9.4`.
### Added
- **`vendored-tls` feature** on `wickra-data` (and the Python binding): builds the
`live-binance` TLS stack against a statically compiled OpenSSL. Off by default;
used by the release wheels and exercised on every PR by a `manylinux` /
`musllinux` container build-smoke CI job.
## [0.9.3] - 2026-06-17 ## [0.9.3] - 2026-06-17
### Changed ### Changed
@@ -1810,7 +1893,11 @@ public API changes.
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.9.3...HEAD [Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.9.7...HEAD
[0.9.7]: https://github.com/wickra-lib/wickra/compare/v0.9.6...v0.9.7
[0.9.6]: https://github.com/wickra-lib/wickra/compare/v0.9.5...v0.9.6
[0.9.5]: https://github.com/wickra-lib/wickra/compare/v0.9.4...v0.9.5
[0.9.4]: https://github.com/wickra-lib/wickra/compare/v0.9.3...v0.9.4
[0.9.3]: https://github.com/wickra-lib/wickra/compare/v0.9.2...v0.9.3 [0.9.3]: https://github.com/wickra-lib/wickra/compare/v0.9.2...v0.9.3
[0.9.2]: https://github.com/wickra-lib/wickra/compare/v0.9.1...v0.9.2 [0.9.2]: https://github.com/wickra-lib/wickra/compare/v0.9.1...v0.9.2
[0.9.1]: https://github.com/wickra-lib/wickra/compare/v0.9.0...v0.9.1 [0.9.1]: https://github.com/wickra-lib/wickra/compare/v0.9.0...v0.9.1
Generated
+19 -9
View File
@@ -907,6 +907,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "openssl-src"
version = "300.5.4+3.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.116" version = "0.9.116"
@@ -915,6 +924,7 @@ checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
"openssl-src",
"pkg-config", "pkg-config",
"vcpkg", "vcpkg",
] ]
@@ -1775,7 +1785,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra" name = "wickra"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"approx", "approx",
"criterion", "criterion",
@@ -1786,7 +1796,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-bench" name = "wickra-bench"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"criterion", "criterion",
"kand", "kand",
@@ -1798,7 +1808,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-c" name = "wickra-c"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"tokio", "tokio",
"wickra-core", "wickra-core",
@@ -1807,7 +1817,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-core" name = "wickra-core"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"approx", "approx",
"proptest", "proptest",
@@ -1817,7 +1827,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-data" name = "wickra-data"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"approx", "approx",
"csv", "csv",
@@ -1836,7 +1846,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-examples" name = "wickra-examples"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"serde_json", "serde_json",
"tokio", "tokio",
@@ -1846,7 +1856,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-node" name = "wickra-node"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"napi", "napi",
"napi-build", "napi-build",
@@ -1858,7 +1868,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-python" name = "wickra-python"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"pyo3", "pyo3",
@@ -1869,7 +1879,7 @@ dependencies = [
[[package]] [[package]]
name = "wickra-wasm" name = "wickra-wasm"
version = "0.9.3" version = "0.9.7"
dependencies = [ dependencies = [
"console_error_panic_hook", "console_error_panic_hook",
"js-sys", "js-sys",
+3 -3
View File
@@ -14,7 +14,7 @@ members = [
exclude = ["fuzz"] exclude = ["fuzz"]
[workspace.package] [workspace.package]
version = "0.9.3" version = "0.9.7"
authors = ["kingchenc <support@wickra.org>"] authors = ["kingchenc <support@wickra.org>"]
edition = "2021" edition = "2021"
rust-version = "1.86" rust-version = "1.86"
@@ -26,8 +26,8 @@ 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.9.3" } wickra-core = { path = "crates/wickra-core", version = "0.9.7" }
wickra-data = { path = "crates/wickra-data", version = "0.9.3" } wickra-data = { path = "crates/wickra-data", version = "0.9.7" }
thiserror = "2" thiserror = "2"
rayon = "1.10" rayon = "1.10"
+3 -3
View File
@@ -2,13 +2,13 @@
## Supported versions ## Supported versions
Wickra is pre-1.0. Security fixes are applied to the latest released `0.9.3` Wickra is pre-1.0. Security fixes are applied to the latest released `0.9.7`
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.9.3 (latest) | :white_check_mark: | | 0.9.7 (latest) | :white_check_mark: |
| < 0.9.3 | :x: | | < 0.9.7 | :x: |
## Reporting a vulnerability ## Reporting a vulnerability
@@ -9,9 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="xunit" Version="2.9.2" /> <PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" /> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+1 -1
View File
@@ -11,7 +11,7 @@
<!-- NuGet package metadata --> <!-- NuGet package metadata -->
<PackageId>Wickra</PackageId> <PackageId>Wickra</PackageId>
<Version>0.9.3</Version> <Version>0.9.7</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>
+2 -2
View File
@@ -30,14 +30,14 @@ Maven:
<dependency> <dependency>
<groupId>org.wickra</groupId> <groupId>org.wickra</groupId>
<artifactId>wickra</artifactId> <artifactId>wickra</artifactId>
<version>0.9.3</version> <version>0.9.7</version>
</dependency> </dependency>
``` ```
Gradle: Gradle:
```kotlin ```kotlin
implementation("org.wickra:wickra:0.9.3") implementation("org.wickra:wickra:0.9.7")
``` ```
The native library ships prebuilt per platform (Linux, macOS, Windows — x64 and The native library ships prebuilt per platform (Linux, macOS, Windows — x64 and
+1 -1
View File
@@ -21,7 +21,7 @@
<dependency> <dependency>
<groupId>org.wickra</groupId> <groupId>org.wickra</groupId>
<artifactId>wickra</artifactId> <artifactId>wickra</artifactId>
<version>0.8.2</version> <version>0.8.8</version>
</dependency> </dependency>
</dependencies> </dependencies>
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>org.wickra</groupId> <groupId>org.wickra</groupId>
<artifactId>wickra</artifactId> <artifactId>wickra</artifactId>
<version>0.9.3</version> <version>0.9.7</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Wickra</name> <name>Wickra</name>
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "wickra-darwin-arm64", "name": "wickra-darwin-arm64",
"version": "0.9.3", "version": "0.9.7",
"description": "Native binding for wickra (macOS Apple Silicon). Installed automatically as an optional dependency of wickra on matching platforms.", "description": "Native binding for wickra (macOS Apple Silicon). Installed automatically as an optional dependency of wickra on matching platforms.",
"main": "wickra.darwin-arm64.node", "main": "wickra.darwin-arm64.node",
"files": [ "files": [
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "wickra-darwin-x64", "name": "wickra-darwin-x64",
"version": "0.9.3", "version": "0.9.7",
"description": "Native binding for wickra (macOS Intel). Installed automatically as an optional dependency of wickra on matching platforms.", "description": "Native binding for wickra (macOS Intel). Installed automatically as an optional dependency of wickra on matching platforms.",
"main": "wickra.darwin-x64.node", "main": "wickra.darwin-x64.node",
"files": [ "files": [
@@ -1,6 +1,6 @@
{ {
"name": "wickra-linux-arm64-gnu", "name": "wickra-linux-arm64-gnu",
"version": "0.9.3", "version": "0.9.7",
"description": "Native binding for wickra (linux arm64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.", "description": "Native binding for wickra (linux arm64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
"main": "wickra.linux-arm64-gnu.node", "main": "wickra.linux-arm64-gnu.node",
"files": [ "files": [
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "wickra-linux-x64-gnu", "name": "wickra-linux-x64-gnu",
"version": "0.9.3", "version": "0.9.7",
"description": "Native binding for wickra (linux x64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.", "description": "Native binding for wickra (linux x64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
"main": "wickra.linux-x64-gnu.node", "main": "wickra.linux-x64-gnu.node",
"files": [ "files": [
@@ -1,6 +1,6 @@
{ {
"name": "wickra-win32-arm64-msvc", "name": "wickra-win32-arm64-msvc",
"version": "0.9.3", "version": "0.9.7",
"description": "Native binding for wickra (Windows arm64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.", "description": "Native binding for wickra (Windows arm64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
"main": "wickra.win32-arm64-msvc.node", "main": "wickra.win32-arm64-msvc.node",
"files": [ "files": [
@@ -1,6 +1,6 @@
{ {
"name": "wickra-win32-x64-msvc", "name": "wickra-win32-x64-msvc",
"version": "0.9.3", "version": "0.9.7",
"description": "Native binding for wickra (Windows x64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.", "description": "Native binding for wickra (Windows x64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
"main": "wickra.win32-x64-msvc.node", "main": "wickra.win32-x64-msvc.node",
"files": [ "files": [
+20 -20
View File
@@ -1,12 +1,12 @@
{ {
"name": "wickra", "name": "wickra",
"version": "0.9.3", "version": "0.9.7",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "wickra", "name": "wickra",
"version": "0.9.3", "version": "0.9.7",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"devDependencies": { "devDependencies": {
"@napi-rs/cli": "^2.18.0" "@napi-rs/cli": "^2.18.0"
@@ -15,12 +15,12 @@
"node": ">= 20" "node": ">= 20"
}, },
"optionalDependencies": { "optionalDependencies": {
"wickra-darwin-arm64": "0.9.3", "wickra-darwin-arm64": "0.9.7",
"wickra-darwin-x64": "0.9.3", "wickra-darwin-x64": "0.9.7",
"wickra-linux-arm64-gnu": "0.9.3", "wickra-linux-arm64-gnu": "0.9.7",
"wickra-linux-x64-gnu": "0.9.3", "wickra-linux-x64-gnu": "0.9.7",
"wickra-win32-arm64-msvc": "0.9.3", "wickra-win32-arm64-msvc": "0.9.7",
"wickra-win32-x64-msvc": "0.9.3" "wickra-win32-x64-msvc": "0.9.7"
} }
}, },
"node_modules/@napi-rs/cli": { "node_modules/@napi-rs/cli": {
@@ -41,8 +41,8 @@
} }
}, },
"node_modules/wickra-darwin-arm64": { "node_modules/wickra-darwin-arm64": {
"version": "0.9.3", "version": "0.9.7",
"resolved": "https://registry.npmjs.org/wickra-darwin-arm64/-/wickra-darwin-arm64-0.9.3.tgz", "resolved": "https://registry.npmjs.org/wickra-darwin-arm64/-/wickra-darwin-arm64-0.9.7.tgz",
"integrity": "sha512-4eZiBR/yGUdr4nzhEUFy2i69XgNx64iI2ax/LPamsThgylC0KpHOZKK19QzJ2d9KbK4C8nMjME5FLuR+4GNEwQ==", "integrity": "sha512-4eZiBR/yGUdr4nzhEUFy2i69XgNx64iI2ax/LPamsThgylC0KpHOZKK19QzJ2d9KbK4C8nMjME5FLuR+4GNEwQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
@@ -57,8 +57,8 @@
} }
}, },
"node_modules/wickra-darwin-x64": { "node_modules/wickra-darwin-x64": {
"version": "0.9.3", "version": "0.9.7",
"resolved": "https://registry.npmjs.org/wickra-darwin-x64/-/wickra-darwin-x64-0.9.3.tgz", "resolved": "https://registry.npmjs.org/wickra-darwin-x64/-/wickra-darwin-x64-0.9.7.tgz",
"integrity": "sha512-6hf8zI3QPjTFp4zCpmgUwDvNtu6jHqNUHKD5e55POo0CgA52HkpyxSPtVm8TGTIZDI7kPjlbOdBM8CJ76mmXwA==", "integrity": "sha512-6hf8zI3QPjTFp4zCpmgUwDvNtu6jHqNUHKD5e55POo0CgA52HkpyxSPtVm8TGTIZDI7kPjlbOdBM8CJ76mmXwA==",
"cpu": [ "cpu": [
"x64" "x64"
@@ -73,8 +73,8 @@
} }
}, },
"node_modules/wickra-linux-arm64-gnu": { "node_modules/wickra-linux-arm64-gnu": {
"version": "0.9.3", "version": "0.9.7",
"resolved": "https://registry.npmjs.org/wickra-linux-arm64-gnu/-/wickra-linux-arm64-gnu-0.9.3.tgz", "resolved": "https://registry.npmjs.org/wickra-linux-arm64-gnu/-/wickra-linux-arm64-gnu-0.9.7.tgz",
"integrity": "sha512-kSe6y0xBMSiqdPLXNjwop5WZdHtvdBNKSEBCwZ4hFq33p4apW25/wrlzv9/oDuyD4kuPabJEhCCnFOplh58CUg==", "integrity": "sha512-kSe6y0xBMSiqdPLXNjwop5WZdHtvdBNKSEBCwZ4hFq33p4apW25/wrlzv9/oDuyD4kuPabJEhCCnFOplh58CUg==",
"cpu": [ "cpu": [
"arm64" "arm64"
@@ -89,8 +89,8 @@
} }
}, },
"node_modules/wickra-linux-x64-gnu": { "node_modules/wickra-linux-x64-gnu": {
"version": "0.9.3", "version": "0.9.7",
"resolved": "https://registry.npmjs.org/wickra-linux-x64-gnu/-/wickra-linux-x64-gnu-0.9.3.tgz", "resolved": "https://registry.npmjs.org/wickra-linux-x64-gnu/-/wickra-linux-x64-gnu-0.9.7.tgz",
"integrity": "sha512-tWBWS4qz7hxM4xnpFb59bhf6TaLwXq0Z3jEa/2l7r8PiHA94g8r8S53NRMiT+4yiL5hSWe/nUiC/YXdRrhEZ4g==", "integrity": "sha512-tWBWS4qz7hxM4xnpFb59bhf6TaLwXq0Z3jEa/2l7r8PiHA94g8r8S53NRMiT+4yiL5hSWe/nUiC/YXdRrhEZ4g==",
"cpu": [ "cpu": [
"x64" "x64"
@@ -105,8 +105,8 @@
} }
}, },
"node_modules/wickra-win32-arm64-msvc": { "node_modules/wickra-win32-arm64-msvc": {
"version": "0.9.3", "version": "0.9.7",
"resolved": "https://registry.npmjs.org/wickra-win32-arm64-msvc/-/wickra-win32-arm64-msvc-0.9.3.tgz", "resolved": "https://registry.npmjs.org/wickra-win32-arm64-msvc/-/wickra-win32-arm64-msvc-0.9.7.tgz",
"integrity": "sha512-EXIckHxAtF75PUGDKRzXyqMe9ldP0JjSdu68WFN6iJfp+McYrGu6h40TEJlQ/oUEIoPqiZB/xhVyo/el5Lg7zw==", "integrity": "sha512-EXIckHxAtF75PUGDKRzXyqMe9ldP0JjSdu68WFN6iJfp+McYrGu6h40TEJlQ/oUEIoPqiZB/xhVyo/el5Lg7zw==",
"cpu": [ "cpu": [
"arm64" "arm64"
@@ -121,8 +121,8 @@
} }
}, },
"node_modules/wickra-win32-x64-msvc": { "node_modules/wickra-win32-x64-msvc": {
"version": "0.9.3", "version": "0.9.7",
"resolved": "https://registry.npmjs.org/wickra-win32-x64-msvc/-/wickra-win32-x64-msvc-0.9.3.tgz", "resolved": "https://registry.npmjs.org/wickra-win32-x64-msvc/-/wickra-win32-x64-msvc-0.9.7.tgz",
"integrity": "sha512-Yfsqq1Xwp6hdxMyLze411vNdo7BDwI6+lPSe7A9XdqyPecNDbtKwYLpsal2r8EHbNzqM+R8XnuRtUaEQS5VlUQ==", "integrity": "sha512-Yfsqq1Xwp6hdxMyLze411vNdo7BDwI6+lPSe7A9XdqyPecNDbtKwYLpsal2r8EHbNzqM+R8XnuRtUaEQS5VlUQ==",
"cpu": [ "cpu": [
"x64" "x64"
+7 -7
View File
@@ -1,6 +1,6 @@
{ {
"name": "wickra", "name": "wickra",
"version": "0.9.3", "version": "0.9.7",
"description": "Streaming-first technical indicators: incremental, fast, install-free. Node bindings powered by Rust.", "description": "Streaming-first technical indicators: incremental, fast, install-free. Node bindings powered by Rust.",
"author": "kingchenc <support@wickra.org>", "author": "kingchenc <support@wickra.org>",
"main": "index.js", "main": "index.js",
@@ -47,12 +47,12 @@
"node": ">= 20" "node": ">= 20"
}, },
"optionalDependencies": { "optionalDependencies": {
"wickra-linux-x64-gnu": "0.9.3", "wickra-linux-x64-gnu": "0.9.7",
"wickra-linux-arm64-gnu": "0.9.3", "wickra-linux-arm64-gnu": "0.9.7",
"wickra-darwin-x64": "0.9.3", "wickra-darwin-x64": "0.9.7",
"wickra-darwin-arm64": "0.9.3", "wickra-darwin-arm64": "0.9.7",
"wickra-win32-x64-msvc": "0.9.3", "wickra-win32-x64-msvc": "0.9.7",
"wickra-win32-arm64-msvc": "0.9.3" "wickra-win32-arm64-msvc": "0.9.7"
}, },
"scripts": { "scripts": {
"build": "napi build --platform --release", "build": "napi build --platform --release",
+7
View File
@@ -17,6 +17,13 @@ publish = false
name = "_wickra" name = "_wickra"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[features]
# Build the bundled data layer against a statically compiled OpenSSL. The
# release workflow (and the manylinux/musllinux CI smoke job) enable this so the
# Linux wheels do not depend on system OpenSSL at build time. See the
# `vendored-tls` feature in wickra-data for the rationale.
vendored-tls = ["wickra-data/vendored-tls"]
[lints] [lints]
workspace = true workspace = true
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "maturin"
[project] [project]
name = "wickra" name = "wickra"
version = "0.9.3" version = "0.9.7"
description = "Streaming-first technical indicators: incremental, fast, install-free." description = "Streaming-first technical indicators: incremental, fast, install-free."
readme = "README.md" readme = "README.md"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
+2 -2
View File
@@ -1,8 +1,8 @@
Package: wickra Package: wickra
Type: Package Type: Package
Title: Streaming-First Technical Indicators Title: Streaming-First Technical Indicators
Version: 0.9.3 Version: 0.9.7
Authors@R: person("Wickra contributors", role = c("aut", "cre"), email = "support@wickra.org") Authors@R: person("kingchenc", role = c("aut", "cre"), email = "support@wickra.org")
Description: R bindings for the Wickra technical-analysis library over its C ABI Description: R bindings for the Wickra technical-analysis library over its C ABI
hub. Exposes 514 indicators, each an O(1) streaming state machine shared with hub. Exposes 514 indicators, each an O(1) streaming state machine shared with
the Rust core and the other language bindings, so that live and historical the Rust core and the other language bindings, so that live and historical
+1 -1
View File
@@ -1,2 +1,2 @@
YEAR: 2026 YEAR: 2026
COPYRIGHT HOLDER: Wickra contributors COPYRIGHT HOLDER: kingchenc and the Wickra contributors
+1 -1
View File
@@ -1,7 +1,7 @@
# Generated by roxygen2: do not edit by hand # Generated by roxygen2: do not edit by hand
S3method(base::flush,wickra_indicator)
S3method(batch,wickra_indicator) S3method(batch,wickra_indicator)
S3method(flush,wickra_indicator)
S3method(is_ready,wickra_indicator) S3method(is_ready,wickra_indicator)
S3method(name,wickra_indicator) S3method(name,wickra_indicator)
S3method(push,wickra_indicator) S3method(push,wickra_indicator)
+46 -3
View File
@@ -479,7 +479,14 @@ Camarilla <- function() {
.wk_obj("camarilla", ptr, "Camarilla") .wk_obj("camarilla", ptr, "Camarilla")
} }
#' CandleReader: parse OHLCV candles from a CSV string #' Parse OHLCV candles from a CSV string
#'
#' Builds a reader over an in-memory CSV string with a header row and OHLCV
#' columns. Pass the result to [read()] to get every parsed candle.
#'
#' @param csv A length-one character string of CSV text (a header row followed
#' by OHLCV data rows).
#' @return A `wickra_indicator` candle reader; read its candles with [read()].
#' @keywords internal #' @keywords internal
#' @export #' @export
CandleReader <- function(csv) { CandleReader <- function(csv) {
@@ -2687,7 +2694,14 @@ RenkoTrailingStop <- function(block_size) {
.wk_obj("renko_trailing_stop", ptr, "RenkoTrailingStop") .wk_obj("renko_trailing_stop", ptr, "RenkoTrailingStop")
} }
#' Resampler indicator #' Resample candles to a higher timeframe
#'
#' Aggregates a stream of candles into higher-timeframe bars. Feed candles with
#' [update()] (it returns a completed higher-timeframe bar, or `NULL` while the
#' current bar is still open) and emit the final, still-open bar with [flush()].
#'
#' @param timeframe Integer number of input candles per higher-timeframe bar.
#' @return A `wickra_indicator` resampler.
#' @keywords internal #' @keywords internal
#' @export #' @export
Resampler <- function(timeframe) { Resampler <- function(timeframe) {
@@ -3487,7 +3501,15 @@ Thrusting <- function() {
.wk_obj("thrusting", ptr, "Thrusting") .wk_obj("thrusting", ptr, "Thrusting")
} }
#' TickAggregator indicator #' Aggregate trade ticks into time-bucketed candles
#'
#' Builds OHLCV candles from a stream of trade ticks. Feed ticks with [push()],
#' which returns the candles closed by that tick.
#'
#' @param bucket Time-bucket width, in the same unit as the tick timestamps.
#' @param gap_fill Logical; if `TRUE`, empty buckets with no trades are still
#' emitted (carried forward) instead of skipped.
#' @return A `wickra_indicator` tick aggregator; feed it ticks with [push()].
#' @keywords internal #' @keywords internal
#' @export #' @export
TickAggregator <- function(bucket, gap_fill) { TickAggregator <- function(bucket, gap_fill) {
@@ -4151,6 +4173,13 @@ Zlema <- function(period) {
#' 15 = 1M). `base_url` overrides the endpoint (`NULL` = production). Not #' 15 = 1M). `base_url` overrides the endpoint (`NULL` = production). Not
#' available in the wasm (r-universe/webR) build, which has no raw sockets. #' available in the wasm (r-universe/webR) build, which has no raw sockets.
#' #'
#' @param symbols Comma-separated trading symbols (case-insensitive), e.g.
#' `"btcusdt,ethusdt"`.
#' @param interval Integer interval code `0:15` (`0` = 1s, `1` = 1m, ...,
#' `12` = 1d, `13` = 3d, `14` = 1w, `15` = 1M).
#' @param base_url Optional endpoint override; `NULL` uses production.
#' @return A `wickra_binance_feed`; poll it with [binance_next()] and close it
#' with [binance_close()].
#' @keywords internal #' @keywords internal
#' @export #' @export
BinanceFeed <- function(symbols, interval, base_url = NULL) { BinanceFeed <- function(symbols, interval, base_url = NULL) {
@@ -4165,6 +4194,10 @@ BinanceFeed <- function(symbols, interval, base_url = NULL) {
#' `high`, `low`, `close`, `volume`, `open_time`, `is_closed`) when an event #' `high`, `low`, `close`, `volume`, `open_time`, `is_closed`) when an event
#' arrives, or `NULL` on timeout. Errors once the stream is closed. #' arrives, or `NULL` on timeout. Errors once the stream is closed.
#' #'
#' @param feed A `wickra_binance_feed` created by [BinanceFeed()].
#' @param timeout_ms Poll timeout in milliseconds.
#' @return A named list (`symbol`, `open`, `high`, `low`, `close`, `volume`,
#' `open_time`, `is_closed`) for an event, or `NULL` on timeout.
#' @keywords internal #' @keywords internal
#' @export #' @export
binance_next <- function(feed, timeout_ms = 1000) { binance_next <- function(feed, timeout_ms = 1000) {
@@ -4173,6 +4206,8 @@ binance_next <- function(feed, timeout_ms = 1000) {
#' Close a Binance feed #' Close a Binance feed
#' #'
#' @param feed A `wickra_binance_feed` created by [BinanceFeed()].
#' @return `NULL`, invisibly.
#' @keywords internal #' @keywords internal
#' @export #' @export
binance_close <- function(feed) { binance_close <- function(feed) {
@@ -4190,6 +4225,14 @@ binance_close <- function(feed) {
#' `volume`, `timestamp`. Blocks until the response arrives. Not available in the #' `volume`, `timestamp`. Blocks until the response arrives. Not available in the
#' wasm (r-universe/webR) build, which has no raw sockets. #' wasm (r-universe/webR) build, which has no raw sockets.
#' #'
#' @param symbol Trading symbol (case-insensitive), e.g. `"btcusdt"`.
#' @param interval Integer interval code `0:15` (see [BinanceFeed()]).
#' @param limit Number of klines to fetch (`1:1000`).
#' @param start_ms,end_ms Optional inclusive Unix-millisecond bounds; a negative
#' value means unset.
#' @param base_url Optional host override; `NULL` uses production.
#' @return An `n x 6` numeric matrix with columns `open`, `high`, `low`,
#' `close`, `volume`, `timestamp`.
#' @keywords internal #' @keywords internal
#' @export #' @export
fetch_binance_klines <- function(symbol, interval, limit, start_ms = -1, fetch_binance_klines <- function(symbol, interval, limit, start_ms = -1,
+1 -1
View File
@@ -151,7 +151,7 @@ name.wickra_indicator <- function(object) {
#' @param timestamp Trade timestamp, in the same unit as the aggregator bucket. #' @param timestamp Trade timestamp, in the same unit as the aggregator bucket.
#' @return A numeric matrix with six named columns (possibly zero rows). #' @return A numeric matrix with six named columns (possibly zero rows).
#' @examples #' @examples
#' agg <- TickAggregator(1000) #' agg <- TickAggregator(1000, FALSE)
#' push(agg, 100, 1, 0) #' push(agg, 100, 1, 0)
#' push(agg, 102, 1, 1000) # closes the first bucket #' push(agg, 102, 1, 1000) # closes the first bucket
#' @export #' @export
+22 -4
View File
@@ -14,6 +14,26 @@ set -e
inc="" inc=""
lib="" lib=""
# A freshly-cut GitHub release can briefly return 404 while its assets propagate
# across the CDN, and a transient network blip should not fail the build either.
# Retry base R's download.file with a backoff (~2 min total) instead of giving up
# on the first miss.
wickra_download() {
_url="$1"
_dest="$2"
_attempt=1
while [ "${_attempt}" -le 6 ]; do
if "${R_HOME}/bin/Rscript" -e "download.file('${_url}', '${_dest}', mode = 'wb', quiet = TRUE)"; then
return 0
fi
echo "wickra: download attempt ${_attempt}/6 failed (${_url}); the release asset may still be propagating — retrying in 20s..."
sleep 20
_attempt=$((_attempt + 1))
done
echo "wickra: failed to download ${_url} after 6 attempts"
return 1
}
# WebAssembly (r-universe / webR): there is no prebuilt wasm C ABI to download, # WebAssembly (r-universe / webR): there is no prebuilt wasm C ABI to download,
# but the build image ships cargo (/usr/local/cargo/bin) and emscripten # but the build image ships cargo (/usr/local/cargo/bin) and emscripten
# (EMSDK on PATH), so build the C ABI staticlib from source for # (EMSDK on PATH), so build the C ABI staticlib from source for
@@ -26,8 +46,7 @@ if [ "$(uname -s)" = "Emscripten" ]; then
echo "wickra: building C ABI from source for wasm32-unknown-emscripten (v${version})" echo "wickra: building C ABI from source for wasm32-unknown-emscripten (v${version})"
build=$(mktemp -d) build=$(mktemp -d)
url="https://github.com/wickra-lib/wickra/archive/refs/tags/v${version}.tar.gz" url="https://github.com/wickra-lib/wickra/archive/refs/tags/v${version}.tar.gz"
"${R_HOME}/bin/Rscript" -e "download.file('${url}', '${build}/src.tar.gz', mode = 'wb', quiet = TRUE)" \ wickra_download "${url}" "${build}/src.tar.gz" || exit 1
|| { echo "wickra: failed to download source ${url}"; exit 1; }
"${R_HOME}/bin/Rscript" -e "untar('${build}/src.tar.gz', exdir = '${build}')" "${R_HOME}/bin/Rscript" -e "untar('${build}/src.tar.gz', exdir = '${build}')"
root="${build}/wickra-${version}" root="${build}/wickra-${version}"
rustup target add wasm32-unknown-emscripten 2>/dev/null || true rustup target add wasm32-unknown-emscripten 2>/dev/null || true
@@ -73,8 +92,7 @@ else
esac esac
url="https://github.com/wickra-lib/wickra/releases/download/v${version}/wickra-c-${triple}.tar.gz" url="https://github.com/wickra-lib/wickra/releases/download/v${version}/wickra-c-${triple}.tar.gz"
echo "wickra: downloading C ABI ${triple} for v${version}" echo "wickra: downloading C ABI ${triple} for v${version}"
"${R_HOME}/bin/Rscript" -e "download.file('${url}', 'src/wickra-c.tar.gz', mode = 'wb', quiet = TRUE)" \ wickra_download "${url}" "src/wickra-c.tar.gz" || exit 1
|| { echo "wickra: failed to download ${url}"; exit 1; }
"${R_HOME}/bin/Rscript" -e "untar('src/wickra-c.tar.gz', exdir = 'src/wickra-c')" "${R_HOME}/bin/Rscript" -e "untar('src/wickra-c.tar.gz', exdir = 'src/wickra-c')"
inc="src/wickra-c/wickra-c-${triple}/include" inc="src/wickra-c/wickra-c-${triple}/include"
lib="src/wickra-c/wickra-c-${triple}/lib" lib="src/wickra-c/wickra-c-${triple}/lib"
+21 -2
View File
@@ -10,6 +10,26 @@
# WICKRA_LIB_DIR to build against a locally built C ABI instead (dev override). # WICKRA_LIB_DIR to build against a locally built C ABI instead (dev override).
set -e set -e
# A freshly-cut GitHub release can briefly return 404 while its assets propagate
# across the CDN, and a transient network blip should not fail the build either.
# Retry base R's download.file with a backoff (~2 min total) instead of giving up
# on the first miss.
wickra_download() {
_url="$1"
_dest="$2"
_attempt=1
while [ "${_attempt}" -le 6 ]; do
if "${R_HOME}/bin/Rscript" -e "download.file('${_url}', '${_dest}', mode = 'wb', quiet = TRUE)"; then
return 0
fi
echo "wickra: download attempt ${_attempt}/6 failed (${_url}); the release asset may still be propagating — retrying in 20s..."
sleep 20
_attempt=$((_attempt + 1))
done
echo "wickra: failed to download ${_url} after 6 attempts"
return 1
}
if [ -n "${WICKRA_INCLUDE_DIR}" ] && [ -n "${WICKRA_LIB_DIR}" ]; then if [ -n "${WICKRA_INCLUDE_DIR}" ] && [ -n "${WICKRA_LIB_DIR}" ]; then
echo "wickra: using C ABI from WICKRA_INCLUDE_DIR / WICKRA_LIB_DIR (dev override)" echo "wickra: using C ABI from WICKRA_INCLUDE_DIR / WICKRA_LIB_DIR (dev override)"
inc="${WICKRA_INCLUDE_DIR}" inc="${WICKRA_INCLUDE_DIR}"
@@ -24,8 +44,7 @@ else
esac esac
url="https://github.com/wickra-lib/wickra/releases/download/v${version}/wickra-c-${triple}.tar.gz" url="https://github.com/wickra-lib/wickra/releases/download/v${version}/wickra-c-${triple}.tar.gz"
echo "wickra: downloading C ABI ${triple} for v${version}" echo "wickra: downloading C ABI ${triple} for v${version}"
"${R_HOME}/bin/Rscript" -e "download.file('${url}', 'src/wickra-c.tar.gz', mode = 'wb', quiet = TRUE)" \ wickra_download "${url}" "src/wickra-c.tar.gz" || exit 1
|| { echo "wickra: failed to download ${url}"; exit 1; }
"${R_HOME}/bin/Rscript" -e "untar('src/wickra-c.tar.gz', exdir = 'src/wickra-c')" "${R_HOME}/bin/Rscript" -e "untar('src/wickra-c.tar.gz', exdir = 'src/wickra-c')"
inc="src/wickra-c/wickra-c-${triple}/include" inc="src/wickra-c/wickra-c-${triple}/include"
lib="src/wickra-c/wickra-c-${triple}/lib" lib="src/wickra-c/wickra-c-${triple}/lib"
+1 -1
View File
@@ -4,7 +4,7 @@
\alias{AwesomeOscillatorHistogram} \alias{AwesomeOscillatorHistogram}
\title{AwesomeOscillatorHistogram indicator} \title{AwesomeOscillatorHistogram indicator}
\usage{ \usage{
AwesomeOscillatorHistogram(fast, slow, sma_period) AwesomeOscillatorHistogram(fast, slow, lookback)
} }
\description{ \description{
AwesomeOscillatorHistogram indicator AwesomeOscillatorHistogram indicator
+29
View File
@@ -0,0 +1,29 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/indicators.R
\name{BinanceFeed}
\alias{BinanceFeed}
\title{Connect to a live Binance kline feed}
\usage{
BinanceFeed(symbols, interval, base_url = NULL)
}
\arguments{
\item{symbols}{Comma-separated trading symbols (case-insensitive), e.g.
\code{"btcusdt,ethusdt"}.}
\item{interval}{Integer interval code \code{0:15} (\code{0} = 1s, \code{1} = 1m, ...,
\code{12} = 1d, \code{13} = 3d, \code{14} = 1w, \code{15} = 1M).}
\item{base_url}{Optional endpoint override; \code{NULL} uses production.}
}
\value{
A \code{wickra_binance_feed}; poll it with \code{\link[=binance_next]{binance_next()}} and close it
with \code{\link[=binance_close]{binance_close()}}.
}
\description{
Opens a live Binance kline stream for one or more comma-separated \code{symbols}
(case-insensitive) at the given \code{interval} code (an integer \code{0:15}, the same
order as the other bindings: 0 = 1s, 1 = 1m, ... 12 = 1d, 13 = 3d, 14 = 1w,
15 = 1M). \code{base_url} overrides the endpoint (\code{NULL} = production). Not
available in the wasm (r-universe/webR) build, which has no raw sockets.
}
\keyword{internal}
+20
View File
@@ -0,0 +1,20 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/indicators.R
\name{CandleReader}
\alias{CandleReader}
\title{Parse OHLCV candles from a CSV string}
\usage{
CandleReader(csv)
}
\arguments{
\item{csv}{A length-one character string of CSV text (a header row followed
by OHLCV data rows).}
}
\value{
A \code{wickra_indicator} candle reader; read its candles with \code{\link[=read]{read()}}.
}
\description{
Builds a reader over an in-memory CSV string with a header row and OHLCV
columns. Pass the result to \code{\link[=read]{read()}} to get every parsed candle.
}
\keyword{internal}
+20
View File
@@ -0,0 +1,20 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/indicators.R
\name{Resampler}
\alias{Resampler}
\title{Resample candles to a higher timeframe}
\usage{
Resampler(timeframe)
}
\arguments{
\item{timeframe}{Integer number of input candles per higher-timeframe bar.}
}
\value{
A \code{wickra_indicator} resampler.
}
\description{
Aggregates a stream of candles into higher-timeframe bars. Feed candles with
\code{\link[=update]{update()}} (it returns a completed higher-timeframe bar, or \code{NULL} while the
current bar is still open) and emit the final, still-open bar with \code{\link[=flush]{flush()}}.
}
\keyword{internal}
+22
View File
@@ -0,0 +1,22 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/indicators.R
\name{TickAggregator}
\alias{TickAggregator}
\title{Aggregate trade ticks into time-bucketed candles}
\usage{
TickAggregator(bucket, gap_fill)
}
\arguments{
\item{bucket}{Time-bucket width, in the same unit as the tick timestamps.}
\item{gap_fill}{Logical; if \code{TRUE}, empty buckets with no trades are still
emitted (carried forward) instead of skipped.}
}
\value{
A \code{wickra_indicator} tick aggregator; feed it ticks with \code{\link[=push]{push()}}.
}
\description{
Builds OHLCV candles from a stream of trade ticks. Feed ticks with \code{\link[=push]{push()}},
which returns the candles closed by that tick.
}
\keyword{internal}
+18
View File
@@ -0,0 +1,18 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/indicators.R
\name{binance_close}
\alias{binance_close}
\title{Close a Binance feed}
\usage{
binance_close(feed)
}
\arguments{
\item{feed}{A \code{wickra_binance_feed} created by \code{\link[=BinanceFeed]{BinanceFeed()}}.}
}
\value{
\code{NULL}, invisibly.
}
\description{
Close a Binance feed
}
\keyword{internal}
+23
View File
@@ -0,0 +1,23 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/indicators.R
\name{binance_next}
\alias{binance_next}
\title{Poll a Binance feed for the next kline event}
\usage{
binance_next(feed, timeout_ms = 1000)
}
\arguments{
\item{feed}{A \code{wickra_binance_feed} created by \code{\link[=BinanceFeed]{BinanceFeed()}}.}
\item{timeout_ms}{Poll timeout in milliseconds.}
}
\value{
A named list (\code{symbol}, \code{open}, \code{high}, \code{low}, \code{close}, \code{volume},
\code{open_time}, \code{is_closed}) for an event, or \code{NULL} on timeout.
}
\description{
Waits up to \code{timeout_ms} milliseconds. Returns a named list (\code{symbol}, \code{open},
\code{high}, \code{low}, \code{close}, \code{volume}, \code{open_time}, \code{is_closed}) when an event
arrives, or \code{NULL} on timeout. Errors once the stream is closed.
}
\keyword{internal}
+41
View File
@@ -0,0 +1,41 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/indicators.R
\name{fetch_binance_klines}
\alias{fetch_binance_klines}
\title{Fetch historical Binance klines over REST}
\usage{
fetch_binance_klines(
symbol,
interval,
limit,
start_ms = -1,
end_ms = -1,
base_url = NULL
)
}
\arguments{
\item{symbol}{Trading symbol (case-insensitive), e.g. \code{"btcusdt"}.}
\item{interval}{Integer interval code \code{0:15} (see \code{\link[=BinanceFeed]{BinanceFeed()}}).}
\item{limit}{Number of klines to fetch (\code{1:1000}).}
\item{start_ms, end_ms}{Optional inclusive Unix-millisecond bounds; a negative
value means unset.}
\item{base_url}{Optional host override; \code{NULL} uses production.}
}
\value{
An \verb{n x 6} numeric matrix with columns \code{open}, \code{high}, \code{low},
\code{close}, \code{volume}, \code{timestamp}.
}
\description{
Downloads up to \code{limit} (\code{1:1000}) historical klines for \code{symbol} at the given
\code{interval} code (an integer \code{0:15}, the same order as the other bindings).
\code{start_ms}/\code{end_ms} are optional inclusive Unix-millisecond bounds (a negative
value means unset); \code{base_url} overrides the host (\code{NULL} = production). Returns
an \verb{n x 6} numeric matrix with columns \code{open}, \code{high}, \code{low}, \code{close},
\code{volume}, \code{timestamp}. Blocks until the response arrives. Not available in the
wasm (r-universe/webR) build, which has no raw sockets.
}
\keyword{internal}
+25
View File
@@ -0,0 +1,25 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/methods.R
\name{flush.wickra_indicator}
\alias{flush.wickra_indicator}
\title{Flush a resampler's final candle}
\usage{
\method{flush}{wickra_indicator}(con)
}
\arguments{
\item{con}{A \code{wickra_indicator} created by \code{\link[=Resampler]{Resampler()}}.}
}
\value{
A named numeric vector (\code{open}, \code{high}, \code{low}, \code{close}, \code{volume},
\code{timestamp}), or \code{NULL} if nothing is pending.
}
\description{
Emit the final, still-open candle a \code{\link[=Resampler]{Resampler()}} is aggregating (the partial
higher-timeframe bar that no later input has closed yet). Extends the base
generic \code{\link[base:flush]{base::flush()}}.
}
\examples{
r <- Resampler(5)
for (t in 0:6) update(r, 100 + t, 101 + t, 99 + t, 100 + t, 10, t)
flush(r)
}
+26
View File
@@ -0,0 +1,26 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/methods.R
\name{is_ready}
\alias{is_ready}
\alias{is_ready.wickra_indicator}
\title{Whether an indicator has consumed enough input to emit a value}
\usage{
is_ready(object)
\method{is_ready}{wickra_indicator}(object)
}
\arguments{
\item{object}{A \code{wickra_indicator}.}
}
\value{
A single logical.
}
\description{
Not available for the alt-chart bar builders, which have no warmup.
}
\examples{
sma <- Sma(3)
is_ready(sma) # FALSE
for (x in c(1, 2, 3)) update(sma, x)
is_ready(sma) # TRUE
}
+24
View File
@@ -0,0 +1,24 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/methods.R
\name{name}
\alias{name}
\alias{name.wickra_indicator}
\title{Canonical name of an indicator}
\usage{
name(object)
\method{name}{wickra_indicator}(object)
}
\arguments{
\item{object}{A \code{wickra_indicator}.}
}
\value{
A single character string.
}
\description{
Returns the stable, human-readable name of the indicator (the same name
reported by every other Wickra binding), e.g. \code{"SMA"} for \code{\link[=Sma]{Sma()}}.
}
\examples{
name(Sma(14)) # "SMA"
}
+33
View File
@@ -0,0 +1,33 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/methods.R
\name{push}
\alias{push}
\alias{push.wickra_indicator}
\title{Push a trade tick into a tick aggregator}
\usage{
push(object, price, size, timestamp)
\method{push}{wickra_indicator}(object, price, size, timestamp)
}
\arguments{
\item{object}{A \code{wickra_indicator} created by \code{\link[=TickAggregator]{TickAggregator()}}.}
\item{price}{Trade price.}
\item{size}{Trade size (volume).}
\item{timestamp}{Trade timestamp, in the same unit as the aggregator bucket.}
}
\value{
A numeric matrix with six named columns (possibly zero rows).
}
\description{
Feeds one trade tick to a \code{\link[=TickAggregator]{TickAggregator()}} and returns the candles it
closed as a numeric matrix with columns \code{open}, \code{high}, \code{low}, \code{close},
\code{volume}, \code{timestamp} (zero rows while the open bar merely grows).
}
\examples{
agg <- TickAggregator(1000, FALSE)
push(agg, 100, 1, 0)
push(agg, 102, 1, 1000) # closes the first bucket
}
+25
View File
@@ -0,0 +1,25 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/methods.R
\name{read}
\alias{read}
\alias{read.wickra_indicator}
\title{Read every candle parsed by a CSV candle reader}
\usage{
read(object)
\method{read}{wickra_indicator}(object)
}
\arguments{
\item{object}{A \code{wickra_indicator} created by \code{\link[=CandleReader]{CandleReader()}}.}
}
\value{
A numeric matrix with six named columns (zero rows for an empty CSV).
}
\description{
Returns all the candles a \code{\link[=CandleReader]{CandleReader()}} parsed from its CSV, as a numeric
matrix with columns \code{open}, \code{high}, \code{low}, \code{close}, \code{volume}, \code{timestamp}.
}
\examples{
r <- CandleReader("timestamp,open,high,low,close,volume\n0,100,101,99,100.5,10\n")
read(r)
}
+6 -6
View File
@@ -7,12 +7,12 @@
\format{ \format{
A data frame with 250 rows and 6 columns: A data frame with 250 rows and 6 columns:
\describe{ \describe{
\item{date}{Trading date (\code{Date}).} \item{date}{Trading date (\code{Date}).}
\item{open}{Opening price.} \item{open}{Opening price.}
\item{high}{Session high.} \item{high}{Session high.}
\item{low}{Session low.} \item{low}{Session low.}
\item{close}{Closing price.} \item{close}{Closing price.}
\item{volume}{Traded volume.} \item{volume}{Traded volume.}
} }
} }
\usage{ \usage{
+24
View File
@@ -0,0 +1,24 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/methods.R
\name{warmup_period}
\alias{warmup_period}
\alias{warmup_period.wickra_indicator}
\title{Number of updates an indicator needs before it produces a value}
\usage{
warmup_period(object)
\method{warmup_period}{wickra_indicator}(object)
}
\arguments{
\item{object}{A \code{wickra_indicator}.}
}
\value{
A single integer: the warmup period.
}
\description{
Not available for the alt-chart bar builders (\code{\link[=RenkoBars]{RenkoBars()}}, \code{\link[=KagiBars]{KagiBars()}},
\code{\link[=PointAndFigureBars]{PointAndFigureBars()}}, …), which have no warmup.
}
\examples{
warmup_period(Sma(14)) # 14
}
+3 -2
View File
@@ -18,16 +18,17 @@ Useful links:
\itemize{ \itemize{
\item \url{https://github.com/wickra-lib/wickra} \item \url{https://github.com/wickra-lib/wickra}
\item \url{https://docs.wickra.org} \item \url{https://docs.wickra.org}
\item \url{https://wickra-lib.r-universe.dev}
\item Report bugs at \url{https://github.com/wickra-lib/wickra/issues} \item Report bugs at \url{https://github.com/wickra-lib/wickra/issues}
} }
} }
\author{ \author{
\strong{Maintainer}: Wickra contributors \email{support@wickra.org} \strong{Maintainer}: kingchenc \email{support@wickra.org}
Authors: Authors:
\itemize{ \itemize{
\item Wickra contributors \email{support@wickra.org} \item kingchenc \email{support@wickra.org}
} }
} }
+9
View File
@@ -54,6 +54,15 @@ default = []
# want. `live-binance` covers both the live WebSocket feed and the historical # want. `live-binance` covers both the live WebSocket feed and the historical
# REST kline fetcher. # REST kline fetcher.
live-binance = ["dep:tokio", "dep:tokio-tungstenite", "dep:futures-util", "dep:url", "dep:ureq", "dep:native-tls"] live-binance = ["dep:tokio", "dep:tokio-tungstenite", "dep:futures-util", "dep:url", "dep:ureq", "dep:native-tls"]
# `live-binance` with a statically built OpenSSL instead of the system one. The
# native-tls stack (tokio-tungstenite + ureq, unified on the same `native-tls`
# crate) links `openssl-sys`, which needs OpenSSL at build time. The manylinux
# and musllinux wheel containers do not provide it — manylinux lacks the headers
# and the musllinux build cross-compiles against a musl sysroot that has no
# OpenSSL at all — so the Linux wheels are built with this feature, which
# compiles OpenSSL from source and links it statically. No-op on macOS/Windows,
# where native-tls uses Security.framework / SChannel and never pulls openssl-sys.
vendored-tls = ["live-binance", "native-tls/vendored"]
[dev-dependencies] [dev-dependencies]
approx = { workspace = true } approx = { workspace = true }
+2 -2
View File
@@ -6,7 +6,7 @@
<groupId>org.wickra.examples</groupId> <groupId>org.wickra.examples</groupId>
<artifactId>wickra-examples</artifactId> <artifactId>wickra-examples</artifactId>
<version>0.9.3</version> <version>0.9.7</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Wickra Java examples</name> <name>Wickra Java examples</name>
@@ -21,7 +21,7 @@
<dependency> <dependency>
<groupId>org.wickra</groupId> <groupId>org.wickra</groupId>
<artifactId>wickra</artifactId> <artifactId>wickra</artifactId>
<version>0.9.3</version> <version>0.9.7</version>
</dependency> </dependency>
</dependencies> </dependencies>
+7 -7
View File
@@ -14,7 +14,7 @@
}, },
"../../bindings/node": { "../../bindings/node": {
"name": "wickra", "name": "wickra",
"version": "0.9.3", "version": "0.9.7",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"devDependencies": { "devDependencies": {
"@napi-rs/cli": "^2.18.0" "@napi-rs/cli": "^2.18.0"
@@ -23,12 +23,12 @@
"node": ">= 20" "node": ">= 20"
}, },
"optionalDependencies": { "optionalDependencies": {
"wickra-darwin-arm64": "0.9.3", "wickra-darwin-arm64": "0.9.7",
"wickra-darwin-x64": "0.9.3", "wickra-darwin-x64": "0.9.7",
"wickra-linux-arm64-gnu": "0.9.3", "wickra-linux-arm64-gnu": "0.9.7",
"wickra-linux-x64-gnu": "0.9.3", "wickra-linux-x64-gnu": "0.9.7",
"wickra-win32-arm64-msvc": "0.9.3", "wickra-win32-arm64-msvc": "0.9.7",
"wickra-win32-x64-msvc": "0.9.3" "wickra-win32-x64-msvc": "0.9.7"
} }
}, },
"node_modules/wickra": { "node_modules/wickra": {