Skip to content

Set TradingView label text with Pine Script code: here's how

Set TradingView label text with Pine Script code: here’s how

Section titled “Set TradingView label text with Pine Script code: here’s how”

TL;DR
Create the label once with label.new(), keep its ID, and call label.set_text(id, string) whenever you need to refresh what it says.

DifficultyBeginner
Time to implement10-15 min
CategoryVisual Effects
//@version=5
indicator("Dynamic labels", overlay=true, max_labels_count=100)
var label priceLabel = na
if barstate.islast
if na(priceLabel)
priceLabel := label.new(bar_index, close, "", style=label.style_label_left, textcolor=color.white, bgcolor=color.new(color.blue, 70))
label.set_x(priceLabel, bar_index)
label.set_y(priceLabel, close)
label.set_text(priceLabel, "Close: " + str.tostring(close, format.mintick))
Tip. Store label IDs in `var` variables so you can update them across bars without recreating hundreds of labels.

Labels are perfect for callouts—signal names, indicator values, or strategy summaries—but they go stale if you never update their text. label.set_text() lets you refresh existing annotations without re-creating them, which keeps charts clean and performance stable.

  • Set label text when you create the label versus updating it later.
  • Build a reusable helper for dynamic labels.
  • Combine text updates with position changes (label.set_x, label.set_y).
  • Use text formatting (str.tostring) to display prices or percentages cleanly.
HelperPurpose
label.new(x, y, text, ...)Create a label and capture its ID.
label.set_text(id, text)Replace the label’s text with the supplied string.
label.set_x / set_yMove the label as new bars print.
str.tostring(value, format)Convert numeric values to strings (with price formatting).
label.get_text(id)Retrieve the current text when you need to append or inspect it.
  1. Create and store the label ID
    Use var so the label persists between bars.

    var label signalLabel = label.new(bar_index, high, "")
  2. Convert numbers to strings
    Labels expect text. Wrap numbers in str.tostring() or str.format() before feeding them to label.set_text.

    summary = "RSI: " + str.tostring(ta.rsi(close, 14), "#.##")
  3. Update the label when needed
    Call label.set_text when a signal changes, or once per bar if you want a live ticker.

    if signalTriggered
    label.set_text(signalLabel, summary)
//@version=5
indicator("Last signal tracker", overlay=true, max_labels_count=100)
length = input.int(14, "RSI length")
overbought = input.int(70, "Overbought level")
oversold = input.int(30, "Oversold level")
rsiValue = ta.rsi(close, length)
longSignal = ta.crossunder(rsiValue, oversold)
shortSignal = ta.crossover(rsiValue, overbought)
var label longLabel = na
var label shortLabel = na
if longSignal
longLabel := na(longLabel) ? label.new(bar_index, low, "") : longLabel
label.set_x(longLabel, bar_index)
label.set_y(longLabel, low)
label.set_text(longLabel, "BUY\nRSI " + str.tostring(rsiValue, "#.##"))
label.set_style(longLabel, label.style_label_up)
if shortSignal
shortLabel := na(shortLabel) ? label.new(bar_index, high, "") : shortLabel
label.set_x(shortLabel, bar_index)
label.set_y(shortLabel, high)
label.set_text(shortLabel, "SELL\nRSI " + str.tostring(rsiValue, "#.##"))
label.set_style(shortLabel, label.style_label_down)
plot(rsiValue, "RSI", color=color.new(color.blue, 0))
hline(overbought, "Overbought", color=color.new(color.red, 60))
hline(oversold, "Oversold", color=color.new(color.green, 60))
Why this works.
  • Labels are created once and updated in place, preventing clutter.
  • Each signal writes the latest RSI reading directly onto the chart.
  • `var` storage lets the script remember label IDs between bars for seamless updates.
  • Always convert numbers to strings before passing them to label.set_text, otherwise Pine throws a compilation error.
  • Limit the number of live labels—max_labels_count prevents runtime errors if you go over the default limit.
  • Combine label.get_text() with label.set_text() if you want to append to existing text instead of replacing it entirely.
  • For frequently changing data (price tickers), update labels only on barstate.islast to keep historical bars clean.

Ensure you reuse the same label ID. Creating a new label each bar and setting its text will leave stale labels behind.

Pass an empty string ("") to label.set_text or delete the label with label.delete(id) when it’s no longer needed.

Yes—build the string with str.format() or conditional logic (trend > 0 ? "Up" : "Down") before calling label.set_text.

  • label.set_text rewrites the caption of an existing label—perfect for live indicators and signal dashboards.
  • Store label IDs in persistent (var) variables and reuse them across bars.
  • Convert numeric values to strings with str.tostring or str.format before updating text.
  • Update labels only when something meaningful changes to avoid unnecessary redraws.

Adapted from tradingcode.net, optimised for Algo Trade Analytics users.

We begin with the indicator() function. That configures the script. With title we name the script.

Next the ta.mfi() function calculates the Money Flow Index (MFI). Its data is the high, low, and close average (hlc3) and a length of 14 bars.

Then the plot() function shows the MFI on the chart. We don’t set the plot type. So Pine Script make a regular line plot by default. This line shows in teal (color.teal).

After that the hline() function makes two horizontal plots. These show the MFI overbought and oversold levels. We place those at 80 and 20.

Next we make two persistent variables with the var keyword:

These mfiBuyLabel and mfiSellLabel label variables will later hold the label identifiers. The reason to make them var variables is so they repeat their value on each bar (unless we update the variable to a different value).

Based on how we use these variables later, their previous bar value (mfiBuyLabel[1] and mfiSellLabel[1]) returns the identifier of the previous buy and sell label, respectively.

And the reason we declare these variables before the if statements that use them, is so that Pine Script can properly store the variable’s value on each bar.

Then we make the first Money Flow Index-based label:

This if statement lets the ta.crossover() function check if the MFI (mfiValue) crossed above 80. When it did, code first makes a new label with the label.new() function.

That label shows at the current bar’s Money Flow Index value (bar_index, mfiValue). Because earlier the indicator() function didn’t overlay the script, this label appears in a chart panel below the chart’s instrument.

The label’s colour is #FDBCB4, the hexadecimal colour value for melon red. With the text argument the label’s text becomes ‘Sell’.

That message should only show with the most recent label, and not with the previous ones. So the label.set_text() function removes the text from the last label. We give the function two arguments. The first, mfiSellLabel[1], returns the identifier of the previous sell label.

This works because a var variable repeats its last value on each bar (unless we update the variable to a different value). And so the previous value of mfiSellLabel returns the identifier of when we made the last sell label.

The other label.set_text() argument is an empty string (""). This removes the text from that previous label.

Since we remove the previous label’s text each time we make a new label, all previous labels are without the ‘Sell’ text message.

Then we look for the Money Flow Index buy signal:

This if statement has the ta.crossunder() function see if the MFI crossed below 20. The script does two things when it did.

First the label.new() function makes a new label. This label shows at the current bar’s MFI (bar_index, mfiValue). Its style points up (label.style_label_up). The label colour is the hexadecimal colour for tea green (#D0F0C0). ‘Buy’ is the label’s text.

Since the previous label shouldn’t keep its text, we call label.set_text(). We get the identifier of that last label with mfiBuyLabel[1]. With an empty string ("") the function removes that label’s text. This way only the last buy signal label shows the text ‘Buy’.

The chart shows ‘Buy’ and ‘Sell’ texts for the two most recent Money Flow Index cross signals. The earlier signals that happened before the last two don’t have text, and instead show as empty labels:

label.set_text(id, text)
// Create a label three bars to the right. It appears in black & // white and points to the left. myLabel = label.new(x=bar_index + 3, y=close, color=color.black, textcolor=color.white, style=label.style_label_left, size=size.large)
// Update the label's text to include the current close price label.set_text(id=myLabel, text="Last price: " + str.tostring(close))
//@version=5 indicator(title="Quick label.set_text() example", overlay=true) // On the chart's last bar, make a label and set its text if barstate.islast // Create a label three bars to the right. It appears in black & // white and points to the left. myLabel = label.new(x=bar_index + 3, y=close, color=color.black, textcolor=color.white, style=label.style_label_left, size=size.large) // Update the label's text to include the current close price label.set_text(id=myLabel, text="Last price: " + str.tostring(close))
// Update the label's text to include the current close price label.set_text(myLabel, "Last price: " + str.tostring(close)) // ^ ^ without optional 'id=' and 'text='
// Create persistent label variables (needed to access past labels) var label mfiBuyLabel = na var label mfiSellLabel = na
// When the MFI crosses above 80, make a sell label if ta.crossover(mfiValue, 80) mfiSellLabel := label.new(bar_index, mfiValue, color=#FDBCB4, text="Sell") // Remove text of the previous sell signal label.set_text(mfiSellLabel[1], "")
// Create a buy label when the MFI moves below 20 if ta.crossunder(mfiValue, 20) mfiBuyLabel := label.new(bar_index, mfiValue, style=label.style_label_up, color=#D0F0C0, text="Buy") // Remove text of the previous buy signal label.set_text(mfiBuyLabel[1], "")
  • id defines the identifier of the label whose text we want to modify.Thanks to this identifier the function knows which label to access. Without an identifier, Pine Script doesn’t understand which label we want to change.The label.new() function returns this identifier when we make the label.When this argument is (accidentally) the na value, the function can’t identify the label. It won’t change the text of a label then. But at least the function doesn’t error with na.

  • Thanks to this identifier the function knows which label to access. Without an identifier, Pine Script doesn’t understand which label we want to change.

  • The label.new() function returns this identifier when we make the label.

  • When this argument is (accidentally) the na value, the function can’t identify the label. It won’t change the text of a label then. But at least the function doesn’t error with na.

  • text is a string (piece of text) with the label’s new text.The maximum label text length is 4,096 characters. With a longer string, Pine Script triggers the ‘string is too long’ error.If this argument is the na value or an empty string (""), then the function removes the label existing text. That is, it empties the label’s text content.

  • The maximum label text length is 4,096 characters. With a longer string, Pine Script triggers the ‘string is too long’ error.

  • If this argument is the na value or an empty string (""), then the function removes the label existing text. That is, it empties the label’s text content.

  • Thanks to this identifier the function knows which label to access. Without an identifier, Pine Script doesn’t understand which label we want to change.

  • The label.new() function returns this identifier when we make the label.

  • When this argument is (accidentally) the na value, the function can’t identify the label. It won’t change the text of a label then. But at least the function doesn’t error with na.

  • The maximum label text length is 4,096 characters. With a longer string, Pine Script triggers the ‘string is too long’ error.

  • If this argument is the na value or an empty string (""), then the function removes the label existing text. That is, it empties the label’s text content.

  • When the label doesn’t have text, this function gives the label text to show.

  • When the label has text, the function can change that text to something else.

  • And the function can remove the label’s entire text.

  • Pine Script labels don’t automatically wrap their text when the lines are long. We do that ourselves when we strategically place the newline character (\n) in the text. Wherever that character appears, Pine Script adds a new line (that is, the equivalent of pressing the Enter key).

  • The maximum length for the label’s text is 4,096 characters. While Pine Script sometimes allows a longer string, it’s unknown if those exceptions remain and in which situations they apply. It’s therefore best to keep the string length below 4 thousand characters. If the string is too long, Pine Script generates the ‘string is too long’ error message (and we cannot use the script).

  • We cannot control a label’s font. This includes the font family, font size, and font style (bold or italic, for instance). These style decisions are made by TradingView. What we can do is change the label size with the label.set_size() function. When the label becomes bigger or smaller, the text’s font size grows or shrinks with it.

  • The label.set_text() function sets the text content of a specified label.

  • The function needs two things. First a label identifier that tells which label to modify. We get this identifier from the label.new() function when we make the label.

  • The other argument is a piece of text (string) with the label’s new content.

  • A label text’s maximum length is 4,096 characters. With the \n escape character we include newlines in this string.

  • To remove a label’s text, label.set_text() sets the text to an empty string ("").

  1. TradingView (n.d.). Pine Script Language Reference Manual. Retrieved on August 3, 2022, from https://www.tradingview.com/pine-script-reference/v5/
  2. TradingView Docs (n.d.). Text and shapes. Retrieved on August 3, 2022, from https://www.tradingview.com/pine-script-docs/en/v5/concepts/Text_and_shapes.html

Ready to implement this in your own strategies?

This tutorial is based on content from TradingCode.net, adapted for Algo Trade Analytics users.

This tutorial is based on content from tradingcode.net, adapted for Algo Trade Analytics users.

//@version=5 indicator(title="Change label's text") // Calculate and plot the Money Flow Index mfiValue = ta.mfi(hlc3, 14) plot(mfiValue, color=color.teal, title="Money Flow Index") hline(80, title="Overbought") hline(20, title="Oversold") // Create persistent label variables (needed to access past labels) var label mfiBuyLabel = na var label mfiSellLabel = na // When the MFI crosses above 80, make a sell label if ta.crossover(mfiValue, 80) mfiSellLabel := label.new(bar_index, mfiValue, color=#FDBCB4, text="Sell") // Remove text of the previous sell signal label.set_text(mfiSellLabel[1], "") // Create a buy label when the MFI moves below 20 if ta.crossunder(mfiValue, 20) mfiBuyLabel := label.new(bar_index, mfiValue, style=label.style_label_up, color=#D0F0C0, text="Buy") // Remove text of the previous buy signal label.set_text(mfiBuyLabel[1], "")

Adapted from tradingcode.net, optimised for Algo Trade Analytics users.