How to Access the Prior Bar Close in TradingView Pine Script?

Accessing historical data is fundamental to developing effective trading indicators and strategies in TradingView Pine Script. While the current bar’s data (open, high, low, close, volume) is readily available, referencing data from past bars is crucial for calculations like moving averages, comparing current price action to previous periods, and detecting historical patterns.

Understanding the Importance of Prior Bar Data

Many common trading concepts rely on historical context. For instance, comparing the current close to the prior bar’s close helps determine if the price has moved up or down. Calculating volatility often involves looking at the range or standard deviation over a lookback period. Building sophisticated algorithms necessitates understanding the price’s journey leading up to the current moment. The prior bar’s close (close[1]) is arguably the most frequently used piece of historical data, serving as a baseline for comparison and a building block for numerous calculations.

Brief Overview of Pine Script and Historical Data Access

Pine Script operates on a bar-by-bar basis. When your script runs on a specific bar, it has direct access to the data for that bar. Accessing data from previous bars is achieved through the history-referencing operator [] or by using specialized functions like security(). The history-referencing operator [] allows you to look back a specified number of bars on the current chart’s timeframe, while security() provides the capability to fetch data from different symbols or timeframes.

Methods for Retrieving Prior Bar Close

There are two primary ways to access the prior bar’s close price in Pine Script, each suitable for different scenarios:

Using the close Variable with Offset

The most straightforward method is using the built-in close variable with the history-referencing operator []. The syntax close[N] refers to the close value N bars ago. To get the close of the bar immediately preceding the current one, you use close[1]. This is the most common and efficient way to access the prior bar’s close on the current chart’s timeframe.

//@version=5
indicator("Prior Bar Close Example 1", overlay=true)

// Get the close of the current bar
current_close = close

// Get the close of the prior bar (1 bar ago)
prior_close = close[1]

// You can access even older data, e.g., 2 bars ago
prior_prior_close = close[2]

// Display the prior bar close on the chart (optional)
// plot(prior_close, title="Prior Close", color=color.blue, linewidth=1, style=plot.style_circles)

// Example usage: Check if current bar closed higher than prior bar
is_higher_close = current_close > prior_close

// You can use this boolean variable in conditions
// if is_higher_close
//     alert("Current bar closed higher than previous!", alert.freq_once_per_bar)

// Note: close[0] is equivalent to close

Using close[1] is highly performant as the data is readily available in the script’s execution context for the current timeframe.

Employing the security() Function for Historical Data

The security() function is used to request data from a different symbol, a different timeframe, or both. While less common specifically for getting just the immediate prior bar close on the same timeframe (where close[1] is preferred), it is essential if you need the prior bar’s close from a higher timeframe or from a different symbol.

To get the close of the last completed bar on a higher timeframe, you would typically request the data for that timeframe and then access its close[1]. However, security() often returns the data corresponding to the current bar’s time on the requested timeframe. To get the prior day’s close, for example, you’d request the ‘1D’ timeframe.

//@version=5
indicator("Prior Day Close Example", overlay=true)

// Request the close price from the '1D' (daily) timeframe
// The security() function returns the value corresponding
// to the current bar's time on the requested timeframe.
// If this is an intraday chart, it gets the daily close up to this point.
daily_close = security(syminfo.tickerid, '1D', close, lookahead=barmerge.lookahead_on)

// To get the close of the *previous* completed daily bar:
// We request the daily close and then apply [1] to the result.
// This gets the daily close value from the bar *before* the one
// corresponding to the current intraday bar's time.
prior_day_close = security(syminfo.tickerid, '1D', close[1], lookahead=barmerge.lookahead_on)

// Note: lookahead=barmerge.lookahead_on is often needed with higher timeframes
// to get the close of the *completed* prior bar without waiting for the current
// higher timeframe bar to close.

// Plotting the prior day's close on the intraday chart
plot(prior_day_close, title="Prior Day Close", color=color.red, linewidth=2)

// Compare current close to prior day's close
is_above_prior_day = close > prior_day_close

// Example: Change plot color based on comparison
plot_color = is_above_prior_day ? color.green : color.red
plot(close, title="Close", color=plot_color, linewidth=1)

Using security() is more resource-intensive than close[1] because it involves requesting and processing data from a different context. Use it judiciously, primarily when you need data from a timeframe or symbol different from the current chart.

Practical Examples and Code Snippets

Let’s look at how the prior bar close is used in common trading calculations and logic.

Simple Moving Average (SMA) Calculation Using Prior Close

While Pine Script has built-in functions like ta.sma(), understanding how an SMA is calculated manually demonstrates the use of historical data, including the prior close.

A simple SMA is the average of the last length closing prices. To calculate the SMA for the current bar, you need the sum of the current close and the previous length - 1 closes.

//@version=5
indicator("SMA using Prior Close Logic", overlay=true)

length = input.int(20, "SMA Length", minval=1)

// Calculate the sum of the last 'length' closes
// This is conceptual; Pine Script's built-in sum function is more efficient.
// A manual sum would iterate or use the history operator repeatedly:
// sum = close + close[1] + close[2] + ... + close[length - 1]

// A more 'Pine-like' manual sum using ta.sma's underlying principle
// (This is not a direct manual implementation but shows using historical data)
// Using ta.sma(close, length) is the standard way.
// For illustration, let's calculate the change from the prior bar's SMA

// Get the built-in SMA for the current and prior bar
current_sma = ta.sma(close, length)
prior_sma = ta.sma(close[1], length) // SMA value calculated one bar ago

// Plot the SMA
plot(current_sma, title="SMA", color=color.purple)

// Illustrate access: Is the current SMA value higher than the prior bar's SMA value?
is_sma_rising = current_sma > prior_sma

// Note: The prior bar's SMA value (prior_sma) is the SMA value *on* the previous bar.
// It is calculated using data up to and including close[1].

In this example, ta.sma(close[1], length) is actually getting the SMA value that was calculated on the previous bar. This is a common pattern when you need to compare an indicator’s current value to its value on a past bar.

Implementing a Price Crossover Strategy with Previous Close Comparison

A simple crossover strategy might involve the current price crossing above or below a moving average. Comparing the current close to the moving average is one part, but comparing the prior bar’s close to the moving average on the prior bar helps confirm a crossover.

//@version=5
strategy("SMA Crossover Strategy", overlay=true)

length = input.int(50, "SMA Length", minval=1)

// Calculate the SMA
sma_val = ta.sma(close, length)

// Get the SMA value from the prior bar
prior_sma_val = sma_val[1]

// Get the close values for the current and prior bar
current_close = close
prior_close = close[1]

// Check for bullish crossover: prior close was <= prior SMA AND current close is > current SMA
bullish_crossover = (prior_close <= prior_sma_val) and (current_close > sma_val)

// Check for bearish crossover: prior close was >= prior SMA AND current close is < current SMA
bearish_crossover = (prior_close >= prior_sma_val) and (current_close < sma_val)

// Execute trades
if bullish_crossover
    strategy.entry("Buy", strategy.long)

if bearish_crossover
    strategy.close("Buy") // Close long position
    strategy.entry("Sell", strategy.short)

// Plot the SMA
plot(sma_val, title="SMA", color=color.blue)

This strategy logic explicitly uses both close[1] and the history-referenced sma_val[1] to define the crossover condition robustly, ensuring the price has moved across the moving average between the two bars.

Displaying Prior Day’s Close on the Current Chart

Traders often use the previous day’s close as a significant price level. Displaying this on an intraday chart requires security().

//@version=5
indicator("Prior Day's Close Level", overlay=true)

// Get the close of the previous completed daily bar
// security(syminfo.tickerid, '1D', close[1], lookahead=barmerge.lookahead_on)
// A common pattern to avoid repainting with security on higher TFs is to
// request the data and then history reference it *after* security returns it.
// This gets the daily close as of the *end* of the previous daily bar.
prior_day_close = security(syminfo.tickerid, '1D', close, lookahead=barmerge.lookahead_on)[1]

// Plot a horizontal line at the prior day's close
plot(prior_day_close, title="Prior Day Close", color=color.red, linewidth=2, style=plot.style_stepline)

// Add a label or text to show the value (optional, for clarity)
// if barstate.islast
//     label.new(bar_index, prior_day_close, "Prior Day Close: " + str.tostring(prior_day_close, format.mintick), color=color.red)

Here, security(..., close)[1] first gets the daily close value for each intraday bar (which updates throughout the day for the current daily bar) and then applies the history operator [1] to get the value that was present on the previous daily bar. Using lookahead=barmerge.lookahead_on helps ensure that the close value fetched by security for the current day reflects the completed value of the previous daily bar when referenced with [1]. This pattern reliably shows the completed previous day’s close.

Considerations and Best Practices

Using historical data introduces specific considerations in Pine Script development.

Handling Edge Cases: First Bar and Data Availability

When using the history-referencing operator [], you must be aware of the first bar on the chart. close[1] is undefined on the very first bar because there is no prior bar. Accessing close[N] where N is greater than or equal to the current bar index will result in a na (not a number) value. Pine Script handles this gracefully – calculations involving na typically result in na.

When writing logic that relies on close[1], consider how your script should behave on the first bar. Often, you might use if not na(close[1]) or check bar_index > 0 before using prior bar data in critical calculations or conditions.

//@version=5
indicator("Prior Close with Edge Case Handling", overlay=true)

// Access prior close safely
prior_close = close[1]

// Example: Calculate price change only if prior close exists
price_change = if not na(prior_close)
    close - prior_close
else
    na

// Plot the price change
plot(price_change, title="Price Change", color=color.teal)

// Another approach: Using bar_index
// if bar_index > 0
//    // Use close[1] here
// else
//    // Handle the first bar

For indicators and strategies, plots or entries based on na values will typically not appear or trigger, which is often the desired behavior on the first bar.

Performance Optimization when Accessing Historical Data

Accessing historical data using close[N] is generally very fast for reasonably small N and within the current timeframe. The data is already loaded.

security() calls, especially multiple ones or those on different symbols/timeframes, can impact script performance and execution speed. Each security() call essentially runs a separate, hidden script instance to fetch the required data. Minimize redundant security() calls.

If you need data from a higher timeframe, fetch it once using security() and store it in a variable. Then, reference that variable or its history using [] rather than making repeated security() calls within your script’s logic.

//@version=5
indicator("Optimized Security Example", overlay=true)

// INEFFICIENT: Calling security multiple times for the same data
// bad_prior_day_close_1 = security(syminfo.tickerid, '1D', close, lookahead=barmerge.lookahead_on)[1]
// bad_prior_day_close_2 = security(syminfo.tickerid, '1D', close, lookahead=barmerge.lookahead_on)[1]

// EFFICIENT: Call security once, store result, then history reference
weekly_close_data = security(syminfo.tickerid, '1W', close, lookahead=barmerge.lookahead_on)

prior_week_close = weekly_close_data[1]

plot(prior_week_close, title="Prior Week Close", color=color.navy, linewidth=2)

Limit the lookback depth (N in close[N]) if possible, as excessively large lookbacks consume more memory, though this is less often a performance bottleneck compared to security() misuse.

Avoiding Common Pitfalls in Prior Bar Data Usage

  1. Repainting with security(): Be extremely cautious when using security() with higher timeframes, especially when referencing close[0] (the current bar’s close on that higher timeframe). This value can change on the current higher timeframe bar until it closes. Using close[1] (the previous completed bar’s close) with lookahead=barmerge.lookahead_on inside security or applying [1] after the security call (security(...)[1]) are common patterns to get non-repainting historical data from higher timeframes. The example showing the prior day’s close demonstrates the latter, safer pattern.
  2. Confusing indicator[1] with indicator(source[1])[0]: If my_indicator = ta.sma(close, 20), then my_indicator[1] is the value of the SMA indicator on the previous bar. This is different from calculating the SMA of the prior bar’s source data (ta.sma(close[1], 20)), which is usually not what you intend.
  3. Ignoring na values: Always consider the first few bars where close[1] (or other historical references) might be na. Ensure your logic handles these cases gracefully to prevent unexpected behavior or errors.

Conclusion

Accessing the prior bar’s close price is a foundational skill in Pine Script. The close[1] syntax provides a simple, efficient way to reference the immediate past on the current timeframe, suitable for a vast majority of calculations and comparisons.

Recap of Accessing Prior Bar Close in Pine Script

  • Use close[1] for the close of the previous bar on the current chart’s timeframe. This is the standard and most performant method.
  • Use security(..., close[1], ...) or preferably security(..., close, ...)[1] to get the close of the previous completed bar from a different timeframe or symbol, being mindful of lookahead and repainting.
  • Always handle the na values that occur on the first bar when using history references.

Further Exploration and Advanced Techniques

Mastering history referencing opens the door to more complex indicators and strategies:

  • Calculating volatility metrics like Average True Range (ta.atr) which inherently use prior bar data.
  • Implementing lookback periods for support/resistance detection.
  • Developing stateful strategies that track conditions across multiple bars.
  • Using functions like ta.valuewhen() to find the value of a variable when a specific condition was true on a previous bar.

By effectively utilizing close[1] and understanding how to safely access other historical data via security(), you can build robust and insightful trading tools in Pine Script.


Leave a Reply