Pine Script Historical Volatility

Master this statistical measure of price fluctuation in TradingView's Pine Script, crucial for risk management, option pricing, and understanding market phases.

Subscribe now @ $99/month

What is Historical Volatility (HV)?

Historical Volatility (HV) is a statistical measure that quantifies the degree of variation of a security's price returns over a specific past period. Unlike indicators like Average True Range (ATR) which measure average price movement, HV specifically uses standard deviation of logarithmic returns to represent volatility as a percentage. It indicates how much price has deviated from its average over time, effectively showing how "jumpy" or "calm" an asset has been.

HV is crucial for risk management, particularly in options trading (where it's compared to implied volatility), and for understanding different market phases. High HV suggests unpredictable, large price swings, while low HV suggests stable, smaller price movements.

In Pine Script, calculating and interpreting Historical Volatility allows traders and investors to adapt their strategies based on the current market's inherent risk and opportunity profile.

Components and Calculation

The calculation of Historical Volatility involves several statistical steps, typically annualized for consistency across different assets and timeframes:

  1. Logarithmic Returns: For each period, calculate the natural logarithm of the current closing price divided by the previous closing price. This normalizes percentage changes.
    `Log Return = math.log(close / close[1])`
  2. Standard Deviation of Log Returns: Calculate the standard deviation of these logarithmic returns over a specified `length` (e.g., 20 periods for 20 trading days).
    `StdDev_Log_Returns = ta.stdev(Log Return, length)`
  3. Annualization: To compare volatility across different assets or timeframes, the daily (or per-period) standard deviation is annualized. This involves multiplying by the square root of the number of periods in a year.
    * For daily data, typically `math.sqrt(252)` (representing 252 trading days in a year). * For weekly data, `math.sqrt(52)`. * For monthly data, `math.sqrt(12)`.
    `Annualized HV = StdDev_Log_Returns * math.sqrt(Annualization Factor)`
  4. Convert to Percentage: The result is often multiplied by 100 to express it as a percentage.
    `Historical Volatility (%) = Annualized HV * 100`

A common `length` for daily charts is 20 periods, representing roughly one trading month.

Basic Historical Volatility (HV) Implementation in Pine Script

Pine Script v5 requires a custom function to calculate Historical Volatility, as `ta.hvol()` is not a direct built-in in its most common annualized form. We'll leverage `math.log` and `ta.stdev`.

//@version=5
indicator("My Historical Volatility (HV)", overlay=false, format=format.percent) // overlay=false to plot in a separate pane

// Input for HV length (number of periods for standard deviation)
length = input.int(20, title="HV Length", minval=2) // Minval 2 needed for log return calculation

// Input for annualization factor
// 252 for daily trading days, 365 for calendar days (if using daily candles)
// 52 for weekly, 12 for monthly
annualizationFactor = input.int(252, title="Annualization Factor (e.g., 252 for daily)", minval=1)

// Calculate Logarithmic Returns
// Handle first bar case (close[1] will be NaN)
logReturn = math.log(close / close[1])

// Calculate Standard Deviation of Log Returns
// Use `fixnan` to handle the first `length-1` bars where stdev would be NaN
stdevLogReturns = ta.stdev(logReturn, length)

// Annualize the Standard Deviation
annualizedHV = stdevLogReturns * math.sqrt(annualizationFactor)

// Convert to percentage
historicalVolatility = annualizedHV * 100

// Plot the Historical Volatility line
plot(historicalVolatility, title="Historical Volatility (%)", color=color.blue, linewidth=2)

// Optional: Add moving average of HV to identify trends in volatility
hvMA = ta.sma(historicalVolatility, 20) // 20-period SMA of HV
plot(hvMA, title="HV SMA", color=color.gray, linewidth=1, style=plot.style_line)

// Highlight background when HV is significantly higher or lower than its average
bgcolor(historicalVolatility > hvMA * 1.2 ? color.new(color.red, 90) : na, title="High HV")
bgcolor(historicalVolatility < hvMA * 0.8 ? color.new(color.green, 90) : na, title="Low HV")

Percentage Volatility: HV expresses volatility as a percentage, directly comparable across different assets, unlike ATR which is in absolute price units.

Practical Historical Volatility (HV) Trading Strategies

1. Volatility Regimes (Mean Reversion of Volatility)

Volatility often exhibits mean-reverting behavior: periods of high volatility tend to be followed by periods of low volatility, and vice versa. HV helps identify these shifts.

//@version=5
strategy("HV Volatility Regimes", overlay=true)

length = input.int(20, title="HV Length", minval=2)
annualizationFactor = input.int(252, title="Annualization Factor", minval=1)
hvUpperThreshold = input.float(30.0, title="High HV Threshold (%)", minval=10.0, step=1.0)
hvLowerThreshold = input.float(15.0, title="Low HV Threshold (%)", minval=5.0, step=1.0)

logReturn = math.log(close / close[1])
stdevLogReturns = ta.stdev(logReturn, length)
historicalVolatility = stdevLogReturns * math.sqrt(annualizationFactor) * 100

plot(historicalVolatility, "Historical Volatility", color.blue, display=display.pane_only)
hline(hvUpperThreshold, "High Vol Threshold", color.red, linestyle=hline.style_dashed, display=display.pane_only)
hline(hvLowerThreshold, "Low Vol Threshold", color.green, linestyle=hline.style_dashed, display=display.pane_only)

// Conditions for Volatility Expansion/Contraction
isHighHV = historicalVolatility > hvUpperThreshold
isLowHV = historicalVolatility < hvLowerThreshold

// Strategy Entry/Exit based on volatility shifts
// Example: Enter long when volatility is low and breaks out bullishly
// And short when volatility is high and reverses bearishly
maFast = ta.ema(close, 10)
maSlow = ta.ema(close, 20)

// Anticipate bullish breakout after low volatility
if (isLowHV[1] and ta.crossover(maFast, maSlow))
    strategy.entry("Long (Vol Expand)", strategy.long)

// Anticipate bearish reversal after high volatility
if (isHighHV[1] and ta.crossunder(maFast, maSlow))
    strategy.entry("Short (Vol Contract)", strategy.short)

// Basic exit logic
strategy.close("Long (Vol Expand)", when=ta.crossunder(maFast, maSlow))
strategy.close("Short (Vol Contract)", when=ta.crossover(maFast, maSlow))

2. Options Trading (Implied Volatility vs. Historical Volatility)

While Pine Script does not directly provide implied volatility data from options chains, traders often compare an option's implied volatility (IV) to the underlying asset's Historical Volatility (HV) to assess if options are relatively cheap or expensive.

This strategy is conceptual within Pine Script, as it requires external IV data, but HV itself is a core component.

//@version=5
indicator("HV for Options Context", overlay=false, format=format.percent)

length = input.int(20, title="HV Length", minval=2)
annualizationFactor = input.int(252, title="Annualization Factor", minval=1)

logReturn = math.log(close / close[1])
stdevLogReturns = ta.stdev(logReturn, length)
historicalVolatility = stdevLogReturns * math.sqrt(annualizationFactor) * 100

plot(historicalVolatility, "Historical Volatility (%)", color=color.blue, linewidth=2)

// To compare with Implied Volatility (IV), you would need to input IV manually or via external data.
// For demonstration, let's assume a hypothetical IV input.
// Note: This 'impliedVol' input is purely for illustration; real IV comes from option chain data.
impliedVol = input.float(na, title="Implied Volatility (%) (Manual Input for Demo)", group="Options Context")

// Plot the hypothetical Implied Volatility for visual comparison
plot(not na(impliedVol) ? impliedVol : na, "Implied Volatility", color=color.orange, linewidth=2)

// Determine if options are relatively expensive or cheap based on IV vs HV
areOptionsExpensive = historicalVolatility > 0 and impliedVol > historicalVolatility * 1.2 // IV is 20% higher than HV
areOptionsCheap = historicalVolatility > 0 and impliedVol < historicalVolatility * 0.8 // IV is 20% lower than HV

bgcolor(areOptionsExpensive ? color.new(color.red, 90) : na, title="Options Potentially Expensive")
bgcolor(areOptionsCheap ? color.new(color.green, 90) : na, title="Options Potentially Cheap")

alertcondition(areOptionsExpensive, "Options Expensive", "Implied Volatility is high relative to Historical Volatility.")
alertcondition(areOptionsCheap, "Options Cheap", "Implied Volatility is low relative to Historical Volatility.")

3. Dynamic Stop Loss & Position Sizing

Similar to ATR, Historical Volatility can be used to dynamically adjust risk management parameters, but on a percentage basis.

//@version=5
strategy("HV Dynamic Risk Management", overlay=true)

length = input.int(20, title="HV Length", minval=2)
annualizationFactor = input.int(252, title="Annualization Factor", minval=1)
hvStopLossMultiplier = input.float(1.5, title="HV Stop Loss Multiplier", minval=0.1, step=0.1) // e.g., 1.5x HV
accountRiskPerTrade = input.float(1000.0, title="Max $ Risk Per Trade", minval=10)

logReturn = math.log(close / close[1])
stdevLogReturns = ta.stdev(logReturn, length)
historicalVolatility = stdevLogReturns * math.sqrt(annualizationFactor) // Not converting to % for calculation

// Simple entry: crossing a 20-period SMA
maLength = input.int(20, "Entry MA Length", minval=1)
maValue = ta.sma(close, maLength)

longCondition = ta.crossover(close, maValue)
shortCondition = ta.crossunder(close, maValue)

// Calculate dynamic stop loss
// Ensure historicalVolatility is not zero to prevent division by zero
longStopLossPercentage = historicalVolatility * hvStopLossMultiplier
shortStopLossPercentage = historicalVolatility * hvStopLossMultiplier

longStopPrice = strategy.position_avg_price * (1 - longStopLossPercentage)
shortStopPrice = strategy.position_avg_price * (1 + shortStopLossPercentage)

// Calculate dynamic position size
// Risk_per_share = Entry Price * HV * Multiplier
// Qty = Account Risk / Risk_per_share
qtyToTrade = 0
if (historicalVolatility > 0)
    riskPerShare = close * historicalVolatility * hvStopLossMultiplier
    qtyToTrade := math.floor(accountRiskPerTrade / riskPerShare)
    qtyToTrade := math.max(1, qtyToTrade) // Ensure at least 1 share

if (longCondition)
    strategy.entry("Long HV", strategy.long, qty=qtyToTrade)

if (shortCondition)
    strategy.entry("Short HV", strategy.short, qty=qtyToTrade)

// Apply dynamic stop losses
strategy.exit("Long Exit", from_entry="Long HV", stop=longStopPrice)
strategy.exit("Short Exit", from_entry="Short HV", profit=na, stop=shortStopPrice) // Added profit=na for clarity based on previous exits; adjust if needed

plot(historicalVolatility * 100, "HV %", color=color.purple, display=display.pane_only) // Plot as percentage for viewing
plot(strategy.position_avg_price > 0 ? longStopPrice : na, "Long Stop", color=color.red, style=plot.style_linebr)
plot(strategy.position_avg_price < 0 ? shortStopPrice : na, "Short Stop", color=color.green, style=plot.style_linebr)

Optimizing Historical Volatility Performance

To get the most from Historical Volatility in Pine Script:

Volatility as a Cycle: Markets often alternate between periods of low volatility (sideways, accumulation) and high volatility (trending, distribution). HV helps you understand where you are in this cycle.

Common Historical Volatility Pitfalls

Conclusion

Historical Volatility (HV) is a fundamental statistical measure in Pine Script for TradingView, providing a quantifiable understanding of an asset's price variability. By measuring the annualized standard deviation of logarithmic returns, it offers valuable insights into market behavior, aiding in crucial aspects like risk management, position sizing, and adapting strategies to changing volatility regimes. While it does not predict price direction, its ability to signal periods of volatility expansion (preceding breakouts) or contraction (preceding reversals/consolidation) is invaluable. By understanding its calculation, thoughtfully tuning its parameters, and integrating it strategically with directional indicators and robust risk management practices, you can leverage Historical Volatility to enhance your trading decisions and navigate various market environments with greater precision.

Enhance Your Trading

Get a high-performance Pine Script analysis tool for actionable market insights, designed for traders on the move.

This strategy runs in live mode on TradingView, helping you identify potential opportunities.

Subscribe now @ $99/month