//@version=6 // Volume Profile + S/R Rejection R1.0 // Built 2026-10-04 America/New_York from the supplied video transcript and Pine files. // Profile/level engine adapted from Buyers & Sellers Profile + Dynamic S/R, © Zeiierman. // That work: CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // Volume attribution formula adapted from Volume Delta, © hapharmonic. // This Pine Script™ code includes code subject to the terms of the Mozilla Public License 2.0 // at https://mozilla.org/MPL/2.0/ (volume-attribution formula, © hapharmonic). // Retain source notices and applicable licenses on redistribution. // Changes: completed truncated profile renderer; combined pane/overlay; corrected net delta; // protected zero-range/missing-volume calculations; added configurable rejection signals. // // USAGE: Paste the entire file into a new TradingView indicator and Add to chart. // One script shows estimated volume in its pane and price levels/profile on the main chart. // BUY: pre-existing support touched within 0.15 ATR; close above level; bullish candle; // estimated buy share >=60%, up >=15 percentage points vs the prior 3-bar volume-weighted share. // SELL: mirror at resistance. All thresholds adjustable. RVOL and POC filters default OFF. // Video provides discretionary interpretation, not these exact numerical signal rules. // Signals/alerts only confirm at bar close. Current-bar table/profile can change intrabar. // Pivots confirm swingLen bars later; actionable lines/dots begin at confirmation, not pivot. // Optional raw-pivot markers are retrospective. Broken/merged/trimmed active drawings disappear; // historical signal shapes remain. Levels do not automatically flip sides after a break. // Estimated buy=volume*(close-low)/(high-low); sell=volume-buy; net=buy-sell. // These are OHLCV estimates, NOT true bid/ask order-flow delta. Zero-range bars split 50/50. // POC confluence uses the current rolling profile on the signal's closed bar. // Level score is a heuristic strength score, NOT a probability of success. // Pine visual layout documentation: https://www.tradingview.com/pine-script-docs/visuals/overview/ // Defaults: rolling 600 bars / 72 rows / 5-bar left and right pivots. No session reset. // Alerts: choose individual BUY/SELL conditions OR Any alert() function call (not both). // Data Window includes the exact level and estimated volume values for each signal. indicator("Volume Profile + S/R Rejection R1.0", shorttitle="VP-SR R1.0", overlay=false, format=format.volume, max_lines_count=250, max_labels_count=500, max_boxes_count=300, max_bars_back=5000) // ~~ Tooltips { var string tt1="Number of historical bars used by the large rolling volume profile. The same lookback is reconstructed historically when a pivot is evaluated, so old pivots are judged only with information available at that time." var string tt2="Number of price rows used to discretize the rolling profile. More rows increase price resolution but also increase drawing and calculation load." var string tt3="Maximum horizontal width of the displayed profile in chart bars. The POC row reaches this width; other rows scale relative to it." var string tt4="Horizontal gap between the current bar and the left edge of the displayed rolling profile." var string tt5="Master switch for the large rolling profile shown at the right side of the chart." var string tt6="Highlight the highest-volume profile row and draw its short guide line and price label." var string tt7="Outline profile rows that currently contain an active profile-guided support or resistance level." var string tt8="Left/right pivot confirmation length. A value of 5 means a pivot is confirmed five bars after the actual swing bar." var string tt9="Maximum ATR distance around a raw pivot in which the profile engine may search for a stronger nearby volume node." var string tt10="Minimum candidate-node volume relative to the profile POC. Lower values admit weaker nearby profile structure." var string tt11="Minimum combined profile evidence needed before a raw price pivot can become an active level." var string tt12="Maximum fraction of the distance from the raw pivot toward the selected profile node. Actual pull is scaled by profile evidence." var string tt13="Minimum final 0-100 score required after profile evidence, absorption, relative pivot volume and wick rejection are combined." var string tt14="Maximum number of active profile-guided levels. When exceeded, the weakest active level is removed first." var string tt15="Same-side levels within this ATR distance are treated as duplicates. A stronger new candidate replaces the weaker nearby level." var string tt16="ATR buffer beyond an active level required for a confirmed close to invalidate that level." var string tt17="Color used for active support levels, support endpoint dots and support profile-row outlines." var string tt18="Color used for active resistance levels, resistance endpoint dots and resistance profile-row outlines." var string tt19="Accent color used for the inner profile-confirmed pivot core and the raw-pivot-to-final-level pull guide." var string tt20="Color of the faint raw price pivot marker before the profile engine relocates the final level." var string tt21="Estimated buying-volume color in the large profile. Buy/sell attribution comes from candle close location inside each bar range." var string tt22="Estimated selling-volume color in the large profile. Buy/sell attribution is approximate rather than true bid/ask volume." var string tt23="Color used for the displayed profile point of control." var string tt24="Shared line style used by active support and resistance levels." var string tt25="Show the strength marker at the level price on the confirmation bar; the level was not actionable on the earlier pivot bar." var string tt26="Show the retrospective raw swing marker and dotted guide to the later level confirmation. Raw markers were not known at their plotted pivot time." var string tt27="Show the heuristic 0-100 strength score at confirmation. This score is not a success probability." var string tt28="Show the current endpoint dot and one-number score label at the right edge of each active level." //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} // ~~ Groups { gPROF="Large Rolling Profile" gENG="Profile-Guided Pivot Engine" gSTY="Visual Style" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} // ~~ Inputs { profLb=input.int(600,"Lookback",minval=100,maxval=1500,group=gPROF,inline="p1") profRows=input.int(72,"Rows",minval=24,maxval=100,group=gPROF,inline="p1",tooltip=tt1+"\n\n"+tt2) profW=input.int(58,"Width",minval=15,maxval=110,group=gPROF,inline="p2") profOff=input.int(8,"Offset",minval=2,maxval=50,group=gPROF,inline="p2",tooltip=tt3+"\n\n"+tt4) showProf=input.bool(true,"Show Profile",group=gPROF,inline="p3") showPoc=input.bool(true,"POC",group=gPROF,inline="p3",active=showProf) showLvlRows=input.bool(true,"Level Rows",group=gPROF,inline="p3",active=showProf,tooltip=tt5+"\n\n"+tt6+"\n\n"+tt7) swingLen=input.int(5,"Swing Length",minval=2,maxval=25,group=gENG,inline="e1") srchAtr=input.float(1.20,"Search ATR",minval=0.20,maxval=3.00,step=0.05,group=gENG,inline="e1",tooltip=tt8+"\n\n"+tt9) nodeMin=input.float(0.08,"Min Node",minval=0.0,maxval=1.0,step=0.01,group=gENG,inline="e2") evidMin=input.float(0.22,"Min Evidence",minval=0.0,maxval=1.0,step=0.01,group=gENG,inline="e2",tooltip=tt10+"\n\n"+tt11) pullMax=input.float(0.85,"Profile Pull",minval=0.0,maxval=1.0,step=0.05,group=gENG,inline="e3") scoreMin=input.float(30.0,"Min Score",minval=0,maxval=100,step=1,group=gENG,inline="e3",tooltip=tt12+"\n\n"+tt13) maxLvl=input.int(20,"Max Levels",minval=2,maxval=40,group=gENG,inline="e4") mergeAtr=input.float(0.16,"Merge ATR",minval=0.0,maxval=1.0,step=0.02,group=gENG,inline="e4") breakAtr=input.float(0.10,"Break ATR",minval=0.0,maxval=0.5,step=0.01,group=gENG,inline="e4",tooltip=tt14+"\n\n"+tt15+"\n\n"+tt16) supCol=input.color(color.rgb(31,199,116),"Support",group=gSTY,inline="c1") resCol=input.color(color.rgb(239,75,75),"Resistance",group=gSTY,inline="c1",tooltip=tt17+"\n\n"+tt18) coreCol=input.color(color.rgb(255,205,64),"Pivot Core",group=gSTY,inline="c2") rawCol=input.color(color.rgb(160,166,178),"Raw Pivot",group=gSTY,inline="c2",tooltip=tt19+"\n\n"+tt20) buyCol=input.color(color.rgb(43,158,143),"Profile Buy",group=gSTY,inline="c3") sellCol=input.color(color.rgb(74,88,182),"Profile Sell",group=gSTY,inline="c3") pocCol=input.color(color.rgb(255,145,32),"POC",group=gSTY,inline="c3",tooltip=tt21+"\n\n"+tt22+"\n\n"+tt23) lvlStyle=input.string("Solid","Line Style",options=["Solid","Dotted","Dashed"],group=gSTY,inline="s1",tooltip=tt24) showDots=input.bool(true,"Pivot Dots",group=gSTY,inline="s2") showRaw=input.bool(false,"Raw Pivot",group=gSTY,inline="s2",active=showDots) showDotScore=input.bool(true,"Dot Score",group=gSTY,inline="s2",active=showDots) showEdge=input.bool(true,"Right Score",group=gSTY,inline="s2",tooltip=tt25+"\n\n"+tt26+"\n\n"+tt27+"\n\n"+tt28) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} // ~~ Constants { int VOL_LEN=40 int ABS_RAD=math.min(3,swingLen) float PIV_VOL_X=2.2 float ABS_BODY_MAX=0.40 float ABS_VOL_X=1.5 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} // ~~ Types { type Lvl float p float sc float raw float node float evid float nStr bool supp int born line ln int confirmed bool fired = false //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} // ~~ Helpers { clip(float x)=>math.max(0.0,math.min(1.0,x)) lstyle(string s)=>s=="Dotted"?line.style_dotted:s=="Dashed"?line.style_dashed:line.style_solid lwidth(float s)=>s>=82?4:s>=62?3:2 lalpha(float s)=>s>=82?8:s>=62?22:s>=45?38:52 rings(float s)=>s>=82?4:s>=66?3:s>=50?2:1 rsize(int r)=>r>=4?size.large:r==3?size.normal:r==2?size.small:size.tiny ralpha(int r)=>r>=4?68:r==3?52:r==2?30:4 row_id(float p,float bot,float step,int rows)=>math.max(0,math.min(rows-1,int(math.floor((p-bot)/step)))) lvl_col(bool supp)=>supp?supCol:resCol clear_boxes(array a)=> while a.size()>0 box.delete(a.pop()) clear_lines(array a)=> while a.size()>0 line.delete(a.pop()) clear_labels(array