# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Cross-exchange perpetual contract arbitrage system between Bitget and HyperLiquid. Scans ~150 coins for price spreads, executes automated arbitrage trades with scale-in/exit logic, and displays real-time data on a React dashboard. ## Build & Run Commands ```bash # Build Go binary go build -o exchange-monitor . # Start (kills old process + builds if needed + runs) bash start.sh # Options: --clean (delete DB), --rebuild (force recompile) bash start.sh --clean --rebuild # Frontend dev (hot reload on :5173, proxies /api to :8888) cd frontend && npm run dev # Frontend production build cd frontend && npm run build # IPC commands (talk to running daemon via Unix socket) ./exchange-monitor status ./exchange-monitor close-all ./exchange-monitor close DOGE ./exchange-monitor stop ./exchange-monitor start ``` ## Architecture ### Data Flow ``` Exchange WS (HL + BG) → PriceStore (in-memory) → scanner → Trader (entry/exit/scale) ↓ dashboard (SSE hub, :8888) ↓ React frontend (SSE events) ``` ### Main Loop (main.go:148-245) Fixed 50ms tick: trader.Tick() → scan.scanBGHL() → TryEntry() for each opportunity. Every 30s: status log. Hourly: Telegram summary. ### Package Layout | Package | Files | Responsibility | |---------|-------|---------------| | `main` (root) | `main.go`, `scanner.go`, `trader.go`, `dashboard.go`, `config.go`, `types.go`, `notifier.go`, `ipc.go` | All core logic in a single flat package | | `exchange/` | `connector.go`, `bitget.go`, `hyperliquid.go`, `bitget_trade.go`, `hyperliquid_trade.go`, `helpers.go` | WS reconnector + exchange-specific REST/WS APIs | | `db/` | `db.go`, `trade_repo.go` | SQLite persistence (trades, orders, system_orders, config_log) | | `frontend/` | Vite + React | Real-time dashboard consuming SSE from backend | ### Key Types - **PriceStore** — Thread-safe in-memory map of coin→exchange→price, with bid/ask spread tracking - **ArbOpportunity** — Scanning result: coin, direction (BG→HL or HL→BG), prices, net profit % - **ArbPosition** — Open position with long/short legs, scale-in tracking, entry prices array - **Trader** — Manages positions, entry/exit logic, fund tracking, blacklist, DB persistence ### Exchange Connector `PriceConnector` (exchange/connector.go) is a reusable WebSocket reconnector with exponential backoff (1s-30s), configurable ping interval, and read deadline. Bitget uses text ping frames; HyperLiquid uses standard ping/pong. ### Trading Logic - **Entry (TryEntry → executeEntry)**: Checks threshold, margin, blacklist, cooldown, max positions. Places both legs asynchronously with 300ms delay. Persists DB record immediately on "entering" status for crash recovery. - **Scale-in (checkScaleIn)**: Adds position when spread widens by ScaleStepPct per level. Posts additional orders on both legs. - **Exit (checkExit)**: Take profit at threshold, converged spread ≤ 0.02%, or timeout. Retries failed closes up to 30 times. - **Blacklist**: Force-closes position open >10min without convergence, prevents re-entry for BlacklistDuration. ### Net Profit Calculation ```go netProfit(buyPrice, sellPrice, buyFee, sellFee) = (revenue/cost - 1)*100 - 2*(buyFee + sellFee) ``` Where cost = buyPrice * (1 + buyFee/100), revenue = sellPrice * (1 - sellFee/100). Four total fees (2 entry + 2 exit). ### Configuration Priority `.env` vars > `config.json` > code defaults. Config struct in `config.go`. Key env vars: `BITGET_API_KEY`, `BITGET_API_SECRET`, `BITGET_PASSPHRASE`, `HL_PRIVATE_KEY`, `HL_ADDRESS`, `HL_API_ADDRESS`, `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`, `TRADE_ENABLED`, `TEST_MODE`. ### Dashboard API | Endpoint | Description | |----------|-------------| | `GET /` | Serves index.html (disk first, fallback embed) | | `GET /api/status` | Prices, positions, stats, exchange funds | | `GET /events` | SSE stream (prices, positions, arb, stats — 1s interval) | | `GET /api/history?coin=&exchange=` | Price history ring buffer (500 pts) | | `GET /api/spread-history?coin=` | BG↔HL spread history | | `GET /api/trades?page=&limit=&coin=` | Paginated trade history from DB | | `GET /api/trade/{id}` | Trade detail + orders | | `GET /api/connections` | Exchange WS health (online/stale/offline) | | `POST /api/stop` | Stop trading + force-close positions | | `POST /api/start` | Resume trading | ### Database SQLite at `~/Project/exchange-monitor-go/data/trades.db` (single-writer mode). Tables: `trades` (trade-level), `orders` (per-leg filled orders), `system_orders` (linked long+short order pairs), `config_log`. ### Coin Tracking ~150 coins in `TrackedCoins` slice (scanner.go). Each entry has Name, BN (Binance, currently unused), BG (Bitget symbol), HL (HyperLiquid symbol). Only BG+HL are actively connected. ### IPC (Unix Socket) `/tmp/exchange-monitor.sock` — JSON commands from CLI to daemon. Actions: status, close-all, close {coin}, stop, start.