feat: overlay stock price on trend charts with right Y axis

- New GET /api/market/prices/{ticker} endpoint serving OHLCV data from
  market_snapshots, deduped by bar_timestamp
- New useMarketPrices hook in frontend
- Trend chart now shows price (purple line) on a right Y axis ($)
  alongside trend metrics (%) on the left Y axis
- Custom tooltip formats price as dollars, metrics as percentages
- Price line uses connectNulls for days with missing bar data
This commit is contained in:
Celes Renata
2026-04-17 01:09:36 +00:00
parent ebe0ccca4c
commit c4206b3f4c
3 changed files with 133 additions and 15 deletions
+50
View File
@@ -465,6 +465,56 @@ async def list_trend_history(
return results
@app.get("/api/market/prices/{ticker}")
async def get_market_prices(
ticker: str,
limit: int = Query(default=30, le=200),
):
"""Return historical close prices for a ticker from market_snapshots.
Each row has a bar_date (from the Polygon bar timestamp) and OHLCV data.
Ordered oldest-first for chart rendering.
"""
ticker = ticker.upper()
rows = await pool.fetch(
"""SELECT
captured_at,
(data->>'c')::float AS close,
(data->>'o')::float AS open,
(data->>'h')::float AS high,
(data->>'l')::float AS low,
(data->>'v')::float AS volume,
(data->>'t')::bigint AS bar_timestamp
FROM market_snapshots
WHERE ticker = $1 AND snapshot_type = 'bar'
ORDER BY captured_at ASC
LIMIT $2""",
ticker, limit,
)
results = []
seen_dates: set[str] = set()
for r in rows:
# Deduplicate by bar_timestamp (same day bar captured multiple times)
bar_ts = r["bar_timestamp"]
if bar_ts is None:
continue
date_key = str(bar_ts)
if date_key in seen_dates:
continue
seen_dates.add(date_key)
results.append({
"ticker": ticker,
"close": r["close"],
"open": r["open"],
"high": r["high"],
"low": r["low"],
"volume": r["volume"],
"bar_timestamp": bar_ts,
"captured_at": r["captured_at"].isoformat() if r["captured_at"] else None,
})
return results
@app.get("/api/trends/{trend_id}")
async def get_trend(trend_id: str):
"""Get a single trend summary by ID."""