Indicator · Pine Script v6 · Own pane

Correlation Heatmap

by regalouisei· code credited to TradingView

This indicator calculates arithmetic returns across a user-defined list of tickers and visualizes their statistical correlation as a heatmap table in a separate pane.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code216
Settings8inputs
LicenceNone statedfile: MPL-2.0
Last update8 months ago25 Feb 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

216 lines of Pine Script v6 from pinescript/editors_picks/correlation-heatmap.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

correlation-heatmap.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © TradingView

//@version=6
indicator("Correlation Heatmap")

// Correlation Heatmap
// v2, 2026.01.09

// This code's style is based on the recommendations from the Pine Script User Manual's Style guide:
//    https://www.tradingview.com/pine-script-docs/writing/style-guide/



import TradingView/ta/12 as TVta
import TradingView/ValueAtTime/2 as TVvt



//#region ———————————————————— Constants and inputs


// Tooltips
string TT_SYM = "A comma-separated list of symbols or ticker IDs with optional spaces."
string TT_COL = (
    "Defines the base colors for the correlation heatmap's color gradient:\n\n "
    + "- The first input sets the color for maximum anticorrelation (corr = -1).\n "
    + "- The second input sets the color for no correlation (corr = 0).\n "
    + "- The third input sets the color for maximum correlation (corr = 1)."
)
string TT_TF = "Timeframe of the sampled returns. Options are '1W' or '1M'."
string TT_MP = (
    "If enabled, the indicator limits the data used in the correlation calculation to the number of "
    + "periods specified in the input field. Otherwise, it uses the maximum number of periods allowed "
    + "by the chart's time span."
)
string TT_PR = "Specifies the number of fractional digits in the displayed correlation values."

// Symbol list, timeframe, and period control inputs
string symbolListInput = input.text_area("AAPL, GOLD, MSFT, BTCUSD, XOM, TLT, DBC, VNQ, SQQQ, VXX, GDX", "Symbol list", TT_SYM)
string tfInput         = input.timeframe("1M", "Returns timeframe", ["1W", "1M"], TT_TF)

// Data limit and precision inputs
bool limitInput      = input.bool(false, "Max periods",        tooltip = TT_MP, inline = "01")
int  maxPeriodsInput = input.int(60,     "         ",   2,     tooltip = TT_MP, inline = "01")
int  precisionInput  = input.int(2,      "Precision",   1, 16, tooltip = TT_PR)

// Gradient color inputs
string GRP1 = "Color gradient"
color negVeryStrongInput = input.color(#fb8c00, "", TT_COL, "01", group = GRP1)
color neutralInput       = input.color(#ffffff, "", TT_COL, "01", group = GRP1)
color posVeryStrongInput = input.color(#00acc1, "", TT_COL, "01", group = GRP1)
//#endregion



//#region ———————————————————— Functions


// @function            Calculates the arithmetic return for the instrument referenced by a specified symbol or ticker
//                      ID based on confirmed prices sampled at aligned periodic points. The function uses spread ticker
//                      IDs formed by the chart's symbol and the specified symbol in its requests to retrieve prices
//                      at times that align with periodic points on the current chart.
// @param symbol        (series string) The symbol of the instrument for which to request aligned price data. For
//                      consistency, the ticker IDs used by the requests include extended hours and dividend adjustment
//                      modifiers, and they inherit additional modifiers from the chart, such as "settlement-as-close"
//                      settings.
// @param timeframe     (series string) The timeframe of the time-aligned data request. The value should represent a
//                      timeframe that is higher than or equal to the chart's timeframe.
// @returns             (float) The arithmetic return of the instrument's prices retrieved at aligned sample points.
getAlignedReturns(series string symbol, series string timeframe) =>
    string chartTicker = ticker.new(syminfo.prefix, syminfo.tickerid)
    string standard1   = ticker.standard(chartTicker)
    string standard2   = ticker.standard(symbol)
    string sumSpread   = ticker.modify(
        ticker.inherit(chartTicker, standard1 + "+" + standard2), session.extended, adjustment.dividends
    )
    string diffSpread = ticker.modify(
        ticker.inherit(chartTicker, standard1 + "-" + standard2), session.extended, adjustment.dividends
    )
    float  currPrice   = close[1]
    float  prevPrice   = nz(close[2], open[1])
    [currSum, prevSum] = request.security(
        sumSpread, timeframe, [currPrice, prevPrice], barmerge.gaps_on, barmerge.lookahead_on
    )
    [currDiff, prevDiff] = request.security(
        diffSpread, timeframe, [currPrice, prevPrice], barmerge.gaps_on, barmerge.lookahead_on
    )
    TVta.changePercent(0.5 * (currSum - currDiff), 0.5 * (prevSum - prevDiff))


// @function            Calculates time-aligned periodic returns for the instruments referenced by an array of symbols,
//                      and stores the results in a matrix. Each row in the matrix corresponds to one of the
//                      specified instruments, and each column corresponds to a successive period where the data for
//                      each instrument is not `na`.
// @param symbols       (array<string>) References an array of symbols representing the instruments for
//                      which to request aligned price data. For consistency, each ticker ID used in the data requests
//                      includes extended hours and dividend adjustment modifiers, and it inherits additional modifiers
//                      from the chart, such as "settlement-as-close" settings.
// @param timeframe     (simple string) The timeframe of the time-aligned data request. The value must represent a
//                      timeframe that is greater than or equal to the chart's timeframe.
// @param maxPeriods    (simple int) Optional. The maximum number of periodic returns to store for each requested
//                      dataset. If the value is `na`, the maximum length of the data is the span of the current chart.
//                      The default is `na`.
// @returns             (matrix<float>) The ID of a matrix containing aligned periodic returns for each requested
//                      dataset.
collectReturns(array<string> symbols, simple string timeframe, simple int maxPeriods = na) =>
    var int           numSymbols   = symbols.size()
    var array<float>  returnsArray = array.new<float>(numSymbols)
    var matrix<float> result       = matrix.new<float>(numSymbols, 0)
    bool exclude = false
    for [i, symbol] in symbols
        float priceReturn = getAlignedReturns(symbol, timeframe)
        if na(priceReturn)
            exclude := true
            break
        returnsArray.set(i, priceReturn)
    int cols = result.columns()
    if not exclude
        result.add_col(cols, returnsArray)
        cols += 1
    if cols > maxPeriods
        result.remove_col(0)
    result


// @function            Calculates the Pearson correlation coefficient between the elements stored in two "float"
//                      arrays. The value represents the linear relationship between the arrays' elements. The
//                      coefficient is a measure of the covariance between the arrays, normalized by the product of
//                      their standard deviaitions.
// @param id1           (array<float>) References the first array to compare in the calculation. The array's size must
//                      match the size of the `id2` array.
// @param id2           (array<float>) References the second array to compare in the calculation. The array's size must
//                      match the size of the `id1` array.
// @returns             (float) The correlation coefficient between the `id1` and `id2` arrays' elements. The
//                      coefficient ranges from -1 to 1. A value of 1 indicates perfect positive correlation, -1
//                      indicates perfect negative correlation (anticorrelation), and 0 indicates no correlation.
arrayCorrelation(array<float> id1, array<float> id2) =>
    float covariance = array.covariance(id1, id2)
    float std1 = id1.stdev()
    float std2 = id2.stdev()
    float result = covariance / (std1 * std2)
//#endregion



//#region ———————————————————— Calculations and display


// @variable References an array of symbol strings representing the instruments for which to calculate correlation.
//           The script converts all letters in the `symbolListInput` to uppercase, splits the input value by its
//           commas, then trims all whitespaces from each item.
var array<string> symbolsArray = TVvt.getArrayFromString(str.upper(symbolListInput))

// @variable The number of symbol strings in the array referenced by `symbolsArray`.
var int numSymbols = symbolsArray.size()
// Calculate the height and width of each table cell, including headers, to evenly distribute cells within the pane.
var float cellWidth  = 95.0 / (numSymbols + 1)
var float cellHeight = 90.0 / (numSymbols + 1)

// @variable References a matrix containing monthly or weekly returns for each specified instrument.
//           Each row corresponds to an instrument (e.g., row 0 stores data for the instrument referenced by the first
//           symbol), and each column corresponds to a period (e.g., column 0 stores the oldest period's returns).
matrix<float> symbolReturns = collectReturns(symbolsArray, tfInput, limitInput ? maxPeriodsInput : na)

// @variable References a table with `numSymbols + 1` rows and columns for the correlation heatmap display.
var table heatmap = table.new(
    position.middle_center, numSymbols + 1, numSymbols + 1, border_color = #8f93a1, border_width = 1
)

// Logic to initialize the table's header cells on the first bar.
if barstate.isfirst
    // Initialize the top-left cell with blank text.
    heatmap.cell(0, 0, "", cellWidth, cellHeight, chart.fg_color, bgcolor = chart.bg_color)
    // Initialize the leftmost and top cell with symbol names.
    for [index, symbol] in symbolsArray
        heatmap.cell(0, index + 1, symbol, cellWidth, cellHeight, chart.fg_color, bgcolor = chart.bg_color)
        heatmap.cell(index + 1, 0, symbol, cellWidth, cellHeight, chart.fg_color, bgcolor = chart.bg_color)

// Logic to display correlation and length data on the last bar.
if barstate.islast
    // @variable The number of periods represented by the `symbolReturns` matrix.
    int numPeriods = symbolReturns.columns()
    // Update the table's first cell to show the number of analyzed periods.
    heatmap.cell_set_text(0, 0, str.format("Length:\n{0} {1}", numPeriods, tfInput == "1M" ? "months" : "weeks"))
    // Nested loops to calculate correlations and set the `heatmap` cells.
    for i = 0 to numSymbols - 1
        for j = 0 to i
            // Initialize the cell with a predefined text and background color if `j` and `i` are the same.
            if j == i
                string cellText = numPeriods < 2 ? "NaN" : "1"
                color  bgColor  = numPeriods < 2 ? color(na) : posVeryStrongInput
                heatmap.cell(i + 1, j + 1, cellText, cellWidth, cellHeight, #000000, bgcolor = bgColor)
                continue
            // @variable References an array of returns for the `i`-th listed instrument.
            array<float> returns1 = symbolReturns.row(i)
            // @variable References an array of returns for the `j`-th listed instrument.
            array<float> returns2 = symbolReturns.row(j)
            // @variable The correlation coefficient between the values in the `returns1` and `returns2` arrays.
            float correlation = arrayCorrelation(returns1, returns2)
            // @variable A string representing the correlation value, rounded to `precisionInput` fractional digits.
            string cellText = str.tostring(correlation, "0." + str.repeat("0", precisionInput))
            // @variable The cell's background color, which uses a polarized gradient based on the correlation's sign.
            color bgColor = switch math.sign(correlation)
                1 => color.from_gradient(correlation,  0, 1, neutralInput, posVeryStrongInput)
                =>   color.from_gradient(correlation, -1, 0, negVeryStrongInput, neutralInput)
            // Initialize the cells at `i + 1, j + 1`, and `j + 1, i + 1` using `cellText` and `bgColor`.
            heatmap.cell(i + 1, j + 1, cellText, cellWidth, cellHeight, #000000, bgcolor = bgColor)
            heatmap.cell(j + 1, i + 1, cellText, cellWidth, cellHeight, #000000, bgcolor = bgColor)

// Raise an error if the `tfInput` represents a timeframe lower than the chart's timeframe.
if timeframe.in_seconds(tfInput) < timeframe.in_seconds()
    runtime.error(
        "For accurate calculations, the requested timeframe must be higher than or equal to the chart's timeframe."
    )
//#endregion

Overview

Correlation Heatmap samples returns at weekly or monthly timeframes aligned with the chart data. Users can configure the symbol list, returns timeframe, maximum periods used for calculation, display precision, and gradient colors representing positive, neutral, and negative correlation.

Details

Published by

regalouisei on GitHub

Code credit

TradingView, as written in the script's header

Draws

Separate pane below the chart

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.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Symbol listtextAAPL, GOLD, MSFT, BTCUSD, XOM, TLT, DBC, VNQ, SQQQ, VXX, GDXsymbolListInput
Returns timeframetimeframe1MtfInput
Max periodsboolfalselimitInput
         int60maxPeriodsInput
Precisionint2precisionInput
negVeryStrongInputcolor#fb8c00negVeryStrongInput
neutralInputcolor#ffffffneutralInput
posVeryStrongInputcolor#00acc1posVeryStrongInput
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

947 stars

This indicator measures the chart symbol’s percentage change from the opening price at the start of each US presidential term and plots those values as histogram columns in a separate pane. Columns are offset so each administration appears separately, with a s

Indicator v6 Screeners & dashboards
Updated 12 days ago · GPL-3.0 GitHub repository of Presidents Performance

This indicator scans a pasted list of symbols for RSI directional momentum and shows matching long and short signals in a table in a separate pane. The user chooses continuous break, continuous retracement, flip break, flip retracement, divergence, or hidden d

Indicator v6 Oscillators & momentumDivergence
Updated 1 year ago · MPL-2.0 GitHub repository of Momentum Setup - RSI Directional Momentum Scanner

Tables-001

by ricardosantos79
261 stars

This indicator builds a TradingView table in a separate pane and fills its cells with fixed placeholder text according to whether each row and column index is even or odd. Users set the table position, the number of rows and columns, and the background, frame,

Indicator v4 Screeners & dashboards
Updated 4 years ago · None stated GitHub repository of Tables-001
257 stars

Donald SPX - Options Trading is an indicator designed to assist SPX index option traders by tracking session benchmarks and multi-timeframe moving average data. It calculates a 200-period weighted moving average (WMA) and requests multi-timeframe bar data from

Indicator v5 Moving averagesScreeners & dashboards Repaints
Updated 7 weeks ago · None stated GitHub repository of Donald SPX - Options Trading

Index Member Distribution

by TradersPost
228 stars

Calculates and plots a weighted histogram of constituent returns for major market indices (NDX, SPX, DJIA, and RUT) in a separate pane. Each histogram bin reflects the summed weights of members within that percentage return bracket. The script renders vertical

Indicator v6 Screeners & dashboards
Updated 3 months ago · None stated GitHub repository of Index Member Distribution

KamaFama

by Mastaaa1987
141 stars

KamaFama is an indicator that translates a Freqtrade trading strategy into Pine Script for visualization. It combines Kaufman Adaptive Moving Average (KAMA), MAMA/FAMA calculations derived via Hilbert Transform, Williams %R, and correlation trend filters to ev

Indicator v6 Moving averagesOscillators & momentum
Updated 6 weeks ago · MIT GitHub repository of KamaFama

More Screeners & dashboards scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers