fix: retryClose saves trade record and persists to DB on success
This commit is contained in:
@@ -51,6 +51,15 @@ type ArbPosition struct {
|
|||||||
RealizedPnl float64
|
RealizedPnl float64
|
||||||
ErrorLog string
|
ErrorLog string
|
||||||
|
|
||||||
|
// Exit metadata — saved when close is first attempted; reused by retryClose
|
||||||
|
ExitDiffPct float64 // spread % at exit trigger
|
||||||
|
ExitNetPnl float64 // net PnL % at exit trigger
|
||||||
|
ExitLongPnl float64 // long leg PnL %
|
||||||
|
ExitShortPnl float64 // short leg PnL %
|
||||||
|
ExitTotalFees float64 // total fee %
|
||||||
|
ExitConvergence string // convergence label
|
||||||
|
ExitReasonText string // reason for exit
|
||||||
|
|
||||||
// Track all entry prices for weighted-average PnL across scale-ins (Issue #2)
|
// Track all entry prices for weighted-average PnL across scale-ins (Issue #2)
|
||||||
LongEntryPrices []float64 // all long entry prices (initial + scale-ins)
|
LongEntryPrices []float64 // all long entry prices (initial + scale-ins)
|
||||||
ShortEntryPrices []float64 // all short entry prices (initial + scale-ins)
|
ShortEntryPrices []float64 // all short entry prices (initial + scale-ins)
|
||||||
@@ -534,6 +543,15 @@ func (t *Trader) checkExit(pos *ArbPosition, bgP, hlP, diffPct float64, notifier
|
|||||||
pos.LongLeg.ExitPrice = longCurrent
|
pos.LongLeg.ExitPrice = longCurrent
|
||||||
pos.ShortLeg.ExitPrice = shortCurrent
|
pos.ShortLeg.ExitPrice = shortCurrent
|
||||||
|
|
||||||
|
// Save exit metadata for retryClose in case closeBothLegs fails
|
||||||
|
pos.ExitDiffPct = diffPct
|
||||||
|
pos.ExitNetPnl = netPnl
|
||||||
|
pos.ExitLongPnl = longPnl
|
||||||
|
pos.ExitShortPnl = shortPnl
|
||||||
|
pos.ExitTotalFees = totalFees
|
||||||
|
pos.ExitConvergence = convergenceLabel
|
||||||
|
pos.ExitReasonText = exitReason
|
||||||
|
|
||||||
closeErr := t.closeBothLegs(pos)
|
closeErr := t.closeBothLegs(pos)
|
||||||
|
|
||||||
if closeErr != "" {
|
if closeErr != "" {
|
||||||
@@ -691,17 +709,41 @@ func (t *Trader) retryClose(pos *ArbPosition, bgP, hlP float64, notifier *Notifi
|
|||||||
|
|
||||||
closeErr := t.closeBothLegs(pos)
|
closeErr := t.closeBothLegs(pos)
|
||||||
if closeErr == "" {
|
if closeErr == "" {
|
||||||
// All legs finally closed — mark as done
|
// All legs finally closed — record + persist
|
||||||
pos.Status = "closed"
|
pos.Status = "closed"
|
||||||
pos.ExitedAt = time.Now()
|
pos.ExitedAt = time.Now()
|
||||||
|
|
||||||
|
elapsed := time.Since(pos.StartedAt)
|
||||||
|
record := TradeRecord{
|
||||||
|
Coin: pos.Coin,
|
||||||
|
Direction: pos.Direction,
|
||||||
|
EntrySpread: pos.EntrySpread,
|
||||||
|
ExitSpread: pos.ExitDiffPct,
|
||||||
|
PnlPct: pos.ExitNetPnl,
|
||||||
|
Convergence: pos.ExitConvergence,
|
||||||
|
Reason: pos.ExitReasonText,
|
||||||
|
Duration: elapsed.Round(time.Second).String(),
|
||||||
|
OpenedAt: pos.StartedAt,
|
||||||
|
ClosedAt: pos.ExitedAt,
|
||||||
|
ScaleLevels: pos.ScaleLevels,
|
||||||
|
AmountUSD: pos.AmountUSD,
|
||||||
|
}
|
||||||
|
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
delete(t.positions, pos.Coin)
|
delete(t.positions, pos.Coin)
|
||||||
t.lastTradeTime[pos.Coin] = time.Now()
|
t.lastTradeTime[pos.Coin] = time.Now()
|
||||||
|
t.closedTrades = append(t.closedTrades, record)
|
||||||
t.mu.Unlock()
|
t.mu.Unlock()
|
||||||
|
|
||||||
|
if t.db != nil {
|
||||||
|
t.persistTrade(pos, pos.ExitDiffPct, pos.ExitConvergence, pos.ExitReasonText,
|
||||||
|
pos.ExitNetPnl, pos.ExitLongPnl, pos.ExitShortPnl, pos.ExitTotalFees)
|
||||||
|
}
|
||||||
|
|
||||||
notifier.Send(fmt.Sprintf(
|
notifier.Send(fmt.Sprintf(
|
||||||
"<b>[平仓重试成功]</b> %s/USDT %s\n"+
|
"<b>[平仓重试成功]</b> %s/USDT %s\n"+
|
||||||
" 之前失败: %s\n"+
|
" 之前失败: %s\n"+
|
||||||
" 已成功关掉所有腿\n", pos.Coin, pos.Direction, pos.ErrorLog))
|
" 已成功关掉所有腿 | 盈亏: %+.4f%%\n", pos.Coin, pos.Direction, pos.ErrorLog, pos.ExitNetPnl))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user