Phase 2: Web dashboard with SSE real-time push

- dashboard.go: SSE hub + HTTP server + price history ring buffer
- static.go: //go:embed for static files
- web/static/index.html: Full dashboard HTML (6 panels)
- web/static/app.js: SSE client, Chart.js price chart, live table updates
- web/static/style.css: GitHub-style dark theme
- main.go: Start dashboard on :8888 + wire price recording + scan results

Dashboard features:
  - Real-time price table (6 coins × 4 exchanges)
  - Arbitrage opportunities table
  - Open positions view
  - Historical trades table (from SQLite)
  - Chart.js price chart with coin/exchange selector
  - Stats summary (total/converged/diverged/flat)
  - 🚫 Zero external Go dependencies (Chart.js loaded from CDN)
This commit is contained in:
jackyu66git
2026-05-03 17:38:26 +08:00
parent 0c1eaedcb6
commit c2489614a7
6 changed files with 1158 additions and 0 deletions
+6
View File
@@ -45,6 +45,10 @@ func main() {
// Initialize trader
trader := NewTrader(cfg, database)
// Initialize dashboard (web server + SSE)
dashboard := NewDashboard(store, trader, database, ":8888")
go dashboard.Run()
if trader.IsConfigured() {
modeLabel := trader.ModeLabel()
log.Printf("[Trader] %s mode: automated trading ENABLED (threshold >= %.2f%%, $%.0f/trade)",
@@ -79,6 +83,7 @@ func main() {
for {
err := runner(func(coin string, price, bid, ask float64) {
store.SetWithSpread(coin, name, price, bid, ask)
dashboard.RecordPrice(coin, name, price)
})
log.Printf("[%s] WS error: %v (reconnecting...)", name, err)
select {
@@ -155,6 +160,7 @@ func main() {
// Scan for arbitrage entries using maker fees (limit orders)
makerOpps := ScanArbWithFees(store, makerFees)
dashboard.UpdateScan(makerOpps)
t2 := time.Now()
for _, opp := range makerOpps {