Why do my thinkorswim scan results differ from what I see on the chart?
Updated August 27, 2026
Short answer
The scan and the chart share the same market data and almost nothing else. Aggregation period, extended-hours session, price type and bar start time are configured separately in each place, so the same script can be looking at genuinely different bars. On top of that the chart updates tick by tick while the scanner re-runs on the server's schedule, and both are evaluating a bar that is still forming and can change before it closes.
Start here: they don’t share settings
The instinct is that a scan is “the chart, run across every symbol”. It isn’t. The chart is a workspace on your machine with its own configuration, and the scan is a query the server runs with its own separate configuration. What they share is the market data underneath. Everything that turns that data into bars is set twice, once in each place, and nobody keeps them in sync for you.
So when a script disagrees with itself, the question is never “is the script broken”. It’s “are these two things looking at the same bar”. Usually they aren’t.
What counts as “the last bar”
Both the chart and the scan evaluate the most recent bar in whatever series they’re given. That sounds like agreement. It isn’t, because “the most recent bar” depends on four things that are configured independently:
- the aggregation period
- whether the extended-hours session is included
- where the bar is allowed to start
- when the data was last refreshed
Change any one of those and “the last bar” is a different chunk of time. Same tape, different bar, different answer.
Aggregation is set per study filter, not per scan
Every study filter row in the Stock Hacker has its own Aggregation Period button. It does not read your chart. Build a setup on a daily chart, drop it into a scan, and the filter sits on whatever period it defaulted to. You will get results, they’ll just be answering a different question.
This is also why you can’t reference a second timeframe inside one filter. The scanner locks its aggregation before evaluating anything, so a script asking for daily data while running on hourly gets refused. That’s the secondary aggregation error.
Extended hours moves the boundaries, not just the data
This is the part that’s genuinely counterintuitive, and it’s the biggest source of “my 60 minute scan is off by an hour”.
Turning the extended-hours session on doesn’t only add premarket and after-hours bars to the end of the series. It changes where every intraday bar starts. On the chart, Chart Settings > Equities has three related checkboxes: Show Extended-Hours Trading session, Highlight Extended-Hours Trading session, and Start aggregations at market open. That last one forces the first bar of the day to begin at 9:30 rather than at some multiple of the aggregation counted from the session start.
thinkorswim’s own scan documentation says the Start aggregations at market open setting is disabled when the Extended-Hours Trading session is off. So if your scan filter has EXT unchecked, the scan is behaving as if that chart option were off, whether or not it’s ticked on your chart.
The result on a 60 minute series: your chart has bars at 9:30, 10:30, 11:30. The scan has bars at 9:00, 10:00, 11:00. A close-versus-high comparison on those is comparing two different sixty minute windows. Nothing is wrong with either one. They’re just not the same bars.
Match the EXT checkbox in the scan to the extended-hours checkbox on the chart and this usually resolves in one step.
The forming bar
In thinkScript, close with no offset means the current bar, and the current bar is still being built. On a daily aggregation at 11am, close is just the last trade. A study that goes true at 11am can go false by 3pm because the bar it’s measuring hasn’t finished.
That’s not repainting in the sinister sense, but it produces the same experience. A scan hit that isn’t there when you open the chart an hour later. A chart signal that was on your screen at lunch and gone by the close.
If you want the answer to stop moving, evaluate the completed bar instead: close[1] > open[1] rather than close > open. Same for every reference in the script. The trade-off is that you find out one bar late. The difference between offsetting and using within is worth understanding properly, and there’s a page on it.
The scanner’s clock is behind yours
Your chart updates on the tick. The scan runs when you click Scan, and then the server re-runs it when it gets to it. Traders on useThinkScript put that at roughly three to seven minutes, longer under load, and it’s queued rather than scheduled, so it isn’t consistent.
On daily setups this doesn’t matter at all. On a 1 minute scan it means the results panel is describing a market that has already moved on. If you find yourself opening a scan hit and seeing nothing, check the timestamp on the last bar before you blame the logic.
Two smaller ones worth ruling out
Your chart’s Price type on the Equities settings tab can be Last, Ask, Bid or Mark. If yours is on Mark, your chart is drawing something the scan almost certainly isn’t. Set it back to Last while you’re comparing.
And the scan’s universe is the other half of it. A symbol you’re staring at on the chart may simply not be in whatever Scan in is pointed at. That’s the first thing on the empty scan checklist for a reason.
How to settle it in about a minute
Don’t reason about it. Make both sides show you their working.
Take the exact code from your custom scan filter, paste it onto the chart as a study, and add a label:
AddLabel(yes, "scan = " + scan + " bars: " + BarNumber(), Color.YELLOW);
Now set the chart’s aggregation to match the filter’s aggregation period exactly, and match the extended-hours checkboxes. If the label goes true on the bar you expected, your logic is fine and the disagreement was configuration. If it doesn’t, you’ve got somewhere to debug where you can actually see the values, which the scanner will never give you.
The habit that saves the most time: before changing a single line of a scan, write down the filter’s aggregation period and EXT state, then go set the chart to match. About four times out of five the disagreement disappears and there was never anything wrong with the script.