713 lines
28 KiB
TypeScript
713 lines
28 KiB
TypeScript
'use client'
|
||
|
||
import { useState, useEffect } from 'react'
|
||
import { TradingChart } from './TradingChart'
|
||
import { TradingTools } from './TradingTools'
|
||
import { MacroReportGenerator } from './MacroReportGenerator'
|
||
|
||
type TradingTab = 'research' | 'strategies' | 'execution' | 'journal' | 'tools'
|
||
|
||
interface Trader {
|
||
id: string
|
||
name: string
|
||
status: 'learning' | 'active' | 'paused'
|
||
framesAnalyzed: number
|
||
patterns: string[]
|
||
entryRules: string[]
|
||
exitRules: string[]
|
||
indicators: string[]
|
||
riskParams: string[]
|
||
}
|
||
|
||
interface Trade {
|
||
id: string
|
||
trader: string
|
||
pair: string
|
||
direction: 'long' | 'short'
|
||
entryPrice: number
|
||
exitPrice?: number
|
||
status: 'open' | 'closed' | 'cancelled'
|
||
pnl?: number
|
||
pnlPercent?: number
|
||
reason: string
|
||
setup: string
|
||
timeframe: string
|
||
openedAt: string
|
||
closedAt?: string
|
||
notes: string
|
||
isDemo: boolean
|
||
traderStyle?: string // NEW: tracks which trader style was used
|
||
}
|
||
|
||
const defaultTraders: Trader[] = [
|
||
{
|
||
id: 'dopetrades',
|
||
name: 'DopeTrades',
|
||
status: 'learning',
|
||
framesAnalyzed: 922,
|
||
patterns: ['Accumulation/Distribution', 'Trend Legs', 'Support/Resistance', 'Pop Pattern'],
|
||
entryRules: ['Identify trend on higher timeframe', 'Find demand/supply zones', 'Wait for retest', '2.5:1 min risk:reward'],
|
||
exitRules: ['Stop below demand (long)', 'Target recent highs', 'Scale 50% at 1:1'],
|
||
indicators: ['Price Action Only', 'Horizontal S/R Lines'],
|
||
riskParams: ['2.5:1 minimum', 'No revenge trading', 'Paper trading first']
|
||
},
|
||
{
|
||
id: 'gareth_soloway',
|
||
name: 'Gareth Soloway',
|
||
status: 'learning',
|
||
framesAnalyzed: 5970,
|
||
patterns: ['Institutional Analysis', 'Yield Curve Signals', 'Cycle Top/Bottom', 'Epic Resistance Rejections'],
|
||
entryRules: ['Track institutional activity', 'Wait for yield curve signals', 'Key level breaks with volume', 'Weekly analysis first'],
|
||
exitRules: ['Stop below support (long)', 'Target structure highs/lows', '2:1 minimum'],
|
||
indicators: ['VWAP', 'MACD', 'Volume', '10-Year Yield', 'Support/Resistance'],
|
||
riskParams: ['No-hype sizing', 'Never average down', 'Respect stops', 'Preservation > profits']
|
||
}
|
||
]
|
||
|
||
// Execute Trade Modal Component
|
||
function ExecuteTradeModal({
|
||
traders,
|
||
selectedTrader,
|
||
onClose,
|
||
onTradeExecuted
|
||
}: {
|
||
traders: Trader[]
|
||
selectedTrader: string
|
||
onClose: () => void
|
||
onTradeExecuted: (trade: Trade) => void
|
||
}) {
|
||
const [form, setForm] = useState({
|
||
pair: 'BTC/USD',
|
||
direction: 'long' as 'long' | 'short',
|
||
isDemo: true,
|
||
entryPrice: '',
|
||
timeframe: '4H',
|
||
setup: ''
|
||
})
|
||
|
||
const submitTrade = () => {
|
||
const trader = traders.find(t => t.id === selectedTrader)
|
||
const trade: Trade = {
|
||
id: Date.now().toString(),
|
||
trader: trader?.name || 'Unknown',
|
||
pair: form.pair,
|
||
direction: form.direction,
|
||
entryPrice: parseFloat(form.entryPrice) || 0,
|
||
status: 'open',
|
||
isDemo: form.isDemo,
|
||
openedAt: new Date().toISOString(),
|
||
setup: form.setup || `${trader?.name} setup`,
|
||
timeframe: form.timeframe,
|
||
reason: '',
|
||
notes: '',
|
||
traderStyle: selectedTrader
|
||
}
|
||
|
||
// Save to API
|
||
fetch('/api/trading/trades', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(trade)
|
||
}).then(() => {
|
||
onTradeExecuted(trade)
|
||
})
|
||
}
|
||
|
||
const trader = traders.find(t => t.id === selectedTrader)
|
||
|
||
return (
|
||
<div className="bg-[#1a1625] border border-white/20 rounded-xl max-w-lg w-full">
|
||
<div className="p-4 border-b border-white/10 flex justify-between items-center">
|
||
<h2 className="text-xl font-bold text-white">Execute Trade</h2>
|
||
<button onClick={onClose} className="text-white/50 hover:text-white text-2xl">×</button>
|
||
</div>
|
||
|
||
<div className="p-4 space-y-4">
|
||
{/* Trader Style Badge */}
|
||
<div className="p-3 bg-brand-pink/20 border border-brand-pink/30 rounded-lg">
|
||
<p className="text-xs text-white/50">Trading Style</p>
|
||
<p className="font-bold text-white">{trader?.name}</p>
|
||
</div>
|
||
|
||
{/* Pair */}
|
||
<div>
|
||
<label className="block text-sm text-white/70 mb-1">Trading Pair</label>
|
||
<select
|
||
value={form.pair}
|
||
onChange={e => setForm({...form, pair: e.target.value})}
|
||
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
|
||
>
|
||
<option value="BTC/USD">BTC/USD</option>
|
||
<option value="ETH/USD">ETH/USD</option>
|
||
<option value="SOL/USD">SOL/USD</option>
|
||
<option value="EUR/USD">EUR/USD</option>
|
||
<option value="GBP/USD">GBP/USD</option>
|
||
</select>
|
||
</div>
|
||
|
||
{/* Direction */}
|
||
<div className="flex gap-2">
|
||
<button
|
||
onClick={() => setForm({...form, direction: 'long'})}
|
||
className={`flex-1 py-2 rounded-lg font-medium ${
|
||
form.direction === 'long' ? 'bg-green-500 text-white' : 'bg-white/10 text-white/70'
|
||
}`}
|
||
>
|
||
📈 LONG
|
||
</button>
|
||
<button
|
||
onClick={() => setForm({...form, direction: 'short'})}
|
||
className={`flex-1 py-2 rounded-lg font-medium ${
|
||
form.direction === 'short' ? 'bg-red-500 text-white' : 'bg-white/10 text-white/70'
|
||
}`}
|
||
>
|
||
📉 SHORT
|
||
</button>
|
||
</div>
|
||
|
||
{/* Entry Price */}
|
||
<div>
|
||
<label className="block text-sm text-white/70 mb-1">Entry Price</label>
|
||
<input
|
||
type="number"
|
||
value={form.entryPrice}
|
||
onChange={e => setForm({...form, entryPrice: e.target.value})}
|
||
placeholder="0.00"
|
||
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
|
||
/>
|
||
</div>
|
||
|
||
{/* Timeframe */}
|
||
<div>
|
||
<label className="block text-sm text-white/70 mb-1">Timeframe</label>
|
||
<select
|
||
value={form.timeframe}
|
||
onChange={e => setForm({...form, timeframe: e.target.value})}
|
||
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
|
||
>
|
||
<option value="15m">15 min</option>
|
||
<option value="1H">1 Hour</option>
|
||
<option value="4H">4 Hour</option>
|
||
<option value="Daily">Daily</option>
|
||
<option value="Weekly">Weekly</option>
|
||
</select>
|
||
</div>
|
||
|
||
{/* Demo/Real */}
|
||
<div className="flex gap-2">
|
||
<button
|
||
onClick={() => setForm({...form, isDemo: true})}
|
||
className={`flex-1 py-2 rounded-lg font-medium ${
|
||
form.isDemo ? 'bg-blue-500 text-white' : 'bg-white/10 text-white/70'
|
||
}`}
|
||
>
|
||
🎯 Demo
|
||
</button>
|
||
<button
|
||
onClick={() => setForm({...form, isDemo: false})}
|
||
className={`flex-1 py-2 rounded-lg font-medium ${
|
||
!form.isDemo ? 'bg-yellow-500 text-white' : 'bg-white/10 text-white/70'
|
||
}`}
|
||
>
|
||
💰 Real
|
||
</button>
|
||
</div>
|
||
|
||
{/* Setup Note */}
|
||
<div>
|
||
<label className="block text-sm text-white/70 mb-1">Setup/Notes</label>
|
||
<input
|
||
value={form.setup}
|
||
onChange={e => setForm({...form, setup: e.target.value})}
|
||
placeholder="What setup is this?"
|
||
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
|
||
/>
|
||
</div>
|
||
|
||
<button
|
||
onClick={submitTrade}
|
||
className="w-full py-3 bg-brand-pink text-white rounded-lg font-bold hover:bg-[#ff7bc0] transition"
|
||
>
|
||
🚀 Execute Trade
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export function TradingPanel() {
|
||
const [activeTab, setActiveTab] = useState<TradingTab>('research')
|
||
const [traders, setTraders] = useState<Trader[]>(defaultTraders)
|
||
const [selectedTrader, setSelectedTrader] = useState<string>('dopetrades')
|
||
const [showFullAnalysis, setShowFullAnalysis] = useState<string | null>(null)
|
||
const [showExecuteTrade, setShowExecuteTrade] = useState(false)
|
||
const [trades, setTrades] = useState<Trade[]>([])
|
||
const [journalFilter, setJournalFilter] = useState<'all' | 'demo' | 'real'>('all')
|
||
|
||
// Load data
|
||
useEffect(() => {
|
||
loadTraders()
|
||
loadTrades()
|
||
}, [])
|
||
|
||
const loadTraders = async () => {
|
||
try {
|
||
const res = await fetch('/api/trading/traders')
|
||
if (res.ok) {
|
||
const data = await res.json()
|
||
if (data.traders?.length > 0) setTraders(data.traders)
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
const loadTrades = async () => {
|
||
try {
|
||
const res = await fetch('/api/trading/trades')
|
||
if (res.ok) {
|
||
const data = await res.json()
|
||
if (data.trades) setTrades(data.trades)
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
const tabs = [
|
||
{ id: 'research', label: '🔬 Deep Research', count: traders.filter(t => t.status === 'learning').length },
|
||
{ id: 'strategies', label: '🎯 Strategies', count: traders.filter(t => t.status === 'active').length },
|
||
{ id: 'execution', label: '⚡ Execution', count: trades.filter(t => t.status === 'open').length },
|
||
{ id: 'journal', label: '📔 Journal', count: trades.length },
|
||
{ id: 'tools', label: '🧮 Tools', count: 3 },
|
||
{ id: 'macro', label: '📈 Trading Reports', count: 0 },
|
||
]
|
||
|
||
const filteredTrades = trades.filter(t => {
|
||
if (journalFilter === 'all') return true
|
||
if (journalFilter === 'demo') return t.isDemo
|
||
return !t.isDemo
|
||
})
|
||
|
||
const openTrades = trades.filter(t => t.status === 'open')
|
||
const closedDemoTrades = trades.filter(t => t.status === 'closed' && t.isDemo)
|
||
const closedRealTrades = trades.filter(t => t.status === 'closed' && !t.isDemo)
|
||
|
||
const totalPnl = closedRealTrades.reduce((sum, t) => sum + (t.pnl || 0), 0)
|
||
const winRate = closedRealTrades.length > 0
|
||
? Math.round((closedRealTrades.filter(t => (t.pnl || 0) > 0).length / closedRealTrades.length) * 100)
|
||
: 0
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
{/* Tab Navigation */}
|
||
<div className="flex gap-2 flex-wrap">
|
||
{tabs.map(tab => (
|
||
<button
|
||
key={tab.id}
|
||
onClick={() => setActiveTab(tab.id as TradingTab)}
|
||
className={`px-4 py-2 rounded-lg text-sm font-medium transition ${
|
||
activeTab === tab.id
|
||
? 'bg-brand-pink text-white'
|
||
: 'bg-white/10 text-white/70 hover:bg-white/20'
|
||
}`}
|
||
>
|
||
{tab.label}
|
||
<span className="ml-2 text-xs opacity-70">({tab.count})</span>
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Research Tab */}
|
||
{activeTab === 'research' && (
|
||
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
|
||
<h3 className="text-lg font-bold mb-4">🔬 Deep Research</h3>
|
||
<p className="text-white/60 mb-4">Learn trading strategies from experts by analyzing their content.</p>
|
||
|
||
<div className="space-y-3">
|
||
{traders.map(trader => (
|
||
<div
|
||
key={trader.id}
|
||
className="p-4 rounded-lg bg-white/5 border border-white/10"
|
||
>
|
||
<div className="flex items-center justify-between mb-2">
|
||
<div className="flex items-center gap-3">
|
||
<span className="text-2xl">👨🏫</span>
|
||
<div>
|
||
<p className="font-medium">{trader.name}</p>
|
||
<p className="text-xs text-white/50">{trader.framesAnalyzed} frames analyzed</p>
|
||
</div>
|
||
</div>
|
||
<span className={`px-2 py-1 rounded text-xs ${
|
||
trader.status === 'learning' ? 'bg-yellow-500/20 text-yellow-400' :
|
||
trader.status === 'active' ? 'bg-green-500/20 text-green-400' :
|
||
'bg-white/10 text-white/50'
|
||
}`}>
|
||
{trader.status}
|
||
</span>
|
||
</div>
|
||
{trader.patterns.length > 0 && (
|
||
<div className="mt-2 flex flex-wrap gap-1">
|
||
{trader.patterns.map(p => (
|
||
<span key={p} className="px-2 py-0.5 bg-white/10 rounded text-xs">{p}</span>
|
||
))}
|
||
</div>
|
||
)}
|
||
<button
|
||
className="mt-3 text-sm text-brand-pink hover:underline"
|
||
onClick={() => setShowFullAnalysis(trader.id)}>
|
||
View full analysis →
|
||
</button>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<button className="mt-4 w-full py-2 border border-dashed border-white/20 rounded-lg text-white/50 hover:border-white/40 hover:text-white transition">
|
||
+ Add new trader to research
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
{/* Strategies Tab */}
|
||
{activeTab === 'strategies' && (
|
||
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
|
||
<h3 className="text-lg font-bold mb-4">🎯 Trading Strategies</h3>
|
||
<p className="text-white/60 mb-4">Select a trader style to follow for your next trade.</p>
|
||
|
||
<div className="flex gap-2 flex-wrap mb-4">
|
||
{traders.filter(t => t.status === 'active').map(trader => (
|
||
<button
|
||
key={trader.id}
|
||
onClick={() => setSelectedTrader(trader.id)}
|
||
className={`px-4 py-2 rounded-lg text-sm font-medium transition ${
|
||
selectedTrader === trader.id
|
||
? 'bg-brand-pink text-white'
|
||
: 'bg-white/10 text-white/70 hover:bg-white/20'
|
||
}`}
|
||
>
|
||
{trader.name}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{traders.find(t => t.id === selectedTrader) && (
|
||
<div className="p-4 rounded-lg bg-black/30 border border-white/10">
|
||
<h4 className="font-medium mb-3">{traders.find(t => t.id === selectedTrader)?.name} Strategy</h4>
|
||
|
||
<div className="space-y-3 text-sm">
|
||
<div>
|
||
<p className="text-white/50 text-xs mb-1">Entry Rules</p>
|
||
<ul className="list-disc list-inside space-y-1">
|
||
{traders.find(t => t.id === selectedTrader)?.entryRules.map(r => (
|
||
<li key={r}>{r}</li>
|
||
))}
|
||
</ul>
|
||
{traders.find(t => t.id === selectedTrader)?.entryRules.length === 0 && (
|
||
<p className="text-white/30 italic">No entry rules defined yet</p>
|
||
)}
|
||
</div>
|
||
|
||
<div>
|
||
<p className="text-white/50 text-xs mb-1">Exit Rules</p>
|
||
<ul className="list-disc list-inside space-y-1">
|
||
{traders.find(t => t.id === selectedTrader)?.exitRules.map(r => (
|
||
<li key={r}>{r}</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
|
||
<div>
|
||
<p className="text-white/50 text-xs mb-1">Indicators</p>
|
||
<div className="flex flex-wrap gap-1">
|
||
{traders.find(t => t.id === selectedTrader)?.indicators.map(i => (
|
||
<span key={i} className="px-2 py-0.5 bg-blue-500/20 text-blue-400 rounded text-xs">{i}</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<p className="text-white/50 text-xs mb-1">Risk Parameters</p>
|
||
<ul className="list-disc list-inside space-y-1">
|
||
{traders.find(t => t.id === selectedTrader)?.riskParams.map(r => (
|
||
<li key={r}>{r}</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<button
|
||
onClick={() => setShowExecuteTrade(true)}
|
||
className="mt-4 w-full py-2 bg-brand-pink rounded-lg font-medium hover:bg-[#ff7bc0] transition">
|
||
Execute Trade in {traders.find(t => t.id === selectedTrader)?.name} Style →
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* Execution Tab */}
|
||
{activeTab === 'execution' && (
|
||
<TradingChart />
|
||
)}
|
||
|
||
{/* Journal Tab */}
|
||
{activeTab === 'journal' && (
|
||
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
|
||
<h3 className="text-lg font-bold mb-4">📔 Trading Journal</h3>
|
||
|
||
{/* Per-Trader Stats */}
|
||
<div className="mb-4">
|
||
<h4 className="text-sm font-medium text-white/70 mb-2">📊 Performance by Trader Style</h4>
|
||
<div className="grid grid-cols-1 gap-2">
|
||
{traders.filter(t => t.status !== 'paused').map(trader => {
|
||
const traderTrades = trades.filter(t => t.traderStyle === trader.id)
|
||
const closedTrades = traderTrades.filter(t => t.status === 'closed' && !t.isDemo)
|
||
const wins = closedTrades.filter(t => (t.pnl || 0) > 0).length
|
||
const totalPnl = closedTrades.reduce((sum, t) => sum + (t.pnl || 0), 0)
|
||
const winRate = closedTrades.length > 0 ? Math.round((wins / closedTrades.length) * 100) : 0
|
||
|
||
return (
|
||
<div key={trader.id} className="p-3 bg-white/5 rounded-lg border border-white/10">
|
||
<div className="flex justify-between items-center">
|
||
<div>
|
||
<span className="font-medium text-white">{trader.name}</span>
|
||
<span className="ml-2 text-xs text-white/50">({traderTrades.length} trades)</span>
|
||
</div>
|
||
<div className="text-right">
|
||
<span className={`font-bold ${totalPnl >= 0 ? 'text-green-400' : 'text-red-400'}`}>
|
||
${totalPnl.toFixed(2)}
|
||
</span>
|
||
<span className="ml-2 text-xs text-white/50">| {winRate}% WR</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
})}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Overall Stats */}
|
||
<div className="grid grid-cols-3 gap-3 mb-4">
|
||
<div className="p-3 rounded bg-white/5 text-center">
|
||
<p className="text-2xl font-bold text-green-400">${totalPnl.toFixed(2)}</p>
|
||
<p className="text-xs text-white/50">Real P&L</p>
|
||
</div>
|
||
<div className="p-3 rounded bg-white/5 text-center">
|
||
<p className="text-2xl font-bold">{winRate}%</p>
|
||
<p className="text-xs text-white/50">Win Rate</p>
|
||
</div>
|
||
<div className="p-3 rounded bg-white/5 text-center">
|
||
<p className="text-2xl font-bold">{closedRealTrades.length}</p>
|
||
<p className="text-xs text-white/50">Real Trades</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Filter */}
|
||
<div className="flex gap-2 mb-4">
|
||
{(['all', 'demo', 'real'] as const).map(filter => (
|
||
<button
|
||
key={filter}
|
||
onClick={() => setJournalFilter(filter)}
|
||
className={`px-3 py-1 rounded text-xs ${
|
||
journalFilter === filter
|
||
? 'bg-brand-pink text-white'
|
||
: 'bg-white/10 text-white/60'
|
||
}`}
|
||
>
|
||
{filter === 'all' ? 'All' : filter === 'demo' ? 'Demo' : 'Real'}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Trades List */}
|
||
<div className="space-y-2 max-h-[400px] overflow-y-auto">
|
||
{filteredTrades.length === 0 ? (
|
||
<p className="text-white/40 text-center py-4">No trades yet</p>
|
||
) : (
|
||
filteredTrades.map(trade => (
|
||
<div
|
||
key={trade.id}
|
||
className={`p-3 rounded border ${
|
||
trade.isDemo
|
||
? 'bg-white/5 border-white/10'
|
||
: trade.status === 'open'
|
||
? 'bg-yellow-500/10 border-yellow-500/30'
|
||
: (trade.pnl || 0) > 0
|
||
? 'bg-green-500/10 border-green-500/30'
|
||
: 'bg-red-500/10 border-red-500/30'
|
||
}`}
|
||
>
|
||
<div className="flex justify-between items-start">
|
||
<div>
|
||
<span className="font-medium">{trade.pair}</span>
|
||
<span className={`ml-2 text-xs px-1.5 py-0.5 rounded ${
|
||
trade.direction === 'long' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
|
||
}`}>
|
||
{trade.direction.toUpperCase()}
|
||
</span>
|
||
{trade.isDemo && <span className="ml-1 text-xs text-white/40">(Demo)</span>}
|
||
</div>
|
||
{trade.status === 'closed' && (
|
||
<span className={`font-bold ${(trade.pnl || 0) >= 0 ? 'text-green-400' : 'text-red-400'}`}>
|
||
{trade.pnl >= 0 ? '+' : ''}{trade.pnl?.toFixed(2)} ({trade.pnlPercent?.toFixed(1)}%)
|
||
</span>
|
||
)}
|
||
</div>
|
||
<p className="text-xs text-white/50 mt-1">{trade.setup}</p>
|
||
<div className="flex gap-4 mt-2 text-xs text-white/40">
|
||
<span>{trade.timeframe}</span>
|
||
<span>{new Date(trade.openedAt).toLocaleDateString()}</span>
|
||
</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Tools Tab */}
|
||
{activeTab === 'tools' && (
|
||
<TradingTools />
|
||
)}
|
||
|
||
{/* Macro Report Tab */}
|
||
{activeTab === 'macro' && (
|
||
<MacroReportGenerator />
|
||
)}
|
||
|
||
{/* Full Analysis Modal */}
|
||
{showFullAnalysis && (
|
||
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||
<div className="bg-[#1a1625] border border-white/20 rounded-xl max-w-2xl w-full max-h-[80vh] overflow-y-auto">
|
||
{(() => {
|
||
const trader = traders.find(t => t.id === showFullAnalysis)
|
||
if (!trader) return null
|
||
return (
|
||
<div className="p-6">
|
||
<div className="flex justify-between items-start mb-6">
|
||
<div>
|
||
<h2 className="text-2xl font-bold text-white">{trader.name}</h2>
|
||
<p className="text-white/50">{trader.framesAnalyzed} frames analyzed • {trader.status}</p>
|
||
</div>
|
||
<button
|
||
onClick={() => setShowFullAnalysis(null)}
|
||
className="text-white/50 hover:text-white text-2xl"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
|
||
<div className="space-y-6">
|
||
{/* Patterns */}
|
||
<div>
|
||
<h3 className="text-brand-pink font-medium mb-2">📊 Patterns</h3>
|
||
<div className="flex flex-wrap gap-2">
|
||
{trader.patterns.map(p => (
|
||
<span key={p} className="px-3 py-1 bg-white/10 rounded-full text-sm text-white/80">{p}</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Entry Rules */}
|
||
<div>
|
||
<h3 className="text-green-400 font-medium mb-2">✅ Entry Rules</h3>
|
||
<ul className="space-y-1">
|
||
{trader.entryRules.map((r, i) => (
|
||
<li key={i} className="text-white/80 text-sm flex gap-2">
|
||
<span className="text-green-400">•</span>
|
||
{r}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
|
||
{/* Exit Rules */}
|
||
<div>
|
||
<h3 className="text-red-400 font-medium mb-2">🚪 Exit Rules</h3>
|
||
<ul className="space-y-1">
|
||
{trader.exitRules.map((r, i) => (
|
||
<li key={i} className="text-white/80 text-sm flex gap-2">
|
||
<span className="text-red-400">•</span>
|
||
{r}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
|
||
{/* Indicators */}
|
||
<div>
|
||
<h3 className="text-blue-400 font-medium mb-2">📈 Indicators</h3>
|
||
<div className="flex flex-wrap gap-2">
|
||
{trader.indicators.map(i => (
|
||
<span key={i} className="px-3 py-1 bg-blue-500/10 border border-blue-500/20 rounded-full text-sm text-blue-300">{i}</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Risk Params */}
|
||
<div>
|
||
<h3 className="text-yellow-400 font-medium mb-2">⚠️ Risk Parameters</h3>
|
||
<ul className="space-y-1">
|
||
{trader.riskParams.map((r, i) => (
|
||
<li key={i} className="text-white/80 text-sm flex gap-2">
|
||
<span className="text-yellow-400">•</span>
|
||
{r}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
|
||
{/* Timeframe */}
|
||
<div>
|
||
<h3 className="text-purple-400 font-medium mb-2">⏱️ Timeframe</h3>
|
||
<p className="text-white/80">{trader.timeframe}</p>
|
||
</div>
|
||
|
||
{/* Notes */}
|
||
{trader.notes && (
|
||
<div>
|
||
<h3 className="text-white/50 font-medium mb-2">📝 Notes</h3>
|
||
<p className="text-white/70 text-sm italic">{trader.notes}</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
<div className="mt-6 pt-4 border-t border-white/10 flex gap-3">
|
||
<button
|
||
onClick={() => {
|
||
setSelectedTrader(trader.id)
|
||
setShowFullAnalysis(null)
|
||
setActiveTab('strategies')
|
||
}}
|
||
className="flex-1 py-2 bg-brand-pink text-white rounded-lg font-medium hover:bg-brand-pink/80 transition"
|
||
>
|
||
Use This Strategy →
|
||
</button>
|
||
<button
|
||
onClick={() => setShowFullAnalysis(null)}
|
||
className="px-4 py-2 border border-white/20 text-white/70 rounded-lg hover:text-white transition"
|
||
>
|
||
Close
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)
|
||
})()}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Execute Trade Modal */}
|
||
{showExecuteTrade && (
|
||
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||
<ExecuteTradeModal
|
||
traders={traders}
|
||
selectedTrader={selectedTrader}
|
||
onClose={() => setShowExecuteTrade(false)}
|
||
onTradeExecuted={(trade) => {
|
||
setTrades([trade, ...trades])
|
||
setShowExecuteTrade(false)
|
||
}}
|
||
/>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|