Other data and timeframes
What kinds of data can I get from a higher timeframe?
Generally speaking, the request.security() function can get the same kinds of data from another timeframe that is available on the chart timeframe. Scripts can retrieve built-in variables like open, high, low, close, volume, and bar_index.
The request.security() function can also evaluate built-in or user-defined functions in the requested context (timeframe and symbol). For example, the following example script retrieves the Average True Range (ATR) value from the daily (1D
) timeframe by passing the ta.atr() function as the expression
argument.
Which `security.*` function should I use for lower timeframes?
The request.security() function is intended for accessing data at timeframes that are equal to or higher than the chart’s current timeframe. It is possible to retrieve data from lower timeframes (LTF) using this function. However, the function returns the value from only one LTF bar within the chart’s current bar (the last bar, by default).
If the script supplies the expression
as a variable or simple calculation, directly or within a function, the data that request.security() returns from a lower timeframe is generally of limited use (see the first script in this section for an example). It is possible, however, to construct a function that performs meaningful calculations on the LTF bars and then returns the result on the last bar. The following example script counts the number of LTF bars in a chart bar and returns this value on the last LTF bar. For simplicity, the timeframes are hardcoded to "1D"
and "1W"
and the script should therefore be run from a chart on the weekly timeframe.
When using the request.security() function on a lower timeframe, all calculations that reference individual LTF bars must be done within the requested context, and only the result of the calculation is returned. Using the request.security_lower_tf() function for intrabar analysis is usually easier and more powerful, because it returns an array of data from all available intrabars within a chart bar. Returning the data for each bar allows scripts to perform calculations on specific bars or all bars in the main script context.
In the following version of our example script, we use request.security_lower_tf() to perform the same calculations. With this approach, we do not need to explicitly define the current chart’s timeframe, nor do we need a custom function.
See the sections in the User Manual page “Other timeframes and Data” about
request.security_lower_tf()
and
using request.security()
on lower timeframes
to learn more about the differences between running these functions on a lower timeframe.
How to avoid repainting when using the `request.security()` function?
Repainting can be a problem when retrieving data from higher or lower timeframes using request.security().
Retrieving data from a different symbol on the chart’s timeframe does not risk repainting. Requesting data from the chart’s own symbol and timeframe does not result in repainting either, but it is usually unnecessary to use request.security() rather than simply referencing the chart’s own values (except when modifying the chart’s ticker using ticker.*()
functions). When using the chart’s timeframe, there is no need to offset the data, change the default lookahead
value, or use barmerge.lookahead_on in order to avoid repainting.
Higher timeframes
Values from a higher timeframe (HTF) often repaint because a historical bar on the chart might include data from a realtime bar on the HTF. Realtime values can change throughout the bar; for example, the close price reflects the latest price update in a realtime bar. When the HTF bar closes and its values become fixed, the relevant historical chart bars change to adjust to the fixed HTF values. This behavior is described in the Historical and realtime behavior section of the User Manual. Users expect historical bars not to change, which is one reason why repainting is such a concern.
To prevent repainting, use confirmed values that remain consistent across all bars. The most robust method is to offset all expressions by 1. For example, instead of close
, which is equivalent to close[0]
, use close[1]
. The request.security() call must also use barmerge.lookahead_on.
This method returns data that is up to one HTF bar “late”, and is thus not subject to change.
The following example script demonstrates the use of a single bar offset to the expression
argument and barmerge.lookahead_on in request.security() to ensure that the data behaves the same on historical and realtime bars.
The script triggers a runtime error if the chart’s timeframe exceeds or matches the daily timeframe, to prevent the return of inaccurate values.
See the Avoiding repainting section of the User Manual for more information.
Lower timeframes
Although the request.security() function is intended to operate on timeframes greater than or equal to the chart timeframe, it can request data from a lower timeframe (LTF), with limitations. When accessing data from a LTF, the function evaluates the given expression in the LTF context and returns the result from a single LTF bar per chart bar. The specific LTF bar returned depends on the lookahead parameter:
- barmerge.lookahead_on returns the first intrabar of the period historically, but the last intrabar in realtime.
- barmerge.lookahead_off always returns the last intrabar for both historical and realtime data. To prevent repainting (in this case, inconsistent results between realtime and historical data) use barmerge.lookahead_off for lower timeframe data requests.
In most cases, using the request.security_lower_tf() function is more suitable for lower timeframes, as it returns an
array containing data from all available intrabars within a chart bar. See the section on request.security_lower_tf()
to learn more.
How can I convert the chart’s timeframe into a numeric format?
The timeframe.in_seconds() function converts a timeframe specified in timeframe.period format into an equivalent number of seconds. Having the timeframe in a numeric format means that scripts can calculate the number of time units within a specific timeframe, or perform operations that adjust the timeframe used in HTF calls in relation to the chart’s timeframe, as described in this FAQ entry.
In this script example, we use the timeframe.in_seconds() function to determine the chart’s timeframe, measured in seconds. Since no specific
timeframe
argument is specified, the function defaults to using timeframe.period
, which returns the chart’s current timeframe. The script then converts the timeframe in seconds into various other units of time, including minutes, hours, and days, and displays the original string and converted numeric values in a table:
How can I convert a timeframe in “float” minutes into a string usable with `request.security()`?
The built-in function timeframe.from_seconds() function converts a number of seconds into a timeframe string that is compatible with request.security().
The example script below converts a user-defined number of minutes into a timeframe string using the timeframe.from_seconds() function. The script then requests the close price from that timeframe using request.security() and plots it. Additionally, we display the resulting timeframe string in a table on the chart’s top right corner:
How do I define a higher timeframe that is a multiple of the chart timeframe?
This example script uses the timeframe.in_seconds() and timeframe.from_seconds() functions to calculate a higher timeframe that is a fixed multiple of the chart’s current timeframe. Using the input for the multiplier, the user can define the ratio between the chart’s
timeframe and the higher timeframe. The script then calculates the Relative Strength Index (RSI) for both the chart’s timeframe and the higher timeframe, plotting both in a separate pane for comparison. We display the calculated higher timeframe string in a table on the main chart pane by using force_overlay
:
How can I plot a moving average only when the chart’s timeframe is 1D or higher?
To plot a moving average on a chart only if it has a timeframe of daily (“1D”) or higher, scripts can use the timeframe.in_seconds() function to convert the chart’s current timeframe into seconds. Since a day consists of 86400 seconds, any timeframe equal to or exceeding this value corresponds to a daily or longer duration.
The example script below calculates and plots a Simple Moving Average (SMA) of the closing prices over the last 200 bars.
The script uses a ternary operator to return the moving average on timeframes of 1D or greater, or na if the timeframe is shorter than one day. Because plot() calls cannot be in a local scope, scripts cannot conditionally call this function. Passing an na value as the series
argument is an effective way to not plot anything. Note that plotting an na value does count towards the script’s plot limit.
What happens if I plot a moving average from the 1H timeframe on a different timeframe?
The request.security() function can access data from a different context, such as a different symbol or timeframe. There are different considerations when accessing data from a timeframe higher or lower than the chart timeframe.
First, let’s consider an example of plotting data from a lower timeframe. The following script plots a 21-period Exponential Moving Average (EMA) derived from the 1-hour (1H) timeframe on any chart, irrespective of the timeframe of that chart:
Assuming that we run this script on a chart with a daily timeframe, we encounter the following problems:
- For each daily bar, the chart can plot only 1 of the 24 MA values theoretically available. The plot misses out the intraday fluctuations and trends that a 1H moving average (MA) is typically used to identify.
- The script above displays only the EMA value calculated for the final 1-hour bar of each day. In realtime, the plot displays the most recently known value.
Unlike request.security(), the request.security_lower_tf() function is intended for use on lower timeframes. It returns an array containing data from all available intrabars within a chart bar. See this section of the User Manual to learn more.
We could rewrite the script to use request.security_lower_tf(), but plotting a moving average from a lower timeframe is still not very practical.
A more logical approach is to plot MAs from a higher timeframe. This strategy shows broader market trends within the context of shorter-term price movements. For example, plotting a daily MA on a 1H chart provides insights into how intraday prices are trending relative to the longer-term daily average.
In the following example script, we plot the 21 EMA calculated at the 1H timeframe, but only when the chart’s timeframe is equal to or lower than 1H. We call the request.security() function in the recommended way to avoid repainting.
Why do intraday price and volume values differ from values retrieved with `request.security()` at daily timeframes and higher?
Intraday open, high, low, close, and volume (OHLCV) values can be different from those from request.security() at daily timeframes and higher for a number of reasons, including the following:
- Different data feeds: Certain trades (like block trades and OTC trades, especially in stocks) are recorded only at the end of the trading day, so their volume affects the End-of-Day (EOD) feed but not the intraday feed.
- Price discrepancies: There can be slight differences in prices between EOD and intraday data. For example, an EOD high might not match any intraday highs due to variations in data feeds.
- Extended hours data: EOD data feeds do not include information from trading outside regular hours, unlike some intraday feeds. For instance, the bars of an hourly chart might straddle the open of a session, mixing data from pre-market and regular trading.
For an extended list of factors with detailed explanations, refer to the Data feeds section in the User Manual.