Files
kingchenc de1112ea91 chore(examples): rename live_trading examples to live_binance (#301)
The examples stream a live Binance feed into the indicators and print signals;
they place no orders, so 'live_trading' overstated them and was inconsistent
with the C/Go/R examples already named live_binance. Rename the Python/Node/WASM
files to live_binance.* and update every reference, run command, header, and the
project-tree listings. Accurate use-case wording ('suitable for live trading
bots') and the risk disclaimers are left unchanged.
2026-06-15 03:41:19 +02:00

155 lines
4.5 KiB
C

/* Live BTCUSDT indicator with the Wickra C ABI.
*
* The C counterpart of `examples/rust/src/bin/live_binance.rs`,
* `examples/python/live_binance.py` and `examples/node/live_binance.js`. Those
* stream Binance over a WebSocket; the C ABI ships only the indicators and no
* socket layer, so this example polls the Binance REST klines endpoint via the
* system `curl` once per interval and feeds each newly *closed* candle into a
* streaming RSI(14). Same "live feed -> incremental indicator" shape, no extra
* dependency.
*
* This example talks to the network and runs until interrupted (Ctrl+C), so it
* is built but NOT run as a ctest.
*
* Build (after `cargo build -p wickra-c --release`):
* cc examples/c/live_binance.c -I bindings/c/include -L target/release -lwickra -lm -o live_binance
* ./live_binance [SYMBOL]
*/
#include "wickra.h"
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#define SLEEP_MS(ms) Sleep(ms)
#define POPEN _popen
#define PCLOSE _pclose
#else
#include <time.h>
#define POPEN popen
#define PCLOSE pclose
static void SLEEP_MS(long ms) {
struct timespec ts = {ms / 1000, (ms % 1000) * 1000000L};
nanosleep(&ts, NULL);
}
#endif
/* Run `curl <url>` and return stdout as a malloc'd, NUL-terminated buffer. */
static char *curl_get(const char *url) {
char cmd[512];
snprintf(cmd, sizeof(cmd),
"curl --silent --show-error --fail --max-time 15 \"%s\"", url);
FILE *p = POPEN(cmd, "r");
if (p == NULL) {
return NULL;
}
size_t cap = 1 << 15, len = 0;
char *buf = (char *)malloc(cap);
if (buf == NULL) {
PCLOSE(p);
return NULL;
}
size_t got;
char tmp[4096];
while ((got = fread(tmp, 1, sizeof(tmp), p)) > 0) {
if (len + got + 1 > cap) {
cap *= 2;
char *grown = (char *)realloc(buf, cap);
if (grown == NULL) {
free(buf);
PCLOSE(p);
return NULL;
}
buf = grown;
}
memcpy(buf + len, tmp, got);
len += got;
}
int rc = PCLOSE(p);
buf[len] = '\0';
if (rc != 0 || len == 0) {
free(buf);
return NULL;
}
return buf;
}
/* Extract the first kline's open time and close price from a klines response of
* the form [[openTime,"open","high","low","close",...],...]. Returns 1 on
* success. The first row (limit=2) is the most recent fully closed candle. */
static int first_kline(const char *body, int64_t *open_time, double *close) {
const char *s = strchr(body, '[');
if (s == NULL) {
return 0;
}
s = strchr(s + 1, '['); /* into the first row */
if (s == NULL) {
return 0;
}
s++;
char tok[64];
int field = 0;
while (*s && *s != ']') {
size_t tl = 0;
while (*s && *s != ',' && *s != ']') {
if (*s != '"' && tl + 1 < sizeof(tok)) {
tok[tl++] = *s;
}
s++;
}
tok[tl] = '\0';
if (field == 0) {
*open_time = strtoll(tok, NULL, 10);
} else if (field == 4) {
*close = strtod(tok, NULL);
return 1;
}
field++;
if (*s == ',') {
s++;
}
}
return 0;
}
int main(int argc, char **argv) {
const char *symbol = (argc > 1) ? argv[1] : "BTCUSDT";
char url[256];
snprintf(url, sizeof(url),
"https://api.binance.com/api/v3/klines?symbol=%s&interval=1m&limit=2",
symbol);
struct Rsi *rsi = wickra_rsi_new(14);
if (rsi == NULL) {
fprintf(stderr, "failed to create RSI\n");
return 1;
}
printf("Listening for %s 1m closes (REST poll, Ctrl+C to stop)...\n", symbol);
int64_t last_open = 0;
for (;;) {
char *body = curl_get(url);
if (body != NULL) {
int64_t open_time = 0;
double close = 0.0;
if (first_kline(body, &open_time, &close) && open_time != last_open) {
last_open = open_time;
double v = wickra_rsi_update(rsi, close);
if (isfinite(v)) {
printf("%s close=%.4f rsi=%.2f\n", symbol, close, v);
} else {
printf("%s close=%.4f rsi=...warmup\n", symbol, close);
}
fflush(stdout);
}
free(body);
}
SLEEP_MS(2000);
}
/* Unreachable in normal use (interrupted by Ctrl+C). */
}