From a09eba4d4277754574684e7602a2f8927d391bc0 Mon Sep 17 00:00:00 2001 From: Investor Flow Build Date: Tue, 30 Jun 2026 09:28:11 -0400 Subject: [PATCH] fix-chartlab-findings (ornith-35): real OHLC candlesticks (CandleShape), remove dead CandleBar, rsiCaption figcaption, relvol domain Re-review by qwopus35b pending. SPA lint 2/2 green. --- app/src/components/ChartLabPanel.tsx | 56 ++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/app/src/components/ChartLabPanel.tsx b/app/src/components/ChartLabPanel.tsx index 9c1090b..caf9437 100644 --- a/app/src/components/ChartLabPanel.tsx +++ b/app/src/components/ChartLabPanel.tsx @@ -8,6 +8,7 @@ import { BarChart, CartesianGrid, Cell, + Defs, Legend, Line, LineChart, @@ -157,14 +158,40 @@ export function ChartLabPanel() { const upColor = DAY_COLORS.up; const downColor = DAY_COLORS.down; - // Build a custom bar fill that respects up/down. - const CandleBar = (props: any) => { + // Custom shape for OHLC candlestick rendering: wick (high→low line) + body (open↔close rectangle). + const CandleShape = (props: any) => { const { x, y, width, height, payload } = props; - const fill = payload.c >= payload.o ? upColor : downColor; + if (!payload) return null; + const isUp = payload.c >= payload.o; + const fill = isUp ? upColor : downColor; + const bodyTop = Math.min(payload.o, payload.c); + const bodyBottom = Math.max(payload.o, payload.c); + const bodyHeight = Math.max(bodyBottom - bodyTop, 1); // minimum 1px body + const wickTop = payload.h; + const wickBottom = payload.l; + return ( - - - + + {/* Wick: vertical line from high to low */} + + {/* Body: rectangle from open to close */} + + ); }; @@ -178,14 +205,14 @@ export function ChartLabPanel() {

{UI_STRINGS.priceChartCaption}

- + `Date: ${label}`} formatter={(value: any, name: string) => { - if (name === "close") return [`$${value?.toFixed(2)}`, UI_STRINGS.priceLabel]; + if (name === "candle") return [`$${value?.toFixed(2)}`, UI_STRINGS.priceLabel]; if (name.startsWith("ema")) { const period = name.replace("ema", ""); return [`$${value?.toFixed(2)}`, `${UI_STRINGS[`ema${period}Label` as keyof typeof UI_STRINGS] ?? `EMA ${period}`}`]; @@ -201,6 +228,12 @@ export function ChartLabPanel() { return `${UI_STRINGS[`ema${period}Label` as keyof typeof UI_STRINGS] ?? `EMA ${period}`}`; }} /> + } + name="candle" + opacity={0.85} + /> {Object.entries(EMA_COLORS).map(([period, color]) => ( ))} - +
@@ -280,7 +314,7 @@ export function ChartLabPanel() {
- {UI_STRINGS.rsiTooltip} + {UI_STRINGS.rsiCaption}
@@ -294,7 +328,7 @@ export function ChartLabPanel() { - + { const label = value > 1 ? "above typical" : value < 1 ? "below typical" : "at typical";