A Scorecard Instead of a Band

After five real-data mockups I dropped the prediction band that covered half the screen, split it into a today view and an accuracy view, and shipped with 220 days of retroactive scoring.

The stock price movement observer predicts the day’s expected high and low before the open and compares them against actuals every 5 minutes during the session; it places no orders. The star of the first screen was the prediction band, a strip drawn over the chart for that expected range. The trouble was that the strip runs 15 to 22% wide, so however it was drawn it covered half the chart.

What I set out to do

I’m building a stock price movement observer. An observation-only service that predicts the day’s expected high and low before the open and compares against actuals every 5 minutes during the session. The star of the first screen was the prediction band. A strip drawn over the chart saying “today’s price will stay inside this,” the picture anyone would think of for a service like this.

But every time I opened the chart something felt wrong. The prediction box was far bigger than the candles. When I asked Claude Code, it explained the calculation structure first. The box drawn at each 5-minute candle isn’t a 5-minute prediction; it’s “today’s final high-low range” repeated at every slot, and that range is the p95 of the last 20 days’ intraday ranges, about 19.5% for the main ticker. It said that width was necessary to maintain 85% coverage.

How I asked

Instead of arguing in words, I had it produce mockups from real data. Claude built the mockups as local HTML, all using the identical real quote data and differing only in how they drew it. (1) the current per-slot boxes, (2) a continuous area strip, (3) a compromise with the current prediction line laid over the area. Later came (4) a version with the band fill removed entirely, leaving only boundary lines and KPI numbers, and (5) a version separating today from the past, for five mockups in total.

(2) and (3) were clearly better than (1). But the root was unchanged. A strip 15-22% wide covers half the chart no matter how you draw it.

Where it broke

In the end I couldn’t hold back.

Should I just remove it? I don’t like any of them. The range is so wide that showing it this way doesn’t mean much.

Claude’s answer was memorable. Instead of pushing back, it conceded, citing its own measured numbers. The moment the band width is 15-22%, showing the range as a picture is no longer information; it’s no different from “the price will go up or down.” But the band’s value lies at its edges, not its interior, so it proposed dropping the picture and moving the value into boundary numbers, breakout alerts, and an accuracy history.

Seeing mockup (4) draw the past 3 days of intraday candles as one continuous stretch, I pointed out one more thing.

The low and high are data confined to a specific date. What you should show is how well it hit in the past.

How I fixed it

This is where the structure pivoted. The band picture was scrapped. The screen split in two. The today view holds only the day’s intraday candles, and the expected high/low is handled by boundary lines and KPI numbers (“-7.7% to the low”). The boundary lines enter the screen only when the price approaches them. Forcing them onto the axis squashes the candles and brings back the original problem. The accuracy view is a daily scorecard of prediction vs. actual. Each day is one dotted prediction box and one line for the actual high-low, and days with a breakout get a red mark.

To fill the scorecard I had it score the past retroactively. Each day’s prediction was computed only from data before that day to prevent future leakage, and across 484 rows total, 220 days per major ticker, the overall hit rate came out at 89%. I shipped in this state.

The same day I had it test “would adding volume make it more accurate?” with a sensitivity regression. The results split. The relationship between gap and range was rejected at R² 0.03. Previous-day volume vs. same-day range had a real signal at R² 0.144, so adding volume adaptation left the width nearly unchanged while the hit rate rose from 89% to 92%. During this quantile sweep, though, Claude confessed to one loop bug. It needed to find the lowest quantile that clears the target coverage, but the loop stopped at the first 88% point. And its answer to the fundamental question was honest too. The band is wide not because of a model flaw but because the ticker moves 12-15% a day by nature, and no feature can lower that floor.

Lessons