Compare commits
3 Commits
e985a9ec6f
...
8e0d7f0969
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e0d7f0969 | ||
|
|
2fcd3b1120 | ||
|
|
6e75a7175e |
30
app/api/drift/trading-history/route.ts
Normal file
30
app/api/drift/trading-history/route.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const limit = parseInt(searchParams.get('limit') || '50')
|
||||
|
||||
console.log('📊 API: Getting Drift trading history...')
|
||||
|
||||
const tradingHistory = await driftTradingService.getTradingHistory(limit)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
trades: tradingHistory,
|
||||
count: tradingHistory.length
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ API: Error getting trading history:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error.message,
|
||||
trades: []
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,124 +1,47 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { tradingViewAutomation } from '../../../lib/tradingview-automation'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
console.log('📊 Getting TradingView session status...')
|
||||
console.log('📊 Session status temporarily disabled due to TradingView automation parsing issues')
|
||||
|
||||
// Initialize if not already done (Docker-safe initialization)
|
||||
if (!tradingViewAutomation['browser']) {
|
||||
console.log('🐳 Initializing TradingView automation in Docker environment...')
|
||||
await tradingViewAutomation.init()
|
||||
}
|
||||
|
||||
// Get lightweight session information without navigation
|
||||
const sessionInfo = await tradingViewAutomation.getQuickSessionStatus()
|
||||
|
||||
// Determine connection status based on browser state and URL
|
||||
let connectionStatus = 'unknown'
|
||||
if (sessionInfo.browserActive) {
|
||||
if (sessionInfo.currentUrl.includes('tradingview.com')) {
|
||||
connectionStatus = 'connected'
|
||||
} else if (sessionInfo.currentUrl) {
|
||||
connectionStatus = 'disconnected'
|
||||
} else {
|
||||
connectionStatus = 'unknown'
|
||||
}
|
||||
} else {
|
||||
connectionStatus = 'disconnected'
|
||||
}
|
||||
|
||||
const response = {
|
||||
success: true,
|
||||
session: {
|
||||
...sessionInfo,
|
||||
connectionStatus,
|
||||
lastChecked: new Date().toISOString(),
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Session status retrieved:', response.session)
|
||||
return NextResponse.json(response)
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to get session status:', error)
|
||||
// Return a basic response instead of using TradingView automation
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to get session status',
|
||||
isAuthenticated: false,
|
||||
status: 'disabled',
|
||||
message: 'TradingView session status temporarily disabled - focusing on Drift integration',
|
||||
session: {
|
||||
isAuthenticated: false,
|
||||
hasSavedCookies: false,
|
||||
hasSavedStorage: false,
|
||||
cookiesCount: 0,
|
||||
currentUrl: '',
|
||||
connectionStatus: 'error',
|
||||
connectionStatus: 'disabled',
|
||||
lastChecked: new Date().toISOString(),
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Session status error:', error.message)
|
||||
return NextResponse.json({
|
||||
isAuthenticated: false,
|
||||
status: 'error',
|
||||
message: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { action } = await request.json()
|
||||
console.log(`🔧 Session action requested: ${action} (Docker: ${process.env.DOCKER_ENV === 'true'})`)
|
||||
|
||||
// Initialize if not already done (Docker-safe initialization)
|
||||
if (!tradingViewAutomation['browser']) {
|
||||
console.log('🐳 Initializing TradingView automation for session action in Docker...')
|
||||
await tradingViewAutomation.init()
|
||||
}
|
||||
|
||||
let result: any = { success: true }
|
||||
|
||||
switch (action) {
|
||||
case 'refresh':
|
||||
const refreshed = await tradingViewAutomation.refreshSession()
|
||||
result.refreshed = refreshed
|
||||
result.message = refreshed ? 'Session refreshed successfully' : 'Failed to refresh session'
|
||||
break
|
||||
|
||||
case 'clear':
|
||||
await tradingViewAutomation.clearSession()
|
||||
result.message = 'Session data cleared successfully'
|
||||
break
|
||||
|
||||
case 'test':
|
||||
const testResult = await tradingViewAutomation.testSessionPersistence()
|
||||
result.testResult = testResult
|
||||
result.message = testResult.isValid ? 'Session is valid' : 'Session is invalid or expired'
|
||||
break
|
||||
|
||||
case 'login-status':
|
||||
const isLoggedIn = await tradingViewAutomation.checkLoginStatus()
|
||||
result.isLoggedIn = isLoggedIn
|
||||
result.message = isLoggedIn ? 'User is logged in' : 'User is not logged in'
|
||||
break
|
||||
|
||||
default:
|
||||
result.success = false
|
||||
result.error = `Unknown action: ${action}`
|
||||
return NextResponse.json(result, { status: 400 })
|
||||
}
|
||||
|
||||
console.log(`✅ Session action '${action}' completed:`, result)
|
||||
return NextResponse.json({
|
||||
...result,
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Session action failed:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Session action failed',
|
||||
dockerEnv: process.env.DOCKER_ENV === 'true',
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
message: 'TradingView automation temporarily disabled - focusing on Drift integration'
|
||||
})
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ export default function Dashboard() {
|
||||
dailyPnL: 0,
|
||||
winRate: 0,
|
||||
totalTrades: 0,
|
||||
accountValue: 0
|
||||
accountValue: 0,
|
||||
netUsdValue: 0
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
@@ -25,11 +26,11 @@ export default function Dashboard() {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
// Try to get Drift positions first
|
||||
// Get Drift positions
|
||||
const driftRes = await fetch('/api/drift/positions')
|
||||
if (driftRes.ok) {
|
||||
const driftData = await driftRes.json()
|
||||
if (driftData.positions && driftData.positions.length > 0) {
|
||||
if (driftData.positions) {
|
||||
setPositions(driftData.positions)
|
||||
|
||||
// Calculate stats from Drift positions
|
||||
@@ -41,58 +42,57 @@ export default function Dashboard() {
|
||||
totalTrades: driftData.positions.length
|
||||
}))
|
||||
|
||||
// Try to get account balance for account value
|
||||
// Get account balance for account value
|
||||
try {
|
||||
const balanceRes = await fetch('/api/drift/balance')
|
||||
if (balanceRes.ok) {
|
||||
const balanceData = await balanceRes.json()
|
||||
setStats(prev => ({
|
||||
...prev,
|
||||
accountValue: balanceData.accountValue || 0
|
||||
accountValue: balanceData.accountValue || 0,
|
||||
netUsdValue: balanceData.netUsdValue || 0
|
||||
}))
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Could not fetch balance:', e)
|
||||
}
|
||||
} else {
|
||||
// Fallback to legacy trading API
|
||||
const res = await fetch('/api/trading')
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
setPositions(data.positions || [])
|
||||
// Calculate some mock stats for demo
|
||||
// No positions available - set empty state
|
||||
setPositions([])
|
||||
setStats({
|
||||
totalPnL: 1247.50,
|
||||
dailyPnL: 67.25,
|
||||
winRate: 73.2,
|
||||
totalTrades: 156,
|
||||
accountValue: 10000
|
||||
totalPnL: 0,
|
||||
dailyPnL: 0,
|
||||
winRate: 0,
|
||||
totalTrades: 0,
|
||||
accountValue: 0,
|
||||
netUsdValue: 0
|
||||
})
|
||||
} else {
|
||||
setError('Failed to load positions')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback to legacy trading API
|
||||
const res = await fetch('/api/trading')
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
setPositions(data.positions || [])
|
||||
// Calculate some mock stats for demo
|
||||
// API failed - set empty state
|
||||
setError('Failed to connect to Drift')
|
||||
setPositions([])
|
||||
setStats({
|
||||
totalPnL: 1247.50,
|
||||
dailyPnL: 67.25,
|
||||
winRate: 73.2,
|
||||
totalTrades: 156,
|
||||
accountValue: 10000
|
||||
totalPnL: 0,
|
||||
dailyPnL: 0,
|
||||
winRate: 0,
|
||||
totalTrades: 0,
|
||||
accountValue: 0,
|
||||
netUsdValue: 0
|
||||
})
|
||||
} else {
|
||||
setError('Failed to load positions')
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
setError('Error loading positions')
|
||||
setError('Error connecting to Drift')
|
||||
console.error('Error:', e)
|
||||
setPositions([])
|
||||
setStats({
|
||||
totalPnL: 0,
|
||||
dailyPnL: 0,
|
||||
winRate: 0,
|
||||
totalTrades: 0,
|
||||
accountValue: 0,
|
||||
netUsdValue: 0
|
||||
})
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
@@ -102,7 +102,21 @@ export default function Dashboard() {
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
{/* Stats Cards */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-6">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-6 gap-6">
|
||||
<div className="card card-gradient">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-gray-400 text-sm font-medium">Net USD Value</p>
|
||||
<p className="text-2xl font-bold text-emerald-400">
|
||||
${stats.netUsdValue.toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 bg-emerald-500/20 rounded-full flex items-center justify-center">
|
||||
<span className="text-emerald-400 text-xl">💎</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card card-gradient">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -238,10 +252,10 @@ export default function Dashboard() {
|
||||
<div className="flex items-center">
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-orange-400 to-orange-600 rounded-full flex items-center justify-center mr-3">
|
||||
<span className="text-white text-xs font-bold">
|
||||
{pos.symbol?.slice(0, 2) || 'BT'}
|
||||
{pos.symbol?.slice(0, 2) || '--'}
|
||||
</span>
|
||||
</div>
|
||||
<span className="font-medium text-white">{pos.symbol || 'BTC/USD'}</span>
|
||||
<span className="font-medium text-white">{pos.symbol || '--'}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-4 px-4">
|
||||
@@ -250,20 +264,20 @@ export default function Dashboard() {
|
||||
? 'bg-green-500/20 text-green-400'
|
||||
: 'bg-red-500/20 text-red-400'
|
||||
}`}>
|
||||
{pos.side || 'Long'}
|
||||
{pos.side || '--'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-4 px-4 text-right font-mono text-gray-300">
|
||||
{typeof pos.size === 'number' ? pos.size.toFixed(4) : (pos.size || '0.1 BTC')}
|
||||
{typeof pos.size === 'number' ? pos.size.toFixed(4) : '--'}
|
||||
</td>
|
||||
<td className="py-4 px-4 text-right font-mono text-gray-300">
|
||||
${typeof pos.entryPrice === 'number' ? pos.entryPrice.toFixed(2) : (pos.entryPrice || '45,230.00')}
|
||||
${typeof pos.entryPrice === 'number' ? pos.entryPrice.toFixed(2) : '--'}
|
||||
</td>
|
||||
<td className="py-4 px-4 text-right">
|
||||
<span className={`font-mono font-medium ${
|
||||
(pos.unrealizedPnl || 125.50) >= 0 ? 'text-green-400' : 'text-red-400'
|
||||
(pos.unrealizedPnl || 0) >= 0 ? 'text-green-400' : 'text-red-400'
|
||||
}`}>
|
||||
{(pos.unrealizedPnl || 125.50) >= 0 ? '+' : ''}${typeof pos.unrealizedPnl === 'number' ? pos.unrealizedPnl.toFixed(2) : '125.50'}
|
||||
{(pos.unrealizedPnl || 0) >= 0 ? '+' : ''}${typeof pos.unrealizedPnl === 'number' ? pos.unrealizedPnl.toFixed(2) : '0.00'}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -19,44 +19,26 @@ export default function TradingHistory() {
|
||||
useEffect(() => {
|
||||
async function fetchTrades() {
|
||||
try {
|
||||
// Try Drift trading history first
|
||||
const driftRes = await fetch('/api/drift/trading-history')
|
||||
if (driftRes.ok) {
|
||||
const data = await driftRes.json()
|
||||
if (data.success && data.trades) {
|
||||
setTrades(data.trades)
|
||||
} else {
|
||||
// No trades available
|
||||
setTrades([])
|
||||
}
|
||||
} else {
|
||||
// API failed - try fallback to local database
|
||||
const res = await fetch('/api/trading-history')
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
setTrades(data)
|
||||
setTrades(data || [])
|
||||
} else {
|
||||
// Mock data for demonstration
|
||||
setTrades([
|
||||
{
|
||||
id: '1',
|
||||
symbol: 'BTCUSD',
|
||||
side: 'BUY',
|
||||
amount: 0.1,
|
||||
price: 45230.50,
|
||||
status: 'FILLED',
|
||||
executedAt: new Date().toISOString(),
|
||||
pnl: 125.50
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
symbol: 'ETHUSD',
|
||||
side: 'SELL',
|
||||
amount: 2.5,
|
||||
price: 2856.75,
|
||||
status: 'FILLED',
|
||||
executedAt: new Date(Date.now() - 3600000).toISOString(),
|
||||
pnl: -67.25
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
symbol: 'SOLUSD',
|
||||
side: 'BUY',
|
||||
amount: 10,
|
||||
price: 95.80,
|
||||
status: 'FILLED',
|
||||
executedAt: new Date(Date.now() - 7200000).toISOString(),
|
||||
pnl: 89.75
|
||||
// Both APIs failed - show empty state
|
||||
setTrades([])
|
||||
}
|
||||
])
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch trades:', error)
|
||||
|
||||
@@ -3,6 +3,7 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
network: host
|
||||
|
||||
# Base environment variables (common to all environments)
|
||||
environment:
|
||||
|
||||
@@ -50,6 +50,20 @@ export interface AccountBalance {
|
||||
accountValue: number
|
||||
leverage: number
|
||||
availableBalance: number
|
||||
netUsdValue: number
|
||||
unrealizedPnl: number
|
||||
}
|
||||
|
||||
export interface TradeHistory {
|
||||
id: string
|
||||
symbol: string
|
||||
side: 'BUY' | 'SELL'
|
||||
amount: number
|
||||
price: number
|
||||
status: 'FILLED' | 'PENDING' | 'CANCELLED'
|
||||
executedAt: string
|
||||
pnl?: number
|
||||
txId?: string
|
||||
}
|
||||
|
||||
export interface LoginStatus {
|
||||
@@ -169,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
|
||||
@@ -184,6 +201,47 @@ export class DriftTradingService {
|
||||
QUOTE_PRECISION
|
||||
)
|
||||
|
||||
// Try to get net USD value using more comprehensive methods
|
||||
let calculatedNetUsdValue = totalCollateral
|
||||
try {
|
||||
// Check if there's a direct method for net USD value or equity
|
||||
// Try different possible method names
|
||||
let directNetValue = null
|
||||
if ('getNetUsdValue' in user) {
|
||||
directNetValue = convertToNumber((user as any).getNetUsdValue(), QUOTE_PRECISION)
|
||||
} else if ('getEquity' in user) {
|
||||
directNetValue = convertToNumber((user as any).getEquity(), QUOTE_PRECISION)
|
||||
} else if ('getTotalAccountValue' in user) {
|
||||
directNetValue = convertToNumber((user as any).getTotalAccountValue(), QUOTE_PRECISION)
|
||||
}
|
||||
|
||||
if (directNetValue !== null) {
|
||||
calculatedNetUsdValue = directNetValue
|
||||
console.log(`📊 Direct net USD value: $${calculatedNetUsdValue.toFixed(2)}`)
|
||||
} else {
|
||||
console.log('⚠️ No direct net USD method found, will calculate manually')
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('⚠️ Direct net USD method failed:', (e as Error).message)
|
||||
}
|
||||
|
||||
// Try to get unsettled PnL and funding
|
||||
let unsettledBalance = 0
|
||||
try {
|
||||
// Try different approaches to get unsettled amounts
|
||||
if ('getUnsettledPnl' in user) {
|
||||
unsettledBalance += convertToNumber((user as any).getUnsettledPnl(), QUOTE_PRECISION)
|
||||
}
|
||||
if ('getPendingFundingPayments' in user) {
|
||||
unsettledBalance += convertToNumber((user as any).getPendingFundingPayments(), QUOTE_PRECISION)
|
||||
}
|
||||
if (unsettledBalance !== 0) {
|
||||
console.log(`📊 Unsettled balance: $${unsettledBalance.toFixed(2)}`)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('⚠️ Unsettled balance calculation failed:', (e as Error).message)
|
||||
}
|
||||
|
||||
// Calculate margin requirement using proper method
|
||||
let marginRequirement = 0
|
||||
try {
|
||||
@@ -201,17 +259,74 @@ 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 calculation with enhanced accuracy
|
||||
let finalNetUsdValue = calculatedNetUsdValue
|
||||
|
||||
// If we got a direct value, use it, otherwise calculate manually
|
||||
if (calculatedNetUsdValue === totalCollateral) {
|
||||
// Manual calculation: Total Collateral + Unrealized PnL + Unsettled
|
||||
finalNetUsdValue = totalCollateral + totalUnrealizedPnl + unsettledBalance
|
||||
console.log(`📊 Manual calculation: Collateral($${totalCollateral.toFixed(2)}) + PnL($${totalUnrealizedPnl.toFixed(2)}) + Unsettled($${unsettledBalance.toFixed(2)}) = $${finalNetUsdValue.toFixed(2)}`)
|
||||
}
|
||||
|
||||
console.log(`💰 Account balance: $${accountValue.toFixed(2)}, Net USD: $${finalNetUsdValue.toFixed(2)}, PnL: $${totalUnrealizedPnl.toFixed(2)}`)
|
||||
|
||||
return {
|
||||
totalCollateral,
|
||||
freeCollateral,
|
||||
marginRequirement,
|
||||
accountValue,
|
||||
leverage,
|
||||
availableBalance
|
||||
availableBalance,
|
||||
netUsdValue: finalNetUsdValue,
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +340,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) {
|
||||
@@ -267,18 +384,22 @@ export class DriftTradingService {
|
||||
}
|
||||
|
||||
async getPositions(): Promise<Position[]> {
|
||||
if (!this.driftClient || !this.isInitialized) {
|
||||
throw new Error('Client not logged in. Call login() first.')
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.isInitialized && this.driftClient) {
|
||||
// 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
|
||||
const positions: Position[] = []
|
||||
|
||||
// Check perp positions
|
||||
for (let marketIndex = 0; marketIndex < 20; marketIndex++) { // Check first 20 markets
|
||||
// Check perp positions - limit to main markets to avoid timeouts
|
||||
const mainMarkets = [0, 1, 2, 3, 4, 5]; // SOL, BTC, ETH and a few others
|
||||
|
||||
for (const marketIndex of mainMarkets) {
|
||||
try {
|
||||
const p = user.getPerpPosition(marketIndex)
|
||||
if (!p || p.baseAssetAmount.isZero()) continue
|
||||
@@ -306,16 +427,79 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
if (this.driftClient) {
|
||||
await this.driftClient.unsubscribe()
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Return empty array instead of demo data
|
||||
console.log('📊 Using fallback positions method - returning empty positions')
|
||||
return []
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error getting positions:', error)
|
||||
return [] // Return empty array instead of throwing error
|
||||
}
|
||||
}
|
||||
|
||||
async getTradingHistory(limit: number = 50): Promise<TradeHistory[]> {
|
||||
try {
|
||||
console.log('📊 Fetching trading history...')
|
||||
|
||||
// Try to get order records from Drift SDK if available
|
||||
if (this.driftClient && this.isInitialized) {
|
||||
try {
|
||||
console.log('🔍 Attempting to get order records from Drift SDK...')
|
||||
|
||||
// For now, return empty array as Drift SDK trading history is complex
|
||||
// and requires parsing transaction logs. This would be implemented
|
||||
// by analyzing on-chain transaction history for the user account.
|
||||
console.log('⚠️ Drift SDK order history not implemented yet - using fallback')
|
||||
|
||||
} catch (sdkError: any) {
|
||||
console.log('⚠️ SDK order history failed, using fallback:', sdkError.message)
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Check if we have any trades in local database
|
||||
try {
|
||||
// This would normally query Prisma for any executed trades
|
||||
console.log('📊 Checking local trade database...')
|
||||
|
||||
// For now, return empty array to show "No trading history"
|
||||
// rather than demo data
|
||||
return []
|
||||
|
||||
} catch (dbError: any) {
|
||||
console.log('⚠️ Database query failed:', dbError.message)
|
||||
return []
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error getting trading history:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: map symbol to market index using Drift market data
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user