What does 'secondary aggregation period is not allowed' mean in thinkorswim?
Updated August 27, 2026
Short answer
Two separate rules produce that family of errors. On a chart, a secondary aggregation period can never be smaller than the chart's own aggregation, so a daily reference on a weekly chart is fine and a 5 minute reference on a daily chart is not. In scans and custom watchlist columns, secondary aggregation is banned outright: thinkorswim's own Stock Hacker documentation states "Secondary aggregation is not allowed". That single rule is why most multi-timeframe scripts copied from forums fail the moment you paste them into a scan.
The rule, in one line
thinkScript will let you look at a bigger timeframe than the one you’re standing on. It will not let you look at a smaller one.
That’s it. Everything else is a consequence of it.
What the error actually looks like
There isn’t one string, which is part of why searching for it is frustrating. Depending on where you triggered it and which build you’re on, people report seeing:
secondary aggregation period is not allowedSecondary period not allowed: Daysecondary aggregations not allowedSecondary period cannot be less than primary
They’re all the same underlying refusal. The first three usually mean “you’re in a context where second timeframes are banned”. The last one means “you’re on a chart and you asked downward”.
On a chart: you can only look up
Schwab’s own thinkScript tutorial puts it plainly. The secondary aggregation period cannot be less than the primary aggregation period defined by chart settings.
So this works on a daily chart:
plot WeeklyHigh = high(period = AggregationPeriod.WEEK);
And this doesn’t:
# on a DAILY chart, asking for 5 minute data. Refused.
plot FiveMinClose = close(period = AggregationPeriod.FIVE_MIN);
The direction confuses people because “secondary” sounds like “smaller”. It doesn’t mean smaller. It means the other one, and the other one has to be equal or larger.
This is also why a script that runs perfectly on your 5 minute chart explodes when you flip to daily to check something. Nothing changed in the code. The floor moved up.
There’s a second restriction in the same tutorial that trips up multi-timeframe scripts: two different secondary aggregation periods cannot be used within a single variable. So this fails:
plot Data = close(period = AggregationPeriod.MONTH) +
close(period = AggregationPeriod.WEEK);
And the fix is just to give each one its own line:
def a = close(period = AggregationPeriod.MONTH);
def b = close(period = AggregationPeriod.WEEK);
plot Data = a + b;
Same maths, two variables, compiles. It looks like a pointless rule and it probably is, but it’s cheap to comply with.
In a scan: banned, full stop
This is the one that makes most forum scripts fail, and it isn’t a bug or a limit you can work around by being clever.
thinkorswim’s Stock Hacker documentation lists the restrictions on custom study filters, and the first one is: Secondary aggregation is not allowed.
The reason is structural. In a scan you choose the aggregation period before the filter runs, using the Aggregation Period button on the filter row itself. The scanner locks that in, then evaluates your code against it. If your code then asks for a different period, there’s nowhere for that request to go, and you get refused regardless of whether the period you asked for is bigger or smaller than the one you picked.
Two other restrictions live on the same page and cause the same confusion. A scan filter script must have exactly one plot. And for forex, only price type last can be used.
In watchlist columns: same story
Custom watchlist columns behave like scans here. A column set to Day that references close(period = "MONTH") comes back NaN or errors rather than working. Long-time answers on useThinkScript and Hahn-Tech both say secondary aggregation isn’t supported in custom columns, and I’ve found nobody claiming otherwise.
Also worth knowing: chart-only functions come along for the ride when you paste a study into a column and they cause their own failures. HighestAll() is the classic. It’s a chart function, it doesn’t belong in a column or a filter, and its presence can be what actually triggers the complaint even when you thought the aggregation was fine.
Three fixes, in the order to try them
Change the chart’s timeframe. Boring but often correct. If the script wants daily data, put it on a daily-or-smaller chart. Half the “secondary period cannot be less than primary” reports are somebody who flipped to a weekly chart to look at something and forgot the study was still loaded.
Use the scanner’s per-filter aggregation instead of asking for it in code. This is the big one and it’s genuinely elegant once it clicks. A scan is allowed to have several filters, and each filter carries its own aggregation period. So a setup that needs “daily hammer, above the monthly support level” doesn’t get written as one multi-timeframe script. It gets written as two filters:
- Add filter, Study, custom code for the hammer, aggregation set to Day
- Add filter, Study, custom code for the monthly level test, aggregation set to Month
The scanner ANDs them together. You’ve expressed a two-timeframe condition without a single secondary aggregation call. Strip every period = reference out of both scripts while you’re doing it.
Match the EXT checkbox on each filter to whatever your chart is doing, too, because intraday filters have their own extended-hours flag and it will change which bars you’re testing.
Restructure so the higher timeframe is the secondary one. If you truly need both timeframes in one script on a chart, put the chart on the faster one and reference the slower one upward. A 5 minute chart can ask for hourly. An hourly chart cannot ask for 5 minute. Write the script to be run from below.
When none of that works
Sometimes the thing you want genuinely can’t be a scan. A condition that needs a smaller timeframe than the one you’re filtering on has no legal form in the Stock Hacker, and no amount of rewriting changes that.
The two-step version works: run a cheap scan on the timeframe you’re allowed to use, save the results as a watchlist, then put the expensive multi-timeframe study on a chart against those forty symbols. It’s clunky. It also runs.
And if the script compiles but the scan comes back with nothing at all, that’s a separate problem entirely, covered in why thinkorswim scans return no results. If it compiles and returns results that disagree with what you see on the chart, that’s usually aggregation and session mismatch between the two, which is the same family of confusion wearing a different hat.