aboutsummaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-05-17Merge branch 'feature/valuation-redesign'Tyler
2026-05-17Fix valuation review: dead code, wrong peer bands, height scalingfeature/valuation-redesignTyler
- Remove dead _build_dcf_canvas_html (~525 lines, superseded by _build_dcf_canvas_only_html) - Remove unused ev_ebit assignment - Fix FCF yield KPI strip and mini row using dividendYieldTTM as peer band proxy (pass None — no equivalent peer field for FCF yield) - Expand st.spinner in _render_historical_ratios to cover get_peers() and get_ratios_for_tickers() calls - Collapse _render_all_multiples / _render_multiples_model indirection into a single function - Replace Comps fixed 2600px height with max(1900, 1500 + n_peers*80), saving 400-700px whitespace for typical 5-8 peer sets Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Fix Historical Ratios blank render and Earnings History height cutoffTyler
Missing semicolon after pts.forEach() prevented ASI, causing a JS syntax error that silently killed all chart and matrix rendering. Also bumped Earnings History iframe height to stop the table from being clipped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Revert "Add TopBar: search hint, NYSE clock, account chip; fix sticky"Tyler
This reverts commit 676ef596d16f39f5e101ea50ef025dd5415705ce.
2026-05-17Redesign Valuation tab: Key Ratios, Models, Historical, Comps, MultiplesTyler
- Key Ratios: 6-KPI snapshot strip with sparklines, 5-category ratio grid (Valuation, Profitability, Growth, Health, Cash Returns) via components.html() - Models (DCF): two-column layout — st.slider() rail + prominent verdict chip, EV→equity bridge, per-share reconciliation, cross-check grid as HTML canvas - Historical Ratios: SVG line chart (subject vs sector median) + clickable heatmap matrix that updates the chart via client-side JS - Comps: 4 percentile rank bars + sortable peer table, all via components.html() - Multiples: math-flow columns (EV/EBITDA, EV/Revenue, P/Book) with sensitivity strip and DCF cross-check; HTML range sliders drive JS computation All redesigned tabs: scrolling=False, string-concat HTML (no f-strings), XSS-safe (escape_html on all user-supplied strings injected into HTML/JS). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Add TopBar: search hint, NYSE clock, account chip; fix stickyTyler
Replaces the keyed-container sticky hack with a proper psm-top HTML bar (st.markdown) matching the design system. Clock is updated via components.html writing to window.parent.document. Fixes ancestor overflow so position:sticky works. Moves the / shortcut listener to window.parent.document so it fires regardless of iframe focus. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Merge branch 'feature/topbar-phase1'Tyler
2026-05-17Phase 2: sticky market bar via CSS position:stickyTyler
Keys the market bar container (st-key-market_bar_sticky) so CSS can target it reliably, then applies position:sticky top:0 z-index:200 with the page background so content scrolling underneath is covered. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Switch keyboard shortcut from Ctrl+K to / for ticker search focusTyler
Ctrl+K conflicts with the browser address bar on Linux. / is the conventional global search shortcut (GitHub, Linear) and is not intercepted by browsers. Guard prevents firing while an input is focused. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Merge branch 'feature/macro-tab'Tyler
2026-05-17Fix yield divisors and cold-cache UX in macro tabTyler
All four treasury yield symbols return values already in percent; the old /10 and /100 divisors were displaying ~0.04–0.46% instead of the correct 3–5% range. Also rename ambiguous `l` variable and add a spinner for the cold-cache load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Add ⌘K / Ctrl+K shortcut to focus sidebar ticker searchTyler
Injects a zero-height components.html block after the market bar that listens for Cmd/Ctrl+K and focuses the sidebar search input by matching its placeholder text. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Merge feature/session-persistence: session persistence + watchlist exit buttonTyler
- Persists watchlist and active ticker to localStorage across page reloads - Adds "← Watchlist" button in sidebar to return to landing page - Fixes write-before-read race that destroyed stored data on fresh load - Fixes click swallow caused by st.rerun() aborting render before click receivers were registered
2026-05-17Fix persistence write-before-read and click swallow bugsTyler
Two root causes: 1. The JS wrote empty session defaults to localStorage before reading stored values back, destroying saved data on every fresh page load. Fixed by gating on data-loaded: JS reads+restores only when loaded=0, writes+saves only when loaded=1. 2. st.rerun() inside render_persistence_bridge() aborted the render before qt_click_receiver/wl_click_receiver were registered. Streamlit clears unrendered widget state, so pending click values (_qt_click, _wl_click) were wiped before quotetable/watchlist could process them. Fixed by removing st.rerun() — the bridge runs at the top of the render cycle so restored session state propagates to components below in the same pass; no extra rerun needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Add Macro tab: Index Performance, Yield Curve, Sector HeatmapTyler
Three market-wide panels backed by yfinance (no new API keys). Macro tab renders before the st.stop() ticker guard so it's always accessible regardless of ticker state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Add session persistence and watchlist exit buttonTyler
Persists watchlist and active ticker across browser refreshes via a localStorage bridge (components/persistence.py), and adds a sidebar "← Watchlist" button to clear the active ticker and return to the QuoteTable landing page. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Merge feature/quotetable: watchlist quote table as empty-state landing pageTyler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Fix quotetable heading, stale click state, and parallel fetchTyler
- Rename "Positions" → "Quotes" (heading was misleading; implies holdings) - Always clear _qt_click on read so stale values from removed tickers don't persist across rerenders - Replace serial get_latest_price + get_company_info calls with parallel ThreadPoolExecutor fetch of get_company_info only; regularMarketPrice/currentPrice from info is sufficient for the table and halves the number of yfinance calls Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Fix click receivers: visibility:hidden instead of display:noneTyler
display:none removes elements from React's event processing, causing JS-dispatched input events to be silently dropped. Switching to visibility:hidden + height:0 keeps the inputs in the React tree so programmatic value changes trigger reruns correctly. Also covers the new qt_click_receiver for the quotetable. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Fix quotetable row click: use data-sym + event delegationTyler
Replaced inline onclick with escaped string literals with the same data-sym / closest(tr[data-sym]) event delegation pattern used by the working sidebar watchlist. Avoids JS string quoting issues in HTML attribute context. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Add QuoteTable as empty-state landing pageTyler
Renders watchlist tickers as a styled psm-card data table (Symbol, Sector, Last, Δ, % Day, Volume) when no ticker is selected. Falls back to the existing placeholder when the watchlist is empty. Uses the same JS hidden-input click pattern as the sidebar watchlist. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Fix 5D x-axis labels and weekend/closed fallback for intraday defaultTyler
- 5D period now uses '%a %H:%M' tick format so each day is labelled (Mon 09:30) instead of bare times that repeat across five days - default_period resolves to '1mo' when 1D series is empty (market closed, weekend, holiday) so the chart isn't blank on first load - JS activePeriod reads from OVERVIEW_META.default_period at boot instead of hardcoded '1d', and bootOverview syncs the active button to match Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17Add 1D and 5D intraday periods to overview chartTyler
Adds get_intraday_history() to data_service.py (5m/30m bars, ttl=60s) and wires it into the overview chart with HH:MM x-axis formatting, market-hours filtering, intraday-only primary fetch, hidden comparison buttons, and 1D as the default period on load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16Fix render_top_movers kwarg incompatibility with st.fragmentTyler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16Sidebar chrome: vertical nav, live clock, brand v1.2, drop snapshotTyler
Replace horizontal st.tabs() with session-state-driven vertical nav buttons in the sidebar (Workspace section). Remove company snapshot entirely — ticker info is covered by the persistent TickerHeader. Add NYSE live clock between brand and search. Update brand sub-label to "v 1.2". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16Rewrite watchlist as custom HTML component with proper stylingTyler
Replaces st.button rows with a components.html iframe that renders sym·price·Δ% in a 3-column grid with hairline dividers, monospace fonts, and colored change percentages. Adds hidden text_input click receiver so row clicks update session state. Fixes toggle button to show toast when watchlist cap is hit and removes now-redundant psm-watch-toggle CSS. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16Add session-scoped personal watchlist to sidebarTyler
Adds a save/remove toggle below the company snapshot, a watchlist section (capped at 10 tickers) that renders sym · price · Δ% rows above Top Movers, and an empty-state placeholder. Clicking a watchlist row loads that ticker. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16Add TickerHeader + KPI strip above tab stripTyler
Injects a persistent header band between the market bar and st.tabs(): sector tag, italic symbol, company name, 52W range rail with price pin, price, and Δ/% change chip; below that a 6-cell KPI strip (Market Cap, P/E, EPS, Div Yield, Beta, Short % Float). All data from cached service calls — free hits. Graceful "—" fallbacks for missing fields. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16Harden script embedding, timezone parsing, and layout buffersTyler
- overview: use json_for_script for inline payload/meta to prevent </script> break-out from yfinance-sourced strings; raise iframe height to cover responsive single-column collapse under 1100px - news: treat naive ISO/strptime datetimes as UTC before converting to local-naive, matching the int-timestamp branch from 75dbe29 - news: bump per-row iframe height to fit summary + metadata under scrolling=False - top_movers: drop name column in compact (sidebar) mode and tighten grid so symbol/price/change fit a default-width Streamlit sidebar Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16Rewrite overview tab as client-side HTML surfaceTyler
2026-05-16Move Top Movers to sidebar and tighten top spacingTyler
2026-05-16Fix timezone shift and script-tag escape in news tabTyler
Unix-int timestamps from Finnhub were returned as naive UTC, then .timestamp() reinterpreted them as local time — shifting relative ages and date filtering. Now normalize to local-naive like the other branches. Also escape </ in the JSON embedded in <script>, so headlines containing </script> cannot break out of the inline script. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16Redesign news tab UI surfaceTyler
2026-05-16Redesign insiders tab with client-side HTML viewTyler
2026-05-16Fix valuation and data robustness bugsTyler
2026-05-15Redesign filings tab as client-side surfaceTyler
2026-05-15Fix options lede title styleTyler
2026-05-15Redesigned Financials tab with components.html() dark-terminal aestheticTyler
Replaces st.radio/st.tabs/st.expander/st.dataframe with a single components.html() panel matching the Prism design system — same token block, val-ctx bar, lede card, and CSS grid tables as the Valuation tabs. Annual/Quarterly toggle and Income/Balance Sheet/Cash Flow tabs are handled in-iframe via vanilla JS with no Streamlit re-renders. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15Fix inner scrollbars on Forward Estimates, Analyst Targets, Earnings History ↵Tyler
tabs Switch scrolling=True → scrolling=False and increase height estimates so iframe content never clips. Excess height is invisible whitespace matching page background. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15Fix peer comparison track slider visual issuesTyler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15Redesigned valuation tabsTyler
2026-05-14Completely refreshed Key Ratios, Historical Ratios, and DCF/MultiplesTyler
tab.
2026-05-14Move DCF sliders into left rail of canvas iframeTyler
The sliders live inside the canvas iframe (keeping live JS behavior) but are now in a narrow left rail column — the same visual layout as before the live-DCF refactor. The canvas uses a 272px + 1fr grid: left aside has the header, four range inputs, and the filings panel; right div has all output sections unchanged. Removes the horizontal va-controls bar added in the previous commit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14Make DCF sliders live — no page reruns on dragTyler
Move all four DCF assumptions (WACC, TG, horizon, FCF growth) from st.slider widgets into the canvas iframe as native range inputs. A JavaScript runDCF() engine recomputes the full projection in the browser on every drag event, updating the verdict, bar chart (Plotly.react), cash-flow table, bridge, recon strip, and cross-check cell in place without a Streamlit round-trip. Python still runs run_dcf() once on page load (using session-state defaults) to populate dcf_intrinsic for the Multiples cross-check. The Recompute button in the rail clears API caches and reruns when fresh filing data is needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13Add Multiples view; fix Recompute button text colorTyler
- Collapse model picker from 4 tabs → 2: DCF and Multiples, persisted in session_state["models_view"] - New Multiples view: summary band, interactive comparison grid (8 math rows × 3 methods), sensitivity strip, DCF cross-check, footer - In-canvas sliders with sector marker + typical-band shading; JS recomputes all derived values live without a Streamlit rerun - Sector medians computed from peer ratios via FMP; falls back to reasonable defaults when peer data is unavailable - DCF intrinsic stored in session_state["dcf_intrinsic"] so the cross-check on the Multiples tab reads the live DCF value - P/Book applicability shows ◐ + warning color for asset-light companies instead of the solid ● used for strong-fit methods - Fix Recompute button text: target inner <p>/<span> with color: var(--brass-ink) to override Streamlit's fg-2 default Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13Redesign DCF tab — inspector rail layout with HTML canvasTyler
Replaces the flat column layout with a two-column inspector design: left rail holds four st.slider inputs + "From the filings" reference panel + Reset/Recompute actions; right canvas renders verdict hero, projection card (Plotly.js bar chart + cash-flow table), EV bridge, per-share recon, and cross-check via a single components.v1.html block. Also fixes primary button text color app-wide by targeting the modern Streamlit selector (stBaseButton-primary) alongside the legacy one. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13Apply Prism design system — brass/ink palette, EB Garamond + IBM Plex ↵Tyler
typography Implements the design kit: champagne brass accent (#C2AA7A), deep midnight backgrounds, EB Garamond italic headings, IBM Plex Sans/Mono body and numbers, terminal-density KPI cards, restyled sidebar brand mark, flat pill tabs, and a global Plotly theme so all charts inherit the dark palette automatically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06gitignoreTyler
2026-04-09Update README to reflect current app stateTyler Hoang
- Add Top Movers section - Note sidebar live price and company info display - Rename DCF Model tab to Models; document all four valuation models - Update project structure with top_movers.py and valuation_service.py description - Expand valuation notes to cover EV/EBITDA, EV/Revenue, and P/B models Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03Make valuation models collapsibleTyler