# Exchange Monitor Go Cross-exchange perpetual futures arbitrage scanner and automated trading system. Monitors real-time prices from 4 exchanges via **WebSocket**, identifies **Bitget ↔ HyperLiquid** arbitrage opportunities, executes maker-fee trades, and provides a real-time Web dashboard. ## Architecture ``` ┌──────────────┐ ┌──────────────┤ Binance │◄──── bookTicker WS (price reference) │ └──────────────┘ │ ┌──────────────┐ │──────────────┤ Bitget │◄──── ticker WS (trading exchange) │ └──────────────┘ PriceStore ─────────┼──────────────┤ │ │ HyperLiquid │◄──── webData2 WS (trading exchange) │ └──────────────┘ │ ┌──────────────┐ └──────────────┤ dYdX │◄──── v4_markets WS (price reference) └──────────────┘ │ ┌─────────▼─────────┐ │ ScanBGHL (50ms) │ │ BG ↔ HL only │ └─────────┬─────────┘ │ ┌───────────────▼────────────────┐ │ Trader │ │ TryEntry (async goroutine) │ │ → placeOrder (REST) │ │ Tick / Exit / Scale-in │ │ Maker fees only │ │ NO display/stat calculations │ └───────────────┬────────────────┘ │ ┌─────────▼─────────┐ │ SpreadWindowTracker│ │ (opportunity life) │ └─────────┬─────────┘ │ ┌──────────────────┼──────────────────┐ │ │ │ ┌─────▼─────┐ ┌────────▼───────┐ ┌─────▼─────┐ │ Notifier │ │ Dashboard │ │ DB │ │ TG │ │ :8888 │ │ SQLite │ │ │ │ Stats calc │ │ trades.db │ │ │ │ (calcDetailed) │ │ │ └───────────┘ └────────────────┘ └───────────┘ ``` ## Tracked Coins | Coin | Binance | Bitget | HyperLiquid | dYdX | |:----:|:--------:|:---------:|:-----------:|:--------:| | DOGE | DOGEUSDT | DOGEUSDT | DOGE | DOGE | | LINK | LINKUSDT | LINKUSDT | LINK | LINK | | ONDO | ONDOUSDT | ONDOUSDT | ONDO | ONDO | | OP | OPUSDT | OPUSDT | OP | OP | | WIF | WIFUSDT | WIFUSDT | WIF | WIF | | ARB | ARBUSDT | ARBUSDT | ARB | ARB | - **Bitget / HyperLiquid** — trading exchanges (limit orders with maker fees) - **Binance / dYdX** — price reference only ## Requirements - Go 1.25+ - WebSocket connectivity to all 4 exchanges ## Quick Start ```bash cd exchange-monitor-go go build -o exchange-monitor . # Edit .env to configure (token, threshold, etc.) ./exchange-monitor ``` Or use the startup script (auto-compiles if sources changed, cleans stale port): ```bash ./start.sh ``` Then open [http://localhost:8888](http://localhost:8888) for the Web dashboard. ## Configuration (.env) | Variable | Code Default | Description | |:---------|:------------:|:------------| | `TELEGRAM_BOT_TOKEN` | — | Telegram bot token for notifications | | `TELEGRAM_CHAT_ID` | — | Target chat ID for notifications | | `TRADE_ENABLED` | `false` | Enable real trading (`1` to enable) | | `TRADE_THRESHOLD` | `0.15` | Min net profit % to enter (after fees) | | `TRADE_AMOUNT_USD` | `10` | USD per leg | | `TRADE_COOLDOWN_MS` | `30000` | Cooldown between same-coin trades (ms) | | `TEST_MODE` | `false` | Simulate orders with mock fills (no real API calls) | | `MOCK_SLIPPAGE_PCT` | `0.005` | Simulated slippage per leg (%) | | `BITGET_API_KEY` / `BITGET_API_SECRET` / `BITGET_PASSPHRASE` | — | Bitget API credentials (test mode skips) | | `HL_PRIVATE_KEY` / `HL_ADDRESS` | — | HyperLiquid wallet credentials (test mode skips) | > **Note:** Scan interval is fixed at **50ms** (not configurable). Order sizes round DOWN (`math.Floor`) on both Bitget and HyperLiquid for consistency. ## Fee Model All trades use **maker** (limit orders), no rebate. Only Bitget and HyperLiquid are used for trading: | Exchange | Maker | Taker | |:---------|:-----:|:-----:| | Bitget | 0.020% | 0.040% | | HyperLiquid | 0.015% | 0.035% | Round trip (2 legs entry + 2 legs exit): **0.07%** total fees. ## Trading Logic 1. **Scanner** runs every 50ms, checks all 6 coins for BG ↔ HL spread 2. **Entry** when net profit ≥ `TRADE_THRESHOLD` (after full round-trip fees) - Uses scan-time prices directly (no re-read from store to avoid WS jitter) - **Async goroutine** — `TryEntry` returns immediately, `executeEntry` runs in background - Direction sanity check (0.1% tolerance) prevents entry on reversed spreads - `entering` status prevents `checkExit` / `checkScaleIn` during leg placement - `entering` map prevents duplicate entries on the same coin 3. **Scale-in** adds another leg-worth when spread widens another 0.10% 4. **Exit** conditions (whichever hits first): - Spread converges to ≤ 0.02% → **价差收敛,止盈平仓** - Spread reverses below -0.02% → **价差反转,止盈平仓** - Position held over 30 minutes → **超时平仓** 5. **Direction**: BG → HL (buy BG, sell HL) or HL → BG (buy HL, sell BG) ## Spread Window Monitoring `SpreadWindowTracker` runs every scan tick and measures how long each coin's spread stays above the trade threshold: - Records window **start time** when netProfit first hits threshold - Tracks real **peak netProfit** during the window - Logs window **duration + peak** when spread converges below threshold (sub-100ms windows filtered as noise) - Covers both directions (BG→HL and HL→BG) independently - Uses the same `netProfit()` fee model as the scanner for exact consistency Log output example: ``` [SpreadWindow] ONDO BG->HL exceeded threshold for 1.4s (peak net=+0.1520%) [SpreadWindow] OP HL->BG exceeded threshold for 3.2s (peak net=+0.1310%) ``` ## Notifications All notifications sent to Telegram (via `TELEGRAM_BOT_TOKEN`): - **开仓** — entry notification with prices, direction, spread, amount - **平仓** — exit notification with PnL breakdown, fees, convergence analysis - **每小时** — summary of open positions (duration, amount) - Uses HTML parse mode for bold formatting ## Web Dashboard Built-in HTTP server at `:8888` with real-time SSE push (1-second refresh): - **Price table** — live prices from all exchanges with bid-ask spread - **BG↔HL spread** — per-coin arbitrage spread with chart - **Open positions** — live PnL estimate, scaling level, duration - **Arb scan results** — current arbitrage opportunities - **Trade history** — past trades with detail view - **Connection status** — exchange health (online / stale / offline) - Charts rendered via Chart.js (loaded from CDN) ## DB & Persistence - SQLite at `data/trades.db` - Tracks open positions across restarts - Stores all closed trades with full PnL details - Historical stats merged with in-memory session stats on startup ## Signals | Signal | Action | |:-------|:-------| | `Ctrl+C` / `SIGINT` | Graceful shutdown (closes all WS connections) | | `SIGUSR1` | Dump convergence statistics to `trade_stats.txt` | ## Project Structure ``` exchange-monitor-go/ ├── main.go # Entry point, WS startup, main loop ├── config.go # .env + config.json hierarchical config ├── types.go # PriceStore, TrackedCoin, ArbOpportunity ├── scanner.go # ScanBGHL — arbitrage scanner ├── trader.go # Position management, entry/exit/scale-in (pure trading logic) ├── dashboard.go # Web server + SSE + stats calc (display layer) ├── toaster.go # Telegram notifications ├── static.go # Embedded web static files ├── start.sh # Startup script (port check + build + run) ├── .env # Local configuration (TELEGRAM, API keys, thresholds) ├── exchange/ │ ├── connector.go # Generic WS connector with reconnect │ ├── binance.go # Binance bookTicker WS │ ├── hyperliquid.go # HyperLiquid webData2 WS │ ├── hyperliquid_trade.go # HL REST trade API │ ├── bitget.go # Bitget ticker WS │ ├── bitget_trade.go # Bitget REST trade API │ ├── dydx.go # dYdX v4_markets WS │ ├── helpers.go # Package helpers │ └── ping.go # Accessibility check tools ├── db/ │ ├── db.go # SQLite open/migrate │ └── trade_repo.go # Trade record queries └── web/static/ ├── index.html # Dashboard HTML ├── app.js # SSE client + UI logic └── style.css # Dashboard CSS ``` ## Disclaimer This software is for educational/research purposes. Use at your own risk. Cryptocurrency trading involves substantial risk of loss.