Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8659b42bef | |||
| b7ef63400d | |||
| 8225e1ab91 | |||
| d0061c73b8 | |||
| 23d636fd97 | |||
| fce26cf881 | |||
| 91f6f67257 | |||
| 4caaa1db97 | |||
| 12681e4b1b | |||
| 91e05e3c26 | |||
| 9d0983b666 |
@@ -1,3 +1,26 @@
|
||||
# Shell scripts must keep LF line endings so they run on Linux/macOS CI and
|
||||
# local shells regardless of the committer's platform autocrlf setting.
|
||||
*.sh text eol=lf
|
||||
|
||||
# The cbindgen-generated C header is committed; pin it to LF so its CI drift
|
||||
# check (regenerate + `git diff`) never trips on a CRLF normalization.
|
||||
bindings/c/include/wickra.h text eol=lf
|
||||
|
||||
# C# sources (including the generated binding) are pinned to LF so the committed
|
||||
# files stay stable regardless of the committer's autocrlf setting.
|
||||
*.cs text eol=lf
|
||||
|
||||
# Go sources (including the generated binding) are pinned to LF so gofmt's CI
|
||||
# check never trips on a CRLF checkout on Windows.
|
||||
*.go text eol=lf
|
||||
go.mod text eol=lf
|
||||
go.sum text eol=lf
|
||||
|
||||
# R binding: `R CMD check` requires LF in sources, Makevars and shell scripts.
|
||||
*.R text eol=lf
|
||||
*.Rd text eol=lf
|
||||
bindings/r/configure.win text eol=lf
|
||||
bindings/r/src/Makevars text eol=lf
|
||||
bindings/r/src/Makevars.win text eol=lf
|
||||
bindings/r/src/wickra.c text eol=lf
|
||||
|
||||
|
||||
@@ -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 / R -->
|
||||
- OS and architecture:
|
||||
- Rust / Python / Node version (If relevant):
|
||||
- Rust / Python / Node / .NET version (If relevant):
|
||||
|
||||
## Additional context
|
||||
|
||||
|
||||
@@ -26,7 +26,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,10 @@ 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 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 / 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 / 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 + 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,10 @@ 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`)
|
||||
- [ ] R binding (`bindings/r`)
|
||||
- [ ] Examples / docs
|
||||
|
||||
## Linked issues
|
||||
|
||||
@@ -622,6 +622,280 @@ jobs:
|
||||
working-directory: bindings/node
|
||||
run: node --test __tests__/
|
||||
|
||||
c-abi:
|
||||
name: C ABI on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
|
||||
- name: Cache cargo
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
|
||||
timeout-minutes: 6
|
||||
|
||||
- name: Install cbindgen
|
||||
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
||||
timeout-minutes: 10 # fail fast on a stuck download instead of hanging the job
|
||||
with:
|
||||
tool: cbindgen
|
||||
|
||||
- name: Build the C ABI library (cdylib + staticlib)
|
||||
run: cargo build -p wickra-c --release
|
||||
|
||||
- name: Rust unit tests
|
||||
run: cargo test -p wickra-c
|
||||
|
||||
# The generated header is platform-independent, so checking drift on one OS
|
||||
# is enough — and avoids a spurious CRLF/LF diff on the Windows runner.
|
||||
- name: Check the committed header is in sync with cbindgen
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: |
|
||||
cbindgen --config bindings/c/cbindgen.toml --crate wickra-c --output bindings/c/include/wickra.h
|
||||
if ! git diff --quiet -- bindings/c/include/wickra.h; then
|
||||
echo "::error::bindings/c/include/wickra.h is out of sync — run cbindgen and commit the result"
|
||||
git --no-pager diff -- bindings/c/include/wickra.h
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The real cross-language test: a foreign C consumer links the generated
|
||||
# header + the compiled library and runs. If this passes on all three OSes,
|
||||
# every C-capable language can link the same way.
|
||||
- name: Build and run the C smoke example (CMake + ctest)
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -S examples/c -B examples/c/build
|
||||
cmake --build examples/c/build --config Release
|
||||
ctest --test-dir examples/c/build -C Release --output-on-failure
|
||||
|
||||
csharp:
|
||||
name: C# on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
|
||||
- name: Cache cargo
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
|
||||
timeout-minutes: 6
|
||||
|
||||
# The binding links against the C ABI hub at runtime; build it first so the
|
||||
# DllImportResolver finds target/release/wickra.{dll,so,dylib}. .NET 8 SDK is
|
||||
# preinstalled on the GitHub runners, so no setup-dotnet step is needed.
|
||||
- name: Build the C ABI library
|
||||
run: cargo build -p wickra-c --release
|
||||
|
||||
- name: .NET info
|
||||
run: dotnet --info
|
||||
|
||||
- name: Test the C# binding
|
||||
run: dotnet test bindings/csharp/Wickra.Tests/Wickra.Tests.csproj -c Release
|
||||
|
||||
- name: Build the C# examples
|
||||
shell: bash
|
||||
run: |
|
||||
for d in streaming backtest multi_timeframe parallel_assets \
|
||||
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze \
|
||||
fetch_btcusdt live_binance; do
|
||||
dotnet build "examples/csharp/$d" -c Release
|
||||
done
|
||||
|
||||
# Run only the offline examples (fetch_btcusdt / live_binance need network).
|
||||
- name: Run the offline C# examples
|
||||
shell: bash
|
||||
run: |
|
||||
for d in streaming backtest multi_timeframe parallel_assets \
|
||||
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze; do
|
||||
dotnet run --project "examples/csharp/$d" -c Release --no-build
|
||||
done
|
||||
|
||||
go:
|
||||
name: Go on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# Go is not reliably on PATH on every runner image, so install it
|
||||
# explicitly. cache: false — the cargo build dominates and the modules
|
||||
# have no external Go deps worth caching.
|
||||
- name: Set up Go
|
||||
id: setup-go
|
||||
continue-on-error: true
|
||||
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
|
||||
with:
|
||||
go-version: "stable"
|
||||
cache: false
|
||||
|
||||
- name: Retry Go setup (CDN flake)
|
||||
if: steps.setup-go.outcome == 'failure'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::warning::setup-go failed (likely CDN flake), waiting 30s before retry..."
|
||||
sleep 30
|
||||
|
||||
- name: Set up Go (retry)
|
||||
if: steps.setup-go.outcome == 'failure'
|
||||
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
|
||||
with:
|
||||
go-version: "stable"
|
||||
cache: false
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
|
||||
- name: Cache cargo
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
continue-on-error: true # cache is an optimisation; never block on a stuck/slow restore
|
||||
timeout-minutes: 6
|
||||
|
||||
# The binding links against the C ABI hub via cgo; build it first and stage
|
||||
# the platform library under bindings/go/lib so cgo's LDFLAGS find it. Go is
|
||||
# preinstalled on the GitHub runners, so no setup-go step is needed.
|
||||
- name: Build the C ABI library
|
||||
run: cargo build -p wickra-c --release
|
||||
|
||||
- name: Stage the native library
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p bindings/go/lib
|
||||
case "$RUNNER_OS" in
|
||||
Linux) cp target/release/libwickra.so bindings/go/lib/ ;;
|
||||
macOS) cp target/release/libwickra.dylib bindings/go/lib/ ;;
|
||||
Windows) cp target/release/wickra.dll bindings/go/lib/ ;;
|
||||
esac
|
||||
|
||||
- name: Go info
|
||||
run: go version
|
||||
|
||||
- name: Check gofmt
|
||||
shell: bash
|
||||
run: |
|
||||
unformatted="$(gofmt -l bindings/go examples/go)"
|
||||
if [ -n "$unformatted" ]; then
|
||||
echo "gofmt needed on:"; echo "$unformatted"; exit 1
|
||||
fi
|
||||
|
||||
- name: Vet and test the Go binding
|
||||
shell: bash
|
||||
# On Windows there is no rpath; the loader resolves wickra.dll via PATH.
|
||||
run: |
|
||||
export PATH="$PWD/bindings/go/lib:$PATH"
|
||||
cd bindings/go
|
||||
go vet ./...
|
||||
go test ./...
|
||||
|
||||
- name: Build the Go examples
|
||||
shell: bash
|
||||
run: |
|
||||
export PATH="$PWD/bindings/go/lib:$PATH"
|
||||
cd examples/go
|
||||
go build ./...
|
||||
|
||||
# Run only the offline examples (fetch_btcusdt / live_binance need network).
|
||||
- name: Run the offline Go examples
|
||||
shell: bash
|
||||
run: |
|
||||
export PATH="$PWD/bindings/go/lib:$PATH"
|
||||
cd examples/go
|
||||
for d in streaming backtest multi_timeframe parallel_assets \
|
||||
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze; do
|
||||
go run "./$d"
|
||||
done
|
||||
|
||||
r:
|
||||
name: R on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
env:
|
||||
WICKRA_INCLUDE_DIR: ${{ github.workspace }}/bindings/c/include
|
||||
WICKRA_LIB_DIR: ${{ github.workspace }}/target/release
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
||||
|
||||
- name: Cache cargo
|
||||
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
||||
continue-on-error: true
|
||||
timeout-minutes: 6
|
||||
|
||||
# The binding compiles a thin .Call glue layer against the C ABI hub; build
|
||||
# the library first. On Windows configure.win bundles a renamed copy
|
||||
# (wickra_abi.dll) so the package's own wickra.dll does not collide with it.
|
||||
- name: Build the C ABI library
|
||||
run: cargo build -p wickra-c --release
|
||||
|
||||
- name: Set up R
|
||||
uses: r-lib/actions/setup-r@a51a8012b0aab7c32ef9d19bf54da93f3254335e # v2
|
||||
with:
|
||||
r-version: "release"
|
||||
use-public-rspm: true
|
||||
|
||||
# Use the repos configured by setup-r (use-public-rspm) so Linux installs
|
||||
# binary packages — building testthat's deps from source is slow and flaky.
|
||||
- name: Install test dependency
|
||||
run: Rscript -e 'install.packages("testthat")'
|
||||
|
||||
- name: Install and test the R binding
|
||||
shell: bash
|
||||
# github.workspace is a backslash path on Windows; configure.win (sh) and
|
||||
# mingw need forward slashes. On Linux/macOS the rpath points at
|
||||
# WICKRA_LIB_DIR; export the loader path too as a belt-and-suspenders.
|
||||
run: |
|
||||
export WICKRA_INCLUDE_DIR="${WICKRA_INCLUDE_DIR//\\//}"
|
||||
export WICKRA_LIB_DIR="${WICKRA_LIB_DIR//\\//}"
|
||||
export LD_LIBRARY_PATH="$WICKRA_LIB_DIR:$LD_LIBRARY_PATH"
|
||||
export DYLD_LIBRARY_PATH="$WICKRA_LIB_DIR:$DYLD_LIBRARY_PATH"
|
||||
R CMD INSTALL bindings/r
|
||||
Rscript -e 'library(testthat); library(wickra); test_dir("bindings/r/tests/testthat", stop_on_failure = TRUE)'
|
||||
|
||||
- name: Run the offline R examples
|
||||
shell: bash
|
||||
run: |
|
||||
export WICKRA_LIB_DIR="${WICKRA_LIB_DIR//\\//}"
|
||||
export LD_LIBRARY_PATH="$WICKRA_LIB_DIR:$LD_LIBRARY_PATH"
|
||||
export DYLD_LIBRARY_PATH="$WICKRA_LIB_DIR:$DYLD_LIBRARY_PATH"
|
||||
cd examples/r
|
||||
for f in streaming backtest multi_timeframe parallel_assets \
|
||||
strategy_rsi_mean_reversion strategy_macd_adx strategy_bollinger_squeeze; do
|
||||
Rscript "$f.R"
|
||||
done
|
||||
|
||||
# fetch_btcusdt / live_binance need the network (and jsonlite / websocket);
|
||||
# build-check that they parse without running them.
|
||||
- name: Parse the network R examples
|
||||
run: Rscript -e 'invisible(lapply(c("examples/r/fetch_btcusdt.R", "examples/r/live_binance.R"), parse)); cat("network R examples parse OK\n")'
|
||||
|
||||
# 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,146 @@ 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
|
||||
|
||||
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 +781,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 +802,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, and R bindings. ${n} indicators, O(1) per-tick updates, no system dependencies. Drop-in TA-Lib replacement."
|
||||
# Enforce the homepage unconditionally — it is a constant, so this both
|
||||
# corrects the stale kingchenc URL and self-heals any future drift.
|
||||
# Same Administration-write permission as --description (no extra scope).
|
||||
@@ -366,14 +373,14 @@ jobs:
|
||||
exit 0
|
||||
fi
|
||||
cd webpage-count
|
||||
sed -i -E "s/[0-9]+ (streaming-first )?indicators/${n} \1indicators/g" index.md .vitepress/config.ts
|
||||
sed -i -E "s/[0-9]+ (streaming-first )?indicators/${n} \1indicators/g" index.md about.md .vitepress/config.ts
|
||||
if git diff --quiet; then
|
||||
echo "Webpage indicator count unchanged."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "wickra-bot"
|
||||
git config user.email "wickra-bot@users.noreply.github.com"
|
||||
git add index.md .vitepress/config.ts
|
||||
git add index.md about.md .vitepress/config.ts
|
||||
git commit -m "chore: sync indicator count to ${n}"
|
||||
if ! git push 2>/dev/null; then
|
||||
echo "::warning::push to wickra-lib/webpage failed — ABOUT_SYNC_TOKEN likely lacks write (findings P10.0a)."
|
||||
|
||||
+22
-8
@@ -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) and the **R** binding
|
||||
(`bindings/r`, `.Call`) are generated from `wickra.h`, with Java planned the
|
||||
same way.
|
||||
|
||||
| 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
|
||||
|
||||
+40
-2
@@ -5,7 +5,41 @@ All notable changes to Wickra are documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
## [0.7.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 +1450,11 @@ 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.7.8...HEAD
|
||||
[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
|
||||
|
||||
+12
-1
@@ -21,6 +21,10 @@ 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`. |
|
||||
| `examples/` | Runnable examples. |
|
||||
| `docs/` | Pointer to the documentation site (docs.wickra.org); the docs live in the `wickra-lib/wickra-docs` repo. |
|
||||
|
||||
@@ -102,7 +106,14 @@ 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`.
|
||||
- **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.7.8"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"criterion",
|
||||
@@ -1955,7 +1955,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-bench"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"kand",
|
||||
@@ -1965,9 +1965,16 @@ dependencies = [
|
||||
"yata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wickra-c"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"wickra-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wickra-core"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"proptest",
|
||||
@@ -1977,7 +1984,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-data"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"csv",
|
||||
@@ -1994,7 +2001,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-examples"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"tokio",
|
||||
@@ -2004,7 +2011,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-node"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"napi",
|
||||
"napi-build",
|
||||
@@ -2014,7 +2021,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-python"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
dependencies = [
|
||||
"numpy",
|
||||
"pyo3",
|
||||
@@ -2023,7 +2030,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wickra-wasm"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
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.7.8"
|
||||
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.7.8" }
|
||||
|
||||
thiserror = "2"
|
||||
rayon = "1.10"
|
||||
|
||||
@@ -2,24 +2,26 @@
|
||||
<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)
|
||||
[](#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, 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 +48,11 @@ Full documentation lives at **[docs.wickra.org](https://docs.wickra.org)**:
|
||||
- **Quickstarts** — [Rust](https://docs.wickra.org/Quickstart-Rust),
|
||||
[Python](https://docs.wickra.org/Quickstart-Python),
|
||||
[Node](https://docs.wickra.org/Quickstart-Node),
|
||||
[WASM](https://docs.wickra.org/Quickstart-WASM).
|
||||
[WASM](https://docs.wickra.org/Quickstart-WASM),
|
||||
[C](https://docs.wickra.org/Quickstart-C),
|
||||
[C#](https://docs.wickra.org/Quickstart-CSharp),
|
||||
[Go](https://docs.wickra.org/Quickstart-Go),
|
||||
[R](https://docs.wickra.org/Quickstart-R).
|
||||
- **Indicators** — a per-indicator deep dive (formula, parameters, warmup) for
|
||||
every one of the 514 indicators; start at the
|
||||
[indicators overview](https://docs.wickra.org/Indicators-Overview).
|
||||
@@ -71,9 +77,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, 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 +102,8 @@ 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** | **514** | **yes** |
|
||||
| | | | **C · C# · Go · R** | | |
|
||||
| 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 +174,9 @@ as one column each. `Doji` is direction-less by default (`+1.0` / `0.0`);
|
||||
construct it in signed mode (`Doji::new().signed()`, `Doji(signed=True)`,
|
||||
`new Doji(true)`) for a dragonfly / gravestone `±1` reading.
|
||||
|
||||
Adding a new indicator means implementing one trait in Rust; all four bindings
|
||||
inherit it automatically.
|
||||
Adding a new indicator means implementing one trait in Rust; every binding
|
||||
inherits it automatically (the C ABI — and the C#, Go and R bindings generated from
|
||||
it — regenerate from the core).
|
||||
|
||||
## Languages
|
||||
|
||||
@@ -177,12 +186,17 @@ 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` |
|
||||
| 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 +258,21 @@ 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)
|
||||
├── 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)
|
||||
└── .github/workflows/ CI and release pipelines
|
||||
```
|
||||
|
||||
@@ -278,6 +300,22 @@ 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
|
||||
```
|
||||
|
||||
## Testing
|
||||
@@ -297,6 +335,10 @@ 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.
|
||||
|
||||
## 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 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 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 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,46 @@
|
||||
[package]
|
||||
name = "wickra-c"
|
||||
description = "C ABI (cdylib + staticlib) for the Wickra streaming-first technical indicators library — the hub every C-capable language (C, C++, Go, C#, Java, R) links against."
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
readme = "README.md"
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "wickra"
|
||||
crate-type = ["cdylib", "staticlib"]
|
||||
|
||||
# The C ABI inherently needs `unsafe` (raw pointers across the FFI boundary,
|
||||
# `#[export_name]` symbol control). The workspace forbids `unsafe_code`, so this
|
||||
# crate cannot inherit `workspace = true`; it mirrors every workspace lint and
|
||||
# only relaxes `unsafe_code` to `allow` (parity with how the proc-macro bindings
|
||||
# emit their unsafe). The Rust core stays `unsafe`-forbidden — this is the one
|
||||
# crate where the boundary lives.
|
||||
[lints.rust]
|
||||
unsafe_code = "allow"
|
||||
missing_debug_implementations = "warn"
|
||||
unreachable_pub = "warn"
|
||||
unused_must_use = "deny"
|
||||
|
||||
[lints.clippy]
|
||||
all = { level = "warn", priority = -1 }
|
||||
pedantic = { level = "warn", priority = -1 }
|
||||
module_name_repetitions = "allow"
|
||||
must_use_candidate = "allow"
|
||||
missing_errors_doc = "allow"
|
||||
missing_panics_doc = "allow"
|
||||
cast_precision_loss = "allow"
|
||||
cast_possible_truncation = "allow"
|
||||
cast_sign_loss = "allow"
|
||||
similar_names = "allow"
|
||||
float_cmp = "allow"
|
||||
|
||||
[dependencies]
|
||||
wickra-core = { workspace = true }
|
||||
@@ -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, 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, 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.7.8</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,100 @@
|
||||
# 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 and
|
||||
any other C-capable language. Every indicator is an O(1) streaming state machine,
|
||||
so live trading bots and historical backtests share the exact same
|
||||
implementation. This package is the Go binding; it consumes the C ABI hub through
|
||||
cgo and exposes all 514 streaming-first indicators as idiomatic types.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/wickra-lib/wickra/bindings/go
|
||||
```
|
||||
|
||||
The binding uses cgo, so a C compiler is required, and it links against the
|
||||
prebuilt Wickra C ABI library. Build that library from the workspace and stage
|
||||
it under this package's `lib/` directory:
|
||||
|
||||
```bash
|
||||
cargo build -p wickra-c --release
|
||||
cp target/release/libwickra.so bindings/go/lib/ # Linux
|
||||
cp target/release/libwickra.dylib bindings/go/lib/ # macOS
|
||||
cp target/release/wickra.dll bindings/go/lib/ # Windows (also on PATH at run time)
|
||||
```
|
||||
|
||||
On Linux and macOS the library path is baked in via rpath; on Windows the DLL
|
||||
must be discoverable at run time (next to the executable or on `PATH`).
|
||||
|
||||
## Quick start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
wickra "github.com/wickra-lib/wickra/bindings/go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Batch: run an indicator over a whole series (NaN at warmup positions).
|
||||
prices := make([]float64, 1000)
|
||||
for i := range prices {
|
||||
prices[i] = 100.0 + float64(i)*0.1
|
||||
}
|
||||
sma, _ := wickra.NewSma(20)
|
||||
defer sma.Close()
|
||||
values := sma.Batch(prices)
|
||||
|
||||
// Streaming: the same indicator, fed tick by tick in O(1).
|
||||
rsi, _ := wickra.NewRsi(14)
|
||||
defer rsi.Close()
|
||||
for _, price := range prices {
|
||||
value := rsi.Update(price) // NaN during warmup, no recomputation
|
||||
if value > 70 {
|
||||
fmt.Println("overbought")
|
||||
}
|
||||
}
|
||||
_ = values
|
||||
}
|
||||
```
|
||||
|
||||
`Batch(prices)` and feeding the same prices through `Update()` produce identical
|
||||
values — the equivalence is enforced by the test suite. Multi-output indicators
|
||||
(MACD, Bollinger, ADX, …) return `(Output, bool)`, with `false` while warming up.
|
||||
Every indicator owns a native handle freed by `Close()`; a finalizer is wired as
|
||||
a backstop, but call `Close()` (e.g. with `defer`) to release memory promptly.
|
||||
|
||||
## Documentation
|
||||
|
||||
The full indicator catalogue, guides, quickstarts, and API reference live in the
|
||||
main repository and documentation site:
|
||||
|
||||
- **Repository & full indicator list:** <https://github.com/wickra-lib/wickra>
|
||||
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
||||
- **Runnable examples:** [`examples/go/`](https://github.com/wickra-lib/wickra/tree/main/examples/go)
|
||||
|
||||
Wickra ships native bindings for Python, Node.js, WebAssembly and Rust, plus a
|
||||
C ABI hub that any C-capable language (C, C++, C#, Go, Java, R) links against —
|
||||
all exposing the same indicators from the shared, `unsafe`-forbidden Rust core.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Wickra is an indicator toolkit, not a trading system. The values it computes are
|
||||
deterministic transforms of the input data — they are not financial advice and
|
||||
do not predict the market. Any use in a live trading context is at your own risk.
|
||||
The library is provided **as is**, without warranty of any kind.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of [Apache-2.0](https://github.com/wickra-lib/wickra/blob/main/LICENSE-APACHE)
|
||||
or [MIT](https://github.com/wickra-lib/wickra/blob/main/LICENSE-MIT) at your option.
|
||||
@@ -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
@@ -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,25 @@
|
||||
// Package wickra provides idiomatic Go bindings for the Wickra
|
||||
// technical-analysis library over its C ABI hub.
|
||||
//
|
||||
// Each indicator is an opaque-handle type with a New<Indicator> constructor and
|
||||
// Update/Batch/Reset/Close methods. Handles are freed by Close and, as a
|
||||
// backstop, by a finalizer; call Close explicitly to release native memory
|
||||
// promptly. The binding links against the prebuilt Wickra C ABI library
|
||||
// (libwickra.so/.dylib or wickra.dll) staged under ./lib — see the package
|
||||
// README for how to provision it.
|
||||
package wickra
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I${SRCDIR}/../c/include
|
||||
#cgo linux LDFLAGS: -L${SRCDIR}/lib -lwickra -Wl,-rpath,${SRCDIR}/lib
|
||||
#cgo darwin LDFLAGS: -L${SRCDIR}/lib -lwickra -Wl,-rpath,${SRCDIR}/lib
|
||||
#cgo windows LDFLAGS: -L${SRCDIR}/lib -l:wickra.dll
|
||||
#include "wickra.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrInvalidParams is returned by a New<Indicator> constructor when the native
|
||||
// constructor rejects the supplied parameters (for example a zero period).
|
||||
var ErrInvalidParams = errors.New("wickra: invalid indicator parameters")
|
||||
@@ -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
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
prebuilt native binary, 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 an O(1)
|
||||
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, 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 Node.js binding (napi-rs);
|
||||
it exposes 200+ streaming-first indicators across sixteen families.
|
||||
@@ -55,8 +56,9 @@ the main repository and documentation site:
|
||||
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
||||
- **Runnable examples:** [`examples/node/`](https://github.com/wickra-lib/wickra/tree/main/examples/node)
|
||||
|
||||
Wickra ships four bindings — Python, Node.js, WebAssembly, and Rust — that all
|
||||
expose the same indicators from the shared, `unsafe`-forbidden Rust core.
|
||||
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
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-darwin-arm64",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"description": "Native binding for wickra (macOS Apple Silicon). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.darwin-arm64.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-darwin-x64",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"description": "Native binding for wickra (macOS Intel). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.darwin-x64.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-linux-arm64-gnu",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"description": "Native binding for wickra (linux arm64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.linux-arm64-gnu.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-linux-x64-gnu",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"description": "Native binding for wickra (linux x64 GNU). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.linux-x64-gnu.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-win32-arm64-msvc",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"description": "Native binding for wickra (Windows arm64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.win32-arm64-msvc.node",
|
||||
"files": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra-win32-x64-msvc",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"description": "Native binding for wickra (Windows x64 MSVC). Installed automatically as an optional dependency of wickra on matching platforms.",
|
||||
"main": "wickra.win32-x64-msvc.node",
|
||||
"files": [
|
||||
|
||||
Generated
+20
-20
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wickra",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wickra",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@napi-rs/cli": "^2.18.0"
|
||||
@@ -15,12 +15,12 @@
|
||||
"node": ">= 18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wickra-darwin-arm64": "0.7.4",
|
||||
"wickra-darwin-x64": "0.7.4",
|
||||
"wickra-linux-arm64-gnu": "0.7.4",
|
||||
"wickra-linux-x64-gnu": "0.7.4",
|
||||
"wickra-win32-arm64-msvc": "0.7.4",
|
||||
"wickra-win32-x64-msvc": "0.7.4"
|
||||
"wickra-darwin-arm64": "0.7.8",
|
||||
"wickra-darwin-x64": "0.7.8",
|
||||
"wickra-linux-arm64-gnu": "0.7.8",
|
||||
"wickra-linux-x64-gnu": "0.7.8",
|
||||
"wickra-win32-arm64-msvc": "0.7.8",
|
||||
"wickra-win32-x64-msvc": "0.7.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/cli": {
|
||||
@@ -41,8 +41,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-darwin-arm64": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-arm64/-/wickra-darwin-arm64-0.7.4.tgz",
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-arm64/-/wickra-darwin-arm64-0.7.8.tgz",
|
||||
"integrity": "sha512-4eZiBR/yGUdr4nzhEUFy2i69XgNx64iI2ax/LPamsThgylC0KpHOZKK19QzJ2d9KbK4C8nMjME5FLuR+4GNEwQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
@@ -57,8 +57,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-darwin-x64": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-x64/-/wickra-darwin-x64-0.7.4.tgz",
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-darwin-x64/-/wickra-darwin-x64-0.7.8.tgz",
|
||||
"integrity": "sha512-6hf8zI3QPjTFp4zCpmgUwDvNtu6jHqNUHKD5e55POo0CgA52HkpyxSPtVm8TGTIZDI7kPjlbOdBM8CJ76mmXwA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
@@ -73,8 +73,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-linux-arm64-gnu": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-arm64-gnu/-/wickra-linux-arm64-gnu-0.7.4.tgz",
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-arm64-gnu/-/wickra-linux-arm64-gnu-0.7.8.tgz",
|
||||
"integrity": "sha512-kSe6y0xBMSiqdPLXNjwop5WZdHtvdBNKSEBCwZ4hFq33p4apW25/wrlzv9/oDuyD4kuPabJEhCCnFOplh58CUg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
@@ -89,8 +89,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-linux-x64-gnu": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-x64-gnu/-/wickra-linux-x64-gnu-0.7.4.tgz",
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-linux-x64-gnu/-/wickra-linux-x64-gnu-0.7.8.tgz",
|
||||
"integrity": "sha512-tWBWS4qz7hxM4xnpFb59bhf6TaLwXq0Z3jEa/2l7r8PiHA94g8r8S53NRMiT+4yiL5hSWe/nUiC/YXdRrhEZ4g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
@@ -105,8 +105,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-win32-arm64-msvc": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-arm64-msvc/-/wickra-win32-arm64-msvc-0.7.4.tgz",
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-arm64-msvc/-/wickra-win32-arm64-msvc-0.7.8.tgz",
|
||||
"integrity": "sha512-EXIckHxAtF75PUGDKRzXyqMe9ldP0JjSdu68WFN6iJfp+McYrGu6h40TEJlQ/oUEIoPqiZB/xhVyo/el5Lg7zw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
@@ -121,8 +121,8 @@
|
||||
}
|
||||
},
|
||||
"node_modules/wickra-win32-x64-msvc": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-x64-msvc/-/wickra-win32-x64-msvc-0.7.4.tgz",
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/wickra-win32-x64-msvc/-/wickra-win32-x64-msvc-0.7.8.tgz",
|
||||
"integrity": "sha512-Yfsqq1Xwp6hdxMyLze411vNdo7BDwI6+lPSe7A9XdqyPecNDbtKwYLpsal2r8EHbNzqM+R8XnuRtUaEQS5VlUQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wickra",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.8",
|
||||
"description": "Streaming-first technical indicators: incremental, fast, install-free. Node bindings powered by Rust.",
|
||||
"author": "kingchenc <support@wickra.org>",
|
||||
"main": "index.js",
|
||||
@@ -47,12 +47,12 @@
|
||||
"node": ">= 18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wickra-linux-x64-gnu": "0.7.4",
|
||||
"wickra-linux-arm64-gnu": "0.7.4",
|
||||
"wickra-darwin-x64": "0.7.4",
|
||||
"wickra-darwin-arm64": "0.7.4",
|
||||
"wickra-win32-x64-msvc": "0.7.4",
|
||||
"wickra-win32-arm64-msvc": "0.7.4"
|
||||
"wickra-linux-x64-gnu": "0.7.8",
|
||||
"wickra-linux-arm64-gnu": "0.7.8",
|
||||
"wickra-darwin-x64": "0.7.8",
|
||||
"wickra-darwin-arm64": "0.7.8",
|
||||
"wickra-win32-x64-msvc": "0.7.8",
|
||||
"wickra-win32-arm64-msvc": "0.7.8"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "napi build --platform --release",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
system dependencies, no C build tooling.**
|
||||
|
||||
Wickra is a multi-language technical-analysis library with a Rust core and
|
||||
bindings for Python, Node.js, and WebAssembly. Every indicator is an O(1)
|
||||
bindings for Python, Node.js and WebAssembly, plus a C ABI for C/C++, C#, Go, 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 Python binding (PyO3); it
|
||||
exposes 200+ streaming-first indicators across sixteen families.
|
||||
@@ -54,8 +55,9 @@ the main repository and documentation site:
|
||||
- **Docs** (quickstarts, cookbook, TA-Lib migration): <https://docs.wickra.org>
|
||||
- **Runnable examples:** [`examples/python/`](https://github.com/wickra-lib/wickra/tree/main/examples/python)
|
||||
|
||||
Wickra ships four bindings — Python, Node.js, WebAssembly, and Rust — that all
|
||||
expose the same indicators from the shared, `unsafe`-forbidden Rust core.
|
||||
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
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "wickra"
|
||||
version = "0.7.4"
|
||||
version = "0.7.8"
|
||||
description = "Streaming-first technical indicators: incremental, fast, install-free."
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
^src/wickra_abi\.dll$
|
||||
^src/wickra_abi\.def$
|
||||
^src/libwickra_abi\.dll\.a$
|
||||
^src/.*\.o$
|
||||
^src/wickra\.dll$
|
||||
^src/wickra\.so$
|
||||
^src/symbols\.rds$
|
||||
^\.gitignore$
|
||||
@@ -0,0 +1,20 @@
|
||||
Package: wickra
|
||||
Type: Package
|
||||
Title: Streaming-First Technical Indicators
|
||||
Version: 0.7.8
|
||||
Authors@R: person("Wickra contributors", role = c("aut", "cre"), email = "support@wickra.org")
|
||||
Description: R bindings for the Wickra technical-analysis library over its C ABI
|
||||
hub. Exposes 514 indicators, each an O(1) streaming state machine shared with
|
||||
the Rust core and the other language bindings, so that live and historical
|
||||
evaluation use the exact same implementation.
|
||||
License: MIT + file LICENSE | Apache License 2.0
|
||||
URL: https://github.com/wickra-lib/wickra, https://docs.wickra.org
|
||||
BugReports: https://github.com/wickra-lib/wickra/issues
|
||||
Encoding: UTF-8
|
||||
NeedsCompilation: yes
|
||||
SystemRequirements: the Wickra C ABI library (libwickra); set WICKRA_INCLUDE_DIR
|
||||
and WICKRA_LIB_DIR when installing from source.
|
||||
Roxygen: list(markdown = TRUE)
|
||||
Suggests: testthat (>= 3.0.0)
|
||||
Config/testthat/edition: 3
|
||||
Config/roxygen2/version: 8.0.0
|
||||
@@ -0,0 +1,2 @@
|
||||
YEAR: 2026
|
||||
COPYRIGHT HOLDER: Wickra contributors
|
||||
@@ -0,0 +1,522 @@
|
||||
# Generated by roxygen2: do not edit by hand
|
||||
|
||||
S3method(batch,wickra_indicator)
|
||||
S3method(reset,wickra_indicator)
|
||||
S3method(update,wickra_indicator)
|
||||
export(AbandonedBaby)
|
||||
export(Abcd)
|
||||
export(AbsoluteBreadthIndex)
|
||||
export(AccelerationBands)
|
||||
export(AcceleratorOscillator)
|
||||
export(AdOscillator)
|
||||
export(AdVolumeLine)
|
||||
export(AdaptiveCci)
|
||||
export(AdaptiveCycle)
|
||||
export(AdaptiveLaguerreFilter)
|
||||
export(AdaptiveRsi)
|
||||
export(Adl)
|
||||
export(AdvanceBlock)
|
||||
export(AdvanceDecline)
|
||||
export(AdvanceDeclineRatio)
|
||||
export(Adx)
|
||||
export(Adxr)
|
||||
export(Alligator)
|
||||
export(Alma)
|
||||
export(Alpha)
|
||||
export(AmihudIlliquidity)
|
||||
export(AnchoredRsi)
|
||||
export(AnchoredVwap)
|
||||
export(AndrewsPitchfork)
|
||||
export(Apo)
|
||||
export(Aroon)
|
||||
export(AroonOscillator)
|
||||
export(Atr)
|
||||
export(AtrBands)
|
||||
export(AtrRatchet)
|
||||
export(AtrTrailingStop)
|
||||
export(AutoFib)
|
||||
export(Autocorrelation)
|
||||
export(AutocorrelationPeriodogram)
|
||||
export(AverageDailyRange)
|
||||
export(AverageDrawdown)
|
||||
export(AvgPrice)
|
||||
export(AwesomeOscillator)
|
||||
export(AwesomeOscillatorHistogram)
|
||||
export(BalanceOfPower)
|
||||
export(BandpassFilter)
|
||||
export(Bat)
|
||||
export(BeltHold)
|
||||
export(Beta)
|
||||
export(BetaNeutralSpread)
|
||||
export(BetterVolume)
|
||||
export(BipowerVariation)
|
||||
export(BodySizePct)
|
||||
export(BollingerBands)
|
||||
export(BollingerBandwidth)
|
||||
export(BomarBands)
|
||||
export(BreadthThrust)
|
||||
export(Breakaway)
|
||||
export(BullishPercentIndex)
|
||||
export(BurkeRatio)
|
||||
export(Butterfly)
|
||||
export(CalendarSpread)
|
||||
export(CalmarRatio)
|
||||
export(Camarilla)
|
||||
export(CandleVolume)
|
||||
export(Cci)
|
||||
export(CenterOfGravity)
|
||||
export(CentralPivotRange)
|
||||
export(Cfo)
|
||||
export(ChaikinMoneyFlow)
|
||||
export(ChaikinOscillator)
|
||||
export(ChaikinVolatility)
|
||||
export(ChandeKrollStop)
|
||||
export(ChandelierExit)
|
||||
export(ChoppinessIndex)
|
||||
export(ClassicPivots)
|
||||
export(CloseVsOpen)
|
||||
export(ClosingMarubozu)
|
||||
export(Cmo)
|
||||
export(CoefficientOfVariation)
|
||||
export(Cointegration)
|
||||
export(CommonSenseRatio)
|
||||
export(CompositeProfile)
|
||||
export(ConcealingBabySwallow)
|
||||
export(ConditionalValueAtRisk)
|
||||
export(ConnorsRsi)
|
||||
export(Coppock)
|
||||
export(CorrelationTrendIndicator)
|
||||
export(Counterattack)
|
||||
export(Crab)
|
||||
export(CumulativeVolumeDelta)
|
||||
export(CumulativeVolumeIndex)
|
||||
export(CupAndHandle)
|
||||
export(CyberneticCycle)
|
||||
export(Cypher)
|
||||
export(DayOfWeekProfile)
|
||||
export(Decycler)
|
||||
export(DecyclerOscillator)
|
||||
export(Dema)
|
||||
export(DemandIndex)
|
||||
export(DemarkPivots)
|
||||
export(DepthSlope)
|
||||
export(DerivativeOscillator)
|
||||
export(DetrendedStdDev)
|
||||
export(DisparityIndex)
|
||||
export(DistanceSsd)
|
||||
export(Doji)
|
||||
export(DojiStar)
|
||||
export(DollarBars)
|
||||
export(Donchian)
|
||||
export(DonchianStop)
|
||||
export(DoubleBollinger)
|
||||
export(DoubleTopBottom)
|
||||
export(DownsideGapThreeMethods)
|
||||
export(Dpo)
|
||||
export(DragonflyDoji)
|
||||
export(DrawdownDuration)
|
||||
export(DumplingTop)
|
||||
export(Dx)
|
||||
export(DynamicMomentumIndex)
|
||||
export(EaseOfMovement)
|
||||
export(EffectiveSpread)
|
||||
export(EhlersStochastic)
|
||||
export(Ehma)
|
||||
export(ElderImpulse)
|
||||
export(ElderRay)
|
||||
export(ElderSafeZone)
|
||||
export(Ema)
|
||||
export(EmpiricalModeDecomposition)
|
||||
export(Engulfing)
|
||||
export(Equivolume)
|
||||
export(EstimatedLeverageRatio)
|
||||
export(EvenBetterSinewave)
|
||||
export(EveningDojiStar)
|
||||
export(Evwma)
|
||||
export(EwmaVolatility)
|
||||
export(Expectancy)
|
||||
export(FallingThreeMethods)
|
||||
export(Fama)
|
||||
export(FibArcs)
|
||||
export(FibChannel)
|
||||
export(FibConfluence)
|
||||
export(FibExtension)
|
||||
export(FibFan)
|
||||
export(FibProjection)
|
||||
export(FibRetracement)
|
||||
export(FibTimeZones)
|
||||
export(FibonacciPivots)
|
||||
export(FisherRsi)
|
||||
export(FisherTransform)
|
||||
export(FlagPennant)
|
||||
export(Footprint)
|
||||
export(ForceIndex)
|
||||
export(FractalChaosBands)
|
||||
export(Frama)
|
||||
export(FryPanBottom)
|
||||
export(FundingBasis)
|
||||
export(FundingImpliedApr)
|
||||
export(FundingRate)
|
||||
export(FundingRateMean)
|
||||
export(FundingRateZScore)
|
||||
export(GainLossRatio)
|
||||
export(GainToPainRatio)
|
||||
export(GapSideBySideWhite)
|
||||
export(Garch11)
|
||||
export(GarmanKlassVolatility)
|
||||
export(Gartley)
|
||||
export(GatorOscillator)
|
||||
export(GeneralizedDema)
|
||||
export(GeometricMa)
|
||||
export(GoldenPocket)
|
||||
export(GrangerCausality)
|
||||
export(GravestoneDoji)
|
||||
export(Hammer)
|
||||
export(HangingMan)
|
||||
export(Harami)
|
||||
export(HaramiCross)
|
||||
export(HasbrouckInformationShare)
|
||||
export(HeadAndShoulders)
|
||||
export(HeikinAshi)
|
||||
export(HeikinAshiOscillator)
|
||||
export(HiLoActivator)
|
||||
export(HighLowIndex)
|
||||
export(HighLowRange)
|
||||
export(HighLowVolumeNodes)
|
||||
export(HighWave)
|
||||
export(HighpassFilter)
|
||||
export(Hikkake)
|
||||
export(HikkakeModified)
|
||||
export(HilbertDominantCycle)
|
||||
export(HistoricalVolatility)
|
||||
export(Hma)
|
||||
export(HoltWinters)
|
||||
export(HomingPigeon)
|
||||
export(HtDcPhase)
|
||||
export(HtPhasor)
|
||||
export(HtTrendMode)
|
||||
export(HurstChannel)
|
||||
export(HurstExponent)
|
||||
export(Ichimoku)
|
||||
export(IdenticalThreeCrows)
|
||||
export(ImbalanceBars)
|
||||
export(InNeck)
|
||||
export(Inertia)
|
||||
export(InformationRatio)
|
||||
export(InitialBalance)
|
||||
export(InstantaneousTrendline)
|
||||
export(IntradayIntensity)
|
||||
export(IntradayMomentumIndex)
|
||||
export(IntradayVolatilityProfile)
|
||||
export(InverseFisherTransform)
|
||||
export(InvertedHammer)
|
||||
export(JarqueBera)
|
||||
export(Jma)
|
||||
export(JumpIndicator)
|
||||
export(KRatio)
|
||||
export(KagiBars)
|
||||
export(KalmanHedgeRatio)
|
||||
export(Kama)
|
||||
export(KaseDevStop)
|
||||
export(KasePermissionStochastic)
|
||||
export(KellyCriterion)
|
||||
export(Keltner)
|
||||
export(KendallTau)
|
||||
export(Kicking)
|
||||
export(KickingByLength)
|
||||
export(Kst)
|
||||
export(Kurtosis)
|
||||
export(Kvo)
|
||||
export(KylesLambda)
|
||||
export(LadderBottom)
|
||||
export(LaguerreRsi)
|
||||
export(LeadLagCrossCorrelation)
|
||||
export(LinRegAngle)
|
||||
export(LinRegChannel)
|
||||
export(LinRegIntercept)
|
||||
export(LinRegSlope)
|
||||
export(LinearRegression)
|
||||
export(LiquidationFeatures)
|
||||
export(LogReturn)
|
||||
export(LongLeggedDoji)
|
||||
export(LongLine)
|
||||
export(LongShortRatio)
|
||||
export(M2Measure)
|
||||
export(MaEnvelope)
|
||||
export(MacdExt)
|
||||
export(MacdFix)
|
||||
export(MacdHistogram)
|
||||
export(MacdIndicator)
|
||||
export(Mama)
|
||||
export(MarketFacilitationIndex)
|
||||
export(MartinRatio)
|
||||
export(Marubozu)
|
||||
export(MassIndex)
|
||||
export(MatHold)
|
||||
export(MatchingLow)
|
||||
export(MaxDrawdown)
|
||||
export(McClellanOscillator)
|
||||
export(McClellanSummationIndex)
|
||||
export(McGinleyDynamic)
|
||||
export(MedianAbsoluteDeviation)
|
||||
export(MedianChannel)
|
||||
export(MedianMa)
|
||||
export(MedianPrice)
|
||||
export(Mfi)
|
||||
export(Microprice)
|
||||
export(MidPoint)
|
||||
export(MidPrice)
|
||||
export(MinusDi)
|
||||
export(MinusDm)
|
||||
export(ModifiedMaStop)
|
||||
export(Mom)
|
||||
export(MorningDojiStar)
|
||||
export(MorningEveningStar)
|
||||
export(MurreyMathLines)
|
||||
export(NakedPoc)
|
||||
export(Natr)
|
||||
export(NewHighsNewLows)
|
||||
export(NewPriceLines)
|
||||
export(Nrtr)
|
||||
export(Nvi)
|
||||
export(OIPriceDivergence)
|
||||
export(OIWeighted)
|
||||
export(Obv)
|
||||
export(OiToVolumeRatio)
|
||||
export(OmegaRatio)
|
||||
export(OnNeck)
|
||||
export(OpenInterestDelta)
|
||||
export(OpenInterestMomentum)
|
||||
export(OpeningMarubozu)
|
||||
export(OpeningRange)
|
||||
export(OrderBookImbalanceFull)
|
||||
export(OrderBookImbalanceTop1)
|
||||
export(OrderBookImbalanceTopN)
|
||||
export(OrderFlowImbalance)
|
||||
export(OuHalfLife)
|
||||
export(OvernightGap)
|
||||
export(OvernightIntradayReturn)
|
||||
export(PainIndex)
|
||||
export(PairSpreadZScore)
|
||||
export(PairwiseBeta)
|
||||
export(ParkinsonVolatility)
|
||||
export(PearsonCorrelation)
|
||||
export(PercentAboveMa)
|
||||
export(PercentB)
|
||||
export(PercentageTrailingStop)
|
||||
export(PerpetualPremiumIndex)
|
||||
export(Pgo)
|
||||
export(PiercingDarkCloud)
|
||||
export(Pin)
|
||||
export(PivotReversal)
|
||||
export(PlusDi)
|
||||
export(PlusDm)
|
||||
export(Pmo)
|
||||
export(PointAndFigureBars)
|
||||
export(PolarizedFractalEfficiency)
|
||||
export(Ppo)
|
||||
export(PpoHistogram)
|
||||
export(ProfileShape)
|
||||
export(ProfitFactor)
|
||||
export(ProjectionBands)
|
||||
export(ProjectionOscillator)
|
||||
export(Psar)
|
||||
export(Pvi)
|
||||
export(Qqe)
|
||||
export(Qstick)
|
||||
export(QuartileBands)
|
||||
export(QuotedSpread)
|
||||
export(RSquared)
|
||||
export(RangeBars)
|
||||
export(RealizedSpread)
|
||||
export(RealizedVolatility)
|
||||
export(RecoveryFactor)
|
||||
export(RectangleRange)
|
||||
export(Reflex)
|
||||
export(RegimeLabel)
|
||||
export(RelativeStrengthAB)
|
||||
export(RenkoBars)
|
||||
export(RenkoTrailingStop)
|
||||
export(RickshawMan)
|
||||
export(RisingThreeMethods)
|
||||
export(Rmi)
|
||||
export(Roc)
|
||||
export(Rocp)
|
||||
export(Rocr)
|
||||
export(Rocr100)
|
||||
export(RogersSatchellVolatility)
|
||||
export(RollMeasure)
|
||||
export(RollingCorrelation)
|
||||
export(RollingCovariance)
|
||||
export(RollingIqr)
|
||||
export(RollingMinMaxScaler)
|
||||
export(RollingPercentileRank)
|
||||
export(RollingQuantile)
|
||||
export(RollingVwap)
|
||||
export(RoofingFilter)
|
||||
export(Rsi)
|
||||
export(Rsx)
|
||||
export(RunBars)
|
||||
export(Rvi)
|
||||
export(RviVolatility)
|
||||
export(Rwi)
|
||||
export(SampleEntropy)
|
||||
export(SarExt)
|
||||
export(SeasonalZScore)
|
||||
export(SeparatingLines)
|
||||
export(SessionHighLow)
|
||||
export(SessionRange)
|
||||
export(SessionVwap)
|
||||
export(ShannonEntropy)
|
||||
export(Shark)
|
||||
export(SharpeRatio)
|
||||
export(ShootingStar)
|
||||
export(ShortLine)
|
||||
export(SignedVolume)
|
||||
export(SineWave)
|
||||
export(SineWeightedMa)
|
||||
export(SinglePrints)
|
||||
export(Skewness)
|
||||
export(Sma)
|
||||
export(Smi)
|
||||
export(Smma)
|
||||
export(SmoothedHeikinAshi)
|
||||
export(SortinoRatio)
|
||||
export(SpearmanCorrelation)
|
||||
export(SpinningTop)
|
||||
export(SpreadAr1Coefficient)
|
||||
export(SpreadBollingerBands)
|
||||
export(SpreadHurst)
|
||||
export(StalledPattern)
|
||||
export(StandardError)
|
||||
export(StandardErrorBands)
|
||||
export(StarcBands)
|
||||
export(Stc)
|
||||
export(StdDev)
|
||||
export(StepTrailingStop)
|
||||
export(SterlingRatio)
|
||||
export(StickSandwich)
|
||||
export(StochRsi)
|
||||
export(Stochastic)
|
||||
export(StochasticCci)
|
||||
export(SuperSmoother)
|
||||
export(SuperTrend)
|
||||
export(T3)
|
||||
export(TailRatio)
|
||||
export(TakerBuySellRatio)
|
||||
export(Takuri)
|
||||
export(TasukiGap)
|
||||
export(TdCamouflage)
|
||||
export(TdClop)
|
||||
export(TdClopwin)
|
||||
export(TdCombo)
|
||||
export(TdCountdown)
|
||||
export(TdDWave)
|
||||
export(TdDeMarker)
|
||||
export(TdDifferential)
|
||||
export(TdLines)
|
||||
export(TdMovingAverage)
|
||||
export(TdOpen)
|
||||
export(TdPressure)
|
||||
export(TdPropulsion)
|
||||
export(TdRangeProjection)
|
||||
export(TdRei)
|
||||
export(TdRiskLevel)
|
||||
export(TdSequential)
|
||||
export(TdSetup)
|
||||
export(TdTrap)
|
||||
export(Tema)
|
||||
export(TermStructureBasis)
|
||||
export(ThreeDrives)
|
||||
export(ThreeInside)
|
||||
export(ThreeLineBreak)
|
||||
export(ThreeLineBreakBars)
|
||||
export(ThreeLineStrike)
|
||||
export(ThreeOutside)
|
||||
export(ThreeSoldiersOrCrows)
|
||||
export(ThreeStarsInSouth)
|
||||
export(Thrusting)
|
||||
export(TickBars)
|
||||
export(TickIndex)
|
||||
export(Tii)
|
||||
export(TimeBasedStop)
|
||||
export(TimeOfDayReturnProfile)
|
||||
export(TowerTopBottom)
|
||||
export(TpoProfile)
|
||||
export(TradeImbalance)
|
||||
export(TradeSignAutocorrelation)
|
||||
export(TradeVolumeIndex)
|
||||
export(TrendLabel)
|
||||
export(TrendStrengthIndex)
|
||||
export(Trendflex)
|
||||
export(TreynorRatio)
|
||||
export(Triangle)
|
||||
export(Trima)
|
||||
export(Trin)
|
||||
export(TripleTopBottom)
|
||||
export(Tristar)
|
||||
export(Trix)
|
||||
export(TrueRange)
|
||||
export(Tsf)
|
||||
export(TsfOscillator)
|
||||
export(Tsi)
|
||||
export(Tsv)
|
||||
export(TtmSqueeze)
|
||||
export(TtmTrend)
|
||||
export(TurnOfMonth)
|
||||
export(Tweezer)
|
||||
export(TwiggsMoneyFlow)
|
||||
export(TwoCrows)
|
||||
export(TypicalPrice)
|
||||
export(UlcerIndex)
|
||||
export(UltimateOscillator)
|
||||
export(UniqueThreeRiver)
|
||||
export(UniversalOscillator)
|
||||
export(UpDownVolumeRatio)
|
||||
export(UpsideGapThreeMethods)
|
||||
export(UpsideGapTwoCrows)
|
||||
export(UpsidePotentialRatio)
|
||||
export(ValueArea)
|
||||
export(ValueAtRisk)
|
||||
export(Variance)
|
||||
export(VarianceRatio)
|
||||
export(VerticalHorizontalFilter)
|
||||
export(Vidya)
|
||||
export(VolatilityCone)
|
||||
export(VolatilityOfVolatility)
|
||||
export(VolatilityRatio)
|
||||
export(VoltyStop)
|
||||
export(VolumeBars)
|
||||
export(VolumeByTimeProfile)
|
||||
export(VolumeOscillator)
|
||||
export(VolumePriceTrend)
|
||||
export(VolumeProfile)
|
||||
export(VolumeRsi)
|
||||
export(VolumeWeightedMacd)
|
||||
export(VolumeWeightedSr)
|
||||
export(Vortex)
|
||||
export(Vpin)
|
||||
export(Vwap)
|
||||
export(VwapStdDevBands)
|
||||
export(Vwma)
|
||||
export(Vzo)
|
||||
export(Wad)
|
||||
export(WavePm)
|
||||
export(WaveTrend)
|
||||
export(Wedge)
|
||||
export(WeightedClose)
|
||||
export(WickRatio)
|
||||
export(WilliamsFractals)
|
||||
export(WilliamsR)
|
||||
export(WinRate)
|
||||
export(Wma)
|
||||
export(WoodiePivots)
|
||||
export(YangZhangVolatility)
|
||||
export(YoyoExit)
|
||||
export(ZScore)
|
||||
export(ZeroLagMacd)
|
||||
export(ZigZag)
|
||||
export(Zlema)
|
||||
export(batch)
|
||||
export(reset)
|
||||
importFrom(stats,update)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
#' wickra: streaming-first technical indicators
|
||||
#'
|
||||
#' R bindings for the Wickra technical-analysis library over its C ABI hub. Each
|
||||
#' indicator is a constructor (for example [Sma()], [Rsi()], [MacdIndicator()])
|
||||
#' returning a `wickra_indicator` object; feed it one observation at a time with
|
||||
#' [update()], run a whole series in one call with [batch()], and clear its
|
||||
#' state with [reset()]. The native handle is freed automatically when the object
|
||||
#' is garbage-collected.
|
||||
#'
|
||||
#' @keywords internal
|
||||
#' @importFrom stats update
|
||||
"_PACKAGE"
|
||||
|
||||
#' Update an indicator with one observation
|
||||
#'
|
||||
#' @param object A `wickra_indicator` created by an indicator constructor.
|
||||
#' @param ... The observation: a single value for scalar indicators, the OHLCV
|
||||
#' fields plus a timestamp for candle indicators, or two values for pairwise
|
||||
#' indicators.
|
||||
#' @return The indicator value: a numeric scalar; a named numeric vector for
|
||||
#' multi-output indicators (`NA` during warmup); a matrix of completed bars for
|
||||
#' bar builders; or a list / numeric vector for profile indicators
|
||||
#' (`NULL` during warmup).
|
||||
#' @examples
|
||||
#' sma <- Sma(3)
|
||||
#' for (x in c(1, 2, 3, 4, 5)) v <- update(sma, x)
|
||||
#' v # 4
|
||||
#' @export
|
||||
update.wickra_indicator <- function(object, ...) {
|
||||
args <- list(object$ptr, ...)
|
||||
if (!is.na(object$values_cap)) {
|
||||
args <- c(args, object$values_cap)
|
||||
}
|
||||
do.call(".Call", c(list(paste0("wk_", object$prefix, "_update")), args,
|
||||
list(PACKAGE = "wickra")))
|
||||
}
|
||||
|
||||
#' Run an indicator over a whole series in one call
|
||||
#'
|
||||
#' Available for scalar indicators. The result is identical to feeding the same
|
||||
#' inputs through [update()] one at a time, with `NA` at warmup positions.
|
||||
#'
|
||||
#' @param object A `wickra_indicator`.
|
||||
#' @param ... The input vector(s).
|
||||
#' @return A numeric vector the same length as the input.
|
||||
#' @examples
|
||||
#' batch(Sma(3), c(1, 2, 3, 4, 5)) # NA NA 2 3 4
|
||||
#' @export
|
||||
batch <- function(object, ...) {
|
||||
UseMethod("batch")
|
||||
}
|
||||
|
||||
#' @rdname batch
|
||||
#' @export
|
||||
batch.wickra_indicator <- function(object, ...) {
|
||||
do.call(".Call", c(list(paste0("wk_", object$prefix, "_batch"), object$ptr),
|
||||
list(...), list(PACKAGE = "wickra")))
|
||||
}
|
||||
|
||||
#' Reset an indicator to its warmup state
|
||||
#'
|
||||
#' @param object A `wickra_indicator`.
|
||||
#' @return The indicator, invisibly.
|
||||
#' @examples
|
||||
#' sma <- Sma(3)
|
||||
#' update(sma, 1)
|
||||
#' reset(sma)
|
||||
#' @export
|
||||
reset <- function(object) {
|
||||
UseMethod("reset")
|
||||
}
|
||||
|
||||
#' @rdname reset
|
||||
#' @export
|
||||
reset.wickra_indicator <- function(object) {
|
||||
.Call(paste0("wk_", object$prefix, "_reset"), object$ptr, PACKAGE = "wickra")
|
||||
invisible(object)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
.onLoad <- function(libname, pkgname) {
|
||||
# On Windows the package's wickra.dll depends on the bundled C ABI
|
||||
# wickra_abi.dll; the loader searches PATH for it, so prepend the package's own
|
||||
# libs directory. On Linux/macOS the rpath baked at build time locates the
|
||||
# shared library, so no PATH change is needed.
|
||||
if (.Platform$OS.type == "windows") {
|
||||
libs <- system.file(paste0("libs", .Platform$r_arch),
|
||||
package = pkgname, lib.loc = libname)
|
||||
if (nzchar(libs)) {
|
||||
Sys.setenv(PATH = paste(libs, Sys.getenv("PATH"), sep = .Platform$path.sep))
|
||||
}
|
||||
}
|
||||
library.dynam("wickra", pkgname, libname)
|
||||
}
|
||||
|
||||
.onUnload <- function(libpath) {
|
||||
library.dynam.unload("wickra", libpath)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
# Wickra — R
|
||||
|
||||
[](https://github.com/wickra-lib/wickra/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/wickra-lib/wickra)
|
||||
[](https://github.com/wickra-lib/wickra#license)
|
||||
|
||||
**Streaming-first technical indicators for R, over the Wickra C ABI hub via `.Call`.**
|
||||
|
||||
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, R
|
||||
and any other C-capable language. Every indicator is an O(1) streaming state
|
||||
machine, so live trading and historical backtests share the exact same
|
||||
implementation. This package is the R binding; it reaches the C ABI hub through
|
||||
R's native `.Call` interface and exposes all 514 indicators as constructors that
|
||||
return a lightweight `wickra_indicator` object.
|
||||
|
||||
## Install
|
||||
|
||||
The package compiles a thin C glue layer (`.Call`) against the prebuilt Wickra
|
||||
C ABI library, so a C toolchain (Rtools on Windows) is required, plus the C ABI
|
||||
header and library. Build the library from the workspace, then install the
|
||||
package pointing at it:
|
||||
|
||||
```bash
|
||||
cargo build -p wickra-c --release
|
||||
WICKRA_INCLUDE_DIR="$PWD/bindings/c/include" \
|
||||
WICKRA_LIB_DIR="$PWD/target/release" \
|
||||
R CMD INSTALL bindings/r
|
||||
```
|
||||
|
||||
On Windows the C ABI DLL is bundled into the package and put on the load path
|
||||
automatically; on Linux and macOS the library path is baked in via rpath.
|
||||
|
||||
## Quick start
|
||||
|
||||
```r
|
||||
library(wickra)
|
||||
|
||||
# Batch: run an indicator over a whole series (NaN at warmup positions).
|
||||
prices <- 100 + (0:999) * 0.1
|
||||
sma <- Sma(20)
|
||||
values <- batch(sma, prices)
|
||||
|
||||
# Streaming: the same indicator, fed one observation at a time in O(1).
|
||||
rsi <- Rsi(14)
|
||||
for (price in prices) {
|
||||
v <- update(rsi, price) # NaN during warmup
|
||||
if (!is.na(v) && v > 70) message("overbought")
|
||||
}
|
||||
|
||||
# Multi-output indicators return a named vector (NA while warming up).
|
||||
macd <- MacdIndicator(12, 26, 9)
|
||||
update(macd, 42) # c(macd = NA, signal = NA, histogram = NA)
|
||||
```
|
||||
|
||||
`batch(ind, prices)` and feeding the same prices through `update()` produce
|
||||
identical values — the equivalence is enforced by the test suite. Candle-input
|
||||
indicators take the OHLCV fields plus a timestamp, e.g.
|
||||
`update(atr, open, high, low, close, volume, timestamp)`. The native handle is
|
||||
freed automatically when the object is garbage-collected.
|
||||
|
||||
## 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/r/`](https://github.com/wickra-lib/wickra/tree/main/examples/r)
|
||||
|
||||
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,17 @@
|
||||
#!/bin/sh
|
||||
# Windows build: the package compiles to wickra.dll, which would collide with the
|
||||
# C ABI's own wickra.dll (the loader would resolve the import to the package
|
||||
# itself). Stage a renamed copy, wickra_abi.dll, into src/ and build a mingw
|
||||
# import library that references it by that name (objdump + dlltool, both shipped
|
||||
# with Rtools — no gendef/pexports needed). install.libs.R then bundles the DLL.
|
||||
set -e
|
||||
: "${WICKRA_LIB_DIR:?set WICKRA_LIB_DIR to the directory containing wickra.dll}"
|
||||
cp "${WICKRA_LIB_DIR}/wickra.dll" src/wickra_abi.dll
|
||||
{
|
||||
echo 'LIBRARY wickra_abi.dll'
|
||||
echo 'EXPORTS'
|
||||
objdump -p src/wickra_abi.dll | awk '/\[ *[0-9]+\]/ {print $NF}' | grep '^wickra_'
|
||||
} > src/wickra_abi.def
|
||||
dlltool --input-def src/wickra_abi.def --dllname wickra_abi.dll \
|
||||
--output-lib src/libwickra_abi.dll.a
|
||||
exit 0
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AbandonedBaby}
|
||||
\alias{AbandonedBaby}
|
||||
\title{AbandonedBaby indicator}
|
||||
\usage{
|
||||
AbandonedBaby()
|
||||
}
|
||||
\description{
|
||||
AbandonedBaby indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Abcd}
|
||||
\alias{Abcd}
|
||||
\title{Abcd indicator}
|
||||
\usage{
|
||||
Abcd()
|
||||
}
|
||||
\description{
|
||||
Abcd indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AbsoluteBreadthIndex}
|
||||
\alias{AbsoluteBreadthIndex}
|
||||
\title{AbsoluteBreadthIndex indicator}
|
||||
\usage{
|
||||
AbsoluteBreadthIndex()
|
||||
}
|
||||
\description{
|
||||
AbsoluteBreadthIndex indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AccelerationBands}
|
||||
\alias{AccelerationBands}
|
||||
\title{AccelerationBands indicator}
|
||||
\usage{
|
||||
AccelerationBands(period, factor)
|
||||
}
|
||||
\description{
|
||||
AccelerationBands indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AcceleratorOscillator}
|
||||
\alias{AcceleratorOscillator}
|
||||
\title{AcceleratorOscillator indicator}
|
||||
\usage{
|
||||
AcceleratorOscillator(ao_fast, ao_slow, signal_period)
|
||||
}
|
||||
\description{
|
||||
AcceleratorOscillator indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdOscillator}
|
||||
\alias{AdOscillator}
|
||||
\title{AdOscillator indicator}
|
||||
\usage{
|
||||
AdOscillator()
|
||||
}
|
||||
\description{
|
||||
AdOscillator indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdVolumeLine}
|
||||
\alias{AdVolumeLine}
|
||||
\title{AdVolumeLine indicator}
|
||||
\usage{
|
||||
AdVolumeLine()
|
||||
}
|
||||
\description{
|
||||
AdVolumeLine indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdaptiveCci}
|
||||
\alias{AdaptiveCci}
|
||||
\title{AdaptiveCci indicator}
|
||||
\usage{
|
||||
AdaptiveCci(period)
|
||||
}
|
||||
\description{
|
||||
AdaptiveCci indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdaptiveCycle}
|
||||
\alias{AdaptiveCycle}
|
||||
\title{AdaptiveCycle indicator}
|
||||
\usage{
|
||||
AdaptiveCycle()
|
||||
}
|
||||
\description{
|
||||
AdaptiveCycle indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdaptiveLaguerreFilter}
|
||||
\alias{AdaptiveLaguerreFilter}
|
||||
\title{AdaptiveLaguerreFilter indicator}
|
||||
\usage{
|
||||
AdaptiveLaguerreFilter(period)
|
||||
}
|
||||
\description{
|
||||
AdaptiveLaguerreFilter indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdaptiveRsi}
|
||||
\alias{AdaptiveRsi}
|
||||
\title{AdaptiveRsi indicator}
|
||||
\usage{
|
||||
AdaptiveRsi(period)
|
||||
}
|
||||
\description{
|
||||
AdaptiveRsi indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Adl}
|
||||
\alias{Adl}
|
||||
\title{Adl indicator}
|
||||
\usage{
|
||||
Adl()
|
||||
}
|
||||
\description{
|
||||
Adl indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdvanceBlock}
|
||||
\alias{AdvanceBlock}
|
||||
\title{AdvanceBlock indicator}
|
||||
\usage{
|
||||
AdvanceBlock()
|
||||
}
|
||||
\description{
|
||||
AdvanceBlock indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdvanceDecline}
|
||||
\alias{AdvanceDecline}
|
||||
\title{AdvanceDecline indicator}
|
||||
\usage{
|
||||
AdvanceDecline()
|
||||
}
|
||||
\description{
|
||||
AdvanceDecline indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AdvanceDeclineRatio}
|
||||
\alias{AdvanceDeclineRatio}
|
||||
\title{AdvanceDeclineRatio indicator}
|
||||
\usage{
|
||||
AdvanceDeclineRatio()
|
||||
}
|
||||
\description{
|
||||
AdvanceDeclineRatio indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Adx}
|
||||
\alias{Adx}
|
||||
\title{Adx indicator}
|
||||
\usage{
|
||||
Adx(period)
|
||||
}
|
||||
\description{
|
||||
Adx indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Adxr}
|
||||
\alias{Adxr}
|
||||
\title{Adxr indicator}
|
||||
\usage{
|
||||
Adxr(period)
|
||||
}
|
||||
\description{
|
||||
Adxr indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Alligator}
|
||||
\alias{Alligator}
|
||||
\title{Alligator indicator}
|
||||
\usage{
|
||||
Alligator(jaw_period, teeth_period, lips_period)
|
||||
}
|
||||
\description{
|
||||
Alligator indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Alma}
|
||||
\alias{Alma}
|
||||
\title{Alma indicator}
|
||||
\usage{
|
||||
Alma(period, offset, sigma)
|
||||
}
|
||||
\description{
|
||||
Alma indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Alpha}
|
||||
\alias{Alpha}
|
||||
\title{Alpha indicator}
|
||||
\usage{
|
||||
Alpha(period, risk_free)
|
||||
}
|
||||
\description{
|
||||
Alpha indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AmihudIlliquidity}
|
||||
\alias{AmihudIlliquidity}
|
||||
\title{AmihudIlliquidity indicator}
|
||||
\usage{
|
||||
AmihudIlliquidity(period)
|
||||
}
|
||||
\description{
|
||||
AmihudIlliquidity indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AnchoredRsi}
|
||||
\alias{AnchoredRsi}
|
||||
\title{AnchoredRsi indicator}
|
||||
\usage{
|
||||
AnchoredRsi()
|
||||
}
|
||||
\description{
|
||||
AnchoredRsi indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AnchoredVwap}
|
||||
\alias{AnchoredVwap}
|
||||
\title{AnchoredVwap indicator}
|
||||
\usage{
|
||||
AnchoredVwap()
|
||||
}
|
||||
\description{
|
||||
AnchoredVwap indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AndrewsPitchfork}
|
||||
\alias{AndrewsPitchfork}
|
||||
\title{AndrewsPitchfork indicator}
|
||||
\usage{
|
||||
AndrewsPitchfork(strength)
|
||||
}
|
||||
\description{
|
||||
AndrewsPitchfork indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Apo}
|
||||
\alias{Apo}
|
||||
\title{Apo indicator}
|
||||
\usage{
|
||||
Apo(fast, slow)
|
||||
}
|
||||
\description{
|
||||
Apo indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Aroon}
|
||||
\alias{Aroon}
|
||||
\title{Aroon indicator}
|
||||
\usage{
|
||||
Aroon(period)
|
||||
}
|
||||
\description{
|
||||
Aroon indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AroonOscillator}
|
||||
\alias{AroonOscillator}
|
||||
\title{AroonOscillator indicator}
|
||||
\usage{
|
||||
AroonOscillator(period)
|
||||
}
|
||||
\description{
|
||||
AroonOscillator indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Atr}
|
||||
\alias{Atr}
|
||||
\title{Atr indicator}
|
||||
\usage{
|
||||
Atr(period)
|
||||
}
|
||||
\description{
|
||||
Atr indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AtrBands}
|
||||
\alias{AtrBands}
|
||||
\title{AtrBands indicator}
|
||||
\usage{
|
||||
AtrBands(period, multiplier)
|
||||
}
|
||||
\description{
|
||||
AtrBands indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AtrRatchet}
|
||||
\alias{AtrRatchet}
|
||||
\title{AtrRatchet indicator}
|
||||
\usage{
|
||||
AtrRatchet(atr_period, start_mult, increment)
|
||||
}
|
||||
\description{
|
||||
AtrRatchet indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AtrTrailingStop}
|
||||
\alias{AtrTrailingStop}
|
||||
\title{AtrTrailingStop indicator}
|
||||
\usage{
|
||||
AtrTrailingStop(atr_period, multiplier)
|
||||
}
|
||||
\description{
|
||||
AtrTrailingStop indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AutoFib}
|
||||
\alias{AutoFib}
|
||||
\title{AutoFib indicator}
|
||||
\usage{
|
||||
AutoFib()
|
||||
}
|
||||
\description{
|
||||
AutoFib indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{Autocorrelation}
|
||||
\alias{Autocorrelation}
|
||||
\title{Autocorrelation indicator}
|
||||
\usage{
|
||||
Autocorrelation(period, lag)
|
||||
}
|
||||
\description{
|
||||
Autocorrelation indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AutocorrelationPeriodogram}
|
||||
\alias{AutocorrelationPeriodogram}
|
||||
\title{AutocorrelationPeriodogram indicator}
|
||||
\usage{
|
||||
AutocorrelationPeriodogram(min_period, max_period)
|
||||
}
|
||||
\description{
|
||||
AutocorrelationPeriodogram indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AverageDailyRange}
|
||||
\alias{AverageDailyRange}
|
||||
\title{AverageDailyRange indicator}
|
||||
\usage{
|
||||
AverageDailyRange(period, utc_offset_minutes)
|
||||
}
|
||||
\description{
|
||||
AverageDailyRange indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AverageDrawdown}
|
||||
\alias{AverageDrawdown}
|
||||
\title{AverageDrawdown indicator}
|
||||
\usage{
|
||||
AverageDrawdown(period)
|
||||
}
|
||||
\description{
|
||||
AverageDrawdown indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
@@ -0,0 +1,12 @@
|
||||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/indicators.R
|
||||
\name{AvgPrice}
|
||||
\alias{AvgPrice}
|
||||
\title{AvgPrice indicator}
|
||||
\usage{
|
||||
AvgPrice()
|
||||
}
|
||||
\description{
|
||||
AvgPrice indicator
|
||||
}
|
||||
\keyword{internal}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user