Enhance trading system: real wallet validation, auto-discovery, and hot reloading

- Update trade validation to use real wallet balances from /api/wallet/balance
- Enhance wallet API to auto-discover all major SPL tokens (USDC, USDT, etc.)
- Improve AIAnalysisPanel to better extract and pass AI values to TradeModal
- Configure Docker Compose for hot reloading with proper volume mounts
- Remove hardcoded balance fallbacks in favor of live wallet data

Result: Trading validation now uses accurate real-time wallet balances
This commit is contained in:
mindesbunister
2025-07-16 11:37:20 +02:00
parent 77eb727f8d
commit ac50d9622c
4 changed files with 205 additions and 54 deletions

View File

@@ -418,52 +418,107 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP
// Trade initiation handler
const handleTradeClick = (tfResult: any) => {
console.log('🔥 AIAnalysisPanel handleTradeClick called with:', tfResult)
const analysis = tfResult?.result?.analysis || tfResult?.analysis || {}
console.log('🔥 Extracted analysis:', analysis)
setTradeModalData({
entry: analysis.entry?.price || analysis.entry || '',
tp: analysis.takeProfits?.tp1?.price || analysis.takeProfits?.tp1 || analysis.takeProfits || '',
sl: analysis.stopLoss?.price || analysis.stopLoss || '',
// Enhanced data extraction with better fallbacks
let entryPrice = ''
let takeProfit1 = ''
let takeProfit2 = ''
let stopLoss = ''
// Extract entry price with multiple fallback options
if (analysis.entry?.price) {
entryPrice = analysis.entry.price.toString()
} else if (analysis.entry && typeof analysis.entry === 'number') {
entryPrice = analysis.entry.toString()
} else if (analysis.entry && typeof analysis.entry === 'string') {
entryPrice = analysis.entry
}
// Extract take profit 1 with multiple fallback options
if (analysis.takeProfits?.tp1?.price) {
takeProfit1 = analysis.takeProfits.tp1.price.toString()
} else if (analysis.takeProfits?.tp1 && typeof analysis.takeProfits.tp1 === 'number') {
takeProfit1 = analysis.takeProfits.tp1.toString()
} else if (analysis.takeProfits && typeof analysis.takeProfits === 'number') {
takeProfit1 = analysis.takeProfits.toString()
} else if (analysis.takeProfit?.price) {
takeProfit1 = analysis.takeProfit.price.toString()
} else if (analysis.takeProfit && typeof analysis.takeProfit === 'number') {
takeProfit1 = analysis.takeProfit.toString()
}
// Extract take profit 2 if available
if (analysis.takeProfits?.tp2?.price) {
takeProfit2 = analysis.takeProfits.tp2.price.toString()
} else if (analysis.takeProfits?.tp2 && typeof analysis.takeProfits.tp2 === 'number') {
takeProfit2 = analysis.takeProfits.tp2.toString()
}
// Extract stop loss with multiple fallback options
if (analysis.stopLoss?.price) {
stopLoss = analysis.stopLoss.price.toString()
} else if (analysis.stopLoss && typeof analysis.stopLoss === 'number') {
stopLoss = analysis.stopLoss.toString()
} else if (analysis.stopLoss && typeof analysis.stopLoss === 'string') {
stopLoss = analysis.stopLoss
}
const tradeData = {
entry: entryPrice,
tp: takeProfit1, // This maps to tp1 in the modal
tp2: takeProfit2, // This will be handled in the modal
sl: stopLoss,
symbol: symbol,
timeframe: tfResult?.timeframeLabel || tfResult?.timeframe || '',
}
console.log('🔥 Enhanced trade data extraction:', {
originalAnalysis: analysis,
extractedData: tradeData
})
setTradeModalData(tradeData)
console.log('🔥 Opening trade modal...')
setTradeModalOpen(true)
}
// Trade execution API call
const executeTrade = async (tradeData: any) => {
try {
const response = await fetch('/api/trading', {
// Use real DEX trading for manual trades
const response = await fetch('/api/trading/execute-dex', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: tradeData.symbol,
symbol: tradeData.symbol || symbol,
side: 'BUY', // Could be derived from analysis
amount: parseFloat(tradeData.size), // Changed from 'size' to 'amount'
price: parseFloat(tradeData.entry),
amount: parseFloat(tradeData.positionSize) || parseFloat(tradeData.size),
stopLoss: parseFloat(tradeData.sl),
takeProfit: parseFloat(tradeData.tp),
leverage: parseInt(tradeData.leverage),
timeframe: tradeData.timeframe,
orderType: 'MARKET' // Default to market order
takeProfit: parseFloat(tradeData.tp1), // Use TP1 as primary target
useRealDEX: true, // Enable real trading for manual execution
tradingPair: `${tradeData.symbol || symbol}/USDC`,
quickSwap: false
})
})
const result = await response.json()
if (response.ok && result.success) {
// Show detailed success message
let message = `✅ Trade executed successfully!\n\n`
message += `📊 Order ID: ${result.txId}\n`
message += `💰 Symbol: ${tradeData.symbol}\n`
message += `📈 Size: ${tradeData.size}\n`
message += `💵 Entry: $${tradeData.entry}\n`
// Show detailed success message for DEX execution
let message = ` Real DEX Trade executed successfully!\n\n`
message += `📊 Transaction ID: ${result.trade?.txId || result.txId}\n`
message += `💰 Symbol: ${tradeData.symbol || symbol}\n`
message += `📈 Size: ${tradeData.positionSize || tradeData.size}\n`
message += `🏪 DEX: ${result.trade?.dex || 'Jupiter'}\n`
if (tradeData.sl) message += `🛑 Stop Loss: $${tradeData.sl}\n`
if (tradeData.tp) message += `🎯 Take Profit: $${tradeData.tp}\n`
if (tradeData.tp1) message += `🎯 Take Profit: $${tradeData.tp1}\n`
if (result.conditionalOrders && result.conditionalOrders.length > 0) {
message += `\n🔄 Conditional orders: ${result.conditionalOrders.length} placed`
if (result.trade?.monitoring) {
message += `\n🔄 Position monitoring: ACTIVE`
}
alert(message)
@@ -471,10 +526,12 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP
// Show detailed error message
const errorMsg = result.error || 'Unknown error occurred'
if (errorMsg.includes('insufficient funds') || errorMsg.includes('balance')) {
alert(`❌ Trade Failed: Insufficient Balance\n\nPlease deposit funds to your Drift account before placing trades.\n\nError: ${errorMsg}`)
} else if (errorMsg.includes('not logged in') || errorMsg.includes('Cannot execute trade')) {
alert(`❌ Trade Failed: Authentication Issue\n\nPlease check your Drift connection in the settings.\n\nError: ${errorMsg}`)
if (errorMsg.includes('not configured') || errorMsg.includes('Wallet not initialized')) {
alert(`❌ Trade Failed: Jupiter DEX Not Configured\n\nPlease configure your Jupiter DEX wallet in the settings before executing real trades.\n\nError: ${errorMsg}`)
} else if (errorMsg.includes('insufficient') || errorMsg.includes('balance')) {
alert(`❌ Trade Failed: Insufficient Balance\n\nPlease ensure you have enough tokens in your wallet.\n\nError: ${errorMsg}`)
} else if (errorMsg.includes('Real Jupiter Perpetuals trading not yet implemented')) {
alert(`❌ Real Trading Not Available\n\nReal Jupiter Perpetuals trading is still in development. This trade will be simulated instead.\n\nTo use real spot trading, reduce the leverage to 1x.`)
} else {
alert(`❌ Trade Failed\n\nError: ${errorMsg}`)
}
@@ -1412,9 +1469,16 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP
)}
{/* Trade Modal */}
{console.log('🔥 About to render TradeModal with:', {
isOpen: tradeModalOpen,
tradeData: tradeModalData
})}
<TradeModal
isOpen={tradeModalOpen}
onClose={() => setTradeModalOpen(false)}
onClose={() => {
console.log('🔥 TradeModal onClose called')
setTradeModalOpen(false)
}}
tradeData={tradeModalData}
onExecute={executeTrade}
/>