Fix SHORT position P&L calculation bug

CRITICAL BUG FIX: SHORT positions were calculating P&L with inverted logic,
causing profits to be recorded as losses and vice versa.

Problem Example:
- SHORT at $156.58, exit at $154.66 (price dropped $1.92)
- Should be +~$25 profit
- Was recorded as -$499.23 LOSS

Root Cause:
Old formula: profitPercent = (exit - entry) / entry * (side === 'long' ? 1 : -1)
This multiplied the LONG formula by -1 for shorts, but then applied it to
full notional instead of properly accounting for direction.

Fix:
- LONG: priceDiff = (exit - entry) → profit when price rises
- SHORT: priceDiff = (entry - exit) → profit when price falls
- profitPercent = priceDiff / entry * 100
- Proper leverage calculation: realizedPnL = collateral * profitPercent * leverage

This fixes both dry-run and live close position calculations in lib/drift/orders.ts

Impact: All SHORT trades since bot launch have incorrect P&L in database.
Future trades will calculate correctly.
This commit is contained in:
mindesbunister
2025-11-07 14:53:03 +01:00
parent a8de1c9d37
commit 4996bc2aad

View File

@@ -527,10 +527,18 @@ export async function closePosition(
console.log('🧪 DRY RUN MODE: Simulating close order (not executing on blockchain)')
// Calculate realized P&L with leverage (default 10x in dry run)
const profitPercent = ((oraclePrice - position.entryPrice) / position.entryPrice) * 100 * (position.side === 'long' ? 1 : -1)
// For LONG: profit when exit > entry → (exit - entry) / entry
// For SHORT: profit when exit < entry → (entry - exit) / entry
const priceDiff = position.side === 'long'
? (oraclePrice - position.entryPrice) // Long: profit when price rises
: (position.entryPrice - oraclePrice) // Short: profit when price falls
const profitPercent = (priceDiff / position.entryPrice) * 100
const closedNotional = sizeToClose * oraclePrice
const realizedPnL = (closedNotional * profitPercent) / 100
const accountPnLPercent = profitPercent * 10 // display using default leverage
const leverage = 10
const collateral = closedNotional / leverage
const realizedPnL = collateral * (profitPercent / 100) * leverage
const accountPnLPercent = profitPercent * leverage
const mockTxSig = `DRY_RUN_CLOSE_${Date.now()}_${Math.random().toString(36).substring(7)}`
@@ -578,8 +586,13 @@ export async function closePosition(
console.log('✅ Transaction confirmed on-chain')
// Calculate realized P&L with leverage
// CRITICAL: P&L must account for leverage and be calculated on USD notional, not base asset size
const profitPercent = ((oraclePrice - position.entryPrice) / position.entryPrice) * 100 * (position.side === 'long' ? 1 : -1)
// For LONG: profit when exit > entry → (exit - entry) / entry
// For SHORT: profit when exit < entry → (entry - exit) / entry
const priceDiff = position.side === 'long'
? (oraclePrice - position.entryPrice) // Long: profit when price rises
: (position.entryPrice - oraclePrice) // Short: profit when price falls
const profitPercent = (priceDiff / position.entryPrice) * 100
// Get leverage from user account (defaults to 10x if not found)
let leverage = 10
@@ -593,9 +606,10 @@ export async function closePosition(
console.log('⚠️ Could not determine leverage from account, using 10x default')
}
// Calculate closed notional value (USD)
// Calculate closed notional value (USD) and actual P&L with leverage
const closedNotional = sizeToClose * oraclePrice
const realizedPnL = (closedNotional * profitPercent) / 100
const collateral = closedNotional / leverage
const realizedPnL = collateral * (profitPercent / 100) * leverage // Leveraged P&L
const accountPnLPercent = profitPercent * leverage
console.log(`💰 Close details:`)