Pine Script Timeframe and Period: How Do They Work?

Timeframes are fundamental to technical analysis. Whether you’re a scalper glued to the 1-minute chart or a position trader focused on the weekly, understanding how to leverage different time perspectives is crucial. In Pine Script, managing timeframes is handled primarily through built-in variables and the powerful security() function. Mastering these elements is key to building robust multi-timeframe indicators and strategies.

Understanding Timeframes in Pine Script

At its core, a timeframe in trading dictates the duration represented by each bar (or candle) on a chart. A 1-hour timeframe means each bar aggregates price action over one hour. A daily timeframe aggregates price action over one trading day. Pine Script provides tools to understand and interact with these time granularities.

What is a Timeframe?

In the context of Pine Script and TradingView, the ‘timeframe’ refers to the duration of time that each historical or real-time bar represents. This setting is controlled by the user viewing the chart, but your script needs to be aware of it and potentially interact with data from other timeframes.

Built-in Timeframe Identifiers (period)

Pine Script uses specific string identifiers for standard timeframes. These are often referred to via the built-in period variable or used directly as strings.

Common identifiers include:

  • Intraday: “1”, “5”, “15”, “30”, “60”, “120”, “240”, etc. (representing minutes)
  • Daily: “D”
  • Weekly: “W”
  • Monthly: “M”

Note that there are also identifiers for yearly, quarterly, etc., but intraday and standard high timeframes are the most common for indicator and strategy development.

Default Chart Timeframe vs. Script Timeframe

It’s essential to distinguish between the timeframe the user has selected for the main chart window and the timeframe(s) your script might request data from. By default, a script executes and calculates on the chart’s chosen timeframe. If the chart is 15-minute, your close variable represents the closing price of the 15-minute bar. However, you can use functions like security() to pull data from, say, the 1-hour or daily timeframe while still running on the 15-minute chart.

Using the ‘timeframe’ Variable

The timeframe built-in variable is a string that holds the current timeframe of the chart on which the script is running.

Accessing the Current Chart Timeframe

You can directly access this value anywhere in your script.

// This script simply prints the current chart timeframe
//@version=5
indicator("Current Timeframe Display", overlay=true)

chart_tf = timeframe

// Display the timeframe on the chart
label.new(bar_index, high, "TF: " + chart_tf, color=color.blue)

// You can also print it to the console for debugging
// print(chart_tf)

This variable is useful for making your script responsive to the user’s chart setting.

Conditional Logic Based on Timeframe

You might want your script to behave differently depending on the timeframe it’s applied to.

// Adjust sensitivity based on timeframe
//@version=5
indicator("Timeframe Adaptive MA", overlay=true)

// Define MA length, longer for higher timeframes
ma_length = switch timeframe
    "1" => 20
    "5" => 40
    "15" => 60
    "60" => 100
    "240" => 150
    "D" => 200
    => // Default case for any other timeframe
       50

ma_value = ta.sma(close, ma_length)

plot(ma_value, color=color.blue, title="Adaptive MA")

This example uses a switch statement to assign a different moving average length based on the value of timeframe. This allows a single indicator to provide more relevant analysis across various chart granularities.

Requesting Data from Different Timeframes with ‘security()’

One of the most powerful features for multi-timeframe analysis is the security() function. It allows your script to look at data series from different symbols and timeframes than the one the script is currently running on.

The ‘security()’ Function Explained

The general syntax is:

security(symbol, timeframe, expression, gaps, lookahead, ignore_invalid_timeframe)

The most crucial parameters are:

  • symbol: The trading symbol string (e.g., syminfo.tickerid for the current symbol, or a specific string like “NASDAQ:AAPL”).
  • timeframe: The timeframe string (e.g., period for the current chart TF, or a specific string like “60”, “D”, “W”).
  • expression: The series variable or expression you want to fetch from that symbol/timeframe (e.g., close, ta.sma(close, 20), volume).

The other parameters (gaps, lookahead, ignore_invalid_timeframe) control how data gaps are handled and, critically, whether the data from the requested timeframe is allowed to “look ahead” (potentially causing repainting). Default gaps = gaps.true and lookahead = barmerge.lookahead_on is often problematic for historical backtesting/analysis due to repainting. Using lookahead = barmerge.lookahead_off is generally recommended for backtestable scripts.

Specifying Timeframes in ‘security()’

You can use static strings or the period variable:

// Fetching Daily Close Price
//@version=5
indicator("Daily Close on Any Chart", overlay=true)

daily_close = security(syminfo.tickerid, "D", close, lookahead=barmerge.lookahead_off)

plot(daily_close, color=color.red, title="Daily Close")

This plots the daily closing price as a stepped line on whatever timeframe the user is viewing.

Mixing Timeframes: Higher and Lower Timeframe Data

The power comes from accessing higher timeframe data on a lower timeframe chart.

// Plotting H4 EMA on H1 Chart
//@version=5
indicator("H4 EMA on H1", overlay=true)

h4_ema_length = input.int(50, "H4 EMA Length")

// Get EMA value from the H4 timeframe
h4_ema_value = security(syminfo.tickerid, "240", ta.ema(close, h4_ema_length), lookahead=barmerge.lookahead_off)

plot(h4_ema_value, color=color.purple, linewidth=2, title="H4 EMA")

// Optional: Plot the H1 EMA for comparison
// plot(ta.ema(close, h4_ema_length), color=color.gray, title="H1 EMA")

When running this on an H1 chart, h4_ema_value will contain the calculated EMA from the corresponding H4 bar. It will appear as a constant value over the H1 bars that fall within that H4 bar’s time range.

Important Considerations When Using ‘security()’

  • Repainting: The default lookahead=barmerge.lookahead_on means the value of the higher timeframe bar’s expression will update as that higher timeframe bar is forming. On a lower timeframe chart, this means historical bars on your chart might change their plotted value when new data comes in for the higher timeframe bar they correspond to. This is repainting and is generally undesirable for backtesting or making decisions on closed bars. Always consider setting lookahead=barmerge.lookahead_off for non-repainting historical data, especially in strategies.
  • Data Alignment (gaps): The gaps parameter (gaps.true or gaps.false) controls whether security() carries forward the last known value when there’s no corresponding bar on the requested timeframe (e.g., weekends for stock data on intraday charts). gaps.true fills these gaps by repeating the last value, gaps.false inserts na. Generally, gaps.true is more useful.
  • Performance: Calling security() multiple times or with complex expressions can impact script performance, especially on lower timeframes pulling data from significantly higher ones. Be mindful of optimization.
  • Timeframe Compatibility: Ensure the requested timeframe string is valid. Using the period variable for the requested timeframe can be useful if you want the security call to dynamically match an input timeframe defined by the user.

Working with the ‘period’ Variable

The period built-in variable is functionally very similar to timeframe. It also returns a string representing the chart’s current timeframe.

Understanding the ‘period’ Variable in Pine Script

In Pine Script v4 and earlier, period was the primary variable for accessing the chart’s timeframe string. In v5, timeframe was introduced, offering a slightly more semantically clear name, but period remains supported and works identically to timeframe in most contexts for getting the chart’s TF string.

Both timeframe and period return the same string value (e.g., “D”, “60”, “W”) corresponding to the chart’s setting.

Using the ‘period’ Variable to Define Custom Timeframes

While period itself is the current chart timeframe string, you can use it in conjunction with input.timeframe() to allow users to select a specific timeframe for a security() call dynamically.

// Fetching MA from User-Selected Timeframe
//@version=5
indicator("MA from Custom TF", overlay=true)

custom_tf_input = input.timeframe("D", "Select MA Timeframe") // Default is Daily
ma_length = input.int(20, "MA Length")

// Use the input variable in security()
custom_tf_ma = security(syminfo.tickerid, custom_tf_input, ta.sma(close, ma_length), lookahead=barmerge.lookahead_off)

plot(custom_tf_ma, color=color.navy, linewidth=2, title="Custom TF MA")

This pattern allows users to specify the timeframe for a calculation directly from the indicator’s settings, offering flexibility without requiring script modification.

Practical Examples and Use Cases

Combining timeframe, period, and security() opens up many possibilities for advanced analysis.

Multi-Timeframe Analysis (MTF) Strategies

A common strategy involves confirming signals on a lower timeframe using indicators or conditions from a higher timeframe.

// Simple MTF Crossover Strategy
//@version=5
strategy("MTF Crossover Strategy", overlay=true, initial_capital=100000, process_orders_on_close=true)

// --- Inputs ---
short_ma_length = input.int(10, "Short MA Length")
long_ma_length  = input.int(30, "Long MA Length")
htf_tf_input    = input.timeframe("240", "Higher Timeframe") // Default H4

// --- Higher Timeframe Calculations (No repainting) ---
htf_short_ma = security(syminfo.tickerid, htf_tf_input, ta.sma(close, short_ma_length), lookahead=barmerge.lookahead_off)
htf_long_ma  = security(syminfo.tickerid, htf_tf_input, ta.sma(close, long_ma_length), lookahead=barmerge.lookahead_off)

// --- Entry Conditions (Using HTF data on current TF) ---
long_condition  = ta.crossover(htf_short_ma, htf_long_ma)
short_condition = ta.crossunder(htf_short_ma, htf_long_ma)

// --- Strategy Orders ---
if long_condition
    strategy.entry("Buy", strategy.long)

if short_condition
    strategy.entry("Sell", strategy.short)

// --- Plot HTF MAs (Optional) ---
plot(htf_short_ma, color=color.green, linewidth=2, title="HTF Short MA")
plot(htf_long_ma,  color=color.red,   linewidth=2, title="HTF Long MA")

This strategy executes on the chart’s timeframe but uses crossovers from a user-specified higher timeframe for entry signals. Crucially, lookahead=barmerge.lookahead_off is used to prevent repainting issues during backtesting.

Creating Alerts Based on Higher Timeframe Conditions

You can trigger alerts when a condition occurs on a higher timeframe, even if you’re primarily watching a lower timeframe chart.

// Alert on Daily RSI Cross Below 30
//@version=5
indicator("Daily RSI Alert", overlay=false)

rsi_length = input.int(14, "RSI Length")
overbought = input.int(70, "Overbought Level")
oversold   = input.int(30, "Oversold Level")

// Get Daily RSI value (non-repainting for closed Daily bar)
daily_rsi = security(syminfo.tickerid, "D", ta.rsi(close, rsi_length), lookahead=barmerge.lookahead_off)

// Check for condition on the *most recent closed* Daily bar
alert_condition = ta.crossunder(daily_rsi, oversold)

// Plot Daily RSI on the lower timeframe chart
plot(daily_rsi, color=color.orange, title="Daily RSI")
plot(oversold, color=color.blue, style=plot.style_circles)
plot(overbought, color=color.red, style=plot.style_circles)

// Create an alert
alertcondition(alert_condition, "Daily RSI crossed below " + str.tostring(oversold))

This script runs on any timeframe but checks if the Daily RSI has crossed below 30 on the last completed Daily bar. An alert is triggered only when this specific event on the daily timeframe is detected while processing a bar on the current chart timeframe.

Dynamically Adjusting Indicators Based on Timeframe

We saw a simple example with the MA length. You can extend this to adjust other parameters or even switch indicator logic.

// Timeframe Adaptive Volatility Bands
//@version=5
indicator("Adaptive Volatility Bands", overlay=true)

// Adjust multiplier based on timeframe
multiplier = switch timeframe
    "1" => 1.5
    "5" => 1.8
    "15" => 2.0
    "60" => 2.5
    "240" => 3.0
    "D" => 3.5
    => // Default
       2.0

// Adjust lookback period based on timeframe
lookback = switch timeframe
    "1" => 10
    "5" => 20
    "15" => 30
    "60" => 40
    "240" => 50
    "D" => 60
    => // Default
       30

// Calculate standard deviation based on adaptive lookback
std_dev = ta.stdev(close, lookback)

// Calculate adaptive upper and lower bands
mid = ta.sma(close, lookback)
upper = mid + std_dev * multiplier
lower = mid - std_dev * multiplier

// Plot bands
plot(mid, color=color.blue, title="Mid")
upper_plot = plot(upper, color=color.green, title="Upper")
lower_plot = plot(lower, color=color.red, title="Lower")
fill(upper_plot, lower_plot, color=color.new(color.blue, 90))

This script makes both the lookback period for the standard deviation and the multiplier for the bands adaptive to the chart’s current timeframe, providing a more consistent visual representation of volatility across different granularities.

By understanding and effectively using the timeframe and period variables, along with the critical security() function (paying careful attention to lookahead and gaps), you can unlock the full potential of multi-timeframe analysis and build sophisticated, adaptable tools for TradingView.


Leave a Reply