๐ŸŽ“ Tutorials

TradingView Pine Script Multi-Chart Layout: Display Multiple Panels from One Indicator

โš ๏ธ Disclosure: Some links on this page are affiliate links. If you sign up through them, I may earn a commission โ€” at no extra cost to you. I only review tools I actually use.
# TradingView Pine Script Multi-Chart Layout: Display Multiple Panels from One Indicator

Every serious trader hits the same wall: you want RSI in one pane, volume in another, and moving averages on the price chart โ€” but TradingView limits how many indicators you can load (3 on the free plan). The solution? Build one Pine Script indicator that outputs to multiple chart panels simultaneously.

This tutorial walks through every technique available in Pine Script v5 and v6 to create multi-panel layouts from a single script. By the end, you'll have a working "Swiss Army Knife" indicator that plots across the main chart and its own separate pane at the same time.

> Need more indicator slots? Upgrade your TradingView plan to unlock up to 25 indicators per chart โ€” essential for complex multi-panel setups.

The Problem: One Indicator, One Pane?

By default, a Pine Script indicator lives in exactly one place:

//@version=6
indicator("My Indicator", overlay = false) // separate pane only
plot(ta.rsi(close, 14), "RSI")

This means if you want RSI below *and* an EMA on the price chart, you traditionally needed two separate indicators โ€” eating into your indicator limit.

That changed with force_overlay.

Step 1: Understanding force_overlay โ€” The Key to Multi-Panel Output

Introduced in mid-2024 and available in both Pine Script v5 and v6, force_overlay lets individual plot elements display on the main chart pane even when the script itself occupies a separate pane.

Here's the core concept:

//@version=6
indicator("Multi-Panel Demo", overlay = false)

// This plots in the indicator's own pane (below the chart)
plot(ta.rsi(close, 14), "RSI", color.purple)

// This plots on the MAIN price chart, despite overlay = false
plot(ta.ema(close, 21), "EMA 21", color.orange, force_overlay = true)

What's happening:

This single parameter is what makes multi-panel layouts possible from one script.

Which Functions Support force_overlay?

Almost every visual function in Pine Script supports it:

Functionforce_overlay Support
plot()โœ…
plotshape()โœ…
plotchar()โœ…
plotarrow()โœ…
plotcandle()โœ…
plotbar()โœ…
bgcolor()โœ…
hline()โœ…
fill()โœ…
label.new()โœ…
line.new()โœ…
box.new()โœ…
table.new()โœ…

Step 2: Build a Combined RSI + EMA + Volume Indicator

Let's build something practical โ€” a single indicator that shows:

1. Main chart: EMA crossover lines + buy/sell signals

2. Separate pane: RSI with overbought/oversold zones 3. Separate pane: Volume (normalized) in the same pane as RSI

//@version=6
indicator("Multi-Panel Swiss Knife", overlay = false)

// โ”€โ”€โ”€ INPUTS โ”€โ”€โ”€
int rsiLen      = input.int(14, "RSI Length")
int emaFast     = input.int(9, "Fast EMA")
int emaSlow     = input.int(21, "Slow EMA")

// โ”€โ”€โ”€ CALCULATIONS โ”€โ”€โ”€
float rsiVal    = ta.rsi(close, rsiLen)
float emaF      = ta.ema(close, emaFast)
float emaS      = ta.ema(close, emaSlow)
bool  bullCross = ta.crossover(emaF, emaS)
bool  bearCross = ta.crossunder(emaF, emaS)

// โ”€โ”€โ”€ PANE: RSI (this indicator's own pane) โ”€โ”€โ”€
plot(rsiVal, "RSI", color.new(color.purple, 0), 2)
hline(70, "Overbought", color.red, hline.style_dashed)
hline(30, "Oversold", color.green, hline.style_dashed)
hline(50, "Midline", color.gray, hline.style_dotted)

// Color the RSI pane background on extremes
bgcolor(rsiVal > 70 ? color.new(color.red, 90) : rsiVal < 30 ? color.new(color.green, 90) : na)

// โ”€โ”€โ”€ MAIN CHART: EMA lines (force_overlay) โ”€โ”€โ”€
plot(emaF, "Fast EMA", color.new(color.blue, 0), 2, force_overlay = true)
plot(emaS, "Slow EMA", color.new(color.orange, 0), 2, force_overlay = true)

// โ”€โ”€โ”€ MAIN CHART: Buy/Sell signals (force_overlay) โ”€โ”€โ”€
plotshape(bullCross, "Buy Signal", shape.triangleup,
     location.belowbar, color.green, size = size.small,
     force_overlay = true)
plotshape(bearCross, "Sell Signal", shape.triangledown,
     location.abovebar, color.red, size = size.small,
     force_overlay = true)

// โ”€โ”€โ”€ MAIN CHART: Highlight background on crossover โ”€โ”€โ”€
bgcolor(bullCross ? color.new(color.green, 85) : bearCross ? color.new(color.red, 85) : na,
     force_overlay = true)

Result: One indicator uses one slot, but you see:

๐Ÿ’ก TradingView

Like what you're reading? Try it yourself โ€” this link supports ChartedTrader at no cost to you.

Get TradingView Pro โ€” unlock more indicators per chart โ†’

Step 3: Add a Multi-Symbol Comparison Panel

Want to compare multiple assets in the same pane? Use request.security() to pull data from other symbols:

//@version=6
indicator("Multi-Symbol RSI Comparison", overlay = false)

// โ”€โ”€โ”€ INPUTS โ”€โ”€โ”€
string sym1 = input.symbol("BINANCE:BTCUSDT", "Symbol 1")
string sym2 = input.symbol("BINANCE:ETHUSDT", "Symbol 2")
string sym3 = input.symbol("BINANCE:SOLUSDT", "Symbol 3")
int    len  = input.int(14, "RSI Length")

// โ”€โ”€โ”€ FETCH RSI FROM EACH SYMBOL โ”€โ”€โ”€
float rsi1 = request.security(sym1, timeframe.period, ta.rsi(close, len))
float rsi2 = request.security(sym2, timeframe.period, ta.rsi(close, len))
float rsi3 = request.security(sym3, timeframe.period, ta.rsi(close, len))

// โ”€โ”€โ”€ PLOT ALL IN ONE PANE โ”€โ”€โ”€
plot(rsi1, "BTC RSI", color.orange, 2)
plot(rsi2, "ETH RSI", color.blue, 2)
plot(rsi3, "SOL RSI", color.purple, 2)

hline(70, "OB", color.red, hline.style_dashed)
hline(30, "OS", color.green, hline.style_dashed)

// โ”€โ”€โ”€ MAIN CHART: Label current values โ”€โ”€โ”€
var table infoTable = table.new(position.top_right, 3, 2,
     bgcolor = color.new(color.black, 70),
     force_overlay = true)

if barstate.islast
    table.cell(infoTable, 0, 0, "BTC RSI", text_color = color.orange)
    table.cell(infoTable, 1, 0, "ETH RSI", text_color = color.blue)
    table.cell(infoTable, 2, 0, "SOL RSI", text_color = color.purple)
    table.cell(infoTable, 0, 1, str.tostring(rsi1, "#.0"), text_color = color.white)
    table.cell(infoTable, 1, 1, str.tostring(rsi2, "#.0"), text_color = color.white)
    table.cell(infoTable, 2, 1, str.tostring(rsi3, "#.0"), text_color = color.white)

This gives you a single pane comparing RSI across three symbols, plus a floating info table on the main chart.

Step 4: Simulate Multiple Sub-Panes with Visual Zones

Pine Script doesn't support creating multiple separate panes from one indicator. But you can visually divide a single pane into zones using hline() boundaries and scaled data:

//@version=6
indicator("Dual Zone Panel", overlay = false)

// โ”€โ”€โ”€ RSI: Scaled to upper zone (50โ€“100 range) โ”€โ”€โ”€
float rsiRaw = ta.rsi(close, 14)
float rsiScaled = 50 + (rsiRaw / 100) * 50  // Maps 0โ€“100 โ†’ 50โ€“100

// โ”€โ”€โ”€ Stochastic: Scaled to lower zone (0โ€“50 range) โ”€โ”€โ”€
float stochRaw = ta.stoch(close, high, low, 14)
float stochScaled = (stochRaw / 100) * 50  // Maps 0โ€“100 โ†’ 0โ€“50

// โ”€โ”€โ”€ Visual separator โ”€โ”€โ”€
hline(50, "โ”€โ”€โ”€ Separator โ”€โ”€โ”€", color.new(color.white, 30), hline.style_solid)

// โ”€โ”€โ”€ Upper zone: RSI โ”€โ”€โ”€
plot(rsiScaled, "RSI", color.purple, 2)
hline(85, "RSI OB", color.new(color.red, 60), hline.style_dotted)
hline(65, "RSI OS", color.new(color.green, 60), hline.style_dotted)

// โ”€โ”€โ”€ Lower zone: Stochastic โ”€โ”€โ”€
plot(stochScaled, "Stoch %K", color.teal, 2)
hline(40, "Stoch OB", color.new(color.red, 60), hline.style_dotted)
hline(10, "Stoch OS", color.new(color.green, 60), hline.style_dotted)

// โ”€โ”€โ”€ Labels for clarity โ”€โ”€โ”€
var label rsiLabel = label.new(na, na, "RSI Zone โ†‘", style = label.style_none,
     textcolor = color.purple, size = size.small)
var label stochLabel = label.new(na, na, "Stoch Zone โ†“", style = label.style_none,
     textcolor = color.teal, size = size.small)

if barstate.islast
    label.set_xy(rsiLabel, bar_index + 3, 90)
    label.set_xy(stochLabel, bar_index + 3, 25)

Result: One pane, two visually separated zones โ€” RSI on top, Stochastic on the bottom, divided by a line at 50.

Step 5: The Full Dashboard โ€” Putting It All Together

Here's a production-ready indicator that combines everything:

//@version=6
indicator("๐Ÿ“Š Multi-Chart Dashboard", overlay = false, max_labels_count = 50)

// โ”€โ”€โ”€ INPUTS โ”€โ”€โ”€
int    rsiLen   = input.int(14, "RSI Length", group = "Oscillators")
int    stochLen = input.int(14, "Stoch Length", group = "Oscillators")
int    emaFast  = input.int(9, "Fast EMA", group = "Trend")
int    emaSlow  = input.int(21, "Slow EMA", group = "Trend")
string sym2     = input.symbol("", "Compare Symbol", group = "Multi-Symbol")

// โ”€โ”€โ”€ CALCULATIONS โ”€โ”€โ”€
float rsiVal    = ta.rsi(close, rsiLen)
float stochK    = ta.stoch(close, high, low, stochLen)
float stochD    = ta.sma(stochK, 3)
float emaF      = ta.ema(close, emaFast)
float emaS      = ta.ema(close, emaSlow)
bool  bullX     = ta.crossover(emaF, emaS)
bool  bearX     = ta.crossunder(emaF, emaS)

// โ”€โ”€โ”€ PANE: RSI (upper zone, 50โ€“100) โ”€โ”€โ”€
float rsiDisplay = 50 + (rsiVal / 100) * 50
plot(rsiDisplay, "RSI", color.new(color.purple, 0), 2)

// โ”€โ”€โ”€ PANE: Stochastic (lower zone, 0โ€“50) โ”€โ”€โ”€
float stochDisplay = (stochK / 100) * 50
float stochDDisplay = (stochD / 100) * 50
plot(stochDisplay, "%K", color.new(color.teal, 0), 2)
plot(stochDDisplay, "%D", color.new(color.orange, 0), 1, plot.style_line)

// โ”€โ”€โ”€ PANE: Zone separator and levels โ”€โ”€โ”€
hline(50, "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€", color.new(color.white, 40), hline.style_solid)
hline(85, "RSI OB", color.new(color.red, 70), hline.style_dotted)
hline(65, "RSI OS", color.new(color.green, 70), hline.style_dotted)
hline(40, "Stoch OB", color.new(color.red, 70), hline.style_dotted)
hline(10, "Stoch OS", color.new(color.green, 70), hline.style_dotted)

// โ”€โ”€โ”€ MAIN CHART: EMAs โ”€โ”€โ”€
plot(emaF, "Fast EMA", color.new(color.blue, 0), 2, force_overlay = true)
plot(emaS, "Slow EMA", color.new(color.orange, 0), 2, force_overlay = true)

// โ”€โ”€โ”€ MAIN CHART: Signals โ”€โ”€โ”€
plotshape(bullX, "Buy", shape.triangleup, location.belowbar,
     color.green, size = size.small, force_overlay = true)
plotshape(bearX, "Sell", shape.triangledown, location.abovebar,
     color.red, size = size.small, force_overlay = true)

// โ”€โ”€โ”€ MAIN CHART: Info table โ”€โ”€โ”€
var table dash = table.new(position.top_right, 2, 4,
     bgcolor = color.new(color.black, 75), border_width = 1,
     border_color = color.new(color.gray, 60),
     force_overlay = true)

if barstate.islast
    table.cell(dash, 0, 0, "RSI", text_color = color.purple, text_size = size.small)
    table.cell(dash, 1, 0, str.tostring(rsiVal, "#.0"),
         text_color = rsiVal > 70 ? color.red : rsiVal < 30 ? color.green : color.white,
         text_size = size.small)
    table.cell(dash, 0, 1, "Stoch %K", text_color = color.teal, text_size = size.small)
    table.cell(dash, 1, 1, str.tostring(stochK, "#.0"), text_color = color.white,
         text_size = size.small)
    table.cell(dash, 0, 2, "EMA Trend", text_color = color.blue, text_size = size.small)
    table.cell(dash, 1, 2, emaF > emaS ? "โ–ฒ Bullish" : "โ–ผ Bearish",
         text_color = emaF > emaS ? color.green : color.red,
         text_size = size.small)

    // Optional second symbol comparison
    if sym2 != ""
        float sym2Close = request.security(sym2, timeframe.period, close)
        float sym2Rsi   = request.security(sym2, timeframe.period, ta.rsi(close, rsiLen))
        table.cell(dash, 0, 3, sym2, text_color = color.yellow, text_size = size.small)
        table.cell(dash, 1, 3, str.tostring(sym2Rsi, "#.0"),
             text_color = color.white, text_size = size.small)

v5 vs v6: What Changed for Multi-Chart Layouts?

FeaturePine Script v5Pine Script v6
force_overlayโœ… Availableโœ… Available
request.security()โœ…โœ… (same behavior)
request.footprint()โŒโœ… New in Jan 2026
Line wrappingStrict 4-space rulesโœ… Relaxed (Dec 2025)
AI code assistantโŒโœ… Built-in
Migration required?NoRecommended for new features
Bottom line: force_overlay works in both v5 and v6. If you're writing new code, use v6 โ€” future features will only land there. If you have existing v5 scripts, they'll keep working without changes.

Tips and Limitations

What You Can Do

What You Can't Do (Yet)

Performance Tips

Conclusion

The force_overlay parameter is the single most important feature for building multi-panel Pine Script indicators. Combined with data scaling for visual sub-zones and request.security() for multi-symbol data, you can pack a full trading dashboard into one indicator slot.

This matters most on TradingView's free plan (3 indicators) but is useful even on paid plans โ€” fewer indicators means faster chart loading and a cleaner workspace.

Ready to build your own multi-panel indicators? Start your free TradingView trial to get access to the Pine Script editor, more indicator slots, and real-time data across global markets.

---

*This tutorial uses Pine Script v6 syntax. All force_overlay examples are backward-compatible with v5 โ€” just change the version comment to //@version=5.*

---

*Affiliate Disclosure: This article contains affiliate links. If you sign up through these links, I may earn a commission at no extra cost to you. I only recommend products and services I personally use and trust. All opinions are my own.*

TradingView

Ready to get started? Use the link below โ€” it helps support ChartedTrader at no cost to you.

Get TradingView Pro โ€” unlock more indicators per chart โ†’
๐Ÿ“ˆ

About the author

I'm a systematic trader running live strategies on IB (USDJPY momentum) and Hyperliquid (crypto perps). Every tool reviewed here is something I've used with real capital. Questions? Reach out.

๐Ÿ“š Related Articles

๐ŸŽ“ Tutorials

TradingView Pine Script Strategy Optimization: How to Find the Best Parameters Without Overfitting (2026)

TradingView has no built-in parameter optimizer โ€” but that doesn't mean you're stuck guessing. Here's a systematic approach to finding the best Pine Script strategy parameters without overfitting, using input ranges, visual comparison, walk-forward validation, and real code from a live USDJPY momentum strategy.

March 28, 2026 โฑ 20 min read
๐ŸŽ“ Tutorials

TradingView Free Plan Indicator Limit: How to Combine RSI, EMA, and MACD Into One Pine Script (2026)

Hit TradingView's 2-indicator limit on the free plan? Learn how to combine RSI, EMA, and MACD into a single all-in-one Pine Script v6 indicator โ€” with full copy-paste code, visual customization tips, and a clear upgrade path when you outgrow the workaround.

March 23, 2026 โฑ 10 min read
๐ŸŽ“ Tutorials

TradingView Webhook to Telegram Bot: Get Real-Time Alerts on Your Phone (2026 Setup Guide)

Learn how to send TradingView alerts directly to Telegram using webhooks. Step-by-step guide covering BotFather setup, free relay options, JSON payload formatting, and real trading alert examples โ€” no coding experience required.

March 22, 2026 โฑ 14 min read

๐Ÿ“ฌ Get weekly trading insights

Real trades, honest reviews, no fluff. One email per week.