- Fixed Prisma table name errors in price-monitor.ts (trades vs trade, automation_sessions vs automationSession) - Commented out excessive P&L calculation logging in analysis-details API that was processing all 69 trades - Restored CoinGecko as primary price source (was falling back to Binance due to DB errors) - Optimized analysis-details to skip P&L calculations for FAILED/EXECUTED trades - Added comprehensive cleanup system for orphaned orders - Performance improvement: eliminated unnecessary processing of old trade data Result: Clean logs, efficient price fetching from CoinGecko, no excessive calculations
168 lines
5.3 KiB
JavaScript
168 lines
5.3 KiB
JavaScript
import { NextResponse } from 'next/server'
|
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js'
|
|
import { DriftClient, getUserAccountPublicKey, initialize } from '@drift-labs/sdk'
|
|
|
|
const getRpcStatus = () => {
|
|
const rpcEndpoints = [
|
|
process.env.SOLANA_RPC_URL,
|
|
process.env.HELIUS_RPC_URL,
|
|
'https://api.mainnet-beta.solana.com'
|
|
].filter(Boolean)
|
|
|
|
return {
|
|
primary: rpcEndpoints[0] || 'Not configured',
|
|
fallbacks: rpcEndpoints.slice(1),
|
|
total: rpcEndpoints.length
|
|
}
|
|
}
|
|
|
|
export async function GET() {
|
|
try {
|
|
console.log('📊 Position History API called')
|
|
|
|
// Get keypair from private key
|
|
if (!process.env.SOLANA_PRIVATE_KEY) {
|
|
throw new Error('SOLANA_PRIVATE_KEY environment variable not set')
|
|
}
|
|
|
|
const privateKeyArray = JSON.parse(process.env.SOLANA_PRIVATE_KEY)
|
|
const keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyArray))
|
|
|
|
// Setup connection with failover
|
|
const rpcEndpoints = [
|
|
process.env.SOLANA_RPC_URL,
|
|
process.env.HELIUS_RPC_URL,
|
|
'https://api.mainnet-beta.solana.com'
|
|
].filter(Boolean)
|
|
|
|
let connection
|
|
let connectedEndpoint = null
|
|
|
|
for (const endpoint of rpcEndpoints) {
|
|
try {
|
|
console.log(`🔗 Attempting connection to: ${endpoint.substring(0, 50)}...`)
|
|
connection = new Connection(endpoint, 'confirmed')
|
|
|
|
// Test the connection
|
|
const balance = await connection.getBalance(keypair.publicKey)
|
|
console.log(`✅ Connected successfully. Balance: ${(balance / 1e9).toFixed(6)} SOL`)
|
|
connectedEndpoint = endpoint
|
|
break
|
|
} catch (connError) {
|
|
console.log(`❌ Connection failed: ${connError.message}`)
|
|
continue
|
|
}
|
|
}
|
|
|
|
if (!connection || !connectedEndpoint) {
|
|
throw new Error('All RPC endpoints failed')
|
|
}
|
|
|
|
// Initialize Drift SDK
|
|
await initialize({ env: 'mainnet-beta' })
|
|
|
|
const userAccountPDA = getUserAccountPublicKey(
|
|
new PublicKey('dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH'),
|
|
keypair.publicKey,
|
|
0
|
|
)
|
|
|
|
console.log('🏦 User PDA:', userAccountPDA.toString())
|
|
|
|
// Create Drift client
|
|
const driftClient = new DriftClient({
|
|
connection,
|
|
wallet: {
|
|
publicKey: keypair.publicKey,
|
|
signTransaction: () => Promise.reject(new Error('Read-only')),
|
|
signAllTransactions: () => Promise.reject(new Error('Read-only'))
|
|
},
|
|
programID: new PublicKey('dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH'),
|
|
opts: { commitment: 'confirmed' }
|
|
})
|
|
|
|
// Try to get real trading history
|
|
let realTradeHistory = []
|
|
|
|
try {
|
|
console.log('🔍 Attempting to fetch real trading history from Drift...')
|
|
|
|
// Real trading history fetching would require:
|
|
// 1. Drift indexer API access
|
|
// 2. Transaction log parsing
|
|
// 3. Event listener aggregation
|
|
// Currently not implemented in SDK
|
|
|
|
console.log('⚠️ Real trading history fetch not implemented - returning empty data')
|
|
|
|
} catch (error) {
|
|
console.log('❌ Could not fetch real trading history:', error.message)
|
|
}
|
|
|
|
// Only use real data - no demo/mock data
|
|
const historicalTrades = realTradeHistory
|
|
|
|
// Calculate statistics
|
|
const wins = historicalTrades.filter(trade => trade.outcome === 'win')
|
|
const losses = historicalTrades.filter(trade => trade.outcome === 'loss')
|
|
|
|
const totalPnl = historicalTrades.reduce((sum, trade) => sum + (trade.pnl || 0), 0)
|
|
const winsPnl = wins.reduce((sum, trade) => sum + (trade.pnl || 0), 0)
|
|
const lossesPnl = losses.reduce((sum, trade) => sum + (trade.pnl || 0), 0)
|
|
|
|
const winRate = historicalTrades.length > 0 ? (wins.length / historicalTrades.length) * 100 : 0
|
|
const avgWin = wins.length > 0 ? winsPnl / wins.length : 0
|
|
const avgLoss = losses.length > 0 ? lossesPnl / losses.length : 0
|
|
const profitFactor = Math.abs(lossesPnl) > 0 ? Math.abs(winsPnl / lossesPnl) : 0
|
|
|
|
const statistics = {
|
|
totalTrades: historicalTrades.length,
|
|
wins: wins.length,
|
|
losses: losses.length,
|
|
winRate: Math.round(winRate),
|
|
totalPnl: Math.round(totalPnl * 100) / 100,
|
|
winsPnl: Math.round(winsPnl * 100) / 100,
|
|
lossesPnl: Math.round(lossesPnl * 100) / 100,
|
|
avgWin: Math.round(avgWin * 100) / 100,
|
|
avgLoss: Math.round(avgLoss * 100) / 100,
|
|
profitFactor: Math.round(profitFactor * 100) / 100
|
|
}
|
|
|
|
console.log('📈 Trading Statistics:', statistics)
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
trades: historicalTrades,
|
|
statistics,
|
|
rpcStatus: {
|
|
connected: connectedEndpoint,
|
|
status: getRpcStatus()
|
|
},
|
|
timestamp: new Date().toISOString(),
|
|
note: "Real trading history API - showing only actual trades when available"
|
|
}, {
|
|
headers: {
|
|
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
'Pragma': 'no-cache',
|
|
'Expires': '0'
|
|
}
|
|
})
|
|
|
|
} catch (error) {
|
|
console.error('❌ Position history API error:', error)
|
|
|
|
return NextResponse.json({
|
|
success: false,
|
|
error: 'Failed to get position history',
|
|
details: error.message,
|
|
rpcStatus: getRpcStatus()
|
|
}, { status: 500 })
|
|
}
|
|
}
|
|
|
|
export async function POST() {
|
|
return NextResponse.json({
|
|
message: 'Use GET method to retrieve position history'
|
|
}, { status: 405 })
|
|
}
|