request.security in local logic still needs a portable expression
Dynamic requests can make Pine scripts more flexible, but the requested expression still runs in another context.
Putting request.security() behind local logic feels natural. A script has a mode, a symbol choice, or a condition, and the request only seems necessary in that branch. Pine’s support for dynamic request behaviour has made many patterns more flexible than they used to be. That flexibility does not remove the main conceptual issue: the requested expression is evaluated in another context.
The reason this matters in real scripts is that request bugs often come from scope confusion. The code compiles, but the author forgets which variables belong to the chart context and which values are being recalculated in the requested context.
Why this catches people
The trap is treating a request inside a branch like an ordinary local calculation. It is not ordinary. The symbol, timeframe, bar sequence, gaps, lookahead, and expression history can all differ from the chart. If the expression depends on mutable local state, arrays, drawings, or assumptions about the current chart’s bar timing, the result may not mean what the author thinks it means.
Older Pine patterns also matter. Scripts migrated across versions may carry assumptions about where requests can appear and when they are evaluated. A modern script may allow more dynamic placement, but the author still needs to design the request expression cleanly.
The Pine bit
I prefer to keep requested expressions as portable as possible. Ask for a value that makes sense in the requested context by itself. Then combine it with local chart logic after the request returns. That keeps the boundary visible.
If a mode switch changes the requested field, I would rather make the switch explicit than bury it inside a complicated expression. That also makes it easier to test each request separately.
mode = input.string("Close", "Requested value", options = ["Close", "Range"])
requested = request.security(
syminfo.tickerid,
"D",
mode == "Close" ? close : high - low)
How I handle it in builds
In larger tools, I centralize requests near the top of the calculation flow. The rest of the script can then consume named series values. That is less clever than scattering requests in every branch, but it makes timing and context easier to audit.
If performance or request limits require conditional structure, I still keep the expression simple and document the context. The comment should explain the timing assumption, not merely say that the request gets daily data.
Where this shows up
A good review is to pull the requested expression into a named helper idea and ask whether it still makes sense if calculated on the other symbol or timeframe. If the answer depends on a chart-local drawing, loop index, or stateful side effect, the expression is probably too tangled for a request.
I watch for request calls hidden inside functions whose names do not reveal that they request data. A function named trendOk() that quietly calls request.security() can be convenient, but it hides cost and context. In a larger script, I prefer names like dailyTrendOk() or getDailyTrend() so the request boundary remains visible to the next person maintaining the code.
I watch request counts and performance. A dynamic request pattern that feels elegant can become expensive if it creates too many unique contexts. Even when the script remains within limits, the code may be harder to reason about. Sometimes a small number of explicit requests is better than a clever branch that changes symbol, timeframe, and expression in one place.
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.
Checks before I trust it
- Keep requested expressions meaningful in the requested context by themselves.
- Combine requested values with chart-local state after the request returns.
- Be cautious with mutable state inside requested expressions.
- Test each mode or branch that changes a request.
- Document lookahead, gaps, and confirmation choices where they affect behaviour.
The thing worth preserving is that local scope does not make a request local in meaning. The context boundary remains, and the script is safer when that boundary stays visible.