feat(stocks): add analyst consensus + price targets to stock analysis panel (#2926)

* feat(stocks): add analyst consensus + price targets to stock analysis panel

Shows recommendation trend (strongBuy/buy/hold/sell), price target range
(high/low/median vs current), and recent upgrade/downgrade actions with
firm names. Data from Yahoo Finance quoteSummary.

* chore: regenerate proto types and OpenAPI docs

* fix(stocks): fallback median to mean + use stock currency for price targets

* fix(stocks): drop fake $0 price targets and force refetch for pre-rollout snapshots

- Make PriceTarget high/low/mean/median/current optional in proto so partial
  Yahoo financialData payloads stop materializing as $0.00 cells in the panel.
- fetchYahooAnalystData now passes undefined (via optionalPositive) when a
  field is missing or non-positive, instead of coercing to 0.
- StockAnalysisPanel.renderPriceTarget skips Low/High cells entirely when the
  upstream value is missing and falls back to a Median + Analysts view.
- Add field-presence freshness check in stock-analysis-history: snapshots
  written before the analyst-revisions rollout (no analystConsensus and no
  priceTarget) are now classified as stale even when their generatedAt is
  inside the freshness window, so the data loader forces a live refetch.
- Tests cover undefined targets path, missing financialData path, and the
  three field-presence freshness branches.

* fix(stocks): preserve fresh snapshots on partial refetch + accept median-only targets

- loadStockAnalysis now merges still-fresh cached symbols with refetched
  live results so a partial refetch does not shrink the rendered watchlist
- renderAnalystConsensus accepts median-only price targets (not just mean)
This commit is contained in:
Elie Habib
2026-04-11 14:26:36 +04:00
committed by GitHub
parent 2ca4b7e60e
commit 889fa62849
12 changed files with 668 additions and 18 deletions

View File

@@ -1224,6 +1224,14 @@ components:
format: double
engineVersion:
type: string
analystConsensus:
$ref: '#/components/schemas/AnalystConsensus'
priceTarget:
$ref: '#/components/schemas/PriceTarget'
recentUpgrades:
type: array
items:
$ref: '#/components/schemas/UpgradeDowngrade'
StockAnalysisHeadline:
type: object
properties:
@@ -1237,6 +1245,65 @@ components:
type: integer
format: int64
description: 'Warning: Values > 2^53 may lose precision in JavaScript'
AnalystConsensus:
type: object
properties:
strongBuy:
type: integer
format: int32
buy:
type: integer
format: int32
hold:
type: integer
format: int32
sell:
type: integer
format: int32
strongSell:
type: integer
format: int32
total:
type: integer
format: int32
period:
type: string
PriceTarget:
type: object
properties:
high:
type: number
format: double
low:
type: number
format: double
mean:
type: number
format: double
median:
type: number
format: double
current:
type: number
format: double
numberOfAnalysts:
type: integer
format: int32
UpgradeDowngrade:
type: object
properties:
firm:
type: string
toGrade:
type: string
fromGrade:
type: string
action:
type: string
epochGradeDate:
type: integer
format: int64
description: 'Warning: Values > 2^53 may lose precision in JavaScript'
GetStockAnalysisHistoryRequest:
type: object
properties: