Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b31a9a3624 | |||
| 6433c9b3de | |||
| 447bbc8220 | |||
| c9ef2fc037 | |||
| 49c2872ad4 | |||
| 0c4bbaf314 | |||
| 99ad2ab107 | |||
| 8e225a5872 | |||
| 87bb008aa1 | |||
| b06ce2678a | |||
| 5b7523265c | |||
| d188959aab | |||
| 167f7b3ffe | |||
| 8659b42bef | |||
| b7ef63400d | |||
| 8225e1ab91 | |||
| d0061c73b8 | |||
| 23d636fd97 | |||
| fce26cf881 | |||
| 91f6f67257 | |||
| 4caaa1db97 | |||
| 12681e4b1b | |||
| 91e05e3c26 | |||
| 9d0983b666 |
@@ -1,3 +1,34 @@
|
||||
# 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. The vendored C ABI header is
|
||||
# a committed copy of bindings/c/include/wickra.h (the parent dir is outside the
|
||||
# Go module), pinned to LF so the drift check never trips on CRLF.
|
||||
*.go text eol=lf
|
||||
go.mod text eol=lf
|
||||
go.sum text eol=lf
|
||||
bindings/go/include/wickra.h 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 text eol=lf
|
||||
bindings/r/configure.win text eol=lf
|
||||
bindings/r/src/Makevars.in text eol=lf
|
||||
bindings/r/src/Makevars.win text eol=lf
|
||||
bindings/r/src/wickra.c text eol=lf
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -622,6 +622,375 @@ 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: Vendored header in sync with the C ABI
|
||||
shell: bash
|
||||
# bindings/go/include/wickra.h is a committed copy of the cbindgen header
|
||||
# (the parent ../c/include is outside the Go module, so it must be
|
||||
# vendored). Fail if it drifts from the source of truth.
|
||||
run: |
|
||||
if ! diff -u bindings/c/include/wickra.h bindings/go/include/wickra.h; then
|
||||
echo "::error::bindings/go/include/wickra.h is stale — copy bindings/c/include/wickra.h over it"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Stage the native library
|
||||
shell: bash
|
||||
# Stage into lib/<goos>_<goarch>/ to match the per-platform cgo LDFLAGS.
|
||||
# CI builds the host target, so RUNNER_OS/ARCH give the right directory
|
||||
# (note macos-latest is arm64).
|
||||
run: |
|
||||
case "$RUNNER_ARCH" in
|
||||
X64) arch=amd64 ;;
|
||||
ARM64) arch=arm64 ;;
|
||||
*) echo "::error::unsupported RUNNER_ARCH '$RUNNER_ARCH'"; exit 1 ;;
|
||||
esac
|
||||
case "$RUNNER_OS" in
|
||||
Linux) dir="linux_$arch"; lib=target/release/libwickra.so ;;
|
||||
macOS) dir="darwin_$arch"; lib=target/release/libwickra.dylib ;;
|
||||
Windows) dir="windows_$arch"; lib=target/release/wickra.dll ;;
|
||||
esac
|
||||
mkdir -p "bindings/go/lib/$dir"
|
||||
cp "$lib" "bindings/go/lib/$dir/"
|
||||
echo "WICKRA_GO_LIBDIR=$PWD/bindings/go/lib/$dir" >> "$GITHUB_ENV"
|
||||
|
||||
- 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
|
||||
# (WICKRA_GO_LIBDIR is the per-platform staged lib dir). Linux/macOS use
|
||||
# the rpath baked by the per-platform cgo LDFLAGS.
|
||||
run: |
|
||||
export PATH="$WICKRA_GO_LIBDIR:$PATH"
|
||||
cd bindings/go
|
||||
go vet ./...
|
||||
go test ./...
|
||||
|
||||
- name: Build the Go examples
|
||||
shell: bash
|
||||
run: |
|
||||
export PATH="$WICKRA_GO_LIBDIR:$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="$WICKRA_GO_LIBDIR:$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. WICKRA_*_DIR makes configure use the locally
|
||||
# built C ABI (dev override) instead of downloading the release asset, so
|
||||
# CI is version-independent. Deliberately do NOT set LD_LIBRARY_PATH /
|
||||
# DYLD_LIBRARY_PATH: the lib is bundled into the package and must resolve
|
||||
# via the rpath ($ORIGIN / @loader_path) baked by configure — that is the
|
||||
# self-contained install path real users (and r-universe) get.
|
||||
run: |
|
||||
export WICKRA_INCLUDE_DIR="${WICKRA_INCLUDE_DIR//\\//}"
|
||||
export WICKRA_LIB_DIR="${WICKRA_LIB_DIR//\\//}"
|
||||
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
|
||||
# No loader-path exports: the installed package is self-contained (bundled
|
||||
# lib + rpath), so the examples exercise exactly what end users run.
|
||||
run: |
|
||||
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
|
||||
|
||||
@@ -569,9 +569,306 @@ 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
|
||||
|
||||
# Mirror the in-repo Go module (bindings/go) to the standalone wickra-go
|
||||
# repository so `go get github.com/wickra-lib/wickra-go` builds with no extra
|
||||
# steps. The in-repo module keeps the prebuilt libraries git-ignored; the
|
||||
# mirror commits them per platform under lib/<goos>_<goarch>/ alongside the
|
||||
# vendored header. Independent of the GitHub-release job so a Go hiccup never
|
||||
# blocks the C/C++ asset release. The push uses a fine-grained PAT
|
||||
# (WICKRA_GO_MIRROR_TOKEN, contents:write on wickra-go); the mirror is a
|
||||
# derived artifact, so its bot commit is intentionally unsigned.
|
||||
go-mirror:
|
||||
name: Mirror the Go module to wickra-go
|
||||
needs: c-abi-build
|
||||
runs-on: ubuntu-latest
|
||||
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: Assemble the wickra-go module tree
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
out=wickra-go-module
|
||||
mkdir -p "$out/include" "$out/lib"
|
||||
# Single-package Go source + vendored C ABI header.
|
||||
cp bindings/go/*.go "$out/"
|
||||
cp bindings/go/include/wickra.h "$out/include/"
|
||||
cp bindings/go/README.md "$out/"
|
||||
# Ship the dual license so pkg.go.dev detects a redistributable license.
|
||||
cp LICENSE-MIT LICENSE-APACHE "$out/"
|
||||
# Standalone module path (the in-repo go.mod points at the subdir).
|
||||
printf 'module github.com/wickra-lib/wickra-go\n\ngo 1.23\n' > "$out/go.mod"
|
||||
# Point install instructions at the standalone module path.
|
||||
sed -i 's#github.com/wickra-lib/wickra/bindings/go#github.com/wickra-lib/wickra-go#g' \
|
||||
"$out/README.md" "$out"/*.go
|
||||
# Stage each prebuilt library under lib/<goos>_<goarch>/ (committed in
|
||||
# the mirror, unlike the in-repo lib/.gitignore). "<dir> <libfile>".
|
||||
declare -A GO=(
|
||||
[x86_64-unknown-linux-gnu]="linux_amd64 libwickra.so"
|
||||
[aarch64-unknown-linux-gnu]="linux_arm64 libwickra.so"
|
||||
[x86_64-apple-darwin]="darwin_amd64 libwickra.dylib"
|
||||
[aarch64-apple-darwin]="darwin_arm64 libwickra.dylib"
|
||||
[x86_64-pc-windows-msvc]="windows_amd64 wickra.dll"
|
||||
[aarch64-pc-windows-msvc]="windows_arm64 wickra.dll"
|
||||
)
|
||||
for target in "${!GO[@]}"; do
|
||||
read -r dir libfile <<< "${GO[$target]}"
|
||||
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"
|
||||
src=$(find "$tmp" -name "$libfile" | head -1)
|
||||
if [ -z "$src" ]; then
|
||||
echo "::error::missing $libfile for $target"; exit 1
|
||||
fi
|
||||
mkdir -p "$out/lib/$dir"; cp "$src" "$out/lib/$dir/"
|
||||
done
|
||||
echo "assembled module:"; find "$out" -type f | sort
|
||||
|
||||
- name: Push to wickra-go and tag the release
|
||||
shell: bash
|
||||
env:
|
||||
MIRROR_TOKEN: ${{ secrets.WICKRA_GO_MIRROR_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
version="${GITHUB_REF_NAME#v}"
|
||||
remote="https://x-access-token:${MIRROR_TOKEN}@github.com/wickra-lib/wickra-go.git"
|
||||
git clone -q "$remote" mirror-repo
|
||||
cd mirror-repo
|
||||
git config user.name "wickra-bot"
|
||||
git config user.email "support@wickra.org"
|
||||
git symbolic-ref HEAD refs/heads/main
|
||||
# Replace all tracked content with the freshly assembled tree.
|
||||
find . -mindepth 1 -maxdepth 1 -not -name .git -exec rm -rf {} +
|
||||
cp -r ../wickra-go-module/. .
|
||||
git add -A
|
||||
if git diff --cached --quiet; then
|
||||
echo "wickra-go already up to date; tagging only"
|
||||
else
|
||||
git -c commit.gpgsign=false commit -q -m "Release v$version"
|
||||
fi
|
||||
git push origin HEAD:refs/heads/main
|
||||
git tag "v$version"
|
||||
git push origin "v$version"
|
||||
|
||||
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 +941,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 +962,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
|
||||
|
||||
|
||||
@@ -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).
|
||||
@@ -325,12 +332,14 @@ jobs:
|
||||
exit 0
|
||||
fi
|
||||
cd docs-ver
|
||||
# Published-versions table rows (crates.io / PyPI / npm): replace only the
|
||||
# version number, leaving the trailing padding + pipe intact. The '.' in
|
||||
# the quickstart pattern matches the literal backtick around the version
|
||||
# without needing a backtick in this shell string. Historical "since
|
||||
# X.Y.Z" references contain no such anchor and are never matched.
|
||||
sed -i -E "s/^(\| (crates\.io|PyPI|npm) .*\| )[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" overview.md
|
||||
# Published-versions table rows (all registries): replace only the
|
||||
# version number, leaving the trailing padding + pipe intact. The
|
||||
# registry name is matched whether plain or wrapped in a markdown link
|
||||
# (\[?...\]?). The '.' in the quickstart pattern matches the literal
|
||||
# backtick around the version without needing a backtick in this shell
|
||||
# string. Historical "since X.Y.Z" references contain no such anchor and
|
||||
# are never matched.
|
||||
sed -i -E "s/^(\| \[?(crates\.io|PyPI|npm|NuGet|Maven Central|Go|r-universe)\]?.*\| )[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" overview.md
|
||||
sed -i -E "s/(published crate is at version .)[0-9]+\.[0-9]+\.[0-9]+/\1${version}/" Quickstart-Rust.md
|
||||
if git diff --quiet; then
|
||||
echo "Docs version already at ${version}."
|
||||
@@ -366,14 +375,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
@@ -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
|
||||
|
||||
+88
-2
@@ -5,7 +5,85 @@ 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.8.2] - 2026-06-10
|
||||
### Fixed
|
||||
- **R binding builds for WebAssembly** — `bindings/r/configure` now builds the
|
||||
C ABI from source for the `wasm32-unknown-emscripten` target (r-universe /
|
||||
webR) using the build image's cargo + emscripten, instead of failing with
|
||||
"unsupported OS Emscripten". rayon is dropped on wasm via
|
||||
`--no-default-features`; the indicators are pure computation, so the serial
|
||||
path is functionally identical.
|
||||
|
||||
## [0.8.1] - 2026-06-10
|
||||
### Fixed
|
||||
- **`wickra-go` license** — the release-time Go module mirror now ships the dual
|
||||
`LICENSE-MIT` and `LICENSE-APACHE` files, so pkg.go.dev detects a
|
||||
redistributable license for `github.com/wickra-lib/wickra-go`. The previous
|
||||
mirror shipped no license file.
|
||||
|
||||
## [0.8.0] - 2026-06-09
|
||||
### Added
|
||||
- **Standalone `wickra-go` module** — the Go binding is now mirrored to a
|
||||
dedicated `github.com/wickra-lib/wickra-go` repository on every release, with
|
||||
the prebuilt C ABI libraries committed per platform under
|
||||
`lib/<goos>_<goarch>/` and the C ABI header vendored alongside the source, so
|
||||
`go get github.com/wickra-lib/wickra-go` builds with no extra steps. The
|
||||
in-repo `bindings/go` module is unchanged for repo-clone workflows.
|
||||
|
||||
### Changed
|
||||
- **Go binding (`bindings/go`) is self-contained** — the C ABI header is now
|
||||
vendored inside the module (`bindings/go/include/wickra.h`) instead of being
|
||||
referenced from the parent `bindings/c` directory, and the cgo link flags
|
||||
resolve the prebuilt library per `GOOS`/`GOARCH` under `lib/<goos>_<goarch>/`.
|
||||
This removes the dependency on a full repository checkout for building the
|
||||
module.
|
||||
|
||||
## [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`).
|
||||
@@ -1416,7 +1494,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.4...HEAD
|
||||
[Unreleased]: https://github.com/wickra-lib/wickra/compare/v0.8.2...HEAD
|
||||
[0.8.2]: https://github.com/wickra-lib/wickra/compare/v0.8.1...v0.8.2
|
||||
[0.8.1]: https://github.com/wickra-lib/wickra/compare/v0.8.0...v0.8.1
|
||||
[0.8.0]: https://github.com/wickra-lib/wickra/compare/v0.7.9...v0.8.0
|
||||
[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
|
||||
|
||||
+15
-1
@@ -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
@@ -1944,7 +1944,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"criterion",
|
||||
@@ -1955,7 +1955,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-bench"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"kand",
|
||||
@@ -1965,9 +1965,16 @@ dependencies = [
|
||||
"yata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wickra-c"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"wickra-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wickra-core"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"proptest",
|
||||
@@ -1977,7 +1984,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-data"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"csv",
|
||||
@@ -1994,7 +2001,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-examples"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"tokio",
|
||||
@@ -2004,7 +2011,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-node"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"napi",
|
||||
"napi-build",
|
||||
@@ -2014,7 +2021,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-python"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"numpy",
|
||||
"pyo3",
|
||||
@@ -2023,7 +2030,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-wasm"
|
||||
version = "0.7.4"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
|
||||
+3
-2
@@ -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.4"
|
||||
version = "0.8.2"
|
||||
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.4" }
|
||||
wickra-core = { path = "crates/wickra-core", version = "0.8.2" }
|
||||
|
||||
thiserror = "2"
|
||||
rayon = "1.10"
|
||||
|
||||
@@ -2,24 +2,29 @@
|
||||
<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>
|
||||
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/codeql.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
[](https://github.com/wickra-lib/wickra/releases/latest)
|
||||
[](https://crates.io/crates/wickra)
|
||||
[](https://pypi.org/project/wickra/)
|
||||
[](https://www.npmjs.com/package/wickra)
|
||||
[](#license)
|
||||
[](https://scorecard.dev/viewer/?uri=github.com/wickra-lib/wickra)
|
||||
[](https://www.bestpractices.dev/projects/13094)
|
||||
[](https://github.com/wickra-lib/wickra/attestations)
|
||||
[](https://docs.wickra.org)
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/codeql.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
[](https://github.com/wickra-lib/wickra/releases/latest)
|
||||
[](https://crates.io/crates/wickra)
|
||||
[](https://pypi.org/project/wickra/)
|
||||
[](https://www.npmjs.com/package/wickra)
|
||||
[](https://www.nuget.org/packages/Wickra)
|
||||
[](https://central.sonatype.com/artifact/org.wickra/wickra)
|
||||
[](https://pkg.go.dev/github.com/wickra-lib/wickra-go)
|
||||
[](https://wickra-lib.r-universe.dev)
|
||||
[](#license)
|
||||
[](https://scorecard.dev/viewer/?uri=github.com/wickra-lib/wickra)
|
||||
[](https://www.bestpractices.dev/projects/13094)
|
||||
[](https://github.com/wickra-lib/wickra/attestations)
|
||||
[](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,7 +51,12 @@ 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),
|
||||
[Java](https://docs.wickra.org/Quickstart-Java),
|
||||
[R](https://docs.wickra.org/Quickstart-R).
|
||||
- **Indicators** — a per-indicator deep dive (formula, parameters, warmup) for
|
||||
every one of the 514 indicators; start at the
|
||||
[indicators overview](https://docs.wickra.org/Indicators-Overview).
|
||||
@@ -71,9 +81,10 @@ times to get there.
|
||||
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
|
||||
@@ -95,7 +106,7 @@ Every other library forces one of those compromises. Wickra doesn't:
|
||||
|
||||
| Library | Install | Streaming | Languages | Indicators | Active |
|
||||
|------------------|-------------|-------------|-----------------------------|-----------:|--------|
|
||||
| **★ Wickra**| **clean** | **yes, O(1)** | **Python · Node · WASM · Rust** | **514** | **yes** |
|
||||
| **★ Wickra**| **clean** | **yes, O(1)** | **Rust · Python · Node · WASM · C · C# · Go · Java · R** | **514** | **yes** |
|
||||
| kand | clean | yes | Python · WASM · Rust | ~60 | yes |
|
||||
| ta-rs | clean | yes | Rust only | ~30 | stale |
|
||||
| yata | clean | partial | Rust only | ~35 | yes |
|
||||
@@ -166,8 +177,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 +189,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
|
||||
|
||||
@@ -244,13 +262,23 @@ wickra/
|
||||
├── 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 +306,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 +344,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
@@ -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
@@ -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
@@ -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
@@ -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. |
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
[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"
|
||||
|
||||
[features]
|
||||
# `parallel` (rayon-backed batch in wickra-core) is on by default for native
|
||||
# builds. The wasm32-unknown-emscripten target has no threads, so the R
|
||||
# package's wasm build (r-universe / webR) compiles this crate with
|
||||
# --no-default-features to drop rayon; wickra-core falls back to its serial
|
||||
# batch path, which is cfg-gated behind the same feature.
|
||||
default = ["parallel"]
|
||||
parallel = ["wickra-core/parallel"]
|
||||
|
||||
[dependencies]
|
||||
# Direct path dep rather than `workspace = true`: a member-level
|
||||
# `default-features = false` is ignored when inheriting a workspace dep that
|
||||
# does not set it, which would leave rayon in the wasm build. wickra-c is
|
||||
# `publish = false`, so no version pin is needed (and none to keep in sync).
|
||||
wickra-core = { path = "../../crates/wickra-core", default-features = false }
|
||||
@@ -0,0 +1,80 @@
|
||||
# Wickra — C / C++
|
||||
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
[](https://github.com/wickra-lib/wickra/releases/latest)
|
||||
[](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.
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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/
|
||||
@@ -0,0 +1,78 @@
|
||||
# Wickra — .NET
|
||||
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
[](https://www.nuget.org/packages/Wickra)
|
||||
[](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));
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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.8.2</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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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/<rid>/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";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
# Wickra — Go
|
||||
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
[](https://pkg.go.dev/github.com/wickra-lib/wickra/bindings/go)
|
||||
[](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
|
||||
|
||||
Use the published **`wickra-go`** module, which bundles the prebuilt C ABI
|
||||
library for every platform, so `go get` + `go build` works with no extra steps
|
||||
(a C compiler is still required, as the binding uses cgo):
|
||||
|
||||
```bash
|
||||
go get github.com/wickra-lib/wickra-go
|
||||
```
|
||||
|
||||
```go
|
||||
import wickra "github.com/wickra-lib/wickra-go"
|
||||
```
|
||||
|
||||
`wickra-go` is generated from this directory by the release pipeline: it mirrors
|
||||
the Go sources, the vendored C ABI header (`include/wickra.h`) and the prebuilt
|
||||
libraries under `lib/<goos>_<goarch>/`. On Linux/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`).
|
||||
|
||||
### Building from this repository (contributors)
|
||||
|
||||
This `bindings/go` directory is the development source. To build it directly,
|
||||
compile the C ABI and stage the library into the per-platform directory cgo
|
||||
links against:
|
||||
|
||||
```bash
|
||||
cargo build -p wickra-c --release
|
||||
mkdir -p bindings/go/lib/linux_amd64 # match your GOOS_GOARCH
|
||||
cp target/release/libwickra.so bindings/go/lib/linux_amd64/ # Linux
|
||||
cp target/release/libwickra.dylib bindings/go/lib/darwin_arm64/ # macOS (arm64)
|
||||
cp target/release/wickra.dll bindings/go/lib/windows_amd64/ # Windows
|
||||
```
|
||||
|
||||
## 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.
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
# Prebuilt Wickra C ABI libraries are provisioned locally / in CI, not committed.
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
*.a
|
||||
*.lib
|
||||
*.exp
|
||||
@@ -0,0 +1,30 @@
|
||||
// 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, staged
|
||||
// per platform under ./lib/<goos>_<goarch>/, with the C ABI header vendored
|
||||
// under ./include. For distribution the libraries are committed alongside the
|
||||
// source in the wickra-go module, so `go get` + `go build` works with no extra
|
||||
// steps — see the package README.
|
||||
package wickra
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I${SRCDIR}/include
|
||||
#cgo linux,amd64 LDFLAGS: -L${SRCDIR}/lib/linux_amd64 -lwickra -Wl,-rpath,${SRCDIR}/lib/linux_amd64
|
||||
#cgo linux,arm64 LDFLAGS: -L${SRCDIR}/lib/linux_arm64 -lwickra -Wl,-rpath,${SRCDIR}/lib/linux_arm64
|
||||
#cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/lib/darwin_amd64 -lwickra -Wl,-rpath,${SRCDIR}/lib/darwin_amd64
|
||||
#cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/lib/darwin_arm64 -lwickra -Wl,-rpath,${SRCDIR}/lib/darwin_arm64
|
||||
#cgo windows,amd64 LDFLAGS: -L${SRCDIR}/lib/windows_amd64 -l:wickra.dll
|
||||
#cgo windows,arm64 LDFLAGS: -L${SRCDIR}/lib/windows_arm64 -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")
|
||||
@@ -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
|
||||
}
|
||||
@@ -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/
|
||||
@@ -0,0 +1,102 @@
|
||||
# Wickra — Java
|
||||
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
[](https://central.sonatype.com/artifact/org.wickra/wickra)
|
||||
[](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.8.2</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Gradle:
|
||||
|
||||
```kotlin
|
||||
implementation("org.wickra:wickra:0.8.2")
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -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.8.2</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();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user