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:
@@ -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))
|
||||
})
|
||||
Reference in New Issue
Block a user