fix: data race, scale-in PnL, nonce mutex, dead code, hourly check
- 🔴 Data race: Add GetPositionsCopy() returning deep copies (no shared ArbPosition pointers). Use it in dashboard broadcastLoop + handleStatus. - 🟡 Scale-in PnL: Track LongEntryPrices/ShortEntryPrices on ArbPosition, compute weighted average (harmonic mean) at exit for accurate PnL. - 🟢 CalcNetProfit: Delete dead code from exchange/helpers.go. - 🟢 HL nonce: Add sync.Mutex around lastNonce++ (thread safety). - 🟢 Hourly check: Change from 5-second window to minute window. - 🟢 ExitPrice: Test mode closeLeg already handled by checkExit.
This commit is contained in:
+8
-6
@@ -290,8 +290,8 @@ func (d *Dashboard) broadcastLoop() {
|
||||
}
|
||||
d.hub.Broadcast("prices", prices)
|
||||
|
||||
// 2. Open positions with live PnL (P3-3)
|
||||
positions := d.trader.GetOpenPositions()
|
||||
// 2. Open positions with live PnL (P3-3) — use safe copy for concurrent read
|
||||
positions := d.trader.GetPositionsCopy()
|
||||
posList := make([]map[string]interface{}, 0, len(positions))
|
||||
for _, pos := range positions {
|
||||
posEntry := map[string]interface{}{
|
||||
@@ -304,7 +304,7 @@ func (d *Dashboard) broadcastLoop() {
|
||||
"started_at": pos.StartedAt.Format("15:04:05"),
|
||||
}
|
||||
|
||||
// Calculate live PnL from current prices
|
||||
// Calculate live PnL from current prices — use weighted average for scale-ins
|
||||
if exMap := snap[pos.Coin]; exMap != nil {
|
||||
bgP := exMap[ExBitget]
|
||||
hlP := exMap[ExHyperLiquid]
|
||||
@@ -315,8 +315,10 @@ func (d *Dashboard) broadcastLoop() {
|
||||
} else {
|
||||
longCurrent, shortCurrent = hlP, bgP
|
||||
}
|
||||
longPnl := (longCurrent - pos.LongLeg.EntryPrice) / pos.LongLeg.EntryPrice * 100
|
||||
shortPnl := (pos.ShortLeg.EntryPrice - shortCurrent) / pos.ShortLeg.EntryPrice * 100
|
||||
longAvg := weightedAvgPrice(pos.LongEntryPrices, pos.AmountUSD/float64(max(1, len(pos.LongEntryPrices))))
|
||||
shortAvg := weightedAvgPrice(pos.ShortEntryPrices, pos.AmountUSD/float64(max(1, len(pos.ShortEntryPrices))))
|
||||
longPnl := (longCurrent - longAvg) / longAvg * 100
|
||||
shortPnl := (shortAvg - shortCurrent) / shortAvg * 100
|
||||
totalFees := 2 * (makerFees[ExBitget] + makerFees[ExHyperLiquid])
|
||||
netPnl := longPnl + shortPnl - totalFees
|
||||
|
||||
@@ -426,7 +428,7 @@ func (d *Dashboard) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (d *Dashboard) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
snap := d.store.GetAll()
|
||||
positions := d.trader.GetOpenPositions()
|
||||
positions := d.trader.GetPositionsCopy()
|
||||
converged, diverged, flat, total := d.trader.GetClosedStats()
|
||||
|
||||
resp := map[string]interface{}{
|
||||
|
||||
Reference in New Issue
Block a user