Price Normalized RSI Profile [UAlgo]Price Normalized RSI Profile is a hybrid visualization tool that combines a rolling RSI distribution study with a profile style overlay drawn directly on the price chart. Instead of plotting a classic RSI line in a separate oscillator pane, this script collects historical RSI readings, groups them into fixed 0 to 100 bins, weights each bin by traded volume, and then renders the resulting distribution as a horizontal profile on the right side of the main chart.
The goal of the script is not to show where price traded the most, but to show where RSI states accumulated the most volume over the selected lookback period. In other words, it answers a different question than a traditional volume profile. Rather than asking which prices were most active, it asks which RSI regimes were most active, then maps those oscillator regimes visually into the chart’s price space for easier on-chart interpretation.
The indicator highlights:
A volume weighted RSI Point of Control (POC)
A Value Area around that POC
A right side histogram of RSI regime distribution
A color gradient that reflects bullish versus bearish RSI zones
Reference labels for POC, VAH, and VAL
Lookback boundary markers for profile context
This makes the script useful for traders who want to blend oscillator distribution analysis with chart based execution, especially when comparing current price position against historically dominant RSI states.
Important note: The POC, VAH, and VAL in this script are derived from an RSI distribution profile , not from a standard price based volume profile. They are visually mapped onto the current chart range for presentation.
🔹 Features
🔸 1) Volume Weighted RSI Distribution Profile
The script collects RSI values over a rolling lookback window and assigns each reading into one of several fixed RSI bins. Each bin accumulates volume , not just frequency, so the profile reflects how much traded participation occurred while RSI was in that zone.
This makes the output more meaningful than a simple occurrence count because highly active bars contribute more weight.
🔸 2) Fixed 0 to 100 RSI Bin Framework
The profile is built over the natural RSI range from 0 to 100, divided into a user defined number of bins. This creates a stable oscillator distribution model that is consistent across symbols and timeframes.
Lower bin counts create thicker, smoother profile bars.
Higher bin counts create finer resolution and more detailed structure.
🔸 3) Overlay on the Main Price Chart
Unlike most RSI tools, this script runs with overlay=true and renders the profile directly on the price chart. It maps RSI bins onto the vertical span of the recent chart range, allowing traders to see the distribution without leaving the main chart.
This is a visual convenience feature and creates a unique fusion of oscillator logic and price space presentation.
🔸 4) Point of Control (POC) Detection
The indicator identifies the RSI bin with the highest accumulated volume and treats it as the RSI Profile POC. This is the most active RSI zone by volume over the lookback window.
The POC is highlighted with:
A wider profile bar
A unique color
A label showing the POC volume
🔸 5) Value Area (VAH / VAL) Calculation
The script builds a Value Area around the POC using the selected percentage of total profile volume. This identifies the core RSI regime zone where the majority of the volume weighted RSI activity occurred.
The Value Area is visually emphasized with more visible bars and separate VAH / VAL guide lines.
🔸 6) Gradient Color Mapping by RSI Regime
Each bin is colored using a gradient based on its RSI location:
Lower RSI zones lean bullish color
Higher RSI zones lean bearish color
This reflects the script’s chosen visual logic, where low RSI bins appear in the bullish color family and high RSI bins appear in the bearish color family.
🔸 7) Distinct Styling for POC, Value Area, and Outside Value
The script visually separates three categories:
POC bin
Bins inside the Value Area
Bins outside the Value Area
This helps traders quickly distinguish the dominant RSI regime from the broader accepted RSI zone and from lower importance outer regions.
🔸 8) Forward Projected Histogram Layout
The profile is drawn to the right of current price using configurable:
Maximum width in bars
Horizontal offset
This keeps the histogram out of the way of current candles while preserving clear visibility on the active chart.
🔸 9) Lookback Context Markers
The script draws a vertical line marking the start of the profile lookback window, plus horizontal guide lines across the chart high and low range used for the profile mapping. This makes it easy to understand which portion of the chart is being analyzed.
🔸 10) Compact On Chart Labels
The indicator adds right side labels for:
POC
VAH
VAL
This makes the distribution easier to read without manually inspecting each bar.
🔸 11) Rolling History Buffer for RSI and Volume
The script stores both RSI and volume into arrays, allowing the profile to be rebuilt from recent history on the last bar. This keeps the logic fully rolling and independent from session boundaries.
🔸 12) Structured Object Based Design
The script uses custom types:
RsiBin for each RSI interval
RsiProfile for the full profile state, including POC and Value Area indexes
This makes the internal logic cleaner and easier to maintain.
🔹 Calculations
1) RSI Calculation
The script calculates RSI from the chosen source and length:
float rsi_val = ta.rsi(rsi_src, rsi_len)
This value is the basis for all binning and profile accumulation.
2) Rolling RSI and Volume History Storage
Every bar, the script pushes the latest RSI value and volume into rolling arrays:
rsi_history.push(rsi_val)
vol_history.push(volume)
To prevent unlimited growth, the arrays are trimmed when they exceed:
lookback + 100
This keeps enough buffer for profile stability while controlling memory size.
3) Fixed RSI Bin Initialization
The profile divides the 0 to 100 RSI range into equal bins:
float step = 100.0 / bins_count
for i = 0 to bins_count - 1
float min_v = i * step
float max_v = (i + 1) * step
this.bins.push(RsiBin.new(min_v, max_v, 0.0, 0))
Each bin stores:
RSI minimum value
RSI maximum value
Accumulated volume
Observation count
4) Volume Weighted Population of the RSI Profile
When populating the profile, each historical RSI value is mapped into the correct bin:
int bin_idx = math.floor(r_val / 100.0 * this.bins.size())
The index is clamped to remain inside valid bounds:
bin_idx := math.min(bin_idx, this.bins.size() - 1)
bin_idx := math.max(bin_idx, 0)
Then the script adds the corresponding bar volume to that bin:
b.volume += v_val
b.count += 1
this.total_vol += v_val
This means the profile is volume weighted RSI distribution , not a simple count histogram.
5) POC Detection
As bins are populated, the script tracks the bin with the highest accumulated volume:
if b.volume > this.max_vol
this.max_vol := b.volume
this.poc_idx := bin_idx
This bin becomes the profile POC and acts as the center for Value Area expansion.
6) Value Area Calculation
The Value Area target is calculated from total profile volume:
float target_vol = this.total_vol * (va_percent / 100.0)
The script starts from the POC and expands outward, comparing the next upper and lower bin volumes:
float vol_up = (top < max_idx) ? this.bins.get(top + 1).volume : 0.0
float vol_dn = (bot > 0) ? this.bins.get(bot - 1).volume : 0.0
Whichever side has more volume is added first. This continues until the accumulated volume reaches the target percentage.
The final indexes are stored as:
this.va_top_idx := top
this.va_bot_idx := bot
7) Mapping RSI Bins into Price Space
A key part of this script is that RSI bins are not drawn in an oscillator pane. Instead, each RSI interval is mapped onto the chart’s recent price range:
float price_range = chart_high - chart_low
float y_bottom = chart_low + (b.min_val / 100.0) * price_range
float y_top = chart_low + (b.max_val / 100.0) * price_range
Interpretation:
RSI 0 maps to the recent chart low.
RSI 100 maps to the recent chart high.
All intermediate RSI bins are proportionally placed between them.
This is a visual mapping device, not a statement that those price levels correspond to actual RSI threshold prices.
8) Histogram Width Normalization
Each bin’s horizontal width is scaled by its volume relative to the maximum profile volume:
int bar_w = math.round((b.volume / this.max_vol) * max_width)
If the bin is the POC, it gets extra width:
if is_poc
bar_w := int(max_width * 1.15)
This makes the POC stand out clearly inside the profile.
9) POC, VA, and Outside VA Styling Logic
Each bin is categorized as:
POC
Inside the Value Area
Outside the Value Area
Then the script applies different opacity and border logic:
POC gets the dedicated POC color
VA bins are more visible
Outside VA bins are more faded
This creates clear visual hierarchy in the profile.
10) Color Gradient by RSI Position
Base color is determined from bin position in the RSI scale:
color base_col = color.from_gradient(b.min_val, 0, 100, c_bull, c_bear)
This means lower RSI bins transition toward the bullish color and higher RSI bins transition toward the bearish color. This is a stylistic mapping choice built into the script.
11) POC Label and Volume Display
When the POC is drawn, the script also adds a label showing:
The text POC
The accumulated volume of that bin
text="POC " + str.tostring(b.volume, format.volume)
This provides quick information about the dominant RSI regime’s participation size.
12) VAH and VAL Price Level Rendering
The script converts the Value Area top and bottom RSI bin indexes into mapped chart levels:
For VAH:
float vah_level = chart_low + (b_vah.max_val / 100.0) * price_range_val
For VAL:
float val_level = chart_low + (b_val.min_val / 100.0) * price_range_val
It then draws dashed horizontal lines and small labels for both.
Important note:
These are RSI profile Value Area boundaries mapped into price space , not true price based VAH and VAL from a market profile.
13) Lookback Boundary Drawing
The start of the lookback window is marked with a vertical dotted line:
int start_bar_idx = bar_index - lookback
line.new(start_bar_idx, chart_low, start_bar_idx, chart_high, ...)
This makes it easier to visually understand which section of chart history contributed to the current profile.
14) Chart Range Anchoring
The vertical display range used for the RSI to price mapping is derived from:
float chart_high = ta.highest(high, lookback)
float chart_low = ta.lowest(low, lookback)
This means the profile always stretches across the full recent visible price range used in the calculation window.
15) Last Bar Rendering Behavior
The profile is built and rendered only on the last bar:
if barstate.islast
vp.init(bin_count)
vp.populate(rsi_history, vol_history, lookback)
vp.calc_va(va_pct)
vp.render(...)
Pine Script® göstergesi






















