Go to file
nicolas 9b76f33d4d chore: clean up stale .gitignore entries 2026-06-04 10:53:10 -03:00
docs cleanup: remove stale files, add session to .gitignore 2026-06-04 10:35:34 -03:00
src chore: remove MAX_DIRTY_BATCH cap, use MAX_SYMBOLS for dirty symbol set 2026-06-03 09:42:06 -03:00
.gitignore chore: clean up stale .gitignore entries 2026-06-04 10:53:10 -03:00
README.md docs: update README with disclaimer and contact; cleanup: remove compare_enum.py 2026-06-04 10:50:40 -03:00
config.yaml.example feat: add allow_same_quote config, fix overlapping pair isolation to check all 3 legs, document config example 2026-05-30 11:22:16 -03:00

README.md

Triangular Arbitrage Bot

Real-time triangular arbitrage detection and execution for KuCoin Spot. Single C binary. WebSocket book feeds, triangle evaluation, and order placement in one process.

Architecture

Monolithic single-process design using N+1 pthreads:

Thread Role
Hot thread WebSocket I/O via epoll, order book maintenance, book update dispatch to evaluator
Evaluator (embedded in hot thread) Triangle profitability evaluation on every book update, delivers to first free executor slot
Executor thread(s) Spin on per-thread slot via atomic state machine; pick up signal, place 3-leg HF market orders via KuCoin REST API, wait for fills via WebSocket, optional balance-wait between legs
[KuCoin WS] ──▶ Hot Thread ──▶ Evaluator ──▶ Slot[0..N] ──▶ Executor Thread(s)
                     │                       (CAS state machine)   │
               Order Book                                        KuCoin REST

Each executor thread owns one slot. The evaluator writes the signal directly into the slot via a CAS state machine (FREE → CLAIMED → READY). The executor picks it up on the next spin iteration (nanoseconds). If all slots are busy or no free slot available, the signal is dropped.

The evaluator runs in-process on every book update (no cooldown). The executor does not re-evaluate, it trusts the signal as valid at emission time.

Prerequisites

  • C compiler (gcc/clang), CMake 3.22+, OpenSSL, libyaml, pthreads

Building

mkdir -p build && cd build
cmake ../src -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

Binary at build/fused_engine.

Configuration

Edit config.yaml (see config.yaml.example):

Key Description
live_mode false = paper trades (test endpoint), true = real orders
signal_threshold_bps Minimum predicted bps to fire a signal (default: 2)
hold_currencies Currencies held as capital; triangles must start/end in one of these
excluded_currencies Currencies to exclude from triangle enumeration
kcs_discount_active Whether KCS fee discount applies
balance_wait_enabled Wait for WS balance settlement between live legs (default: false)
concurrent_slots Number of executor threads (default: 1, max 16)
initial_capital Map of currency to max quote per signal
kucoin_api_key/secret/passphrase KuCoin API credentials

Running

./build/fused_engine

Fetches fee table and symbol list, connects to KuCoin WebSocket, subscribes to order books, enumerates triangles, evaluates on every book update, and executes signals via REST.

Project Structure

tri_arb/
├── src/                     # C source
│   ├── main.c              # Entry point, thread spawn
│   ├── ws_client.c/h       # KuCoin WebSocket client (TLS, epoll, book/balance/order frames)
│   ├── book.c/h            # Order book store (top-5 bid/ask)
│   ├── symbols_api.c/h     # Symbol discovery, triangle enumeration
│   ├── triangle.c/h        # Triangle set, leg, signal types
│   ├── evaluate.c/h        # Triangle evaluation and signal dispatch
│   ├── executor.c/h        # Signal execution, REST order placement, fill+balance wait
│   ├── events.c/h          # Event loops (hot thread + executor thread(s))
│   ├── fill_handler.c/h    # Cross-thread fill event channel (SPSC ring + eventfd)
│   ├── rest_client.c/h     # KuCoin REST API client (signed requests, keepalive)
│   ├── http_client.c/h     # One-shot HTTPS requests (token fetch, fee table)
│   ├── slot.c/h            # Per-executor signal slot with atomic CAS delivery
│   ├── config.c/h          # YAML config parser
│   ├── hash.c/h            # Hash table
│   ├── cJSON.c/h           # JSON parser
│   ├── log.c/h             # Logging
│   └── CMakeLists.txt
├── build/                   # Build output
├── config.yaml              # Runtime config (gitignored)
├── config.yaml.example      # Config template
└── scripts/                 # Deployment scripts

Disclaimer

This software is designed for low-latency environments. It is only useful when colocated with the exchange's servers.

Contact

Nicolás Sánchez — nicolassanchez@tutanota.com