2026-06-09 02:14:28 +02:00
|
|
|
/* Streaming indicators with the Wickra C ABI.
|
2026-06-09 02:07:03 +02:00
|
|
|
*
|
2026-06-09 02:14:28 +02:00
|
|
|
* 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.
|
2026-06-09 02:07:03 +02:00
|
|
|
*
|
|
|
|
|
* 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"
|
2026-06-09 02:14:28 +02:00
|
|
|
#include <math.h>
|
2026-06-09 02:07:03 +02:00
|
|
|
#include <stdio.h>
|
2026-06-09 02:14:28 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2026-06-09 02:07:03 +02:00
|
|
|
|
2026-06-09 02:14:28 +02:00
|
|
|
#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");
|
2026-06-09 02:07:03 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 02:14:28 +02:00
|
|
|
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);
|
2026-06-09 02:07:03 +02:00
|
|
|
|
2026-06-09 02:14:28 +02:00
|
|
|
/* Only act once every indicator has produced a value. */
|
|
|
|
|
if (!isfinite(sv) || !isfinite(ev) || !isfinite(rv) || !macd_ready) {
|
|
|
|
|
continue;
|
2026-06-09 02:07:03 +02:00
|
|
|
}
|
2026-06-09 02:14:28 +02:00
|
|
|
|
|
|
|
|
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);
|
2026-06-09 02:07:03 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-09 02:14:28 +02:00
|
|
|
printf("\nDone — %llu candidate signal(s) over %llu ticks.\n",
|
|
|
|
|
(unsigned long long)signals, (unsigned long long)ticks);
|
|
|
|
|
|
|
|
|
|
wickra_sma_free(sma);
|
2026-06-09 02:07:03 +02:00
|
|
|
wickra_ema_free(ema);
|
2026-06-09 02:14:28 +02:00
|
|
|
wickra_rsi_free(rsi);
|
|
|
|
|
wickra_macd_indicator_free(macd);
|
|
|
|
|
free(prices);
|
2026-06-09 02:07:03 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|