feat: company names for tickers (Alpaca backfill + subtle display)
Store an optional company name on Ticker (migration 014) and backfill it from Alpaca's asset list in a single Trading-API call for the whole universe — no per-ticker fetch. Runs automatically at the end of universe bootstrap and via a manual "Backfill Names" button (admin) / POST /admin/tickers/backfill-names. The name ships on /tickers; a shared symbol→name map (useTickerNames) lets any view show it without its own request. Displayed subtly next to the symbol — in the global search, the ticker header, and as a small muted line under the symbol in Top Setups and Open Trades (no extra column, truncated so it never widens the table). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
useBackfillTickerNames,
|
||||
useBootstrapTickers,
|
||||
useTickerUniverseSetting,
|
||||
useUpdateTickerUniverseSetting,
|
||||
@@ -17,6 +18,7 @@ export function TickerUniverseBootstrap() {
|
||||
const { data, isLoading, isError, error } = useTickerUniverseSetting();
|
||||
const updateDefault = useUpdateTickerUniverseSetting();
|
||||
const bootstrap = useBootstrapTickers();
|
||||
const backfillNames = useBackfillTickerNames();
|
||||
|
||||
const [universe, setUniverse] = useState<TickerUniverse>('sp500');
|
||||
const [pruneMissing, setPruneMissing] = useState(false);
|
||||
@@ -85,6 +87,14 @@ export function TickerUniverseBootstrap() {
|
||||
>
|
||||
{bootstrap.isPending ? 'Bootstrapping…' : 'Bootstrap Now'}
|
||||
</button>
|
||||
<button
|
||||
className="px-4 py-2 text-sm rounded border border-white/[0.1] text-gray-300 hover:text-white disabled:opacity-50"
|
||||
onClick={() => backfillNames.mutate()}
|
||||
disabled={backfillNames.isPending}
|
||||
title="Fill in company names from Alpaca (one request for all tickers)"
|
||||
>
|
||||
{backfillNames.isPending ? 'Backfilling…' : 'Backfill Names'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { usePaperTrades, useClosePaperTrade, useExitPolicy } from '../../hooks/usePaperTrades';
|
||||
import { useTickerNames } from '../../hooks/useTickers';
|
||||
import { tradePnl } from '../../lib/paperTrade';
|
||||
import { formatPrice } from '../../lib/format';
|
||||
import { Section } from '../ui/Section';
|
||||
@@ -19,6 +20,7 @@ function pnlColor(v: number): string {
|
||||
export function OpenTradesPanel() {
|
||||
const { data: trades, isLoading } = usePaperTrades('open');
|
||||
const { data: policy } = useExitPolicy();
|
||||
const tickerNames = useTickerNames();
|
||||
const close = useClosePaperTrade();
|
||||
|
||||
const exitLabel = policy
|
||||
@@ -84,6 +86,11 @@ export function OpenTradesPanel() {
|
||||
<Link to={`/ticker/${t.symbol}`} className="font-medium text-blue-300 hover:text-blue-200">
|
||||
{t.symbol}
|
||||
</Link>
|
||||
{tickerNames.get(t.symbol.toUpperCase()) && (
|
||||
<div className="max-w-[150px] truncate text-[11px] text-gray-500">
|
||||
{tickerNames.get(t.symbol.toUpperCase())}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className={`num text-[10px] font-semibold uppercase ${t.direction === 'long' ? 'text-emerald-400' : 'text-red-400'}`}>
|
||||
|
||||
@@ -81,11 +81,12 @@ export default function TickerSearch({ onNavigate }: { onNavigate?: () => void }
|
||||
type="button"
|
||||
onMouseEnter={() => setActive(i)}
|
||||
onClick={() => go(t.symbol)}
|
||||
className={`flex w-full items-center px-3 py-1.5 text-left text-sm transition-colors ${
|
||||
className={`flex w-full items-baseline gap-2 px-3 py-1.5 text-left text-sm transition-colors ${
|
||||
i === active ? 'bg-blue-400/[0.12] text-blue-200' : 'text-gray-300 hover:bg-white/[0.04]'
|
||||
}`}
|
||||
>
|
||||
{t.symbol}
|
||||
<span className="font-medium">{t.symbol}</span>
|
||||
{t.name && <span className="truncate text-xs text-gray-500">{t.name}</span>}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user