Files
trading_bot_v3/app/chart-trading-demo/page.tsx
mindesbunister 2db2be241b Implement Jupiter-style trading chart with lightweight-charts
- Add TradingView Lightweight Charts library for professional chart display
- Create TradingChart component with real-time candlestick data
- Implement position overlays (entry, stop loss, take profit lines)
- Add chart header with symbol and price information
- Create CompactTradingPanel for Jupiter-style order form
- Build ChartTradingPage combining chart and trading panel
- Add demo and test pages for chart functionality
- Use dynamic imports to avoid SSR issues with lightweight-charts
- Generate sample price data for demonstration

Features:
- Full-screen candlestick chart with dark theme
- Position markers on chart (blue entry, red SL, green TP)
- Real-time price display and P&L tracking
- Responsive design with proper chart resizing
- Professional trading interface similar to Jupiter Perps
2025-07-16 12:31:58 +02:00

221 lines
7.9 KiB
TypeScript

'use client'
import React, { useState, useEffect } from 'react'
import TradingChart from '../../components/TradingChart'
import CompactTradingPanel from '../../components/CompactTradingPanel'
export default function ChartTradingPageSimple() {
const [currentPrice, setCurrentPrice] = useState(166.21)
const [positions, setPositions] = useState([
// Mock position data for demo
{
id: 'demo_pos_1',
symbol: 'SOL/USDC',
side: 'BUY' as 'BUY' | 'SELL',
amount: 0.5,
entryPrice: 165.50,
stopLoss: 160.00,
takeProfit: 170.00,
currentPrice: 166.21,
unrealizedPnl: 0.355,
}
])
const [selectedSymbol, setSelectedSymbol] = useState('SOL')
const handleTrade = async (tradeData: any) => {
try {
console.log('Trade executed (demo):', tradeData)
// Create a mock position for demo
const newPosition = {
id: `demo_${Date.now()}`,
symbol: `${tradeData.symbol}/USDC`,
side: tradeData.side,
amount: tradeData.amount,
entryPrice: tradeData.price,
stopLoss: tradeData.stopLoss,
takeProfit: tradeData.takeProfit,
currentPrice: currentPrice,
unrealizedPnl: 0,
}
setPositions(prev => [...prev, newPosition])
alert(`Demo trade executed: ${tradeData.side} ${tradeData.amount} ${tradeData.symbol}`)
} catch (error) {
console.error('Trade execution error:', error)
}
}
const handlePriceUpdate = (price: number) => {
setCurrentPrice(price)
// Update position P&L based on new price
setPositions(prev => prev.map(pos => ({
...pos,
currentPrice: price,
unrealizedPnl: pos.side === 'BUY'
? (price - pos.entryPrice) * pos.amount
: (pos.entryPrice - price) * pos.amount
})))
}
const handleClosePosition = (positionId: string) => {
setPositions(prev => prev.filter(pos => pos.id !== positionId))
alert('Position closed (demo)')
}
return (
<div className="h-screen bg-gray-900 flex flex-col">
{/* Top Bar */}
<div className="bg-gray-800 border-b border-gray-700 p-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-6">
<h1 className="text-xl font-bold text-white">Chart Trading Terminal</h1>
{/* Symbol Selector */}
<div className="flex space-x-2">
{['SOL', 'BTC', 'ETH'].map(symbol => (
<button
key={symbol}
onClick={() => setSelectedSymbol(symbol)}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-all ${
selectedSymbol === symbol
? 'bg-blue-600 text-white'
: 'bg-gray-700 text-gray-300 hover:bg-gray-600'
}`}
>
{symbol}
</button>
))}
</div>
</div>
{/* Market Status */}
<div className="flex items-center space-x-4 text-sm">
<div className="flex items-center space-x-2">
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
<span className="text-gray-300">Demo Mode</span>
</div>
<div className="text-gray-400">
{new Date().toLocaleTimeString()}
</div>
</div>
</div>
</div>
{/* Main Trading Interface */}
<div className="flex-1 flex">
{/* Chart Area (70% width) */}
<div className="flex-1 p-4">
<TradingChart
symbol={selectedSymbol}
positions={positions}
onPriceUpdate={handlePriceUpdate}
/>
</div>
{/* Trading Panel (30% width) */}
<div className="w-96 border-l border-gray-700 p-4 space-y-4">
<CompactTradingPanel
symbol={selectedSymbol}
currentPrice={currentPrice}
onTrade={handleTrade}
/>
</div>
</div>
{/* Bottom Panel - Positions */}
<div className="border-t border-gray-700 bg-gray-800">
<div className="p-4">
<div className="flex items-center justify-between mb-4">
<div className="flex space-x-6">
<button className="text-white font-medium border-b-2 border-blue-500 pb-2">
Positions ({positions.length})
</button>
<button className="text-gray-400 hover:text-white pb-2">
Orders (0)
</button>
<button className="text-gray-400 hover:text-white pb-2">
History
</button>
</div>
{positions.length > 0 && (
<div className="text-sm text-gray-400">
Total P&L: <span className={`${
positions.reduce((sum, pos) => sum + (pos.unrealizedPnl || 0), 0) >= 0
? 'text-green-400' : 'text-red-400'
}`}>
{positions.reduce((sum, pos) => sum + (pos.unrealizedPnl || 0), 0) >= 0 ? '+' : ''}$
{positions.reduce((sum, pos) => sum + (pos.unrealizedPnl || 0), 0).toFixed(2)}
</span>
</div>
)}
</div>
{/* Positions Table */}
<div className="max-h-48 overflow-y-auto">
{positions.length === 0 ? (
<div className="text-center py-8 text-gray-400">
No open positions
</div>
) : (
<div className="space-y-2">
{positions.map((position: any) => (
<div
key={position.id}
className="bg-gray-900 rounded-lg p-4 flex items-center justify-between"
>
<div className="flex items-center space-x-4">
<div className={`w-3 h-3 rounded-full ${
position.side === 'BUY' ? 'bg-green-400' : 'bg-red-400'
}`}></div>
<div>
<div className="text-white font-medium">
{position.symbol} {position.side}
</div>
<div className="text-sm text-gray-400">
Size: {position.amount} Entry: ${position.entryPrice?.toFixed(2)}
</div>
{position.stopLoss && (
<div className="text-xs text-red-400">
SL: ${position.stopLoss.toFixed(2)}
</div>
)}
{position.takeProfit && (
<div className="text-xs text-green-400">
TP: ${position.takeProfit.toFixed(2)}
</div>
)}
</div>
</div>
<div className="text-right">
<div className="text-white font-medium">
${(position.amount * position.currentPrice).toFixed(2)}
</div>
<div className={`text-sm ${
(position.unrealizedPnl || 0) >= 0 ? 'text-green-400' : 'text-red-400'
}`}>
{(position.unrealizedPnl || 0) >= 0 ? '+' : ''}${(position.unrealizedPnl || 0).toFixed(2)}
</div>
</div>
<div className="flex space-x-2">
<button
onClick={() => handleClosePosition(position.id)}
className="px-3 py-1 bg-red-600 text-white rounded text-sm hover:bg-red-700"
>
Close
</button>
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
</div>
)
}