/* ───────────────────────────────────────────────────────── components.jsx — reusable bits for the dashboard Export each to window so the main app.jsx can use them. ───────────────────────────────────────────────────────── */ const { useState, useMemo, useRef, useEffect } = React; /* ───────── format helpers ───────── */ const fmtUSD = (n, opts = {}) => { const { showSign = false, decimals = 2 } = opts; const sign = n > 0 ? "+" : n < 0 ? "−" : ""; const abs = Math.abs(n).toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals, }); return (showSign ? sign : (n < 0 ? "−" : "")) + "$" + abs; }; const fmtPct = (n, decimals = 1) => { const sign = n > 0 ? "+" : n < 0 ? "−" : ""; return sign + Math.abs(n).toFixed(decimals) + "%"; }; const fmtDateShort = (iso) => { const d = new Date(iso + "T12:00:00"); return d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); }; const pnlClass = (n) => (n > 0 ? "pos" : n < 0 ? "neg" : ""); /* ───────── Tiny sparkline ───────── */ function Sparkline({ values, color = "var(--text-2)", height = 28, fill = false }) { if (!values || values.length === 0) return null; const min = Math.min(...values); const max = Math.max(...values); const W = 100, H = 30; const span = max - min || 1; const pts = values.map((v, i) => { const x = (i / (values.length - 1)) * W; const y = H - ((v - min) / span) * H; return [x, y]; }); const d = pts.map((p, i) => (i === 0 ? "M" : "L") + p[0].toFixed(2) + "," + p[1].toFixed(2)).join(" "); const dFill = d + ` L${W},${H} L0,${H} Z`; return ( {fill && } ); } /* ───────── ET clock + market status hook ───────── Mirrors the timing_optimizer reference: - 00:00–04:00 ET → AFTER-HRS - 04:00–09:30 ET → PRE-MKT - 09:30–16:00 ET → OPEN - 16:00–24:00 ET → AFTER-HRS Updates every second. ─────────────────────────────────────────────────── */ function getETParts(d = new Date()) { // Use Intl to reliably read NY time regardless of viewer's local tz const fmt = new Intl.DateTimeFormat("en-US", { timeZone: "America/New_York", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, weekday: "short", year: "numeric", month: "2-digit", day: "2-digit", }); const parts = fmt.formatToParts(d); const get = k => parts.find(p => p.type === k)?.value; const h = parseInt(get("hour"), 10) % 24; const m = parseInt(get("minute"), 10); const s = parseInt(get("second"), 10); const weekday = get("weekday"); // "Mon" "Tue" ... const isoDate = `${get("year")}-${get("month")}-${get("day")}`; return { h, m, s, weekday, isoDate, totalMin: h * 60 + m }; } function getMarketStatus(parts) { const { totalMin, weekday } = parts; const isWeekend = weekday === "Sat" || weekday === "Sun"; if (isWeekend) return { label: "WEEKEND", color: "var(--text-3)", isAfterHours: true, isOpen: false }; if (totalMin < 240) return { label: "AFTER-HRS", color: "var(--warn)", isAfterHours: true, isOpen: false }; if (totalMin < 570) return { label: "PRE-MKT", color: "#FF8A3D", isAfterHours: false, isOpen: false }; if (totalMin < 960) return { label: "OPEN", color: "var(--pos)", isAfterHours: false, isOpen: true }; return { label: "AFTER-HRS", color: "var(--warn)", isAfterHours: true, isOpen: false }; } function useETClock() { const [now, setNow] = React.useState(() => new Date()); React.useEffect(() => { const id = setInterval(() => setNow(new Date()), 1000); return () => clearInterval(id); }, []); const parts = getETParts(now); const status = getMarketStatus(parts); return { parts, status, now }; } function fmtETTime12(parts) { const { h, m, s } = parts; const period = h >= 12 ? "PM" : "AM"; const h12 = ((h + 11) % 12) + 1; const pad = n => String(n).padStart(2, "0"); return `${h12}:${pad(m)}:${pad(s)} ${period}`; } /* Next-trading-day label, used in the hero when after hours. - Friday after hours → Monday - Sat/Sun → Monday - Other days after hours → tomorrow's weekday + date */ function nextTradingDayLabel(parts) { // Walk forward at least 1 calendar day, skip Sat/Sun const base = new Date(parts.isoDate + "T12:00:00Z"); base.setUTCDate(base.getUTCDate() + 1); while ([0, 6].includes(base.getUTCDay())) base.setUTCDate(base.getUTCDate() + 1); return base.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", timeZone: "UTC" }); } /* ───────── Logo variants ───────── */ function LogoVariant({ variant = "candlesticks" }) { if (variant === "candlesticks") { return ( TRADING .OPT ); } if (variant === "monogram") { return ( trading-optimizer ); } if (variant === "ticker") { return ( $ TO TRADING OPTIMIZER ); } if (variant === "target") { return ( / OPTIMIZER / ); } if (variant === "network") { return ( trading · optimizer ); } if (variant === "bracket") { return ( [ 10:45 → 13:00 TRADING OPTIMIZER ] ); } return null; } Object.assign(window, { LogoVariant }); /* ───────── Account switcher tabs ───────── */ function AccountTabs({ accounts, selected, onSelect }) { return (
Accounts
{accounts.map((acct, i) => { const isOn = selected === i; const dayPos = acct.account.day_pnl_dollars >= 0; return ( ); })}
); } function Topbar({ botHealth, asOf, clock, logoVariant = "candlesticks" }) { const statusDot = botHealth.last_cron_status === "ok" ? "dot" : botHealth.last_cron_status === "warn" ? "dot warn" : "dot neg"; const timeStr = clock ? fmtETTime12(clock.parts) : "—"; const status = clock?.status; return (
bot live
Current Time
{timeStr} ET
Market Hours
{status?.label || "—"}
); } /* ───────── Hero / TODAY ───────── */ function TodayHero({ plan, account, streakHistory, currentStreak, botHealth, equitySpark, asOf, acct, clock }) { const isStrategyB = acct && acct.strategyKind === "B"; // Variable central content per state let badge = null; let ticker = plan.ticker || "—"; let tickerCls = "tile-hero-ticker"; let context = null; if (plan.state === "holding") { badge = Live · Holding; const h = Math.floor(plan.closes_in_minutes / 60); const m = plan.closes_in_minutes % 60; context = (
Buy {plan.buy_time} · Sell {plan.sell_time} · closes in {h}h {m}m
); } else if (plan.state === "closed") { const won = (plan.realized_pnl ?? 0) >= 0; badge = Closed · {won ? "win" : "loss"} settled; context = (
Bought {plan.buy_time} · Sold {plan.sell_time} · day complete
); } else if (plan.state === "pre_market") { badge = Pre-market · queued; const h = Math.floor(plan.fires_in_minutes / 60); const m = plan.fires_in_minutes % 60; context = (
Scanner picked {plan.ticker} · order fires in {h}h {m}m at {plan.buy_time}
); } else if (plan.state === "no_trade") { ticker = "NO TRADE"; tickerCls = "tile-hero-ticker no-trade"; badge = Scanner · no qualifying mover; context = (
{plan.reason}
); } else if (plan.state === "weekend") { ticker = "MARKETS CLOSED"; tickerCls = "tile-hero-ticker no-trade"; badge = Weekend · cron paused; const h = Math.floor(plan.next_fire_in_minutes / 60); const m = plan.next_fire_in_minutes % 60; context = (
Next cron fires {plan.next_fire_at} · in {h}h {m}m
); } else if (plan.state === "next_day") { ticker = "AWAITING SCANNER"; tickerCls = "tile-hero-ticker no-trade"; badge = After-hours · tomorrow's plan; context = (
Stake
${plan.stake.toLocaleString()}
{plan.stake_basis}
Buy
{plan.buy_time}
market order
Sell
{plan.sell_time}
market order
Formula in effect
{plan.formula}
{isStrategyB ? "always-on compounding" : "win × 1.5 / loss = port × 2%"}
{plan.stake_explanation} {plan.note}
); } const isActive = plan.state === "holding" || plan.state === "closed" || plan.state === "pre_market"; const showStake = isActive || plan.state === "next_day"; // Today P&L value (unrealized or realized; 0 otherwise) const todayPnl = plan.unrealized_pnl ?? plan.realized_pnl ?? 0; const asOfDate = asOf ? new Date(asOf) : new Date(); return (
{plan.state === "next_day" ? "Today's trading day" : "Today"}

{(() => { const d = clock ? new Date(clock.parts.isoDate + "T12:00:00Z") : asOfDate; const opts = { weekday: "long", month: "long", day: "numeric", timeZone: clock ? "UTC" : undefined }; return d.toLocaleDateString("en-US", opts); })()}

{plan.state === "next_day" ? `cron fires next at 09:20 ET` : `cron @ 09:20 ET · last fire ${botHealth.last_cron_at}`}
{/* Dominant tile */}
{badge}
{isActive ? plan.formula : ""}

{ticker}

{plan.ticker_long && isActive && (
{plan.ticker_long}
)} {plan.ticker_sector && isActive && (
{plan.ticker_sector}{plan.ticker_exchange ? ` · ${plan.ticker_exchange}` : ""} {plan.ticker_industry ? {` · ${plan.ticker_industry}`} : ""}
)}
{context} {plan.state === "holding" && (
Last · Bought
${plan.last_price.toFixed(2)} / ${plan.bought_at.toFixed(2)}
)} {plan.state === "closed" && (
Sell · Buy · Shares
${plan.sell_price.toFixed(2)} / ${plan.buy_price.toFixed(2)} · {plan.shares}sh
)}
{/* Supporting tiles */}
{/* Stake tile (today) OR Today's trade tile (next_day) */} {plan.state === "next_day" && plan.today_settled ? (
Today's trade {plan.today_settled.ticker}
Buy
${plan.today_settled.buy_price.toFixed(2)}
{plan.today_settled.buy_time}
Sell
${plan.today_settled.sell_price.toFixed(2)}
{plan.today_settled.sell_time}
{plan.today_settled.shares.toLocaleString()} shares of {plan.today_settled.ticker}
) : (
Stake deployed {showStake && plan.stake_basis && ( {plan.stake_basis} )}
{showStake ? "$" + plan.stake.toLocaleString() : }
{showStake ? (plan.stake_explanation || "Stake set from current streak formula.") : "No position deployed today."}
)}
Streak last 8
{isStrategyB ? n/a : currentStreak.count === 0 ? 0reset : {currentStreak.count}{currentStreak.kind} }
{!isStrategyB && currentStreak.count === 0 && (
broken 5/15 from 4W by CSCO loss
)} {isStrategyB && (
Strategy B always deploys full portfolio — no streak formula.
)}
{plan.state === "next_day" ? "Today's result" : "Today P&L"} {plan.state === "next_day" && plan.today_settled && ( {plan.today_settled.ticker} )}
{plan.state === "next_day" && plan.today_settled ? (() => { const pnl = plan.today_settled.realized_pnl; const pct = plan.today_settled.realized_pnl_pct; const cls = pnl > 0 ? "value-pos" : pnl < 0 ? "value-neg" : "value-neutral"; return ( <>
{fmtUSD(pnl, { showSign: true })}
{fmtPct(pct, 2)} · settled at 13:00 ET · {plan.today_settled.shares}sh of {plan.today_settled.ticker}
); })() : ( <>
0 ? "value-pos" : todayPnl < 0 ? "value-neg" : "value-neutral")}> {isActive ? fmtUSD(todayPnl, { showSign: true }) : $0.00}
{plan.state === "holding" ? "unrealized · marks every tick" : plan.state === "closed" ? "realized · settled" : "no trade today"}
)}
Portfolio value
${account.portfolio_value.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
Last cron fire
{botHealth.last_cron_at}
status OK · {botHealth.consecutive_successful_fires} successful in a row · backup {botHealth.backup_age_hours}h old
Open positions
{account.open_positions_count === 0 ? 0 : account.open_positions_count} {account.open_positions_count > 0 && plan.ticker && ( · {plan.ticker} )}
cash ${account.cash.toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: 0 })} available
); } /* ───────── Stats row ───────── */ function StatsRow({ perf }) { return (
Total return since 2026-03-31
0 ? "value-pos" : "value-neg")}> {fmtPct(perf.totalReturnPct, 2)}
0 ? "value-pos" : "value-neg"}> {fmtUSD(perf.totalReturnDollars, { showSign: true })}  on ${perf.startingBalance.toLocaleString()} starting equity
Win rate
{perf.winRate.toFixed(1)}%
{perf.wins}W / {perf.losses}L  of {perf.totalTrades} trades · Sharpe {perf.sharpe.toFixed(1)}
Best · Worst day
Best
{fmtUSD(perf.bestDay.pnl_dollars, { showSign: true })}
{perf.bestDay.ticker} · {fmtDateShort(perf.bestDay.date)}
Worst
{fmtUSD(perf.worstDay.pnl_dollars, { showSign: true })}
{perf.worstDay.ticker} · {fmtDateShort(perf.worstDay.date)}
); } /* ───────── Main chart — tabbed (Strategy-A-style) ───────── Tabs: Portfolio Value · Daily P&L ($) · Daily P&L (%) · Cumulative P&L Range: 3D · 7D · 14D · 1M · All ─────────────────────────────────────────────────────────── */ const TAB_DEFS = [ { id: "portfolio", label: "Portfolio Value", tip: "Account value at each daily close.\nThe headline strategy curve — answers \"is this making money over time?\"" }, { id: "daily", label: "Daily P&L ($)", tip: "Per-day realized profit/loss in dollars.\nBars colored green positive, red negative." }, { id: "dailypct", label: "Daily P&L (%)", tip: "Per-day P&L as a percent of the stake deployed that day.\nNormalizes for variable position sizing — apples-to-apples across streak-scaled days." }, { id: "cumulative", label: "Cumulative P&L", tip: "Running sum of daily P&L from the start of the window.\nSame trajectory as Portfolio Value minus starting balance." }, ]; const RANGE_DEFS = [ { id: "3D", label: "3D", days: 3 }, { id: "7D", label: "7D", days: 7 }, { id: "14D", label: "14D", days: 14 }, { id: "1M", label: "1M", days: 22 }, { id: "3M", label: "3M", days: 66 }, { id: "6M", label: "6M", days: 126 }, { id: "1Y", label: "1Y", days: 252 }, { id: "5Y", label: "5Y", days: 1260 }, { id: "All", label: "All", days: Infinity }, ]; function MainChart({ equityCurve, dailyPnl, tradeByDate, tickerMeta, accentColor = "#00E5A0" }) { const [tab, setTab] = useState("portfolio"); // View window expressed as data-array indices [start, end). Range pills are // shortcuts that snap this window; pan/pinch/wheel mutate it directly. const total = equityCurve.length; const defaultDays = Math.min(35, total); const [view, setView] = useState({ start: total - defaultDays, end: total }); const [isDragging, setIsDragging] = useState(false); // Refs for pointer interaction (mutating per-event without re-rendering) const bodyRef = useRef(null); const pointersRef = useRef(new Map()); const dragRef = useRef(null); const pinchRef = useRef(null); function snapToRange(rangeId) { const def = RANGE_DEFS.find(r => r.id === rangeId); if (!def) return; const N = !isFinite(def.days) ? total : Math.min(def.days, total); setView({ start: total - N, end: total }); } function clampWindow(start, end) { let s = start, e = end; if (s < 0) { e -= s; s = 0; } if (e > total) { s -= (e - total); e = total; } s = Math.max(0, Math.round(s)); e = Math.min(total, Math.round(e)); if (e - s < 2) e = Math.min(total, s + 2); return { start: s, end: e }; } // Which range pill (if any) matches the current window exactly + is end-anchored const activeRange = (() => { if (view.end !== total) return null; const win = view.end - view.start; for (const r of RANGE_DEFS) { const target = !isFinite(r.days) ? total : Math.min(r.days, total); if (win === target) return r.id; } return null; })(); /* ── Pointer interaction handlers (mouse + touch + pen via Pointer Events) ── */ function onPointerDown(e) { bodyRef.current?.setPointerCapture?.(e.pointerId); pointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY }); const n = pointersRef.current.size; if (n === 1) { const rect = bodyRef.current.getBoundingClientRect(); dragRef.current = { startX: e.clientX, startView: { ...view }, width: rect.width }; pinchRef.current = null; } else if (n === 2) { const [a, b] = [...pointersRef.current.values()]; pinchRef.current = { startDist: Math.hypot(a.x - b.x, a.y - b.y), startMidX: (a.x + b.x) / 2, startView: { ...view }, rectLeft: bodyRef.current.getBoundingClientRect().left, width: bodyRef.current.getBoundingClientRect().width, }; dragRef.current = null; } setIsDragging(true); } function onPointerMove(e) { if (!pointersRef.current.has(e.pointerId)) return; pointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY }); const n = pointersRef.current.size; if (n === 1 && dragRef.current) { const { startX, startView, width } = dragRef.current; const dx = e.clientX - startX; const win = startView.end - startView.start; const dIdx = -(dx / width) * win; setView(clampWindow(startView.start + dIdx, startView.end + dIdx)); } else if (n === 2 && pinchRef.current) { const [a, b] = [...pointersRef.current.values()]; const dist = Math.hypot(a.x - b.x, a.y - b.y); const { startDist, startMidX, startView, rectLeft, width } = pinchRef.current; const scale = startDist / Math.max(1, dist); // >1 zooms out, <1 zooms in const startWin = startView.end - startView.start; const newWin = Math.max(2, Math.min(total, startWin * scale)); // Anchor zoom around the midpoint of the two fingers (in data-index space) const midT = (startMidX - rectLeft) / width; const midIdx = startView.start + midT * startWin; setView(clampWindow(midIdx - midT * newWin, midIdx + (1 - midT) * newWin)); } } function onPointerUp(e) { if (pointersRef.current.has(e.pointerId)) { pointersRef.current.delete(e.pointerId); } if (pointersRef.current.size === 0) { dragRef.current = null; pinchRef.current = null; setIsDragging(false); } else if (pointersRef.current.size === 1) { // Transition from pinch back to drag — restart drag anchor const [pid] = [...pointersRef.current.keys()]; const pt = pointersRef.current.get(pid); const rect = bodyRef.current.getBoundingClientRect(); dragRef.current = { startX: pt.x, startView: { ...view }, width: rect.width }; pinchRef.current = null; } } function onWheel(e) { e.preventDefault(); const rect = bodyRef.current.getBoundingClientRect(); const cursorT = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)); const win = view.end - view.start; const factor = e.deltaY > 0 ? 1.18 : 1 / 1.18; const newWin = Math.max(2, Math.min(total, win * factor)); const cursorIdx = view.start + cursorT * win; setView(clampWindow(cursorIdx - cursorT * newWin, cursorIdx + (1 - cursorT) * newWin)); } // Suppress default browser wheel scrolling over the chart, but only while // the user is actually hovering us. Attach as non-passive so preventDefault sticks. useEffect(() => { const el = bodyRef.current; if (!el) return; const handler = (e) => onWheel(e); el.addEventListener("wheel", handler, { passive: false }); return () => el.removeEventListener("wheel", handler); }, [view.start, view.end, total]); /* ── Derived data slices for current view window ── */ const eqSlice = equityCurve.slice(view.start, view.end); const pnlSlice = dailyPnl.slice(view.start, view.end); const pnlPctSlice = pnlSlice.map(d => { const tr = tradeByDate[d.date]; const stake = (tr && tr.stake_dollars) || 15000; return { date: d.date, pnl_dollars: d.pnl_dollars, pct: stake ? (d.pnl_dollars / stake) * 100 : 0, stake }; }); const cumulativeSlice = (() => { let sum = 0; return pnlSlice.map(d => { sum += d.pnl_dollars; return { date: d.date, cumulative: sum }; }); })(); const lastEq = eqSlice[eqSlice.length - 1]?.portfolio_value; const firstEq = eqSlice[0]?.portfolio_value; // ─── Sub-line under tabs: summary of current tab+range ─── let summaryLeft = ""; let summaryRight = ""; if (tab === "portfolio") { summaryLeft = `${eqSlice.length} trading days · daily close`; summaryRight = `$${firstEq?.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} → $${lastEq?.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; } else if (tab === "daily") { const wins = pnlSlice.filter(d => d.pnl_dollars > 0).length; const losses = pnlSlice.filter(d => d.pnl_dollars < 0).length; const net = pnlSlice.reduce((a, d) => a + d.pnl_dollars, 0); summaryLeft = `${pnlSlice.length} days · ${wins}W / ${losses}L`; summaryRight = `net ${fmtUSD(net, { showSign: true })}`; } else if (tab === "dailypct") { const winRows = pnlPctSlice.filter(d => d.pct > 0); const lossRows = pnlPctSlice.filter(d => d.pct < 0); const avgWin = winRows.length ? winRows.reduce((a, d) => a + d.pct, 0) / winRows.length : 0; const avgLoss = lossRows.length ? lossRows.reduce((a, d) => a + d.pct, 0) / lossRows.length : 0; summaryLeft = `avg win ${fmtPct(avgWin, 2)} · avg loss ${fmtPct(avgLoss, 2)}`; summaryRight = `% of daily stake deployed`; } else if (tab === "cumulative") { const t = cumulativeSlice[cumulativeSlice.length - 1]?.cumulative ?? 0; summaryLeft = `running sum · ${cumulativeSlice.length} days`; summaryRight = `total ${fmtUSD(t, { showSign: true })}`; } // ─── Choose data + renderer per tab ─── let chartEl = null; if (tab === "portfolio") { chartEl = "$" + (v / 1000).toFixed(1) + "k"} tooltipPrimary={v => "$" + v.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} tooltipPrimaryLabel="EQUITY" tooltipDeltaLabel="Δ START" tradeByDate={tradeByDate} tickerMeta={tickerMeta} interactive={!isDragging} accentColor={accentColor} />; } else if (tab === "daily") { chartEl = ({ ...d, value: d.pnl_dollars }))} yFmt={v => (v < 0 ? "−" : "") + "$" + Math.abs(v / 1000).toFixed(1) + "k"} tooltipPrimary={v => fmtUSD(v, { showSign: true })} tooltipPrimaryLabel="P&L" tradeByDate={tradeByDate} tickerMeta={tickerMeta} interactive={!isDragging} />; } else if (tab === "dailypct") { chartEl = ({ ...d, value: d.pct }))} yFmt={v => (v > 0 ? "+" : v < 0 ? "−" : "") + Math.abs(v).toFixed(1) + "%"} tooltipPrimary={v => fmtPct(v, 2)} tooltipPrimaryLabel="P&L %" extraRows={(d) => [["STAKE", "$" + d.stake.toLocaleString()], ["P&L $", fmtUSD(d.pnl_dollars, { showSign: true })]]} tradeByDate={tradeByDate} tickerMeta={tickerMeta} interactive={!isDragging} />; } else if (tab === "cumulative") { chartEl = (v < 0 ? "−" : "") + "$" + Math.abs(v / 1000).toFixed(1) + "k"} tooltipPrimary={v => fmtUSD(v, { showSign: true })} tooltipPrimaryLabel="CUM P&L" tradeByDate={tradeByDate} tickerMeta={tickerMeta} anchorAtZero={true} interactive={!isDragging} accentColor={accentColor} />; } return (
{TAB_DEFS.map(t => ( ))}
{RANGE_DEFS.map(r => ( ))}
{summaryLeft} {summaryRight} · drag to pan · pinch / scroll to zoom
{chartEl}
); } /* ───────── Generic line view (Portfolio / Cumulative) ───────── */ function LineView({ data, yKey, yFmt, tooltipPrimary, tooltipPrimaryLabel, tooltipDeltaLabel, tradeByDate, tickerMeta, anchorAtZero = false, height = 300, interactive = true, accentColor = "#00E5A0" }) { const wrapRef = useRef(null); const [hover, setHover] = useState(null); const [width, setWidth] = useState(900); useEffect(() => { const el = wrapRef.current; if (!el) return; const ro = new ResizeObserver(() => setWidth(el.clientWidth)); ro.observe(el); setWidth(el.clientWidth); return () => ro.disconnect(); }, []); useEffect(() => { if (!interactive) setHover(null); }, [interactive]); const pad = { l: 56, r: 16, t: 8, b: 28 }; const W = width, H = height; const iw = W - pad.l - pad.r; const ih = H - pad.t - pad.b; if (!data || data.length === 0) return
; const values = data.map(d => d[yKey]); let min = Math.min(...values); let max = Math.max(...values); if (anchorAtZero) { min = Math.min(0, min); max = Math.max(0, max); } const yPadV = (max - min) * 0.1 || 1; const yMin = min - yPadV; const yMax = max + yPadV; const x = i => pad.l + (data.length === 1 ? iw / 2 : (i / (data.length - 1)) * iw); const y = v => pad.t + ih - ((v - yMin) / (yMax - yMin)) * ih; const linePath = data.map((d, i) => (i === 0 ? "M" : "L") + x(i).toFixed(2) + "," + y(d[yKey]).toFixed(2)).join(" "); const areaPath = linePath + ` L${x(data.length - 1).toFixed(2)},${pad.t + ih} L${x(0).toFixed(2)},${pad.t + ih} Z`; const yTicks = 4; const yVals = Array.from({ length: yTicks + 1 }, (_, i) => yMin + ((yMax - yMin) * i) / yTicks); const xTickCount = Math.min(5, data.length); const xIdx = xTickCount <= 1 ? [0] : Array.from({ length: xTickCount }, (_, i) => Math.round((i * (data.length - 1)) / (xTickCount - 1))); // Color (green for non-negative trend / positive zero-anchor, red for negative) const lastVal = data[data.length - 1][yKey]; const lineColor = anchorAtZero ? (lastVal >= 0 ? accentColor : "#FF5C6F") : accentColor; const isNeg = anchorAtZero && lastVal < 0; function onMove(e) { if (!interactive) return; const rect = e.currentTarget.getBoundingClientRect(); const px = e.clientX - rect.left; const t = (px - pad.l) / iw; const i = Math.max(0, Math.min(data.length - 1, Math.round(t * (data.length - 1)))); setHover({ i, x: x(i), y: y(data[i][yKey]) }); } function onLeave() { setHover(null); } const startVal = data[0][yKey]; const hovered = hover ? data[hover.i] : null; const hoveredTrade = hovered ? tradeByDate[hovered.date] : null; const hoveredMeta = hoveredTrade ? tickerMeta[hoveredTrade.ticker] : null; const tooltipDelta = hovered ? hovered[yKey] - startVal : 0; return (
{yVals.map((v, i) => ( ))} {/* zero baseline */} {anchorAtZero && yMin < 0 && yMax > 0 && ( )} {yVals.map((v, i) => ( {yFmt(v)} ))} {xIdx.map((i, k) => ( {fmtDateShort(data[i].date)} ))} {hover && ( )} {hover && (
DATE{fmtDateShort(hovered.date)} · {new Date(hovered.date).getFullYear()}
{tooltipPrimaryLabel}= 0 ? "pnl-pos" : "pnl-neg") : "v"}>{tooltipPrimary(hovered[yKey])}
{tooltipDeltaLabel && (
{tooltipDeltaLabel}= 0 ? "pnl-pos" : "pnl-neg"}>{fmtUSD(tooltipDelta, { showSign: true })}
)} {hoveredTrade && (
{hoveredTrade.ticker}{hoveredMeta ? " · " + hoveredMeta.n : ""} {hoveredMeta && {hoveredMeta.s} · {hoveredMeta.x}}
)}
)}
); } /* ───────── Generic bars view (Daily $ / Daily %) ───────── */ function BarsView({ data, yFmt, tooltipPrimary, tooltipPrimaryLabel, extraRows, tradeByDate, tickerMeta, height = 300, interactive = true }) { const wrapRef = useRef(null); const [width, setWidth] = useState(900); const [hover, setHover] = useState(null); useEffect(() => { const el = wrapRef.current; if (!el) return; const ro = new ResizeObserver(() => setWidth(el.clientWidth)); ro.observe(el); setWidth(el.clientWidth); return () => ro.disconnect(); }, []); useEffect(() => { if (!interactive) setHover(null); }, [interactive]); const pad = { l: 56, r: 16, t: 14, b: 28 }; const W = width, H = height; const iw = W - pad.l - pad.r; const ih = H - pad.t - pad.b; if (!data || data.length === 0) return
; const max = Math.max(...data.map(d => Math.abs(d.value))) || 1; const zero = pad.t + ih / 2; const yScale = (ih / 2) / max; // With very dense data (1000+ bars in ~800px) bars can go sub-pixel; clamp to 1. const bw = Math.max(1, Math.min(20, (iw / data.length) - (data.length > 200 ? 0 : 2))); const xTickCount = Math.min(5, data.length); const xIdx = xTickCount <= 1 ? [0] : Array.from({ length: xTickCount }, (_, i) => Math.round((i * (data.length - 1)) / (xTickCount - 1))); const yTickVals = [max, max / 2, 0, -max / 2, -max]; const yTickY = v => zero - v * yScale; const hovered = hover ? data[hover.i] : null; const hoveredTrade = hovered ? tradeByDate[hovered.date] : null; const hoveredMeta = hoveredTrade ? tickerMeta[hoveredTrade.ticker] : null; return (
{yTickVals.map((v, i) => ( ))} {yTickVals.map((v, i) => ( {yFmt(v)} ))} {xIdx.map((i, k) => ( {fmtDateShort(data[i].date)} ))} {data.map((d, i) => { const xCenter = pad.l + (data.length === 1 ? iw / 2 : (i / (data.length - 1)) * iw); const x = xCenter - bw / 2; const v = d.value; const h = Math.abs(v) * yScale; const yTop = v >= 0 ? zero - h : zero; const fill = v >= 0 ? "var(--pos)" : "var(--neg)"; const isHovered = hover && hover.i === i; return ( interactive && setHover({ i, x: xCenter, yTop })} onMouseLeave={() => interactive && setHover(null)} /> ); })} {hover && ( )} {hover && hovered && (
DATE{fmtDateShort(hovered.date)}
{tooltipPrimaryLabel}= 0 ? "pnl-pos" : "pnl-neg"}>{tooltipPrimary(hovered.value)}
{extraRows && extraRows(hovered).map(([k, v], idx) => (
{k}{v}
))} {hoveredTrade && (
{hoveredTrade.ticker}{hoveredMeta ? " · " + hoveredMeta.n : ""} {hoveredMeta && {hoveredMeta.s} · {hoveredMeta.x}}
)}
)}
); } /* ───────── Recent trades ───────── */ function TradesTable({ trades, tickerMeta }) { return (
Recent trades
last {trades.length} closed positions · newest first
read-only · source: alpaca
{trades.map((t, i) => { const meta = tickerMeta[t.ticker] || { n: t.ticker, s: "—", x: "" }; return ( ); })}
Date Ticker Company Sector Stake P&L $ P&L %
{fmtDateShort(t.date)} {t.ticker} {meta.x && · {meta.x}} {meta.n} {meta.s} ${t.stake_dollars.toLocaleString()} {fmtUSD(t.pnl_dollars, { showSign: true })} {fmtPct(t.pnl_percent, 2)}
); } /* ───────── About / How it works ───────── */ function AboutSection({ strategy, acct }) { const isB = acct && acct.strategyKind === "B"; const steps = [ { time: "09:00", name: "Optimizer", desc: isB ? "No formula search for Strategy B — stake is always the full portfolio. Optimizer still picks buy/sell timing." : "Brute-force search over 14,700 combinations picks today's win/loss formula and buy/sell time." }, { time: "09:20", name: "Scanner", desc: "Pulls pre-market movers from a curated watchlist. Picks the top % gainer above 4%." }, { time: strategy.buy_time, name: "Buy", desc: isB ? "Deploys the ENTIRE portfolio into the picked ticker. Today's stake = yesterday's close." : `Submits a market buy on Alpaca. Today's stake: $${strategy.base_stake_dollars.toLocaleString()} (base).` }, { time: strategy.sell_time, name: "Sell", desc: "Closes the position at the chosen sell time. Realized P&L lands." }, { time: "13:15", name: "Log", desc: "Writes logs/YYYY-MM-DD.json. Updates streak state for tomorrow." }, { time: "13:30", name: "Notify", desc: "SNS email with the day's summary. CloudWatch records the run." }, ]; return (
How it works

{isB ? "Compound everything, every day." : "One stock, one day, one schedule."}

read-only · alpaca · v0.1
{isB ? ( <>

{acct.label} runs Strategy B — full compounding. Each day the bot deploys the entire portfolio balance into one stock rather than a fixed $15k stake. The trade execution is identical to Account 1, but the sizing changes every day.

Both gains and losses compound exponentially. A 5% winning day on a $130,000 portfolio returns $6,500 — but a 7.9% losing day (like CSCO on 5/15) wipes out $10,200+ in one trade. There is no streak formula — stake is always 100% of available capital.

Backtest over the last {strategy.backtest_days} days returned {" "}+{strategy.backtest_pnl_percent.toFixed(2)}% {" "}at a {(strategy.backtest_win_rate * 100).toFixed(1)}% win rate.

) : ( <>

This bot trades one stock per day on Alpaca. Each morning a scanner pulls pre-market movers from a curated watchlist of 570 tickers and picks the top percent gainer above 4%. An optimizer decides what time to buy and sell based on what has worked historically.

Stake size scales up after winning streaks and resets after a loss. The current win formula is {strategy.win_formula_expression} {" "}({strategy.win_formula_label}); the loss formula is {" "}{strategy.loss_formula_expression} {" "}({strategy.loss_formula_label}). Both were chosen by {strategy.chosen_via}.

Backtest over the last {strategy.backtest_days} days returned {" "}+{strategy.backtest_pnl_percent.toFixed(2)}% {" "}at a {(strategy.backtest_win_rate * 100).toFixed(1)}% win rate. The dashboard reads the daily logs the bot writes to disk after each run.

)}
AWS EC2 Alpaca Markets API Python 3.12 cron @ 09:20 ET SNS email alerts CloudWatch github.com / trading-optimizer
{steps.map((s, i) => (
{s.time} ET
{s.name}
{s.desc}
))}
); } /* ───────── Export ───────── */ Object.assign(window, { Sparkline, Topbar, TodayHero, StatsRow, MainChart, TradesTable, AboutSection, AccountTabs, fmtUSD, fmtPct, fmtDateShort, pnlClass, });