Commit Graph

10 Commits

Author SHA1 Message Date
nicolas b0056f4b6b fix: per-slot fill channels with orderId fallback routing; fix reconnect double-subscribe
Architecture: each executor slot owns its own fill_channel_t. Executor encodes
slot_index in client_oid bytes 1-2 ("c{slot:02x}{ts:08x}{leg:04x}"). Hot thread
decodes slot from client_oid to route match events. For terminal events without
clientOid, falls back to orderId->slot_index mapping registered after each
successful rest_order_place.

Reconnect fixes:
- Remove redundant ws_client_subscribe after reconnect (already done in
  ws_client_connect) - caused "exceed max subscription count" 509 errors
- Only advance last_activity_ms on successful reconnect, so failed attempts
  retry every 100ms instead of every 5s
- Private channel subscriptions gated to connection 0 only to prevent
  duplicate fill events from KuCoin broadcasting to all connections
2026-06-02 18:29:30 -03:00
nicolas 60257f068f fix: use double-precision timestamps for sub-millisecond signal timing 2026-05-29 15:24:38 -03:00
nicolas 2f518d1a2d fix: cascade-based threshold gate, status log, best_net_bps tracking
- Restore post-simulation threshold gate using cascade net_bps (catches
  edge cases where cumulative formula sign differs from cascade result)
- Restore STATUS line with eval count (pre-simulation, every 30s)
- Move best_net_bps/worst tracking before post-simulation gate so all
  cascade-evaluated triangles contribute
- Remove executor idle diagnostic line
- Remove cooldown from evaluator (last_signal_ts_ms field removed)
- Move cooldown check before max_volume computation to save CPU
2026-05-28 10:01:17 -03:00
nicolas 562fddf124 cleanup: remove Python executor, dead config/HTTP server; add balance wait; fix fee hold, PnL, warnings
- Remove executor/ and common/ Python directories (dead code after C migration)
- Remove src/http_server.c/.h (was for Python executor, generates warnings)
- Remove dead config keys: socket_path, executor_socket_path, send_signals, rest_host, rest_port
- Remove dead UDS code in events.c/h (send_signal_to_executor, unix_* functions)
- Fix fee hold on leg 0 buys (apply_fee_hold to prevent Balance insufficient)
- Fix PnL leg0_in to use fills[0][4] instead of wrong currency field
- Fix REST keepalive warmup currency (use initial_capital[0] instead of hardcoded USDT)
- Add balance wait between legs via /account/balance WS + eventfd wake
- Fix all strncpy truncation warnings in config.c, symbols_api.c, ws_client.c
2026-05-27 12:14:10 -03:00
nicolas 06706ca479 fix: timing legends, log timestamp cache, mask generation, fill drop warning, remove fast parser
- Remove zero-alloc JSON fast parser (caused CPU increase, reverted to cJSON)
- Add descriptive legends to timing fields (t-1_snapshot, t0_arrival, t1_signal, etc.)
- Fix t2 missing when order fires at exec_start (guard on fills[l][0] not timing value)
- Cache log_write timestamp to avoid time()+localtime_r() per call
- Collapse 4 now_ms_impl() calls to 1 for WS mask generation
- Add fill_drop_warn counter for lost fill events (rate-limited warning)
- Add fill_drop_warn field to ws_client_t
2026-05-27 11:40:03 -03:00
nicolas 03b5daa003 migrate: absorb all executor functions into fused_engine (C)
Replace the Python executor with direct C execution in a dedicated
executor thread. Removes UDS JSON serialization, Python async
overhead, and the 2+ms pipeline gap between signal creation and
order fire.

New components:
- src/rest_client.c/h: Keepalive HTTPS, HMAC-SHA256 signing,
  order_place, order_test, Content-Length response parsing
- src/fill_handler.c/h: SPSC ring buffer for WS match events,
  hot thread -> executor thread fill dispatch
- src/executor.c/h: execute_triangle() cascade, fee hold
  reduction, increment floor, paper mode simulation, PnL,
  concurrency isolation, reporting

Modified:
- src/ws_client.c: Subscribe to tradeOrdersV2 + account.balance,
  dispatch orderChange match events to fill SPSC, private token
  fetch via bullet-private, token cleared on reconnect
- src/http_client.c: Added https_post_auth() for signed POST
- src/events.c: Cold thread replaced with executor thread
  (poll on wake_fd + fill_fd, direct execution)
- config.yaml.example: initial_capital moved to fused_engine,
  added cooldown_seconds, kcs_discount_active

Removed:
- src/kucoin_sign.c/h (redundant with http_client.c helpers)
2026-05-26 19:54:41 -03:00
nicolas c1c4aa4be8 docs: add docstrings to ~50 undocumented functions across C source files 2026-05-24 23:32:33 -03:00
nicolas 7afd4977ca fix: revert jsmn parser to cJSON, keep coalescing
The jsmn zero-alloc parser had token-navigation bugs that caused
all book updates to fail silently. Restore cJSON-based parsing
while preserving the coalescing architecture (accumulate dirty
symbols, evaluate once per burst).
2026-05-24 19:34:43 -03:00
nicolas 7c9b7f7ae6 perf: jsmn zero-alloc parser, coalesce evaluations, fix fill race
Engine (ws_client.c/h):
- Replace cJSON with jsmn (stack tokens, zero malloc) for book updates
- Quick-route message frames ("type":"message") to jsmn, bypass cJSON
- Coalesce same-symbol updates within one SSL_read burst: evaluate once
- ws_client_process_frame returns symbol_idx for batch tracking
- Restore book->sequence field update from sequence/sequenceNum

Executor (ws_client.py):
- Fix race: fill event arriving before await_fill registers future
  is now detected via FillAccumulator._done flag, resolved immediately
2026-05-24 18:17:14 -03:00
nicolas 2a82086683 Add initial triangular arbitrage bot
Two-process architecture: a C17 fused engine (WebSocket order book
mirror, triangle enumeration, real-time profitability evaluation)
communicating via Unix domain socket to a Python 3 executor (order
placement with paper/live trading modes, REST control API).
Targets KuCoin spot market.
2026-05-24 16:12:04 -03:00