heatmap

Pasted Oct 22, 2026, 11:04 PM1 file94 lines

Scan to open on your phone

Point a camera at the QR code - it opens this exact paste, no app needed.

https://codepastes.com/zzgsp8trsjh2d4rv
heatmap
//@version=6
indicator("Mini Heatmap - 7 Big Techs", shorttitle="Heatmap", overlay=true, max_labels_count=100)

// =====================================================================
// Painel fixo no gráfico mostrando a variação % do dia (igual ao Stock
// Heatmap do TradingView) de até 7 ativos escolhidos por você.
// O Heatmap nativo do TradingView não deixa filtrar só alguns tickers,
// ele é preso ao índice inteiro. Esse indicador resolve isso: você
// escolhe exatamente quem quer ver, plugado direto no seu gráfico.
// =====================================================================

// Peso (%) é o quanto cada ativo pesa dentro do Nasdaq 100 (carteira do QQQ).
// O painel ordena sozinho do mais poderoso pro menos poderoso usando esse número.
// Atualize esses valores de vez em quando, o peso muda com o tempo (fonte: holdings do QQQ).
grpAtivos = "Ativos (padrão: pesos aproximados do Nasdaq 100, ajuste quando quiser)"
sym1 = input.symbol("NASDAQ:NVDA", "Ativo 1", group=grpAtivos, inline="a1")
w1   = input.float(8.7, "Peso %", group=grpAtivos, inline="a1")
sym2 = input.symbol("NASDAQ:AAPL", "Ativo 2", group=grpAtivos, inline="a2")
w2   = input.float(7.6, "Peso %", group=grpAtivos, inline="a2")
sym3 = input.symbol("NASDAQ:MSFT", "Ativo 3", group=grpAtivos, inline="a3")
w3   = input.float(5.6, "Peso %", group=grpAtivos, inline="a3")
sym4 = input.symbol("NASDAQ:AMZN", "Ativo 4", group=grpAtivos, inline="a4")
w4   = input.float(4.6, "Peso %", group=grpAtivos, inline="a4")
sym5 = input.symbol("NASDAQ:TSLA", "Ativo 5", group=grpAtivos, inline="a5")
w5   = input.float(3.8, "Peso %", group=grpAtivos, inline="a5")
sym6 = input.symbol("NASDAQ:META", "Ativo 6", group=grpAtivos, inline="a6")
w6   = input.float(3.5, "Peso %", group=grpAtivos, inline="a6")
sym7 = input.symbol("NASDAQ:GOOGL", "Ativo 7", group=grpAtivos, inline="a7")
w7   = input.float(3.4, "Peso %", group=grpAtivos, inline="a7")

grpVisual = "Visual"
posOpt = input.string("Superior Direito", "Posição do painel", options=["Superior Direito", "Superior Esquerdo", "Superior Centro", "Inferior Direito", "Inferior Esquerdo", "Inferior Centro", "Meio Direito", "Meio Esquerdo"], group=grpVisual)
cols = input.int(4, "Colunas", minval=1, maxval=7, group=grpVisual, tooltip="Quantos quadrados por linha. Ex: 4 colunas com 7 ativos vira 4+3")
txtSizeOpt = input.string("Normal", "Tamanho do texto", options=["Minúsculo", "Pequeno", "Normal", "Grande"], group=grpVisual)
maxPct = input.float(3.0, "Saturação máxima (%)", minval=0.1, group=grpVisual, tooltip="A partir de quantos % de variação a cor fica no verde/vermelho mais forte")
showTicker = input.bool(true, "Mostrar ticker", group=grpVisual)
showPct = input.bool(true, "Mostrar variação %", group=grpVisual)
showWeight = input.bool(true, "Mostrar peso %", group=grpVisual)

getPosition(p) =>
    result = switch p
        "Superior Esquerdo" => position.top_left
        "Superior Centro"   => position.top_center
        "Inferior Direito"  => position.bottom_right
        "Inferior Esquerdo" => position.bottom_left
        "Inferior Centro"   => position.bottom_center
        "Meio Direito"      => position.middle_right
        "Meio Esquerdo"     => position.middle_left
        => position.top_right
    result

getTxtSize(s) =>
    s == "Minúsculo" ? size.tiny : s == "Pequeno" ? size.small : s == "Grande" ? size.large : size.normal

// variação % do dia (igual "Change 1D, %" do heatmap), calculada no contexto diário
f_change(sym) =>
    request.security(sym, "D", (close - close[1]) / close[1] * 100, barmerge.gaps_off, barmerge.lookahead_off)

f_ticker(sym) =>
    parts = str.split(sym, ":")
    array.size(parts) > 1 ? array.get(parts, array.size(parts) - 1) : sym

f_color(pct) =>
    t = math.min(math.abs(pct) / maxPct, 1.0)
    pct >= 0 ? color.from_gradient(t, 0, 1, color.new(color.green, 80), color.new(color.green, 5)) : color.from_gradient(t, 0, 1, color.new(color.red, 80), color.new(color.red, 5))

if barstate.islast
    symbols = array.from(sym1, sym2, sym3, sym4, sym5, sym6, sym7)
    weights = array.from(w1, w2, w3, w4, w5, w6, w7)
    n = array.size(symbols)
    rows = int(math.ceil(n / cols))

    // ordena do mais poderoso (maior peso) pro menos poderoso
    rankIdx = array.sort_indices(array.copy(weights), order.descending)

    var table tbl = table.new(getPosition(posOpt), cols, rows, border_width=1, border_color=color.new(color.gray, 50), frame_width=1, frame_color=color.new(color.gray, 50))

    txtSz = getTxtSize(txtSizeOpt)

    for i = 0 to n - 1
        idx = array.get(rankIdx, i)
        s = array.get(symbols, idx)
        w = array.get(weights, idx)
        pct = f_change(s)
        tk = f_ticker(s)
        r = int(math.floor(i / cols))
        c = int(i % cols)
        line1 = showTicker ? tk : ""
        line2 = showWeight ? str.tostring(w, "#.#") + "%" : ""
        line3 = showPct ? (pct >= 0 ? "+" : "") + str.tostring(pct, "#.##") + "%" : ""
        txt = line1
        txt := txt + (line2 != "" ? "\n" + line2 : "")
        txt := txt + (line3 != "" ? "\n" + line3 : "")
        table.cell(tbl, c, r, txt, text_color=color.white, bgcolor=f_color(pct), text_size=txtSz)

5,184 chars · codepastes.com