'use client' import React, { useState, useRef, useEffect } from 'react' import SimpleChart from '../../components/SimpleChart' interface Position { id: string symbol: string side: 'BUY' | 'SELL' amount: number entryPrice: number stopLoss: number takeProfit: number currentPrice: number unrealizedPnl: number leverage: number } export default function ChartTradingDemo() { const [selectedSymbol, setSelectedSymbol] = useState('SOL') const [leverage, setLeverage] = useState(1) const [payingAmount, setPayingAmount] = useState('') const [payingToken, setPayingToken] = useState('USDC') const [receivingAmount, setReceivingAmount] = useState('') const [stopLoss, setStopLoss] = useState('') const [takeProfit, setTakeProfit] = useState('') const [isSymbolDropdownOpen, setIsSymbolDropdownOpen] = useState(false) const [isPayingTokenDropdownOpen, setIsPayingTokenDropdownOpen] = useState(false) const dropdownRef = useRef(null) const payingTokenDropdownRef = useRef(null) const [positions, setPositions] = useState([]) const [isLoading, setIsLoading] = useState(false) const [tradeStatus, setTradeStatus] = useState('') const [liveBalances, setLiveBalances] = useState<{[key: string]: number}>({}) const [marketPrices, setMarketPrices] = useState<{[key: string]: {price: number, change: number}}>({}); const symbols = [ { symbol: 'SOL', name: 'Solana', price: marketPrices.SOL?.price || 166.21, change: marketPrices.SOL?.change || 2.45, icon: '๐ŸŸฃ' }, { symbol: 'BTC', name: 'Bitcoin', price: marketPrices.BTC?.price || 42150.00, change: marketPrices.BTC?.change || -1.23, icon: '๐ŸŸ ' }, { symbol: 'ETH', name: 'Ethereum', price: marketPrices.ETH?.price || 2580.50, change: marketPrices.ETH?.change || 3.12, icon: 'โฌœ' }, { symbol: 'BONK', name: 'Bonk', price: marketPrices.BONK?.price || 0.00003456, change: marketPrices.BONK?.change || 15.67, icon: '๐Ÿ•' }, { symbol: 'JUP', name: 'Jupiter', price: marketPrices.JUP?.price || 0.8234, change: marketPrices.JUP?.change || 5.43, icon: '๐Ÿช' }, { symbol: 'WIF', name: 'dogwifhat', price: marketPrices.WIF?.price || 3.42, change: marketPrices.WIF?.change || -8.21, icon: '๐Ÿงข' }, ] const payingTokens = [ { symbol: 'USDC', name: 'USD Coin', balance: liveBalances.USDC || 0, icon: '๐Ÿ’ต' }, { symbol: 'USDT', name: 'Tether', balance: liveBalances.USDT || 0, icon: '๐Ÿ’ฐ' }, { symbol: 'SOL', name: 'Solana', balance: liveBalances.SOL || 0, icon: '๐ŸŸฃ' }, { symbol: 'BTC', name: 'Bitcoin', balance: liveBalances.BTC || 0, icon: '๐ŸŸ ' }, { symbol: 'ETH', name: 'Ethereum', balance: liveBalances.ETH || 0, icon: 'โฌœ' }, ] // Close dropdown when clicking outside useEffect(() => { function handleClickOutside(event: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsSymbolDropdownOpen(false) } if (payingTokenDropdownRef.current && !payingTokenDropdownRef.current.contains(event.target as Node)) { setIsPayingTokenDropdownOpen(false) } } document.addEventListener('mousedown', handleClickOutside) return () => { document.removeEventListener('mousedown', handleClickOutside) } }, []) // Load real wallet balances and positions useEffect(() => { const loadRealData = async () => { try { // Fetch real wallet balances const balanceResponse = await fetch('/api/wallet/balance') if (balanceResponse.ok) { const balanceData = await balanceResponse.json() if (balanceData.success && balanceData.balance?.positions) { // Convert positions array to balances object const balances: {[key: string]: number} = {} balanceData.balance.positions.forEach((position: any) => { balances[position.symbol] = position.amount }) setLiveBalances(balances) console.log('โœ… Loaded wallet balances:', balances) } } // Fetch real positions const positionsResponse = await fetch('/api/trading/positions') if (positionsResponse.ok) { const positionsData = await positionsResponse.json() if (positionsData.success) { setPositions(positionsData.positions || []) } } // Fetch market prices const pricesResponse = await fetch('/api/prices') if (pricesResponse.ok) { const pricesData = await pricesResponse.json() if (pricesData.success) { setMarketPrices(pricesData.prices || {}) } } } catch (error) { console.error('Error loading real data:', error) setTradeStatus('Error loading wallet data') } } loadRealData() // Refresh data every 30 seconds const interval = setInterval(loadRealData, 30000) return () => clearInterval(interval) }, []) const getCurrentSymbolData = () => { return symbols.find(s => s.symbol === selectedSymbol) || symbols[0] } const getCurrentPayingTokenData = () => { const tokenData = payingTokens.find(t => t.symbol === payingToken) || payingTokens[0] console.log(`Getting token data for ${payingToken}:`, tokenData, 'Live balances:', liveBalances) return tokenData } // Calculate receiving amount based on paying amount useEffect(() => { if (payingAmount && payingToken === 'USDC') { const symbolData = getCurrentSymbolData() const symbolPrice = symbolData.price const receiving = parseFloat(payingAmount) / symbolPrice setReceivingAmount(receiving.toFixed(6)) } else if (payingAmount && payingToken === selectedSymbol) { setReceivingAmount(payingAmount) } else { setReceivingAmount('') } }, [payingAmount, payingToken, selectedSymbol]) const handleTrade = async (side: 'BUY' | 'SELL') => { const amount = parseFloat(payingAmount) if (!amount || amount <= 0) { alert('Please enter a valid amount') return } setIsLoading(true) setTradeStatus(`Executing ${side} order...`) try { // Execute real trade based on leverage const tradeEndpoint = leverage > 1 ? '/api/trading/execute-perp' : '/api/trading/execute-dex' const tradePayload = { symbol: selectedSymbol, side, amount, stopLoss: stopLoss ? parseFloat(stopLoss) : undefined, takeProfit: takeProfit ? parseFloat(takeProfit) : undefined, leverage: leverage > 1 ? leverage : undefined, fromCoin: payingToken, toCoin: selectedSymbol, useRealDEX: true } console.log('Executing trade:', tradePayload) const response = await fetch(tradeEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(tradePayload) }) const result = await response.json() if (result.success) { setTradeStatus(`${side} order executed successfully!`) // Refresh positions and balances const positionsResponse = await fetch('/api/trading/positions') if (positionsResponse.ok) { const positionsData = await positionsResponse.json() if (positionsData.success) { setPositions(positionsData.positions || []) } } const balanceResponse = await fetch('/api/wallet/balance') if (balanceResponse.ok) { const balanceData = await balanceResponse.json() if (balanceData.success && balanceData.balance?.positions) { // Convert positions array to balances object const balances: {[key: string]: number} = {} balanceData.balance.positions.forEach((position: any) => { balances[position.symbol] = position.amount }) setLiveBalances(balances) } } // Clear form setPayingAmount('') setReceivingAmount('') setStopLoss('') setTakeProfit('') alert(`โœ… ${side} order executed successfully!\nTransaction: ${result.signature || 'Completed'}`) } else { setTradeStatus(`Trade failed: ${result.error || 'Unknown error'}`) alert(`โŒ Trade failed: ${result.message || result.error || 'Unknown error'}`) } } catch (error) { console.error('Trade execution error:', error) setTradeStatus('Trade execution failed') alert('โŒ Trade execution failed. Please try again.') } finally { setIsLoading(false) setTimeout(() => setTradeStatus(''), 5000) } } const handleClosePosition = async (positionId: string) => { const position = positions.find(pos => pos.id === positionId) if (!position) return if (!confirm(`Are you sure you want to close ${position.symbol} ${position.side} position?`)) { return } setIsLoading(true) setTradeStatus('Closing position...') try { const response = await fetch(`/api/trading/positions/${positionId}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', }, }) const result = await response.json() if (result.success) { setTradeStatus('Position closed successfully!') // Refresh positions and balances const positionsResponse = await fetch('/api/trading/positions') if (positionsResponse.ok) { const positionsData = await positionsResponse.json() if (positionsData.success) { setPositions(positionsData.positions || []) } } const balanceResponse = await fetch('/api/wallet/balance') if (balanceResponse.ok) { const balanceData = await balanceResponse.json() if (balanceData.success && balanceData.balance?.positions) { // Convert positions array to balances object const balances: {[key: string]: number} = {} balanceData.balance.positions.forEach((position: any) => { balances[position.symbol] = position.amount }) setLiveBalances(balances) } } alert(`โœ… Position closed successfully!\nP&L: ${result.realizedPnl ? (result.realizedPnl >= 0 ? '+' : '') + '$' + result.realizedPnl.toFixed(2) : 'Calculated at settlement'}`) } else { setTradeStatus(`Failed to close position: ${result.error}`) alert(`โŒ Failed to close position: ${result.message || result.error}`) } } catch (error) { console.error('Position close error:', error) setTradeStatus('Failed to close position') alert('โŒ Failed to close position. Please try again.') } finally { setIsLoading(false) setTimeout(() => setTradeStatus(''), 5000) } } return ( <>
{/* Top Bar */}

Live Trading Terminal

{/* Symbol Selector Dropdown */}
{/* Dropdown Menu */} {isSymbolDropdownOpen && (
Select Trading Pair
{symbols.map(({ symbol, name, price, change, icon }) => ( ))}
)}
{/* Market Status */}
{isLoading ? 'Processing...' : 'Live Trading'}
{tradeStatus && (
{tradeStatus}
)}
{new Date().toLocaleTimeString()}
{/* Main Trading Interface */}
{/* Chart Area (70% width) */}
{/* Trading Panel (30% width) */}

{selectedSymbol}/USDC

${getCurrentSymbolData().price.toLocaleString()}
= 0 ? 'text-green-400' : 'text-red-400'}`}> {getCurrentSymbolData().change >= 0 ? '+' : ''}{getCurrentSymbolData().change}%
{/* Leverage Selector */}
{leverage}x
{/* Leverage Slider */}
setLeverage(parseInt(e.target.value))} className="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer slider" style={{ background: `linear-gradient(to right, #eab308 0%, #eab308 ${((leverage - 1) / 99) * 100}%, #374151 ${((leverage - 1) / 99) * 100}%, #374151 100%)` }} /> {/* Leverage Marks */}
{[1, 2, 5, 10, 20, 50, 100].map((mark) => ( ))}
{/* Leverage Warning */} {leverage > 10 && (
High leverage increases liquidation risk
)}
{/* Quick Trade Buttons */}
{/* Trade Form */}
{/* You're Paying Section */}
setPayingAmount(e.target.value)} placeholder="0.00" step="0.01" min="0" className="bg-transparent text-white text-lg font-medium focus:outline-none flex-1 mr-3" /> {/* Paying Token Selector */}
{/* Paying Token Dropdown */} {isPayingTokenDropdownOpen && (
{payingTokens.map(({ symbol, name, balance, icon }) => ( ))}
)}
{/* Balance and MAX button */}
Balance: {getCurrentPayingTokenData().balance.toFixed(getCurrentPayingTokenData().balance < 1 ? 6 : 2)} {payingToken}
{getCurrentPayingTokenData().balance === 0 && (
โš ๏ธ No {payingToken} balance available
)} {payingAmount && parseFloat(payingAmount) > getCurrentPayingTokenData().balance && (
โš ๏ธ Insufficient balance ({getCurrentPayingTokenData().balance.toFixed(getCurrentPayingTokenData().balance < 1 ? 6 : 2)} {payingToken} available)
)}
{leverage > 1 && payingAmount && (
Position value: ${(parseFloat(payingAmount) * leverage).toLocaleString()} ({leverage}x leverage)
)}
{/* You're Receiving Section */}
{receivingAmount || '0.00'}
{getCurrentSymbolData().icon} {selectedSymbol}
Rate: 1 {payingToken} = {payingToken === 'USDC' ? (1 / getCurrentSymbolData().price).toFixed(8) : '1.00'} {selectedSymbol}
setStopLoss(e.target.value)} placeholder="Optional" step="0.01" min="0" className="w-full bg-gray-700 text-white rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" />
setTakeProfit(e.target.value)} placeholder="Optional" step="0.01" min="0" className="w-full bg-gray-700 text-white rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" />
{/* Risk Information */} {payingAmount && leverage > 1 && (
โš ๏ธ Leveraged Position Risk
Position value: ${(parseFloat(payingAmount) * leverage).toLocaleString()} ({leverage}x leverage)
Liquidation risk: High with {leverage}x leverage
)}
{/* Bottom Panel - Positions */}
{positions.length > 0 && (
Total P&L: sum + pos.unrealizedPnl, 0) >= 0 ? 'text-green-400' : 'text-red-400' }`}> {positions.reduce((sum, pos) => sum + pos.unrealizedPnl, 0) >= 0 ? '+' : ''} ${positions.reduce((sum, pos) => sum + pos.unrealizedPnl, 0).toFixed(2)}
)}
{/* Positions Table */}
{isLoading && positions.length === 0 && (
Loading positions...
)} {!isLoading && positions.length === 0 ? (
No open positions
) : (
{positions.map((position: Position) => (
{position.symbol} โ€ข {position.side} {position.leverage > 1 && ( {position.leverage}x )}
Size: {position.amount} โ€ข Entry: ${position.entryPrice?.toFixed(2)}
SL: ${position.stopLoss.toFixed(2)}
TP: ${position.takeProfit.toFixed(2)}
${(position.amount * position.currentPrice).toFixed(2)}
= 0 ? 'text-green-400' : 'text-red-400' }`}> {position.unrealizedPnl >= 0 ? '+' : ''}${(position.unrealizedPnl || 0).toFixed(2)}
{position.leverage > 1 && (
{position.leverage}x Leveraged
)}
))}
)}
) }