slice 5c ChartLab panel (ornith-35): candlestick/volume/EMA/RSI/relvol + P7 tooltips, trpc.market.candles+indicators wiring

Cross-review by qwopus35b pending. SPA lint 2/2 green.
This commit is contained in:
Investor Flow Build
2026-06-30 08:46:47 -04:00
parent 2c7e7a0786
commit ce26a0ca15
4 changed files with 367 additions and 1 deletions
+26
View File
@@ -42,6 +42,32 @@ export const UI_STRINGS = {
drawdownNote: "A default max-drawdown tolerance is set from your experience level (you can change it later).",
completeOnboardingButton: "Finish setup",
onboardingDone: "Setup complete — your starter watchlist is tracking.",
onboardingDone: "Setup complete — your starter watchlist is tracking.",
// Chart Lab (Slice 5c)
chartLabTitle: "Chart Lab — price, volume, and indicator overlays",
priceChartCaption:
"Daily price range (bar) with closing-price line — visual context, not a signal.",
volumeLabel: "Volume",
volumeCaption:
"Number of shares traded per day — relative size, not a directional cue.",
rsiLabel: "Relative Strength Index (RSI)",
rsiCaption:
"Momentum oscillator comparing gain and loss magnitude over a rolling window.",
rsiTooltip:
"RSI reads the speed and change of price movements; values near extremes can mark overextended stretches, but do not imply a direction.",
emaTooltip:
"Average price over the last N days — a smoothing filter that tracks the prevailing trend direction.",
ema9Label: "EMA 9",
ema21Label: "EMA 21",
ema50Label: "EMA 50",
ema200Label: "EMA 200",
relvolLabel: "Relative Volume",
relvolCaption:
"Today's volume compared to the rolling average — above typical or below typical.",
relvolTooltip:
"Relative volume shows whether trading activity is above or below the recent average; it does not predict direction.",
noCandleData: "No candle data available for this symbol/timeframe.",
} as const;
export const UI_STRING_LIST: string[] = Object.values(UI_STRINGS);
+18 -1
View File
@@ -67,8 +67,25 @@ export type Complexity = "beginner" | "intermediate" | "advanced";
export interface StarterEntry { symbol: string; tickerKind: string; reason: string; }
export interface PortfolioEntry { symbol: string; qty: number; avgCost: number; acquiredAt: string; }
export interface IndicatorOptions {
ema?: number[];
rsi?: { period?: number };
relvol?: { period?: number };
}
export interface IndicatorResult {
ema?: Record<number, Array<{ ts: string; value: number }>>;
rsi?: Array<{ ts: string; value: number }>;
relvol?: Array<{ ts: string; value: number }>;
}
export const api = {
market: { snapshot: (symbol: string) => trpcQuery<Snapshot>("market.snapshot", { symbol }) },
market: {
snapshot: (symbol: string) => trpcQuery<Snapshot>("market.snapshot", { symbol }),
candles: (symbol: string, timeframe = "1d") =>
trpcQuery<PriceCandle[]>("market.candles", { symbol, timeframe }),
indicators: (symbol: string, opts: IndicatorOptions) =>
trpcQuery<IndicatorResult>("market.indicators", { symbol, ...opts }),
},
auth: {
signup: (email: string, password: string) => trpcMutate<{ userId: string }>("auth.signup", { email, password }),
login: (email: string, password: string, totp?: string) => trpcMutate<{ userId: string }>("auth.login", { email, password, ...(totp ? { totp } : {}) }),