Add Net USD Value display to dashboard

- Updated AccountBalance interface to include netUsdValue and unrealizedPnl
- Enhanced getAccountBalance() to calculate Net USD Value (collateral + unrealized PnL)
- Added Net USD Value calculation from all position unrealized PnL
- Updated Dashboard.tsx to display Net USD Value as primary metric
- Added new stats card with emerald styling for Net USD Value
- Reorganized stats grid to 6 columns to accommodate new metric
- Net USD Value = Total Collateral + Total Unrealized PnL from all positions
This commit is contained in:
mindesbunister
2025-07-13 01:02:48 +02:00
parent 6e75a7175e
commit 2fcd3b1120
3 changed files with 226 additions and 134 deletions

View File

@@ -50,6 +50,8 @@ export interface AccountBalance {
accountValue: number
leverage: number
availableBalance: number
netUsdValue: number
unrealizedPnl: number
}
export interface TradeHistory {
@@ -181,8 +183,11 @@ export class DriftTradingService {
async getAccountBalance(): Promise<AccountBalance> {
try {
if (this.isInitialized && this.driftClient) {
// Try to use SDK without subscription
// Subscribe to user account to access balance data
try {
console.log('🔍 Subscribing to user account for balance...')
await this.driftClient.subscribe()
const user = this.driftClient.getUser()
// Get account equity and collateral information using proper SDK methods
@@ -213,17 +218,67 @@ export class DriftTradingService {
const leverage = marginRequirement > 0 ? totalCollateral / marginRequirement : 1
const availableBalance = freeCollateral
// Calculate unrealized PnL from all positions
let totalUnrealizedPnl = 0
try {
// Get all perp positions to calculate total unrealized PnL
const mainMarkets = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // Check more markets for PnL
for (const marketIndex of mainMarkets) {
try {
const position = user.getPerpPosition(marketIndex)
if (!position || position.baseAssetAmount.isZero()) continue
// Calculate unrealized PnL manually
const marketData = this.driftClient.getPerpMarketAccount(marketIndex)
const markPrice = convertToNumber(marketData?.amm.lastMarkPriceTwap || new BN(0), PRICE_PRECISION)
const entryPrice = convertToNumber(position.quoteEntryAmount.abs(), PRICE_PRECISION) /
convertToNumber(position.baseAssetAmount.abs(), BASE_PRECISION)
const size = convertToNumber(position.baseAssetAmount.abs(), BASE_PRECISION)
const isLong = position.baseAssetAmount.gt(new BN(0))
const unrealizedPnl = isLong ?
(markPrice - entryPrice) * size :
(entryPrice - markPrice) * size
totalUnrealizedPnl += unrealizedPnl
} catch (e) {
// Skip markets that don't exist
continue
}
}
} catch (e) {
console.warn('Could not calculate unrealized PnL:', e)
}
// Net USD Value = Total Collateral + Unrealized PnL
const netUsdValue = totalCollateral + totalUnrealizedPnl
console.log(`💰 Account balance: $${accountValue.toFixed(2)}, Net USD: $${netUsdValue.toFixed(2)}, PnL: $${totalUnrealizedPnl.toFixed(2)}`)
return {
totalCollateral,
freeCollateral,
marginRequirement,
accountValue,
leverage,
availableBalance
availableBalance,
netUsdValue,
unrealizedPnl: totalUnrealizedPnl
}
} catch (sdkError: any) {
console.log('⚠️ SDK method failed, using fallback:', sdkError.message)
console.log('⚠️ SDK balance method failed, using fallback:', sdkError.message)
// Fall through to fallback method
} finally {
// Always unsubscribe to clean up
if (this.driftClient) {
try {
await this.driftClient.unsubscribe()
} catch (e) {
// Ignore unsubscribe errors
}
}
}
}
@@ -237,7 +292,9 @@ export class DriftTradingService {
marginRequirement: 0,
accountValue: balance / 1e9, // SOL balance
leverage: 0,
availableBalance: 0
availableBalance: 0,
netUsdValue: balance / 1e9, // Use SOL balance as fallback
unrealizedPnl: 0
}
} catch (error: any) {
@@ -281,8 +338,11 @@ export class DriftTradingService {
async getPositions(): Promise<Position[]> {
try {
if (this.isInitialized && this.driftClient) {
// Try to use SDK without subscription
// Subscribe to user account to access positions
try {
console.log('🔍 Subscribing to user account for positions...')
await this.driftClient.subscribe()
const user = this.driftClient.getUser()
// Get all available markets
@@ -296,7 +356,7 @@ export class DriftTradingService {
const p = user.getPerpPosition(marketIndex)
if (!p || p.baseAssetAmount.isZero()) continue
// Get market price without subscription
// Get market price
const marketData = this.driftClient.getPerpMarketAccount(marketIndex)
const markPrice = convertToNumber(marketData?.amm.lastMarkPriceTwap || new BN(0), PRICE_PRECISION)
@@ -319,16 +379,29 @@ export class DriftTradingService {
marketIndex,
marketType: 'PERP'
})
console.log(`✅ Found position: ${this.getSymbolFromMarketIndex(marketIndex)} ${isLong ? 'LONG' : 'SHORT'} ${size}`)
} catch (error) {
// Skip markets that don't exist or have errors
continue
}
}
console.log(`📊 Found ${positions.length} total positions`)
return positions
} catch (sdkError: any) {
console.log('⚠️ SDK positions method failed, using fallback:', sdkError.message)
// Fall through to fallback method
} finally {
// Always unsubscribe to clean up
if (this.driftClient) {
try {
await this.driftClient.unsubscribe()
} catch (e) {
// Ignore unsubscribe errors
}
}
}
}