Files
trading_bot_v3/components/TradeExecutionPanel.js
mindesbunister e9517d5ec4 feat: Complete Bitquery trading integration with real wallet support
Features Added:
- Real-time price data via CoinGecko API (BTC: 21k+, SOL: 66+, etc.)
- Actual Solana wallet integration using private key from .env
- Trade execution API with Bitquery simulation
 trade recommendation → execution flow
- Portfolio display showing real wallet balance (~2.49 SOL)

- /api/market - Live cryptocurrency prices
- /api/trading/execute - Execute trades based on analysis
- /api/trading/balance - Real wallet balance
- /api/wallet/balance - Direct Solana wallet access

- TradeExecutionPanel.js - Complete trading interface
- WalletConnection.js - Wallet connection component
- Updated AIAnalysisPanel - Analysis → trade execution flow
- Updated StatusOverview - Real market data + wallet balance

- AI analysis generates trade recommendations
- Users can execute trades based on AI suggestions
- Real portfolio tracking with actual Solana wallet
- Live market prices (no more fake data)
- Ready for production trading

Security: Private key stays in .env, only public data exposed to frontend
2025-07-14 14:58:01 +02:00

297 lines
9.4 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import React, { useState, useEffect } from 'react'
export default function TradeExecutionPanel({ analysis, symbol = 'SOL' }) {
const [tradeType, setTradeType] = useState('BUY')
const [amount, setAmount] = useState('')
const [customPrice, setCustomPrice] = useState('')
const [useRecommendedPrice, setUseRecommendedPrice] = useState(true)
const [isExecuting, setIsExecuting] = useState(false)
const [executionResult, setExecutionResult] = useState(null)
const [balance, setBalance] = useState(null)
// Get recommended price from analysis
const getRecommendedPrice = () => {
if (!analysis) return null
if (analysis.recommendation === 'BUY' && analysis.entry?.price) {
return analysis.entry.price
} else if (analysis.recommendation === 'SELL' && analysis.entry?.price) {
return analysis.entry.price
}
return null
}
const recommendedPrice = getRecommendedPrice()
// Fetch balance on component mount
useEffect(() => {
fetchBalance()
}, [])
const fetchBalance = async () => {
try {
const response = await fetch('/api/trading/balance')
const data = await response.json()
if (data.success) {
setBalance(data.balance)
}
} catch (error) {
console.error('Failed to fetch balance:', error)
}
}
const executeTrade = async () => {
if (!amount || parseFloat(amount) <= 0) {
alert('Please enter a valid amount')
return
}
setIsExecuting(true)
setExecutionResult(null)
try {
const tradePrice = useRecommendedPrice && recommendedPrice
? recommendedPrice
: customPrice ? parseFloat(customPrice) : undefined
const response = await fetch('/api/trading/execute', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
symbol,
side: tradeType,
amount: parseFloat(amount),
price: tradePrice,
orderType: tradePrice ? 'limit' : 'market'
})
})
const result = await response.json()
if (result.success) {
setExecutionResult({
success: true,
trade: result.trade,
message: result.message
})
// Refresh balance after successful trade
await fetchBalance()
} else {
setExecutionResult({
success: false,
error: result.error,
message: result.message
})
}
} catch (error) {
setExecutionResult({
success: false,
error: 'Network error',
message: 'Failed to execute trade. Please try again.'
})
} finally {
setIsExecuting(false)
}
}
const getTradeButtonColor = () => {
if (tradeType === 'BUY') return 'bg-green-600 hover:bg-green-700'
return 'bg-red-600 hover:bg-red-700'
}
const getRecommendationColor = () => {
if (!analysis) return 'text-gray-400'
switch (analysis.recommendation) {
case 'BUY': return 'text-green-400'
case 'SELL': return 'text-red-400'
default: return 'text-yellow-400'
}
}
return (
<div className="card card-gradient p-6 space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-xl font-bold text-white">Execute Trade</h2>
<div className="text-sm text-gray-400">
{symbol} Trading
</div>
</div>
{/* Balance Display */}
{balance && (
<div className="bg-gray-800 rounded-lg p-4">
<h3 className="text-sm font-medium text-gray-300 mb-2">Portfolio Balance</h3>
<div className="flex justify-between items-center">
<span className="text-lg font-bold text-white">
${balance.totalValue?.toFixed(2)}
</span>
<span className="text-sm text-gray-400">
Available: ${balance.availableBalance?.toFixed(2)}
</span>
</div>
</div>
)}
{/* AI Recommendation Display */}
{analysis && (
<div className="bg-gray-800 rounded-lg p-4">
<h3 className="text-sm font-medium text-gray-300 mb-2">AI Recommendation</h3>
<div className="flex items-center justify-between mb-2">
<span className={`font-bold text-lg ${getRecommendationColor()}`}>
{analysis.recommendation}
</span>
<span className="text-sm text-gray-400">
{analysis.confidence}% confidence
</span>
</div>
{recommendedPrice && (
<div className="text-sm text-gray-300">
Entry: ${recommendedPrice.toFixed(4)}
{analysis.entry?.buffer && (
<span className="text-gray-400 ml-1">({analysis.entry.buffer})</span>
)}
</div>
)}
{analysis.stopLoss && (
<div className="text-sm text-gray-300">
Stop Loss: ${analysis.stopLoss.price.toFixed(4)}
</div>
)}
{analysis.takeProfits?.tp1 && (
<div className="text-sm text-gray-300">
TP1: ${analysis.takeProfits.tp1.price.toFixed(4)}
</div>
)}
<div className="text-xs text-gray-400 mt-2">
{analysis.reasoning}
</div>
</div>
)}
{/* Trade Type Selection */}
<div className="grid grid-cols-2 gap-2">
<button
onClick={() => setTradeType('BUY')}
className={`py-2 px-4 rounded-lg font-medium transition-colors ${
tradeType === 'BUY'
? 'bg-green-600 text-white'
: 'bg-gray-700 text-gray-300 hover:bg-gray-600'
}`}
>
BUY
</button>
<button
onClick={() => setTradeType('SELL')}
className={`py-2 px-4 rounded-lg font-medium transition-colors ${
tradeType === 'SELL'
? 'bg-red-600 text-white'
: 'bg-gray-700 text-gray-300 hover:bg-gray-600'
}`}
>
SELL
</button>
</div>
{/* Amount Input */}
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Amount ({symbol})
</label>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="0.00"
step="0.001"
min="0"
className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
{/* Price Selection */}
<div className="space-y-3">
<label className="block text-sm font-medium text-gray-300">
Price Selection
</label>
{recommendedPrice && (
<label className="flex items-center space-x-3">
<input
type="radio"
name="priceType"
checked={useRecommendedPrice}
onChange={() => setUseRecommendedPrice(true)}
className="text-blue-500"
/>
<span className="text-gray-300">
Use AI Recommended Price: ${recommendedPrice.toFixed(4)}
</span>
</label>
)}
<label className="flex items-center space-x-3">
<input
type="radio"
name="priceType"
checked={!useRecommendedPrice}
onChange={() => setUseRecommendedPrice(false)}
className="text-blue-500"
/>
<span className="text-gray-300">Market Price / Custom</span>
</label>
{!useRecommendedPrice && (
<input
type="number"
value={customPrice}
onChange={(e) => setCustomPrice(e.target.value)}
placeholder="Enter price (leave empty for market)"
step="0.0001"
min="0"
className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
)}
</div>
{/* Execute Button */}
<button
onClick={executeTrade}
disabled={isExecuting || !amount}
className={`w-full py-3 px-4 rounded-lg font-bold text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${getTradeButtonColor()}`}
>
{isExecuting ? 'Executing...' : `Execute ${tradeType} Order`}
</button>
{/* Execution Result */}
{executionResult && (
<div className={`p-4 rounded-lg ${
executionResult.success ? 'bg-green-900 border border-green-600' : 'bg-red-900 border border-red-600'
}`}>
<div className={`font-bold ${executionResult.success ? 'text-green-400' : 'text-red-400'}`}>
{executionResult.success ? '✅ Trade Executed' : '❌ Trade Failed'}
</div>
<div className="text-sm text-gray-300 mt-1">
{executionResult.message}
</div>
{executionResult.trade && (
<div className="text-xs text-gray-400 mt-2">
TX ID: {executionResult.trade.txId}
</div>
)}
</div>
)}
{/* Risk Warning */}
<div className="text-xs text-gray-500 border-t border-gray-700 pt-3">
Trading involves significant risk. This is a simulated trading environment using Bitquery data.
</div>
</div>
)
}