Appearance
Other symbols and timeframes
How do you read another symbol or timeframe, such as the daily close on an hourly chart, without looking ahead? Call request.security with the symbol, the timeframe and what to read there. Each value shows on the first chart bar that closes at or after the value became known, so history never sees a day before the day is over.
pine
//@version=6
indicator("Daily close on an hourly chart", overlay = true)
// Each day's close, from the day's last hour on
float dayClose = request.security(syminfo.tickerid, "1D", close)
// the last finished day, from each new day's first hour
float prevDay = request.security(syminfo.tickerid, "1D", close[1],
lookahead = barmerge.lookahead_on)
plot(dayClose, "Day's close", color.gray, style = plot.style_stepline)
plot(prevDay, "Previous day's close", color.orange,
style = plot.style_stepline)The two lines are the same values a bar apart in time. The first shows each day's close as soon as the day ends, and moves on the live bar while today forms. The second shows yesterday's close for the whole of today, which never moves.
Writing a symbol
syminfo.tickerid is the chart's own symbol. Any other is a string, written the way this terminal names it:
| Market | Write it as |
|---|---|
| A coin in US dollars | "BTC-USD", "ETH-USD" |
| A pair on one exchange | "binance:BTC/USDT", "coinbase:ETH/USD": the exchange, a colon, the pair with a slash |
| A coin wherever its history goes back furthest | "crypto:BTC" |
| TradingView's crypto indexes | "INDEX:BTCUSD", "INDEX:ETHUSD", "CRYPTO:SOLUSD" and a few more |
| A share or a fund | "AAPL", "SPY", with no exchange in front |
| A currency pair | "EUR/USD" |
TradingView's spelling of an exchange pair, such as "BINANCE:BTCUSDT", reaches the same pair. Its spelling of a share, such as "NASDAQ:AAPL", reads nothing: write "AAPL". A symbol that reads nothing gives na and a warning (see no data).
When a value shows
A value from the other series is known once its bar closes. The close comes from that symbol's calendar and its exchange's session, or, for a series with release dates such as an economic one, from its release time. The value then shows on the first chart bar that closes at or after that moment, and stays until the next value shows.
| Chart | Request | Each value shows |
|---|---|---|
| Hourly | The same symbol, "1D" | On the day's last hourly bar |
| A coin, daily | "1W" | On Sunday, the week's last daily bar |
| A share, daily | "1W", "1M" | On Friday, and on the month's last session |
| A share, daily | Another share, "1D" | On the same day's bar |
| A share, daily | A coin, "1D" | The coin's previous day: a coin's day ends at midnight UTC, after the share's close |
| A coin, daily | A share, "1D" | That day's session, held over the weekend |
| A share, hourly | Another share, "1D" | On the hour that ends at the closing bell |
A holiday or an early close moves the close, as the schedule says.
Looking ahead
lookahead = barmerge.lookahead_off, the default, gives the rule above. barmerge.lookahead_on shows a higher timeframe's bar from the first chart bar of its period, with the value it ends on.
A backtest that reads the future
On history, lookahead_on without an offset hands each bar a value no one had yet, so a strategy on it looks better than anything could trade. The script warns: "ETH-USD" at 1D: lookahead_on without an offset like close[1] shows future values on historical bars.
With an offset, close[1], the same call reads the last finished period from the first bar of the next one. That's the idiom in the example at the top, and it reads the same on history and on the live bar.
On a lower timeframe, lookahead_on reads the first intrabar of the chart bar instead of the last. A series with release dates never looks ahead, whatever lookahead says.
AmenoScript runs leak-safe, so it refuses lookahead_on with or without an offset. Write the request without it, as request.security(syminfo.tickerid, "1D", close): in AmenoScript that already reads the last day closed by this bar's close. See Leak-safe AmenoScript.
Gaps
gaps = barmerge.gaps_off, the default, holds the last value on every chart bar until the next one arrives. barmerge.gaps_on gives na on every bar but the one where a new value arrives, which suits a value you count or mark once. With lookahead_on as well, it gives the first chart bar of each period only.
The forming bar and repainting
Closed bars keep confirmed values. A chart bar that is still forming reads the other series' forming bar, so on the live bar request.security(sym, "1D", close) shows today's close so far, and the value moves with each tick. When the chart bar closes, it keeps the value known at its close, which can differ from what the live bar showed. That is repainting: a value the script showed live isn't the one history keeps. It happens on the forming bar and nowhere else.
barstate.isconfirmed is false on a forming bar, in the chart and inside the request. To show only values that won't change, read them through the close[1] and lookahead_on idiom, or act only when barstate.isconfirmed is true.
What the expression can be
The third argument can be any expression: a ta.* call, close[1], an input, a user function or a tuple. It runs on the other series' own bars, so a ta.sma(close, 20) there averages 20 of that series' bars.
pine
//@version=6
indicator("Another symbol's bar and average")
// A tuple reads several values in one request
[o, c, avg] = request.security("ETH-USD", "1D",
[open, close, ta.sma(close, 20)])
plot(c - o, "Body", style = plot.style_columns)
plot(c - avg, "Close less its 20-day average")On the other series the engine runs only what the expression needs, from the lines above the call. A name the expression reads holds what those lines wrote to it, and nothing a line below the call writes. A request inside an if still runs its expression on every bar of the other series, so its windows fill as if the request were outside. Plots, drawings, alerts and strategy calls inside the expression do nothing.
The symbol and the timeframe can be expressions too, and a request can sit in a loop. On a chart, a run that asks for a series it doesn't have reads na for it and names it; the chart fetches it and runs the script again. A request inside another request's expression reads relative to the outer request's symbol and timeframe.
Every intrabar
request.security on a lower timeframe gives one value per chart bar: the last intrabar's, or the first's with lookahead_on. To read them all, request.security_lower_tf returns an array of every intrabar inside the chart bar, oldest first, and an empty array when there is none. A timeframe above the chart's stops the script, unless ignore_invalid_timeframe = true, which reads na instead.
When there's no data
A request with no data reads na, never the chart's own value, and says so in a warning such as "SPY" at 1D: no data loaded, so this request reads na. ignore_invalid_symbol = true keeps it quiet. TradingView stops a script on an invalid symbol, where ours reads na, since a symbol the terminal couldn't fetch isn't an error in the script.
currency converts nothing here: the values stay in the symbol's own currency, with a warning. request.currency_rate reads na here, with a warning.
Other requests
request.dividends, request.splits, request.earnings, request.economic and request.financial read the company and economic data the terminal stores, each as a daily series dated when it was published: see Facts and data packs. AmenoScript adds reads of its own: a whole list of symbols in one call (each and pairs), a daily market-cap ranking (universe), and how old and how complete a series' latest value is (known time).
Traps
lookahead_onwithout an offset shows each period's final value from its first bar.- The live bar repaints:
request.security(sym, "1D", close)moves with today's ticks and settles at the close. - A write to a name below the call never reaches the request, so a
varcounter incremented after the call reads one behind inside it. - A share's daily bar and a coin's daily bar end at different moments, so one reads the other a day apart in one direction and not in the other.
ta.*inside the expression runs on the other series' bars, not the chart's.
See also
- The request reference, every argument
- Time and sessions, for when each bar closes
- Leak-safe AmenoScript, for what a leak-safe run refuses and why