From f22313deafc08adb7a99676dfa16ffbe63b93176 Mon Sep 17 00:00:00 2001 From: Dennis Thiessen Date: Sat, 8 Aug 2026 17:24:04 +0200 Subject: [PATCH] chore: remove dead frontend code and one unused service helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scan of every module and exported symbol, with each candidate verified by hand rather than trusted from the scan. Deleted outright: frontend/src/lib/fundamentals.ts (112 lines, 12 exports) — imported by nothing, including FundamentalsPanel, which reads backend values. It mirrors scoring_service._compute_fundamental_score, so it is the same *kind* of thing as lib/qualification.ts — but nothing consumes it, so it mirrored nothing and could drift out of sync unnoticed. Skeleton.SkeletonLine, paperTrades.getEquityCurve, regime.regimeColor breadth_service.compute_breadth_today — self-described "thin wrapper, for future live use"; that future did not arrive. Kept, but unexported — used inside their own module, so the dead part was the public surface, not the code: Button.Spinner, exitPlan.SETUP_STOP_ATR_MULTIPLIER, client.ApiError. Three things the scan flagged that are NOT dead, recorded so the next sweep does not re-raise them: RegimeChart.tsx — lazy(() => import(...)) in RegimePage, so it looks orphaned to any importer-graph scan. Deleting it would break the risk page. qualification.ts MIN_TARGET_PROBABILITY / liveRiskReward — that file is a live mirror of app/services/qualification.py used in five places, and the constant is exported to document the backend value it tracks. ssl_bootstrap.ssl_status — called from an inline python snippet inside scripts/run_tier1_macbook.sh, invisible to a .py-only search. No orphaned backend modules across app/. Co-Authored-By: Claude Opus 5 --- app/services/breadth_service.py | 8 -- frontend/src/api/client.ts | 2 +- frontend/src/api/paperTrades.ts | 4 - frontend/src/components/ui/Button.tsx | 2 +- frontend/src/components/ui/Skeleton.tsx | 4 - frontend/src/lib/exitPlan.ts | 2 +- frontend/src/lib/fundamentals.ts | 112 ------------------------ frontend/src/lib/regime.ts | 13 --- 8 files changed, 3 insertions(+), 144 deletions(-) delete mode 100644 frontend/src/lib/fundamentals.ts diff --git a/app/services/breadth_service.py b/app/services/breadth_service.py index be4f9a6..6dd29bd 100644 --- a/app/services/breadth_service.py +++ b/app/services/breadth_service.py @@ -148,11 +148,3 @@ async def compute_breadth_details( """Breadth values plus the qualifying-member count for snapshot metadata.""" closes_by_symbol = await _load_universe_closes(db, symbols) return _breadth_with_counts(closes_by_symbol, window, min_tickers) - - -async def compute_breadth_today(db: AsyncSession) -> float | None: - """Latest breadth reading (thin wrapper, for future live use).""" - series = await compute_breadth_series(db) - if not series: - return None - return series[max(series)] diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index ecb5c37..55a4907 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -6,7 +6,7 @@ import { useAuthStore } from '../stores/authStore'; * Typed error class for API errors, providing structured error handling * across the application. */ -export class ApiError extends Error { +class ApiError extends Error { constructor(message: string) { super(message); this.name = 'ApiError'; diff --git a/frontend/src/api/paperTrades.ts b/frontend/src/api/paperTrades.ts index d3b78b1..e38748d 100644 --- a/frontend/src/api/paperTrades.ts +++ b/frontend/src/api/paperTrades.ts @@ -34,10 +34,6 @@ export interface EquityPoint { benchmark_pnl: number; } -export function getEquityCurve() { - return apiClient.get('paper-trades/equity-curve').then((r) => r.data); -} - export interface PerfPoint { date: string; manual_pnl: number; diff --git a/frontend/src/components/ui/Button.tsx b/frontend/src/components/ui/Button.tsx index 9233cb6..0f4efab 100644 --- a/frontend/src/components/ui/Button.tsx +++ b/frontend/src/components/ui/Button.tsx @@ -16,7 +16,7 @@ const sizeClasses: Record = { md: 'px-4 py-2 text-sm', }; -export function Spinner({ className = 'h-4 w-4' }: { className?: string }) { +function Spinner({ className = 'h-4 w-4' }: { className?: string }) { return (
; -} - export function SkeletonCard({ className = '' }: { className?: string }) { return
; } diff --git a/frontend/src/lib/exitPlan.ts b/frontend/src/lib/exitPlan.ts index dc6dc8b..be95dea 100644 --- a/frontend/src/lib/exitPlan.ts +++ b/frontend/src/lib/exitPlan.ts @@ -21,7 +21,7 @@ import type { ExitPolicy, TradeSetup } from './types'; * Guarded by test_prod_strategy_parity.py so a backend change can't silently * desync this. */ -export const SETUP_STOP_ATR_MULTIPLIER = 1.5; +const SETUP_STOP_ATR_MULTIPLIER = 1.5; export interface ExitPlan { mode: ExitPolicy['mode']; diff --git a/frontend/src/lib/fundamentals.ts b/frontend/src/lib/fundamentals.ts deleted file mode 100644 index 917c918..0000000 --- a/frontend/src/lib/fundamentals.ts +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Fundamental dimension readouts for the Fundamentals tab. - * - * Scoring mirrors app/services/scoring_service.py _compute_fundamental_score: - * equal-weighted average of available P/E, revenue growth, and earnings - * surprise (need ≥2 metrics). Market cap is display-only, not scored. - */ - -export interface FundamentalMetrics { - pe_ratio: number | null; - revenue_growth: number | null; - earnings_surprise: number | null; - market_cap?: number | null; -} - -export interface StatusRead { - text: string; - tone: string; -} - -const clamp = (v: number, lo = 0, hi = 100) => Math.max(lo, Math.min(hi, v)); - -/** P/E sub-score: lower is better. PE 15 → 100, 30 → 50, 45 → 0. */ -export function peSubScore(pe: number): number { - return clamp(100 - (pe - 15) * (100 / 30)); -} - -/** Revenue growth sub-score: 0% → 50, +20% → 100, −20% → 0. */ -export function revenueGrowthSubScore(growthPct: number): number { - return clamp(50 + growthPct * 2.5); -} - -/** Earnings surprise sub-score: 0% → 50, +10% → 100, −10% → 0. */ -export function earningsSurpriseSubScore(surprisePct: number): number { - return clamp(50 + surprisePct * 5); -} - -/** - * Overall fundamental score, or null when fewer than 2 scored metrics. - * Matches backend MIN_METRICS = 2. - */ -export function fundamentalScore(m: FundamentalMetrics): number | null { - const parts: number[] = []; - if (m.pe_ratio != null && m.pe_ratio > 0) parts.push(peSubScore(m.pe_ratio)); - if (m.revenue_growth != null) parts.push(revenueGrowthSubScore(m.revenue_growth)); - if (m.earnings_surprise != null) parts.push(earningsSurpriseSubScore(m.earnings_surprise)); - if (parts.length < 2) return null; - return parts.reduce((a, b) => a + b, 0) / parts.length; -} - -export function overallFundamentalStatus(score: number | null): StatusRead { - if (score == null) { - return { text: 'incomplete data', tone: 'text-amber-300' }; - } - if (score >= 70) return { text: 'strong fundamentals', tone: 'text-emerald-300' }; - if (score >= 55) return { text: 'healthy', tone: 'text-emerald-300' }; - if (score >= 45) return { text: 'mixed / average', tone: 'text-gray-400' }; - if (score >= 30) return { text: 'soft', tone: 'text-amber-300' }; - return { text: 'weak fundamentals', tone: 'text-red-300' }; -} - -export function peStatus(pe: number | null): StatusRead | null { - if (pe == null || !(pe > 0)) return null; - if (pe <= 15) return { text: 'cheap / attractive', tone: 'text-emerald-300' }; - if (pe <= 25) return { text: 'fair', tone: 'text-gray-400' }; - if (pe <= 35) return { text: 'expensive', tone: 'text-amber-300' }; - return { text: 'rich', tone: 'text-red-300' }; -} - -export function revenueGrowthStatus(growthPct: number | null): StatusRead | null { - if (growthPct == null) return null; - if (growthPct >= 20) return { text: 'strong growth', tone: 'text-emerald-300' }; - if (growthPct >= 5) return { text: 'solid growth', tone: 'text-emerald-300' }; - if (growthPct >= -5) return { text: 'flat', tone: 'text-gray-400' }; - if (growthPct >= -20) return { text: 'contracting', tone: 'text-amber-300' }; - return { text: 'deep contraction', tone: 'text-red-300' }; -} - -export function earningsSurpriseStatus(surprisePct: number | null): StatusRead | null { - if (surprisePct == null) return null; - if (surprisePct >= 10) return { text: 'beat (large)', tone: 'text-emerald-300' }; - if (surprisePct >= 2) return { text: 'beat', tone: 'text-emerald-300' }; - if (surprisePct >= -2) return { text: 'in line', tone: 'text-gray-400' }; - if (surprisePct >= -10) return { text: 'miss', tone: 'text-amber-300' }; - return { text: 'miss (large)', tone: 'text-red-300' }; -} - -/** Size band only — not good/bad, not part of the score. */ -export function marketCapStatus(marketCap: number | null): StatusRead | null { - if (marketCap == null || !(marketCap > 0)) return null; - if (marketCap >= 200e9) return { text: 'mega cap', tone: 'text-gray-400' }; - if (marketCap >= 10e9) return { text: 'large cap', tone: 'text-gray-400' }; - if (marketCap >= 2e9) return { text: 'mid cap', tone: 'text-gray-400' }; - if (marketCap >= 300e6) return { text: 'small cap', tone: 'text-gray-400' }; - return { text: 'micro cap', tone: 'text-gray-400' }; -} - -export function metricStatus( - key: 'pe_ratio' | 'revenue_growth' | 'earnings_surprise' | 'market_cap', - value: number | null, -): StatusRead | null { - switch (key) { - case 'pe_ratio': - return peStatus(value); - case 'revenue_growth': - return revenueGrowthStatus(value); - case 'earnings_surprise': - return earningsSurpriseStatus(value); - case 'market_cap': - return marketCapStatus(value); - } -} diff --git a/frontend/src/lib/regime.ts b/frontend/src/lib/regime.ts index 9849da7..b8bfc94 100644 --- a/frontend/src/lib/regime.ts +++ b/frontend/src/lib/regime.ts @@ -1,18 +1,5 @@ import type { MarketRegime } from './types'; -export function regimeColor(label: MarketRegime['label']): string { - switch (label) { - case 'bullish': - return 'text-emerald-400'; - case 'bearish': - return 'text-red-400'; - case 'neutral': - return 'text-amber-400'; - default: - return 'text-gray-400'; - } -} - export function regimeDot(label: MarketRegime['label']): string { switch (label) { case 'bullish':