Add the R binding over the C ABI hub (#230)

Adds an R binding (`bindings/r`) over the C ABI hub — the third language stecker after C# and Go, reaching the hub through R's native `.Call` interface (not extendr).

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

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

No Rust crate or `Cargo.toml` change — the R package is standalone and additive.
This commit is contained in:
kingchenc
2026-06-09 19:18:40 +02:00
committed by GitHub
parent 8225e1ab91
commit b7ef63400d
569 changed files with 30036 additions and 25 deletions
@@ -0,0 +1,62 @@
# One indicator per FFI archetype, exercised against the real native library.
test_that("scalar update returns the textbook value", {
s <- Sma(3)
v <- NA_real_
for (x in c(1, 2, 3, 4, 5)) v <- update(s, x)
expect_equal(v, 4)
})
test_that("batch matches streaming", {
input <- c(1, 2, 3, 4, 5, 6, 7, 8)
stream <- Sma(3)
want <- vapply(input, function(x) update(stream, x), numeric(1))
got <- batch(Sma(3), input)
expect_equal(got, want)
})
test_that("multi-output returns a named vector, NA during warmup", {
m <- MacdIndicator(3, 6, 3)
out <- update(m, 100)
expect_true(all(is.na(out)))
for (i in 1:30) out <- update(m, 100 + i)
expect_false(any(is.na(out)))
expect_named(out, c("macd", "signal", "histogram"))
})
test_that("bar builders return a matrix of completed bars", {
rb <- RangeBars(2.0)
total <- 0
for (p in c(100, 101, 103, 104, 99, 96, 102, 108, 95, 110)) {
total <- total + nrow(update(rb, p, p, p, p, 1, 0))
}
expect_gt(total, 0)
})
test_that("profile indicators return scalars plus a values vector", {
vp <- VolumeProfile(10, 24)
snap <- NULL
for (i in 0:49) {
price <- 100 + 5 * sin(i * 0.3)
snap <- update(vp, price, price + 1, price - 1, price, 1000, i)
}
expect_false(is.null(snap))
expect_gt(length(snap$values), 0)
})
test_that("array-input indicators consume vectors", {
ob <- OrderBookImbalanceFull()
v <- update(ob, c(99.9, 99.8, 99.7), c(5, 3, 2), c(100.1, 100.2, 100.3), c(1, 1, 1))
expect_false(is.na(v))
})
test_that("reset returns the indicator to warmup", {
s <- Sma(3)
for (x in c(1, 2, 3)) update(s, x)
reset(s)
expect_true(is.na(update(s, 10)))
})
test_that("invalid parameters raise an error", {
expect_error(Sma(0))
})