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:
@@ -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}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user