feat: 添加OKX行情接入+趋势检测+累积变动系统+界面重构
- 新增OKX WebSocket行情连接器,扩展4交易所价格监控 - 新增z-score趋势检测引擎(TrendDetector),识别价格异动/趋势启动 - 新增累积变动跟踪(CumulativeTracker),基于1min/5min多交易所共识 - 趋势事件和累积变动事件持久化到SQLite - 新增Binance/OKX动量检测字段,扩展前端动量卡片至15列 - 迁移至macOS(darwin-arm64),更新前端依赖 - Dashboard网格重构:非交易卡片置顶,交易卡片置底 - TrackedCoin添加OK字段,添加ExBinance/ExOKX常量 - 前端新增趋势检测卡片、趋势历史卡片、累积变动卡片 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
047571921e
commit
b7767c95ae
@@ -60,6 +60,21 @@ func main() {
|
||||
store := NewPriceStore()
|
||||
notifier := NewNotifier(cfg.TelegramBotToken, cfg.TelegramChatID)
|
||||
|
||||
// Initialize momentum tracker (for momentum scanning mode)
|
||||
momentumTracker := NewMomentumTracker()
|
||||
|
||||
// Initialize trend detector (for price anomaly / trend detection)
|
||||
trendDetector := NewTrendDetector(momentumTracker)
|
||||
if cfg.TrendEnabled {
|
||||
trendDetector.Configure(cfg.TrendBaselineWindow, cfg.TrendAnomalyMul, cfg.TrendConfirmTicks, cfg.TrendAlertCooldown)
|
||||
log.Printf("[Trend] Z-score detection enabled (z-score >= %.1fσ, window=%d ticks, confirm=%d ticks)",
|
||||
cfg.TrendAnomalyMul, cfg.TrendBaselineWindow, cfg.TrendConfirmTicks)
|
||||
}
|
||||
|
||||
// Initialize cumulative tracker (1min/5min multi-exchange consensus change)
|
||||
cumulativeTracker := NewCumulativeTracker()
|
||||
log.Printf("[CM] Cumulative change tracking enabled (1m >= %.1f%%, 3+ exchanges)", cumulativeTracker.surgePct1m)
|
||||
|
||||
// Initialize SQLite database
|
||||
database, err := db.Open("")
|
||||
if err != nil {
|
||||
@@ -75,7 +90,7 @@ func main() {
|
||||
trader.startIPCServer()
|
||||
|
||||
// Initialize dashboard (web server + SSE)
|
||||
dashboard := NewDashboard(store, trader, database, ":8888")
|
||||
dashboard := NewDashboard(store, trader, database, ":8888", cfg, momentumTracker, trendDetector, cumulativeTracker)
|
||||
go dashboard.Run()
|
||||
|
||||
// Spread window tracker — measures how long spreads stay above threshold
|
||||
@@ -83,7 +98,9 @@ func main() {
|
||||
|
||||
// P3-4: wire real-time trade event broadcast
|
||||
trader.OnTradeEvent = dashboard.BroadcastEvent
|
||||
if trader.IsConfigured() {
|
||||
if cfg.MomentumEnabled {
|
||||
log.Printf("[Trader] MOMENTUM SCAN mode: arbitrage trading disabled, momentum detection active (threshold >= %.2f%%)", cfg.MomentumThresholdPct)
|
||||
} else if trader.IsConfigured() {
|
||||
log.Printf("[Trader] %s mode: automated trading ENABLED (threshold >= %.2f%%, $%.0f/leg, max %d positions, $%.0f capital)",
|
||||
trader.ModeLabel(), cfg.TradeThreshold, cfg.TradeAmountUSD, cfg.MaxPositions, cfg.InitialCapital)
|
||||
if cfg.TestMode {
|
||||
@@ -101,8 +118,8 @@ func main() {
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGUSR1)
|
||||
|
||||
// Collect symbols — only BG and HL for now (BN, dYdX disabled)
|
||||
var bgSymbols, hlSymbols []string
|
||||
// Collect symbols for all exchanges
|
||||
var bgSymbols, hlSymbols, bnSymbols, okxSymbols []string
|
||||
for _, c := range TrackedCoins {
|
||||
if c.BG != "" {
|
||||
bgSymbols = append(bgSymbols, c.BG)
|
||||
@@ -110,9 +127,15 @@ func main() {
|
||||
if c.HL != "" {
|
||||
hlSymbols = append(hlSymbols, c.HL)
|
||||
}
|
||||
if c.BN != "" {
|
||||
bnSymbols = append(bnSymbols, c.BN)
|
||||
}
|
||||
if c.OK != "" {
|
||||
okxSymbols = append(okxSymbols, c.OK)
|
||||
}
|
||||
}
|
||||
|
||||
// Start exchange WS connections (BG + HL only)
|
||||
// Start exchange WS connections
|
||||
startExchange := func(name string, runner func(func(string, float64, float64, float64)) error) {
|
||||
go func() {
|
||||
for {
|
||||
@@ -133,6 +156,8 @@ func main() {
|
||||
|
||||
startExchange("HyperLiquid", exchange.NewHyperLiquidWS(hlSymbols).Run)
|
||||
startExchange("Bitget", exchange.NewBitgetWS(bgSymbols).Run)
|
||||
startExchange("Binance", exchange.NewBinanceWS(bnSymbols).Run)
|
||||
startExchange("OKX", exchange.NewOKXWS(okxSymbols).Run)
|
||||
|
||||
log.Println("[Monitor] Waiting for initial data...")
|
||||
time.Sleep(10 * time.Second)
|
||||
@@ -206,6 +231,25 @@ func main() {
|
||||
|
||||
// Scan for arbitrage entries using maker fees (limit orders)
|
||||
snap := store.GetAll()
|
||||
|
||||
// Feed prices to momentum tracker (for momentum scanning or trend detection)
|
||||
if cfg.MomentumEnabled || cfg.TrendEnabled {
|
||||
for coin, exMap := range snap {
|
||||
for ex, price := range exMap {
|
||||
momentumTracker.Record(coin, ex, price)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Feed snapshots to cumulative tracker (always on)
|
||||
for _, tc := range TrackedCoins {
|
||||
exMap := snap[tc.Name]
|
||||
if exMap == nil || len(exMap) < 3 {
|
||||
continue
|
||||
}
|
||||
cumulativeTracker.Record(tc.Name, exMap)
|
||||
}
|
||||
|
||||
makerOpps := ScanBGHL(snap)
|
||||
dashboard.UpdateScan(makerOpps)
|
||||
t2 := time.Now()
|
||||
@@ -213,12 +257,15 @@ func main() {
|
||||
// Track spread window durations (how long each opportunity stays alive)
|
||||
spreadTracker.Tick(snap, cfg.TradeThreshold)
|
||||
|
||||
for _, opp := range makerOpps {
|
||||
if opp.NetProfit < cfg.ArbThreshold {
|
||||
continue
|
||||
}
|
||||
if trader.TryEntry(opp, store, notifier) {
|
||||
log.Printf("[Trader] %s: entry initiated for %.4f%%", opp.Coin, opp.NetProfit)
|
||||
// In momentum mode, arbitrage trading is disabled
|
||||
if !cfg.MomentumEnabled {
|
||||
for _, opp := range makerOpps {
|
||||
if opp.NetProfit < cfg.ArbThreshold {
|
||||
continue
|
||||
}
|
||||
if trader.TryEntry(opp, store, notifier) {
|
||||
log.Printf("[Trader] %s: entry initiated for %.4f%%", opp.Coin, opp.NetProfit)
|
||||
}
|
||||
}
|
||||
}
|
||||
t3 := time.Now()
|
||||
|
||||
Reference in New Issue
Block a user