feat: 重构为三所价差异动监控系统
删除 HyperLiquid + 全部交易功能,构建自适应 surge 检测器。 - 新增 surge_detector.go: 每币独立滚动窗口基线,检测三所价差异常飙升 - 新增 SpreadCard/SurgeCard 前端组件 - 保留 momentum/trend/cumulative/trend_filter 扫描功能 - 更新文档和配置以反映新系统 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
559d7bb870
commit
d38782490c
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -11,7 +10,6 @@ type TrackedCoin struct {
|
||||
Name string // Display name (BTC, ETH, etc.)
|
||||
BN string // Binance symbol (BTCUSDT)
|
||||
BG string // Bitget symbol (BTCUSDT)
|
||||
HL string // HyperLiquid symbol (BTC)
|
||||
OK string // OKX symbol (BTC-USDT-SWAP)
|
||||
}
|
||||
|
||||
@@ -31,9 +29,9 @@ type Spread struct {
|
||||
|
||||
// PriceStore holds the latest prices from all exchanges, thread-safe.
|
||||
type PriceStore struct {
|
||||
mu sync.RWMutex
|
||||
prices map[string]map[string]float64 // coin -> exchange -> price
|
||||
spreads map[string]map[string]*Spread // coin -> exchange -> spread
|
||||
mu sync.RWMutex
|
||||
prices map[string]map[string]float64 // coin -> exchange -> price
|
||||
spreads map[string]map[string]*Spread // coin -> exchange -> spread
|
||||
}
|
||||
|
||||
func NewPriceStore() *PriceStore {
|
||||
@@ -109,92 +107,3 @@ func (s *PriceStore) GetAll() map[string]map[string]float64 {
|
||||
}
|
||||
return snap
|
||||
}
|
||||
|
||||
// ArbOpportunity represents a profitable arbitrage route.
|
||||
type ArbOpportunity struct {
|
||||
Coin string
|
||||
Direction string // e.g. "BN->HL"
|
||||
BuyEx string
|
||||
SellEx string
|
||||
BuyPrice float64
|
||||
SellPrice float64
|
||||
NetProfit float64 // percentage after fees
|
||||
GrossBasis float64 // raw price difference %
|
||||
}
|
||||
|
||||
// SpreadWindow tracks how long each coin's spread stays above threshold.
|
||||
// Used to measure the window of opportunity between threshold-crossing and
|
||||
// convergence — helps diagnose whether entry latency is a problem.
|
||||
type SpreadWindow struct {
|
||||
Coin string
|
||||
Direction string // "BG->HL" or "HL->BG"
|
||||
Since time.Time
|
||||
PeakNet float64 // highest netProfit % observed during this window
|
||||
}
|
||||
|
||||
type SpreadWindowTracker struct {
|
||||
windows map[string]*SpreadWindow // key: "COIN:DIRECTION"
|
||||
}
|
||||
|
||||
func NewSpreadWindowTracker() *SpreadWindowTracker {
|
||||
return &SpreadWindowTracker{windows: make(map[string]*SpreadWindow)}
|
||||
}
|
||||
|
||||
func (swt *SpreadWindowTracker) Tick(snap map[string]map[string]float64, threshold float64) {
|
||||
now := time.Now()
|
||||
for _, coin := range TrackedCoins {
|
||||
if coin.BG == "" || coin.HL == "" {
|
||||
continue
|
||||
}
|
||||
exMap := snap[coin.Name]
|
||||
if exMap == nil {
|
||||
continue
|
||||
}
|
||||
bgP := exMap[ExBitget]
|
||||
hlP := exMap[ExHyperLiquid]
|
||||
if bgP <= 0 || hlP <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check both directions — use netProfit() for exact fee model match
|
||||
// BG→HL: buy BG (Bitget 0.020%), sell HL (HL 0.015%)
|
||||
// HL→BG: buy HL (HL 0.015%), sell BG (Bitget 0.020%)
|
||||
type dirCheck struct {
|
||||
name string
|
||||
buyPrice float64
|
||||
sellPrice float64
|
||||
buyFee float64
|
||||
sellFee float64
|
||||
}
|
||||
for _, dir := range []dirCheck{
|
||||
{"BG->HL", bgP, hlP, takerFees[ExBitget], takerFees[ExHyperLiquid]},
|
||||
{"HL->BG", hlP, bgP, takerFees[ExHyperLiquid], takerFees[ExBitget]},
|
||||
} {
|
||||
key := coin.Name + ":" + dir.name
|
||||
netSpr := netProfit(dir.buyPrice, dir.sellPrice, dir.buyFee, dir.sellFee)
|
||||
|
||||
w, exists := swt.windows[key]
|
||||
if netSpr >= threshold {
|
||||
if !exists {
|
||||
swt.windows[key] = &SpreadWindow{
|
||||
Coin: coin.Name,
|
||||
Direction: dir.name,
|
||||
Since: now,
|
||||
PeakNet: netSpr,
|
||||
}
|
||||
} else if netSpr > w.PeakNet {
|
||||
w.PeakNet = netSpr
|
||||
}
|
||||
} else {
|
||||
if exists {
|
||||
dur := now.Sub(w.Since)
|
||||
if dur > 100*time.Millisecond {
|
||||
log.Printf("[SpreadWindow] %s %s exceeded threshold for %v (peak net=%+.4f%%)",
|
||||
w.Coin, w.Direction, dur.Round(time.Millisecond), w.PeakNet)
|
||||
}
|
||||
delete(swt.windows, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user