fix: PnL计算改为美元归一化,加仓不再虚增手续费 (calcArbPnL)
This commit is contained in:
@@ -520,8 +520,7 @@ func (t *Trader) checkExit(pos *ArbPosition, bgP, hlP, diffPct float64, notifier
|
|||||||
|
|
||||||
longPnl := (longCurrent - longAvg) / longAvg * 100
|
longPnl := (longCurrent - longAvg) / longAvg * 100
|
||||||
shortPnl := (shortAvg - shortCurrent) / shortAvg * 100
|
shortPnl := (shortAvg - shortCurrent) / shortAvg * 100
|
||||||
totalFees := float64(2+pos.ScaleLevels) * (takerFees[ExBitget] + takerFees[ExHyperLiquid]) // 开仓(含加仓) + 平仓手续费
|
netPnl, totalFees := calcArbPnL(longPnl, shortPnl, pos.ScaleLevels, t.cfg.TradeAmountUSD) // 净利为总资本的百分比
|
||||||
netPnl := longPnl + shortPnl - totalFees
|
|
||||||
|
|
||||||
elapsed := time.Since(pos.StartedAt)
|
elapsed := time.Since(pos.StartedAt)
|
||||||
|
|
||||||
@@ -602,7 +601,7 @@ func (t *Trader) checkExit(pos *ArbPosition, bgP, hlP, diffPct float64, notifier
|
|||||||
EntrySpread: pos.EntrySpread,
|
EntrySpread: pos.EntrySpread,
|
||||||
ExitSpread: diffPct,
|
ExitSpread: diffPct,
|
||||||
PnlPct: netPnl,
|
PnlPct: netPnl,
|
||||||
PnlUSD: pos.AmountUSD * netPnl / 100,
|
PnlUSD: 2 * pos.AmountUSD * netPnl / 100,
|
||||||
Convergence: convergenceLabel,
|
Convergence: convergenceLabel,
|
||||||
Reason: exitReason,
|
Reason: exitReason,
|
||||||
Duration: elapsed.Round(time.Second).String(),
|
Duration: elapsed.Round(time.Second).String(),
|
||||||
@@ -854,6 +853,27 @@ func (t *Trader) GetOpenPositions() []*ArbPosition {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calcArbPnL computes net PnL and total fees in USD, then normalizes to % of total deployed capital.
|
||||||
|
// This correctly handles scale-ins where the old formula (longPnl+shortPnl - (2+N)*0.105)
|
||||||
|
// double-counted fees because it didn't divide by (1+N) batches.
|
||||||
|
func calcArbPnL(longPnl, shortPnl float64, scaleLevels int, tradeAmountUSD float64) (netPnlPct, feePct float64) {
|
||||||
|
numBatches := 1 + scaleLevels
|
||||||
|
legCapital := tradeAmountUSD
|
||||||
|
totalCapital := float64(numBatches) * 2 * legCapital
|
||||||
|
|
||||||
|
// Gross PnL in USD
|
||||||
|
longPnlUSD := longPnl / 100 * float64(numBatches) * legCapital
|
||||||
|
shortPnlUSD := shortPnl / 100 * float64(numBatches) * legCapital
|
||||||
|
grossPnLUSD := longPnlUSD + shortPnlUSD
|
||||||
|
|
||||||
|
// Fee in USD (entry+exit per order-pair)
|
||||||
|
feeUSD := float64(2+scaleLevels) * legCapital * (takerFees[ExBitget] + takerFees[ExHyperLiquid]) / 100
|
||||||
|
|
||||||
|
netPnlPct = (grossPnLUSD - feeUSD) / totalCapital * 100
|
||||||
|
feePct = feeUSD / totalCapital * 100
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// weightedAvgPrice computes the weighted average entry price across multiple scale levels.
|
// weightedAvgPrice computes the weighted average entry price across multiple scale levels.
|
||||||
// Each level trades the same USD amount, so the result is the harmonic mean of prices.
|
// Each level trades the same USD amount, so the result is the harmonic mean of prices.
|
||||||
func weightedAvgPrice(prices []float64, amountPerTrade float64) float64 {
|
func weightedAvgPrice(prices []float64, amountPerTrade float64) float64 {
|
||||||
@@ -1161,8 +1181,7 @@ func (t *Trader) blacklistCoin(pos *ArbPosition, bgP, hlP, diffPct float64, noti
|
|||||||
shortAvg := weightedAvgPrice(pos.ShortEntryPrices, t.cfg.TradeAmountUSD)
|
shortAvg := weightedAvgPrice(pos.ShortEntryPrices, t.cfg.TradeAmountUSD)
|
||||||
longPnl := (longCurrent - longAvg) / longAvg * 100
|
longPnl := (longCurrent - longAvg) / longAvg * 100
|
||||||
shortPnl := (shortAvg - shortCurrent) / shortAvg * 100
|
shortPnl := (shortAvg - shortCurrent) / shortAvg * 100
|
||||||
totalFees := float64(2+pos.ScaleLevels) * (takerFees[ExBitget] + takerFees[ExHyperLiquid])
|
netPnl, totalFees := calcArbPnL(longPnl, shortPnl, pos.ScaleLevels, t.cfg.TradeAmountUSD)
|
||||||
netPnl := longPnl + shortPnl - totalFees
|
|
||||||
|
|
||||||
pos.ExitDiffPct = diffPct
|
pos.ExitDiffPct = diffPct
|
||||||
pos.ExitNetPnl = netPnl
|
pos.ExitNetPnl = netPnl
|
||||||
|
|||||||
Reference in New Issue
Block a user