8.1 KiB
Implementation Plan: Score Transparency & Trade Overlay
Overview
Extend the scoring API and UI to expose full score breakdowns (sub-scores, weights, raw values, formulas) for each dimension and the composite score. Add trade setup chart overlays (entry, stop-loss, take-profit zones) to the candlestick chart on the ticker detail page. Backend changes are in Python/FastAPI, frontend in React/TypeScript.
Tasks
-
1. Add score breakdown schemas and refactor scoring service
-
1.1 Add breakdown Pydantic models to
app/schemas/score.py- Add
SubScoreResponse,ScoreBreakdownResponse,CompositeBreakdownResponsemodels - Extend
DimensionScoreResponsewith optionalbreakdown: ScoreBreakdownResponsefield - Extend
ScoreResponsewith optionalcomposite_breakdown: CompositeBreakdownResponsefield - Requirements: 1.1, 1.7
- Add
-
1.2 Refactor
_compute_technical_scoreinapp/services/scoring_service.pyto return breakdown- Change return type to
tuple[float | None, ScoreBreakdown | None] - Return sub-scores for ADX (weight 0.4), EMA (weight 0.3), RSI (weight 0.3) with raw indicator values
- Include formula description string
- Add unavailable sub-scores with reason when data is insufficient
- Requirements: 1.2, 1.8
- Change return type to
-
1.3 Refactor
_compute_sentiment_scoreto return breakdown- Return record count, decay rate, lookback window, and weighted average formula parameters as sub-score metadata
- Requirements: 1.3, 1.8
-
1.4 Refactor
_compute_fundamental_scoreto return breakdown- Return PE Ratio, Revenue Growth, Earnings Surprise sub-scores with raw metric values and normalization formula
- Requirements: 1.4, 1.8
-
1.5 Refactor
_compute_momentum_scoreto return breakdown- Return 5-day ROC (weight 0.5) and 20-day ROC (weight 0.5) sub-scores with raw ROC percentages
- Requirements: 1.5, 1.8
-
1.6 Refactor
_compute_sr_quality_scoreto return breakdown- Return strong count (max 40 pts), proximity (max 30 pts), avg strength (max 30 pts) sub-scores with input values
- Requirements: 1.6, 1.8
-
1.7 Update
get_scoreto assemble composite breakdown and pass dimension breakdowns through- Build
CompositeBreakdownResponsewith original weights, available/missing dimensions, re-normalized weights, and formula - Wire dimension breakdowns into the response dict
- Requirements: 1.7, 3.2
- Build
-
1.8 Update
read_scoreinapp/routers/scores.pyto populate breakdown fields from service response- Map breakdown dicts from service into the new Pydantic response models
- Requirements: 1.1
-
* 1.9 Write property test: Dimension breakdown contains correct sub-scores (Property 1)
- Property 1: Dimension breakdown contains correct sub-scores
- Use
hypothesisto generate valid input data for each dimension type - Verify returned breakdown has expected sub-score names, correct weights, and non-null raw values
- Validates: Requirements 1.1, 1.2, 1.3, 1.4, 1.5, 1.6
-
* 1.10 Write property test: Composite re-normalization correctness (Property 2)
- Property 2: Composite re-normalization correctness
- Use
hypothesisto generate random subsets of dimensions with random weights - Verify re-normalized weights sum to 1.0 and each equals
original_weight / sum(available_weights) - Validates: Requirements 1.7, 3.2
-
-
2. Checkpoint — Backend score breakdown
- Ensure all tests pass, ask the user if questions arise.
-
3. Add frontend types and DimensionBreakdownPanel component
-
3.1 Extend frontend types in
frontend/src/lib/types.ts- Add
SubScore,ScoreBreakdown,CompositeBreakdowninterfaces - Extend
DimensionScoreDetailwith optionalbreakdownfield - Extend
ScoreResponsewith optionalcomposite_breakdownfield - Requirements: 1.1, 1.7
- Add
-
3.2 Create
frontend/src/components/ticker/DimensionBreakdownPanel.tsx- Expandable panel showing sub-score rows: name, score value, weight badge, raw input value
- Formula description text section
- Muted "unavailable" labels for missing sub-scores with reason
- Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8
-
3.3 Modify
frontend/src/components/ui/ScoreCard.tsxfor composite transparency- Make each dimension row expandable, rendering
DimensionBreakdownPanelwhen expanded - Show dimension weight next to each bar
- Show missing dimensions with muted styling and "redistributed" indicator
- Add tooltip/inline text explaining weighted average with re-normalization
- Requirements: 3.1, 3.2, 3.3
- Make each dimension row expandable, rendering
-
* 3.4 Write property test: Dimension breakdown UI rendering completeness (Property 3)
- Property 3: Dimension breakdown UI rendering completeness
- Use
fast-checkto generate randomScoreBreakdownobjects with 1-5 sub-scores - Render
DimensionBreakdownPaneland verify DOM contains exactly N sub-score rows with all required fields - Validates: Requirements 2.1
-
* 3.5 Write property test: Composite weight display (Property 4)
- Property 4: Composite weight display
- Use
fast-checkto generate random score responses with random available/missing dimension combinations - Render
ScoreCardand verify weight labels present and missing dimensions visually distinct - Validates: Requirements 3.1, 3.2
-
-
4. Checkpoint — Score transparency UI
- Ensure all tests pass, ask the user if questions arise.
-
5. Add trade setup chart overlay
-
5.1 Modify
frontend/src/components/charts/CandlestickChart.tsxto accept and render trade overlay- Add optional
tradeSetup?: TradeSetupprop - Draw entry price as dashed horizontal line (blue/white) spanning full chart width
- Draw stop-loss zone as red semi-transparent rectangle between entry and stop-loss
- Draw take-profit zone as green semi-transparent rectangle between entry and target
- Include entry, stop-loss, target in y-axis price range calculation
- Add hover tooltip showing direction, entry, stop, target, R:R ratio
- Render no overlay when prop is absent
- Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6
- Add optional
-
* 5.2 Write property test: Trade overlay y-axis range includes all trade levels (Property 5)
- Property 5: Trade overlay y-axis range includes all trade levels
- Use
fast-checkto generate random OHLCV data and random trade setups - Extract the y-axis range computation logic and verify all three trade levels fall within
[lo, hi] - Validates: Requirements 4.4
-
-
6. Integrate trade setup data on ticker detail page
-
6.1 Update
frontend/src/hooks/useTickerDetail.tsto include trades data- Add trades query to the hook return value
- Requirements: 5.1
-
6.2 Modify
frontend/src/pages/TickerDetailPage.tsxto wire trade overlay- Fetch trade setups via
useTrades(), filter for current symbol, pick latest bydetected_at - Pass
tradeSetupprop toCandlestickChart - Render trade setup summary card below chart (direction, entry, stop, target, R:R)
- Handle trades API failure gracefully — chart renders without overlay, error logged
- Requirements: 5.1, 5.2, 5.3, 5.4, 5.5
- Fetch trade setups via
-
* 6.3 Write property test: Trade setup selection picks latest matching symbol (Property 6)
- Property 6: Trade setup selection picks latest matching symbol
- Use
fast-checkto generate random lists of trade setups with random symbols and timestamps - Verify selection logic returns the latest setup for the target symbol, or null if no match
- Validates: Requirements 5.1, 5.5
-
-
7. Final checkpoint — Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
Notes
- Tasks marked with
*are optional and can be skipped for faster MVP - Each task references specific requirements for traceability
- Property tests use
hypothesis(Python) andfast-check(TypeScript) with minimum 100 iterations - No new database tables — breakdowns are computed on-the-fly from existing data
- Trade overlay uses the existing
lightweight-chartsrendering pipeline, no new library needed