Indicator · Pine Script v6 · On the chart

Capital41 Opening Drive Playbook

by damianpitt· code credited to Capital41 | MIT License

This overlay indicator maps an opening drive for a chosen session, using the first 30 or 60 minutes.

View on GitHub

GitHub stars6on the repository
Pine versionv6current
Lines of code286
Settings13inputs
LicenceMIT
Last update8 weeks ago31 Aug 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

286 lines of Pine Script v6 from Capital41_ Opening Drive Playbook/Capital41_Opening_Drive_Playbook_v2.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

Capital41_Opening_Drive_Playbook_v2.pine
// Copyright (c) 2026 Capital41 | MIT License
// CAPITAL41 OPENING DRIVE PLAYBOOK v2

// What it does:
// - Builds a dynamic Opening Drive (first 30/60 min) from your chosen session.
// - Computes pace and relative volume so the drive can be read as slow/normal/fast.
// - Projects adaptive continuation lines (drive edge + VWAP deviation).
// - Projects adaptive fade lines (drive midpoint +/- sigma) for mean-revert targets.
// - Tracks session stats: gap size, overnight drift, and first pullback depth.
//
// v2 changes:
// - FIXED: Continuation and fade triggers gated by barstate.isconfirmed, so
//          markers and alerts fire on bar close instead of repainting when a
//          live close crosses a trigger line and pulls back.
//
// TradingView setup:
// 1) Open TradingView -> Pine Editor.
// 2) Paste this script, Save, and Add to chart.
// 3) Use intraday charts (5m-30m recommended).
// 4) Set session timezone/session hours to your market.
//
// Usage guide (30m/4h):
// - Strong drive = high pace + volume ratio > 1.0x.
// - Continuation lines are trigger zones for break-and-go behavior.
// - Fade lines are mean-reversion targets when extension starts failing.
// - Use pullback depth to size risk after first breakout.



//@version=6
indicator("Capital41 Opening Drive Playbook v2", overlay = true, max_boxes_count = 80, max_labels_count = 100, max_lines_count = 80)

// Inputs
useExchangeTz = input.bool(false, "Use exchange timezone")
sessTz = input.string("America/New_York", "Session timezone",
                      options = ["America/New_York", "America/Chicago", "Etc/UTC", "Europe/London", "Asia/Tokyo"])
sessTimes = input.session("0930-1600", "Session times")


driveMinutes = input.int(30, "Opening drive minutes", options = [30, 60])
volAvgSessions = input.int(20, "Drive volume average sessions", minval = 5, maxval = 100)
sigmaLen = input.int(20, "Sigma length", minval = 5, maxval = 100)

contMult = input.float(1.0, "Continuation multiplier", minval = 0.1, maxval = 3.0)
fadeSigmaMult = input.float(1.0, "Fade sigma multiplier", minval = 0.1, maxval = 3.0)

showDriveBox = input.bool(true, "Show opening drive box")
showDriveLevels = input.bool(true, "Show drive levels")
showTriggerLines = input.bool(true, "Show continuation/fade lines")
showSessionVWAP = input.bool(true, "Show session VWAP")
showStats = input.bool(true, "Show stats badge")

colorDrive = color.new(color.blue, 88)
colorContUp = color.new(color.lime, 0)
colorContDn = color.new(color.red, 0)
colorFade = color.new(color.orange, 0)


f_arrayAvg(_arr) =>
    sz = array.size(_arr)
    if sz == 0
        na
    else
        s = 0.0
        for i = 0 to sz - 1
            s += array.get(_arr, i)
        s / sz

// Session state
inSession = useExchangeTz ? not na(time(timeframe.period, sessTimes)) : not na(time(timeframe.period, sessTimes, sessTz))
newSession = inSession and not inSession[1]
sessionEnded = not inSession and inSession[1]

// Persistent state
var float sessOpen = na
var float prevSessionClose = na
var float overnightDrift = na
var float gapSize = na
var int sessStartTime = na

var float driveHigh = na
var float driveLow = na
var float driveRange = na
var float driveMid = na
var float driveVol = na
var float drivePace = na
var float driveVolRatio = na
var bool driveLocked = false
var float contUpper = na
var float contLower = na
var float fadeUpper = na
var float fadeLower = na
var float firstPullbackDepth = na
var bool breakoutSeen = false
var int breakoutDir = 0
var float breakoutExtreme = na
var float cumPV = 0.0
var float cumV = 0.0
var box driveBox = na
var float[] histDriveVol = array.new_float()

priorDayClose = request.security(syminfo.tickerid, "D", close[1])

if sessionEnded
    prevSessionClose := close[1]
    if not na(driveBox)
        box.set_right(driveBox, bar_index)

if newSession
    sessOpen := open
    sessStartTime := time

    overnightDrift := not na(prevSessionClose) ? sessOpen - prevSessionClose : na
    gapSize := not na(priorDayClose) ? sessOpen - priorDayClose : na

    driveHigh := na
    driveLow := na
    driveRange := na
    driveMid := na
    driveVol := 0.0
    drivePace := na
    driveVolRatio := na
    driveLocked := false

    contUpper := na
    contLower := na
    fadeUpper := na
    fadeLower := na

    firstPullbackDepth := na
    breakoutSeen := false
    breakoutDir := 0
    breakoutExtreme := na

    cumPV := 0.0
    cumV := 0.0

    if showDriveBox
        driveBox := box.new(left = bar_index, right = bar_index + 1, top = high, bottom = low, border_width = 0, bgcolor = colorDrive)
    else
        driveBox := na

if inSession
    tp = hlc3
    cumPV += tp * volume
    cumV += volume


sessionVwap = cumV > 0 ? cumPV / cumV : na

elapsedMin = inSession and not na(sessStartTime) ? (time - sessStartTime) / 60000.0 : na
insideDrive = inSession and not driveLocked and not na(elapsedMin) and elapsedMin < driveMinutes

if insideDrive
    driveHigh := na(driveHigh) ? high : math.max(driveHigh, high)
    driveLow := na(driveLow) ? low : math.min(driveLow, low)
    driveVol += volume

    if showDriveBox and not na(driveBox)
        box.set_top(driveBox, driveHigh)
        box.set_bottom(driveBox, driveLow)
        box.set_right(driveBox, bar_index + 1)

if inSession and not driveLocked and not na(elapsedMin) and elapsedMin >= driveMinutes and not na(driveHigh) and not na(driveLow)
    driveLocked := true

    driveRange := driveHigh - driveLow
    driveMid := (driveHigh + driveLow) * 0.5

    sigma = ta.stdev(close, sigmaLen)
    vwapDev = not na(sessionVwap) ? math.abs(driveMid - sessionVwap) : driveRange * 0.25
    contOffset = math.max(vwapDev, driveRange * 0.15) * contMult

    contUpper := driveHigh + contOffset
    contLower := driveLow - contOffset

    fadeUpper := driveMid + sigma * fadeSigmaMult
    fadeLower := driveMid - sigma * fadeSigmaMult

    drivePace := driveMinutes > 0 ? driveRange / driveMinutes : na
    avgDriveVol = f_arrayAvg(histDriveVol)
    driveVolRatio := not na(avgDriveVol) and avgDriveVol > 0 ? driveVol / avgDriveVol : na

    array.push(histDriveVol, driveVol)
    if array.size(histDriveVol) > volAvgSessions
        array.shift(histDriveVol)


if inSession and driveLocked
    if not breakoutSeen
        if high > driveHigh
            breakoutSeen := true
            breakoutDir := 1
            breakoutExtreme := high
            firstPullbackDepth := 0.0
        else if low < driveLow
            breakoutSeen := true
            breakoutDir := -1
            breakoutExtreme := low
            firstPullbackDepth := 0.0
    else
        if breakoutDir == 1
            breakoutExtreme := math.max(breakoutExtreme, high)
            retrace = breakoutExtreme - low
            firstPullbackDepth := math.max(firstPullbackDepth, retrace)
        else if breakoutDir == -1
            breakoutExtreme := math.min(breakoutExtreme, low)
            retrace = high - breakoutExtreme
            firstPullbackDepth := math.max(firstPullbackDepth, retrace)

// Plot lines
plot(showSessionVWAP and inSession ? sessionVwap : na, title = "Session VWAP", color = color.new(color.blue, 0), linewidth = 2)

plot(showDriveLevels and inSession ? driveHigh : na, title = "Drive High", color = color.new(color.green, 25), linewidth = 1, style = plot.style_linebr)
plot(showDriveLevels and inSession ? driveLow : na, title = "Drive Low", color = color.new(color.red, 25), linewidth = 1, style = plot.style_linebr)

plot(showTriggerLines and inSession and driveLocked ? contUpper : na, title = "Continuation Upper", color = colorContUp, linewidth = 2, style = plot.style_linebr)
plot(showTriggerLines and inSession and driveLocked ? contLower : na, title = "Continuation Lower", color = colorContDn, linewidth = 2, style = plot.style_linebr)

plot(showTriggerLines and inSession and driveLocked ? fadeUpper : na, title = "Fade Upper", color = color.new(colorFade, 15), linewidth = 1, style = plot.style_linebr)
plot(showTriggerLines and inSession and driveLocked ? fadeLower : na, title = "Fade Lower", color = color.new(colorFade, 15), linewidth = 1, style = plot.style_linebr)

// Crosses are hoisted so ta.* runs every bar and is never short-circuited
contUpCross = ta.crossover(close, contUpper)
contDnCross = ta.crossunder(close, contLower)

// Triggers (confirmed: a live close can cross a line and fall back before close)
contLong      = inSession and driveLocked and barstate.isconfirmed and contUpCross
contShort     = inSession and driveLocked and barstate.isconfirmed and contDnCross
fadeUpTouch   = inSession and driveLocked and barstate.isconfirmed and high >= fadeUpper and high[1] < fadeUpper
fadeDownTouch = inSession and driveLocked and barstate.isconfirmed and low <= fadeLower and low[1] > fadeLower

plotshape(contLong, title = "Continuation Long", style = shape.triangleup,
          location = location.belowbar, color = colorContUp, size = size.tiny, text = "C")

plotshape(contShort, title = "Continuation Short", style = shape.triangledown,
          location = location.abovebar, color = colorContDn, size = size.tiny, text = "C")

plotshape(fadeUpTouch, title = "Fade Upper Touch", style = shape.circle,
          location = location.abovebar, color = color.new(colorFade, 0), size = size.tiny, text = "F")

plotshape(fadeDownTouch, title = "Fade Lower Touch", style = shape.circle,
          location = location.belowbar, color = color.new(colorFade, 0), size = size.tiny, text = "F")


// Stats badge
var table stats = table.new(position.bottom_right, 2, 7, border_width = 1)
if barstate.islast
    if showStats
        stateText = not inSession ? "OUT" : driveLocked ? "POST-DRIVE" : "OPEN-DRIVE"
        rangeText = not na(driveRange) ? str.tostring(driveRange, "#.####") : "na"
        paceText = not na(drivePace) ? str.tostring(drivePace, "#.####") : "na"
        volText = not na(driveVolRatio) ? str.tostring(driveVolRatio, "#.00") + "x" : "na"
        gapText = not na(gapSize) ? str.tostring(gapSize, "#.####") : "na"
        onText = not na(overnightDrift) ? str.tostring(overnightDrift, "#.####") : "na"
        pullText = not na(firstPullbackDepth) ? str.tostring(firstPullbackDepth, "#.####") : "na"

        table.cell(stats, 0, 0, "State", bgcolor = color.new(color.black, 0), text_color = color.white, text_size = size.tiny)
        table.cell(stats, 1, 0, stateText, bgcolor = color.new(color.gray, 70), text_color = color.white, text_size = size.tiny)

        table.cell(stats, 0, 1, "Drive Range", bgcolor = color.new(color.black, 0), text_color = color.white, text_size = size.tiny)
        table.cell(stats, 1, 1, rangeText, bgcolor = color.new(color.blue, 78), text_color = color.white, text_size = size.tiny)

        table.cell(stats, 0, 2, "Pace", bgcolor = color.new(color.black, 0), text_color = color.white, text_size = size.tiny)
        table.cell(stats, 1, 2, paceText, bgcolor = color.new(color.blue, 82), text_color = color.white, text_size = size.tiny)

        table.cell(stats, 0, 3, "Drive Vol", bgcolor = color.new(color.black, 0), text_color = color.white, text_size = size.tiny)
        table.cell(stats, 1, 3, volText, bgcolor = color.new(color.orange, 76), text_color = color.white, text_size = size.tiny)

        table.cell(stats, 0, 4, "Gap Size", bgcolor = color.new(color.black, 0), text_color = color.white, text_size = size.tiny)
        table.cell(stats, 1, 4, gapText, bgcolor = color.new(color.purple, 74), text_color = color.white, text_size = size.tiny)

        table.cell(stats, 0, 5, "ON Drift", bgcolor = color.new(color.black, 0), text_color = color.white, text_size = size.tiny)
        table.cell(stats, 1, 5, onText, bgcolor = color.new(color.purple, 80), text_color = color.white, text_size = size.tiny)

        table.cell(stats, 0, 6, "1st Pullback", bgcolor = color.new(color.black, 0), text_color = color.white, text_size = size.tiny)
        table.cell(stats, 1, 6, pullText, bgcolor = color.new(color.gray, 72), text_color = color.white, text_size = size.tiny)
    else
        for r = 0 to 6
            table.cell(stats, 0, r, "", bgcolor = color.new(color.black, 100), text_color = color.new(color.black, 100))
            table.cell(stats, 1, r, "", bgcolor = color.new(color.black, 100), text_color = color.new(color.black, 100))

alertcondition(contLong, title = "Continuation Long", message = "Opening Drive: continuation long trigger on {{ticker}} ({{interval}})")
alertcondition(contShort, title = "Continuation Short", message = "Opening Drive: continuation short trigger on {{ticker}} ({{interval}})")
alertcondition(fadeUpTouch, title = "Fade Upper Touch", message = "Opening Drive: fade upper touch on {{ticker}} ({{interval}})")
alertcondition(fadeDownTouch, title = "Fade Lower Touch", message = "Opening Drive: fade lower touch on {{ticker}} ({{interval}})")

Overview

Capital41 Opening Drive Playbook tracks drive high, low, midpoint, range, pace, and volume versus a multi-session average, then projects continuation lines from the drive edge and fade lines around the midpoint using a sigma band. It also plots session VWAP and a stats badge for gap size, overnight drift, and first pullback depth. Session timezone, hours, and display toggles control the layout. Confirmed-bar gating keeps markers and alerts from changing on the live bar.

Details

Published by

damianpitt on GitHub

Code credit

Capital41 | MIT License, as written in the script's header

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Sessions & time, Support & resistance, Volume, Volatility & bands

Markets

Stocks, Crypto

Timeframes

M1-M5, M15-H1, H4 and above

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

cryptoindicatorsmarket-structureorder-blockspinescriptsmart-moneytechnical-analysistechnical-analysis-indicatorstradingtradingview

Settings

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

SettingTypeDefaultVariable
Use exchange timezoneboolfalseuseExchangeTz
Session timezonestringAmerica/New_YorksessTz
Session timessession0930-1600sessTimes
Opening drive minutesint30driveMinutes
Drive volume average sessionsint20volAvgSessions
Sigma lengthint20sigmaLen
Continuation multiplierfloat1.0contMult
Fade sigma multiplierfloat1.0fadeSigmaMult
Show opening drive boxbooltrueshowDriveBox
Show drive levelsbooltrueshowDriveLevels
Show continuation/fade linesbooltrueshowTriggerLines
Show session VWAPbooltrueshowSessionVWAP
Show all 13 settings
SettingTypeDefaultVariable
Show stats badgebooltrueshowStats
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

LoD Intraday Entry

by ChartsLector
41 stars

This overlay indicator marks the current day's low and a suggested entry zone a fraction of daily ATR below that low. It compares daily volume with a volume moving average, plots daily SMA and EMA distance, and draws an optional ATR-width price cloud. Labels c

Indicator v6 Support & resistanceVolatility & bands
Updated 2 days ago · None stated GitHub repository of LoD Intraday Entry

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

Midnight VWAP

by TradersPost
218 stars

The Midnight VWAP indicator calculates and overlays two distinct Volume Weighted Average Price (VWAP) lines on the price chart based on customizable session timeframes. It tracks an overnight or pre-market session alongside regular trading hours, resetting cal

Indicator v6 Moving averagesSessions & time
Updated 3 months ago · None stated GitHub repository of Midnight VWAP

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

D/W/M VWAPs

by cryptorife
75 stars

This indicator plots daily, weekly, and monthly volume-weighted average prices on the price chart, using a selectable source that defaults to hlc3. For each enabled period it also draws two standard-deviation bands around the VWAP, with multipliers defaulting

Indicator v4 VolumeVolatility & bands
Updated 3 years ago · GPL-3.0 GitHub repository of D/W/M VWAPs
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