Indicator · Pine Script v6 · On the chart

Session Open Line

by piecioshka

This indicator draws a horizontal line across each session on the main price chart, anchoring to either the previous session close or the current session open.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code193
Settings14inputs
LicenceMIT
Last update10 days ago18 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

193 lines of Pine Script v6 from indicators/overlays/session-open-line/session-open-line.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

session-open-line.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Piotr Kowalski "piecioshka"
// Docs (EN): https://github.com/piecioshka/tradingview-pine-scripts/blob/main/indicators/overlays/session-open-line/session-open-line.md
// Docs (PL): https://github.com/piecioshka/tradingview-pine-scripts/blob/main/indicators/overlays/session-open-line/session-open-line.pl.md

//@version=6
// Draws a horizontal line at the session's reference level - from the first
// to the last bar of the session. By default the reference is the previous
// session's close, so the change matches the day change quoted against the
// prior close and opening gaps become visible; the 'Reference level' input
// switches it to the session open, measuring only what happened inside the
// session. A label shows the price change during the session (close vs the
// reference level) as a percent, as a difference in the instrument currency,
// or both - each part has its own checkbox. The 'Percent
// position' input decides where the label sits - above or below the line, or
// behind its end - and the choice applies consistently to completed sessions
// and to the ongoing one. During the ongoing session the value updates on
// every bar. Line and label colors depend on the sign of the change - up,
// down, or unchanged when the close sits exactly at the reference level - and
// the whole session is shaded with the same color (can be turned off). Alerts
// fire when the price crosses the line in either direction, and the
// reference level plus the session change (%) are exposed as hidden series -
// other scripts can use them as external sources. Works on intraday
// timeframes - on D and above every bar is its own session, so the indicator
// only shows a hint.
indicator('Session Open Line', overlay = true, max_lines_count = 500, max_labels_count = 500, max_boxes_count = 500)

refLevelName = input.string('Previous session close', 'Reference level', options = ['Previous session close', 'Session open'], group = 'General', tooltip = 'The level the line sits at and the change is measured from. Previous session close (default): the close of the last bar of the previous session - the change matches the day change quoted against the prior close, and an opening gap shows up as the distance between the line and the first candle. Session open: the open of the first bar of the session - the change measures only what happened inside the session. The first session in the loaded history has no previous close, so in the default mode it gets no line.')
showPct = input.bool(true, 'Show percent change', group = 'General', tooltip = 'Shows the session change as a percent of the reference level, e.g. +0.84%.')
showAbs = input.bool(false, 'Show change in instrument currency', group = 'General', tooltip = 'Shows the session change as a price difference (close minus the reference level) in the currency of the instrument, e.g. +12.50 USD. With both checkboxes on the label reads +0.84% (+12.50 USD).')
GRP = 'Appearance'
upColor = input.color(#26A69A, 'Up color', group = GRP)
downColor = input.color(#EF5350, 'Down color', group = GRP)
flatColor = input.color(#787B86, 'Unchanged color', group = GRP, tooltip = 'Used when the close sits exactly at the reference level - neither a rise nor a fall. Happens on the first bar of a session opening at the previous close, and on illiquid instruments.')
lineStyleName = input.string('Solid', 'Line style', options = ['Solid', 'Dashed', 'Dotted'], group = GRP)
lineWidth = input.int(1, 'Line width', minval = 1, maxval = 4, group = GRP)
textSizeName = input.string('Small', 'Text size', options = ['Auto', 'Tiny', 'Small', 'Normal', 'Large'], group = GRP)
pctPositionName = input.string('Behind the line', 'Percent position', options = ['Above the line', 'Below the line', 'Behind the line'], group = GRP, tooltip = 'Above the line: the value sits over the end of the line. Below the line: the value hangs under the end of the line. Behind the line: the value sits at the reference level, right of the line end, as if continuing it. The choice applies to both completed and ongoing sessions.')
GRP_BG = 'Session highlight'
showBg = input.bool(true, 'Highlight the whole session', group = GRP_BG, tooltip = 'Fills the entire session with a single color, decided by where the price stands against the reference level.')
bgUpColor = input.color(color.new(#26A69A, 90), 'Highlight up color', group = GRP_BG)
bgDownColor = input.color(color.new(#EF5350, 90), 'Highlight down color', group = GRP_BG)
bgFlatColor = input.color(color.new(#787B86, 90), 'Highlight unchanged color', group = GRP_BG)

usePrevClose = refLevelName == 'Previous session close'

lineStyle = switch lineStyleName
    'Dashed' => line.style_dashed
    'Dotted' => line.style_dotted
    => line.style_solid

textSize = switch textSizeName
    'Auto' => size.auto
    'Tiny' => size.tiny
    'Normal' => size.normal
    'Large' => size.large
    => size.small

// One position for every label the indicator draws — completed sessions and
// the ongoing one alike.
pctStyle = switch pctPositionName
    'Above the line' => label.style_label_lower_right
    'Below the line' => label.style_label_upper_right
    => label.style_label_left

// Both checkboxes off means no label at all.
showLabel = showPct or showAbs

// syminfo.currency is empty for some symbols (e.g. indices without a quote
// currency) - then the difference is shown as a bare number.
currencySuffix = not na(syminfo.currency) and syminfo.currency != '' ? ' ' + syminfo.currency : ''

fmtPct(float pct) =>
    (pct >= 0 ? '+' : '') + str.tostring(pct, '0.00') + '%'

fmtAbs(float delta) =>
    (delta >= 0 ? '+' : '') + str.tostring(delta, format.mintick) + currencySuffix

// Percent first, the currency difference in parentheses - or either one
// alone. An undefined percent (reference level at or below zero) falls back
// to the price difference, which stays meaningful at any price.
fmtChange(float delta, float pct) =>
    showPct and showAbs and not na(pct) ? fmtPct(pct) + ' (' + fmtAbs(delta) + ')' : showPct and not na(pct) ? fmtPct(pct) : fmtAbs(delta)

// label_lower_right - anchor at the bottom-right corner, the text sits above
// the line and does not stick out past the session end. label_upper_right -
// anchor at the top-right corner, the text hangs below the line, again inside
// the session. label_left - anchor on the left edge, the text sits at the
// reference level, to the right of the line end, as if continuing the line.
newLabel(int x, float y, float delta, float pct, color col, string sizeName, string labelStyle) =>
    label.new(x, y, fmtChange(delta, pct), xloc = xloc.bar_index, style = labelStyle, textcolor = col, color = color.new(color.black, 100), size = sizeName)

// Vertical bounds of the session highlight. TradingView silently skips boxes
// whose top/bottom lie extremely far from the price scale (measured on an
// instrument near 85: bounds of +-1e8 still draw, +-1e9 do not), so absurd
// constants like 1e17 produce boxes that exist but never render. Instead
// the bounds follow the price range of the loaded data - 100x that range
// above and below covers the full height of the pane at any realistic zoom
// while staying far inside the renderer's limits.
BG_PAD = 100.0
var float dataHigh = na
var float dataLow = na
if not na(high) and not na(low)
    dataHigh := na(dataHigh) ? high : math.max(dataHigh, high)
    dataLow := na(dataLow) ? low : math.min(dataLow, low)
bgPad = math.max(dataHigh - dataLow, syminfo.mintick) * BG_PAD
bgTop = dataHigh + bgPad
bgBottom = dataLow - bgPad

// time('D') changes on the first bar of the trading day, so it also works
// for sessions crossing midnight (e.g. futures).
newSession = timeframe.change('D')

var line ln = na
var label lb = na
var box bg = na
var float sessionRef = na

// The reference level of the session: its own open, or the close of the
// previous session (close[1] on the session's first bar). On the very first
// loaded bar close[1] is na - in 'Previous session close' mode the first
// session has no reference, so it draws nothing.
if timeframe.isintraday and (newSession or barstate.isfirst)
    sessionRef := usePrevClose ? close[1] : open
    lb := na
    if not na(sessionRef)
        ln := line.new(bar_index, sessionRef, bar_index, sessionRef, xloc = xloc.bar_index, color = flatColor, style = lineStyle, width = lineWidth)
        // One box per session instead of bgcolor(), which paints a single bar
        // and cannot be repainted later - a box spans the whole session and
        // keeps one color, corrected on every bar of that session. Box
        // 'extend' works on the time axis only, so the vertical coverage
        // comes from the bgTop/bgBottom bounds.
        bg := showBg ? box.new(bar_index, bgTop, bar_index, bgBottom, xloc = xloc.bar_index, border_color = color.new(color.black, 100), bgcolor = bgFlatColor) : na
    else
        ln := na
        bg := na

// The sign of the change comes from the price difference, not from the
// percent - for a reference level at or below zero (possible on futures
// spreads) the percent flips sign or loses meaning, the difference never
// does.
delta = close - sessionRef
pct = sessionRef > 0 ? delta / sessionRef * 100 : na
// Three states, not two: a close exactly at the reference level is neither a
// rise nor a fall and gets its own neutral color instead of being folded into
// one of them.
col = delta > 0 ? upColor : delta < 0 ? downColor : flatColor

if timeframe.isintraday and not na(ln)
    line.set_x2(ln, bar_index)
    line.set_color(ln, col)
    if not na(bg)
        box.set_right(bg, bar_index)
        box.set_bgcolor(bg, delta > 0 ? bgUpColor : delta < 0 ? bgDownColor : bgFlatColor)
    // The label follows the end of the line and updates on every bar of
    // the session.
    if showLabel
        if na(lb)
            lb := newLabel(bar_index, sessionRef, delta, pct, col, textSize, pctStyle)
        else
            label.set_x(lb, bar_index)
            label.set_text(lb, fmtChange(delta, pct))
            label.set_textcolor(lb, col)

if timeframe.isintraday
    // Boxes of earlier sessions were created while less data was loaded, so
    // their bounds are narrower - on the last bar bring every box to the
    // final bounds. Runs only when the bounds actually change.
    var float sweptTop = na
    if barstate.islast and (na(sweptTop) or bgTop != sweptTop)
        sweptTop := bgTop
        for b in box.all
            box.set_top(b, bgTop)
            box.set_bottom(b, bgBottom)
else
    if barstate.islast
        var table hint = table.new(position.top_right, 1, 1)
        table.cell(hint, 0, 0, 'Session Open Line: the indicator works on intraday timeframes', text_color = color.gray, text_size = size.small)

// A cross is only meaningful against the current session's line, so the
// first bar of a session - where the line jumps to the new reference - is
// excluded.
crossUp = ta.crossover(close, sessionRef)
crossDown = ta.crossunder(close, sessionRef)
alertOk = timeframe.isintraday and not newSession
alertcondition(alertOk and crossUp, 'Cross above the reference level', 'Price crossed above the session reference level (session open or previous session close)')
alertcondition(alertOk and crossDown, 'Cross below the reference level', 'Price crossed below the session reference level (session open or previous session close)')

// Hidden series - rows in the Data Window and external sources for other
// scripts (any input.source field): the reference level and the session
// change as a percent.
plot(timeframe.isintraday ? sessionRef : na, 'Reference level', display = display.data_window, editable = false)
plot(timeframe.isintraday ? pct : na, 'Session change %', display = display.data_window, editable = false)

Overview

Session Open Line displays session price performance through customizable labels showing percentage change, currency differences, or both. Background shading reflects whether current price is above, below, or equal to the reference mark. Key inputs toggle display metrics, adjust visual styling, and reposition text. The tool operates solely on intraday charts and triggers alerts when price crosses the reference line.

Details

Published by

piecioshka on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Sessions & time, Support & resistance

Markets

Any symbol

Timeframes

M15-H1, M1-M5

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

pinescriptpinescript-indicatorspinescript-strategiestradingtradingview

Settings

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

SettingTypeDefaultVariable
Reference levelstringPrevious session closerefLevelName
Show percent changebooltrueshowPct
Show change in instrument currencyboolfalseshowAbs
Up colorcolor#26A69AupColor
Down colorcolor#EF5350downColor
Unchanged colorcolor#787B86flatColor
Line stylestringSolidlineStyleName
Line widthint1lineWidth
Text sizestringSmalltextSizeName
Percent positionstringBehind the linepctPositionName
Highlight the whole sessionbooltrueshowBg
Highlight up colorcolorcolor.new(#26A69A, 90)bgUpColor
Show all 14 settings
SettingTypeDefaultVariable
Highlight down colorcolorcolor.new(#EF5350, 90)bgDownColor
Highlight unchanged colorcolorcolor.new(#787B86, 90)bgFlatColor
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
257 stars

This indicator plots auto trade signals for E-mini S&P 500 futures on the price chart. It computes an EMA200 filter along with day ETH RTH session levels and percentage-based entry zones. Signals trigger CALL or PUT cases when price crosses defined thresholds

Indicator v6 TrendSupport & resistance
Updated 6 weeks ago · None stated GitHub repository of Auto Trade Futures ES
219 stars

This indicator plots reference levels for previous daily high and low prices directly on the price chart. It requests daily timeframe data using the security function and plots the offset values as continuous lines, displaying resistance in red and support in

Indicator v4 Support & resistanceSessions & time
Updated 5 years ago · None stated GitHub repository of 昨日高低點標示

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

Moon Dev GEX Arrows

by moondevonyt
92 stars

This overlay indicator plots option strike walls and an optional session VWAP on the price chart for SPY or ES. It spaces major strikes by the selected instrument, draws a set number of strikes on each side, and marks wall-trap and sweep events after a cooldow

Indicator v5 Support & resistanceSessions & time
Updated 8 weeks ago · Custom licence GitHub repository of Moon Dev GEX Arrows

Key Levels

by cryptorife
75 stars

This indicator plots reference levels and session markers directly on the price chart. It calculates and draws lines for the daily open, weekly open, monthly open, previous day OHLC, and previous week extremes, along with a selectable day-of-week range and ini

Indicator v4 Support & resistanceSessions & time Repaints
Updated 3 years ago · GPL-3.0 GitHub repository of Key Levels

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