feat: Add per-symbol trading controls for SOL and ETH
- Add SymbolSettings interface with enabled/positionSize/leverage fields - Implement per-symbol ENV variables (SOLANA_*, ETHEREUM_*) - Add SOL and ETH sections to settings UI with enable/disable toggles - Add symbol-specific test buttons (SOL LONG/SHORT, ETH LONG/SHORT) - Update execute and test endpoints to check symbol enabled status - Add real-time risk/reward calculator per symbol - Rename 'Position Sizing' to 'Global Fallback' for clarity - Fix position manager P&L calculation for externally closed positions - Fix zero P&L bug affecting 12 historical trades - Add SQL scripts for recalculating historical P&L data - Move archive TypeScript files to .archive to fix build Defaults: - SOL: 10 base × 10x leverage = 100 notional (profit trading) - ETH: base × 1x leverage = notional (data collection) - Global: 10 × 10x for BTC and other symbols Configuration priority: Per-symbol ENV > Market config > Global ENV > Defaults
This commit is contained in:
116
app/api/drift/history/route.ts
Normal file
116
app/api/drift/history/route.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Query Drift History API
|
||||
* GET /api/drift/history
|
||||
*
|
||||
* Queries Drift Protocol directly to compare with database
|
||||
*/
|
||||
|
||||
import { NextResponse } from 'next/server'
|
||||
import { initializeDriftService, getDriftService } from '@/lib/drift/client'
|
||||
import { getPrismaClient } from '@/lib/database/trades'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
console.log('🔍 Querying Drift Protocol...')
|
||||
|
||||
// Initialize Drift service if not already done
|
||||
console.log('⏳ Calling initializeDriftService()...')
|
||||
const driftService = await initializeDriftService()
|
||||
console.log('✅ Drift service initialized, got service object')
|
||||
|
||||
console.log('⏳ Getting Drift client...')
|
||||
const driftClient = driftService.getClient()
|
||||
console.log('✅ Got Drift client')
|
||||
|
||||
// Get user account
|
||||
const userAccount = driftClient.getUserAccount()
|
||||
|
||||
if (!userAccount) {
|
||||
return NextResponse.json({ error: 'User account not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
// Get account equity and P&L
|
||||
const equity = driftClient.getUser().getTotalCollateral()
|
||||
const unrealizedPnL = driftClient.getUser().getUnrealizedPNL()
|
||||
|
||||
// Get settled P&L from perp positions
|
||||
const perpPositions = userAccount.perpPositions
|
||||
let totalSettledPnL = 0
|
||||
const positionDetails: any[] = []
|
||||
|
||||
for (const position of perpPositions) {
|
||||
if (position.marketIndex === 0 || position.marketIndex === 1 || position.marketIndex === 2) {
|
||||
const marketName = position.marketIndex === 0 ? 'SOL-PERP' :
|
||||
position.marketIndex === 1 ? 'BTC-PERP' : 'ETH-PERP'
|
||||
|
||||
const settledPnL = Number(position.settledPnl) / 1e6
|
||||
const baseAssetAmount = Number(position.baseAssetAmount) / 1e9
|
||||
|
||||
totalSettledPnL += settledPnL
|
||||
|
||||
positionDetails.push({
|
||||
market: marketName,
|
||||
currentPosition: baseAssetAmount,
|
||||
settledPnL: settledPnL,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Get spot balance (USDC)
|
||||
const spotPositions = userAccount.spotPositions
|
||||
let usdcBalance = 0
|
||||
let cumulativeDeposits = 0
|
||||
|
||||
for (const spot of spotPositions) {
|
||||
if (spot.marketIndex === 0) { // USDC
|
||||
usdcBalance = Number(spot.scaledBalance) / 1e9
|
||||
cumulativeDeposits = Number(spot.cumulativeDeposits) / 1e6
|
||||
}
|
||||
}
|
||||
|
||||
// Query database for comparison
|
||||
const prisma = getPrismaClient()
|
||||
|
||||
const dbStats = await prisma.trade.aggregate({
|
||||
where: {
|
||||
exitReason: { not: null },
|
||||
entryTime: { gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }
|
||||
},
|
||||
_sum: { realizedPnL: true },
|
||||
_count: true
|
||||
})
|
||||
|
||||
const dbPnL = Number(dbStats._sum.realizedPnL || 0)
|
||||
const dbTrades = dbStats._count
|
||||
|
||||
const discrepancy = totalSettledPnL - dbPnL
|
||||
const estimatedFeePerTrade = dbTrades > 0 ? discrepancy / dbTrades : 0
|
||||
|
||||
return NextResponse.json({
|
||||
drift: {
|
||||
totalCollateral: Number(equity) / 1e6,
|
||||
unrealizedPnL: Number(unrealizedPnL) / 1e6,
|
||||
settledPnL: totalSettledPnL,
|
||||
usdcBalance,
|
||||
cumulativeDeposits,
|
||||
positions: positionDetails,
|
||||
},
|
||||
database: {
|
||||
totalTrades: dbTrades,
|
||||
totalPnL: dbPnL,
|
||||
},
|
||||
comparison: {
|
||||
discrepancy,
|
||||
estimatedFeePerTrade,
|
||||
note: 'Discrepancy includes funding rates, trading fees, and any manual trades not tracked by bot',
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error querying Drift:', error)
|
||||
return NextResponse.json(
|
||||
{ error: error instanceof Error ? error.message : 'Unknown error' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user