Commit Graph

6 Commits

Author SHA1 Message Date
kingchenc d362ae26a3 feat(data): expose CandleReader (CSV) natively in all 10 languages (#311)
Add the data-layer CSV candle reader to every binding so loading OHLCV
candles from a CSV no longer needs a per-language CSV/dataframe dependency.

- C ABI: wickra_candle_reader_new(bytes, len) / _count / _read / _free over
  an opaque CandleReader handle (parse the whole buffer up front, then drain).
- Native: Node/WASM CandleReader.read() -> Candle[], Python read() -> list[tuple].
- C-ABI languages: Go Read() []Candle, C# Candle[] Read(), Java Candle[] read(),
  R read() S3 generic (n x 6 matrix); C / C++ call the C ABI directly.
- Cross-language golden testdata/golden/data_csv*.csv pins the parsed candles
  bit-for-bit across every binding.

Verified locally across Rust (test+clippy+fmt), Node, WASM, Python, C#, Go,
Java, R, and the C/C++ cmake parity suite.
2026-06-16 00:10:58 +02:00
kingchenc cb6da4d737 feat(data-layer): Resampler (candle resampling) in all 10 languages (#310)
* feat(data-layer): Resampler (candle resampling) in all 10 languages

Second data-layer feature (F3): resample candles into a higher timeframe.

- Native (Node.js/WASM): new Resampler(timeframe) -> update(o,h,l,c,v,ts):
  Candle|null + flush(): Candle|null. Python the same -> tuple|None.
- C ABI: wickra_resampler_new/update/flush/free (update has the multi-output
  shape so the generators auto-emit it; flush is bespoke). Go Update -> (Candle,
  bool) + Flush; C# Candle? Update/Flush; Java Candle update/flush; R update()
  generic + a flush() S3 method (extends base::flush); C/C++ direct.
- Cross-language golden (testdata/golden/data_resampled.csv): the shared input
  candles resampled into 5-unit buckets, the final partial bucket via flush,
  pinned bit-for-bit across every binding.

Verified locally in all 10 (3 candles for the 5-unit smoke; 16 for the golden).
The WickraCandle output record is shared with the tick aggregator (deduped).

* test(node): exclude data-layer types from the indicator completeness contract

The Resampler exposes update(), so the completeness test flagged it as an
indicator and required batch/reset/isReady/warmupPeriod, which a data-layer type
does not have. Exclude TickAggregator and Resampler like the bar builders.
2026-06-15 22:36:16 +02:00
kingchenc 8a103ef920 feat(data-layer): TickAggregator (tick-to-candle) in all 10 languages (#309)
* feat(data-layer): TickAggregator in Node, WASM, Python + C ABI hub

First data-layer feature (F2): roll trade ticks up into fixed-timeframe OHLCV
candles, exposed natively and over the C ABI.

- wickra-data wired as a binding dependency (workspace dep; its wickra-core dep
  is default-features=false so it never forces rayon into the rayon-free WASM
  build — native bindings re-enable parallel through their own dependency).
- Node `TickAggregator(bucket, gapFill?)` -> `push(price, size, ts): Candle[]`;
  WASM the same (array of objects); Python `push(...) -> list[tuple]`.
- C ABI: `WickraCandle` struct + `wickra_tick_aggregator_new/push/free` (push
  writes candles into a caller buffer and returns the count), generated via the
  capi generator's new DATA_LAYER section; cbindgen now parses wickra-data so
  `TickAggregator` is a forward-declared opaque; header vendored to bindings/go.

Verified bit-identical across Node/WASM/Python/C/C++ (o=100 h=101 l=100 c=101
v=3 ts=0 for the shared 3-tick probe). WIP: Go/C#/Java/R generated bindings and
the cross-language golden are still pending.

* feat(data-layer): TickAggregator in Go, C#, Java, R (lossless push/drain)

Complete F2 across all 10 languages: the C-ABI tick aggregator now uses a
two-step push/drain so gap-fill candles are never lost, and the four generated
bindings expose it idiomatically.

- C ABI redesigned: opaque TickAggregator handle (inner aggregator + pending
  buffer); push consumes a tick and returns the closed-candle count, drain copies
  them into a count-sized caller buffer.
- Go: NewTickAggregator + Push(price,size,ts) []Candle; C#: TickAggregator +
  Candle[] Push(...); Java: TickAggregator + Candle[] push(...); R: TickAggregator
  constructor + push() S3 generic returning an (n x 6) numeric matrix.
- Candle output record generated per language from WickraCandle.

Verified bit-identical to the native bindings (o=100 h=101 l=100 c=101 v=3 ts=0)
in Go, C#, Java, and R at runtime; R passes R CMD check (pre-existing doc
warnings only). WIP: cross-language data-layer golden + CHANGELOG still pending.

* test(data-layer): cross-language golden for the tick aggregator + CHANGELOG

gen_golden emits a deterministic tick stream (testdata/golden/data_ticks.csv) and
the reference candle streams with and without gap filling (data_candles.csv,
data_candles_gap.csv). Every binding replays the shared ticks through its
TickAggregator and checks the candles bit-for-bit (fp tolerance) against the Rust
reference:

- Node / WASM / Python / Go / C# / Java / R: a dedicated parity test each.
- C / C++: data_layer_test.c (compiled as both, run as ctest).

The gap-fill fixture closes several candles from a single push, exercising the
lossless push/drain path. Records the feature under CHANGELOG [Unreleased].

* fix(examples): rename the CSV-loader candle to WickraBar

The example CSV helper (wickra_csv.h) defined its own struct WickraCandle, which
now collides with the public C ABI WickraCandle (the tick aggregator output) in
any example that includes both headers (backtest, multi_timeframe, the strategy
examples). The public type owns the name; rename the example loader's bar to
WickraBar. The generated golden_test.c is untouched (its only match was the
unrelated WickraCandleVolumeOutput).
2026-06-15 21:24:33 +02:00
kingchenc fd9f4c8bc6 feat(bindings): expose name() on every indicator in all 10 languages (#308)
* feat(bindings): expose name() on every indicator in Node, WASM, and Python

Surface the core Indicator::name() / BarBuilder::name() accessor through the
three native bindings so every indicator reports its canonical name at runtime,
matching the existing reset/isReady/warmupPeriod surface.

- Node (napi): name(): string on all 514 classes (regenerated index.d.ts)
- WASM (wasm-bindgen): name(): string on all 514 classes
- Python (pyo3): name() -> str on all classes

* feat(bindings): expose name() across the C ABI and C/C++/Go/C#/Java/R

Regenerate the C ABI and the four generated language bindings from the updated
ScriptHelpers generators so every indicator and bar builder reports its
canonical name at runtime, completing name() coverage across all 10 languages.

- C ABI (bindings/c): wickra_<ind>_name() -> *const c_char for all 514, cached
  in a per-function OnceLock<CString> with ind.name() as the source of truth;
  cbindgen header regenerated and vendored into bindings/go/include.
- Go: Name() string; C#: string Name(); Java: String name(); R: name() S3
  generic over the wk_<ind>_name C glue (methods.R + NAMESPACE).

The Java regeneration also restores two fixes that had drifted out of the
generator (bool* arrays via boolSegment; uint8_t ctor args cast to byte) and C#
re-emits '#nullable enable'; these are no-op vs the previous committed output
apart from the new name() accessors.

* test(golden): pin canonical name() across all 10 language bindings

Add a cross-language name() consistency check: every indicator must report the
exact core Indicator::name() (which can differ from the registered class name,
e.g. ChaikinMoneyFlow -> "CMF", Donchian -> "DonchianChannels"). The 514 core
names are committed as testdata/golden/names.json (keyed by Rust canonical) and
asserted by each binding's golden replay, which already reconstructs the whole
catalogue:

- node / wasm: assert against names.json in the existing golden test
- python: new test_golden_names.py over the shared node manifest
- go / csharp / java / c+c++ / r: the golden-test generators load names.json and
  emit a name assertion per indicator (regenerated test artifacts committed)

All 10 bindings return identical names by construction (each delegates to core),
so this pins that contract and guards against a future binding breaking the
passthrough.

* docs(changelog): record name() across all 10 bindings under Unreleased

* fix(r): restore bool* flag marshalling in the regenerated C glue

The name() regeneration had reverted the cross-section bool fix: the R glue
emitted (bool *)REAL(x) for const bool* inputs, reinterpreting 8-byte doubles as
1-byte bools so every flag read as false (PercentAboveMa, NewHighsNewLows,
HighLowIndex, BullishPercentIndex returned 0 instead of the breadth value). The
wk_bool_vec() helper is restored in the generator and the glue routes bool arrays
through it again.
2026-06-15 17:19:24 +02:00
kingchenc 0c925aa9d5 feat(c-abi): expose warmup_period / is_ready across the C ABI bindings (#297)
* feat(c-abi): expose warmup_period / is_ready across the C ABI bindings

The C ABI hub exposed new/update/batch/reset/free per indicator but not the
Indicator::warmup_period / is_ready queries that the native (Python/Node/WASM)
bindings already had, so C/C#/Go/Java/R callers could not ask an indicator
whether it was warmed up without feeding it and watching for NaN.

Regenerated from the ScriptHelpers capi + language generators:
- bindings/c: wickra_<ind>_warmup_period (size_t) and wickra_<ind>_is_ready
  (bool) for every indicator (504; the 10 alt-chart bar builders are excluded
  by design). wickra.h regenerated via cbindgen (additive only).
- bindings/csharp: int WarmupPeriod() / bool IsReady() on each wrapper.
- bindings/go: WarmupPeriod() int / IsReady() bool.
- bindings/java: int warmupPeriod() / boolean isReady().
- bindings/r: C glue + registration; hand-written warmup_period() / is_ready()
  S3 generics in methods.R, plus NAMESPACE exports.

Tests: C-ABI Rust unit tests, the C examples/archetypes.c suite, and the C#,
Go, Java and R archetype suites all gain a warmup/is_ready transition check.

* build(go): sync vendored wickra.h with the C ABI header

The Go binding vendors bindings/c/include/wickra.h; refresh it with the new
warmup_period / is_ready declarations so the CI sync check passes.
2026-06-14 01:04:06 +02:00
kingchenc b06ce2678a Restructure the Go binding for self-contained distribution (#236)
## Problem
Plain `go get` + `go build` of the Go binding never worked **as a dependency**:
- cgo `CFLAGS` pointed at `${SRCDIR}/../c/include` — the parent dir is **outside** the Go module, so a proxy-fetched module has no header.
- the library under `./lib` was git-ignored and never shipped; the README told users to `cargo build` it from the workspace, which only works inside a clone, not from the read-only module cache.

cgo has no build hook and Go has no registry, so the only way a consumer's `go get`+build can find the lib is for it to be committed **inside the module the consumer pulls**. Per the design decision, that module is a separate **`wickra-go`** repo (keeps this repo free of committed binaries), populated by the release pipeline — this PR is the in-repo restructure that makes that possible.

## Changes
- **Vendor the header** at `bindings/go/include/wickra.h` (committed copy of `bindings/c/include/wickra.h`); `CFLAGS` → `-I${SRCDIR}/include`. A **CI drift check** fails if the copy goes stale.
- **Per-platform libraries**: cgo `LDFLAGS` become per `GOOS`/`GOARCH`, linking `${SRCDIR}/lib/<goos>_<goarch>/`.
- **CI** stages the host library into `lib/<goos>_<goarch>/` (`RUNNER_OS`/`RUNNER_ARCH` — note `macos-latest` is arm64) and exports `WICKRA_GO_LIBDIR` for the Windows PATH; libraries stay git-ignored here.
- **README**: install via the `wickra-go` module + a contributor build section.

## Validation
- Local **windows/amd64**: `gofmt` clean, `go vet`, `go build`, `go test` all green against the staged library + vendored header.
- Linux/macOS arches → the 3-OS `Go on …` CI job.

Follow-up (Stage 2, separate): create `wickra-lib/wickra-go` + a `release.yml` mirror job (source + 6 platform libs → `lib/<goos>_<goarch>/`, commit + tag), and point the docs at the new import path. Part of the self-contained gap (`todo-11`).
2026-06-09 23:06:16 +02:00