Drawings
Starting with Pine v4, indicators and strategies can create drawing objects on the chart. Three types of drawings are currently supported: label, line, and boxes. You will find one instance of each on the following chart:
The line, label, and box drawings in Pine v4 allow you to create indicators with more sophisticated visual components, e.g., pivot points, support/resistance levels, zig zag lines, labels containing dynamic text, etc.
In contrast to indicator plots (plots are created with functions plot
,
plotshape
, plotchar
), drawing objects can be created on historical
bars as well as in the future, where no bars exist yet.
Creating drawings
Pine drawing objects are created with the label.new , line.new and box.new functions. While each function has many parameters, only the coordinates are mandatory. This is an example of code used to create a label on every bar:
The label is created with the parameters x=bar_index
(the index of the
current bar,
bar_index)
and y=high
(high price of the current bar). When a new bar opens, a
new label is created on it. Label objects created on previous bars stay
on the chart until the indicator deletes them with an explicit call of
the
label.delete
function, or until the automatic garbage collection process removes
them.
Here is a modified version of the same script that shows the values of
the x
and y
coordinates used to create the labels:
In this example labels are shown without background coloring (because of
parameter style=label.style_none
) but with dynamically created text
(text="x=" + tostring(bar_index) + "\ny=" + tostring(high)
) that
prints label coordinates.
This is an example of code that creates line objects on a chart:
This is an example of code that creates box objects on a chart:
Calculation of drawings on bar updates
Drawing objects are subject to both commit and rollback actions, which affect the behavior of a script when it executes in the realtime bar, Execution model.
This script demonstrates the effect of rollback when running in the realtime bar:
While label.new
creates a new label on every iteration of the script
when price changes in the realtime bar, the most recent label created in
the script’s previous iteration is also automatically deleted because
of rollback before the next iteration. Only the last label created
before the realtime bar’s close will be committed, and will thus
persist.
Coordinates
Drawing objects are positioned on the chart according to x and y
coordinates using a combination of 4 parameters: x
, y
, xloc
and
yloc
. The value of xloc
determines whether x
will hold a bar index
or time value. When yloc=yloc.price
, y
holds a price. y
is ignored
when yloc
is set to
yloc.abovebar
or
yloc.belowbar.
If a drawing object uses
xloc.bar_index,
then the x-coordinate is treated as an absolute bar index. The bar index
of the current bar can be obtained from the built-in variable
bar_index
. The bar index of previous bars is bar_index[1]
,
bar_index[2]
and so on. xloc.bar_index
is the default value for
x-location parameters of both label and line drawings.
If a drawing object uses
xloc.bar_time,
then the x-coordinate is treated as a UNIX time in milliseconds. The
start time of the current bar can be obtained from the built-in variable
time
. The bar time of previous bars is time[1]
, time[2]
and so on.
Time can also be set to an absolute time point with the
timestamp
function.
The xloc.bar_time
and xloc.bar_index
modes makes it possible to
place a drawing object in the future, to the right of the current bar.
For example:
This code places a label object in the future. X-location logic works identically for label, line, and box drawings.
Example for xloc.bar_index
:
In contrast, y-location logic is different for label and line or box drawings. Pine’s line and box drawings always use yloc.price, so their y-coordinate is always treated as an absolute price value.
Label drawings have additional y-location values:
yloc.abovebar
and
yloc.belowbar.
When they are used, the value of the y
parameter is ignored and the
drawing object is placed above or below the bar.
Modifying drawings
A drawing object can be modified after its creation. The label.new
,
line.new
, and box.new
functions return a reference to the created
drawing object (of type series label, series line and series box
respectively). This reference can then be used as the first argument to
the label.set_*
, line.set_*
, or box.set_*
functions used to modify
drawings. For example:
This simple script first creates a label on the current bar and then it
writes a reference to it in a variable l
. Then, depending on whether
the current bar is rising or falling (condition close >= open
), a
number of label drawing properties are modified: text, color, y
coordinate location (yloc
) and label style.
One may notice that na
is passed as the y
argument to the
label.new
function call. The reason for this is that the example’s
label uses either yloc.belowbar
or yloc.abovebar
y-locations, which
don’t require a y value. A finite value for y
is needed only if a
label uses yloc.price
.
The available setter functions for label drawings are:
- label.set_color — changes color of label
- label.set_size — changes size of label
- label.set_style — changes style of label
- label.set_text — changes text of label
- label.set_textcolor — changes color of text
- label.set_x — changes x-coordinate of label
- label.set_y — changes y-coordinate of label
- label.set_xy — changes both x and y coordinates of label
- label.set_xloc — changes x-location of label
- label.set_yloc — changes y-location of label
- label.set_tooltip — changes tooltip of label
The available setter functions for line drawings are:
- line.set_color — changes color of line
- line.set_extend
— changes attribute that makes:
extend.none
- a line segmentextend.left
/extend.right
- a rayextend.both
- an endless line
- line.set_style — changes [style of line](drawings_label_styles.interpreted-text role”ref”)
- line.set_width — changes width of line
- line.set_xloc — changes x-location of line (both x1 and x2)
- line.set_x1 — changes x1-coordinate of line
- line.set_y1 — changes y1-coordinate of line
- line.set_xy1 — changes both x1 and y1 coordinates of line
- line.set_x2 — changes x2-coordinate of line
- line.set_y2 — changes y2-coordinate of line
- line.set_xy2 — changes both x2 and y2 coordinates of line at once
The available setter functions for box drawings are:
- box.set_border_color — changes border color of the box
- box.set_bgcolor — changes background color of the box
- box.set_extend
— changes attribute that makes:
extend.none
- the horizontal borders start at the left border and end at the right borderextend.left
/extend.right
- the horizontal borders are extended indefinitely to the left/right of the boxextend.both
- the horizontal borders are extended on both sides
- box.set_border_style — changes border style of the box
- box.set_border_width — changes border width of the box
- box.set_bottom — changes bottom coordinate of the box
- box.set_right — changes right coordinate of the box
- box.set_rightbottom — changes both right and bottom coordinates of the box at once
- box.set_top — changes top coordinate of the box
- box.set_left — changes left coordinate of the box
- box.set_lefttop — changes both left and top coordinates of the box at once
Label styles
Various styles can be applied to labels with either the label.new or label.set_style function:
Label style name | Label | Label with text |
---|---|---|
label.style_none | ||
label.style_xcross | ||
label.style_cross | ||
label.style_triangleup | ||
label.style_triangledown | ||
label.style_flag | ||
label.style_circle | ||
label.style_arrowup | ||
label.style_arrowdown | ||
label.style_label_up | ||
label.style_label_down | ||
label.style_square | ||
label.style_diamond |
Line and box styles
Various styles can be applied to lines with either the line.new, box.new, line.set_style or box.set_border_style function:
Line style name | Line | Box |
---|---|---|
line.style_solid | ||
line.style_dotted | ||
line.style_dashed | ||
line.style_arrow_left | Not supported | |
line.style_arrow_right | Not supported | |
line.style_arrow_both | Not supported |
Deleting drawings
The label.delete, line.delete and box.delete functions delete label, line, or box drawing objects from the chart.
Here is Pine code that keeps just one label drawing object on the current bar, deleting the old ones:
On every new bar update of the “Last Bar Close 1” study, a new label
object is created and written to variable l
. Variable l
is of type
series label, so the []
operator is used to get the previous bar’s
label object. That previous label is then passed to the label.delete
function to delete it.
Functions label.delete
and line.delete
do nothing if the na
value
is used as an id, which makes code like the following unnecessary:
The previous script’s behavior can be reproduced using another approach:
When the study “Last Bar Close 2” gets a new bar update, variable l
is still referencing the old label object created on the previous bar.
This label is deleted with the label.delete(l)
call. A new label is
then created and its id saved to l
. Using this approach there is no
need to use the []
operator.
Note the use of the new Pine v4
var keyword. It
creates variable l
and initializes it with the na
value only once.
label.delete(l)
would have no object to delete if it weren’t for the
fact that l
is initialized only once.
There is yet another way to achieve the same objective as in the two previous scripts, this time by modifying the label rather than deleting it:
Once again, the use of new
var keyword is
essential. It is what allows the label.new
call to be executed only
once, on the very first historical bar.
Examples of classic indicators
Pivot Points Standard
Pivot Points High/Low
Linear Regression
Zig Zag
Limits
Total number of drawings
Drawing objects consume server resources, which is why there is a limit to the total number of drawings per study or strategy. When too many drawings are created, old ones are automatically deleted by the Pine runtime, in a process referred to as garbage collection.
This code creates a drawing on every bar:
Scrolling the chart left, one will see there are no drawings after approximately 50 bars:
You can change the drawing limit to a value in range from 1 to 500 using the max_lines_count, max_labels_count, or max_boxes_count parameters for the study and strategy functions:
Bars count in future with xloc.bar_index
Objects positioned using xloc.bar_index cannot be drawn further than 500 bars into the future.
Additional securities
Pine code sometimes uses additional symbols and/or timeframes with the security function. Drawing functions can only be used in the main symbol’s context.
max_bars_back of time
Use of barstate.isrealtime
in combination with drawings may sometimes
produce unexpected results. This code’s intention, for example, is to
ignore all historical bars and create a label drawing on the realtime
bar:
It will, however, fail at runtime. The reason for the error is that Pine
cannot determine the buffer size for historical values of the time
plot, even though the time
built-in variable isn’t mentioned in the
code. This is due to the fact that the built-in variable bar_index
uses the time
series in its inner workings. Accessing the value of the
bar index 10 bars back requires that the history buffer size of the
time
series be of size 10 or more.
In Pine, there is a mechanism that automaticaly detects the required
historical buffer size for most cases. Autodetection works by letting
Pine code access historical values any number of bars back for a limited
duration. In this script’s case, the if barstate.isrealtime
condition
prevents any such accesses to occur, so the required historical buffer
size cannot be inferred and the code fails.
The solution to this conundrum is to use the
max_bars_back
function to explicitly set the historical buffer size for the time
series:
Such occurrences are confusing, but rare. In time, the Pine team hopes to eliminate them.