feat: 所有参数移至config.json, 重构退出逻辑, 清理遗留接口

- 将所有硬编码参数迁移到 config.json (手续费率、止盈/止损阈值、
  超时、腿间隔、加仓步进等)
- 退出条件: 净利 >= take_profit_pct 止盈, 价差 <= 0 平仓
- 删除 Binance/dYdX 遗留代码
- 更新 README 文档
- Dashboard: 双交易所价格表、黑名单UI、按币名排序持仓
- Bitget WS: 文本ping保活
- 数据库: 重置, 无历史仓位
This commit is contained in:
jackyu66git
2026-05-04 01:46:17 +08:00
parent 2ed6ffc747
commit 21a3f9a962
10 changed files with 450 additions and 206 deletions
+98 -100
View File
@@ -1,35 +1,28 @@
# 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.
Cross-exchange perpetual futures arbitrage monitoring and automated trading system. Tracks **Bitget ↔ HyperLiquid** spread in real time, executes simulated trades at configurable thresholds.
## Architecture
```
┌──────────────┐
┌──────────────┤ Binance │◄──── bookTicker WS (price reference)
└──────────────┘
│ ┌──────────────┐
│──────────────┤ Bitget │◄──── ticker WS (trading exchange)
│ └──────────────┘
│ Bitget │◄──── ticker WS (trading exchange)
└──────────────┘
PriceStore ─────────┼──────────────┤
│ HyperLiquid │◄──── webData2 WS (trading exchange)
│ └──────────────┘
│ ┌──────────────┐
└──────────────┤ dYdX │◄──── v4_markets WS (price reference)
│ HyperLiquid │◄──── webData2 WS (trading exchange)
└──────────────┘
┌─────────▼─────────┐
│ ScanBGHL (50ms)
│ ScanBGHL (200ms) │
│ BG ↔ HL only │
└─────────┬─────────┘
┌───────────────▼────────────────┐
│ Trader │
│ TryEntry (async goroutine) │
│ → placeOrder (REST)
│ → placeOrder (REST/mock)
│ Tick / Exit / Scale-in │
Maker fees only
│ NO display/stat calculations │
Config-driven thresholds
└───────────────┬────────────────┘
┌─────────▼─────────┐
@@ -41,136 +34,143 @@ PriceStore ─────────┼─────────────
│ │ │
┌─────▼─────┐ ┌────────▼───────┐ ┌─────▼─────┐
│ Notifier │ │ Dashboard │ │ DB │
│ TG │ │ :8888 │ │ SQLite │
│ Telegram │ │ :8888 │ │ SQLite │
│ │ │ Stats calc │ │ trades.db │
│ │ │ (calcDetailed) │ │ │
│ │ │ Blacklist UI │ │ │
└───────────┘ └────────────────┘ └───────────┘
```
## 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 |
| Coin | Bitget | HyperLiquid |
|:----:|:---------:|:-----------:|
| DOGE | DOGEUSDT | DOGE |
| LINK | LINKUSDT | LINK |
| ONDO | ONDOUSDT | ONDO |
| OP | OPUSDT | OP |
| WIF | WIFUSDT | WIF |
| ARB | ARBUSDT | ARB |
- **Bitget / HyperLiquid** — trading exchanges (limit orders with maker fees)
- **Binance / dYdX** — price reference only
> **Note:** Binance and dYdX have been removed — only Bitget and HyperLiquid are monitored.
## Requirements
- Go 1.25+
- WebSocket connectivity to all 4 exchanges
- WebSocket connectivity to Bitget and HyperLiquid
## Quick Start
```bash
cd exchange-monitor-go
go build -o exchange-monitor .
# Edit .env to configure (token, threshold, etc.)
# Edit config.json to set parameters
./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)
## Configuration
| 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) |
### config.json (all trading parameters)
> **Note:** Scan interval is fixed at **50ms** (not configurable). Order sizes round DOWN (`math.Floor`) on both Bitget and HyperLiquid for consistency.
All numerical parameters are defined in `config.json`**no need to edit Go source**:
| Parameter | Default | Description |
|:----------|:-------:|:------------|
| `test_mode` | `true` | Simulate orders with mock fills (no real API calls) |
| `trade_enabled` | `true` | Enable automated trading |
| `scan_interval_ms` | `200` | Scanner loop interval (ms) |
| `arb_threshold` | `0.03` | Min net profit % to trigger alert |
| `trade_threshold` | `0.10` | Min net profit % to execute trade |
| `trade_amount_usd` | `5` | USD per leg (per order) |
| `trade_cooldown_ms` | `30000` | Cooldown between same-coin trades (ms) |
| `max_positions` | `5` | Maximum concurrent open positions |
| `initial_capital` | `1000` | Starting capital in USD (for PnL %) |
| `mock_slippage_pct` | `0.005` | Simulated slippage per leg (%) |
| `blacklist_duration_sec` | `3600` | Coin blacklist duration (seconds) |
| `taker_fee_bitget` | `0.060` | Bitget taker fee rate (%) |
| `taker_fee_hyperliquid` | `0.045` | HyperLiquid taker fee rate (%) |
| `take_profit_pct` | `0.20` | Net profit % threshold for take-profit |
| `spread_reverse_exit_pct` | `0` | Spread convergence/reversal exit (0 = exit when ≤ 0) |
| `position_timeout_sec` | `1800` | Max position hold time before auto-close (30 min) |
| `leg_delay_ms` | `300` | Delay between placing long and short legs |
| `reversal_tolerance_pct` | `0.1` | Price movement tolerance for entry sanity check |
| `scale_step_pct` | `0.10` | Spread widening % to trigger each scale-in level |
| `scale_cooldown_sec` | `5` | Minimum seconds between scale-ins |
### .env (secrets only)
Secrets (API keys) go in `.env` — never checked into git:
| Variable | Description |
|:---------|:------------|
| `TELEGRAM_BOT_TOKEN` | Telegram bot token for notifications |
| `TELEGRAM_CHAT_ID` | Target chat ID for notifications |
| `BITGET_API_KEY` | Bitget API key (skipped if test_mode) |
| `BITGET_API_SECRET` | Bitget API secret |
| `BITGET_PASSPHRASE` | Bitget passphrase |
| `HL_PRIVATE_KEY` | HyperLiquid ed25519 private key hex |
| `HL_ADDRESS` | HyperLiquid wallet address |
> **Priority:** `.env` vars > `config.json` > code defaults.
## Fee Model
All trades use **maker** (limit orders), no rebate. Only Bitget and HyperLiquid are used for trading:
All trades use **taker** (market orders). Only Bitget and HyperLiquid:
| Exchange | Maker | Taker |
|:---------|:-----:|:-----:|
| Bitget | 0.020% | 0.040% |
| HyperLiquid | 0.015% | 0.035% |
| Exchange | Taker Fee |
|:---------|:---------:|
| Bitget | configurable (`taker_fee_bitget`, default 0.060%) |
| HyperLiquid | configurable (`taker_fee_hyperliquid`, default 0.045%) |
Round trip (2 legs entry + 2 legs exit): **0.07%** total fees.
Round trip (2 legs entry + 2 legs exit): configurable, default **0.21%** 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)
1. **Scanner** runs every `scan_interval_ms`, checks all 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 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%
- Reversal tolerance check prevents entry on flipped spreads
- `entering` map prevents duplicate entries on same coin
3. **Scale-in** adds another leg-worth when spread widens another `scale_step_pct` (default 0.10%)
4. **Exit** conditions (whichever hits first):
- Spread converges to ≤ 0.02% → **价差收敛,止盈平仓**
- Spread reverses below -0.02%**价差反转,止盈平仓**
- Position held over 30 minutes**超时平仓**
- **Net profit ≥ `take_profit_pct`** → **利润止盈**
- **Spread converges to ≤ 0 (prices equal or reversed)****价差收敛止盈**
- **Position held > `position_timeout_sec`****超时平仓**
5. **Direction**: BG → HL (buy BG, sell HL) or HL → BG (buy HL, sell BG)
## Blacklist Mechanism
- Positions held open for > 10 minutes without converging are auto-closed and blacklisted
- Blacklisted coins are skipped for `blacklist_duration_sec` (default 1 hour)
- Blacklist state visible on the dashboard
## 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)
- Records window **start time** when net profit first hits threshold
- Tracks real **peak net profit** during the window
- Logs window **duration + peak** when spread converges below threshold
- 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
- **Price table** — live prices from both exchanges
- **BG↔HL spread** — per-coin arbitrage spread
- **Open positions** — live PnL estimate, scaling level, duration, sorting by coin
- **Trade history** — past trades with detail view
- **Blacklist** — currently blacklisted coins and remaining time
- **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
- SQLite at current directory (auto-deleted on each restart in test mode)
- Tracks open positions across restarts (`restoreOpenPositions`)
- Stores all closed trades with full PnL details
- Historical stats merged with in-memory session stats on startup
## Signals
@@ -184,23 +184,21 @@ Built-in HTTP server at `:8888` with real-time SSE push (1-second refresh):
```
exchange-monitor-go/
├── main.go # Entry point, WS startup, main loop
├── config.go # .env + config.json hierarchical config
├── config.go # config.json + .env hierarchical config
├── config.json # All trading parameters (editable)
├── 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)
├── trader.go # Position management, entry/exit/scale-in
├── dashboard.go # Web server + SSE + stats calc
├── 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)
├── .env # Secrets only (API keys)
├── 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.go # Bitget ticker WS (TextPing for stability)
│ ├── bitget_trade.go # Bitget REST trade API
│ ├── dydx.go # dYdX v4_markets WS
│ ├── helpers.go # Package helpers
│ └── ping.go # Accessibility check tools
├── db/