An indicator that draws a Dynamic P0 line on the price chart: a rolling volume-weighted equilibrium price computed over a window set in minutes, with a value area band around it.
1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.
Source Code
611 lines of Pine Script v6 from Dynamic_P0_Architecture_Dashboard.pine, published under GPL-3.0. Keep the author's credit and licence lines when you reuse it.
Dynamic_P0_Architecture_Dashboard.pine
//@version=6
indicator(
title = "Dynamic P0 + Architecture Dashboard",
shorttitle = "Dynamic P0 Dashboard",
overlay = true,
max_labels_count = 50,
max_lines_count = 50
)
//=============================================================================
// WHAT THIS IS
//-----------------------------------------------------------------------------
// A trimmed-down INDICATOR extracted from P0_Delta_DBR_ChangePoint_Merged_
// Strategy.pine, containing ONLY the two pieces requested:
// - The Dynamic P0 line (+ its Value Area band) -- a rolling, volume-
// weighted equilibrium price, recomputed every bar over a lookback
// window sized in real minutes (Equilibrium Window), not bars.
// - The Architecture dashboard table -- the same Acceptance/Rejection
// scoring readout as the merged strategy (rows 0-9 there), built from
// P0 migration/catch-up, new-location volume, value-area migration,
// delta alignment/persistence, price/delta efficiency, dwell/return,
// and profile coherence.
//
// Everything else from the merged strategy -- the Structural Profile (POC/
// VAH/VAL/Support/Resistance/Liquidity Zones), the Anchor Trail entry
// engine, the whole DBR Change-Point engine (CUSUM/MTF/retest/DeltaFlow),
// and all order/alert logic -- is NOT here. This is a pure indicator: no
// strategy.entry/exit calls, no alertcondition()s, nothing that places or
// simulates a trade. It only computes and displays.
//
// Pine does not expose native bid/ask aggressor volume here. Delta is
// estimated from OHLCV candle pressure, same as in the merged strategy.
//=============================================================================
//=============================================================================
// 01 — Master Visibility
//=============================================================================
string G_MASTER = "01 — Master Visibility"
bool showAllChartObjectsInput = input.bool(true, "Show All Chart Objects", tooltip = "Master switch for everything this script draws on the chart pane -- the Dynamic P0 line, its Value Area fill, the P0 label, and the Architecture dashboard table. Uncheck to hide all of it at once instead of unticking every individual 'Show ...' toggle below.", group = G_MASTER)
//=============================================================================
// 02 — Dynamic P0
//=============================================================================
string G_P0 = "02 — Dynamic P0"
int equilibriumMinutes = input.int(240, "Equilibrium Window (Minutes)", minval = 60, maxval = 1440, step = 30, tooltip = "Measured in real minutes, not bars. On a fast chart timeframe this can be a very large number of bars (e.g. 240 minutes = 120 bars on a 2-minute chart) -- if P0 and the dashboard feel sluggish/unresponsive, lower this to something proportionate to your chart's timeframe.", group = G_P0)
int equilibriumRows = input.int(32, "Dynamic P0 Price Rows", minval = 16, maxval = 64, group = G_P0)
int maximumEquilibriumBars = input.int(500, "Maximum Bars In Dynamic Profile", minval = 50, maxval = 1000, group = G_P0)
float dynamicValueAreaPercent = input.float(70.0, "Dynamic Value Area %", minval = 50.0, maxval = 95.0, step = 1.0, group = G_P0)
int coherenceRadius = input.int(2, "P0 Coherence Radius (Rows)", minval = 1, maxval = 5, group = G_P0)
float equilibriumBandATR = input.float(0.35, "Equilibrium Band (ATR)", minval = 0.10, maxval = 1.0, step = 0.05, group = G_P0)
float minimumDistanceATR = input.float(0.80, "Minimum Meaningful Displacement (ATR)", minval = 0.25, maxval = 3.0, step = 0.05, tooltip = "Minimum distance from P0 (in ATR) before the dashboard's TOTAL/marketState read treats price as meaningfully displaced at all. Purely informational here -- there is no entry engine in this file for it to gate.", group = G_P0)
//=============================================================================
// 03 — Acceptance / Rejection Metrics
//=============================================================================
string G_METRICS = "03 — Acceptance / Rejection Metrics"
int migrationLookback = input.int(4, "P0 / Value Migration Lookback", minval = 1, maxval = 20, group = G_METRICS)
float migrationTargetATR = input.float(0.15, "Strong P0 Migration (ATR)", minval = 0.02, maxval = 1.0, step = 0.01, group = G_METRICS)
float catchUpTargetPercent = input.float(40.0, "Strong P0 Catch-Up %", minval = 10.0, maxval = 100.0, step = 5.0, group = G_METRICS)
float newLocationBandATR = input.float(0.25, "New-Location Volume Band (ATR)", minval = 0.10, maxval = 1.0, step = 0.05, group = G_METRICS)
float newLocationTargetPercent = input.float(35.0, "Strong New-Location Volume %", minval = 10.0, maxval = 80.0, step = 5.0, group = G_METRICS)
int newLocationRecentBars = input.int(20, "New-Location Recency Window (Bars)", minval = 3, maxval = 100, tooltip = "New-Location Volume only counts volume from the most recent N bars, not the entire multi-hour rolling profile -- measures whether volume is NEWLY piling in at the current price right now.", group = G_METRICS)
float valueMigrationTargetATR = input.float(0.10, "Strong Value-Area Migration (ATR)", minval = 0.02, maxval = 1.0, step = 0.01, group = G_METRICS)
int deltaWindow = input.int(3, "Delta State Window", minval = 1, maxval = 10, group = G_METRICS)
int deltaPersistenceBars = input.int(3, "Delta Persistence Bars", minval = 2, maxval = 8, group = G_METRICS)
float alignedDeltaTarget = input.float(20.0, "Strong Aligned Delta %", minval = 5.0, maxval = 80.0, step = 1.0, group = G_METRICS)
float opposingDeltaTarget = input.float(20.0, "Strong Opposing Delta %", minval = 5.0, maxval = 80.0, step = 1.0, group = G_METRICS)
int efficiencyLookback = input.int(3, "Efficiency Lookback", minval = 1, maxval = 10, group = G_METRICS)
float efficiencyTargetATR = input.float(0.30, "Efficient Price Progress (ATR)", minval = 0.05, maxval = 1.50, step = 0.05, group = G_METRICS)
float absorptionDeltaTarget = input.float(25.0, "Absorption Delta Magnitude %", minval = 5.0, maxval = 100.0, step = 1.0, group = G_METRICS)
float absorptionMaximumProgressATR = input.float(0.12, "Absorption Maximum Price Progress (ATR)", minval = 0.02, maxval = 0.50, step = 0.01, group = G_METRICS)
int dwellMeasurementBars = input.int(4, "Dwell Measurement Bars", minval = 2, maxval = 12, group = G_METRICS)
float minimumCoherence = input.float(55.0, "Minimum Profile Coherence", minval = 0.0, maxval = 100.0, step = 1.0, group = G_METRICS)
float acceptanceThresholdLong = input.float(65.0, "Acceptance Score Threshold (Long)", minval = 40.0, maxval = 95.0, step = 1.0, tooltip = "Tunes only when the dashboard's TOTAL/marketState reads a BULLISH acceptance as dominant. There is no entry engine here for it to gate.", group = G_METRICS)
float acceptanceThresholdShort = input.float(65.0, "Acceptance Score Threshold (Short)", minval = 40.0, maxval = 95.0, step = 1.0, group = G_METRICS)
float rejectionThresholdLong = input.float(50.0, "Rejection Score Threshold (Long)", minval = 40.0, maxval = 95.0, step = 1.0, group = G_METRICS)
float rejectionThresholdShort = input.float(50.0, "Rejection Score Threshold (Short)", minval = 40.0, maxval = 95.0, step = 1.0, group = G_METRICS)
float scoreDominanceLong = input.float(24.0, "Required Score Dominance (Long)", minval = 0.0, maxval = 40.0, step = 1.0, group = G_METRICS)
float scoreDominanceShort = input.float(24.0, "Required Score Dominance (Short)", minval = 0.0, maxval = 40.0, step = 1.0, group = G_METRICS)
float signalStabilityMargin = input.float(0.0, "Signal Stability Margin", minval = 0.0, maxval = 20.0, step = 0.5, group = G_METRICS)
//=============================================================================
// 04 — P0 / Key Levels
//=============================================================================
string G_STYLE = "04 — P0 / Key Levels"
bool showDynamicP0 = input.bool(true, "Show Dynamic P0", group = G_STYLE)
bool showDynamicP0LabelInput = input.bool(true, "Label The Dynamic P0 Line", group = G_STYLE)
color dynamicP0Color = input.color(color.aqua, "Dynamic P0 Color", group = G_STYLE)
int dynamicP0Width = input.int(3, "Dynamic P0 Width", minval = 1, maxval = 5, group = G_STYLE)
bool showDynamicValueArea = input.bool(true, "Show Dynamic VAH / VAL", group = G_STYLE)
color dynamicValueAreaColor = input.color(color.rgb(70, 115, 255), "Dynamic Value Area Color", group = G_STYLE)
//=============================================================================
// 05 — Architecture Dashboard
//=============================================================================
string G_DASH = "05 — Architecture Dashboard"
bool showArchitectureHistogram = input.bool(true, "Show Acceptance / Rejection Dashboard", group = G_DASH)
string architecturePosition = input.string("Top Right", "Position", options = ["Top Left", "Top Right", "Bottom Left", "Bottom Right"], group = G_DASH)
string dashboardTextSize = input.string("Small", "Dashboard Text Size", options = ["Tiny", "Small", "Normal", "Large", "Huge"], group = G_DASH)
bool showLiveColumnInput = input.bool(false, "Show LIVE Value Column", group = G_DASH)
color acceptanceColor = input.color(color.rgb(0, 200, 140), "Acceptance Color", group = G_DASH)
color rejectionColor = input.color(color.rgb(245, 75, 85), "Rejection Color", group = G_DASH)
//=============================================================================
// HELPERS
//=============================================================================
f_clamp(float value, float lowValue, float highValue) =>
math.max(lowValue, math.min(highValue, value))
f_delta(float o, float h, float l, float c, float v) =>
float safeRange = math.max(h - l, syminfo.mintick)
float pressure = f_clamp((c - o) / safeRange, -1.0, 1.0)
v * pressure
f_score(float value, float target) =>
target <= 0 ? 0.0 : f_clamp(value / target * 100.0, 0.0, 100.0)
f_price(float value) =>
na(value) ? "—" : str.tostring(value, format.mintick)
f_pct(float value) =>
na(value) ? "—" : str.tostring(value, "#.0") + "%"
f_bar(float value) =>
int filled = int(math.round(f_clamp(value, 0.0, 100.0) / 10.0))
string result = ""
for i = 1 to 10
result += i <= filled ? "█" : "·"
result
f_rowVerdict(float acceptValue, float rejectValue, string acceptWord, string rejectWord, string neutralWord) => acceptValue >= rejectValue + 15.0 ? acceptWord : rejectValue >= acceptValue + 15.0 ? rejectWord : neutralWord
f_dashboardSize(string sizeName) =>
(sizeName == "Tiny" ? size.tiny :
sizeName == "Normal" ? size.normal :
sizeName == "Large" ? size.large :
sizeName == "Huge" ? size.huge :
size.small)
//=============================================================================
// DYNAMIC P0 PROFILE
//=============================================================================
float atr = math.max(nz(ta.atr(14), ta.tr(true)), syminfo.mintick)
float timeframeSeconds = nz(timeframe.in_seconds(timeframe.period), 60.0)
int equilibriumBarsRaw = int(math.ceil(equilibriumMinutes * 60.0 / timeframeSeconds))
int equilibriumBars = math.max(4, math.min(maximumEquilibriumBars, equilibriumBarsRaw))
float equilibriumHigh = ta.highest(high, equilibriumBars)
float equilibriumLow = ta.lowest(low, equilibriumBars)
float equilibriumStep = math.max((equilibriumHigh - equilibriumLow) / equilibriumRows, syminfo.mintick)
array<float> dynamicTotal = array.new_float(equilibriumRows, 0.0)
array<float> dynamicBuy = array.new_float(equilibriumRows, 0.0)
array<float> dynamicSell = array.new_float(equilibriumRows, 0.0)
for i = 0 to equilibriumBars - 1
if not na(high[i])
float barOpen = open[i]
float barHigh = high[i]
float barLow = low[i]
float barClose = close[i]
float barVolume = nz(volume[i], 0.0)
float barRange = barHigh - barLow
float safeRange = math.max(barRange, syminfo.mintick)
float pressure = f_clamp((barClose - barOpen) / safeRange, -1.0, 1.0)
float buyShare = (1.0 + pressure) * 0.5
float sellShare = 1.0 - buyShare
if barRange <= syminfo.mintick
int row = int(math.floor((barClose - equilibriumLow) / equilibriumStep))
row := math.max(0, math.min(equilibriumRows - 1, row))
array.set(dynamicTotal, row, array.get(dynamicTotal, row) + barVolume)
array.set(dynamicBuy, row, array.get(dynamicBuy, row) + barVolume * buyShare)
array.set(dynamicSell, row, array.get(dynamicSell, row) + barVolume * sellShare)
else
int firstRow = int(math.floor((barLow - equilibriumLow) / equilibriumStep))
int lastRow = int(math.floor((barHigh - equilibriumLow) / equilibriumStep))
firstRow := math.max(0, math.min(equilibriumRows - 1, firstRow))
lastRow := math.max(0, math.min(equilibriumRows - 1, lastRow))
for row = firstRow to lastRow
float rowLow = equilibriumLow + row * equilibriumStep
float rowHigh = rowLow + equilibriumStep
float overlap = math.max(0.0, math.min(barHigh, rowHigh) - math.max(barLow, rowLow))
float fraction = overlap / barRange
if fraction > 0
float rowVolume = barVolume * fraction
array.set(dynamicTotal, row, array.get(dynamicTotal, row) + rowVolume)
array.set(dynamicBuy, row, array.get(dynamicBuy, row) + rowVolume * buyShare)
array.set(dynamicSell, row, array.get(dynamicSell, row) + rowVolume * sellShare)
//=============================================================================
// DYNAMIC P0 / VALUE AREA
//=============================================================================
float totalDynamicVolume = 0.0
float maximumDynamicVolume = 0.0
int dynamicP0Index = 0
for row = 0 to equilibriumRows - 1
float rowVolume = array.get(dynamicTotal, row)
totalDynamicVolume += rowVolume
if rowVolume > maximumDynamicVolume
maximumDynamicVolume := rowVolume
dynamicP0Index := row
float dynamicP0 = equilibriumLow + (dynamicP0Index + 0.5) * equilibriumStep
int dynamicVALIndex = dynamicP0Index
int dynamicVAHIndex = dynamicP0Index
float valueAreaVolume = array.get(dynamicTotal, dynamicP0Index)
float valueAreaTarget = totalDynamicVolume * dynamicValueAreaPercent / 100.0
while valueAreaVolume < valueAreaTarget and (dynamicVALIndex > 0 or dynamicVAHIndex < equilibriumRows - 1)
float leftVolume = dynamicVALIndex > 0 ? array.get(dynamicTotal, dynamicVALIndex - 1) : -1.0
float rightVolume = dynamicVAHIndex < equilibriumRows - 1 ? array.get(dynamicTotal, dynamicVAHIndex + 1) : -1.0
if rightVolume > leftVolume
dynamicVAHIndex += 1
valueAreaVolume += array.get(dynamicTotal, dynamicVAHIndex)
else
if dynamicVALIndex > 0
dynamicVALIndex -= 1
valueAreaVolume += array.get(dynamicTotal, dynamicVALIndex)
else if dynamicVAHIndex < equilibriumRows - 1
dynamicVAHIndex += 1
valueAreaVolume += array.get(dynamicTotal, dynamicVAHIndex)
float dynamicVAL = equilibriumLow + dynamicVALIndex * equilibriumStep
float dynamicVAH = equilibriumLow + (dynamicVAHIndex + 1.0) * equilibriumStep
float dynamicValueCenter = (dynamicVAH + dynamicVAL) * 0.5
//=============================================================================
// PROFILE COHERENCE
//=============================================================================
int coherenceLow = math.max(0, dynamicP0Index - coherenceRadius)
int coherenceHigh = math.min(equilibriumRows - 1, dynamicP0Index + coherenceRadius)
float coherenceVolume = 0.0
for row = coherenceLow to coherenceHigh
coherenceVolume += array.get(dynamicTotal, row)
int coherenceRowCount = coherenceHigh - coherenceLow + 1
float coherenceShare = totalDynamicVolume > 0 ? coherenceVolume / totalDynamicVolume * 100.0 : 0.0
float uniformShare = 100.0 * coherenceRowCount / equilibriumRows
float profileCoherence = (coherenceShare + uniformShare > 0 ?
100.0 * coherenceShare / (coherenceShare + uniformShare) :
0.0)
//=============================================================================
// NEW-LOCATION VOLUME
//=============================================================================
float newLocationBand = atr * newLocationBandATR
float newLocationRecentVolume = 0.0
float newLocationRecentTotal = 0.0
for i = 0 to newLocationRecentBars - 1
float barVolume = nz(volume[i], 0.0)
newLocationRecentTotal += barVolume
if math.abs(close[i] - close) <= newLocationBand
newLocationRecentVolume += barVolume
float newLocationShare = (newLocationRecentTotal > 0 ?
newLocationRecentVolume / newLocationRecentTotal * 100.0 :
0.0)
//=============================================================================
// DELTA STATE
//=============================================================================
float aggregateDelta = 0.0
float aggregateVolume = 0.0
for i = 0 to deltaWindow - 1
float barVolume = nz(volume[i], 0.0)
aggregateDelta += f_delta(open[i], high[i], low[i], close[i], barVolume)
aggregateVolume += barVolume
float deltaPercent = (aggregateVolume > 0 ? aggregateDelta / aggregateVolume * 100.0 : 0.0)
float distanceFromP0ATR = (close - dynamicP0) / atr
int displacementDirection = (distanceFromP0ATR > 0 ? 1 : distanceFromP0ATR < 0 ? -1 : 0)
int alignedDeltaBars = 0
for i = 0 to deltaPersistenceBars - 1
float deltaBar = f_delta(open[i], high[i], low[i], close[i], nz(volume[i], 0.0))
if displacementDirection > 0 and deltaBar > 0
alignedDeltaBars += 1
if displacementDirection < 0 and deltaBar < 0
alignedDeltaBars += 1
float deltaPersistence = 100.0 * alignedDeltaBars / deltaPersistenceBars
//=============================================================================
// P0 MIGRATION / CATCH-UP
//=============================================================================
float priorP0 = dynamicP0[migrationLookback]
float priorValueCenter = dynamicValueCenter[migrationLookback]
float p0MigrationATR = (not na(priorP0) ? (dynamicP0 - priorP0) / atr : 0.0)
float valueMigrationATR = (not na(priorValueCenter) ? (dynamicValueCenter - priorValueCenter) / atr : 0.0)
bool p0MigrationAligned = displacementDirection != 0 and displacementDirection * p0MigrationATR > 0
float catchUpDenominator = (not na(priorP0) ? math.max(math.abs(close - priorP0), syminfo.mintick) : syminfo.mintick)
float p0CatchUpPercent = (p0MigrationAligned and not na(priorP0) ?
math.abs(dynamicP0 - priorP0) / catchUpDenominator * 100.0 :
0.0)
p0CatchUpPercent := f_clamp(p0CatchUpPercent, 0.0, 150.0)
//=============================================================================
// PRICE / DELTA EFFICIENCY
//=============================================================================
float priceProgressATR = (not na(close[efficiencyLookback]) ? (close - close[efficiencyLookback]) / atr : 0.0)
float alignedPriceProgress = displacementDirection * priceProgressATR
float alignedDeltaMagnitude = displacementDirection * deltaPercent
float alignedDeltaScore = f_score(alignedDeltaMagnitude, alignedDeltaTarget)
float opposingDeltaScore = f_score(-alignedDeltaMagnitude, opposingDeltaTarget)
float efficiencyScore = (alignedDeltaMagnitude > 0 ? f_score(math.max(alignedPriceProgress, 0.0), efficiencyTargetATR) : 0.0)
float absorptionDeltaScore = f_score(math.abs(deltaPercent), absorptionDeltaTarget)
float absorptionProgressScore = (absorptionMaximumProgressATR > 0 ?
f_clamp((absorptionMaximumProgressATR - math.max(alignedPriceProgress, 0.0)) / absorptionMaximumProgressATR * 100.0, 0.0, 100.0) :
0.0)
float absorptionScore = absorptionDeltaScore * absorptionProgressScore / 100.0
//=============================================================================
// DWELL / RETURN
//=============================================================================
int dwellCount = 0
for i = 0 to dwellMeasurementBars - 1
if not na(dynamicP0[i])
float band = atr[i] * equilibriumBandATR
if displacementDirection > 0 and close[i] > dynamicP0[i] + band
dwellCount += 1
if displacementDirection < 0 and close[i] < dynamicP0[i] - band
dwellCount += 1
float dwellPercent = 100.0 * dwellCount / dwellMeasurementBars
float currentDistance = math.abs(close - dynamicP0)
float previousDistance = (not na(dynamicP0[1]) ? math.abs(close[1] - dynamicP0[1]) : currentDistance)
bool returningTowardP0 = currentDistance < previousDistance
bool candleTowardP0 = (displacementDirection > 0 ? close < open : displacementDirection < 0 ? close > open : false)
float returnTowardP0Score = (returningTowardP0 and candleTowardP0 ? 100.0 : returningTowardP0 ? 50.0 : 0.0)
//=============================================================================
// ACCEPTANCE SCORE
//=============================================================================
float acceptanceMigration = f_score(displacementDirection * p0MigrationATR, migrationTargetATR)
float acceptanceCatchUp = f_score(p0CatchUpPercent, catchUpTargetPercent)
float acceptanceNewLocation = f_score(newLocationShare, newLocationTargetPercent)
float acceptanceValueMigration = f_score(displacementDirection * valueMigrationATR, valueMigrationTargetATR)
float acceptanceDelta = (alignedDeltaScore + deltaPersistence) * 0.5
float acceptanceEfficiency = efficiencyScore
float acceptanceRaw = (
acceptanceMigration * 0.20 +
acceptanceCatchUp * 0.15 +
acceptanceNewLocation * 0.20 +
acceptanceValueMigration * 0.15 +
acceptanceDelta * 0.15 +
dwellPercent * 0.10 +
acceptanceEfficiency * 0.05)
float coherenceMultiplier = 0.55 + 0.45 * profileCoherence / 100.0
float acceptanceScore = f_clamp(acceptanceRaw * coherenceMultiplier, 0.0, 100.0)
//=============================================================================
// REJECTION SCORE
//=============================================================================
float rejectionP0Stall = 100.0 - acceptanceMigration
float rejectionValueNonMigration = 100.0 - acceptanceValueMigration
float rejectionWeakNewLocation = 100.0 - acceptanceNewLocation
float rejectionRaw = (
rejectionP0Stall * 0.20 +
opposingDeltaScore * 0.25 +
absorptionScore * 0.15 +
returnTowardP0Score * 0.15 +
rejectionValueNonMigration * 0.10 +
rejectionWeakNewLocation * 0.15)
float rejectionScore = f_clamp(rejectionRaw * coherenceMultiplier, 0.0, 100.0)
//=============================================================================
// MARKET STATE
//=============================================================================
bool meaningfulDisplacement = math.abs(distanceFromP0ATR) >= minimumDistanceATR
bool coherenceOK = profileCoherence >= minimumCoherence
bool bullAcceptanceDominant = (acceptanceScore >= acceptanceThresholdLong + signalStabilityMargin and acceptanceScore >= rejectionScore + scoreDominanceLong)
bool bearAcceptanceDominant = (acceptanceScore >= acceptanceThresholdShort + signalStabilityMargin and acceptanceScore >= rejectionScore + scoreDominanceShort)
bool bullRejectionDominant = (rejectionScore >= rejectionThresholdLong + signalStabilityMargin and rejectionScore >= acceptanceScore + scoreDominanceLong)
bool bearRejectionDominant = (rejectionScore >= rejectionThresholdShort + signalStabilityMargin and rejectionScore >= acceptanceScore + scoreDominanceShort)
bool bullishAcceptance = (meaningfulDisplacement and coherenceOK and displacementDirection > 0 and bullAcceptanceDominant)
bool bearishAcceptance = (meaningfulDisplacement and coherenceOK and displacementDirection < 0 and bearAcceptanceDominant)
bool bullishRejection = (meaningfulDisplacement and coherenceOK and displacementDirection < 0 and bullRejectionDominant)
bool bearishRejection = (meaningfulDisplacement and coherenceOK and displacementDirection > 0 and bearRejectionDominant)
string marketState = "EQUILIBRIUM"
if meaningfulDisplacement
marketState := "TRANSITION"
if bullishAcceptance
marketState := "BULL ACCEPTANCE"
if bearishAcceptance
marketState := "BEAR ACCEPTANCE"
if bullishRejection
marketState := "BULL REJECTION"
if bearishRejection
marketState := "BEAR REJECTION"
//=============================================================================
// DYNAMIC P0 / VA DISPLAY
//=============================================================================
dynamicP0Plot = plot(showAllChartObjectsInput and showDynamicP0 ? dynamicP0 : na, title = "Dynamic P0", color = dynamicP0Color, linewidth = dynamicP0Width)
var label dynamicP0Label = na
if showAllChartObjectsInput and showDynamicP0 and showDynamicP0LabelInput
if na(dynamicP0Label)
dynamicP0Label := label.new(bar_index, dynamicP0, "P0 " + f_price(dynamicP0), xloc = xloc.bar_index, style = label.style_label_left, color = color.new(dynamicP0Color, 0), textcolor = color.black, size = size.small)
else
label.set_xy(dynamicP0Label, bar_index, dynamicP0)
label.set_text(dynamicP0Label, "P0 " + f_price(dynamicP0))
dynamicVAHPlot = plot(showAllChartObjectsInput and showDynamicValueArea ? dynamicVAH : na, title = "Dynamic VAH", color = color.new(dynamicValueAreaColor, 25), linewidth = 1)
dynamicVALPlot = plot(showAllChartObjectsInput and showDynamicValueArea ? dynamicVAL : na, title = "Dynamic VAL", color = color.new(dynamicValueAreaColor, 25), linewidth = 1)
fill(dynamicVAHPlot, dynamicVALPlot, color = showAllChartObjectsInput and showDynamicValueArea ? color.new(dynamicValueAreaColor, 93) : na, title = "Dynamic Value Area")
//=============================================================================
// ARCHITECTURE DASHBOARD
//=============================================================================
architectureTablePosition = (
architecturePosition == "Top Left" ?
position.top_left :
architecturePosition == "Bottom Left" ?
position.bottom_left :
architecturePosition == "Bottom Right" ?
position.bottom_right :
position.top_right)
var table architectureTable = table.new(architectureTablePosition, 5, 10, bgcolor = color.new(color.rgb(15, 20, 27), 10), border_width = 1)
if barstate.islast
if showAllChartObjectsInput and showArchitectureHistogram
int readCol = showLiveColumnInput ? 4 : 3
table.cell(architectureTable, 0, 0, "ARCHITECTURE", text_color = color.white, bgcolor = color.rgb(22, 52, 86))
table.cell(architectureTable, 1, 0, "ACCEPT", text_color = color.white, bgcolor = color.rgb(22, 52, 86))
table.cell(architectureTable, 2, 0, "REJECT", text_color = color.white, bgcolor = color.rgb(22, 52, 86))
if showLiveColumnInput
table.cell(architectureTable, 3, 0, "LIVE", text_color = color.white, bgcolor = color.rgb(22, 52, 86))
table.cell(architectureTable, readCol, 0, "READ", text_color = color.white, bgcolor = color.rgb(22, 52, 86))
string readMigration = f_rowVerdict(acceptanceMigration, rejectionP0Stall, "MIGRATING", "STALLING", "FLAT")
table.cell(architectureTable, 0, 1, "P0 Mig / Stall", text_color = color.white)
table.cell(architectureTable, 1, 1, f_bar(acceptanceMigration), text_color = acceptanceColor)
table.cell(architectureTable, 2, 1, f_bar(rejectionP0Stall), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 1, str.tostring(p0MigrationATR, "#.##") + "A", text_color = color.white)
table.cell(architectureTable, readCol, 1, readMigration, text_color = readMigration == "MIGRATING" ? acceptanceColor : readMigration == "STALLING" ? rejectionColor : color.gray)
string readCatchUp = f_rowVerdict(acceptanceCatchUp, 100.0 - acceptanceCatchUp, "CONVERGING", "LAGGING", "MIXED")
table.cell(architectureTable, 0, 2, "Catch-Up", text_color = color.white)
table.cell(architectureTable, 1, 2, f_bar(acceptanceCatchUp), text_color = acceptanceColor)
table.cell(architectureTable, 2, 2, f_bar(100.0 - acceptanceCatchUp), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 2, f_pct(p0CatchUpPercent), text_color = color.white)
table.cell(architectureTable, readCol, 2, readCatchUp, text_color = readCatchUp == "CONVERGING" ? acceptanceColor : readCatchUp == "LAGGING" ? rejectionColor : color.gray)
string readNewValue = f_rowVerdict(acceptanceNewLocation, rejectionWeakNewLocation, "ACCEPTED", "REJECTED", "MIXED")
table.cell(architectureTable, 0, 3, "New Value", text_color = color.white)
table.cell(architectureTable, 1, 3, f_bar(acceptanceNewLocation), text_color = acceptanceColor)
table.cell(architectureTable, 2, 3, f_bar(rejectionWeakNewLocation), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 3, f_pct(newLocationShare), text_color = color.white)
table.cell(architectureTable, readCol, 3, readNewValue, text_color = readNewValue == "ACCEPTED" ? acceptanceColor : readNewValue == "REJECTED" ? rejectionColor : color.gray)
string readVaMigration = f_rowVerdict(acceptanceValueMigration, rejectionValueNonMigration, "SHIFTING", "ANCHORED", "MIXED")
table.cell(architectureTable, 0, 4, "VA Migration", text_color = color.white)
table.cell(architectureTable, 1, 4, f_bar(acceptanceValueMigration), text_color = acceptanceColor)
table.cell(architectureTable, 2, 4, f_bar(rejectionValueNonMigration), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 4, str.tostring(valueMigrationATR, "#.##") + "A", text_color = color.white)
table.cell(architectureTable, readCol, 4, readVaMigration, text_color = readVaMigration == "SHIFTING" ? acceptanceColor : readVaMigration == "ANCHORED" ? rejectionColor : color.gray)
string readDelta = f_rowVerdict(acceptanceDelta, opposingDeltaScore, "ALIGNED", "OPPOSING", "MIXED")
table.cell(architectureTable, 0, 5, "Delta", text_color = color.white)
table.cell(architectureTable, 1, 5, f_bar(acceptanceDelta), text_color = acceptanceColor)
table.cell(architectureTable, 2, 5, f_bar(opposingDeltaScore), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 5, f_pct(deltaPercent), text_color = color.white)
table.cell(architectureTable, readCol, 5, readDelta, text_color = readDelta == "ALIGNED" ? acceptanceColor : readDelta == "OPPOSING" ? rejectionColor : color.gray)
string readEfficiency = f_rowVerdict(acceptanceEfficiency, absorptionScore, "EFFICIENT", "ABSORBED", "MIXED")
table.cell(architectureTable, 0, 6, "Efficiency", text_color = color.white)
table.cell(architectureTable, 1, 6, f_bar(acceptanceEfficiency), text_color = acceptanceColor)
table.cell(architectureTable, 2, 6, f_bar(absorptionScore), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 6, str.tostring(priceProgressATR, "#.##") + "A", text_color = color.white)
table.cell(architectureTable, readCol, 6, readEfficiency, text_color = readEfficiency == "EFFICIENT" ? acceptanceColor : readEfficiency == "ABSORBED" ? rejectionColor : color.gray)
string readDwell = f_rowVerdict(dwellPercent, returnTowardP0Score, "HOLDING", "RETURNING", "MIXED")
table.cell(architectureTable, 0, 7, "Dwell / Return", text_color = color.white)
table.cell(architectureTable, 1, 7, f_bar(dwellPercent), text_color = acceptanceColor)
table.cell(architectureTable, 2, 7, f_bar(returnTowardP0Score), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 7, str.tostring(dwellCount) + "/" + str.tostring(dwellMeasurementBars), text_color = color.white)
table.cell(architectureTable, readCol, 7, readDwell, text_color = readDwell == "HOLDING" ? acceptanceColor : readDwell == "RETURNING" ? rejectionColor : color.gray)
string readTotal = marketState == "BULL ACCEPTANCE" ? "BULL BREAK" : marketState == "BEAR ACCEPTANCE" ? "BEAR BREAK" : marketState == "BULL REJECTION" ? "BULL BOUNCE" : marketState == "BEAR REJECTION" ? "BEAR BOUNCE" : marketState
table.cell(architectureTable, 0, 8, "TOTAL", text_color = color.white)
table.cell(architectureTable, 1, 8, f_bar(acceptanceScore) + " " + str.tostring(acceptanceScore, "#"), text_color = acceptanceColor)
table.cell(architectureTable, 2, 8, f_bar(rejectionScore) + " " + str.tostring(rejectionScore, "#"), text_color = rejectionColor)
if showLiveColumnInput
table.cell(architectureTable, 3, 8, marketState, text_color = color.white)
table.cell(architectureTable, readCol, 8, readTotal, text_color = str.contains(readTotal, "BULL") ? acceptanceColor : str.contains(readTotal, "BEAR") ? rejectionColor : color.gray)
table.cell(architectureTable, 0, 9, "P0 / Dist / Coh", text_color = color.white)
table.cell(architectureTable, 1, 9, f_price(dynamicP0), text_color = dynamicP0Color)
table.cell(architectureTable, 2, 9, str.tostring(distanceFromP0ATR, "#.##") + "A", text_color = color.white)
if showLiveColumnInput
table.cell(architectureTable, 3, 9, f_pct(profileCoherence), text_color = color.white)
table.cell(architectureTable, readCol, 9, profileCoherence >= minimumCoherence ? "STRUCTURED" : "NOISY", text_color = profileCoherence >= minimumCoherence ? acceptanceColor : color.gray)
dashboardSizeValue = f_dashboardSize(dashboardTextSize)
for dashboardRow = 0 to 9
for dashboardCol = 0 to 4
table.cell_set_text_size(architectureTable, dashboardCol, dashboardRow, dashboardSizeValue)
Overview
A dashboard table scores acceptance and rejection from P0 migration, new-location volume, value area migration, estimated delta alignment, price efficiency, dwell and profile coherence. Delta is estimated from candle data, not true order flow. It places no orders and has many tunable thresholds.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Show All Chart Objects
bool
true
showAllChartObjectsInput
Equilibrium Window (Minutes)
int
240
equilibriumMinutes
Dynamic P0 Price Rows
int
32
equilibriumRows
Maximum Bars In Dynamic Profile
int
500
maximumEquilibriumBars
Dynamic Value Area %
float
70.0
dynamicValueAreaPercent
P0 Coherence Radius (Rows)
int
2
coherenceRadius
Equilibrium Band (ATR)
float
0.35
equilibriumBandATR
Minimum Meaningful Displacement (ATR)
float
0.80
minimumDistanceATR
P0 / Value Migration Lookback
int
4
migrationLookback
Strong P0 Migration (ATR)
float
0.15
migrationTargetATR
Strong P0 Catch-Up %
float
40.0
catchUpTargetPercent
New-Location Volume Band (ATR)
float
0.25
newLocationBandATR
Show all 40 settings
Setting
Type
Default
Variable
Strong New-Location Volume %
float
35.0
newLocationTargetPercent
New-Location Recency Window (Bars)
int
20
newLocationRecentBars
Strong Value-Area Migration (ATR)
float
0.10
valueMigrationTargetATR
Delta State Window
int
3
deltaWindow
Delta Persistence Bars
int
3
deltaPersistenceBars
Strong Aligned Delta %
float
20.0
alignedDeltaTarget
Strong Opposing Delta %
float
20.0
opposingDeltaTarget
Efficiency Lookback
int
3
efficiencyLookback
Efficient Price Progress (ATR)
float
0.30
efficiencyTargetATR
Absorption Delta Magnitude %
float
25.0
absorptionDeltaTarget
Absorption Maximum Price Progress (ATR)
float
0.12
absorptionMaximumProgressATR
Dwell Measurement Bars
int
4
dwellMeasurementBars
Minimum Profile Coherence
float
55.0
minimumCoherence
Acceptance Score Threshold (Long)
float
65.0
acceptanceThresholdLong
Acceptance Score Threshold (Short)
float
65.0
acceptanceThresholdShort
Rejection Score Threshold (Long)
float
50.0
rejectionThresholdLong
Rejection Score Threshold (Short)
float
50.0
rejectionThresholdShort
Required Score Dominance (Long)
float
24.0
scoreDominanceLong
Required Score Dominance (Short)
float
24.0
scoreDominanceShort
Signal Stability Margin
float
0.0
signalStabilityMargin
Show Dynamic P0
bool
true
showDynamicP0
Label The Dynamic P0 Line
bool
true
showDynamicP0LabelInput
Dynamic P0 Color
color
color.aqua
dynamicP0Color
Dynamic P0 Width
int
3
dynamicP0Width
Show Dynamic VAH / VAL
bool
true
showDynamicValueArea
Dynamic Value Area Color
color
color.rgb(70, 115, 255)
dynamicValueAreaColor
Show Acceptance / Rejection Dashboard
bool
true
showArchitectureHistogram
Position
string
Top Right
architecturePosition
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.
This indicator plots a session VWAP of the typical price on the price chart. It marks an up triangle under a bar when close crosses above VWAP and a down triangle above a bar when close crosses below it. A star pinned at the top of the pane marks bars whose vo
This overlay indicator builds a horizontal momentum profile over a chosen lookback. It splits price into rows and plots the average WaveTrend of each zone as a bar colored by direction, plus an optional MFI reference band that stays gray when real trade volume
The Holographic Market Microstructure indicator overlays market structure and smart money insights directly on the price chart. It identifies liquidity voids, order flow imbalances, accumulation zones, price and volume divergences, and fractal market structure
This indicator builds a frozen volume profile over a fixed, half-open timestamp range and draws it on the price chart. It aggregates one-minute source bars into output rows sized by a chosen tick count, marks a configurable value-area percentage, and can plot
This overlay indicator draws an on-chart depth-of-market table that splits volume at each price tick into estimated buy volume, sell volume, delta, and session volume. Growing text bars compare buyers and sellers, and recent bars approximate resting bid and as
This indicator overlays an order flow intelligence suite directly on the price chart. It renders a liquidity heatmap across configured price zones, alongside an on-chart information panel displaying volume delta, cumulative volume delta, a momentum compass bas