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 withlabel.new(), keep its ID, and calllabel.set_text(id, string)whenever you need to refresh what it says.
At a Glance
Section titled “At a Glance”| Difficulty | Beginner |
| Time to implement | 10-15 min |
| Category | Visual Effects |
Quick Actions
Section titled “Quick Actions”Quick Start
Section titled “Quick Start”//@version=5indicator("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))Why It Matters
Section titled “Why It Matters”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.
What You’ll Learn
Section titled “What You’ll Learn”- 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.
Quick Reference
Section titled “Quick Reference”| Helper | Purpose |
|---|---|
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_y | Move 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. |
Implementation Blueprint
Section titled “Implementation Blueprint”-
Create and store the label ID
Usevarso the label persists between bars.var label signalLabel = label.new(bar_index, high, "") -
Convert numbers to strings
Labels expect text. Wrap numbers instr.tostring()orstr.format()before feeding them tolabel.set_text.summary = "RSI: " + str.tostring(ta.rsi(close, 14), "#.##") -
Update the label when needed
Calllabel.set_textwhen a signal changes, or once per bar if you want a live ticker.if signalTriggeredlabel.set_text(signalLabel, summary)
Example Playbook
Section titled “Example Playbook”//@version=5indicator("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 = navar 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))- 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.
Pro Tips & Pitfalls
Section titled “Pro Tips & Pitfalls”- 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_countprevents runtime errors if you go over the default limit. - Combine
label.get_text()withlabel.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.islastto keep historical bars clean.
Troubleshooting & FAQ
Section titled “Troubleshooting & FAQ”Label text never updates
Section titled “Label text never updates”Ensure you reuse the same label ID. Creating a new label each bar and setting its text will leave stale labels behind.
How do I clear label text?
Section titled “How do I clear label text?”Pass an empty string ("") to label.set_text or delete the label with label.delete(id) when it’s no longer needed.
Can I change formatting on the fly?
Section titled “Can I change formatting on the fly?”Yes—build the string with str.format() or conditional logic (trend > 0 ? "Up" : "Down") before calling label.set_text.
Key Takeaways
Section titled “Key Takeaways”label.set_textrewrites 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.tostringorstr.formatbefore updating text. - Update labels only when something meaningful changes to avoid unnecessary redraws.
Keep Going
Section titled “Keep Going”- Open AI Editor to apply the pattern with guided assistance
- Browse PineScript Examples for ready-to-run templates
- Connect to Live Trading when you are ready to automate
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 ("").
- TradingView (n.d.). Pine Script Language Reference Manual. Retrieved on August 3, 2022, from https://www.tradingview.com/pine-script-reference/v5/
- 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?
- Open AI Editor: Get AI assistance while coding
- See More Examples: Browse complete strategy examples
- Connect to Trading: Turn your PineScript into live trades via Alpaca
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.
Example Playbook
Section titled “Example Playbook”//@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], "")Keep Going
Section titled “Keep Going”- Open AI Editor to apply the pattern with guided assistance
- Browse Strategy Examples for ready-to-run templates
- Connect to Live Trading when you are ready to automate
Adapted from tradingcode.net, optimised for Algo Trade Analytics users.