Fix sleeper DCF: cap growth rates to enforce bear ≤ base ≤ bull ordering - #6
Open
rmalhotra25 wants to merge 10 commits into
Open
Fix sleeper DCF: cap growth rates to enforce bear ≤ base ≤ bull ordering#6rmalhotra25 wants to merge 10 commits into
rmalhotra25 wants to merge 10 commits into
Conversation
…eleration - _fetch_fundamentals: add 8 new fields from same Finnhub call at no extra API cost: 6mo/3mo price returns, FCF margin, ROIC, quarterly rev growth - _add_derived_signals: compute rev_accel (quarterly vs TTM growth speed) and growth_efficiency (rev growth / P/S, PEG-style) per stock - _pct_ranks: percentile-normalize each metric across the scanned universe so scoring reflects relative rank, not arbitrary fixed thresholds - _build_compounder_scores / _build_sleeper_scores: weighted multi-factor models replacing the old point-ladder system; momentum and acceleration are now first-class signals alongside margins and valuation - _fmt_candidates: richer context sent to Claude (FCF, momentum, ROIC, [↑ACCEL]/[↓DECEL] tags) so thesis quality improves with the data - PickCard: new chips for FCF Margin, ROIC, 6mo Return (green/red), Acceleration (green/red arrow); MetricChip supports accent color https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
finnhub_client.py:
- get_insider_sentiment(): fetches last 90 days of direct (non-derivative)
insider transactions; requires 2+ distinct insiders for a buy/sell signal
to filter out noise from single-exec routine option exercises
discovery_engine.py (Phase 3 enrichment):
- For each finalist (top 35 per category, rate-limited) fetch:
- Finnhub insider sentiment: signal + buyer/seller counts stored on dict
- Polygon short interest: days_to_cover + short_vol_pct (optional, no
Finnhub rate limit, silently skipped if Polygon unavailable)
- _fmt_candidates: passes InsiderBuying/InsiderSelling and ShortDTC context
to Claude so theses can reference these signals
- _enrich: exposes insider_signal, insiders_buying, insiders_selling,
days_to_cover, short_vol_pct to the frontend
DiscoveryTab.jsx:
- insiderBuyBadge (green) and insiderSellBadge (orange) styles added
- PickCard: shows "Insiders Buying (N)" / "Insiders Selling (N)" badge
when signal is triggered; Short DTC chip highlights squeeze potential
(green accent when DTC > 10 days)
https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
discovery_engine.py:
- _fmt_candidates: d['pe'] / d['ps'] → d.get('pe') / d.get('ps') so the
expression is safe even if the key is absent (guard on left side of
conditional already prevents reaching the round() call, but using .get()
is defensive and consistent with every other field access in this file)
- _enrich: same fix for the two round() calls on pe and ps
DiscoveryTab.jsx:
- insiders_buying / insiders_selling comparisons use ?? 0 so that old
cached scan results (pre-dating these fields) degrade gracefully instead
of comparing undefined >= 2
https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
…o Discovery picks - New `_dcf_scenarios()`: 10-year FCF DCF with bull/base/bear scenarios using PS-derived revenue and gross-margin FCF floor for pre-profit compounders. Compounders use 12% discount rate; sleepers use 10%. - DCF recommendation (Strong Buy/Buy/Hold/Pass) driven by base-case upside vs current market cap. - Updated Claude prompt to request `bull_case`, `bear_case`, and `long_term_rec` fields alongside existing thesis/catalyst/risk. - Frontend: new `DcfSection` component shows Bear/Base/Bull intrinsic values with % upside, DCF recommendation badge, and AI recommendation badge. - Replaced Catalyst/Risk boxes with 🐂 Bull Case / 🐻 Bear Case boxes (fall back to old catalyst/risk text if new fields absent on cached results). https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
Derives current share price from shareOutstanding (company profile) and computes implied price targets for each DCF scenario. Each cell now shows market cap, price target, and % upside. https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
…unavailable Finnhub often omits fcfMarginTTM (e.g. NVDA), causing FCF to default to 0 and the gross_margin*0.15 floor to severely underestimate intrinsic value. Adding net_margin*0.85 as an intermediate proxy (FCF ≈ 85% of net income) fixes this: for NVDA (~55% net margin) fcf_0 goes from 0.107 to 0.468, producing realistic bear/base/bull price targets instead of -90%+ downsides. https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
Previous push via GitHub API encoded newlines as literal \n characters, putting the entire file on one line and causing a SyntaxError on startup. Restoring the correct version with proper newlines. https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
For high-growth stocks appearing in sleepers (e.g. NVDA with 65.5% rev growth), the base case was using uncapped rev_growth while the bull case was capped at 30%. This made base > bull (e.g. $15T base vs $5.8T bull for NVDA). Fix: cap base at min(rev_growth*0.80, 20%) and bear at min(rev_growth*0.30, base), enforcing monotonic ordering. This also correctly signals that a high-growth stock is overvalued as a sleeper (NVDA sleeper base ~$3.2T vs $5.2T market cap). https://claude.ai/code/session_0118U48tD3eV3sNjsCUvrmch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For high-growth stocks appearing in sleepers (e.g. NVDA with 65.5% rev growth), the base case used uncapped rev_growth while the bull case was capped at 30%. This inverted the ordering (base $15T > bull $5.8T for NVDA).
Fix: cap base at min(rev_growth0.80, 20%) and bear at min(rev_growth0.30, base), enforcing bear ≤ base ≤ bull. Also includes the newline-fix and FCF net margin proxy commits already in master.
Generated by Claude Code