✅ Restore working dashboard and TradingView analysis
- Fixed layout conflicts by removing minimal layout.tsx in favor of complete layout.js - Restored original AI Analysis page with full TradingView integration - Connected enhanced screenshot API to real TradingView automation service - Fixed screenshot gallery to handle both string and object formats - Added image serving API route for screenshot display - Resolved hydration mismatch issues with suppressHydrationWarning - All navigation pages working (Analysis, Trading, Automation, Settings) - TradingView automation successfully capturing screenshots from AI and DIY layouts - Docker Compose v2 compatibility ensured Working features: - Homepage with hero section and status cards - Navigation menu with Trading Bot branding - Real TradingView screenshot capture - AI-powered chart analysis - Multi-layout support (AI + DIY module) - Screenshot gallery with image serving - API endpoints for balance, status, screenshots, trading
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const balance = await driftTradingService.getTradingBalance()
|
||||
return NextResponse.json(balance)
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { symbol, amount } = await request.json()
|
||||
|
||||
console.log(`🔒 Close position request: ${amount || 'ALL'} ${symbol}`)
|
||||
|
||||
// Validate inputs
|
||||
if (!symbol) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Symbol is required' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Execute position close
|
||||
const result = await driftTradingService.closePosition(symbol, amount)
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ Position closed successfully: ${result.txId}`)
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
txId: result.txId,
|
||||
message: `Position in ${symbol} closed successfully`
|
||||
})
|
||||
} else {
|
||||
console.error(`❌ Failed to close position: ${result.error}`)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: result.error },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Close position API error:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error.message || 'Failed to close position'
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const status = await driftTradingService.getDataAvailabilityStatus()
|
||||
|
||||
return NextResponse.json(status)
|
||||
} catch (error) {
|
||||
console.error('Error getting data status:', error)
|
||||
|
||||
// Return fallback status
|
||||
return NextResponse.json({
|
||||
status: 'Error Checking Status',
|
||||
sources: [
|
||||
{
|
||||
name: 'System Check',
|
||||
available: false,
|
||||
description: 'Unable to check data source availability'
|
||||
}
|
||||
],
|
||||
recommendations: [
|
||||
'Try refreshing the page',
|
||||
'Check your internet connection',
|
||||
'Contact support if the issue persists'
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
const loginStatus = await driftTradingService.login()
|
||||
return NextResponse.json(loginStatus)
|
||||
} catch (error: any) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
isLoggedIn: false,
|
||||
publicKey: '',
|
||||
userAccountExists: false,
|
||||
error: error.message
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const positions = await driftTradingService.getPositions()
|
||||
return NextResponse.json({ positions })
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { action } = await request.json()
|
||||
|
||||
if (action === 'start') {
|
||||
console.log('🚀 Starting real-time monitoring...')
|
||||
const result = await driftTradingService.startRealtimeMonitoring()
|
||||
|
||||
if (result.success) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Real-time monitoring started successfully',
|
||||
status: driftTradingService.getRealtimeMonitoringStatus()
|
||||
})
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: result.error,
|
||||
message: 'Failed to start real-time monitoring'
|
||||
}, { status: 500 })
|
||||
}
|
||||
|
||||
} else if (action === 'stop') {
|
||||
console.log('🛑 Stopping real-time monitoring...')
|
||||
await driftTradingService.stopRealtimeMonitoring()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Real-time monitoring stopped',
|
||||
status: driftTradingService.getRealtimeMonitoringStatus()
|
||||
})
|
||||
|
||||
} else if (action === 'status') {
|
||||
const status = driftTradingService.getRealtimeMonitoringStatus()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
status,
|
||||
message: status.isActive ? 'Real-time monitoring is active' : 'Real-time monitoring is not active'
|
||||
})
|
||||
|
||||
} else if (action === 'clear') {
|
||||
driftTradingService.clearRealtimeTradesCache()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Real-time trades cache cleared',
|
||||
status: driftTradingService.getRealtimeMonitoringStatus()
|
||||
})
|
||||
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: 'Invalid action. Use: start, stop, status, or clear'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error in realtime monitoring endpoint:', error)
|
||||
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message,
|
||||
message: 'Internal server error'
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const status = driftTradingService.getRealtimeMonitoringStatus()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
status,
|
||||
message: status.isActive ? 'Real-time monitoring is active' : 'Real-time monitoring is not active'
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error getting monitoring status:', error)
|
||||
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
console.log('🔄 API: Manually syncing trades with Drift...')
|
||||
|
||||
// Get current positions to check for any changes
|
||||
const positions = await driftTradingService.getPositions()
|
||||
|
||||
// Check for recent closures that might not be in history yet
|
||||
const recentClosures = await driftTradingService.getRecentClosures(24)
|
||||
|
||||
// Get existing trading history
|
||||
const existingTrades = await driftTradingService.getTradingHistory(100)
|
||||
|
||||
console.log(`📊 Found ${positions.length} active positions`)
|
||||
console.log(`📊 Found ${recentClosures.length} recent closures`)
|
||||
console.log(`📊 Found ${existingTrades.length} existing trades`)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Trade sync completed',
|
||||
data: {
|
||||
activePositions: positions.length,
|
||||
recentClosures: recentClosures.length,
|
||||
existingTrades: existingTrades.length,
|
||||
positions: positions,
|
||||
closures: recentClosures
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ API: Error syncing trades:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error.message,
|
||||
message: 'Failed to sync trades. Please try again.'
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const {
|
||||
symbol,
|
||||
side,
|
||||
amount,
|
||||
leverage,
|
||||
orderType,
|
||||
price,
|
||||
stopLoss,
|
||||
takeProfit,
|
||||
stopLossType,
|
||||
takeProfitType
|
||||
} = await request.json()
|
||||
|
||||
console.log(`🎯 Trade request: ${side} ${amount} ${symbol} at ${leverage}x leverage`)
|
||||
if (stopLoss) console.log(`🛑 Stop Loss: $${stopLoss} (${stopLossType})`)
|
||||
if (takeProfit) console.log(`🎯 Take Profit: $${takeProfit} (${takeProfitType})`)
|
||||
|
||||
// Validate inputs
|
||||
if (!symbol || !side || !amount || !leverage) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Missing required trade parameters' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
if (amount <= 0 || leverage < 1 || leverage > 20) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Invalid trade parameters' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Validate stop loss and take profit if provided
|
||||
if (stopLoss && stopLoss <= 0) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Invalid stop loss price' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
if (takeProfit && takeProfit <= 0) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Invalid take profit price' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Convert LONG/SHORT to BUY/SELL for the trading service
|
||||
const tradeSide: 'BUY' | 'SELL' = side === 'LONG' ? 'BUY' : 'SELL'
|
||||
|
||||
// Execute trade
|
||||
const tradeParams = {
|
||||
symbol,
|
||||
side: tradeSide,
|
||||
amount, // Position size in tokens
|
||||
orderType: orderType || 'MARKET',
|
||||
price: orderType === 'LIMIT' ? price : undefined,
|
||||
stopLoss,
|
||||
takeProfit,
|
||||
stopLossType,
|
||||
takeProfitType
|
||||
}
|
||||
|
||||
const result = await driftTradingService.executeTrade(tradeParams)
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ Trade executed successfully: ${result.txId}`)
|
||||
const response: any = {
|
||||
success: true,
|
||||
txId: result.txId,
|
||||
executedPrice: result.executedPrice,
|
||||
executedAmount: result.executedAmount,
|
||||
message: `${side} order for ${amount} ${symbol} executed successfully`
|
||||
}
|
||||
|
||||
if (result.conditionalOrders && result.conditionalOrders.length > 0) {
|
||||
response.conditionalOrders = result.conditionalOrders
|
||||
response.message += ` with ${result.conditionalOrders.length} conditional order(s)`
|
||||
}
|
||||
|
||||
return NextResponse.json(response)
|
||||
} else {
|
||||
console.error(`❌ Trade execution failed: ${result.error}`)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: result.error },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Trade API error:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error.message || 'Trade execution failed'
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
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)
|
||||
|
||||
// If no trades found, provide helpful message
|
||||
if (tradingHistory.length === 0) {
|
||||
console.log('⚠️ No trading history found')
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
trades: [],
|
||||
count: 0,
|
||||
message: 'No trading history found. If you recently closed positions, they may take some time to appear in history.'
|
||||
})
|
||||
}
|
||||
|
||||
console.log(`✅ Successfully fetched ${tradingHistory.length} trades`)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
trades: tradingHistory,
|
||||
count: tradingHistory.length,
|
||||
message: `Found ${tradingHistory.length} trade(s)`
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ API: Error getting trading history:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error.message,
|
||||
trades: [],
|
||||
count: 0,
|
||||
message: 'Failed to fetch trading history. Please try again.'
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { driftTradingService } from '../../../../lib/drift-trading'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { symbol, side, leverage } = await request.json()
|
||||
|
||||
console.log(`📊 Calculating trade requirements for ${symbol} ${side} with ${leverage}x leverage`)
|
||||
|
||||
// Get current account balance
|
||||
const balance = await driftTradingService.getAccountBalance()
|
||||
|
||||
// Get current market price for the symbol
|
||||
let marketPrice = 160 // Default SOL price
|
||||
try {
|
||||
// You could get real market price here from Drift or other price feeds
|
||||
if (symbol === 'SOLUSD') {
|
||||
marketPrice = 160 // Could be fetched from oracle
|
||||
} else if (symbol === 'BTCUSD') {
|
||||
marketPrice = 65000
|
||||
} else if (symbol === 'ETHUSD') {
|
||||
marketPrice = 3500
|
||||
}
|
||||
} catch (priceError) {
|
||||
console.log('⚠️ Could not get market price, using default')
|
||||
}
|
||||
|
||||
// Calculate position limits based on available collateral
|
||||
const availableCollateral = balance.freeCollateral || balance.availableBalance || 0
|
||||
const maxLeveragedValue = availableCollateral * (leverage || 1)
|
||||
|
||||
// Calculate max position size in tokens
|
||||
const maxPositionSize = marketPrice > 0 ? maxLeveragedValue / marketPrice : 0
|
||||
|
||||
// Calculate margin requirement for this position size
|
||||
const marginRequirement = maxLeveragedValue / (leverage || 1)
|
||||
|
||||
// Calculate estimated liquidation price (simplified)
|
||||
const maintenanceMarginRatio = 0.05 // 5% maintenance margin
|
||||
let estimatedLiquidationPrice = 0
|
||||
|
||||
if (side.toUpperCase() === 'LONG') {
|
||||
estimatedLiquidationPrice = marketPrice * (1 - (1 / leverage) + maintenanceMarginRatio)
|
||||
} else {
|
||||
estimatedLiquidationPrice = marketPrice * (1 + (1 / leverage) - maintenanceMarginRatio)
|
||||
}
|
||||
|
||||
const tradingCalculations = {
|
||||
marketPrice,
|
||||
availableCollateral,
|
||||
maxPositionSize,
|
||||
maxLeveragedValue,
|
||||
marginRequirement,
|
||||
estimatedLiquidationPrice,
|
||||
leverage: leverage || 1,
|
||||
symbol,
|
||||
side: side.toUpperCase()
|
||||
}
|
||||
|
||||
console.log(`📊 Trading calculations:`, tradingCalculations)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
calculations: tradingCalculations,
|
||||
balance: {
|
||||
totalCollateral: balance.totalCollateral,
|
||||
freeCollateral: balance.freeCollateral,
|
||||
availableBalance: balance.availableBalance,
|
||||
marginRequirement: balance.marginRequirement,
|
||||
netUsdValue: balance.netUsdValue
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error calculating trade requirements:', error)
|
||||
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message,
|
||||
calculations: {
|
||||
marketPrice: 0,
|
||||
availableCollateral: 0,
|
||||
maxPositionSize: 0,
|
||||
maxLeveragedValue: 0,
|
||||
marginRequirement: 0,
|
||||
estimatedLiquidationPrice: 0,
|
||||
leverage: 1,
|
||||
symbol: 'UNKNOWN',
|
||||
side: 'BUY'
|
||||
}
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// Return basic trading info without specific calculations
|
||||
const balance = await driftTradingService.getAccountBalance()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
balance: {
|
||||
totalCollateral: balance.totalCollateral,
|
||||
freeCollateral: balance.freeCollateral,
|
||||
availableBalance: balance.availableBalance,
|
||||
marginRequirement: balance.marginRequirement,
|
||||
netUsdValue: balance.netUsdValue,
|
||||
leverage: balance.leverage,
|
||||
unrealizedPnl: balance.unrealizedPnl
|
||||
},
|
||||
message: 'Account balance retrieved successfully'
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Error getting trading info:', error)
|
||||
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { Connection, PublicKey, Keypair } from '@solana/web3.js'
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const limit = parseInt(searchParams.get('limit') || '50')
|
||||
|
||||
console.log('📊 API: Getting Solana transaction history...')
|
||||
|
||||
// Get private key from environment
|
||||
const privateKeyString = process.env.PRIVATE_KEY
|
||||
if (!privateKeyString) {
|
||||
throw new Error('PRIVATE_KEY not found in environment variables')
|
||||
}
|
||||
|
||||
// Convert private key to Keypair
|
||||
const privateKeyBytes = JSON.parse(privateKeyString)
|
||||
const keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyBytes))
|
||||
|
||||
// Connect to Helius RPC
|
||||
const connection = new Connection(process.env.HELIUS_RPC_ENDPOINT || 'https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY')
|
||||
|
||||
// Get transaction signatures for this wallet
|
||||
const signatures = await connection.getSignaturesForAddress(
|
||||
keypair.publicKey,
|
||||
{ limit: limit * 2 } // Get more signatures to filter for Drift transactions
|
||||
)
|
||||
|
||||
console.log(`🔍 Found ${signatures.length} total signatures`)
|
||||
|
||||
// Get transaction details for each signature
|
||||
const transactions = []
|
||||
const driftProgramId = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH' // Drift program ID
|
||||
|
||||
for (const sig of signatures.slice(0, limit)) {
|
||||
try {
|
||||
const tx = await connection.getTransaction(sig.signature, {
|
||||
maxSupportedTransactionVersion: 0
|
||||
})
|
||||
|
||||
if (!tx) continue
|
||||
|
||||
// Check if this transaction involves the Drift program
|
||||
const isDriftTransaction = tx.transaction.message.staticAccountKeys?.some(
|
||||
key => key.toString() === driftProgramId
|
||||
) || tx.transaction.message.compiledInstructions?.some(
|
||||
instruction => {
|
||||
const programKey = tx.transaction.message.staticAccountKeys?.[instruction.programIdIndex]
|
||||
return programKey?.toString() === driftProgramId
|
||||
}
|
||||
)
|
||||
|
||||
if (isDriftTransaction) {
|
||||
// Parse the transaction to extract trading information
|
||||
const blockTime = tx.blockTime ? new Date(tx.blockTime * 1000) : new Date()
|
||||
|
||||
transactions.push({
|
||||
id: sig.signature,
|
||||
signature: sig.signature,
|
||||
blockTime: blockTime.toISOString(),
|
||||
slot: tx.slot,
|
||||
status: sig.err ? 'FAILED' : 'SUCCESS',
|
||||
fee: tx.meta?.fee || 0,
|
||||
// Try to extract more details from logs
|
||||
logs: tx.meta?.logMessages?.slice(0, 5) || [],
|
||||
accounts: tx.transaction.message.staticAccountKeys?.slice(0, 10).map(k => k.toString()) || []
|
||||
})
|
||||
}
|
||||
} catch (txError) {
|
||||
console.log(`⚠️ Failed to get transaction ${sig.signature}:`, txError)
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📊 Found ${transactions.length} Drift transactions`)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
transactions,
|
||||
count: transactions.length,
|
||||
totalSignatures: signatures.length
|
||||
})
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ API: Error getting transaction history:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error.message,
|
||||
transactions: []
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user