Commit Graph

14 Commits

Author SHA1 Message Date
nicolas 46084de4b2 fix: keepalive, connection health check, log file, single-line reports, timings fix
- Move REST keepalive to poll loop (async, not blocking signal execution)
- Fix ensure_connected to detect RST connections (recv < 0, not just == 0)
- Add log_set_file() + log file /tmp/engine.log (background thread writes)
- Single-line FILLED/FAILED reports (no multi-line fills inside brackets)
- Fix timing clock (use CLOCK_REALTIME consistently, not mixing with MONOTONIC)
- Add ORDER/FILL/REJECTED intermediate output lines
- Add session warmup at executor_thread_create
- Fix FILL latency (use order-fire time, not signal-received time)
- Paper mode: add clientOid to test endpoint, fix fee simulation
- Concurrency: add primary_quote isolation
2026-05-27 00:15:08 -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 60c21bed36 chore: add microsecond resolution to structlog timestamps 2026-05-25 23:12:32 -03:00
nicolas e9727003d7 chore: remove session_warmed info log from warmup 2026-05-25 22:49:38 -03:00
nicolas affe18cbac fix: authenticated session warmup, balance-aware cascade, books always in signal
executor/executor.py:
- Replace unauthenticated /api/v1/time warmup with authenticated /api/v1/accounts
- Keepalive interval 15s -> 30s, uses authenticated warmup_session
- After sell leg, override filled_volume with latest balance from WS (net of fee)

executor/kucoin_api.py:
- Add warmup_session() method for GET /api/v1/accounts (authenticated)
- Pre-heats TCP/TLS connection pool to reduce first-order latency

executor/ws_client.py:
- Add latest_balance() method to expose WS balance cache

src/events.c:
- Always include book tops in signal (remove !sig->live gate)
- Only serialize top bid/ask level (not all 5)
2026-05-25 22:34:24 -03:00
nicolas 0d3acc62cb fix: add kcs_discount_active to Python config known keys 2026-05-25 20:39:40 -03:00
nicolas 3828e2b104 fix: cross-leg increment floor, ceiling-to-floor rounding, balance WS subscription, order-level logging
src/evaluate.c:
- Add cross-leg increment floor after each leg's output
- Fix sell-leg min_volume conversion (was understated by rates[leg])
- Change ceil to floor for all leg rounding (round input down, then compute)

executor/ws_client.py:
- Subscribe to /account/balance via Classic WS (subject: account.balance)
- Add await_balance() with ack tracking and per-currency futures
- Handle balance events and store latest available per currency

executor/executor.py:
- Reject order detail included in fills list with real attempted volume/latency
- Screen/log output shows fills, book tops, profit for all statuses
- side field in order_placed/order_rejected logs
- predicted_bps read early from signal (no more hardcoded 0.0)
- timings in failed/aborted reports
- Paper mode rounding: buy funds/base floored to qi/bi
2026-05-25 20:21:19 -03:00
nicolas c1c4aa4be8 docs: add docstrings to ~50 undocumented functions across C source files 2026-05-24 23:32:33 -03:00
nicolas 97b341fec9 cleanup: remove dead fh_ob/oe_em Python modules, add book_ts_ms to screen output 2026-05-24 21:36:48 -03:00
nicolas 43333984a3 feat: print execution reports to stdout for all statuses
Screen-print every completed trade (filled/failed/aborted) with
correlation_id, triangle, predicted_bps, effective_bps, profit, and
error (if any).  Flushes immediately for real-time visibility.
2026-05-24 20:50:16 -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 71ed25fe56 refactor: move order sizing to engine, simplify executor
Engine (evaluate.c):
- Compute per-leg minimum order size from quoteMinSize
  (max(baseMinSize * price, quoteMinSize), rounded to quoteIncrement)
- Convert each leg's minimum to starting-quote via pure-rate product (no fees)
- Viability gate: skip triangle if candidate < min_volume (strictest leg)
- Floor starting_volume at min_volume; supersedes old base_min_size guard

Data (symbols_api.h, triangle.h, symbols_api.c):
- Parse quoteMinSize from KuCoin /api/v2/symbols; propagate to triangle struct

Executor (executor.py):
- Remove _precheck_volume: sizing is the engine's responsibility
- Live mode: don't deduct estimated fee from filled_volume (exchange nets fees)
- Live mode: LegFill.fee always zero
2026-05-24 17:49:09 -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