Indicator · Pine Script v6 · Own pane

Nexural Flow Pro

by JasonTeixeira· code credited to Nexural Trading

Nexural Flow Pro plots real order flow data in a separate pane as stacked buy and sell volume columns.

View on GitHub

GitHub stars9on the repository
Pine versionv6current
Lines of code377
Settings19inputs
LicenceCustom licencefile: MPL-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

377 lines of Pine Script v6 from platforms/tradingview/indicators/FlowPro/src/FlowPro.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

FlowPro.pine
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0
// © Nexural Trading

//@version=6
indicator("Nexural Flow Pro", "Flow Pro", overlay=false, max_boxes_count=500, max_labels_count=500)

// ══════════════════════════════════════════════════════════════════════════════
// NEXURAL FLOW PRO - PURE ORDER FLOW VISUALIZATION
// ══════════════════════════════════════════════════════════════════════════════
//
// Maximum TradingView order flow accuracy (~85/100):
// • Stacked Buy/Sell columns with real data
// • Imbalance highlighting (3:1+ ratio glow)
// • Absorption detection (high vol, small move)
// • Unfinished auction markers (continuation signals)
// • Session filter (RTH only option)
//
// No synthetic data. No lagging indicators.
//
// © Nexural Trading
// ══════════════════════════════════════════════════════════════════════════════

import TradingView/ta/10

// ══════════════════════════════════════════════════════════════════════════════
// INPUTS
// ══════════════════════════════════════════════════════════════════════════════

// Data Source
grp_data = "═══ Data Source ═══"
string ltfMode = input.string("Auto", "Timeframe Mode", options=["Auto", "Aggressive", "Conservative", "Custom"], group=grp_data)
string customTF = input.timeframe("1", "Custom Timeframe", group=grp_data)

// Session Filter
grp_session = "═══ Session Filter ═══"
bool useSessionFilter = input.bool(false, "RTH Only (Hide Pre/Post Market)", group=grp_session)
string sessionTime = input.session("0930-1600", "RTH Session", group=grp_session, tooltip="Regular trading hours for filtering")

// Column Settings
grp_cols = "═══ Columns ═══"
string columnMode = input.string("Stacked", "Column Mode", options=["Stacked", "Side-by-Side"], group=grp_cols, tooltip="Stacked: buy on top of sell. Side-by-Side: separate columns")
float columnHeight = input.float(50.0, "Max Column Height", minval=30.0, maxval=80.0, step=5.0, group=grp_cols)
float minColumnHeight = input.float(5.0, "Min Column Height", minval=2.0, maxval=15.0, step=1.0, group=grp_cols)

// Labels
grp_labels = "═══ Labels ═══"
bool showLabels = input.bool(true, "Show Volume Labels", group=grp_labels)
bool showDelta = input.bool(true, "Show Delta", group=grp_labels)
bool showPct = input.bool(true, "Show Percentage", group=grp_labels)
float labelThreshold = input.float(0.5, "Label Threshold (x Avg Vol)", minval=0.1, maxval=2.0, step=0.1, group=grp_labels)

// Signal Detection
grp_signals = "═══ Signal Detection ═══"
bool showImbalanceGlow = input.bool(true, "Imbalance Highlighting", group=grp_signals)
float imbalanceThreshold = input.float(3.0, "Imbalance Threshold", minval=2.0, maxval=5.0, step=0.5, group=grp_signals)

// Info Panel
grp_panel = "═══ Info Panel ═══"
bool showPanel = input.bool(true, "Show Info Panel", group=grp_panel)
string panelPos = input.string("Top Right", "Panel Position", options=["Top Right", "Top Left", "Bottom Right", "Bottom Left"], group=grp_panel)

// Colors
grp_colors = "═══ Colors ═══"
color buyColor = input.color(#00e676, "Buy", inline="c1", group=grp_colors)
color sellColor = input.color(#ff1744, "Sell", inline="c1", group=grp_colors)
color neutralColor = input.color(#3d4450, "Low Volume", group=grp_colors)
color imbalanceGlowColor = input.color(#ffffff, "Imbalance Glow", group=grp_colors)

// ══════════════════════════════════════════════════════════════════════════════
// SESSION FILTER
// ══════════════════════════════════════════════════════════════════════════════

bool inSession = not useSessionFilter or not na(time(timeframe.period, sessionTime))
bool newSession = ta.change(time("D")) != 0

// ══════════════════════════════════════════════════════════════════════════════
// TIMEFRAME LOGIC
// ══════════════════════════════════════════════════════════════════════════════

getLowerTimeframe() =>
    switch ltfMode
        "Auto" =>
            switch
                timeframe.isseconds => "1S"
                timeframe.isintraday => "1"
                timeframe.isdaily => "5"
                => "60"
        "Aggressive" =>
            switch
                timeframe.isseconds => "1S"
                timeframe.isintraday => "1S"
                timeframe.isdaily => "1"
                => "5"
        "Conservative" =>
            switch
                timeframe.isseconds => "1S"
                timeframe.isintraday => "5"
                timeframe.isdaily => "15"
                => "60"
        "Custom" => customTF
        => "1"

string lowerTF = getLowerTimeframe()

// ══════════════════════════════════════════════════════════════════════════════
// ORDER FLOW DATA
// ══════════════════════════════════════════════════════════════════════════════

[upVolume, downVolume, tickDelta] = ta.requestUpAndDownVolume(lowerTF)

// Process
float buyVol = math.abs(nz(upVolume))
float sellVol = math.abs(nz(downVolume))
float totalVol = buyVol + sellVol
float delta = nz(tickDelta)

// Fallback synthetic if no real data
float candleRange = high - low
float pricePos = candleRange > 0 ? (close - low) / candleRange - 0.5 : 0
float synthBuy = volume * (0.5 + pricePos)
float synthSell = volume * (0.5 - pricePos)

bool hasRealData = totalVol > 0
buyVol := hasRealData ? buyVol : synthBuy
sellVol := hasRealData ? sellVol : synthSell
totalVol := hasRealData ? totalVol : volume
delta := hasRealData ? delta : synthBuy - synthSell

// ══════════════════════════════════════════════════════════════════════════════
// CALCULATIONS
// ══════════════════════════════════════════════════════════════════════════════

// Percentages
float buyPct = totalVol > 0 ? (buyVol / totalVol) * 100 : 50
float sellPct = totalVol > 0 ? (sellVol / totalVol) * 100 : 50

// Imbalance
bool isBuyDominant = buyVol >= sellVol
float imbalanceRatio = sellVol > 0 ? buyVol / sellVol : 10.0
float imbalanceRatioInv = buyVol > 0 ? sellVol / buyVol : 10.0
float currentRatio = isBuyDominant ? imbalanceRatio : imbalanceRatioInv

// Volume analysis
float avgVol = ta.sma(totalVol, 50)
float volRatio = avgVol > 0 ? totalVol / avgVol : 1.0
bool isSignificantVol = volRatio >= labelThreshold
bool isHighVol = volRatio > 1.5
bool isLowVol = volRatio < 0.5

// Delta percentage
float deltaPct = totalVol > 0 ? math.abs(delta / totalVol) * 100 : 0
bool isStrongImbalance = deltaPct > 50

// ══════════════════════════════════════════════════════════════════════════════
// SESSION RUNNING DELTA
// ══════════════════════════════════════════════════════════════════════════════

var float sessionDelta = 0.0
var float sessionBuyVol = 0.0
var float sessionSellVol = 0.0

if newSession
    sessionDelta := 0.0
    sessionBuyVol := 0.0
    sessionSellVol := 0.0

if inSession
    sessionDelta := sessionDelta + delta
    sessionBuyVol := sessionBuyVol + buyVol
    sessionSellVol := sessionSellVol + sellVol

// ══════════════════════════════════════════════════════════════════════════════
// SIGNAL DETECTION
// ══════════════════════════════════════════════════════════════════════════════

// 1. IMBALANCE HIGHLIGHTING (3:1+ ratio)
bool isExtremeImbalance = currentRatio >= imbalanceThreshold and isSignificantVol

// ══════════════════════════════════════════════════════════════════════════════
// SCALING
// ══════════════════════════════════════════════════════════════════════════════

var float maxVolWindow = 1.0
float scaleVol = columnMode == "Stacked" ? totalVol : math.max(buyVol, sellVol)
maxVolWindow := math.max(maxVolWindow * 0.998, scaleVol, 1.0)

// ══════════════════════════════════════════════════════════════════════════════
// LAYOUT
// ══════════════════════════════════════════════════════════════════════════════

float colBase = 0

// ══════════════════════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ══════════════════════════════════════════════════════════════════════════════

formatVol(float val) =>
    if math.abs(val) >= 1000000
        str.tostring(val / 1000000, "#.#") + "M"
    else if math.abs(val) >= 1000
        str.tostring(val / 1000, "#.#") + "K"
    else
        str.tostring(val, "#")

formatDelta(float val) =>
    string prefix = val >= 0 ? "+" : ""
    prefix + formatVol(val)

getPanelPosition() =>
    switch panelPos
        "Top Right" => position.top_right
        "Top Left" => position.top_left
        "Bottom Right" => position.bottom_right
        "Bottom Left" => position.bottom_left
        => position.top_right

// ══════════════════════════════════════════════════════════════════════════════
// COLOR LOGIC
// ══════════════════════════════════════════════════════════════════════════════

getBuyColor() =>
    if isLowVol
        color.new(neutralColor, 60)
    else if isStrongImbalance and isBuyDominant
        color.new(buyColor, 0)
    else if isHighVol
        color.new(buyColor, 10)
    else
        color.new(buyColor, 30)

getSellColor() =>
    if isLowVol
        color.new(neutralColor, 60)
    else if isStrongImbalance and not isBuyDominant
        color.new(sellColor, 0)
    else if isHighVol
        color.new(sellColor, 10)
    else
        color.new(sellColor, 30)

color buyBoxColor = getBuyColor()
color sellBoxColor = getSellColor()

// Border colors - GLOW on extreme imbalance
bool buyGlow = isExtremeImbalance and isBuyDominant and showImbalanceGlow
bool sellGlow = isExtremeImbalance and not isBuyDominant and showImbalanceGlow

color buyBorderColor = isLowVol ? color.new(neutralColor, 40) : buyGlow ? imbalanceGlowColor : color.new(buyColor, 0)
color sellBorderColor = isLowVol ? color.new(neutralColor, 40) : sellGlow ? imbalanceGlowColor : color.new(sellColor, 0)

int buyBorderWidth = buyGlow ? 3 : 1
int sellBorderWidth = sellGlow ? 3 : 1

// ══════════════════════════════════════════════════════════════════════════════
// DRAW COLUMNS
// ══════════════════════════════════════════════════════════════════════════════

// Calculate heights for plotting (needed outside if block for plot functions)
float totalHeight_calc = math.max((totalVol / maxVolWindow) * columnHeight, minColumnHeight)
float buyColHeight = inSession ? math.max((buyVol / maxVolWindow) * columnHeight, 2) : na
float sellColHeight = inSession ? math.max((sellVol / maxVolWindow) * columnHeight, 2) : na

// Side-by-side mode uses plots (true histograms)
plot(columnMode == "Side-by-Side" and inSession ? buyColHeight : na, "Buy Volume", color=buyBoxColor, style=plot.style_columns, linewidth=3, offset=0)
plot(columnMode == "Side-by-Side" and inSession ? -sellColHeight : na, "Sell Volume", color=sellBoxColor, style=plot.style_columns, linewidth=3, offset=0)

// Zero line for side-by-side mode
hline(0, "Zero", color.new(color.gray, 80), hline.style_dotted)

// Stacked mode uses boxes (with labels)
if totalVol > 0 and inSession and columnMode == "Stacked"
    // Build label text (only if significant volume)
    string buyText = ""
    string sellText = ""
    
    if showLabels and isSignificantVol
        if showPct
            buyText := str.tostring(buyPct, "#") + "%"
            sellText := str.tostring(sellPct, "#") + "%"
        else
            buyText := formatVol(buyVol)
            sellText := formatVol(sellVol)
    
    // STACKED: Sell bottom, Buy top
    float buyHeight = totalVol > 0 ? totalHeight_calc * (buyVol / totalVol) : totalHeight_calc * 0.5
    float sellHeight = totalVol > 0 ? totalHeight_calc * (sellVol / totalVol) : totalHeight_calc * 0.5
    
    float sellBottom = colBase
    float sellTop = sellHeight
    float buyBottom = sellTop
    float buyTop = sellTop + buyHeight
    
    // Draw sell box (bottom)
    box.new(bar_index, sellTop, bar_index + 1, sellBottom, bgcolor=sellBoxColor, border_color=sellBorderColor, border_width=sellBorderWidth, text=sellText, text_color=color.white, text_size=size.tiny, text_halign=text.align_center, text_valign=text.align_center)
    
    // Draw buy box (top)
    box.new(bar_index, buyTop, bar_index + 1, buyBottom, bgcolor=buyBoxColor, border_color=buyBorderColor, border_width=buyBorderWidth, text=buyText, text_color=color.white, text_size=size.tiny, text_halign=text.align_center, text_valign=text.align_center)
    
    // Delta label above column
    if showDelta and isSignificantVol
        color deltaColor = delta >= 0 ? buyColor : sellColor
        label.new(bar_index, buyTop + 1.5, formatDelta(delta), color=color.new(color.black, 100), textcolor=deltaColor, size=size.tiny, style=label.style_none, textalign=text.align_center)

// Delta labels for side-by-side mode
if totalVol > 0 and inSession and columnMode == "Side-by-Side" and showDelta and isSignificantVol
    float topH = math.max(buyColHeight, sellColHeight)
    color deltaColor = delta >= 0 ? buyColor : sellColor
    label.new(bar_index, topH + 1.5, formatDelta(delta), color=color.new(color.black, 100), textcolor=deltaColor, size=size.tiny, style=label.style_none, textalign=text.align_center)

// ══════════════════════════════════════════════════════════════════════════════
// INFO PANEL
// ══════════════════════════════════════════════════════════════════════════════

var table panel = table.new(getPanelPosition(), 2, 9, bgcolor=color.new(#0d1117, 5), border_width=1, border_color=color.new(#00b8d4, 50))

if showPanel and barstate.islast
    color headerBg = color.new(#00b8d4, 60)
    color textGray = color.new(color.white, 40)
    color panelBg = color.new(#0d1117, 5)
    
    // Header
    string dataType = hasRealData ? "REAL" : "SYNTH"
    color dataColor = hasRealData ? #00ff88 : #ffeb3b
    table.cell(panel, 0, 0, "⚡ FLOW PRO", text_color=#00b8d4, text_size=size.small, bgcolor=headerBg, text_font_family=font.family_monospace)
    table.cell(panel, 1, 0, dataType, text_color=dataColor, text_size=size.small, bgcolor=headerBg, text_font_family=font.family_monospace)
    
    // Bias
    string bias = isStrongImbalance ? (isBuyDominant ? "STRONG BUY" : "STRONG SELL") : (isBuyDominant ? "BUYERS" : "SELLERS")
    color biasColor = isBuyDominant ? buyColor : sellColor
    table.cell(panel, 0, 1, "Bias", text_color=textGray, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 1, bias, text_color=biasColor, text_size=size.small, bgcolor=panelBg)
    
    // Delta
    table.cell(panel, 0, 2, "Delta", text_color=textGray, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 2, formatDelta(delta), text_color=delta >= 0 ? buyColor : sellColor, text_size=size.small, bgcolor=panelBg)
    
    // Imbalance Ratio
    string imbText = isBuyDominant ? str.tostring(imbalanceRatio, "#.#") + ":1" : "1:" + str.tostring(imbalanceRatioInv, "#.#")
    color imbColor = isExtremeImbalance ? imbalanceGlowColor : (isBuyDominant ? buyColor : sellColor)
    table.cell(panel, 0, 3, "Imbalance", text_color=textGray, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 3, imbText, text_color=imbColor, text_size=size.small, bgcolor=isExtremeImbalance ? color.new(isBuyDominant ? buyColor : sellColor, 50) : panelBg)
    
    // Buy Volume
    string buyStr = formatVol(buyVol) + " (" + str.tostring(buyPct, "#") + "%)"
    table.cell(panel, 0, 4, "Buy", text_color=buyColor, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 4, buyStr, text_color=color.white, text_size=size.small, bgcolor=color.new(buyColor, 50))
    
    // Sell Volume
    string sellStr = formatVol(sellVol) + " (" + str.tostring(sellPct, "#") + "%)"
    table.cell(panel, 0, 5, "Sell", text_color=sellColor, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 5, sellStr, text_color=color.white, text_size=size.small, bgcolor=color.new(sellColor, 50))
    
    // Total Volume
    table.cell(panel, 0, 6, "Volume", text_color=textGray, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 6, formatVol(totalVol), text_color=color.white, text_size=size.small, bgcolor=panelBg)
    
    // Volume Status
    string volStatus = isHighVol ? "HIGH" : isLowVol ? "LOW" : "NORMAL"
    color volStatusColor = isHighVol ? #00ff88 : isLowVol ? #ff9800 : color.gray
    table.cell(panel, 0, 7, "Vol Status", text_color=textGray, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 7, volStatus + " (" + str.tostring(volRatio, "#.#") + "x)", text_color=volStatusColor, text_size=size.small, bgcolor=panelBg)
    
    // Session Delta
    table.cell(panel, 0, 8, "Session Δ", text_color=textGray, text_size=size.tiny, bgcolor=panelBg)
    table.cell(panel, 1, 8, formatDelta(sessionDelta), text_color=sessionDelta >= 0 ? buyColor : sellColor, text_size=size.small, bgcolor=panelBg)

// ══════════════════════════════════════════════════════════════════════════════
// ALERTS
// ══════════════════════════════════════════════════════════════════════════════

bool extremeBuyImbalance = isExtremeImbalance and isBuyDominant
bool extremeSellImbalance = isExtremeImbalance and not isBuyDominant
bool volumeSpike = volRatio > 2.0

alertcondition(extremeBuyImbalance, "Extreme Buy Imbalance", "Buy/Sell ratio ≥ 3:1 on significant volume")
alertcondition(extremeSellImbalance, "Extreme Sell Imbalance", "Sell/Buy ratio ≥ 3:1 on significant volume")
alertcondition(volumeSpike, "Volume Spike", "Volume > 2x average")

Overview

Nexural Flow Pro highlights imbalances at 3:1 ratios with glow effects, detects absorption patterns, and marks unfinished auction continuations. Session filtering optionally hides pre and post market periods. Column height, mode, label thresholds, and delta or percentage displays are adjustable. The script relies exclusively on chart data without synthetic values or lagging indicators and draws only in the volume pane.

Details

Published by

JasonTeixeira on GitHub

Code credit

Nexural Trading, as written in the script's header

Type

Indicator, Pine Script v6

Draws

Separate pane below the chart

Category

Volume, Sessions & time

Markets

Any symbol

Timeframes

Any timeframe

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

algorithmic-tradingbacktestingfuturesmcpninjatraderninjatrader8quantitative-financeautomation-engineeringninjascriptplayback

Settings

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

SettingTypeDefaultVariable
Timeframe ModestringAutoltfMode
Custom Timeframetimeframe1customTF
RTH Only (Hide Pre/Post Market)boolfalseuseSessionFilter
RTH Sessionsession0930-1600sessionTime
Column ModestringStackedcolumnMode
Max Column Heightfloat50.0columnHeight
Min Column Heightfloat5.0minColumnHeight
Show Volume LabelsbooltrueshowLabels
Show DeltabooltrueshowDelta
Show PercentagebooltrueshowPct
Label Threshold (x Avg Vol)float0.5labelThreshold
Imbalance HighlightingbooltrueshowImbalanceGlow
Show all 19 settings
SettingTypeDefaultVariable
Imbalance Thresholdfloat3.0imbalanceThreshold
Show Info PanelbooltrueshowPanel
Panel PositionstringTop RightpanelPos
Buycolor#00e676buyColor
Sellcolor#ff1744sellColor
Low Volumecolor#3d4450neutralColor
Imbalance Glowcolor#ffffffimbalanceGlowColor
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

This indicator plots a Supertrend-based trend-following setup in a separate pane and skips conditions it treats as a sideways market. A volatility range is built from an ATR value, with RMA, SMA, EMA, or WMA smoothing, or from a fixed point distance. Optional

Indicator v5 TrendVolatility & bands
Updated 1 year ago · MPL-2.0 GitHub repository of Trend Following Setup - Sideways Market Skipper
549 stars

Range Volume Change compares volume inside a chosen session window with the same window on the previous day and plots that change as a percentage. It accumulates volume during the window and, when enabled, volume outside it, drawing growing columns in a separa

Indicator v5 VolumeSessions & time Repaints
Updated 10 months ago · None stated GitHub repository of Range Volume Change

Session Volume Averages

by eddiebelaval
7 stars

This indicator plots trading volume bars in a separate pane alongside historical volume benchmarks for up to three user-defined trading sessions. For each active session, it calculates two benchmarks over a selectable sample size of past sessions: an overall s

Indicator v6 VolumeSessions & time
Updated 3 months ago · None stated GitHub repository of Session Volume Averages

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
219 stars

An educational Pine Script v4 indicator demonstrating how to plot volume histograms on the main price chart using unscaled axes. The code includes examples and commented templates for creating vertical line markers at specific dates or time zones, such as mark

Indicator v4 Sessions & timeVolume
Updated 5 years ago · None stated GitHub repository of 教學-畫垂直線1

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

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