Session Volatility Indicator
Table of Contents
What Is This Script?
This script calculates the average volatility of trading sessions.
You specify a start date, an end date, and a session time (eg. market open, Asian session etc)
The script then scans through all the price action on your chart and calculates the average price movement during that specified period.
What Is It For?
I created this script for my own purposes when developing certain strategies and testing certain ideas.
The purpose of this script is to give you an idea of how much price tends to move during certain times of day for certain markets.
You could think of it as a “session’s average true range”.
In crypto and forex this might be how much price tends to move on certain pairs during the Australian/Asian session, or the European session, or the overnight U.S. session etc.
In stocks this might be how much a symbol tends to move during the first hour of the day or the last hour of the day.
The point of calculating this information is for better understanding how markets move during certain times of day.
It’s not a perfect science obviously since some days can be wilder than others depending on what fundamental events are developing, but it’s useful information to have for times when there are no expected volatility-inducing events.
This info can help with optimizing targets and stop loss placement for certain day-trading strategies, and just generally getting an idea of what kinds of moves you might reasonably expect out of overnight positions or certain times of day etc – or at least that’s what I use it for.
How It Works
Once you specify a start date, an end date and a time session, the script will scan through all the bars on your chart and calculate the price range within that time session and calculate the average max price move for that time of day.
It saves the highest high of the range and the lowest low of the range, and then determines the difference between the two prices.
It then compares that number to the average to give you a % of the current average range.
Indicator Values
The indicator outputs a handful of values onto your chart. This is what the colors correspond to:
Top-Right Box: The average price range during the given time of day over historical price action.
Green Number: The recent session’s highest price.
Red Number: The recent session’s lowest price.
Purple Number: The recent session’s price range (high – low).
Orange Number: The recent session’s range ÷ the average (outputs a relative % of the average).
Settings

Hover your mouse over the “i” symbol to get more information on the script’s settings, but here’s a brief description:
Start Date:
The date to begin calculating from (set to 1000 by default so it scans the entire chart).
End Date:
The date to stop calculating (set to 2099 by default so it scans the entire chart)
Time Session:
This is the time session during the day that you want to analyze.
Color Background:
If turned on, this setting changes the background color to highlight the session.
Source Code
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © ZenAndTheArtOfTrading / www.PineScriptMastery.com // Last Updated: 3rd June, 2021 // @version=4 study("[2021] Session Volatility", overlay=true) // Get user input startDate = input(title="Start Date", defval=timestamp("01 Jan 1000 13:30 +0000"), type=input.time, tooltip="Date & time to begin analysis") endDate = input(title="End Date", defval=timestamp("1 Jan 2099 19:30 +0000"), type=input.time, tooltip="Date & time to stop analysis") timeSession = input(title="Time Session To Analyze", type=input.session, defval="0600-0915", tooltip="Time session to analyze volatility") colorBG = input(title="Color Background?", type=input.bool, defval=true, tooltip="Change the background color based on whether the current bar falls within the given session?") // Custom function to convert forex pips into whole numbers atr = atr(14) toWhole(number) => if syminfo.type == "forex" // This method only works on forex pairs return = atr < 1.0 ? (number / syminfo.mintick) / 10 : number return := atr >= 1.0 and atr < 100.0 and syminfo.currency == "JPY" ? return * 100 : return else number // This function returns true if the current bar falls within the given time session (:1234567 is to include all weekdays) inSession(sess) => na(time(timeframe.period, sess + ":1234567")) == false and time >= startDate and time <= endDate bgcolor(inSession(timeSession) and colorBG ? color.rgb(0, 0, 255, 90) : na) // Check if a new session has begun var withinSession = false if inSession(timeSession) and not inSession(timeSession)[1] withinSession := true // Declare required variables for analysis var recentMovement = 0.0 var totalMovement = 0.0 var sessionsCounted = 0 var MAXINT = 2147483647.0 var highestHigh = -1.0 var lowestLow = MAXINT // Check if a session has ended if not inSession(timeSession) and inSession(timeSession)[1] withinSession := false // Analyze movement recentMovement := highestHigh - lowestLow totalMovement := totalMovement + recentMovement sessionsCounted := sessionsCounted + 1 // Reset stored high/low highestHigh := -1.0 lowestLow := MAXINT // Get highest high and lowest low of current session if withinSession if high > highestHigh highestHigh := high if low < lowestLow lowestLow := low // Calculate average pip movement over all analyzed sessions averageMovement = totalMovement / sessionsCounted // Plot volatility info plot(withinSession ? highestHigh : na, color=color.rgb(0,255,0,100), style=plot.style_linebr, title="Highest High") plot(withinSession ? lowestLow : na, color=color.rgb(255,0,0,100), style=plot.style_linebr, title="Lowest Low") plot(not withinSession ? recentMovement : na, color=color.rgb(128,0,128,100), title="Recent Change") plot(not withinSession ? recentMovement / averageMovement : na, color=color.rgb(255,165,0,100), title="Recent Change ÷ Average Change") // Create an output table to display average pip change var table resultTable = table.new(position.top_right, 3, 2, border_width = 3) f_fillCell(_table, _column, _row, _value, _text) => _c_color = color.green _transp = 80 _cellText = tostring(_value, "#.#####") + "\n" + _text table.cell(_table, _column, _row, _cellText, bgcolor = color.new(_c_color, _transp), text_color = _c_color) // Only fill the cell data on the last bar on the chart (for optimization) if barstate.islast f_fillCell(resultTable, 0, 0, toWhole(averageMovement), syminfo.type == "forex" ? "Pip Change" : "Price Change")
Last Updated: 1st October, 2020