request.security_lower_tf returns arrays, not a smaller normal series
Lower-timeframe requests in Pine are powerful, but their array results need different handling from ordinary series values.
request.security_lower_tf() is one of the more interesting additions to Pine because it gives a chart bar access to lower-timeframe values inside that bar. That opens useful doors: intrabar volume analysis, directional counts, lower-timeframe confirmation, and more realistic inspection of what happened inside a larger candle.
It keeps coming up because the function is easy to misunderstand. It does not simply turn the chart into a lower-timeframe series. It returns arrays of values for each chart bar. That means the script has to think in collections per bar, not one value per bar.
Why this catches people
The pattern that causes trouble is expecting the result to behave like request.security(). A normal higher-timeframe or same-timeframe request returns a series value aligned to chart bars. A lower-timeframe request can return multiple values for one chart bar, so Pine gives you an array. If the chart bar contains no lower-timeframe bars, the array can be empty. If it contains many, the array can be large.
This changes everything about guard logic. You cannot read the first value until you know the array has a first value. You cannot assume every chart bar has the same number of intrabars. You cannot treat the array’s last element as confirmed without understanding the realtime state.
The Pine bit
The useful pattern is to immediately summarize the array into the thing the chart-level logic needs. Count up-volume intrabars, sum volume, find the max range, check whether any lower-timeframe close crossed a level. Once that summary is produced, the rest of the script can work with a normal chart-level series.
Tuple returns make this even more useful. A request can return arrays for volume and direction at the same time, for example. The script can then loop through matching elements and build a bar-level summary.
//@version=6
indicator("Lower timeframe array summary", overlay = true)
ltf = input.timeframe("1", "Lower timeframe")
[volumes, directions] = request.security_lower_tf(
syminfo.tickerid,
ltf,
[volume, math.sign(close - open)])
float upVolume = 0.0
for i = 0 to array.size(volumes) - 1
if array.get(directions, i) > 0
upVolume += array.get(volumes, i)
Why it can survive a quick review
This can slip through review because array results can look deceptively simple in examples. The example works on a liquid symbol and an ordinary timeframe, so the author assumes every bar will behave like that. Then the script moves to a thin market, a session boundary, a custom chart, or realtime execution, and the number of lower-timeframe bars changes.
Realtime is the other trap. The current chart bar may still be collecting lower-timeframe data. A summary built from the current array can be useful, but it should not be presented as final until the chart bar is confirmed.
How I handle it in builds
In practical tools, I summarize lower-timeframe arrays close to the request and then pass only the summary forward. I decide what an empty array means. Sometimes it means no confirmation. Sometimes it means skip the bar. Sometimes it means the requested lower timeframe is not appropriate for the chart.
For dashboards, I mark lower-timeframe confirmations differently when the chart bar is live. A lower-timeframe count on a forming bar is not the same as a completed count on a historical bar.
Where this shows up
The best lower-timeframe array scripts have a clear aggregation rule. “Any intrabar crossed the level” is different from “most intrabars closed above the level” and different again from “the last intrabar confirmed the level.” Those rules can produce very different signals from the same array.
I like to store diagnostic counts while developing: number of intrabars, up count, down count, total volume, and whether the chart bar is confirmed. When a user reports a strange signal, those counts can explain whether the lower-timeframe data was thin, incomplete, or genuinely supportive.
This is one of the places where Pine can become very expressive without becoming vague. The array is raw material. The aggregation rule is the indicator.
I treat lower-timeframe arrays as a data-quality question. On a liquid symbol, a fifteen-minute bar requested down to one-minute data may usually contain fifteen elements. On thin symbols, session breaks, or unusual chart types, that assumption can fail. The script should not collapse just because the ideal intrabar sample is missing.
If the lower-timeframe aggregation drives alerts, I prefer to include the intrabar count in debug output. It tells me whether a signal came from a full sample or a partial one. That is important when comparing live behaviour with a historical screenshot.
How I test it
I test multi-timeframe logic at timeframe boundaries. The first lower-timeframe bars after a new higher-timeframe period are where timing mistakes show up. If the script is honest there, it is usually honest in the easier middle of the period.
When multi-timeframe logic is central, I compare confirmed and developing versions side by side. The disagreement is not noise. It is the useful part of the test because it shows where the script’s knowledge changes from provisional to final.
I decide whether the aggregation should use all intrabars or only confirmed lower-timeframe bars. On the live chart, the last lower-timeframe element may still be forming. If that element can change the signal, the chart should treat the result as developing until the parent bar confirms.
When the array is used for volume, I check whether missing intrabars should mean zero participation or unknown participation. Those are very different trading interpretations.
I prefer unknown until the script can prove otherwise. It is safer for alerts and easier to explain later.
Especially live.
Checks before I trust it
- Treat the result as an array per chart bar, not as a normal series.
- Guard loops and reads with
array.size(). - Summarize arrays into chart-level values before using them broadly.
- Define what an empty lower-timeframe array means.
- Separate live lower-timeframe summaries from confirmed summaries.
What matters here is that lower-timeframe data arrives as structure, not magic. Once the script respects the arrays, the function becomes powerful without becoming mysterious.