Compare commits

..

19 Commits

Author SHA1 Message Date
kingchenc d188959aab release: bump 0.7.8 -> 0.7.9 (#234)
Version bump 0.7.8 -> 0.7.9 for the Java binding release.
2026-06-09 20:33:17 +02:00
kingchenc 167f7b3ffe Add the Java binding over the C ABI hub (Panama/FFM) (#233)
Adds a Java binding (`bindings/java`) over the C ABI hub — the fourth language stecker after C#, Go and R, reaching the hub through the Java Foreign Function & Memory API (Panama, `java.lang.foreign`, final in Java 22) rather than JNI or jextract.

## What's here
- **`bindings/java`** — a Maven module (`org.wickra:wickra`) exposing all 514 indicators as idiomatic `AutoCloseable` classes. The downcall handles (`internal/NativeMethods.java`), the per-indicator wrappers and the output records are generated from `bindings/c/include/wickra.h` (same eight-archetype taxonomy as the C#/Go/R generators: scalar/batch, multi-output, bars, profile, values-profile, array-input). The opaque handle is a `MemorySegment` freed by a registered `java.lang.ref.Cleaner` action; multi-output returns a `record` (`null` at warmup), bars a `record[]`, profiles a record with a trailing `double[]`. The hand-written `WickraNative` resolves the native library (a bundled per-platform copy, or a `target/release` fallback for local development) and validates it against a sentinel symbol. repr(C) struct offsets are computed in the generator so the FFM reads land on the exact bytes.
- **`examples/java`** — the full example suite mirroring C/C#/Go/R: streaming, backtest, multi_timeframe, parallel_assets (parallel streams), three strategies, and `FetchBtcusdt`/`LiveBinance`.
- **CI** — a `java` job builds the C ABI library, sets up JDK 22 (Temurin, with a CDN-flake retry), runs the archetype test suite and the seven offline examples on Linux, macOS and Windows.
- **Release** — a gated `java-publish` job (skipped until the `JAVA_PUBLISH_ENABLED` repository variable is set) stages the native libraries from the `wickra-c-<triple>.tar.gz` assets into the binding's resources and deploys to Maven Central with GPG signing. Independent of the GitHub-release job, like the NuGet job.
- **Docs** — Java added to the README languages table, project layout, building/testing and comparison table, CONTRIBUTING, ARCHITECTURE, the examples index, the issue/PR templates, the About-description template, and the other binding READMEs.

## Requirements
Java 22+ (the FFM API is final since Java 22). The binding requires `--enable-native-access=ALL-UNNAMED` at runtime; the test and example runners pass it automatically.

No Rust crate or `Cargo.toml` change — the Java binding is standalone and additive. The generated `*.java` are committed (like the node `index.js`/`index.d.ts`); the generator stays private.
2026-06-09 20:30:29 +02:00
kingchenc 8659b42bef release: bump 0.7.7 -> 0.7.8 (#232)
Version bump 0.7.7 -> 0.7.8 for the R binding release.
2026-06-09 19:22:11 +02:00
kingchenc b7ef63400d Add the R binding over the C ABI hub (#230)
Adds an R binding (`bindings/r`) over the C ABI hub — the third language stecker after C# and Go, reaching the hub through R's native `.Call` interface (not extendr).

## What's here
- **`bindings/r`** — an R package exposing all 514 indicators as constructors that return a `wickra_indicator` object with generic `update`/`batch`/`reset` methods. The C glue (`src/wickra.c`) and R wrappers (`R/indicators.R`) are generated from `bindings/c/include/wickra.h` (same archetype taxonomy as the C#/Go generators: scalar/batch, multi-output, bars, profile, profile-values, array-input). The opaque handle is an R external pointer freed by a registered finalizer; multi-output returns a named vector (`NA` at warmup), bars a matrix, profiles a list.
- **`examples/r`** — the full example suite mirroring C/C#/Go: streaming, backtest, multi_timeframe, parallel_assets (`mclapply`), three strategies, and `fetch_btcusdt`/`live_binance`.
- **CI** — an `r` job builds the C ABI library, installs the package, runs the `testthat` suite and the offline examples on Linux, macOS and Windows (`R CMD check` is clean: 0 warnings, 0 notes).
- **Docs** — R added to the README languages table, project layout, building/testing, CONTRIBUTING binding table + regenerate note, ARCHITECTURE, examples index, issue/PR templates, the About-description template, and the other binding READMEs.

## Linking / distribution
The package compiles a thin `.Call` glue layer against the prebuilt C ABI library (header via `WICKRA_INCLUDE_DIR`, library via `WICKRA_LIB_DIR`). On Windows the package's own `wickra.dll` would collide with the C ABI's `wickra.dll`, so `configure.win` stages a renamed copy (`wickra_abi.dll`) and builds an import library referencing it; `install.libs.R` bundles the DLL and `.onLoad` puts it on the load path. On Linux/macOS the rpath locates the shared library. No `release.yml` change — R is distributed via r-universe / source install (gated).

No Rust crate or `Cargo.toml` change — the R package is standalone and additive.
2026-06-09 19:18:40 +02:00
kingchenc 8225e1ab91 Check out the PR head by SHA in the count-sync workflow (#231)
## Problem
The **Sync indicator count** check has failed on every release-bump PR since 0.7.5 (`release/0.7.6`, `release/0.7.7`, …). It is a race, not a counter mismatch.

The checkout step used the PR head **branch name**:
\`\`\`yaml
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref }}
\`\`\`
Release PRs are merged with \`gh pr merge --squash --delete-branch\`, which deletes the head branch the instant the PR merges — usually before this queued read-only check reaches its checkout. Fetching the now-gone \`refs/heads/release/X.Y.Z\` then fails with exit 1 (3 retries, then error). Push-to-main, tag and slower feature PRs stayed green because their head branch still existed when the check ran.

## Fix
Check out \`github.event.pull_request.head.sha\` instead. The head SHA stays reachable via \`refs/pull/N/head\` after the branch is deleted, so an instant merge no longer red-Xes the run. It is still the author's head commit (not the merge ref), so the counter validates exactly what will land — the existing design intent is preserved.

Because \`pull_request\` runs the workflow definition from the merge commit, the fix already applies to this PR itself.
2026-06-09 18:59:09 +02:00
kingchenc d0061c73b8 release: bump 0.7.6 -> 0.7.7 (#229)
Bumps the workspace to 0.7.7 to ship the Go binding.
2026-06-09 17:35:25 +02:00
kingchenc 23d636fd97 Add the Go binding over the C ABI hub (#228)
Adds a Go binding (`bindings/go`) over the C ABI hub — the second language stecker after C#.

## What's here
- **`bindings/go`** — a cgo binding exposing all 514 indicators as idiomatic Go types with `New<Indicator>` constructors and `Update`/`Batch`/`Reset`/`Close` methods. The wrappers in `indicators_gen.go` are generated from `bindings/c/include/wickra.h` (same archetype taxonomy as the C# generator: scalar/batch, multi-output, bars, profile, profile-values, array-input). Opaque handles are freed by `Close()` with a `runtime.SetFinalizer` backstop; pointer arguments are caller-owned, panics never cross the boundary.
- **`examples/go`** — the full example suite mirroring C/C#: streaming, backtest, multi_timeframe, parallel_assets (goroutine fan-out), three strategies, and `fetch_btcusdt`/`live_binance`.
- **CI** — a `go` job builds the C ABI library, stages it, and runs `gofmt`/`go vet`/`go test` plus the offline examples on Linux, macOS and Windows.
- **Docs** — Go added to the README languages table, project layout, building/testing, CONTRIBUTING binding table + regenerate note, ARCHITECTURE, examples index, issue/PR templates, the About-description template, and the other binding READMEs.

## Linking / distribution
The binding links the prebuilt C ABI library via cgo (`libwickra.so`/`.dylib`/`wickra.dll` staged under `bindings/go/lib`, gitignored). The native libraries are already shipped per target triple by the existing `c-abi-build` release job; distribution is via the subdirectory module tag `bindings/go/vX.Y.Z` (gated), so `release.yml` needs no new publish job.

No Rust crate or `Cargo.toml` change — the Go module is standalone and additive.

Not for merge yet (gated, per request).
2026-06-09 17:33:37 +02:00
kingchenc fce26cf881 release: bump 0.7.5 -> 0.7.6 (#227)
Bumps the workspace to 0.7.6 to ship the C# (.NET) binding to NuGet.
2026-06-09 14:34:18 +02:00
kingchenc 91f6f67257 Add C# (.NET) binding over the C ABI hub (#226)
The first language stecker on the C ABI hub: a .NET binding exposing all 514
indicators as idiomatic `IDisposable` classes, generated from `wickra.h`.

## What's here

- **`bindings/csharp/`** — the `Wickra` .NET 8 package. `[LibraryImport]`
  source-generated P/Invoke (`NativeMethods.g.cs`) plus idiomatic wrappers
  (`Indicators.g.cs`), both generated from the committed `bindings/c/include/wickra.h`.
  The binding owns no indicator maths — it only marshals types across the C ABI.
- **Marshalling, verified end-to-end against the native library.** Opaque handles
  cross as `nint` kept alive per call via a `SafeHandle`; `bool` as
  `[MarshalAs(U1)]` (Rust `bool` is one byte); a self-correcting
  `DllImportResolver` validates the loaded library actually exports the Wickra
  ABI. Tests cover one representative per FFI archetype (scalar, candle, pairwise,
  multi-output, bars, profile, values-profile, order-book / array-input) plus
  exact Sma reference values.
- **NuGet packaging** — `dotnet pack` produces `Wickra.<version>.nupkg`; the
  release pipeline stages prebuilt native libraries under `runtimes/<rid>/native/`
  for six target triples (win/linux/osx × x64/arm64).
- **`examples/csharp/`** — nine examples mirroring `examples/c/`: streaming,
  backtest, multi_timeframe, parallel_assets, three strategies, and
  fetch_btcusdt + live_binance.
- **CI** — a `csharp` job on the three OSes builds the C ABI, tests the binding,
  and runs the offline examples. **Release** — a gated `csharp-publish` job packs
  and pushes to NuGet (gated on `NUGET_API_KEY`, independent of the GitHub-release
  job so a C# hiccup never blocks the C/C++ asset release).
- **Docs consistency wave** — README, CONTRIBUTING, CHANGELOG, examples/README,
  the issue / PR templates, `sync-about.yml`, and `.gitattributes`.

The native Python / Node / WASM bindings and the C ABI are untouched; this is
additive. Publishing to NuGet stays gated behind the release tag and the secret.
2026-06-09 14:32:05 +02:00
kingchenc 4caaa1db97 release: bump 0.7.4 -> 0.7.5 (#225)
Version bump for the C ABI hub release (0.7.4 -> 0.7.5). See #222 + #224.
2026-06-09 02:26:27 +02:00
kingchenc 12681e4b1b C ABI: full example suite + docs & About coverage (#224)
Stacked on #222 (base `feat/c-abi-hub`), so the diff is just the additions on top of the hub foundation — no merge of #222 required.

## What this adds

**Examples — full parity with rust/python/node (`examples/c/`)**
- `streaming.c` upgraded to the multi-indicator (SMA/EMA/RSI/MACD + signals) demo
- `backtest.c`, `multi_timeframe.c` (manual time-bucket resampling), `parallel_assets.c` (serial vs OpenMP fan-out, one handle per asset)
- three educational strategies: `strategy_rsi_mean_reversion.c`, `strategy_macd_adx.c`, `strategy_bollinger_squeeze.c`
- two network examples shelling out to `curl`: `fetch_btcusdt.c`, `live_binance.c` (REST poll)
- two header-only helpers (`wickra_csv.h`, `wickra_strategy.h`) since the C ABI ships no IO layer
- CMake builds all 11; the 9 offline ones run under `ctest` on 3 OS; the network two are built-only

**Docs & metadata — surface the C ABI everywhere it was missing**
- ARCHITECTURE diagram + crate table, SECURITY + THREAT_MODEL (the C ABI as the sole `unsafe` FFI surface), the three binding package READMEs, issue/PR templates, CHANGELOG, and the GitHub About template (live About + org description updated too)

**Cleanup**
- removed all references to the private generator tooling from public files (`bindings/c/src/lib.rs` header, `CONTRIBUTING.md`, `sync-about.yml`)

Verified locally: `cargo build -p wickra-c --release`, `cmake + ctest` (9/9 pass), and `-Wall -Wextra -Wpedantic` clean on gcc 13.
2026-06-09 02:14:28 +02:00
kingchenc 91e05e3c26 C ABI hub crate (bindings/c) foundation (#222)
## What

Introduces `wickra-c` — a `cdylib` + `staticlib` that exposes the Rust core over a **C ABI**. This is the hub every C-capable language (C, C++, Go, C#, Java, R) links against, instead of re-wiring each indicator natively. The native Python/Node/WASM bindings are untouched; this is purely additive, for ecosystems without first-class Rust tooling.

## Scope (foundation slice)

This PR deliberately validates the **whole pipeline end to end with one indicator (SMA)** before scaling to all 514, so the CI / cross-OS / header-drift mechanics are proven green first.

- Opaque `*mut T` handles; `wickra_<ind>_{new,update,batch,reset,free}`.
- NaN sentinel for warmup / NULL handles; caller-owned batch buffers; every function NULL-safe.
- cbindgen generates and commits `bindings/c/include/wickra.h` with opaque handle typedefs.
- A C smoke example (`examples/c/`) links the header + compiled library and runs (CMake + ctest).
- A `c-abi` CI job builds the library and runs the smoke test on **Linux, macOS and Windows**, plus a header drift check on Linux.

## Notes

- The per-indicator FFI blocks are plain `#[no_mangle]` functions, **not** a macro: cbindgen cannot see macro-generated functions on stable Rust (macro expansion needs nightly), so the blocks are written literally and will be generated mechanically by the ScriptHelpers `capi` wrapper in a follow-up (same model as the committed-but-generated Node `index.js`).
- `bindings/c` cannot inherit the workspace `forbid(unsafe_code)` lint (the C boundary needs raw pointers), so it mirrors every workspace lint and only relaxes `unsafe_code`. The Rust core stays `unsafe`-forbidden.

## Follow-ups (separate PRs)

- ScriptHelpers `capi` generator + wire the scalar family (~235).
- Hand-written blocks for multi-output / custom-input / bars (~279).
- Docs consistency wave (README / docs / webpage: Python·Node·WASM·Rust → +C).
- Release wiring (native-lib matrix + header/lib GH-release assets) — gated.
2026-06-09 02:07:03 +02:00
kingchenc 9d0983b666 ci(sync-about): sync indicator count into the webpage About page (#223)
The `wickra.org/about` page carries the indicator count in the bot-syncable `<N> indicators` token, but `sync-about.yml` only rewrote `index.md` + `.vitepress/config.ts` on the webpage. Add `about.md` to the webpage count step's `sed` file list and its `git add`, so the About page's count self-heals on every push-to-main / tag like the rest of the marketing site.

No-op for the Rust build — workflow file only.
2026-06-08 21:38:42 +02:00
kingchenc 13c8250488 release: bump 0.7.3 -> 0.7.4 (#221)
Version bump **0.7.3 → 0.7.4** for the B19 Alt-Chart Bars batch (7 new bar builders, 507 → 514).

Bumps `Cargo.toml` (+ `wickra-core` dep), `Cargo.lock`, `pyproject.toml`, the Node `package.json` and its six platform packages, both `package-lock.json` files, and the CHANGELOG (`[Unreleased]` → `[0.7.4]` with compare URLs).
2026-06-08 14:33:43 +02:00
kingchenc e5305ffa94 feat: add 7 alt-chart bar builders (B19) (#220)
Adds seven information-driven bar builders to the **Alt-Chart Bars** family, the final batch of the family-deepening run. Indicator count **507 → 514**.

## Builders
All implement the `BarBuilder` trait (`update(Candle) -> Vec<Bar>`), emitting a data-dependent number of completed bars per candle.

| Builder | Driver | Bar fields |
|---------|--------|-----------|
| `RangeBars` | close | open, close, direction |
| `TickBars` | OHLCV | open, high, low, close, volume |
| `VolumeBars` | OHLCV | open, high, low, close, volume |
| `DollarBars` (Lopez de Prado) | OHLCV | + dollar |
| `ImbalanceBars` | OHLC | + imbalance, direction |
| `RunBars` | OHLC | + length, direction |
| `ThreeLineBreakBars` | close | open, close, direction |

## Touchpoints
Seven core modules (each with full unit tests), `mod.rs`/`lib.rs` (builders counted, bar element types on their own re-export lines), README family rows, Python/Node/WASM hand-written bindings for the variable-length output (Python tuples + `(k, N)` ndarray; Node `Vec<object>`; WASM array of objects), the `bar_builder_update_candle` fuzz target, dedicated Python + Node tests, the `BAR_BUILDERS` completeness exclusion, and CHANGELOG.

## Verification
- `cargo test -p wickra-core --lib` — 4207 passed
- `cargo test -p wickra-core --doc` — 464 passed
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` — clean
- `npm test` (node) — 584 passed
- `pytest` (python) — 957 passed
2026-06-08 14:32:40 +02:00
kingchenc 46be7a54ea release: bump 0.7.2 -> 0.7.3 (#219)
Version bump **0.7.2 → 0.7.3** for the B18 Risk / Performance batch (9 new indicators, 498 → 507).

Bumps `Cargo.toml` (+ `wickra-core` dep), `Cargo.lock`, `pyproject.toml`, the Node `package.json` and its six platform packages, both `package-lock.json` files, and the CHANGELOG (`[Unreleased]` → `[0.7.3]` with compare URLs).
2026-06-08 13:29:39 +02:00
kingchenc bca61322b5 feat: add 9 Risk / Performance indicators (B18) (#218)
Adds nine risk/performance metrics to the existing **Risk / Performance** family, all consuming a per-period return series (`f64` in, `f64` out). Indicator count **498 → 507**.

## Indicators

Single-param (`new(period)`, macro bindings):
- **SterlingRatio** — mean return over average drawdown of the equity curve.
- **BurkeRatio** — return over root-sum-squared drawdowns.
- **MartinRatio** — Ulcer Performance Index; return over RMS percentage drawdown.
- **TailRatio** — 95th percentile over the absolute 5th percentile return.
- **KRatio** — Kestner; equity-curve OLS slope over the standard error of that slope.
- **CommonSenseRatio** — tail ratio times gain-to-pain.
- **GainToPainRatio** — sum of returns over the sum of absolute losses.

Multi-param (hand-written Python/Node bindings, variadic WASM macro):
- **UpsidePotentialRatio** — `new(period, mar)`; upside mean over downside deviation (Sortino philosophy).
- **M2Measure** — `new(period, risk_free, benchmark_stddev)`; Modigliani M², Sharpe rescaled into benchmark return units.

## Touchpoints
Core modules + unit tests, `mod.rs`/`lib.rs` wiring, Python/Node/WASM bindings (`index.d.ts`/`index.js` regenerated), fuzz drive lines, Python `SCALAR` registry + Node factories, CHANGELOG, and the indicator counters.

## Verification
- `cargo test -p wickra-core --lib` — 4149 passed
- `cargo test -p wickra-core --doc` — 457 passed
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` — clean
- `npm test` (node) — 577 passed
- `pytest` (python) — 947 passed
2026-06-08 13:23:01 +02:00
kingchenc fc6f619550 release: bump 0.7.1 -> 0.7.2 (#217)
Version bump 0.7.1 -> 0.7.2 for the B17 Market Profile batch (498 indicators).
2026-06-08 04:18:34 +02:00
kingchenc 91aa6fffbf feat(market-profile): naked POC, single prints, profile shape, HVN/LVN, composite profile (B17) (#216)
## B17 Market Profile — five new indicators (493 → 498)

| Indicator | Output | Notes |
|-----------|--------|-------|
| `NakedPoc` | `f64` | most recent untouched point-of-control level |
| `SinglePrints` | `f64` | count of single-print price levels |
| `ProfileShape` | `f64` | b/P/D shape classification as a numeric code |
| `HighLowVolumeNodes` | struct `{hvn, lvn}` | highest/lowest volume nodes |
| `CompositeProfile` | struct `{poc, vah, val}` | multi-session composite volume profile |

### Wiring
- Core structs + full unit tests; all join the existing **Market Profile** family.
- Hand-written Python/Node/WASM bindings (f64 via candle helpers; struct via PyArray2 / `#[napi(object)]` / `Object`+`Reflect::set`).
- Fuzz drives in `indicator_update_candle.rs`; CANDLE_SCALAR + MULTI registry tests + reference tests.
- README counter + `docs/README.md` + `FAMILIES` assert bumped to 498.

### Verify (local, all green)
- `cargo test -p wickra-core --lib`: 4066 · `--doc`: 448
- clippy workspace: clean
- node: 568 · pytest: 938
2026-06-08 04:17:06 +02:00
1330 changed files with 212499 additions and 204 deletions
+27
View File
@@ -1,3 +1,30 @@
# Shell scripts must keep LF line endings so they run on Linux/macOS CI and
# local shells regardless of the committer's platform autocrlf setting.
*.sh text eol=lf
# The cbindgen-generated C header is committed; pin it to LF so its CI drift
# check (regenerate + `git diff`) never trips on a CRLF normalization.
bindings/c/include/wickra.h text eol=lf
# C# sources (including the generated binding) are pinned to LF so the committed
# files stay stable regardless of the committer's autocrlf setting.
*.cs text eol=lf
# Go sources (including the generated binding) are pinned to LF so gofmt's CI
# check never trips on a CRLF checkout on Windows.
*.go text eol=lf
go.mod text eol=lf
go.sum text eol=lf
# Java sources (including the generated binding) are pinned to LF so the
# committed files stay stable regardless of the committer's autocrlf setting.
*.java text eol=lf
# R binding: `R CMD check` requires LF in sources, Makevars and shell scripts.
*.R text eol=lf
*.Rd text eol=lf
bindings/r/configure.win text eol=lf
bindings/r/src/Makevars text eol=lf
bindings/r/src/Makevars.win text eol=lf
bindings/r/src/wickra.c text eol=lf
+2 -2
View File
@@ -30,9 +30,9 @@ assignees: ""
## Environment
- Wickra version:
- Language / binding: <!-- Rust crate / Python / Node / WASM -->
- Language / binding: <!-- Rust crate / Python / Node / WASM / C ABI / C# (.NET) / Go / Java / R -->
- OS and architecture:
- Rust / Python / Node version (If relevant):
- Rust / Python / Node / .NET version (If relevant):
## Additional context
@@ -16,6 +16,11 @@ assignees: []
- [ ] Python (`pip install wickra`)
- [ ] Node.js (`npm install wickra`)
- [ ] WebAssembly
- [ ] C ABI (`bindings/c`)
- [ ] C# / .NET (`Wickra` on NuGet)
- [ ] Go (`bindings/go`)
- [ ] Java (`org.wickra:wickra` on Maven Central)
- [ ] R (`bindings/r`)
- [ ] Docs / examples only
## Environment
@@ -26,7 +31,7 @@ assignees: []
| Binding version | `e.g. python 0.4.2 / node 0.4.2` |
| OS / arch | `e.g. Windows 11 x86_64, Linux glibc` |
| Rust toolchain | `rustc --version` (If building from source) |
| Python / Node version | `python --version` / `node --version` |
| Python / Node / .NET version | `python --version` / `node --version` / `dotnet --version` |
## Minimal reproducer
@@ -25,6 +25,11 @@ assignees: ""
- [ ] Should be exposed in the Python binding
- [ ] Should be exposed in the Node binding
- [ ] Should be exposed in the WASM binding
- [ ] Should be exposed in the C ABI
- [ ] Should be exposed in the C# / .NET binding
- [ ] Should be exposed in the Go binding
- [ ] Should be exposed in the Java binding
- [ ] Should be exposed in the R binding
## Additional context
@@ -13,7 +13,7 @@ assignees: []
## Affected code path
- Indicator / API: `e.g. EMA.update`
- Binding: `Rust / Python / Node / Wasm`
- Binding: `Rust / Python / Node / Wasm / C ABI / C# (.NET) / Go / Java / R`
- Hot loop or one-shot call?
## Versions compared
+1 -1
View File
@@ -33,4 +33,4 @@ import wickra as ta
## Environment (Only if relevant)
- Wickra version: `e.g. 0.4.2`
- Binding: `Rust / Python / Node / Wasm`
- Binding: `Rust / Python / Node / Wasm / C ABI / C# (.NET) / Go / Java / R`
+1 -1
View File
@@ -22,7 +22,7 @@
- [ ] `cargo clippy --workspace --all-targets -- -D warnings` is clean.
- [ ] `cargo test --workspace` passes.
- [ ] New behaviour has tests; bug fixes have a regression test.
- [ ] Public API changes are mirrored in the Python / Node / WASM bindings
- [ ] Public API changes are mirrored in the Python / Node / WASM bindings, and the C ABI + C# + Go + Java + R bindings are regenerated
and their type stubs (If applicable).
- [ ] The relevant page on the [documentation site](https://docs.wickra.org)
and the `README.md` are updated (If applicable). Docs edits go to a
@@ -23,6 +23,11 @@ Please fill in the sections below. Delete any that don't apply.
- [ ] Python binding (`bindings/python`)
- [ ] Node.js binding (`bindings/node`)
- [ ] WebAssembly binding (`bindings/wasm`)
- [ ] C ABI (`bindings/c`)
- [ ] C# / .NET binding (`bindings/csharp`)
- [ ] Go binding (`bindings/go`)
- [ ] Java binding (`bindings/java`)
- [ ] R binding (`bindings/r`)
- [ ] Examples / docs
## Linked issues
+345
View File
@@ -622,6 +622,351 @@ jobs:
working-directory: bindings/node
run: node --test __tests__/
c-abi:
name: C ABI on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
- name: Cache cargo
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 cbindgen
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
with:
tool: cbindgen
- name: Build the C ABI library (cdylib + staticlib)
run: cargo build -p wickra-c --release
- name: Rust unit tests
run: cargo test -p wickra-c
# The generated header is platform-independent, so checking drift on one OS
# is enough — and avoids a spurious CRLF/LF diff on the Windows runner.
- name: Check the committed header is in sync with cbindgen
if: runner.os == 'Linux'
shell: bash
run: |
cbindgen --config bindings/c/cbindgen.toml --crate wickra-c --output bindings/c/include/wickra.h
if ! git diff --quiet -- bindings/c/include/wickra.h; then
echo "::error::bindings/c/include/wickra.h is out of sync — run cbindgen and commit the result"
git --no-pager diff -- bindings/c/include/wickra.h
exit 1
fi
# The real cross-language test: a foreign C consumer links the generated
# header + the compiled library and runs. If this passes on all three OSes,
# every C-capable language can link the same way.
- name: Build and run the C smoke example (CMake + ctest)
shell: bash
run: |
cmake -S examples/c -B examples/c/build
cmake --build examples/c/build --config Release
ctest --test-dir examples/c/build -C Release --output-on-failure
csharp:
name: C# on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
- name: Cache cargo
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
timeout-minutes: 6
# 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
# preinstalled on the GitHub runners, so no setup-dotnet step is needed.
- name: Build the C ABI library
run: cargo build -p wickra-c --release
- name: .NET info
run: dotnet --info
- name: Test the C# binding
run: dotnet test bindings/csharp/Wickra.Tests/Wickra.Tests.csproj -c Release
- name: Build the C# examples
shell: bash
run: |
for d in streaming backtest multi_timeframe parallel_assets \
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze \
fetch_btcusdt live_binance; do
dotnet build "examples/csharp/$d" -c Release
done
# Run only the offline examples (fetch_btcusdt / live_binance need network).
- name: Run the offline C# examples
shell: bash
run: |
for d in streaming backtest multi_timeframe parallel_assets \
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze; do
dotnet run --project "examples/csharp/$d" -c Release --no-build
done
go:
name: Go on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Go is not reliably on PATH on every runner image, so install it
# explicitly. cache: false — the cargo build dominates and the modules
# have no external Go deps worth caching.
- name: Set up Go
id: setup-go
continue-on-error: true
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: "stable"
cache: false
- name: Retry Go setup (CDN flake)
if: steps.setup-go.outcome == 'failure'
shell: bash
run: |
echo "::warning::setup-go failed (likely CDN flake), waiting 30s before retry..."
sleep 30
- name: Set up Go (retry)
if: steps.setup-go.outcome == 'failure'
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: "stable"
cache: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
- name: Cache cargo
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
timeout-minutes: 6
# The binding links against the C ABI hub via cgo; build it first and stage
# the platform library under bindings/go/lib so cgo's LDFLAGS find it. Go is
# preinstalled on the GitHub runners, so no setup-go step is needed.
- name: Build the C ABI library
run: cargo build -p wickra-c --release
- name: Stage the native library
shell: bash
run: |
mkdir -p bindings/go/lib
case "$RUNNER_OS" in
Linux) cp target/release/libwickra.so bindings/go/lib/ ;;
macOS) cp target/release/libwickra.dylib bindings/go/lib/ ;;
Windows) cp target/release/wickra.dll bindings/go/lib/ ;;
esac
- name: Go info
run: go version
- name: Check gofmt
shell: bash
run: |
unformatted="$(gofmt -l bindings/go examples/go)"
if [ -n "$unformatted" ]; then
echo "gofmt needed on:"; echo "$unformatted"; exit 1
fi
- name: Vet and test the Go binding
shell: bash
# On Windows there is no rpath; the loader resolves wickra.dll via PATH.
run: |
export PATH="$PWD/bindings/go/lib:$PATH"
cd bindings/go
go vet ./...
go test ./...
- name: Build the Go examples
shell: bash
run: |
export PATH="$PWD/bindings/go/lib:$PATH"
cd examples/go
go build ./...
# Run only the offline examples (fetch_btcusdt / live_binance need network).
- name: Run the offline Go examples
shell: bash
run: |
export PATH="$PWD/bindings/go/lib:$PATH"
cd examples/go
for d in streaming backtest multi_timeframe parallel_assets \
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze; do
go run "./$d"
done
r:
name: R on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
env:
WICKRA_INCLUDE_DIR: ${{ github.workspace }}/bindings/c/include
WICKRA_LIB_DIR: ${{ github.workspace }}/target/release
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
- name: Cache cargo
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
continue-on-error: true
timeout-minutes: 6
# The binding compiles a thin .Call glue layer against the C ABI hub; build
# the library first. On Windows configure.win bundles a renamed copy
# (wickra_abi.dll) so the package's own wickra.dll does not collide with it.
- name: Build the C ABI library
run: cargo build -p wickra-c --release
- name: Set up R
uses: r-lib/actions/setup-r@a51a8012b0aab7c32ef9d19bf54da93f3254335e # v2
with:
r-version: "release"
use-public-rspm: true
# Use the repos configured by setup-r (use-public-rspm) so Linux installs
# binary packages — building testthat's deps from source is slow and flaky.
- name: Install test dependency
run: Rscript -e 'install.packages("testthat")'
- name: Install and test the R binding
shell: bash
# github.workspace is a backslash path on Windows; configure.win (sh) and
# mingw need forward slashes. On Linux/macOS the rpath points at
# WICKRA_LIB_DIR; export the loader path too as a belt-and-suspenders.
run: |
export WICKRA_INCLUDE_DIR="${WICKRA_INCLUDE_DIR//\\//}"
export WICKRA_LIB_DIR="${WICKRA_LIB_DIR//\\//}"
export LD_LIBRARY_PATH="$WICKRA_LIB_DIR:$LD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH="$WICKRA_LIB_DIR:$DYLD_LIBRARY_PATH"
R CMD INSTALL bindings/r
Rscript -e 'library(testthat); library(wickra); test_dir("bindings/r/tests/testthat", stop_on_failure = TRUE)'
- name: Run the offline R examples
shell: bash
run: |
export WICKRA_LIB_DIR="${WICKRA_LIB_DIR//\\//}"
export LD_LIBRARY_PATH="$WICKRA_LIB_DIR:$LD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH="$WICKRA_LIB_DIR:$DYLD_LIBRARY_PATH"
cd examples/r
for f in streaming backtest multi_timeframe parallel_assets \
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze; do
Rscript "$f.R"
done
# fetch_btcusdt / live_binance need the network (and jsonlite / websocket);
# build-check that they parse without running them.
- name: Parse the network R examples
run: Rscript -e 'invisible(lapply(c("examples/r/fetch_btcusdt.R", "examples/r/live_binance.R"), parse)); cat("network R examples parse OK\n")'
java:
name: Java on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
- name: Cache cargo
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
timeout-minutes: 6
# The binding links the C ABI hub at runtime through the Java FFM API; build
# it first so WickraNative's development fallback finds
# target/release/wickra.{so,dylib,dll}. JDK 22+ is required for the final FFM
# API, so it is installed explicitly (runners ship 17/21).
- name: Build the C ABI library
run: cargo build -p wickra-c --release
- name: Set up JDK 22
id: setup-java
continue-on-error: true
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: temurin
java-version: "22"
cache: maven
- name: Retry JDK setup (CDN flake)
if: steps.setup-java.outcome == 'failure'
shell: bash
run: |
echo "::warning::setup-java failed (likely CDN flake), waiting 30s before retry..."
sleep 30
- name: Set up JDK 22 (retry)
if: steps.setup-java.outcome == 'failure'
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: temurin
java-version: "22"
cache: maven
- name: Java info
run: java -version
# `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.
- name: Test and install the Java binding
run: mvn -B -f bindings/java install
- name: Build the Java examples
run: mvn -B -f examples/java compile
# Run only the offline examples (fetch_btcusdt / live_binance need network).
- name: Run the offline Java examples
shell: bash
run: |
for cls in Streaming Backtest MultiTimeframe ParallelAssets \
StrategyRsiMeanReversion StrategyMacdAdx StrategyBollingerSqueeze; do
mvn -B -q -f examples/java exec:exec -Dexec.mainClass="org.wickra.examples.$cls"
done
# The cross-library benchmark has moved to a dedicated scheduled workflow
# (.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
+211 -2
View File
@@ -569,9 +569,215 @@ jobs:
# the old "publish, then upload provenance" order would have the provenance
# upload rejected once immutability is enabled.
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
# C ABI native libraries (bindings/c) — built per target on a native runner
# (no cross toolchain needed) and attached to the GitHub Release as the
# distribution channel. There is no package registry for the C ABI.
# --------------------------------------------------------------------------
c-abi-build:
name: C ABI library (${{ matrix.target }})
strategy:
fail-fast: false
matrix:
include:
- { host: ubuntu-latest, target: x86_64-unknown-linux-gnu }
- { host: ubuntu-24.04-arm, target: aarch64-unknown-linux-gnu }
- { host: macos-latest, target: x86_64-apple-darwin }
- { host: macos-latest, target: aarch64-apple-darwin }
- { host: windows-latest, target: x86_64-pc-windows-msvc }
- { host: windows-11-arm, target: aarch64-pc-windows-msvc }
runs-on: ${{ matrix.host }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
with:
targets: ${{ matrix.target }}
- 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: Build the C ABI library (cdylib + staticlib)
run: cargo build -p wickra-c --release --target ${{ matrix.target }}
- name: Package header + libraries
shell: bash
run: |
set -e
dir="wickra-c-${{ matrix.target }}"
mkdir -p "$dir/include" "$dir/lib"
cp bindings/c/include/wickra.h bindings/c/include/wickra.hpp "$dir/include/"
for f in libwickra.so libwickra.a libwickra.dylib wickra.dll wickra.dll.lib wickra.lib; do
src="target/${{ matrix.target }}/release/$f"
[ -f "$src" ] && cp "$src" "$dir/lib/"
done
tar -czf "$dir.tar.gz" "$dir"
echo "packaged $dir:"; ls -lR "$dir"
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: c-abi-${{ matrix.target }}
path: wickra-c-${{ matrix.target }}.tar.gz
if-no-files-found: error
# Pack and publish the .NET binding to NuGet. Independent of the GitHub-release
# job so a C# hiccup never blocks the C/C++ asset release. Authentication uses
# NuGet Trusted Publishing (OIDC) — no long-lived API key. The 'wickra-release'
# trusted-publishing policy on nuget.org (owner KingchenC, repo wickra-lib/wickra,
# workflow release.yml) exchanges the GitHub OIDC token for a short-lived key.
csharp-publish:
name: Publish to NuGet
needs: c-abi-build
runs-on: ubuntu-latest
environment: release
permissions:
contents: read
id-token: write # request the GitHub OIDC token for trusted publishing
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download the C ABI native libraries
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: c-abi-*
path: c-abi-artifacts
- name: Stage native libraries into runtimes/<rid>/native
shell: bash
run: |
set -e
declare -A RID=(
[x86_64-unknown-linux-gnu]=linux-x64
[aarch64-unknown-linux-gnu]=linux-arm64
[x86_64-apple-darwin]=osx-x64
[aarch64-apple-darwin]=osx-arm64
[x86_64-pc-windows-msvc]=win-x64
[aarch64-pc-windows-msvc]=win-arm64
)
base=bindings/csharp/Wickra/runtimes
for target in "${!RID[@]}"; do
archive=$(find c-abi-artifacts -name "wickra-c-$target.tar.gz" | head -1)
if [ -z "$archive" ]; then
echo "::error::missing native artifact for $target"; exit 1
fi
tmp=$(mktemp -d); tar -xzf "$archive" -C "$tmp"
dest="$base/${RID[$target]}/native"; mkdir -p "$dest"
for f in libwickra.so libwickra.dylib wickra.dll; do
src=$(find "$tmp" -name "$f" | head -1)
[ -n "$src" ] && cp "$src" "$dest/"
done
echo "staged ${RID[$target]}:"; ls -l "$dest"
done
- name: Pack
shell: bash
run: |
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.
# 'user' is the nuget.org profile name (the package owner), not an email.
- name: NuGet login (OIDC -> temporary API key)
uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0
id: nuget_login
with:
user: KingchenC
# Pass the temporary key through the environment (not string-interpolated
# into the script) so it cannot be parsed as shell — avoids template injection.
- name: Push to NuGet
shell: bash
env:
NUGET_API_KEY: ${{ steps.nuget_login.outputs.NUGET_API_KEY }}
run: |
dotnet nuget push "nupkg/*.nupkg" --api-key "$NUGET_API_KEY" \
--source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Upload the NuGet package as a build artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nuget-package
path: nupkg/*.nupkg
if-no-files-found: error
# Publish the Java binding to Maven Central. Independent of the GitHub-release
# job so a Java hiccup never blocks the C/C++ asset release. The Maven Central
# namespace (org.wickra) is verified; authentication uses the Sonatype Central
# Portal token (CENTRAL_USERNAME / CENTRAL_PASSWORD) and artifacts are signed
# with the GPG key (GPG_PRIVATE_KEY / GPG_PASSPHRASE). The pom version must
# match the release tag (kept in sync by the version-bump checklist).
java-publish:
name: Publish to Maven Central
needs: c-abi-build
runs-on: ubuntu-latest
environment: release
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download the C ABI native libraries
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: c-abi-*
path: c-abi-artifacts
- name: Stage native libraries into resources/native/<os>-<arch>
shell: bash
run: |
set -e
declare -A PLAT=(
[x86_64-unknown-linux-gnu]=linux-x64
[aarch64-unknown-linux-gnu]=linux-arm64
[x86_64-apple-darwin]=osx-x64
[aarch64-apple-darwin]=osx-arm64
[x86_64-pc-windows-msvc]=win-x64
[aarch64-pc-windows-msvc]=win-arm64
)
base=bindings/java/src/main/resources/native
for target in "${!PLAT[@]}"; do
archive=$(find c-abi-artifacts -name "wickra-c-$target.tar.gz" | head -1)
if [ -z "$archive" ]; then
echo "::error::missing native artifact for $target"; exit 1
fi
tmp=$(mktemp -d); tar -xzf "$archive" -C "$tmp"
dest="$base/${PLAT[$target]}"; mkdir -p "$dest"
for f in libwickra.so libwickra.dylib wickra.dll; do
src=$(find "$tmp" -name "$f" | head -1)
[ -n "$src" ] && cp "$src" "$dest/"
done
echo "staged ${PLAT[$target]}:"; ls -l "$dest"
done
# setup-java writes a settings.xml with the 'central' server credentials
# (mapped from the env vars below) and imports the GPG signing key.
- name: Set up JDK 22 + Maven Central credentials + GPG
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: temurin
java-version: "22"
server-id: central
server-username: CENTRAL_USERNAME
server-password: CENTRAL_PASSWORD
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-passphrase: GPG_PASSPHRASE
- name: Deploy to Maven Central
env:
CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: mvn -B -f bindings/java -Prelease deploy -DskipTests
github-release:
name: Attach assets to the draft GitHub Release
needs: [cargo-publish, python-publish, node-publish, wasm-publish]
needs: [cargo-publish, python-publish, node-publish, wasm-publish, c-abi-build]
runs-on: ubuntu-latest
permissions:
contents: write
@@ -644,7 +850,7 @@ jobs:
# the provenance bundle is attached (P24, immutability-ready).
draft: true
body: |
Wickra ${{ github.ref_name }} — streaming-first technical indicators across 4 language registries.
Wickra ${{ github.ref_name }} — streaming-first technical indicators across 4 language registries plus a C ABI.
### Install
@@ -665,6 +871,9 @@ jobs:
darwin-arm64, win32-x64-msvc)
- `wickra-*.tgz` — npm-pack tarballs (main package + per-platform subpackages + WASM)
- `*.crate` — cargo source crates (wickra-core, wickra-data, wickra)
- `wickra-c-<target>.tar.gz` — C ABI: `include/wickra.h` + `wickra.hpp`
and the cdylib/staticlib per target (linux/macos/windows × x64/arm64),
the hub for C / C++ / Go / C# / Java / R
### Auto-generated changelog
+16 -9
View File
@@ -9,7 +9,7 @@ name: Sync indicator count
# 2. GitHub repo "About" description — synced on push to main / v* tag
# 3. Docs site: index.md / overview.md / Indicators-Overview.md
# (wickra-lib/wickra-docs) — synced on push to main / v* tag*
# 4. Marketing site count (wickra-lib/webpage: index.md /
# 4. Marketing site count (wickra-lib/webpage: index.md / about.md /
# .vitepress/config.ts) — push to main / v* tag*
# 5. org profile README count (wickra-lib/.github, profile/README.md)
# — synced on push to main / v* tag*
@@ -42,10 +42,10 @@ name: Sync indicator count
# single source of truth for what the bindings reach.
#
# Design: on PRs this workflow is a READ-ONLY check. The indicator wiring
# (ScriptHelpers/_common.py wire_readme_counter) bumps both README.md and
# docs/README.md inside the author's code commit, so the counter is already
# correct by the time CI runs. If it is not, the check below fails loud and
# asks the author to re-run the wiring — it never pushes a fix-up commit.
# bumps both README.md and docs/README.md inside the author's code commit, so
# the counter is already correct by the time CI runs. If it is not, the check
# below fails loud and asks the author to re-run the wiring — it never pushes a
# fix-up commit.
#
# (An earlier version pushed a GITHUB_TOKEN "sync indicator count" commit to
# the PR head. Because GITHUB_TOKEN pushes trigger no workflows, that commit
@@ -86,10 +86,17 @@ jobs:
# merge ref) so the counter check validates exactly what will land. On
# push events we check out the default ref. No push is made, so a shallow
# checkout is enough.
#
# Check out by head SHA, not head ref (branch name): a fast `gh pr merge
# --squash --delete-branch` deletes the head branch the moment the PR
# merges, often before this queued read-only check reaches its checkout.
# Fetching the now-gone `refs/heads/<branch>` then fails the run (exit 1).
# The head SHA stays reachable via `refs/pull/N/head` after the branch is
# gone, so the checkout — and the run — survives an instant merge.
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref }}
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
repository: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
- name: Count indicators
@@ -149,7 +156,7 @@ jobs:
# actually live (Cloudflare Pages, P8.1); merging this PR is therefore
# gated on the domain resolving, otherwise the About link would 404.
homepage="https://docs.wickra.org"
desc="Streaming-first technical indicators with a Rust core and Python, Node.js, and WebAssembly bindings. ${n} indicators, O(1) per-tick updates, no system dependencies. Drop-in TA-Lib replacement."
desc="Streaming-first technical indicators with a Rust core and Python, Node.js, WebAssembly, C ABI, .NET, Go, Java, and R bindings. ${n} indicators, O(1) per-tick updates, no system dependencies. Drop-in TA-Lib replacement."
# Enforce the homepage unconditionally — it is a constant, so this both
# corrects the stale kingchenc URL and self-heals any future drift.
# Same Administration-write permission as --description (no extra scope).
@@ -366,14 +373,14 @@ jobs:
exit 0
fi
cd webpage-count
sed -i -E "s/[0-9]+ (streaming-first )?indicators/${n} \1indicators/g" index.md .vitepress/config.ts
sed -i -E "s/[0-9]+ (streaming-first )?indicators/${n} \1indicators/g" index.md about.md .vitepress/config.ts
if git diff --quiet; then
echo "Webpage indicator count unchanged."
exit 0
fi
git config user.name "wickra-bot"
git config user.email "wickra-bot@users.noreply.github.com"
git add index.md .vitepress/config.ts
git add index.md about.md .vitepress/config.ts
git commit -m "chore: sync indicator count to ${n}"
if ! git push 2>/dev/null; then
echo "::warning::push to wickra-lib/webpage failed — ABOUT_SYNC_TOKEN likely lacks write (findings P10.0a)."
+22 -8
View File
@@ -27,16 +27,29 @@ or replace lives behind a separate crate boundary.
│ no I/O, no deps │ │ optional features │
└──────────────────────┘ └────────────────────┘
(every binding wraps the same core)
┌────────────┴───────────┬─────────────────────┐
│ │ │
┌──▼──────┐ ┌───────▼──────┐ ┌───────▼────────┐
Python │ │ Node │ │ WASM
│ (PyO3) │ │ (napi-rs) │ │ (wasm-bindgen) │
└─────────┘ └──────────────┘ └────────────────┘
every binding wraps the same core
┌────────────┼────────────┬────────────────┐
│ │ │ │
┌──▼───────┐ ┌──▼───────┐ ┌──▼───────────┐ ┌──▼──────────────────┐
│ Python │ │ Node │ │ WASM │ │ C ABI (cbindgen) │
(PyO3) │ │ (napi-rs)│ │(wasm-bindgen)│ │ cdylib + header
└──────────┘ └──────────┘ └──────────────┘ └─────────┬───────────┘
│ linked by
┌──────────▼──────────┐
│ C · C++ · C# · Go │
│ · Java · R │
└─────────────────────┘
```
Python, Node and WASM are *native* Rust bindings (PyO3 / napi-rs /
wasm-bindgen). The C ABI is the *hub* every other C-capable language links
against: it builds to a `cdylib`/`staticlib` plus a generated `wickra.h`, and
downstream languages link that one artifact rather than each re-wrapping the
core. C and C++ link it directly; the **C# / .NET** binding (`bindings/csharp`,
on NuGet), the **Go** binding (`bindings/go`, cgo), the **R** binding
(`bindings/r`, `.Call`) and the **Java** binding (`bindings/java`, the Java FFM
API / Panama, on Maven Central) are all generated from `wickra.h`.
| Crate | Path | What it owns | Public deps |
|---|---|---|---|
| `wickra-core` | `crates/wickra-core` | every indicator, the `Indicator` trait, `BatchExt`, `Candle`/`Tick` types, `Error` | `thiserror`, `rayon` (parallel batch) |
@@ -45,6 +58,7 @@ or replace lives behind a separate crate boundary.
| `wickra-python` | `bindings/python` | `_wickra` PyO3 module + Python package | `pyo3`, `numpy`, depends on `wickra-core` |
| `wickra-node` | `bindings/node` | NAPI-RS native binding | `napi`, depends on `wickra-core` |
| `wickra-wasm` | `bindings/wasm` | WebAssembly binding | `wasm-bindgen`, depends on `wickra-core` |
| `wickra-c` | `bindings/c` | C ABI hub — `cdylib`/`staticlib` + generated `wickra.h` (cbindgen) | depends on `wickra-core` |
| `wickra-examples` | `examples/rust` | runnable binary examples | depends on `wickra`, `wickra-data` |
The `fuzz/` directory is **excluded** from the workspace (it has its own
+82 -2
View File
@@ -5,7 +5,79 @@ All notable changes to Wickra are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.7.9] - 2026-06-09
### Added
- **Java binding (`bindings/java`)** — a Java binding reaching the C ABI hub
through the Java Foreign Function & Memory API (Panama, `java.lang.foreign`,
final in Java 22) rather than JNI or jextract, exposing all 514 indicators as
idiomatic `AutoCloseable` classes. The downcall handles, per-indicator
wrappers and output records are generated from `wickra.h`; the opaque handle is
a `MemorySegment` freed by a `java.lang.ref.Cleaner` action. Ships a full
example suite mirroring the C, C#, Go and R examples; published to Maven
Central as `org.wickra:wickra`.
## [0.7.8] - 2026-06-09
### Added
- **R binding (`bindings/r`)** — an R package reaching the C ABI hub through R's
native `.Call` interface, exposing all 514 indicators as constructors that
return a `wickra_indicator` object with `update`/`batch`/`reset` methods. The
C glue and R wrappers are generated from `wickra.h`; the native handle is freed
by a registered finalizer. Ships a full example suite mirroring the C, C# and
Go examples; distributed for r-universe / source install.
## [0.7.7] - 2026-06-09
### Added
- **Go binding (`bindings/go`)** — a cgo binding over the C ABI hub exposing all
514 indicators as idiomatic types with `New<Indicator>` constructors and
`Update`/`Batch`/`Reset`/`Close` methods, generated from `wickra.h`. Handles are
freed by `Close()` with a `runtime.SetFinalizer` backstop. Ships a full example
suite mirroring the C and C# examples; distributed as a subdirectory module
(`go get github.com/wickra-lib/wickra/bindings/go`).
## [0.7.6] - 2026-06-09
### Added
- **C# / .NET binding (`bindings/csharp`)** — the first language stecker on the
C ABI hub. Exposes all 514 indicators as idiomatic `IDisposable` classes via
`[LibraryImport]` source-generated P/Invoke, generated from `wickra.h`. Ships
on NuGet as `Wickra` with prebuilt native libraries for six target triples
(win/linux/osx × x64/arm64), plus a full example suite mirroring the C examples.
## [0.7.5] - 2026-06-09
### Added
- **C ABI (`bindings/c`)** — a `cdylib` + `staticlib` plus a generated
`include/wickra.h` exposing all 514 indicators and 10 bar builders over an
opaque-handle C ABI: the hub any C-capable language (C, C++, Go, C#, Java, R)
links against, complementing the native Python/Node/WASM bindings. Ships a
full example suite (streaming, backtest, multi-timeframe, OpenMP parallel
fan-out, three educational strategies, and Binance fetch/live over `curl`)
mirroring the other bindings, plus an optional `wickra.hpp` C++ RAII wrapper.
## [0.7.4] - 2026-06-08
- **Three-Line Break** — Three-line-break bars (reversal needs N-line break) (`THREE_LINE_BREAK_BARS`).
- **Run** — Run bars (consecutive same-direction tick runs) (`RUN_BARS`).
- **Imbalance** — Imbalance bars (tick-rule signed imbalance threshold) (`IMBALANCE_BARS`).
- **Dollar** — Dollar bars (fixed traded value per bar, Lopez de Prado) (`DOLLAR_BARS`).
- **Volume** — Volume bars (fixed traded volume per bar) (`VOLUME_BARS`).
- **Tick** — Tick bars (fixed candle count per bar) (`TICK_BARS`).
- **Range** — Range bars (fixed price-range bricks) (`RANGE_BARS`).
## [0.7.3] - 2026-06-08
- **M2Measure** — M2 measure (Modigliani; Sharpe expressed in benchmark return units) (`M2Measure`).
- **UpsidePotentialRatio** — Upside Potential Ratio (upside mean over downside deviation) (`UpsidePotentialRatio`).
- **GainToPainRatio** — Gain-to-Pain Ratio (sum of returns over sum of losses) (`GainToPainRatio`).
- **CommonSenseRatio** — Common Sense Ratio (tail ratio times gain-to-pain) (`CommonSenseRatio`).
- **KRatio** — K-Ratio (Kestner; equity-curve slope over its standard error) (`KRatio`).
- **TailRatio** — Tail Ratio (95th over absolute 5th return percentile) (`TailRatio`).
- **MartinRatio** — Martin Ratio (Ulcer Performance Index; return over RMS drawdown) (`MartinRatio`).
- **BurkeRatio** — Burke Ratio (return over root-sum-squared drawdowns) (`BurkeRatio`).
- **SterlingRatio** — Sterling Ratio (mean return over average drawdown) (`SterlingRatio`).
## [0.7.2] - 2026-06-08
- **Composite Profile** — multi-session composite volume profile exposing POC, VAH and VAL (`CompositeProfile`).
- **High/Low Volume Nodes** — highest- and lowest-volume price nodes in the profile (`HighLowVolumeNodes`).
- **Profile Shape** — profile shape classification (b/P/D normal) as a numeric code (`ProfileShape`).
- **Single Prints** — count of single-print (low-activity) price levels in the profile (`SinglePrints`).
- **Naked POC** — most recent untouched (naked) point of control level (`NakedPoc`).
## [0.7.1] - 2026-06-08
- **Open-Interest Momentum** — rate-of-change of open interest over a rolling window (`OpenInterestMomentum`).
@@ -1389,7 +1461,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
optional Binance live feed.
- Bindings for Python, Node.js, and WebAssembly.
[Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.7.1...HEAD
[Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.7.9...HEAD
[0.7.9]: https://github.com/wickra-lib/wickra/compare/v0.7.8...v0.7.9
[0.7.8]: https://github.com/wickra-lib/wickra/compare/v0.7.7...v0.7.8
[0.7.7]: https://github.com/wickra-lib/wickra/compare/v0.7.6...v0.7.7
[0.7.6]: https://github.com/wickra-lib/wickra/compare/v0.7.5...v0.7.6
[0.7.5]: https://github.com/wickra-lib/wickra/compare/v0.7.4...v0.7.5
[0.7.4]: https://github.com/wickra-lib/wickra/compare/v0.7.3...v0.7.4
[0.7.3]: https://github.com/wickra-lib/wickra/compare/v0.7.2...v0.7.3
[0.7.2]: https://github.com/wickra-lib/wickra/compare/v0.7.1...v0.7.2
[0.7.1]: https://github.com/wickra-lib/wickra/compare/v0.7.0...v0.7.1
[0.7.0]: https://github.com/wickra-lib/wickra/compare/v0.6.9...v0.7.0
[0.6.9]: https://github.com/wickra-lib/wickra/compare/v0.6.8...v0.6.9
+15 -1
View File
@@ -21,6 +21,11 @@ licensed as above, without any additional terms or conditions.
| `bindings/python` | PyO3 bindings (`wickra` on PyPI). |
| `bindings/node` | napi-rs bindings (`wickra` on npm). |
| `bindings/wasm` | wasm-bindgen bindings (`wickra-wasm` on npm). |
| `bindings/c` | C ABI — `cdylib` + `staticlib` + generated `include/wickra.h`. The hub for C / C++ and any C-capable language. |
| `bindings/csharp` | .NET binding over the C ABI (`Wickra` on NuGet) — `[LibraryImport]` P/Invoke generated from `wickra.h`. |
| `bindings/go` | Go binding over the C ABI via cgo (module tag `bindings/go/vX.Y.Z`) — wrappers generated from `wickra.h`. |
| `bindings/r` | R binding over the C ABI via `.Call` (R package) — C glue + R wrappers generated from `wickra.h`. |
| `bindings/java` | Java binding over the C ABI via the FFM API (Panama, Maven Central) — wrappers generated from `wickra.h`. |
| `examples/` | Runnable examples. |
| `docs/` | Pointer to the documentation site (docs.wickra.org); the docs live in the `wickra-lib/wickra-docs` repo. |
@@ -102,7 +107,16 @@ installed. Dependabot also keeps the `.github/requirements` pins current.
- **Streaming parity.** An indicator's `batch` output must equal the sequence
of `update` calls.
- **Bindings.** A change to a public indicator API must be mirrored across the
Python, Node, and WASM bindings, including their type stubs / `.d.ts`.
Python, Node, and WASM bindings, including their type stubs / `.d.ts`. The C ABI
(`bindings/c`) is generated from the core, so regenerate it from the core and
commit `src/lib.rs` + `include/wickra.h`. The C# binding (`bindings/csharp`) is
generated from `wickra.h`, so regenerate and commit its `Generated/*.g.cs` too.
The Go binding (`bindings/go`) is likewise generated from `wickra.h`, so
regenerate and commit `indicators_gen.go` (`gofmt`-clean). The R binding
(`bindings/r`) is generated from `wickra.h` too, so regenerate and commit
`src/wickra.c` + `R/indicators.R`. The Java binding (`bindings/java`) is
generated from `wickra.h` as well, so regenerate and commit its
`src/main/java/org/wickra/*.java`.
- **Docs.** Update the relevant page on the
[documentation site](https://docs.wickra.org) and the
`README.md` when behaviour or the public API changes. The docs live in
Generated
+15 -8
View File
@@ -1944,7 +1944,7 @@ dependencies = [
[[package]]
name = "wickra"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"approx",
"criterion",
@@ -1955,7 +1955,7 @@ dependencies = [
[[package]]
name = "wickra-bench"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"criterion",
"kand",
@@ -1965,9 +1965,16 @@ dependencies = [
"yata",
]
[[package]]
name = "wickra-c"
version = "0.7.9"
dependencies = [
"wickra-core",
]
[[package]]
name = "wickra-core"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"approx",
"proptest",
@@ -1977,7 +1984,7 @@ dependencies = [
[[package]]
name = "wickra-data"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"approx",
"csv",
@@ -1994,7 +2001,7 @@ dependencies = [
[[package]]
name = "wickra-examples"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"serde_json",
"tokio",
@@ -2004,7 +2011,7 @@ dependencies = [
[[package]]
name = "wickra-node"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"napi",
"napi-build",
@@ -2014,7 +2021,7 @@ dependencies = [
[[package]]
name = "wickra-python"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"numpy",
"pyo3",
@@ -2023,7 +2030,7 @@ dependencies = [
[[package]]
name = "wickra-wasm"
version = "0.7.1"
version = "0.7.9"
dependencies = [
"console_error_panic_hook",
"js-sys",
+3 -2
View File
@@ -7,13 +7,14 @@ members = [
"bindings/python",
"bindings/wasm",
"bindings/node",
"bindings/c",
"examples/rust",
"crates/wickra-bench",
]
exclude = ["fuzz"]
[workspace.package]
version = "0.7.1"
version = "0.7.9"
authors = ["kingchenc <support@wickra.org>"]
edition = "2021"
rust-version = "1.86"
@@ -25,7 +26,7 @@ keywords = ["finance", "trading", "indicators", "technical-analysis", "ta"]
categories = ["finance", "mathematics", "science"]
[workspace.dependencies]
wickra-core = { path = "crates/wickra-core", version = "0.7.1" }
wickra-core = { path = "crates/wickra-core", version = "0.7.9" }
thiserror = "2"
rayon = "1.10"
+83 -33
View File
@@ -1,25 +1,27 @@
<p align="center">
<a href="https://wickra.org"><img src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/wickra-banner.webp?v=493" alt="Wickra — streaming-first technical indicators" width="100%"></a>
<a href="https://wickra.org"><img src="https://raw.githubusercontent.com/wickra-lib/.github/main/profile/wickra-banner.webp?v=514" alt="Wickra — streaming-first technical indicators" width="100%"></a>
</p>
[![CI](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml/badge.svg)](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
[![CodeQL](https://github.com/wickra-lib/wickra/actions/workflows/codeql.yml/badge.svg)](https://github.com/wickra-lib/wickra/actions/workflows/codeql.yml)
[![codecov](https://codecov.io/gh/wickra-lib/wickra/branch/main/graph/badge.svg)](https://codecov.io/gh/wickra-lib/wickra)
[![GitHub release](https://img.shields.io/github/v/release/wickra-lib/wickra?logo=github&color=green)](https://github.com/wickra-lib/wickra/releases/latest)
[![crates.io](https://img.shields.io/crates/v/wickra.svg?logo=rust&color=orange)](https://crates.io/crates/wickra)
[![PyPI](https://img.shields.io/pypi/v/wickra.svg?logo=pypi&color=blue)](https://pypi.org/project/wickra/)
[![npm](https://img.shields.io/npm/v/wickra.svg?logo=npm&color=red)](https://www.npmjs.com/package/wickra)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue)](#license)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/wickra-lib/wickra/badge)](https://scorecard.dev/viewer/?uri=github.com/wickra-lib/wickra)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13094/badge)](https://www.bestpractices.dev/projects/13094)
[![Build provenance](https://img.shields.io/badge/provenance-attested-brightgreen?logo=github)](https://github.com/wickra-lib/wickra/attestations)
[![Docs](https://img.shields.io/badge/docs-docs.wickra.org-0ea5e9?logo=readthedocs&logoColor=white)](https://docs.wickra.org)
[![CI](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/ci.svg)](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
[![CodeQL](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/codeql.svg)](https://github.com/wickra-lib/wickra/actions/workflows/codeql.yml)
[![codecov](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/codecov.svg)](https://codecov.io/gh/wickra-lib/wickra)
[![GitHub release](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/release.svg)](https://github.com/wickra-lib/wickra/releases/latest)
[![crates.io](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/crates.svg)](https://crates.io/crates/wickra)
[![PyPI](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/pypi.svg)](https://pypi.org/project/wickra/)
[![npm](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/npm.svg)](https://www.npmjs.com/package/wickra)
[![NuGet](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/nuget.svg)](https://www.nuget.org/packages/Wickra)
[![License: MIT OR Apache-2.0](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/license.svg)](#license)
[![OpenSSF Scorecard](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/scorecard.svg)](https://scorecard.dev/viewer/?uri=github.com/wickra-lib/wickra)
[![OpenSSF Best Practices](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/best-practices.svg)](https://www.bestpractices.dev/projects/13094)
[![Build provenance](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/provenance.svg)](https://github.com/wickra-lib/wickra/attestations)
[![Docs](https://raw.githubusercontent.com/wickra-lib/.github/main/profile/badges/docs.svg)](https://docs.wickra.org)
**Streaming-first technical indicators. Install with `pip install wickra` — no system dependencies.**
Wickra is a multi-language technical-analysis library with a Rust core and
bindings for Python, Node.js, and WebAssembly. Every indicator is a state
machine that updates in O(1) per new data point, so live trading bots and
native bindings for Python, Node.js and WebAssembly, plus a C ABI that C, C++,
C# / .NET, Go, Java, R and any other C-capable language links against. Every indicator is a
state machine that updates in O(1) per new data point, so live trading bots and
historical backtests share the exact same implementation.
```python
@@ -46,9 +48,13 @@ Full documentation lives at **[docs.wickra.org](https://docs.wickra.org)**:
- **Quickstarts** — [Rust](https://docs.wickra.org/Quickstart-Rust),
[Python](https://docs.wickra.org/Quickstart-Python),
[Node](https://docs.wickra.org/Quickstart-Node),
[WASM](https://docs.wickra.org/Quickstart-WASM).
[WASM](https://docs.wickra.org/Quickstart-WASM),
[C](https://docs.wickra.org/Quickstart-C),
[C#](https://docs.wickra.org/Quickstart-CSharp),
[Go](https://docs.wickra.org/Quickstart-Go),
[R](https://docs.wickra.org/Quickstart-R).
- **Indicators** — a per-indicator deep dive (formula, parameters, warmup) for
every one of the 493 indicators; start at the
every one of the 514 indicators; start at the
[indicators overview](https://docs.wickra.org/Indicators-Overview).
- **Reference** — [warmup periods](https://docs.wickra.org/Warmup-Periods),
[streaming vs batch](https://docs.wickra.org/Streaming-vs-Batch),
@@ -66,18 +72,19 @@ an afterthought — **live, tick-by-tick data** — without giving up the breadt
a full batch library, and without making you reimplement your indicators four
times to get there.
- **The biggest streaming-native catalogue, period.** 493 indicators across 24
- **The biggest streaming-native catalogue, period.** 514 indicators across 24
families — candlesticks, harmonic & chart patterns, market profile, market
breadth, Renko/Kagi/Point&Figure bars, Ehlers DSP cycles, risk/performance
metrics — every single one updating in **O(1) per tick**. TA-Lib ships ~150 and
none of them stream.
- **One Rust core, four first-class targets.** Native **Python · Node.js ·
WebAssembly · Rust** — identical math, identical results, zero per-language
reimplementation and zero GIL bottleneck.
- **One Rust core, five first-class targets.** Native **Python · Node.js ·
WebAssembly · Rust** plus a **C ABI** for C / C++, C# / .NET, Go, Java, R and any other C-capable language
identical math, identical results, zero per-language reimplementation and zero
GIL bottleneck.
- **Correct by construction, not by hope.** Every `update` validates its input,
runs a real warmup, and returns an `Option` so a single bad tick can't silently
poison state. `batch == streaming` is **bit-exact, fuzzed and 100 %-line-covered
for all 493 indicators**.
for all 514 indicators**.
- **Orders of magnitude faster where it counts.** In streaming Wickra is **1156×**
faster than the only other incremental peer and **thousands of times** faster
than recompute-on-every-tick libraries. On batch it wins several rows outright
@@ -95,7 +102,8 @@ Every other library forces one of those compromises. Wickra doesn't:
| Library | Install | Streaming | Languages | Indicators | Active |
|------------------|-------------|-------------|-----------------------------|-----------:|--------|
| **★&nbsp;Wickra**| **clean** | **yes, O(1)** | **Python · Node · WASM · Rust** | **493** | **yes** |
| **★&nbsp;Wickra**| **clean** | **yes, O(1)** | **Rust · Python · Node · WASM** | **514** | **yes** |
| | | | **C · C# · Go · Java · R** | | |
| kand | clean | yes | Python · WASM · Rust | ~60 | yes |
| ta-rs | clean | yes | Rust only | ~30 | stale |
| yata | clean | partial | Rust only | ~35 | yes |
@@ -128,7 +136,7 @@ Full tables (Rust + Python, streaming + batch) and how to reproduce them live in
## Indicators
493 streaming-first indicators across twenty-four families. Every one passes the
514 streaming-first indicators across twenty-four families. Every one passes the
`batch == streaming` equivalence test, reference-value tests, and reset
semantics tests. Each has a per-indicator deep dive (formula, parameters,
warmup) at [docs.wickra.org](https://docs.wickra.org/Indicators-Overview).
@@ -148,14 +156,14 @@ warmup) at [docs.wickra.org](https://docs.wickra.org/Indicators-Overview).
| Pivots & S/R | Classic Pivots, Fibonacci Pivots, Camarilla, Woodie Pivots, DeMark Pivots, Williams Fractals, ZigZag, Central Pivot Range, Murrey Math Lines, Andrews Pitchfork, Volume-Weighted Support/Resistance, Pivot Reversal |
| DeMark | TD Setup, TD Sequential, TD DeMarker, TD REI, TD Pressure, TD Combo, TD Countdown, TD Lines, TD Range Projection, TD Differential, TD Open, TD Risk Level, TD Camouflage, TD Clop, TD Clopwin, TD Propulsion, TD Trap, TD D-Wave, TD Moving Averages |
| Ichimoku & Charts | Ichimoku Kinko Hyo (Tenkan, Kijun, Senkou A/B, Chikou), Heikin-Ashi, Heikin-Ashi Oscillator, Three Line Break, Smoothed Heikin-Ashi, Equivolume, CandleVolume |
| Alt-Chart Bars | Renko (box-size bricks), Kagi (reversal-amount lines), Point & Figure (X/O columns) |
| Alt-Chart Bars | Renko (box-size bricks), Kagi (reversal-amount lines), Point & Figure (X/O columns), Range, Tick, Volume, Dollar, Imbalance, Run, Three-Line Break |
| Candlestick Patterns | Doji, Hammer, Inverted Hammer, Hanging Man, Shooting Star, Engulfing, Harami, Morning/Evening Star, Three White Soldiers/Black Crows, Piercing Line/Dark Cloud Cover, Marubozu, Tweezer, Spinning Top, Three Inside Up/Down, Three Outside Up/Down, Two Crows, Upside Gap Two Crows, Identical Three Crows, Three Line Strike, Three Stars in the South, Abandoned Baby, Advance Block, Belt-hold, Breakaway, Counterattack, Doji Star, Dragonfly Doji, Gravestone Doji, Long-Legged Doji, Rickshaw Man, Evening Doji Star, Morning Doji Star, Gap Side-by-Side White, High-Wave, Hikkake, Modified Hikkake, Homing Pigeon, On-Neck, In-Neck, Thrusting, Separating Lines, Kicking, Kicking by Length, Ladder Bottom, Mat Hold, Matching Low, Long Line, Short Line, Rising Three Methods, Falling Three Methods, Upside Gap Three Methods, Downside Gap Three Methods, Stalled Pattern, Stick Sandwich, Takuri, Closing Marubozu, Opening Marubozu, Tasuki Gap, Unique Three River, Concealing Baby Swallow, Tristar, Harami Cross, Tower Top/Bottom, Dumpling Top, New Price Lines, Frying Pan Bottom |
| Chart Patterns | Double Top / Bottom, Triple Top / Bottom, Head and Shoulders, Triangle (asc/desc/sym), Wedge (rising/falling), Flag / Pennant, Rectangle / Range, Cup and Handle |
| Harmonic Patterns | AB=CD, Gartley, Butterfly, Bat, Crab, Shark, Cypher, Three Drives |
| Fibonacci | Fibonacci Retracement, Fibonacci Extension, Fibonacci Projection, Auto-Fibonacci, Golden Pocket, Fibonacci Confluence, Fibonacci Fan, Fibonacci Arcs, Fibonacci Channel, Fibonacci Time Zones |
| Microstructure | Order-Book Imbalance (Top-1 / Top-N / Full), Microprice, Quoted Spread, Depth Slope, Signed Volume, Cumulative Volume Delta, Trade Imbalance, Effective Spread, Realized Spread, Kyle's Lambda, Footprint, Order Flow Imbalance, VPIN, Amihud Illiquidity, Roll Measure, Trade-Sign Autocorrelation, Hasbrouck Information Share |
| Derivatives | Funding Rate, Funding Rate Mean, Funding Rate Z-Score, Funding Basis, Open-Interest Delta, OI / Price Divergence, OI-Weighted Price, Long/Short Ratio, Taker Buy/Sell Ratio, Liquidation Features, Term-Structure Basis, Calendar Spread, Estimated Leverage Ratio, OI-to-Volume Ratio, Perpetual Premium Index, Funding-Implied APR, Open-Interest Momentum |
| Market Profile | Value Area (POC / VAH / VAL), Volume Profile (histogram), TPO Profile, Initial Balance, Opening Range |
| Market Profile | Value Area (POC / VAH / VAL), Volume Profile (histogram), TPO Profile, Initial Balance, Opening Range, Naked POC, Single Prints, Profile Shape, High/Low Volume Nodes, Composite Profile |
| Market Breadth | Advance/Decline Line, Advance/Decline Ratio, Advance/Decline Volume Line, McClellan Oscillator, McClellan Summation Index, TRIN / Arms Index, Breadth Thrust, New Highs - New Lows, High-Low Index, Percent Above Moving Average, Up/Down Volume Ratio, Bullish Percent Index, Cumulative Volume Index, Absolute Breadth Index, TICK Index |
| Risk / Performance | Sharpe Ratio, Sortino Ratio, Calmar Ratio, Omega Ratio, Max Drawdown, Average Drawdown, Drawdown Duration, Pain Index, Value at Risk, Conditional Value at Risk (CVaR), Profit Factor, Gain/Loss Ratio, Recovery Factor, Kelly Criterion, Treynor Ratio, Information Ratio, Alpha (Jensen) |
| Seasonality & Session | Session VWAP, Session High/Low, Session Range, Average Daily Range, Overnight Gap, Overnight/Intraday Return, Turn-of-Month, Seasonal Z-Score, Time-of-Day Return Profile, Day-of-Week Profile, Intraday Volatility Profile, Volume-by-Time Profile |
@@ -166,8 +174,9 @@ as one column each. `Doji` is direction-less by default (`+1.0` / `0.0`);
construct it in signed mode (`Doji::new().signed()`, `Doji(signed=True)`,
`new Doji(true)`) for a dragonfly / gravestone `±1` reading.
Adding a new indicator means implementing one trait in Rust; all four bindings
inherit it automatically.
Adding a new indicator means implementing one trait in Rust; every binding
inherits it automatically (the C ABI — and the C#, Go, Java and R bindings generated from
it — regenerate from the core).
## Languages
@@ -177,12 +186,18 @@ inherit it automatically.
| Node.js (napi-rs) | `npm install wickra` | `examples/node/backtest.js` |
| Browser / WASM | `npm install wickra-wasm` | `examples/wasm/index.html` |
| Rust | `cargo add wickra` | `examples/rust/src/bin/backtest.rs` |
| C / C++ (C ABI) | header + library, see [`bindings/c`](bindings/c) | `examples/c/streaming.c` |
| C# / .NET (C ABI) | `dotnet add package Wickra`, see [`bindings/csharp`](bindings/csharp) | `examples/csharp/streaming` |
| Go (cgo, C ABI) | `go get github.com/wickra-lib/wickra/bindings/go`, see [`bindings/go`](bindings/go) | `examples/go/streaming` |
| Java (FFM, C ABI) | Maven Central `org.wickra:wickra`, see [`bindings/java`](bindings/java) | `examples/java` (`Streaming`) |
| R (`.Call`, C ABI) | `R CMD INSTALL bindings/r`, see [`bindings/r`](bindings/r) | `examples/r/streaming.R` |
Each binding ships several runnable examples (streaming, backtest, live feed);
[`examples/README.md`](examples/README.md) is the full cross-language index.
The wickra-core crate is `unsafe`-forbidden, so every binding inherits a
memory-safe implementation.
The wickra-core crate is `unsafe`-forbidden, so the native bindings are
memory-safe end to end. The C ABI runs the same safe core; only its thin FFI
boundary uses `unsafe`, and the caller owns handle lifetimes (`_new` / `_free`).
## Rust API
@@ -237,20 +252,30 @@ A Python live-trading example using the public `websockets` package lives at
```
wickra/
├── crates/
│ ├── wickra-core/ core engine + all 493 indicators
│ ├── wickra-core/ core engine + all 514 indicators
│ ├── wickra/ top-level facade crate (publishes on crates.io) + benches/
│ ├── wickra-data/ CSV reader, tick aggregator, live exchange feeds
│ └── wickra-bench/ internal cross-library benchmark harness (not published)
├── bindings/
│ ├── python/ PyO3 + maturin (publishes on PyPI)
│ ├── node/ napi-rs (publishes on npm)
── wasm/ wasm-bindgen (browsers, bundlers, Node)
── wasm/ wasm-bindgen (browsers, bundlers, Node)
│ ├── c/ C ABI (cdylib + staticlib) + generated include/wickra.h
│ ├── csharp/ .NET binding over the C ABI (publishes on NuGet)
│ ├── go/ Go binding over the C ABI via cgo (module tag)
│ ├── r/ R binding over the C ABI via .Call (R package)
│ └── java/ Java binding over the C ABI via the FFM API (Maven Central)
├── examples/ examples/README.md indexes every language
│ ├── data/ real BTCUSDT OHLCV datasets, one per timeframe
│ ├── rust/ Rust workspace member (`wickra-examples`)
│ ├── python/ backtest, live trading, parallel assets, multi-tf
│ ├── node/ streaming, backtest, live trading (load `wickra`)
── wasm/ browser demo for `wickra-wasm`
── wasm/ browser demo for `wickra-wasm`
│ ├── c/ C smoke + streaming, C++ RAII wrapper
│ ├── csharp/ streaming, backtest, strategies (load `Wickra`)
│ ├── go/ streaming, backtest, strategies (cgo binding)
│ ├── r/ streaming, backtest, strategies (.Call binding)
│ └── java/ streaming, backtest, strategies (FFM binding)
└── .github/workflows/ CI and release pipelines
```
@@ -278,6 +303,25 @@ wasm-pack build bindings/wasm --target web --release --features panic-hook
# Node binding (requires @napi-rs/cli)
cd bindings/node && npm install && npm run build && npm test
# C ABI (cdylib + staticlib + generated header)
cargo build -p wickra-c --release
cmake -S examples/c -B examples/c/build -DWICKRA_LIB_DIR="$PWD/target/release"
cmake --build examples/c/build && ctest --test-dir examples/c/build --output-on-failure
# C# / .NET binding (requires the .NET 8 SDK; links the C ABI above)
dotnet test bindings/csharp/Wickra.Tests/Wickra.Tests.csproj
# Go binding (requires a C compiler for cgo; links the C ABI above)
cp target/release/libwickra.so bindings/go/lib/ # .dylib on macOS, wickra.dll on Windows
cd bindings/go && go test ./...
# R binding (requires a C toolchain / Rtools; links the C ABI above)
WICKRA_INCLUDE_DIR="$PWD/bindings/c/include" WICKRA_LIB_DIR="$PWD/target/release" \
R CMD INSTALL bindings/r
# Java binding (requires JDK 22+ and Maven; links the C ABI above)
mvn -f bindings/java test
```
## Testing
@@ -297,6 +341,12 @@ Every layer is covered; run the suites with the commands in
values across all indicators.
- `bindings/wasm`: `wasm-bindgen-test` cases for constructors, equivalence,
and reference values.
- `bindings/go`: `go test` cases covering one indicator per FFI archetype
(scalar/batch, multi-output, bars, profile, array input), reset, and lifecycle.
- `bindings/r`: `testthat` cases covering one indicator per FFI archetype
(scalar/batch, multi-output, bars, profile, array input), reset, and validation.
- `bindings/java`: JUnit cases covering one indicator per FFI archetype
(scalar/batch, multi-output, bars, profile, array input) plus batch equivalence.
## Contributing
+3 -2
View File
@@ -21,8 +21,9 @@ minor releases; breaking changes are called out in the changelog.
versioning stability for a 1.0 release.
- **Performance.** Keep per-tick updates O(1) and maintain the benchmark suite;
investigate further allocation and cache improvements.
- **Bindings parity.** Keep the Python, Node.js and WebAssembly bindings in
lockstep with the Rust core, including type stubs and platform coverage.
- **Bindings parity.** Keep the Python, Node.js and WebAssembly bindings — plus
the C ABI and the C# / .NET, Go, Java and R bindings generated from it — in lockstep with the
Rust core, including type stubs and platform coverage.
- **Documentation.** Maintain a deep-dive page per indicator on
<https://docs.wickra.org>, plus quickstarts and cookbook material.
- **Project health.** Maintain test coverage, static and dynamic analysis,
+5 -1
View File
@@ -58,7 +58,11 @@ artifacts, and (4) a healthy dependency supply chain.
- *Memory safety* — the core and all bindings are written in Rust. The crates
forbid or minimise `unsafe`, so the compiler guarantees memory and thread
safety for the indicator logic.
safety for the indicator logic. The one exception is the C ABI
([`bindings/c`](bindings/c)), whose thin FFI shim is necessarily `unsafe`
because it dereferences caller-supplied pointers; it adds no indicator logic,
validates every handle for NULL, and never lets a panic cross the boundary, so
the safe core's guarantees still cover all computation.
- *Input robustness* — every indicator validates its parameters and rejects
non-finite inputs at construction; behaviour on edge cases (flat markets,
warmup, reset) is pinned by unit tests, and the public update paths are
+2 -2
View File
@@ -7,8 +7,8 @@ Thanks for using Wickra! Here is where to get help, depending on what you need.
Most questions are answered in the documentation:
- **Docs site:** <https://docs.wickra.org> — quickstarts for Rust, Python,
Node.js and WebAssembly, a per-indicator reference, warmup periods, the data
layer, and an FAQ.
Node.js, WebAssembly, C, C#, Go, Java and R, a per-indicator reference, warmup periods, the
data layer, and an FAQ.
- **README:** <https://github.com/wickra-lib/wickra#readme> — installation and a
quick overview.
- **API docs (Rust):** <https://docs.rs/wickra>.
+5 -2
View File
@@ -3,8 +3,10 @@
This document describes Wickra's attack surface and the threats considered,
together with their mitigations. It complements the security assurance case in
[`SECURITY.md`](SECURITY.md). Wickra is a computational technical-analysis
library (a Rust core with Python, Node.js and WebAssembly bindings), not a
network service or trading system; the attack surface is correspondingly small.
library (a Rust core with Python, Node.js and WebAssembly bindings plus a C ABI
and the .NET, Go, Java and R bindings built on it),
not a network service or trading system; the attack surface is correspondingly
small.
## Assets
@@ -31,6 +33,7 @@ network service or trading system; the attack surface is correspondingly small.
| Threat | Mitigation |
| --- | --- |
| Memory-safety exploit (buffer overflow, UAF) via crafted input | Pure safe Rust; `unsafe` is forbidden/minimised, so the compiler precludes these classes. |
| Misuse of the C ABI FFI boundary (invalid/dangling handle, undersized batch buffer) | The C ABI (`bindings/c`) is the sole `unsafe` surface. Its shim adds no logic, NULL-checks every handle (returning `NaN`/no-op), writes only into caller-sized buffers, and catches panics so none cross the boundary. A caller passing a non-NULL but dangling pointer is undefined behaviour by C's own contract — out of scope, the same as any C library. |
| Denial of service via malformed/degenerate input (NaN, infinities, extreme magnitudes) | Indicators reject non-finite inputs and validate parameters at construction; update paths are exercised by coverage-guided fuzzing and unit tests for edge cases. |
| Silently incorrect results | 100% line coverage on the core crate; reference-value tests against known-good sources; streaming/batch parity tests. |
| Integer overflow / panics | `clippy::pedantic` with `-D warnings`; debug assertions and overflow checks enabled in test/fuzz builds. |
+46
View File
@@ -0,0 +1,46 @@
[package]
name = "wickra-c"
description = "C ABI (cdylib + staticlib) for the Wickra streaming-first technical indicators library — the hub every C-capable language (C, C++, Go, C#, Java, R) links against."
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
readme = "README.md"
keywords.workspace = true
categories.workspace = true
publish = false
[lib]
name = "wickra"
crate-type = ["cdylib", "staticlib"]
# The C ABI inherently needs `unsafe` (raw pointers across the FFI boundary,
# `#[export_name]` symbol control). The workspace forbids `unsafe_code`, so this
# crate cannot inherit `workspace = true`; it mirrors every workspace lint and
# only relaxes `unsafe_code` to `allow` (parity with how the proc-macro bindings
# emit their unsafe). The Rust core stays `unsafe`-forbidden — this is the one
# crate where the boundary lives.
[lints.rust]
unsafe_code = "allow"
missing_debug_implementations = "warn"
unreachable_pub = "warn"
unused_must_use = "deny"
[lints.clippy]
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
module_name_repetitions = "allow"
must_use_candidate = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
cast_precision_loss = "allow"
cast_possible_truncation = "allow"
cast_sign_loss = "allow"
similar_names = "allow"
float_cmp = "allow"
[dependencies]
wickra-core = { workspace = true }
+80
View File
@@ -0,0 +1,80 @@
# Wickra — C / C++
[![CI](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml/badge.svg)](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/wickra-lib/wickra/branch/main/graph/badge.svg)](https://codecov.io/gh/wickra-lib/wickra)
[![GitHub release](https://img.shields.io/github/v/release/wickra-lib/wickra?logo=github&color=green)](https://github.com/wickra-lib/wickra/releases/latest)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue)](https://github.com/wickra-lib/wickra#license)
**Streaming-first technical indicators for C and C++. A prebuilt shared/static
library plus a generated `wickra.h` — no system dependencies.**
Wickra is a multi-language technical-analysis library with a Rust core and
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R and any
other C-capable language. Every indicator is an O(1)
streaming state machine, so live trading bots and historical backtests share
the exact same implementation. This package is the **C ABI hub**: it compiles the
core to a C-compatible shared/static library plus a generated header, so any
C-capable language (C, C++, Go, C#, Java, R) links against one artifact instead
of re-wrapping every indicator natively.
## Install
Grab the prebuilt header + library for your platform from the
[GitHub releases](https://github.com/wickra-lib/wickra/releases) — each archive
has `wickra.h`, the optional `wickra.hpp` C++ wrapper, and the shared/static
library — or build from source:
```bash
cargo build -p wickra-c --release
# -> target/release/libwickra.{so,dylib} or wickra.dll (+ import lib) + a staticlib
```
Then compile against the header and link the library
(`cc app.c -I include -L lib -lwickra -lm -o app`).
## Quick start
```c
#include "wickra.h"
struct Rsi *rsi = wickra_rsi_new(14); /* NULL on invalid params */
for (size_t i = 0; i < n; ++i) {
double v = wickra_rsi_update(rsi, prices[i]); /* NaN during warmup */
if (v == v && v > 70.0) /* v == v is the NaN check */
printf("overbought\n");
}
wickra_rsi_free(rsi); /* exactly once per _new */
```
Every indicator is an opaque handle with the same five functions —
`_new` / `_update` / `_batch` / `_reset` / `_free`. `update` is O(1); there is no
RAII across the C boundary, so each `_new` needs exactly one `_free`, and every
function is NULL-safe (a NULL handle yields `NaN` or a no-op, never a crash).
Multi-output indicators (MACD, Bollinger, ADX, …) take a pointer to a `#[repr(C)]`
struct and return a `bool`. The optional `wickra.hpp` wraps any handle in a
move-only `wickra::Handle` for exception-safe C++ lifetimes.
## Documentation
The full indicator catalogue, guides, quickstarts, and API reference live in
the main repository and documentation site:
- **Repository & full indicator list:** <https://github.com/wickra-lib/wickra>
- **Docs** (C quickstart, cookbook, TA-Lib migration): <https://docs.wickra.org/Quickstart-C>
- **Runnable examples:** [`examples/c/`](https://github.com/wickra-lib/wickra/tree/main/examples/c)
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus this
C ABI hub that any C-capable language (C, C++, Go, C#, Java, R) links against —
all exposing the same indicators from the shared Rust core.
## Disclaimer
Wickra is an indicator toolkit, not a trading system. The values it computes
are deterministic transforms of the input data — they are not financial advice
and do not predict the market. Any use in a live trading context is at your own
risk. The library is provided **as is**, without warranty of any kind.
## License
Licensed under either of [Apache-2.0](https://github.com/wickra-lib/wickra/blob/main/LICENSE-APACHE)
or [MIT](https://github.com/wickra-lib/wickra/blob/main/LICENSE-MIT) at your option.
+20
View File
@@ -0,0 +1,20 @@
language = "C"
header = "/* Wickra C ABI — generated by cbindgen. Do not edit by hand. */"
include_guard = "WICKRA_H"
pragma_once = true
# Wrap the declarations in `extern "C"` under __cplusplus so the header is usable
# from C++ (the optional wickra.hpp RAII layer and any C++ consumer).
cpp_compat = true
tab_width = 4
# Off: cbindgen copies the Rust struct/fn doc comments verbatim, and some core
# indicator docs contain markdown (e.g. `**1/8**/**7/8**`) whose `*/` would close
# the C block comment early and break the header. Usage docs live in the crate
# README and examples; the header is a pure declaration contract.
documentation = false
[parse]
# Parse wickra-core too so the opaque indicator handle types (Sma, Ema, …) are
# discovered and emitted as forward-declared opaque structs. Their fields are
# never exposed — only `T *` handles cross the boundary.
parse_deps = true
include = ["wickra-core"]
File diff suppressed because it is too large Load Diff
+66
View File
@@ -0,0 +1,66 @@
// Optional C++ convenience layer over the Wickra C ABI (`wickra.h`).
//
// The C ABI hands out raw handles that must be released exactly once with the
// matching `wickra_<ind>_free`. `wickra::Handle` wraps that in a move-only RAII
// owner so the free happens automatically at scope exit:
//
// #include "wickra.hpp"
//
// wickra::Handle<Sma, wickra_sma_free> sma(wickra_sma_new(14));
// if (sma) {
// double v = wickra_sma_update(sma.get(), 42.0); // NaN during warmup
// }
// // sma is freed here
//
// This is header-only and adds no runtime cost beyond the C calls themselves.
#ifndef WICKRA_HPP
#define WICKRA_HPP
#include "wickra.h"
#include <utility>
namespace wickra {
/// Move-only RAII owner of a Wickra handle. `T` is the opaque indicator type and
/// `Free` its `wickra_<ind>_free` function.
template <typename T, void (*Free)(T *)>
class Handle {
public:
explicit Handle(T *ptr) noexcept : ptr_(ptr) {}
~Handle() {
if (ptr_ != nullptr) {
Free(ptr_);
}
}
Handle(const Handle &) = delete;
Handle &operator=(const Handle &) = delete;
Handle(Handle &&other) noexcept : ptr_(std::exchange(other.ptr_, nullptr)) {}
Handle &operator=(Handle &&other) noexcept {
if (this != &other) {
if (ptr_ != nullptr) {
Free(ptr_);
}
ptr_ = std::exchange(other.ptr_, nullptr);
}
return *this;
}
/// The raw handle, for passing to the `wickra_<ind>_*` functions.
T *get() const noexcept { return ptr_; }
/// True if the handle is non-null (construction succeeded).
explicit operator bool() const noexcept { return ptr_ != nullptr; }
private:
T *ptr_;
};
} // namespace wickra
#endif // WICKRA_HPP
+44290
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
# .NET build output
bin/
obj/
*.user
# NuGet packaging output
*.nupkg
*.snupkg
# Native libraries staged for packaging (produced by the release pipeline from
# the wickra-c-<triple>.tar.gz assets; never committed to source).
Wickra/runtimes/
+78
View File
@@ -0,0 +1,78 @@
# Wickra — .NET
[![CI](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml/badge.svg)](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/wickra-lib/wickra/branch/main/graph/badge.svg)](https://codecov.io/gh/wickra-lib/wickra)
[![NuGet](https://img.shields.io/nuget/v/Wickra.svg?logo=nuget&color=blue)](https://www.nuget.org/packages/Wickra)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue)](https://github.com/wickra-lib/wickra#license)
**Streaming-first technical indicators for .NET. `dotnet add package Wickra`
prebuilt native library, no system dependencies.**
Wickra is a multi-language technical-analysis library with a Rust core and
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R and any
other C-capable language. Every indicator is an O(1)
streaming state machine, so live trading bots and historical backtests share
the exact same implementation. This package is the .NET binding; it consumes the
C ABI hub through `[LibraryImport]` P/Invoke and exposes all 514 streaming-first
indicators as idiomatic `IDisposable` classes.
## Install
```bash
dotnet add package Wickra
```
The native library ships prebuilt per platform (Linux, macOS, Windows — x64 and
arm64) under `runtimes/<rid>/native/`, selected automatically. There is nothing
to compile. Targets .NET 8 and later.
## Quick start
```csharp
using Wickra;
// Batch: run an indicator over a whole series (NaN at warmup positions).
var prices = Enumerable.Range(0, 1000).Select(i => 100.0 + i * 0.1).ToArray();
using var sma = new Sma(20);
double[] values = sma.Batch(prices);
// Streaming: the same indicator, fed tick by tick in O(1).
using var rsi = new Rsi(14);
foreach (var price in liveFeed)
{
var value = rsi.Update(price); // NaN during warmup, no recomputation
if (double.IsFinite(value) && value > 70)
{
Console.WriteLine("overbought");
}
}
```
`Batch(prices)` and feeding the same prices through `Update()` produce identical
values — the equivalence is enforced by the test suite. Multi-output indicators
(MACD, Bollinger, ADX, …) return a nullable `record struct`, `null` while warming up.
## Documentation
The full indicator catalogue, guides, quickstarts, and API reference live in
the main repository and documentation site:
- **Repository & full indicator list:** <https://github.com/wickra-lib/wickra>
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
- **Runnable examples:** [`examples/csharp/`](https://github.com/wickra-lib/wickra/tree/main/examples/csharp)
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus a
C ABI hub that any C-capable language (C, C++, Go, C#, Java, R) links against —
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
## Disclaimer
Wickra is an indicator toolkit, not a trading system. The values it computes
are deterministic transforms of the input data — they are not financial advice
and do not predict the market. Any use in a live trading context is at your own
risk. The library is provided **as is**, without warranty of any kind.
## License
Licensed under either of [Apache-2.0](https://github.com/wickra-lib/wickra/blob/main/LICENSE-APACHE)
or [MIT](https://github.com/wickra-lib/wickra/blob/main/LICENSE-MIT) at your option.
@@ -0,0 +1,144 @@
using Wickra;
using Xunit;
namespace Wickra.Tests;
/// <summary>
/// One representative per FFI archetype, exercising every marshalling path the
/// generator produces (scalar, candle, pairwise, multi-output, bars, profile,
/// values-profile, array-input). Garbage marshalling surfaces as NaN, wild
/// values, or crashes — so finite/sane assertions are the real check.
/// </summary>
public class ArchetypeTests
{
private static (double open, double high, double low, double close, double volume, long ts) Candle(int i)
{
var close = 100.0 + 10.0 * Math.Sin(i * 0.3);
var open = 100.0 + 10.0 * Math.Sin((i - 1) * 0.3);
var high = Math.Max(open, close) + 1.0;
var low = Math.Min(open, close) - 1.0;
return (open, high, low, close, 1_000.0, i * 60_000L);
}
[Fact]
public void Scalar_Ema_IsFiniteAfterWarmup()
{
using var ema = new Ema(3);
double last = double.NaN;
for (var i = 1; i <= 10; i++)
{
last = ema.Update(i);
}
Assert.True(double.IsFinite(last));
Assert.InRange(last, 1.0, 10.0);
}
[Fact]
public void Candle_Atr_IsFinitePositive()
{
using var atr = new Atr(3);
double last = double.NaN;
for (var i = 0; i < 20; i++)
{
var (o, h, l, c, v, ts) = Candle(i);
last = atr.Update(o, h, l, c, v, ts);
}
Assert.True(double.IsFinite(last));
Assert.True(last > 0.0);
}
[Fact]
public void Pairwise_Beta_IsFinite()
{
using var beta = new Beta(5);
double last = double.NaN;
for (var i = 0; i < 30; i++)
{
var market = 100.0 + 10.0 * Math.Sin(i * 0.5);
var asset = 50.0 + 6.0 * Math.Sin(i * 0.5 + 0.2);
last = beta.Update(market, asset);
}
Assert.True(double.IsFinite(last));
}
[Fact]
public void MultiOutput_Adx_ReturnsFiniteStruct()
{
using var adx = new Adx(5);
AdxOutput? result = null;
for (var i = 0; i < 60; i++)
{
var (o, h, l, c, v, ts) = Candle(i);
result = adx.Update(o, h, l, c, v, ts);
}
Assert.NotNull(result);
Assert.True(double.IsFinite(result!.Value.Adx));
Assert.True(double.IsFinite(result.Value.PlusDi));
Assert.True(double.IsFinite(result.Value.MinusDi));
}
[Fact]
public void Bars_DollarBars_EmitsBars()
{
using var bars = new DollarBars(5_000.0);
var total = 0;
for (var i = 0; i < 200; i++)
{
var (o, h, l, c, v, ts) = Candle(i);
total += bars.Update(o, h, l, c, v, ts).Length;
}
Assert.True(total > 0);
}
[Fact]
public void Profile_VolumeProfile_ReturnsValues()
{
using var profile = new VolumeProfile(20, 8);
VolumeProfileOutputScalars? result = null;
for (var i = 0; i < 60; i++)
{
var (o, h, l, c, v, ts) = Candle(i);
result = profile.Update(o, h, l, c, v, ts);
}
Assert.NotNull(result);
Assert.NotNull(result!.Value.Values);
Assert.True(result.Value.PriceLow <= result.Value.PriceHigh);
}
[Fact]
public void ProfileValues_DayOfWeekProfile_NoCrash()
{
using var profile = new DayOfWeekProfile(0);
double[]? result = null;
for (var i = 0; i < 60; i++)
{
var close = 100.0 + 5.0 * Math.Sin(i * 0.2);
// one day apart so the day-of-week buckets fill
result = profile.Update(close, close + 1, close - 1, close, 1_000.0, i * 86_400_000L);
}
if (result is not null)
{
Assert.All(result, v => Assert.True(double.IsFinite(v)));
}
}
[Fact]
public void ArrayInput_DepthSlope_IsFinite()
{
using var slope = new DepthSlope();
ReadOnlySpan<double> bidPrice = stackalloc double[] { 99.0, 98.0, 97.0 };
ReadOnlySpan<double> bidSize = stackalloc double[] { 10.0, 20.0, 30.0 };
ReadOnlySpan<double> askPrice = stackalloc double[] { 101.0, 102.0, 103.0 };
ReadOnlySpan<double> askSize = stackalloc double[] { 12.0, 22.0, 32.0 };
var result = slope.Update(bidPrice, bidSize, askPrice, askSize);
Assert.True(double.IsFinite(result));
}
}
+51
View File
@@ -0,0 +1,51 @@
using Wickra;
using Xunit;
namespace Wickra.Tests;
public class SmaTests
{
[Fact]
public void StreamingMatchesReference()
{
using var sma = new Sma(3);
Assert.True(double.IsNaN(sma.Update(1)));
Assert.True(double.IsNaN(sma.Update(2)));
Assert.Equal(2.0, sma.Update(3), 9);
Assert.Equal(3.0, sma.Update(4), 9);
Assert.Equal(4.0, sma.Update(5), 9);
}
[Fact]
public void BatchMatchesStreaming()
{
using var sma = new Sma(3);
var output = sma.Batch(new double[] { 1, 2, 3, 4, 5 });
Assert.True(double.IsNaN(output[0]));
Assert.True(double.IsNaN(output[1]));
Assert.Equal(2.0, output[2], 9);
Assert.Equal(3.0, output[3], 9);
Assert.Equal(4.0, output[4], 9);
}
[Fact]
public void ResetClearsState()
{
using var sma = new Sma(3);
sma.Update(1);
sma.Update(2);
sma.Update(3);
sma.Reset();
Assert.True(double.IsNaN(sma.Update(10)));
}
[Fact]
public void ZeroPeriodThrows()
{
// Zero is rejected by the native constructor (returns NULL) -> ArgumentException;
// a negative period is caught earlier by the wrapper guard.
Assert.Throws<ArgumentException>(() => new Sma(0));
Assert.Throws<ArgumentOutOfRangeException>(() => new Sma(-1));
}
}
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wickra\Wickra.csproj" />
</ItemGroup>
</Project>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+57
View File
@@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RootNamespace>Wickra</RootNamespace>
<AssemblyName>Wickra</AssemblyName>
<!-- NuGet package metadata -->
<PackageId>Wickra</PackageId>
<Version>0.7.9</Version>
<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>
<PackageLicenseExpression>MIT OR Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/wickra-lib/wickra</PackageProjectUrl>
<RepositoryUrl>https://github.com/wickra-lib/wickra</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>technical-analysis;indicators;trading;finance;streaming;ffi;native</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- A managed package carrying per-RID native assets; not built per-RID itself. -->
<IncludeBuildOutput>true</IncludeBuildOutput>
<!-- NU5128: managed package carrying only per-RID native assets.
CS1591: generated members are self-descriptive; hand-written API is documented. -->
<NoWarn>$(NoWarn);NU5128;CS1591</NoWarn>
</PropertyGroup>
<!--
Supported native runtime identifiers. The release pipeline builds the C ABI
per target triple and stages the libraries under
Wickra/runtimes/<rid>/native/ before `dotnet pack`:
win-x64 win-arm64 linux-x64 linux-arm64 osx-x64 osx-arm64
-->
<PropertyGroup>
<WickraRuntimeIdentifiers>win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</WickraRuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>
<None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<!--
Native libraries are packed under runtimes/<rid>/native/ by the release pipeline,
which unpacks the wickra-c-<triple>.tar.gz assets into the matching RID folders.
For local development and tests the natives are resolved from the cargo target dir
via WickraNative's DllImportResolver.
-->
<ItemGroup>
<None Include="runtimes/**/native/*" Pack="true" PackagePath="runtimes" Condition="Exists('runtimes')" />
</ItemGroup>
</Project>
+26
View File
@@ -0,0 +1,26 @@
using Microsoft.Win32.SafeHandles;
namespace Wickra;
/// <summary>
/// Owns an opaque native indicator handle and releases it via the indicator's
/// <c>_free</c> function. One generic handle type backs every indicator; the
/// correct free routine is captured at construction time.
/// </summary>
internal sealed class WickraHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private readonly Action<nint> _free;
internal WickraHandle(nint handle, Action<nint> free)
: base(ownsHandle: true)
{
_free = free;
SetHandle(handle);
}
protected override bool ReleaseHandle()
{
_free(handle);
return true;
}
}
+87
View File
@@ -0,0 +1,87 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Wickra;
/// <summary>
/// Native library resolution for the Wickra C ABI.
/// </summary>
/// <remarks>
/// When consumed as a NuGet package the native library ships under
/// <c>runtimes/&lt;rid&gt;/native/</c> and the default runtime resolver finds it
/// automatically. For local development (project reference against a cargo build)
/// the resolver additionally walks up the directory tree to locate
/// <c>target/release</c> or <c>target/debug</c>. Every candidate is validated to
/// actually export the Wickra ABI before it is accepted, so an unrelated library
/// of the same name cannot shadow the real one.
/// </remarks>
internal static class WickraNative
{
/// <summary>The library name passed to <c>[LibraryImport]</c>.</summary>
internal const string LibraryName = "wickra";
// Any exported symbol works as a fingerprint; sma_new exists in every build.
private const string SentinelSymbol = "wickra_sma_new";
[ModuleInitializer]
internal static void Register()
{
NativeLibrary.SetDllImportResolver(typeof(WickraNative).Assembly, Resolve);
}
private static nint Resolve(string libraryName, System.Reflection.Assembly assembly, DllImportSearchPath? searchPath)
{
if (libraryName != LibraryName)
{
return nint.Zero;
}
// 1. Default resolution (NuGet runtimes/ layout, app-local copies). Accept
// only if it is genuinely the Wickra ABI; otherwise discard and fall through.
if (NativeLibrary.TryLoad(libraryName, assembly, searchPath, out var handle))
{
if (Exports(handle))
{
return handle;
}
NativeLibrary.Free(handle);
}
// 2. Development fallback: locate the cargo build output.
var fileName = NativeFileName();
var dir = AppContext.BaseDirectory;
for (var i = 0; i < 16 && dir is not null; i++)
{
foreach (var profile in new[] { "release", "debug" })
{
var candidate = Path.Combine(dir, "target", profile, fileName);
if (File.Exists(candidate) && NativeLibrary.TryLoad(candidate, out var devHandle))
{
if (Exports(devHandle))
{
return devHandle;
}
NativeLibrary.Free(devHandle);
}
}
dir = Path.GetDirectoryName(dir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
}
return nint.Zero;
}
private static bool Exports(nint handle) => NativeLibrary.TryGetExport(handle, SentinelSymbol, out _);
private static string NativeFileName()
{
if (OperatingSystem.IsWindows())
{
return "wickra.dll";
}
return OperatingSystem.IsMacOS() ? "libwickra.dylib" : "libwickra.so";
}
}
+100
View File
@@ -0,0 +1,100 @@
# Wickra — Go
[![CI](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml/badge.svg)](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/wickra-lib/wickra/branch/main/graph/badge.svg)](https://codecov.io/gh/wickra-lib/wickra)
[![Go Reference](https://pkg.go.dev/badge/github.com/wickra-lib/wickra/bindings/go.svg)](https://pkg.go.dev/github.com/wickra-lib/wickra/bindings/go)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue)](https://github.com/wickra-lib/wickra#license)
**Streaming-first technical indicators for Go, over the Wickra C ABI hub via cgo.**
Wickra is a multi-language technical-analysis library with a Rust core and
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R and
any other C-capable language. Every indicator is an O(1) streaming state machine,
so live trading bots and historical backtests share the exact same
implementation. This package is the Go binding; it consumes the C ABI hub through
cgo and exposes all 514 streaming-first indicators as idiomatic types.
## Install
```bash
go get github.com/wickra-lib/wickra/bindings/go
```
The binding uses cgo, so a C compiler is required, and it links against the
prebuilt Wickra C ABI library. Build that library from the workspace and stage
it under this package's `lib/` directory:
```bash
cargo build -p wickra-c --release
cp target/release/libwickra.so bindings/go/lib/ # Linux
cp target/release/libwickra.dylib bindings/go/lib/ # macOS
cp target/release/wickra.dll bindings/go/lib/ # Windows (also on PATH at run time)
```
On Linux and macOS the library path is baked in via rpath; on Windows the DLL
must be discoverable at run time (next to the executable or on `PATH`).
## Quick start
```go
package main
import (
"fmt"
wickra "github.com/wickra-lib/wickra/bindings/go"
)
func main() {
// Batch: run an indicator over a whole series (NaN at warmup positions).
prices := make([]float64, 1000)
for i := range prices {
prices[i] = 100.0 + float64(i)*0.1
}
sma, _ := wickra.NewSma(20)
defer sma.Close()
values := sma.Batch(prices)
// Streaming: the same indicator, fed tick by tick in O(1).
rsi, _ := wickra.NewRsi(14)
defer rsi.Close()
for _, price := range prices {
value := rsi.Update(price) // NaN during warmup, no recomputation
if value > 70 {
fmt.Println("overbought")
}
}
_ = values
}
```
`Batch(prices)` and feeding the same prices through `Update()` produce identical
values — the equivalence is enforced by the test suite. Multi-output indicators
(MACD, Bollinger, ADX, …) return `(Output, bool)`, with `false` while warming up.
Every indicator owns a native handle freed by `Close()`; a finalizer is wired as
a backstop, but call `Close()` (e.g. with `defer`) to release memory promptly.
## Documentation
The full indicator catalogue, guides, quickstarts, and API reference live in the
main repository and documentation site:
- **Repository & full indicator list:** <https://github.com/wickra-lib/wickra>
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
- **Runnable examples:** [`examples/go/`](https://github.com/wickra-lib/wickra/tree/main/examples/go)
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus a
C ABI hub that any C-capable language (C, C++, C#, Go, Java, R) links against —
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
## Disclaimer
Wickra is an indicator toolkit, not a trading system. The values it computes are
deterministic transforms of the input data — they are not financial advice and
do not predict the market. Any use in a live trading context is at your own risk.
The library is provided **as is**, without warranty of any kind.
## License
Licensed under either of [Apache-2.0](https://github.com/wickra-lib/wickra/blob/main/LICENSE-APACHE)
or [MIT](https://github.com/wickra-lib/wickra/blob/main/LICENSE-MIT) at your option.
+3
View File
@@ -0,0 +1,3 @@
module github.com/wickra-lib/wickra/bindings/go
go 1.23
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
# Prebuilt Wickra C ABI libraries are provisioned locally / in CI, not committed.
*.so
*.dylib
*.dll
*.a
*.lib
*.exp
+25
View File
@@ -0,0 +1,25 @@
// Package wickra provides idiomatic Go bindings for the Wickra
// technical-analysis library over its C ABI hub.
//
// Each indicator is an opaque-handle type with a New<Indicator> constructor and
// Update/Batch/Reset/Close methods. Handles are freed by Close and, as a
// backstop, by a finalizer; call Close explicitly to release native memory
// promptly. The binding links against the prebuilt Wickra C ABI library
// (libwickra.so/.dylib or wickra.dll) staged under ./lib — see the package
// README for how to provision it.
package wickra
/*
#cgo CFLAGS: -I${SRCDIR}/../c/include
#cgo linux LDFLAGS: -L${SRCDIR}/lib -lwickra -Wl,-rpath,${SRCDIR}/lib
#cgo darwin LDFLAGS: -L${SRCDIR}/lib -lwickra -Wl,-rpath,${SRCDIR}/lib
#cgo windows LDFLAGS: -L${SRCDIR}/lib -l:wickra.dll
#include "wickra.h"
*/
import "C"
import "errors"
// ErrInvalidParams is returned by a New<Indicator> constructor when the native
// constructor rejects the supplied parameters (for example a zero period).
var ErrInvalidParams = errors.New("wickra: invalid indicator parameters")
+151
View File
@@ -0,0 +1,151 @@
package wickra
import (
"math"
"testing"
)
// One indicator per FFI archetype, exercising the full New/Update/Batch/Reset/
// Close surface against the real native library.
func TestScalarKnownValue(t *testing.T) {
s, err := NewSma(3)
if err != nil {
t.Fatalf("NewSma: %v", err)
}
defer s.Close()
var last float64
for _, v := range []float64{1, 2, 3, 4, 5} {
last = s.Update(v)
}
if math.Abs(last-4.0) > 1e-9 {
t.Fatalf("sma(3) last = %v, want 4.0", last)
}
}
func TestScalarBatchMatchesStreaming(t *testing.T) {
input := []float64{1, 2, 3, 4, 5, 6, 7, 8}
stream, _ := NewSma(3)
defer stream.Close()
want := make([]float64, len(input))
for i, v := range input {
want[i] = stream.Update(v)
}
batchInd, _ := NewSma(3)
defer batchInd.Close()
got := batchInd.Batch(input)
if len(got) != len(want) {
t.Fatalf("batch len = %d, want %d", len(got), len(want))
}
for i := range want {
if math.IsNaN(want[i]) && math.IsNaN(got[i]) {
continue
}
if math.Abs(got[i]-want[i]) > 1e-9 {
t.Fatalf("batch[%d] = %v, streaming = %v", i, got[i], want[i])
}
}
}
func TestMultiOutput(t *testing.T) {
m, err := NewMacdIndicator(3, 6, 3)
if err != nil {
t.Fatalf("NewMacdIndicator: %v", err)
}
defer m.Close()
var ok bool
var out MacdOutput
for i := 0; i < 30; i++ {
out, ok = m.Update(100 + float64(i))
}
if !ok {
t.Fatal("macd never produced a value after warmup")
}
if math.IsNaN(out.Macd) {
t.Fatal("macd value is NaN after warmup")
}
}
func TestBars(t *testing.T) {
rb, err := NewRangeBars(2.0)
if err != nil {
t.Fatalf("NewRangeBars: %v", err)
}
defer rb.Close()
total := 0
for _, p := range []float64{100, 101, 103, 104, 99, 96, 102, 108, 95, 110} {
bars := rb.Update(p, p, p, p, 1, 0)
total += len(bars)
}
if total == 0 {
t.Fatal("range bars produced no bars over a 15-point move")
}
}
func TestProfile(t *testing.T) {
vp, err := NewVolumeProfile(10, 24)
if err != nil {
t.Fatalf("NewVolumeProfile: %v", err)
}
defer vp.Close()
var ok bool
var snap VolumeProfileOutputScalars
for i := 0; i < 50; i++ {
price := 100 + 5*math.Sin(float64(i)*0.3)
snap, ok = vp.Update(price, price+1, price-1, price, 1000, int64(i))
}
if !ok {
t.Fatal("volume profile never produced a snapshot")
}
if len(snap.Values) == 0 {
t.Fatal("volume profile returned an empty values buffer")
}
}
func TestArrayInput(t *testing.T) {
ob, err := NewOrderBookImbalanceFull()
if err != nil {
t.Fatalf("NewOrderBookImbalanceFull: %v", err)
}
defer ob.Close()
bidPrice := []float64{99.9, 99.8, 99.7}
bidSize := []float64{5, 3, 2}
askPrice := []float64{100.1, 100.2, 100.3}
askSize := []float64{1, 1, 1}
v := ob.Update(bidPrice, bidSize, askPrice, askSize)
if math.IsNaN(v) {
t.Fatal("order-book imbalance is NaN on a populated book")
}
}
func TestResetReturnsToWarmup(t *testing.T) {
s, _ := NewSma(3)
defer s.Close()
for _, v := range []float64{1, 2, 3} {
s.Update(v)
}
s.Reset()
if got := s.Update(10); !math.IsNaN(got) {
t.Fatalf("after reset first update = %v, want NaN (warmup)", got)
}
}
func TestInvalidParams(t *testing.T) {
if _, err := NewSma(0); err == nil {
t.Fatal("NewSma(0) should return ErrInvalidParams")
}
}
func TestCloseIsIdempotent(t *testing.T) {
s, _ := NewSma(3)
s.Close()
s.Close() // must not panic or double-free
}
+6
View File
@@ -0,0 +1,6 @@
# Maven build output
target/
# Native libraries staged for packaging (produced by the release pipeline from
# the wickra-c-<triple>.tar.gz assets; never committed to source).
src/main/resources/native/
+102
View File
@@ -0,0 +1,102 @@
# Wickra — Java
[![CI](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml/badge.svg)](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/wickra-lib/wickra/branch/main/graph/badge.svg)](https://codecov.io/gh/wickra-lib/wickra)
[![Maven Central](https://img.shields.io/maven-central/v/org.wickra/wickra.svg?logo=apache-maven&color=blue)](https://central.sonatype.com/artifact/org.wickra/wickra)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue)](https://github.com/wickra-lib/wickra#license)
**Streaming-first technical indicators for the JVM, on the Java Foreign Function
& Memory API — prebuilt native library, no JNI, no system dependencies.**
Wickra is a multi-language technical-analysis library with a Rust core and
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, Java, R
and any other C-capable language. Every indicator is an O(1) streaming state
machine, so live trading bots and historical backtests share the exact same
implementation. This package is the Java binding; it consumes the C ABI hub
through the Panama FFM API (`java.lang.foreign`) and exposes all 514
streaming-first indicators as idiomatic `AutoCloseable` classes.
## Requirements
- **Java 22 or later** (the FFM API is final since Java 22; no preview flag).
- The FFM API is *restricted*: pass `--enable-native-access=ALL-UNNAMED` when you
run your application to silence the native-access warning.
## Install
Maven:
```xml
<dependency>
<groupId>org.wickra</groupId>
<artifactId>wickra</artifactId>
<version>0.7.9</version>
</dependency>
```
Gradle:
```kotlin
implementation("org.wickra:wickra:0.7.9")
```
The native library ships prebuilt per platform (Linux, macOS, Windows — x64 and
arm64) inside the jar and is extracted automatically on first use. There is
nothing to compile.
## Quick start
```java
import org.wickra.Ema;
import org.wickra.Rsi;
// Batch: run an indicator over a whole series (NaN at warmup positions).
double[] prices = new double[1000];
for (int i = 0; i < prices.length; i++) {
prices[i] = 100.0 + i * 0.1;
}
try (Ema ema = new Ema(20)) {
double[] values = ema.batch(prices);
}
// Streaming: the same indicator, fed tick by tick in O(1).
try (Rsi rsi = new Rsi(14)) {
for (double price : liveFeed) {
double value = rsi.update(price); // NaN during warmup, no recomputation
if (Double.isFinite(value) && value > 70) {
System.out.println("overbought");
}
}
}
```
`batch(prices)` and feeding the same prices through `update()` produce identical
values — the equivalence is enforced by the test suite. Multi-output indicators
(MACD, Bollinger, ADX, …) return a `record`, `null` while warming up. Each
indicator owns a native handle freed by a `Cleaner`; `close()` releases it
eagerly (use try-with-resources).
## Documentation
The full indicator catalogue, guides, quickstarts, and API reference live in
the main repository and documentation site:
- **Repository & full indicator list:** <https://github.com/wickra-lib/wickra>
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
- **Runnable examples:** [`examples/java/`](https://github.com/wickra-lib/wickra/tree/main/examples/java)
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus a
C ABI hub that any C-capable language (C, C++, Go, C#, Java, R) links against —
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
## Disclaimer
Wickra is an indicator toolkit, not a trading system. The values it computes
are deterministic transforms of the input data — they are not financial advice
and do not predict the market. Any use in a live trading context is at your own
risk. The library is provided **as is**, without warranty of any kind.
## License
Licensed under either of [Apache-2.0](https://github.com/wickra-lib/wickra/blob/main/LICENSE-APACHE)
or [MIT](https://github.com/wickra-lib/wickra/blob/main/LICENSE-MIT) at your option.
+171
View File
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.wickra</groupId>
<artifactId>wickra</artifactId>
<version>0.7.9</version>
<packaging>jar</packaging>
<name>Wickra</name>
<description>High-performance streaming technical-analysis indicators (514 indicators) for the
JVM, backed by the native Rust core through the Wickra C ABI via the Java FFM API (Panama).</description>
<url>https://github.com/wickra-lib/wickra</url>
<licenses>
<license>
<name>MIT</name>
<url>https://opensource.org/licenses/MIT</url>
<distribution>repo</distribution>
</license>
<license>
<name>Apache-2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>kingchenc</id>
<name>kingchenc</name>
<url>https://github.com/kingchenc</url>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/wickra-lib/wickra.git</connection>
<developerConnection>scm:git:https://github.com/wickra-lib/wickra.git</developerConnection>
<url>https://github.com/wickra-lib/wickra</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>22</maven.compiler.release>
<junit.version>5.10.2</junit.version>
<!-- The FFM API is restricted; grant native access to the unnamed module so
tests and examples run without warnings. Consumers pass the same flag. -->
<native.access.arg>--enable-native-access=ALL-UNNAMED</native.access.arg>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>${native.access.arg}</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<archive>
<manifestEntries>
<!-- Grant native access when the jar is run directly. -->
<Enable-Native-Access>ALL-UNNAMED</Enable-Native-Access>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<!--
Release profile (CI only, gated): attaches source + javadoc jars, GPG-signs
every artifact, and publishes to Maven Central via the central-publishing
plugin. The native libraries are unpacked from the wickra-c-<triple>.tar.gz
release assets into src/main/resources/native/<os>-<arch>/ before `mvn deploy`,
so the published jar carries every platform's library.
-->
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals><goal>jar-no-fork</goal></goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<!-- Generated members are self-descriptive; do not fail on doclint. -->
<doclint>none</doclint>
<quiet>true</quiet>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals><goal>jar</goal></goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals><goal>sign</goal></goals>
<configuration>
<!-- Non-interactive signing on CI: modern GPG needs loopback
pinentry to take the passphrase from the env without a TTY. -->
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.5.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AbandonedBaby indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AbandonedBaby implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AbandonedBaby() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ABANDONED_BABY_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AbandonedBaby parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ABANDONED_BABY_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ABANDONED_BABY_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ABANDONED_BABY_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ABANDONED_BABY_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Abcd indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Abcd implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Abcd() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ABCD_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Abcd parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ABCD_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ABCD_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ABCD_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ABCD_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,72 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AbsoluteBreadthIndex indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AbsoluteBreadthIndex implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AbsoluteBreadthIndex() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ABSOLUTE_BREADTH_INDEX_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AbsoluteBreadthIndex parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ABSOLUTE_BREADTH_INDEX_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double[] change, double[] volume, double[] newHigh, double[] newLow, double[] aboveMa, double[] onBuySignal, long timestamp) {
if (volume.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newHigh.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newLow.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (aboveMa.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (onBuySignal.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment changeSeg = a.allocateFrom(JAVA_DOUBLE, change);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment newHighSeg = a.allocateFrom(JAVA_DOUBLE, newHigh);
MemorySegment newLowSeg = a.allocateFrom(JAVA_DOUBLE, newLow);
MemorySegment aboveMaSeg = a.allocateFrom(JAVA_DOUBLE, aboveMa);
MemorySegment onBuySignalSeg = a.allocateFrom(JAVA_DOUBLE, onBuySignal);
return (double) NativeMethods.WICKRA_ABSOLUTE_BREADTH_INDEX_UPDATE.invokeExact(handle, changeSeg, volumeSeg, newHighSeg, newLowSeg, aboveMaSeg, onBuySignalSeg, (long) change.length, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ABSOLUTE_BREADTH_INDEX_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,62 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AccelerationBands indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AccelerationBands implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AccelerationBands(int period, double factor) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ACCELERATION_BANDS_NEW.invokeExact((long) period, factor);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AccelerationBands parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ACCELERATION_BANDS_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AccelerationBandsOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(24L);
byte ok = (byte) NativeMethods.WICKRA_ACCELERATION_BANDS_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AccelerationBandsOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L),
out.get(JAVA_DOUBLE, 16L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ACCELERATION_BANDS_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AccelerationBandsOutput(double upper, double middle, double lower) {}
@@ -0,0 +1,95 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AcceleratorOscillator indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AcceleratorOscillator implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AcceleratorOscillator(int aoFast, int aoSlow, int signalPeriod) {
if (aoFast < 0) {
throw new IllegalArgumentException("aoFast must be non-negative");
}
if (aoSlow < 0) {
throw new IllegalArgumentException("aoSlow must be non-negative");
}
if (signalPeriod < 0) {
throw new IllegalArgumentException("signalPeriod must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ACCELERATOR_OSCILLATOR_NEW.invokeExact((long) aoFast, (long) aoSlow, (long) signalPeriod);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AcceleratorOscillator parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ACCELERATOR_OSCILLATOR_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ACCELERATOR_OSCILLATOR_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ACCELERATOR_OSCILLATOR_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ACCELERATOR_OSCILLATOR_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdOscillator indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdOscillator implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdOscillator() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AD_OSCILLATOR_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdOscillator parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AD_OSCILLATOR_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_AD_OSCILLATOR_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AD_OSCILLATOR_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AD_OSCILLATOR_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,72 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdVolumeLine indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdVolumeLine implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdVolumeLine() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AD_VOLUME_LINE_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdVolumeLine parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AD_VOLUME_LINE_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double[] change, double[] volume, double[] newHigh, double[] newLow, double[] aboveMa, double[] onBuySignal, long timestamp) {
if (volume.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newHigh.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newLow.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (aboveMa.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (onBuySignal.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment changeSeg = a.allocateFrom(JAVA_DOUBLE, change);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment newHighSeg = a.allocateFrom(JAVA_DOUBLE, newHigh);
MemorySegment newLowSeg = a.allocateFrom(JAVA_DOUBLE, newLow);
MemorySegment aboveMaSeg = a.allocateFrom(JAVA_DOUBLE, aboveMa);
MemorySegment onBuySignalSeg = a.allocateFrom(JAVA_DOUBLE, onBuySignal);
return (double) NativeMethods.WICKRA_AD_VOLUME_LINE_UPDATE.invokeExact(handle, changeSeg, volumeSeg, newHighSeg, newLowSeg, aboveMaSeg, onBuySignalSeg, (long) change.length, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AD_VOLUME_LINE_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,89 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdaptiveCci indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdaptiveCci implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdaptiveCci(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADAPTIVE_CCI_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdaptiveCci parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADAPTIVE_CCI_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ADAPTIVE_CCI_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ADAPTIVE_CCI_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADAPTIVE_CCI_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,66 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdaptiveCycle indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdaptiveCycle implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdaptiveCycle() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADAPTIVE_CYCLE_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdaptiveCycle parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADAPTIVE_CYCLE_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_ADAPTIVE_CYCLE_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ADAPTIVE_CYCLE_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADAPTIVE_CYCLE_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,69 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdaptiveLaguerreFilter indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdaptiveLaguerreFilter implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdaptiveLaguerreFilter(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADAPTIVE_LAGUERRE_FILTER_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdaptiveLaguerreFilter parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADAPTIVE_LAGUERRE_FILTER_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_ADAPTIVE_LAGUERRE_FILTER_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ADAPTIVE_LAGUERRE_FILTER_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADAPTIVE_LAGUERRE_FILTER_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,69 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdaptiveRsi indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdaptiveRsi implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdaptiveRsi(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADAPTIVE_RSI_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdaptiveRsi parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADAPTIVE_RSI_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_ADAPTIVE_RSI_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ADAPTIVE_RSI_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADAPTIVE_RSI_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Adl indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Adl implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Adl() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADL_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Adl parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADL_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ADL_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ADL_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADL_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdvanceBlock indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdvanceBlock implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdvanceBlock() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADVANCE_BLOCK_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdvanceBlock parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADVANCE_BLOCK_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ADVANCE_BLOCK_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ADVANCE_BLOCK_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADVANCE_BLOCK_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,72 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdvanceDecline indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdvanceDecline implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdvanceDecline() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADVANCE_DECLINE_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdvanceDecline parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADVANCE_DECLINE_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double[] change, double[] volume, double[] newHigh, double[] newLow, double[] aboveMa, double[] onBuySignal, long timestamp) {
if (volume.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newHigh.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newLow.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (aboveMa.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (onBuySignal.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment changeSeg = a.allocateFrom(JAVA_DOUBLE, change);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment newHighSeg = a.allocateFrom(JAVA_DOUBLE, newHigh);
MemorySegment newLowSeg = a.allocateFrom(JAVA_DOUBLE, newLow);
MemorySegment aboveMaSeg = a.allocateFrom(JAVA_DOUBLE, aboveMa);
MemorySegment onBuySignalSeg = a.allocateFrom(JAVA_DOUBLE, onBuySignal);
return (double) NativeMethods.WICKRA_ADVANCE_DECLINE_UPDATE.invokeExact(handle, changeSeg, volumeSeg, newHighSeg, newLowSeg, aboveMaSeg, onBuySignalSeg, (long) change.length, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADVANCE_DECLINE_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,72 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AdvanceDeclineRatio indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AdvanceDeclineRatio implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AdvanceDeclineRatio() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADVANCE_DECLINE_RATIO_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AdvanceDeclineRatio parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADVANCE_DECLINE_RATIO_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double[] change, double[] volume, double[] newHigh, double[] newLow, double[] aboveMa, double[] onBuySignal, long timestamp) {
if (volume.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newHigh.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (newLow.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (aboveMa.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
if (onBuySignal.length != change.length) {
throw new IllegalArgumentException("input arrays in the same group must have equal length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment changeSeg = a.allocateFrom(JAVA_DOUBLE, change);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment newHighSeg = a.allocateFrom(JAVA_DOUBLE, newHigh);
MemorySegment newLowSeg = a.allocateFrom(JAVA_DOUBLE, newLow);
MemorySegment aboveMaSeg = a.allocateFrom(JAVA_DOUBLE, aboveMa);
MemorySegment onBuySignalSeg = a.allocateFrom(JAVA_DOUBLE, onBuySignal);
return (double) NativeMethods.WICKRA_ADVANCE_DECLINE_RATIO_UPDATE.invokeExact(handle, changeSeg, volumeSeg, newHighSeg, newLowSeg, aboveMaSeg, onBuySignalSeg, (long) change.length, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADVANCE_DECLINE_RATIO_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,62 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Adx indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Adx implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Adx(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADX_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Adx parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADX_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AdxOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(24L);
byte ok = (byte) NativeMethods.WICKRA_ADX_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AdxOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L),
out.get(JAVA_DOUBLE, 16L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADX_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AdxOutput(double plusDi, double minusDi, double adx) {}
@@ -0,0 +1,89 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Adxr indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Adxr implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Adxr(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ADXR_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Adxr parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ADXR_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ADXR_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ADXR_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ADXR_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,68 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Alligator indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Alligator implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Alligator(int jawPeriod, int teethPeriod, int lipsPeriod) {
if (jawPeriod < 0) {
throw new IllegalArgumentException("jawPeriod must be non-negative");
}
if (teethPeriod < 0) {
throw new IllegalArgumentException("teethPeriod must be non-negative");
}
if (lipsPeriod < 0) {
throw new IllegalArgumentException("lipsPeriod must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ALLIGATOR_NEW.invokeExact((long) jawPeriod, (long) teethPeriod, (long) lipsPeriod);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Alligator parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ALLIGATOR_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AlligatorOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(24L);
byte ok = (byte) NativeMethods.WICKRA_ALLIGATOR_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AlligatorOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L),
out.get(JAVA_DOUBLE, 16L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ALLIGATOR_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AlligatorOutput(double jaw, double teeth, double lips) {}
@@ -0,0 +1,69 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Alma indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Alma implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Alma(int period, double offset, double sigma) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ALMA_NEW.invokeExact((long) period, offset, sigma);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Alma parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ALMA_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_ALMA_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ALMA_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ALMA_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,73 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Alpha indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Alpha implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Alpha(int period, double riskFree) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ALPHA_NEW.invokeExact((long) period, riskFree);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Alpha parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ALPHA_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double x, double y) {
try {
return (double) NativeMethods.WICKRA_ALPHA_UPDATE.invokeExact(handle, x, y);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] x, double[] y) {
int n = x.length;
if (y.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment xSeg = a.allocateFrom(JAVA_DOUBLE, x);
MemorySegment ySeg = a.allocateFrom(JAVA_DOUBLE, y);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ALPHA_BATCH.invokeExact(handle, xSeg, ySeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ALPHA_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,54 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AmihudIlliquidity indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AmihudIlliquidity implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AmihudIlliquidity(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AMIHUD_ILLIQUIDITY_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AmihudIlliquidity parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AMIHUD_ILLIQUIDITY_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double price, double size, boolean isBuy, long timestamp) {
try {
return (double) NativeMethods.WICKRA_AMIHUD_ILLIQUIDITY_UPDATE.invokeExact(handle, price, size, (byte) (isBuy ? 1 : 0), timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AMIHUD_ILLIQUIDITY_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,66 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AnchoredRsi indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AnchoredRsi implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AnchoredRsi() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ANCHORED_RSI_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AnchoredRsi parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ANCHORED_RSI_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_ANCHORED_RSI_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ANCHORED_RSI_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ANCHORED_RSI_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AnchoredVwap indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AnchoredVwap implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AnchoredVwap() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ANCHORED_VWAP_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AnchoredVwap parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ANCHORED_VWAP_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ANCHORED_VWAP_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ANCHORED_VWAP_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ANCHORED_VWAP_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,62 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AndrewsPitchfork indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AndrewsPitchfork implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AndrewsPitchfork(int strength) {
if (strength < 0) {
throw new IllegalArgumentException("strength must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ANDREWS_PITCHFORK_NEW.invokeExact((long) strength);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AndrewsPitchfork parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ANDREWS_PITCHFORK_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AndrewsPitchforkOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(24L);
byte ok = (byte) NativeMethods.WICKRA_ANDREWS_PITCHFORK_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AndrewsPitchforkOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L),
out.get(JAVA_DOUBLE, 16L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ANDREWS_PITCHFORK_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AndrewsPitchforkOutput(double median, double upper, double lower) {}
@@ -0,0 +1,72 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Apo indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Apo implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Apo(int fast, int slow) {
if (fast < 0) {
throw new IllegalArgumentException("fast must be non-negative");
}
if (slow < 0) {
throw new IllegalArgumentException("slow must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_APO_NEW.invokeExact((long) fast, (long) slow);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Apo parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_APO_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_APO_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_APO_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_APO_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,61 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Aroon indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Aroon implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Aroon(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AROON_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Aroon parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AROON_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AroonOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(16L);
byte ok = (byte) NativeMethods.WICKRA_AROON_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AroonOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AROON_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,89 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AroonOscillator indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AroonOscillator implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AroonOscillator(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AROON_OSCILLATOR_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AroonOscillator parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AROON_OSCILLATOR_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_AROON_OSCILLATOR_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AROON_OSCILLATOR_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AROON_OSCILLATOR_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AroonOutput(double up, double down) {}
@@ -0,0 +1,89 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Atr indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Atr implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Atr(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ATR_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Atr parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ATR_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ATR_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ATR_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ATR_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,62 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AtrBands indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AtrBands implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AtrBands(int period, double multiplier) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ATR_BANDS_NEW.invokeExact((long) period, multiplier);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AtrBands parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ATR_BANDS_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AtrBandsOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(24L);
byte ok = (byte) NativeMethods.WICKRA_ATR_BANDS_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AtrBandsOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L),
out.get(JAVA_DOUBLE, 16L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ATR_BANDS_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AtrBandsOutput(double upper, double middle, double lower) {}
@@ -0,0 +1,61 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AtrRatchet indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AtrRatchet implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AtrRatchet(int atrPeriod, double startMult, double increment) {
if (atrPeriod < 0) {
throw new IllegalArgumentException("atrPeriod must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ATR_RATCHET_NEW.invokeExact((long) atrPeriod, startMult, increment);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AtrRatchet parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ATR_RATCHET_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AtrRatchetOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(16L);
byte ok = (byte) NativeMethods.WICKRA_ATR_RATCHET_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AtrRatchetOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ATR_RATCHET_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AtrRatchetOutput(double value, double direction) {}
@@ -0,0 +1,89 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AtrTrailingStop indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AtrTrailingStop implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AtrTrailingStop(int atrPeriod, double multiplier) {
if (atrPeriod < 0) {
throw new IllegalArgumentException("atrPeriod must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_ATR_TRAILING_STOP_NEW.invokeExact((long) atrPeriod, multiplier);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AtrTrailingStop parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_ATR_TRAILING_STOP_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_ATR_TRAILING_STOP_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_ATR_TRAILING_STOP_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_ATR_TRAILING_STOP_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,63 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AutoFib indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AutoFib implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AutoFib() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AUTO_FIB_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AutoFib parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AUTO_FIB_FREE);
}
/** Push one observation; returns the result, or null during warmup. */
public AutoFibOutput update(double open, double high, double low, double close, double volume, long timestamp) {
try (Arena a = Arena.ofConfined()) {
MemorySegment out = a.allocate(56L);
byte ok = (byte) NativeMethods.WICKRA_AUTO_FIB_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp, out);
if (ok == 0) {
return null;
}
return new AutoFibOutput(
out.get(JAVA_DOUBLE, 0L),
out.get(JAVA_DOUBLE, 8L),
out.get(JAVA_DOUBLE, 16L),
out.get(JAVA_DOUBLE, 24L),
out.get(JAVA_DOUBLE, 32L),
out.get(JAVA_DOUBLE, 40L),
out.get(JAVA_DOUBLE, 48L));
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AUTO_FIB_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,5 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
/** Output record produced by the matching indicator. */
public record AutoFibOutput(double level0, double level236, double level382, double level500, double level618, double level786, double level1000) {}
@@ -0,0 +1,72 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Autocorrelation indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Autocorrelation implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Autocorrelation(int period, int lag) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
if (lag < 0) {
throw new IllegalArgumentException("lag must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AUTOCORRELATION_NEW.invokeExact((long) period, (long) lag);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Autocorrelation parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AUTOCORRELATION_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_AUTOCORRELATION_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AUTOCORRELATION_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AUTOCORRELATION_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,72 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AutocorrelationPeriodogram indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AutocorrelationPeriodogram implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AutocorrelationPeriodogram(int minPeriod, int maxPeriod) {
if (minPeriod < 0) {
throw new IllegalArgumentException("minPeriod must be non-negative");
}
if (maxPeriod < 0) {
throw new IllegalArgumentException("maxPeriod must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AUTOCORRELATION_PERIODOGRAM_NEW.invokeExact((long) minPeriod, (long) maxPeriod);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AutocorrelationPeriodogram parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AUTOCORRELATION_PERIODOGRAM_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_AUTOCORRELATION_PERIODOGRAM_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AUTOCORRELATION_PERIODOGRAM_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AUTOCORRELATION_PERIODOGRAM_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,89 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AverageDailyRange indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AverageDailyRange implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AverageDailyRange(int period, int utcOffsetMinutes) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AVERAGE_DAILY_RANGE_NEW.invokeExact((long) period, utcOffsetMinutes);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AverageDailyRange parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AVERAGE_DAILY_RANGE_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_AVERAGE_DAILY_RANGE_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AVERAGE_DAILY_RANGE_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AVERAGE_DAILY_RANGE_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,69 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AverageDrawdown indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AverageDrawdown implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AverageDrawdown(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AVERAGE_DRAWDOWN_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AverageDrawdown parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AVERAGE_DRAWDOWN_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_AVERAGE_DRAWDOWN_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AVERAGE_DRAWDOWN_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AVERAGE_DRAWDOWN_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AvgPrice indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AvgPrice implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AvgPrice() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AVG_PRICE_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AvgPrice parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AVG_PRICE_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_AVG_PRICE_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AVG_PRICE_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AVG_PRICE_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,92 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AwesomeOscillator indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AwesomeOscillator implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AwesomeOscillator(int fast, int slow) {
if (fast < 0) {
throw new IllegalArgumentException("fast must be non-negative");
}
if (slow < 0) {
throw new IllegalArgumentException("slow must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AWESOME_OSCILLATOR_NEW.invokeExact((long) fast, (long) slow);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AwesomeOscillator parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AWESOME_OSCILLATOR_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_AWESOME_OSCILLATOR_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AWESOME_OSCILLATOR_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AWESOME_OSCILLATOR_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,95 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming AwesomeOscillatorHistogram indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class AwesomeOscillatorHistogram implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public AwesomeOscillatorHistogram(int fast, int slow, int smaPeriod) {
if (fast < 0) {
throw new IllegalArgumentException("fast must be non-negative");
}
if (slow < 0) {
throw new IllegalArgumentException("slow must be non-negative");
}
if (smaPeriod < 0) {
throw new IllegalArgumentException("smaPeriod must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_AWESOME_OSCILLATOR_HISTOGRAM_NEW.invokeExact((long) fast, (long) slow, (long) smaPeriod);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid AwesomeOscillatorHistogram parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_AWESOME_OSCILLATOR_HISTOGRAM_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_AWESOME_OSCILLATOR_HISTOGRAM_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_AWESOME_OSCILLATOR_HISTOGRAM_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_AWESOME_OSCILLATOR_HISTOGRAM_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming BalanceOfPower indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class BalanceOfPower implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public BalanceOfPower() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_BALANCE_OF_POWER_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid BalanceOfPower parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_BALANCE_OF_POWER_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_BALANCE_OF_POWER_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_BALANCE_OF_POWER_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_BALANCE_OF_POWER_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,69 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming BandpassFilter indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class BandpassFilter implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public BandpassFilter(int period, double bandwidth) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_BANDPASS_FILTER_NEW.invokeExact((long) period, bandwidth);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid BandpassFilter parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_BANDPASS_FILTER_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double value) {
try {
return (double) NativeMethods.WICKRA_BANDPASS_FILTER_UPDATE.invokeExact(handle, value);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] input) {
int n = input.length;
try (Arena a = Arena.ofConfined()) {
MemorySegment inputSeg = a.allocateFrom(JAVA_DOUBLE, input);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_BANDPASS_FILTER_BATCH.invokeExact(handle, inputSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_BANDPASS_FILTER_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Bat indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Bat implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Bat() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_BAT_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Bat parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_BAT_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_BAT_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_BAT_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_BAT_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,86 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming BeltHold indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class BeltHold implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public BeltHold() {
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_BELT_HOLD_NEW.invokeExact();
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid BeltHold parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_BELT_HOLD_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_BELT_HOLD_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_BELT_HOLD_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_BELT_HOLD_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,73 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming Beta indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class Beta implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public Beta(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_BETA_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid Beta parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_BETA_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double x, double y) {
try {
return (double) NativeMethods.WICKRA_BETA_UPDATE.invokeExact(handle, x, y);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] x, double[] y) {
int n = x.length;
if (y.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment xSeg = a.allocateFrom(JAVA_DOUBLE, x);
MemorySegment ySeg = a.allocateFrom(JAVA_DOUBLE, y);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_BETA_BATCH.invokeExact(handle, xSeg, ySeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_BETA_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,73 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming BetaNeutralSpread indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class BetaNeutralSpread implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public BetaNeutralSpread(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_BETA_NEUTRAL_SPREAD_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid BetaNeutralSpread parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_BETA_NEUTRAL_SPREAD_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double x, double y) {
try {
return (double) NativeMethods.WICKRA_BETA_NEUTRAL_SPREAD_UPDATE.invokeExact(handle, x, y);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] x, double[] y) {
int n = x.length;
if (y.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment xSeg = a.allocateFrom(JAVA_DOUBLE, x);
MemorySegment ySeg = a.allocateFrom(JAVA_DOUBLE, y);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_BETA_NEUTRAL_SPREAD_BATCH.invokeExact(handle, xSeg, ySeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_BETA_NEUTRAL_SPREAD_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}
@@ -0,0 +1,89 @@
// Generated from bindings/c/include/wickra.h. Do not edit by hand.
package org.wickra;
import org.wickra.internal.NativeMethods;
import org.wickra.internal.WickraNative;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Cleaner;
import static java.lang.foreign.ValueLayout.*;
/** Streaming BetterVolume indicator over the Wickra C ABI. Not thread-safe; close when done. */
public final class BetterVolume implements AutoCloseable {
private final MemorySegment handle;
private final Cleaner.Cleanable cleanable;
public BetterVolume(int period) {
if (period < 0) {
throw new IllegalArgumentException("period must be non-negative");
}
MemorySegment h;
try {
h = (MemorySegment) NativeMethods.WICKRA_BETTER_VOLUME_NEW.invokeExact((long) period);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
if (h.address() == 0L) {
throw new IllegalArgumentException("invalid BetterVolume parameters");
}
this.handle = h;
this.cleanable = WickraNative.register(this, h, NativeMethods.WICKRA_BETTER_VOLUME_FREE);
}
/** Push one observation; returns the indicator value (NaN during warmup). */
public double update(double open, double high, double low, double close, double volume, long timestamp) {
try {
return (double) NativeMethods.WICKRA_BETTER_VOLUME_UPDATE.invokeExact(handle, open, high, low, close, volume, timestamp);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Vectorized update over a whole series; NaN at warmup positions. */
public double[] batch(double[] open, double[] high, double[] low, double[] close, double[] volume, double[] timestamp) {
int n = open.length;
if (high.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (low.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (close.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (volume.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
if (timestamp.length != n) {
throw new IllegalArgumentException("all input arrays must have the same length");
}
try (Arena a = Arena.ofConfined()) {
MemorySegment openSeg = a.allocateFrom(JAVA_DOUBLE, open);
MemorySegment highSeg = a.allocateFrom(JAVA_DOUBLE, high);
MemorySegment lowSeg = a.allocateFrom(JAVA_DOUBLE, low);
MemorySegment closeSeg = a.allocateFrom(JAVA_DOUBLE, close);
MemorySegment volumeSeg = a.allocateFrom(JAVA_DOUBLE, volume);
MemorySegment timestampSeg = a.allocateFrom(JAVA_DOUBLE, timestamp);
MemorySegment outSeg = a.allocate(JAVA_DOUBLE.byteSize() * n);
NativeMethods.WICKRA_BETTER_VOLUME_BATCH.invokeExact(handle, openSeg, highSeg, lowSeg, closeSeg, volumeSeg, timestampSeg, outSeg, (long) n);
double[] out = new double[n];
MemorySegment.copy(outSeg, JAVA_DOUBLE, 0L, out, 0, n);
return out;
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
/** Reset to the just-constructed state. */
public void reset() {
try {
NativeMethods.WICKRA_BETTER_VOLUME_RESET.invokeExact(handle);
} catch (Throwable t) {
throw WickraNative.rethrow(t);
}
}
@Override public void close() {
cleanable.clean();
}
}

Some files were not shown because too many files have changed in this diff Show More