Indicator · Pine Script v6 · On the chart

Taught to Trade - Session Range & Value Area Map

by obekheet

This indicator calculates and plots key market profile structure from previous sessions, including Value Area High, Value Area Low, Point of Control, and session High/Low levels, alongside the current session's Opening Range.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code192
Settings13inputs
LicenceMPL-2.0
Last update12 days ago16 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

192 lines of Pine Script v6 from scripts/session-range-value-area-map.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

session-range-value-area-map.pine
//@version=6
// Taught to Trade - Session Range & Value Area Map
//
// The first decision-class tool in the suite. It marks structure that already happened:
// where the previous session actually traded, where most of its volume changed hands,
// and where the current session's first N minutes set their boundaries.
//
// Drawing where price traded yesterday is a fact, not a forecast. Nothing here predicts,
// ranks or scores anything, and no buy/sell signal is sent. Alerts are conditions you arm.
//
// All series reads happen at top level. The conditional blocks touch only arrays and vars.
indicator("Taught to Trade - Session Range & Value Area Map", shorttitle = "TT SESSION MAP",
     overlay = true, max_bars_back = 5000, max_lines_count = 1)

// ─────────────────────────────── Inputs ───────────────────────────────
grpS = "Session"
sessSpec = input.session("0930-1600", "Regular session", group = grpS,
     tooltip = "Exchange time. Use 0000-0000 for a 24-hour instrument, in which case the session boundary is the exchange day roll.")
orMin = input.int(30, "Opening range (minutes)", minval = 1, maxval = 480, group = grpS)

grpV = "Value area"
vaPct = input.float(70.0, "Value area (% of session volume)", minval = 50.0, maxval = 95.0, step = 5.0, group = grpV)
binsIn = input.int(50, "Profile resolution (bins)", minval = 10, maxval = 200, group = grpV,
     tooltip = "More bins give a finer profile and a noisier one. 50 is a common default.")

grpD = "Draw"
showVA = input.bool(true,  "Prior session value area (VAH / POC / VAL)", group = grpD)
showHL = input.bool(true,  "Prior session high / low", group = grpD)
showOR = input.bool(true,  "Opening range of the current session", group = grpD)
shadeVA = input.bool(true, "Shade the value area", group = grpD)
showTbl = input.bool(true, "Levels table", group = grpD)

colVA  = input.color(color.new(#2F6FED, 0),  "Value area high / low", group = grpD, inline = "c1")
colPOC = input.color(color.new(#F2A33C, 0),  "POC",                   group = grpD, inline = "c1")
colHL  = input.color(color.new(#8A94A6, 0),  "Prior high / low",      group = grpD, inline = "c2")
colOR  = input.color(color.new(#2E7D32, 0),  "Opening range",         group = grpD, inline = "c2")

// ─────────────────────────── Session detection ───────────────────────────
// Top-level series calls only.
tIn      = time(timeframe.period, sessSpec)
inSess   = not na(tIn)
newSess  = inSess and not inSess[1]
intraday = timeframe.isintraday

// ─────────────────────────── Session accumulators ───────────────────────────
var array<float> hiA = array.new<float>()
var array<float> loA = array.new<float>()
var array<float> vlA = array.new<float>()

var float sH = na
var float sL = na
var int   sStart = na

var float orH = na
var float orL = na

var float pVAH = na
var float pPOC = na
var float pVAL = na
var float pHi  = na
var float pLo  = na
var int   pBars = 0

// ─────────────────────────── Build and finalise ───────────────────────────
if intraday and inSess
    if newSess
        // Finalise the session that just ended, from what was collected during it.
        int n = array.size(vlA)
        if n > 0 and not na(sH) and not na(sL) and sH > sL and n <= 20000
            float binW = (sH - sL) / binsIn
            array<float> prof = array.new<float>(binsIn, 0.0)
            for i = 0 to n - 1
                float bh = array.get(hiA, i)
                float bl = array.get(loA, i)
                float bv = array.get(vlA, i)
                if bv > 0
                    int i0 = math.max(0, math.min(binsIn - 1, int((bl - sL) / binW)))
                    int i1 = math.max(0, math.min(binsIn - 1, int((bh - sL) / binW)))
                    float per = bv / (i1 - i0 + 1)
                    for j = i0 to i1
                        array.set(prof, j, array.get(prof, j) + per)

            float total = array.sum(prof)
            if total > 0
                int pocIdx = array.indexof(prof, array.max(prof))
                float target = total * vaPct / 100.0
                float acc = array.get(prof, pocIdx)
                int loI = pocIdx
                int hiI = pocIdx
                while acc < target and (loI > 0 or hiI < binsIn - 1)
                    float belowV = loI > 0 ? array.get(prof, loI - 1) : -1.0
                    float aboveV = hiI < binsIn - 1 ? array.get(prof, hiI + 1) : -1.0
                    if aboveV >= belowV
                        hiI += 1
                        acc += aboveV
                    else
                        loI -= 1
                        acc += belowV
                pPOC := sL + (pocIdx + 0.5) * binW
                pVAL := sL + loI * binW
                pVAH := sL + (hiI + 1) * binW
                pHi  := sH
                pLo  := sL
                pBars := n

        // Reset for the session that is starting.
        array.clear(hiA)
        array.clear(loA)
        array.clear(vlA)
        sH := high
        sL := low
        sStart := time
        orH := na
        orL := na
    else
        sH := math.max(nz(sH, high), high)
        sL := math.min(nz(sL, low), low)

    array.push(hiA, high)
    array.push(loA, low)
    array.push(vlA, nz(volume, 0.0))

    // Opening range: bars whose open time falls inside the first orMin minutes.
    if not na(sStart) and (time - sStart) < orMin * 60000
        orH := na(orH) ? high : math.max(orH, high)
        orL := na(orL) ? low  : math.min(orL, low)

// ─────────────────────────── Draw ───────────────────────────
bool live = intraday and inSess

pVAHp = plot(live and showVA ? pVAH : na, "Prior value area high", color = colVA, linewidth = 1, style = plot.style_linebr)
pVALp = plot(live and showVA ? pVAL : na, "Prior value area low",  color = colVA, linewidth = 1, style = plot.style_linebr)
fill(pVAHp, pVALp, color = shadeVA and showVA ? color.new(#2F6FED, 92) : na, title = "Value area")

plot(live and showVA ? pPOC : na, "Prior POC", color = colPOC, linewidth = 2, style = plot.style_linebr)
plot(live and showHL ? pHi  : na, "Prior session high", color = colHL, linewidth = 1, style = plot.style_linebr)
plot(live and showHL ? pLo  : na, "Prior session low",  color = colHL, linewidth = 1, style = plot.style_linebr)
plot(live and showOR ? orH  : na, "Opening range high", color = colOR, linewidth = 1, style = plot.style_linebr)
plot(live and showOR ? orL  : na, "Opening range low",  color = colOR, linewidth = 1, style = plot.style_linebr)

// ─────────────────────────── Table ───────────────────────────
bgCol  = color.new(#0E1526, 10)
txtCol = color.new(#E6EAF2, 0)
hdrCol = color.new(#2F6FED, 0)

var table t = table.new(position.bottom_right, 2, 7, border_width = 1, border_color = color.new(#2F6FED, 70))

f_num(float v) => na(v) ? "-" : str.tostring(v, format.mintick)
f_row(int r, string k, string v, color kc) =>
    table.cell(t, 0, r, k, text_color = txtCol, text_size = size.small, text_halign = text.align_left,  bgcolor = kc)
    table.cell(t, 1, r, v, text_color = txtCol, text_size = size.small, text_halign = text.align_right, bgcolor = bgCol)

if barstate.islast and showTbl
    if not intraday
        table.cell(t, 0, 0, "SESSION MAP", text_color = color.white, text_size = size.small, bgcolor = hdrCol)
        table.cell(t, 1, 0, "intraday only", text_color = color.white, text_size = size.small, bgcolor = hdrCol)
        f_row(1, "Timeframe", "needs an intraday chart", bgCol)
    else
        table.cell(t, 0, 0, "SESSION MAP", text_color = color.white, text_size = size.small, bgcolor = hdrCol)
        table.cell(t, 1, 0, sessSpec, text_color = color.white, text_size = size.small, bgcolor = hdrCol)
        f_row(1, "Prior VAH", f_num(pVAH), bgCol)
        f_row(2, "Prior POC", f_num(pPOC), bgCol)
        f_row(3, "Prior VAL", f_num(pVAL), bgCol)
        f_row(4, "Prior high / low", na(pHi) or na(pLo) ? "-" : f_num(pHi) + " / " + f_num(pLo), bgCol)
        f_row(5, "Open range", na(orH) or na(orL) ? "-" : f_num(orL) + " - " + f_num(orH), bgCol)
        f_row(6, "Bars in profile", pBars > 0 ? str.tostring(pBars) : "-", bgCol)

// ─────────────────── Alerts (conditions you arm yourself) ───────────────────
// Every ta.* call is evaluated at top level on every bar and stored, so its history
// stays consistent. Calling them inside the alertcondition expression would let the
// short-circuit skip bars and quietly corrupt the crossover state.
xUpVAH = ta.crossover(close, pVAH)
xDnVAL = ta.crossunder(close, pVAL)
xPOCcr = ta.cross(close, pPOC)
xUpOR  = ta.crossover(close, orH)
xDnOR  = ta.crossunder(close, orL)

alertcondition(not na(pVAH) and xUpVAH,
     title   = "Close crossed above the prior value area high",
     message = "Session Map: close crossed above the prior session's value area high.")
alertcondition(not na(pVAL) and xDnVAL,
     title   = "Close crossed below the prior value area low",
     message = "Session Map: close crossed below the prior session's value area low.")
alertcondition(not na(pPOC) and xPOCcr,
     title   = "Close crossed the prior POC",
     message = "Session Map: close crossed the prior session's point of control.")
alertcondition(not na(orH) and xUpOR,
     title   = "Close crossed above the opening range high",
     message = "Session Map: close crossed above the opening range high.")
alertcondition(not na(orL) and xDnOR,
     title   = "Close crossed below the opening range low",
     message = "Session Map: close crossed below the opening range low.")

Overview

User settings allow customization of session timeframes, opening range duration in minutes, volume percentage target, profile bin resolution, shading, and an optional on-chart levels dashboard table.

Details

Published by

obekheet on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Sessions & time, Support & resistance, Volume, Screeners & dashboards

Markets

Any symbol

Timeframes

M1-M5, M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

pine-scriptpinescripttechnical-analysistrading-indicatorstradingviewtradingview-indicators

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Regular sessionsession0930-1600sessSpec
Opening range (minutes)int30orMin
Value area (% of session volume)float70.0vaPct
Profile resolution (bins)int50binsIn
Prior session value area (VAH / POC / VAL)booltrueshowVA
Prior session high / lowbooltrueshowHL
Opening range of the current sessionbooltrueshowOR
Shade the value areabooltrueshadeVA
Levels tablebooltrueshowTbl
Value area high / lowcolorcolor.new(#2F6FED, 0)colVA
POCcolorcolor.new(#F2A33C, 0)colPOC
Prior high / lowcolorcolor.new(#8A94A6, 0)colHL
Show all 13 settings
SettingTypeDefaultVariable
Opening rangecolorcolor.new(#2E7D32, 0)colOR
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

575 stars

This indicator builds Market Profile Time Price Opportunity (TPO) structures across defined session timeframes directly on the main price chart. It visualizes the Point of Control (POC) and Value Area boundaries using dynamic box drawings. An integrated multi-

Indicator v5 Support & resistanceScreeners & dashboards
Updated 1 year ago · MPL-2.0 GitHub repository of Market Profile with Screener

VP

by dearvn
257 stars

This indicator calculates and plots a session-based volume profile directly on the price chart. It maps volume distribution across price levels, highlighting key structural reference points including the Point of Control, Value Area High, and Value Area Low. C

Indicator v5 VolumeSupport & resistance
Updated 6 weeks ago · None stated GitHub repository of VP

Golden Bullet Strategy

by TradersPost
218 stars

The Golden Bullet Strategy is an overlay signal indicator based on Smart Money Concepts and time-based liquidity models. It identifies liquidity sweeps of a designated reference session range during a specified hunt window. It then confirms Market Structure Sh

Indicator v6 SMC / ICT / price actionSessions & time
Updated 3 months ago · None stated GitHub repository of Golden Bullet Strategy

Session Edge Probabilities

by TraderOracle
61 stars

Session Edge Probabilities tracks eight session-based trading rules using statistical probabilities evaluated on historical chart data. It utilizes a fixed calculation timeframe to evaluate opening ranges, midnight levels, afternoon reversal windows, and price

Indicator v6 Sessions & timeScreeners & dashboards
Updated 9 days ago · None stated GitHub repository of Session Edge Probabilities
56 stars

This indicator marks forex trading sessions and opening ranges on the price chart. It can draw Sydney, Tokyo, Frankfurt, London, and New York session boxes or five- and fifteen-minute opening ranges, plus an optional opening channel and a day-open range. Day r

Indicator v5 Sessions & timeSupport & resistance Repaints
Updated 2 months ago · None stated GitHub repository of Day Trading Booster by DGT

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers