Indicator · Pine Script v6 · On the chart

Chart Visualization

by danielbodnar

A Pine Script visualization script demonstrating custom technical drawing techniques on price charts.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code366
Settings0inputs
LicenceMIT
Last update2 months ago8 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

366 lines of Pine Script v6 from snippets/pinescript/chart-visualization.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

chart-visualization.pine
// Pine Script Chart Visualization Examples
// @version=6

// ===== ADVANCED PLOTTING TECHNIQUES =====
indicator("Chart Visualization", shorttitle="Viz", overlay=true, max_boxes_count=100, max_labels_count=200)

// ===== DYNAMIC COLOR SCHEMES =====
// Color gradient based on price movement
price_change_pct = (close - close[20]) / close[20] * 100
color_intensity = math.min(math.abs(price_change_pct) * 10, 100)

dynamic_color = price_change_pct > 0 ? 
    color.new(color.green, 100 - color_intensity) : 
    color.new(color.red, 100 - color_intensity)

// Multi-level color coding
volatility = ta.atr(14) / close * 100
vol_color = volatility > 3 ? color.red : 
           volatility > 2 ? color.orange :
           volatility > 1 ? color.yellow : color.green

// Plot with dynamic colors
sma_20 = ta.sma(close, 20)
plot(sma_20, "Dynamic SMA", color=dynamic_color, linewidth=2)

// ===== CUSTOM SHAPES AND SYMBOLS =====
// Price action patterns with custom shapes
is_inside_bar = high < high[1] and low > low[1]
is_outside_bar = high > high[1] and low < low[1]
is_up_bar = close > open
is_down_bar = close < open

// Plot different shapes for different patterns
plotshape(is_inside_bar and is_up_bar, "Inside Bull", 
          shape.circle, location.belowbar, color.green, size=size.tiny)
plotshape(is_inside_bar and is_down_bar, "Inside Bear", 
          shape.circle, location.abovebar, color.red, size=size.tiny)
plotshape(is_outside_bar and is_up_bar, "Outside Bull", 
          shape.square, location.belowbar, color.lime, size=size.small)
plotshape(is_outside_bar and is_down_bar, "Outside Bear", 
          shape.square, location.abovebar, color.maroon, size=size.small)

// Custom Unicode symbols
plotchar(high == ta.highest(high, 20), "New High", "🔥", location.abovebar, color.orange, size=size.normal)
plotchar(low == ta.lowest(low, 20), "New Low", "❄️", location.belowbar, color.aqua, size=size.normal)

// ===== BACKGROUND STYLING =====
// Time-based background coloring
is_morning = hour >= 9 and hour < 12
is_afternoon = hour >= 12 and hour < 16
is_after_hours = hour >= 16 or hour < 9

session_color = is_morning ? color.new(color.blue, 98) :
                is_afternoon ? color.new(color.orange, 98) :
                color.new(color.gray, 99)

bgcolor(session_color, title="Session Background")

// Trend-based background
ema_50 = ta.ema(close, 50)
ema_200 = ta.ema(close, 200)
strong_uptrend = close > ema_50 and ema_50 > ema_200 and close > close[5]
strong_downtrend = close < ema_50 and ema_50 < ema_200 and close < close[5]

trend_bg = strong_uptrend ? color.new(color.green, 97) :
           strong_downtrend ? color.new(color.red, 97) : na
bgcolor(trend_bg, title="Trend Background")

// ===== LINES AND DRAWINGS =====
var line[] trend_lines = array.new<line>()
var box[] price_boxes = array.new<box>()

// Swing point connections
swing_high = ta.pivothigh(high, 5, 5)
swing_low = ta.pivotlow(low, 5, 5)

var float last_swing_high = na
var int last_swing_high_bar = na
var float last_swing_low = na
var int last_swing_low_bar = na

// Draw trend lines connecting swing points
if not na(swing_high)
    if not na(last_swing_high)
        trend_line = line.new(
            x1=last_swing_high_bar, y1=last_swing_high,
            x2=bar_index - 5, y2=swing_high,
            color=swing_high > last_swing_high ? color.green : color.red,
            width=1, style=line.style_dashed
        )
        array.push(trend_lines, trend_line)
        
        // Keep only recent lines
        if array.size(trend_lines) > 20
            line.delete(array.get(trend_lines, 0))
            array.shift(trend_lines)
    
    last_swing_high := swing_high
    last_swing_high_bar := bar_index - 5

if not na(swing_low)
    if not na(last_swing_low)
        trend_line = line.new(
            x1=last_swing_low_bar, y1=last_swing_low,
            x2=bar_index - 5, y2=swing_low,
            color=swing_low < last_swing_low ? color.red : color.green,
            width=1, style=line.style_dashed
        )
        array.push(trend_lines, trend_line)
        
        if array.size(trend_lines) > 20
            line.delete(array.get(trend_lines, 0))
            array.shift(trend_lines)
    
    last_swing_low := swing_low
    last_swing_low_bar := bar_index - 5

// ===== BOXES AND RECTANGLES =====
// Daily high/low boxes
daily_high = request.security(syminfo.tickerid, "1D", high)
daily_low = request.security(syminfo.tickerid, "1D", low)
daily_open = request.security(syminfo.tickerid, "1D", open)

// Create box for daily range
if timeframe.isintraday and ta.change(time("1D"))
    if array.size(price_boxes) > 0
        box.delete(array.get(price_boxes, array.size(price_boxes) - 1))
    
    daily_box = box.new(
        left=bar_index, top=daily_high,
        right=bar_index + 50, bottom=daily_low,
        bgcolor=color.new(color.blue, 95),
        border_color=color.blue,
        border_width=1
    )
    array.push(price_boxes, daily_box)

// Consolidation zones
consolidation_threshold = ta.atr(20) * 0.5
price_range = ta.highest(high, 10) - ta.lowest(low, 10)
is_consolidating = price_range < consolidation_threshold

var box consolidation_box = na
if is_consolidating and not is_consolidating[1]
    consolidation_box := box.new(
        left=bar_index - 10, top=ta.highest(high, 10),
        right=bar_index + 10, bottom=ta.lowest(low, 10),
        bgcolor=color.new(color.yellow, 90),
        border_color=color.yellow,
        border_width=1
    )

if not is_consolidating and is_consolidating[1] and not na(consolidation_box)
    box.set_right(consolidation_box, bar_index)

// ===== LABELS AND ANNOTATIONS =====
// Price level labels
resistance_level = ta.highest(high, 50)
support_level = ta.lowest(low, 50)

if barstate.islast
    // Resistance label
    resistance_label = label.new(
        x=bar_index, y=resistance_level,
        text="R: " + str.tostring(resistance_level, "#.##"),
        color=color.red, textcolor=color.white,
        style=label.style_label_down,
        size=size.normal
    )
    
    // Support label
    support_label = label.new(
        x=bar_index, y=support_level,
        text="S: " + str.tostring(support_level, "#.##"),
        color=color.green, textcolor=color.white,
        style=label.style_label_up,
        size=size.normal
    )

// Volume labels on high volume bars
avg_volume = ta.sma(volume, 20)
high_volume = volume > avg_volume * 2

if high_volume and not high_volume[1]
    volume_label = label.new(
        x=bar_index, y=high,
        text="Vol: " + str.tostring(volume / 1000000, "#.#") + "M",
        color=color.new(color.purple, 80),
        textcolor=color.white,
        style=label.style_label_down,
        size=size.small
    )

// ===== TABLES FOR DATA DISPLAY =====
// Market statistics table
var table stats_table = table.new(position.top_left, 2, 8, bgcolor=color.white, border_width=1)

if barstate.islast
    // Symbol information
    table.cell(stats_table, 0, 0, "Symbol", text_color=color.black, bgcolor=color.gray)
    table.cell(stats_table, 1, 0, syminfo.ticker, text_color=color.black)
    
    // Current price
    table.cell(stats_table, 0, 1, "Price", text_color=color.black, bgcolor=color.gray)
    table.cell(stats_table, 1, 1, str.tostring(close, "#.####"), text_color=color.black)
    
    // Daily change
    daily_change = (close - daily_open) / daily_open * 100
    table.cell(stats_table, 0, 2, "Daily %", text_color=color.black, bgcolor=color.gray)
    table.cell(stats_table, 1, 2, str.tostring(daily_change, "+#.##") + "%", 
               text_color=daily_change > 0 ? color.green : color.red)
    
    // Volume
    table.cell(stats_table, 0, 3, "Volume", text_color=color.black, bgcolor=color.gray)
    table.cell(stats_table, 1, 3, str.tostring(volume, "#.##"), text_color=color.black)
    
    // ATR
    atr_value = ta.atr(14)
    table.cell(stats_table, 0, 4, "ATR(14)", text_color=color.black, bgcolor=color.gray)
    table.cell(stats_table, 1, 4, str.tostring(atr_value, "#.####"), text_color=color.black)
    
    // RSI
    rsi_value = ta.rsi(close, 14)
    table.cell(stats_table, 0, 5, "RSI(14)", text_color=color.black, bgcolor=color.gray)
    rsi_color = rsi_value > 70 ? color.red : rsi_value < 30 ? color.green : color.black
    table.cell(stats_table, 1, 5, str.tostring(rsi_value, "#.#"), text_color=rsi_color)
    
    // Market structure
    table.cell(stats_table, 0, 6, "Trend", text_color=color.black, bgcolor=color.gray)
    trend_text = strong_uptrend ? "Strong Up" : strong_downtrend ? "Strong Down" : "Sideways"
    trend_color = strong_uptrend ? color.green : strong_downtrend ? color.red : color.gray
    table.cell(stats_table, 1, 6, trend_text, text_color=trend_color)
    
    // Time info
    table.cell(stats_table, 0, 7, "Time", text_color=color.black, bgcolor=color.gray)
    table.cell(stats_table, 1, 7, str.format("{0,time,HH:mm}", timenow), text_color=color.black)

// ===== PERFORMANCE HEATMAP =====
// Create a heatmap showing performance across different periods
var table heatmap = table.new(position.bottom_left, 6, 3, bgcolor=color.white, border_width=1)

if barstate.islast
    // Headers
    table.cell(heatmap, 0, 0, "Period", text_color=color.white, bgcolor=color.black)
    table.cell(heatmap, 1, 0, "1D", text_color=color.white, bgcolor=color.black)
    table.cell(heatmap, 2, 0, "1W", text_color=color.white, bgcolor=color.black)
    table.cell(heatmap, 3, 0, "1M", text_color=color.white, bgcolor=color.black)
    table.cell(heatmap, 4, 0, "3M", text_color=color.white, bgcolor=color.black)
    table.cell(heatmap, 5, 0, "1Y", text_color=color.white, bgcolor=color.black)
    
    // Performance calculations
    perf_1d = (close - close[1]) / close[1] * 100
    perf_1w = (close - close[5]) / close[5] * 100
    perf_1m = (close - close[22]) / close[22] * 100
    perf_3m = (close - close[66]) / close[66] * 100
    perf_1y = (close - close[252]) / close[252] * 100
    
    perfs = array.from(perf_1d, perf_1w, perf_1m, perf_3m, perf_1y)
    
    // Returns row
    table.cell(heatmap, 0, 1, "Return %", text_color=color.black)
    for i = 0 to 4
        perf = array.get(perfs, i)
        cell_color = perf > 5 ? color.new(color.green, 60) :
                     perf > 0 ? color.new(color.green, 80) :
                     perf > -5 ? color.new(color.red, 80) : color.new(color.red, 60)
        
        table.cell(heatmap, i + 1, 1, str.tostring(perf, "#.#") + "%", 
                   text_color=color.white, bgcolor=cell_color)
    
    // Volatility row  
    vol_1d = ta.stdev(ta.change(close), 5) / close * 100
    vol_1w = ta.stdev(ta.change(close), 22) / close * 100
    vol_1m = ta.stdev(ta.change(close), 66) / close * 100
    
    table.cell(heatmap, 0, 2, "Vol %", text_color=color.black)
    table.cell(heatmap, 1, 2, str.tostring(vol_1d, "#.#"), text_color=color.black)
    table.cell(heatmap, 2, 2, str.tostring(vol_1w, "#.#"), text_color=color.black)
    table.cell(heatmap, 3, 2, str.tostring(vol_1m, "#.#"), text_color=color.black)
    table.cell(heatmap, 4, 2, "N/A", text_color=color.gray)
    table.cell(heatmap, 5, 2, "N/A", text_color=color.gray)

// ===== MULTI-PANE VISUALIZATION =====
// Plot oscillators in separate pane when not overlay
rsi_14 = ta.rsi(close, 14)
stoch_k = ta.stoch(close, high, low, 14)
[macd_line, signal_line, histogram] = ta.macd(close, 12, 26, 9)

// These would go in a separate pane if overlay=false
plot(rsi_14, "RSI", color.purple, display=display.data_window)
plot(stoch_k, "Stoch", color.orange, display=display.data_window)
plot(macd_line, "MACD", color.blue, display=display.data_window)
plot(signal_line, "Signal", color.red, display=display.data_window)

// ===== CUSTOM DRAWING TOOLS =====
// Draw support/resistance zones as filled areas
var box[] sr_zones = array.new<box>()

// Function to draw S/R zone
drawSRZone(level, strength, isResistance) =>
    zone_height = ta.atr(14) * 0.5
    zone_color = isResistance ? color.red : color.green
    
    sr_box = box.new(
        left=bar_index - 50, top=level + (isResistance ? zone_height : 0),
        right=bar_index + 20, bottom=level - (isResistance ? 0 : zone_height),
        bgcolor=color.new(zone_color, 85),
        border_color=zone_color,
        border_width=strength
    )
    
    array.push(sr_zones, sr_box)
    
    // Limit number of zones
    if array.size(sr_zones) > 10
        box.delete(array.get(sr_zones, 0))
        array.shift(sr_zones)

// Identify and draw key levels
pivot_high = ta.pivothigh(high, 10, 10)
pivot_low = ta.pivotlow(low, 10, 10)

if not na(pivot_high)
    drawSRZone(pivot_high, 2, true)

if not na(pivot_low)
    drawSRZone(pivot_low, 2, false)

// ===== CHART OVERLAYS =====
// Price projection based on linear regression
lr_length = 20
lr_slope = ta.linreg(close, lr_length, 1) - ta.linreg(close, lr_length, 0)
lr_projection = close + lr_slope * 10  // Project 10 bars ahead

plot(lr_projection, "Price Projection", color=color.new(color.yellow, 50), 
     style=plot.style_circles, linewidth=1)

// Fibonacci extension levels
fib_high = ta.highest(high, 50)
fib_low = ta.lowest(low, 50)
fib_range = fib_high - fib_low

fib_161 = fib_high + fib_range * 0.618
fib_261 = fib_high + fib_range * 1.618

plot(fib_161, "Fib 161.8%", color=color.new(color.orange, 70), 
     style=plot.style_stepline_diamond, linewidth=1)
plot(fib_261, "Fib 261.8%", color=color.new(color.red, 70), 
     style=plot.style_stepline_diamond, linewidth=1)

// ===== ANIMATION EFFECTS =====
// Pulsating effect for alerts
alert_condition = ta.crossover(close, sma_20)
pulse_intensity = alert_condition ? 0 : alert_condition[1] ? 20 : 
                 alert_condition[2] ? 40 : alert_condition[3] ? 60 : 80

alert_color = color.new(color.yellow, pulse_intensity)
plotshape(alert_condition or alert_condition[1] or alert_condition[2] or alert_condition[3], 
          "Alert Pulse", shape.circle, location.abovebar, alert_color, size=size.large)

// Trail effect for moving average
ma_trail_color = close > sma_20 ? 
    color.new(color.green, math.min(90, 50 + (close - sma_20) / sma_20 * 1000)) :
    color.new(color.red, math.min(90, 50 + (sma_20 - close) / sma_20 * 1000))

plot(sma_20, "MA Trail", color=ma_trail_color, linewidth=3)

Overview

Chart Visualization plots a 20-period simple moving average with dynamic color intensity derived from price momentum, marks inside and outside bar patterns using shapes, and labels 20-period price extremes with symbols. It also applies background shading according to session hours and EMA trend alignment, while drawing dashed lines between confirmed swing pivot points.

Details

Published by

danielbodnar on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Trend, Candlestick patterns, Support & resistance, 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.

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

Hercules Rewrite

by g-moe
3 stars

Hercules Rewrite is a signal and visual trade management indicator that overlays entry setups directly on the price chart. It detects candle setups based on minimum tick movement and engulfing patterns, filtering entries through parameters like moving averages

Indicator v5 Candlestick patternsTrend
Updated 5 months ago · None stated GitHub repository of Hercules Rewrite
257 stars

This indicator plots auto trade signals for E-mini S&P 500 futures on the price chart. It computes an EMA200 filter along with day ETH RTH session levels and percentage-based entry zones. Signals trigger CALL or PUT cases when price crosses defined thresholds

Indicator v6 TrendSupport & resistance
Updated 6 weeks ago · None stated GitHub repository of Auto Trade Futures ES
56 stars

This overlay indicator highlights candles with a body smaller than 50% of their total range by coloring them white on the price chart. Simultaneously, it calculates and plots horizontal lines for open prices across multiple higher timeframes, such as daily, we

Indicator v6 Support & resistanceCandlestick patterns Repaints
Updated 2 months ago · None stated GitHub repository of Daily Weekly Monthly Yearly Opens

Reversal Breakout System

by TamaraKGreen
46 stars

This indicator detects inside candles inside larger parent candles on the price chart. It plots colored boxes around inside and parent candles, fills them with user-adjustable transparency, draws Fibonacci retracement lines and mother candle range lines, and d

Indicator v6 Candlestick patternsBreakout
Updated 7 weeks ago · None stated GitHub repository of Reversal Breakout System

Market Monitor 5m

by chris-c-thomas
14 stars

Market Monitor 5m is an intraday context overlay designed for 5-minute chart analysis. It calculates directional bias using exponential moving averages, VWAP, TTM Squeeze volatility state, NYSE TICK market breadth, and ATR volatility regimes. The script plots

Indicator v6 Screeners & dashboardsSupport & resistance Repaints
Updated 6 months ago · MIT GitHub repository of Market Monitor 5m

Pro Pattern Al-Sat

by MeridianAlgo
9 stars

This overlay indicator marks bullish and bearish chart patterns on the price chart and can hide either side. Optional filters require agreement from fast and slow EMAs, Supertrend, and ADX, plus volume, RSI, nearby pivot support or resistance, and a user-defin

Indicator v6 Candlestick patternsTrend
Updated 4 months ago · MIT GitHub repository of Pro Pattern Al-Sat

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