- Architecture diagram: async goroutine entry path - Trading Logic: async entry, entering status protection - Config note: floor rounding on both exchanges
218 lines
10 KiB
Markdown
218 lines
10 KiB
Markdown
# 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.
|