<feed xmlns='http://www.w3.org/2005/Atom'>
<title>prism.git/components, branch master</title>
<subtitle>Webapp for stock analysis</subtitle>
<id>https://git.tylerhoang.xyz/prism.git/atom?h=master</id>
<link rel='self' href='https://git.tylerhoang.xyz/prism.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/'/>
<updated>2026-05-17T09:08:31Z</updated>
<entry>
<title>Merge branch 'feature/valuation-redesign'</title>
<updated>2026-05-17T09:08:31Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T09:08:31Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=811fb970ac87c6f9e78e24889011623f097041a5'/>
<id>urn:sha1:811fb970ac87c6f9e78e24889011623f097041a5</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Fix valuation review: dead code, wrong peer bands, height scaling</title>
<updated>2026-05-17T09:08:26Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T09:08:26Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=85160a558b2d37965ee2b8799fdd177ec986eadd'/>
<id>urn:sha1:85160a558b2d37965ee2b8799fdd177ec986eadd</id>
<content type='text'>
- 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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix Historical Ratios blank render and Earnings History height cutoff</title>
<updated>2026-05-17T08:55:53Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T08:55:53Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=636086c5332b8aab5c1cc322bef1f3bb446a5add'/>
<id>urn:sha1:636086c5332b8aab5c1cc322bef1f3bb446a5add</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Redesign Valuation tab: Key Ratios, Models, Historical, Comps, Multiples</title>
<updated>2026-05-17T08:33:17Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T08:33:17Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=bb55d8be4a080e16227290333f667a5b39fa6575'/>
<id>urn:sha1:bb55d8be4a080e16227290333f667a5b39fa6575</id>
<content type='text'>
- 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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Merge branch 'feature/macro-tab'</title>
<updated>2026-05-17T08:11:29Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T08:11:29Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=5f3dd9a00706257758838d15f678773e5a2d7a13'/>
<id>urn:sha1:5f3dd9a00706257758838d15f678773e5a2d7a13</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Fix yield divisors and cold-cache UX in macro tab</title>
<updated>2026-05-17T08:10:49Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T08:10:49Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=722ab4f3e3ba895879191e2be3c5361fb755a786'/>
<id>urn:sha1:722ab4f3e3ba895879191e2be3c5361fb755a786</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix persistence write-before-read and click swallow bugs</title>
<updated>2026-05-17T07:58:25Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T07:58:25Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=48f3bc1960d71785aad44292205845612a4f1cb8'/>
<id>urn:sha1:48f3bc1960d71785aad44292205845612a4f1cb8</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add Macro tab: Index Performance, Yield Curve, Sector Heatmap</title>
<updated>2026-05-17T07:54:46Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T07:54:46Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=c48218eae73f1a07fd23496837cc030d82845353'/>
<id>urn:sha1:c48218eae73f1a07fd23496837cc030d82845353</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add session persistence and watchlist exit button</title>
<updated>2026-05-17T07:48:26Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T07:48:26Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=e885be599095037f93209d42ba55c77c2fb6b6ee'/>
<id>urn:sha1:e885be599095037f93209d42ba55c77c2fb6b6ee</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix quotetable heading, stale click state, and parallel fetch</title>
<updated>2026-05-17T07:40:20Z</updated>
<author>
<name>Tyler</name>
<email>tyler@tylerhoang.xyz</email>
</author>
<published>2026-05-17T07:40:20Z</published>
<link rel='alternate' type='text/html' href='https://git.tylerhoang.xyz/prism.git/commit/?id=9b5e0572de9721b90eee769251cf815cf714a5ad'/>
<id>urn:sha1:9b5e0572de9721b90eee769251cf815cf714a5ad</id>
<content type='text'>
- 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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
