Guide

Pine Script Drawing Objects: Lines, Boxes, and Labels That Do Not Hit the Limit

Your indicator draws beautifully for the first 200 bars, then everything disappears. Understanding the drawing limits and the patterns that stay within them is essential for any visual indicator.

•11 min read

Pine Script has three drawing object types that let you paint directly on the chart: lines, boxes, and labels. These are what make indicators like order blocks, supply and demand zones, support and resistance lines, and pivot level markers possible. They transform a chart from a sea of overlapping plots into a readable visual analysis. But they come with strict limits, and exceeding those limits causes objects to silently disappear, which is one of the most confusing failures in Pine Script.

Understanding what each object type does, how to manage the limits, and which patterns work within those constraints is the difference between an indicator that renders reliably and one that looks broken after a few hundred bars. This guide covers the drawing system from the ground up, with the patterns that actually work in production.

The three object types

Lines draw a segment between two points, optionally extending infinitely in one or both directions. They are used for trendlines, horizontal support and resistance levels, and ray lines that project into the future. The syntax is straightforward: you define a line with a starting point and an ending point, then use line.set_* functions to modify properties like color, style, and width.

Boxes draw a rectangular region between two price points across a range of bars. They are the natural choice for order blocks, supply and demand zones, and any indicator that needs to highlight a price range over time. A box is defined by its top, bottom, left, and right boundaries, and it can be filled with a color or left empty with only a border. The order block indicator in the order blocks guide uses boxes as its primary visualization.

Labels place text at a specific bar and price. They are used for showing signal markers, price annotations, ratio displays, and any indicator that needs to annotate the chart with information. Labels can be positioned above, below, or on the bar, and they support a variety of text alignment and styling options. The key advantage of labels is that they can display dynamic text, which makes them useful for showing values like RSI readings or signal strength directly on the chart.

The limits that trip everyone up

TradingView imposes hard limits on how many drawing objects a script can display simultaneously. The defaults are 500 labels, 500 lines, and 500 boxes per script. These limits are adjustable in the script settings, but increasing them trades memory for performance, and very high values can cause the chart to lag.

The silent failure mode is what makes these limits dangerous. When your code attempts to draw the 501st label and the limit is set to 500, the new label is simply not drawn. No error is thrown. The chart continues rendering, but your indicator appears to stop working after a certain number of signals. This is not a bug in your logic. It is a resource limit that your code needs to manage explicitly.

Managing the limits requires a cleanup strategy. The most common approach is to delete the oldest objects when the count approaches the limit. Pine Script provides line.delete(), box.delete(), and label.delete() for this purpose. A typical pattern checks the number of existing objects and removes the oldest one before adding a new one, maintaining a rolling window of visible objects.

The strategy declaration accepts max_labels_count, max_lines_count, and max_boxes_count parameters that set these limits programmatically. Setting them explicitly in your code makes the behavior consistent regardless of user settings. The drawing limits guide covers the exact mechanics and the common mistakes that cause objects to disappear.

Drawing order blocks correctly

An order block is a contiguous range of bars where institutional buying or selling created a significant move away. Visually, it is a box that spans the price range of those bars, placed at the location where the move began. The challenge is that as new bars form, older order blocks may become irrelevant or may need to be removed when they are invalidated by price breaking through them.

The implementation pattern uses an array to store the box objects. When a new order block is detected, you create a box and push it to the array. Before adding a new box, you check the array length. If it exceeds your limit, you delete the oldest box and remove it from the array. This rolling window approach keeps the indicator performing well while showing the most recent order blocks.

Invalidation is a separate concern. An order block is invalidated when price closes beyond its boundary in the opposite direction of the original move. Checking this on every bar requires iterating through the array of boxes and removing any that are no longer valid. The full implementation involves pivot detection to find the order block formation bars, box creation with the correct price boundaries, and continuous invalidation checking. The order block build guide walks through this step by step.

Horizontal levels with lines

Horizontal support and resistance levels are among the simplest drawing implementations, but they have their own nuance. The most common mistake is creating a new line object on every bar, which hits the limit within minutes. The correct approach creates a line once and updates its price level as needed, rather than deleting and recreating it.

For dynamic levels that adjust based on indicator values, use a single line object and update its y1 and y2 coordinates on each bar. This keeps the object count at one regardless of how the level moves. If you need multiple levels, create them once during initialization and update them individually rather than creating new objects each time.

Extended lines that project into the future use the line.new function with the x2 parameter set to bar_index + N where N is the number of bars to project. This creates the ray effect that extends horizontally from a point. The same limit management applies: track how many extended lines you have and remove old ones before adding new ones.

Signal markers with labels

Labels are ideal for marking buy and sell signals on the chart. A common pattern places an arrow or letter at the bar where a signal fires. The label is created with label.new() and can include text like BUY, SELL, or a custom message. The positioning parameters control whether the label appears above or below the bar.

The limit challenge for labels is the same as lines and boxes. If your strategy generates 10 signals per day, you will hit the 500-label limit in about 50 trading days. The fix is the same: maintain a rolling window by deleting the oldest label when you add a new one, or by checking the total count before creating a new label and removing the oldest if necessary.

One useful feature of labels is that they can display dynamic text, including values calculated by your indicator. A label can show the current RSI value, the signal strength, or any other computed number. This makes labels more informative than simple plot markers, but it also means the label content changes on every bar, which requires updating rather than creating new labels.

Building complex drawing indicators with AI

Drawing-based indicators are among the most complex Pine Script builds. They require array management, limit handling, invalidation logic, and coordinate calculations that are easy to get wrong. The complexity is exactly why they are a strong use case for AI-assisted development. A general-purpose AI may generate code that works for the first hundred bars and then silently fails when the limits are hit. PineScripter understands the limit constraints and generates code that manages the object lifecycle correctly from the start.

The conversion moment for drawing objects is direct. If you want an indicator that shows order blocks, supply and demand zones, pivot levels, or any visual annotation on your chart, the complexity of managing the drawing limits is what makes this a problem worth solving with dedicated tooling rather than from scratch. Generating the correct array management and cleanup logic in one pass, rather than discovering the limits through trial and error, is exactly where the compile-aware workflow adds value.


Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.