decouple display from trading: snapMu + RefreshSnapshot/ReadSnapshot
- Add snapMu RWMutex + positionsSnapshot to Trader - RefreshSnapshot() called from main loop after Tick() — acquires t.mu briefly, stores deep copy under snapMu - ReadSnapshot() returns snapshot copy under snapMu.RLock — never touches t.mu, zero contention with trading path - Dashboard + handleStatus + hourly summary + status log all use ReadSnapshot() instead of GetPositionsCopy() - Trading path (Tick/TryEntry/executeEntry/checkExit/checkScaleIn) never blocked by display reads - Snapshot is at most 1 tick behind live state — acceptable delay
This commit is contained in:
@@ -147,8 +147,8 @@ func main() {
|
||||
}
|
||||
log.Printf("[Status] %d prices / %d coins connected", count, len(snap))
|
||||
|
||||
// Show open positions
|
||||
if positions := trader.GetOpenPositions(); len(positions) > 0 {
|
||||
// Show open positions (read from decoupled snapshot)
|
||||
if positions := trader.ReadSnapshot(); len(positions) > 0 {
|
||||
for _, pos := range positions {
|
||||
log.Printf(" [Position] %s %s open %d scales $%.0f since %s",
|
||||
pos.Coin, pos.Direction, pos.ScaleLevels, pos.AmountUSD,
|
||||
@@ -162,6 +162,7 @@ func main() {
|
||||
|
||||
// Tick the trader (monitor open positions for exit)
|
||||
trader.Tick(store, notifier)
|
||||
trader.RefreshSnapshot() // decoupled snapshot for display
|
||||
t1 := time.Now()
|
||||
|
||||
// Scan for arbitrage entries using maker fees (limit orders)
|
||||
@@ -190,7 +191,7 @@ func main() {
|
||||
// Hourly trade summary — use hour-based tracking (wider window than second-granularity)
|
||||
hour := now.Hour()
|
||||
if hour != lastHour && now.Minute() < 1 {
|
||||
positions := trader.GetPositionsCopy()
|
||||
positions := trader.ReadSnapshot()
|
||||
notifier.SendTradeSummary(positions, now.Format("2006-01-02 15:04"))
|
||||
lastHour = hour
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user