// Pantalla de Portafolio: resumen + holdings + watchlist + movers function Portfolio({ onOpenTicker, watchlist, holdings, accent, intensity }) { // Cálculos sobre holdings const positions = holdings.map((h) => { const t = window.TICKERS[h.symbol]; const value = t.price * h.shares; const cost = h.avgCost * h.shares; const pl = value - cost; const plPct = (pl / cost) * 100; const dayPl = t.change * h.shares; return { ...h, t, value, cost, pl, plPct, dayPl }; }); const totalValue = positions.reduce((s, p) => s + p.value, 0); const totalCost = positions.reduce((s, p) => s + p.cost, 0); const totalPl = totalValue - totalCost; const totalPlPct = (totalPl / totalCost) * 100; const dayPl = positions.reduce((s, p) => s + p.dayPl, 0); const dayPlPct = (dayPl / (totalValue - dayPl)) * 100; const cash = 12480.50; // Movers: del universo de tickers, top 3 ganadores y 3 perdedores const allTickers = Object.values(window.TICKERS); const gainers = [...allTickers].sort((a, b) => b.pct - a.pct).slice(0, 3); const losers = [...allTickers].sort((a, b) => a.pct - b.pct).slice(0, 3); // Serie agregada del portafolio (suma de series de holdings, normalizada) const portfolioSeries = React.useMemo(() => { const N = 80; const sums = new Array(N).fill(0); positions.forEach((p) => { const s = window.genSeries(p.symbol, '1A', N); s.forEach((v, i) => { sums[i] += v * p.shares; }); }); return sums; }, [holdings]); const fmt = (n) => n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const allocations = positions .map((p) => ({ ...p, alloc: (p.value / totalValue) * 100 })) .sort((a, b) => b.alloc - a.alloc); return (
| Ticker | Acciones | Coste medio | Último | Cambio hoy | Valor | P&L total | 1A |
|---|---|---|---|---|---|---|---|
|
{p.symbol}
{p.t.name}
|
{p.shares} | ${p.avgCost.toFixed(2)} | ${p.t.price.toFixed(2)} | {dayUp ? '+' : ''}{p.t.pct.toFixed(2)}% | ${fmt(p.value)} |
{plUp ? '+' : ''}${fmt(Math.abs(p.pl))}
{plUp ? '+' : ''}{p.plPct.toFixed(1)}%
|
|