Files
kingchenc 12681e4b1b C ABI: full example suite + docs & About coverage (#224)
Stacked on #222 (base `feat/c-abi-hub`), so the diff is just the additions on top of the hub foundation — no merge of #222 required.

## What this adds

**Examples — full parity with rust/python/node (`examples/c/`)**
- `streaming.c` upgraded to the multi-indicator (SMA/EMA/RSI/MACD + signals) demo
- `backtest.c`, `multi_timeframe.c` (manual time-bucket resampling), `parallel_assets.c` (serial vs OpenMP fan-out, one handle per asset)
- three educational strategies: `strategy_rsi_mean_reversion.c`, `strategy_macd_adx.c`, `strategy_bollinger_squeeze.c`
- two network examples shelling out to `curl`: `fetch_btcusdt.c`, `live_binance.c` (REST poll)
- two header-only helpers (`wickra_csv.h`, `wickra_strategy.h`) since the C ABI ships no IO layer
- CMake builds all 11; the 9 offline ones run under `ctest` on 3 OS; the network two are built-only

**Docs & metadata — surface the C ABI everywhere it was missing**
- ARCHITECTURE diagram + crate table, SECURITY + THREAT_MODEL (the C ABI as the sole `unsafe` FFI surface), the three binding package READMEs, issue/PR templates, CHANGELOG, and the GitHub About template (live About + org description updated too)

**Cleanup**
- removed all references to the private generator tooling from public files (`bindings/c/src/lib.rs` header, `CONTRIBUTING.md`, `sync-about.yml`)

Verified locally: `cargo build -p wickra-c --release`, `cmake + ctest` (9/9 pass), and `-Wall -Wextra -Wpedantic` clean on gcc 13.
2026-06-09 02:14:28 +02:00

111 lines
3.9 KiB
C

/* Streaming indicators with the Wickra C ABI.
*
* Feeds a synthetic price series through several indicators tick by tick — the
* same O(1)-per-update model a live trading bot would use — and prints a status
* line once every indicator has warmed up. The C counterpart of
* `examples/rust/src/bin/streaming.rs`, `examples/python/streaming.py` and
* `examples/node/streaming.js`, using the same seeded LCG so a side-by-side run
* produces visibly comparable streams.
*
* Build (after `cargo build -p wickra-c --release`):
* cc examples/c/streaming.c -I bindings/c/include -L target/release -lwickra -lm -o streaming
*/
#include "wickra.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_TICKS 120
/* Deterministic synthetic series matching the sibling examples' seeded LCG. */
static void make_series(double *prices, size_t n) {
uint64_t seed = 1234567u;
for (size_t t = 0; t < n; ++t) {
seed = (seed * 1103515245u + 12345u) & 0x7FFFFFFFu;
double rnd = (double)seed / (double)0x7FFFFFFFu;
double tf = (double)t;
prices[t] = 100.0 + tf * 0.05 + sin(tf * 0.07) * 8.0 + cos(tf * 0.21) * 3.0 +
(rnd - 0.5);
}
}
/* Format an indicator value, rendering warmup (NaN) as a dashed placeholder. */
static void fmt(char *buf, size_t buflen, double v) {
if (isfinite(v)) {
snprintf(buf, buflen, "%7.2f", v);
} else {
snprintf(buf, buflen, " -- ");
}
}
int main(int argc, char **argv) {
size_t ticks = DEFAULT_TICKS;
if (argc == 3 && strcmp(argv[1], "--ticks") == 0) {
long parsed = strtol(argv[2], NULL, 10);
if (parsed <= 0) {
fprintf(stderr, "--ticks must be positive\n");
return 1;
}
ticks = (size_t)parsed;
} else if (argc != 1) {
fprintf(stderr, "usage: streaming [--ticks N]\n");
return 1;
}
struct Sma *sma = wickra_sma_new(20);
struct Ema *ema = wickra_ema_new(20);
struct Rsi *rsi = wickra_rsi_new(14);
struct MacdIndicator *macd = wickra_macd_indicator_new(12, 26, 9);
double *prices = (double *)malloc(ticks * sizeof(*prices));
if (sma == NULL || ema == NULL || rsi == NULL || macd == NULL || prices == NULL) {
fprintf(stderr, "allocation failed\n");
return 1;
}
make_series(prices, ticks);
printf("Wickra streaming indicator demo (C)\n\n");
size_t signals = 0;
for (size_t t = 0; t < ticks; ++t) {
double price = prices[t];
double sv = wickra_sma_update(sma, price);
double ev = wickra_ema_update(ema, price);
double rv = wickra_rsi_update(rsi, price);
WickraMacdOutput m;
int macd_ready = wickra_macd_indicator_update(macd, price, &m);
/* Only act once every indicator has produced a value. */
if (!isfinite(sv) || !isfinite(ev) || !isfinite(rv) || !macd_ready) {
continue;
}
int overbought = rv > 70.0 && m.histogram < 0.0;
int oversold = rv < 30.0 && m.histogram > 0.0;
const char *tag = overbought ? "SELL?" : (oversold ? "BUY? " : " ");
if (overbought || oversold) {
signals++;
}
char b_price[16], b_sma[16], b_ema[16], b_rsi[16], b_hist[16];
fmt(b_price, sizeof(b_price), price);
fmt(b_sma, sizeof(b_sma), sv);
fmt(b_ema, sizeof(b_ema), ev);
fmt(b_rsi, sizeof(b_rsi), rv);
fmt(b_hist, sizeof(b_hist), m.histogram);
printf("t=%3llu price=%s sma=%s ema=%s rsi=%s macd_hist=%s %s\n",
(unsigned long long)t, b_price, b_sma, b_ema, b_rsi, b_hist, tag);
}
printf("\nDone — %llu candidate signal(s) over %llu ticks.\n",
(unsigned long long)signals, (unsigned long long)ticks);
wickra_sma_free(sma);
wickra_ema_free(ema);
wickra_rsi_free(rsi);
wickra_macd_indicator_free(macd);
free(prices);
return 0;
}