Polyline PlusThis library introduces the `PolylinePlus` type, which is an enhanced version of the built-in PineScript `polyline`. It enables two features that are absent from the built-in type:
1. Developers can now efficiently add or remove points from the polyline. In contrast, the built-in `polyline` type is immutable, requiring developers to create a new instance of the polyline to make changes, which is cumbersome and incurs a significant performance penalty.
2. Each `PolylinePlus` instance can theoretically hold up to ~1M points, surpassing the built-in `polyline` type's limit of 10K points, as long as it does not exceed the memory limit of the PineScript runtime.
Internally, each `PolylinePlus` instance utilizes an array of `line`s and an array of `polyline`s. The `line`s array serves as a buffer to store lines formed by recently added points. When the buffer reaches its capacity, it flushes the contents and converts the lines into polylines. These polylines are expected to undergo fewer updates. This approach is similiar to the concept of "Buffered I/O" in file and network systems. By connecting the underlying lines and polylines, this library achieves an enhanced polyline that is dynamic, efficient, and capable of surpassing the maximum number of points imposed by the built-in polyline.
🔵 API
Step 1: Import this library
import algotraderdev/polylineplus/1 as pp
// remember to check the latest version of this library and replace the 1 above.
Step 2: Initialize the `PolylinePlus` type.
var p = pp.PolylinePlus.new()
There are a few optional params that developers can specify in the constructor to modify the behavior and appearance of the polyline instance.
var p = pp.PolylinePlus.new(
// If true, the drawing will also connect the first point to the last point, resulting in a closed polyline.
closed = false,
// Determines the field of the chart.point objects that the polyline will use for its x coordinates. Either xloc.bar_index (default), or xloc.bar_time.
xloc = xloc.bar_index,
// Color of the polyline. Default is blue.
line_color = color.blue,
// Style of the polyline. Default is line.style_solid.
line_style = line.style_solid,
// Width of the polyline. Default is 1.
line_width = 1,
// The maximum number of points that each built-in `polyline` instance can contain.
// NOTE: this is not to be confused with the maximum of points that each `PolylinePlus` instance can contain.
max_points_per_builtin_polyline = 10000,
// The number of lines to keep in the buffer. If more points are to be added while the buffer is full, then all the lines in the buffer will be flushed into the poylines.
// The higher the number, the less frequent we'll need to // flush the buffer, and thus lead to better performance.
// NOTE: the maximum total number of lines per chart allowed by PineScript is 500. But given there might be other places where the indicator or strategy are drawing lines outside this polyline context, the default value is 50 to be safe.
lines_bffer_size = 50)
Step 3: Push / Pop Points
// Push a single point
p.push_point(chart.point.now())
// Push multiple points
chart.point points = array.from(p1, p2, p3) // Where p1, p2, p3 are all chart.point type.
p.push_points(points)
// Pop point
p.pop_point()
// Resets all the points in the polyline.
p.set_points(points)
// Deletes the polyline.
p.delete()
🔵 Benchmark
Below is a simple benchmark comparing the performance between `PolylinePlus` and the native `polyline` type for incrementally adding 10K points to a polyline.
import algotraderdev/polylineplus/2 as pp
var t1 = 0
var t2 = 0
if bar_index < 10000
int start = timenow
var p = pp.PolylinePlus.new(xloc = xloc.bar_time, closed = true)
p.push_point(chart.point.now())
t1 += timenow - start
start := timenow
var polyline pl = na
var points = array.new()
points.push(chart.point.now())
if not na(pl)
pl.delete()
pl := polyline.new(points)
t2 += timenow - start
if barstate.islast
log.info('{0} {1}', t1, t2)
For this benchmark, `PolylinePlus` took ~300ms, whereas the native `polyline` type took ~6000ms.
We can also fine-tune the parameters for `PolylinePlus` to have a larger buffer size for `line`s and a smaller buffer for `polyline`s.
var p = pp.PolylinePlus.new(xloc = xloc.bar_time, closed = true, lines_buffer_size = 500, max_points_per_builtin_polyline = 1000)
With the above optimization, it only took `PolylinePlus` ~80ms to process the same 10K points, which is ~75x the performance compared to the native `polyline`.
Lines
Drawings_publicLibrary "Drawings_public"
: Functions to manage drawings on the chart
extend_line(lineId, labelId)
: Extend specific line with its label
Parameters:
lineId
labelId
update_line_coordinates(lineId, labelId, x1, y1, x2, y2)
: Update specific line coordinates with its label
Parameters:
lineId
labelId
x1
y1
x2
y2
update_label_coordinates(labelId, value)
: Update coordinates of a label
Parameters:
labelId
value
delete_line(lineId, labelId)
: Delete specific line with its label
Parameters:
lineId
labelId
update_box_coordinates(boxId, labelId, left, top, right, bottom)
: Update specific box coordinates with its label
Parameters:
boxId
labelId
left
top
right
bottom
delete_box(boxId, labelId)
: Delete specific box with its label
Parameters:
boxId
labelId
AlgebraLibrary "Algebra"
Algebra functions.
line_fromXy(x1, y1, x2, y2)
Get line slope and y-intercept from coordinates
Parameters:
x1 : x coordinate 1 (int - bar index)
y1 : y coordinate 1 (float - price/value)
x2 : x coordinate 2 (int - bar index)
y2 : y coordinate 2 (float - price/value)
Returns: of line
line_getPrice(x, slope, yInt)
Get line slope and y-intercept from coordinates
Parameters:
x : x coordinate to solve for y (int - bar index)
slope : slope of line (float)
yInt : y-intercept of line (float)
Returns: y (price/value)
ObjectStackLibrary "ObjectStack"
init()
push()
push()
push()
push()
push()
nextIndex()
nextIndex()
nextIndex()
nextIndex()
nextIndex()
delete()
delete()
delete()
delete()
delete()
cleanOldest()
cleanOldest()
cleanOldest()
cleanOldest()
cleanOldest()
LineGetPriceOnLogScaleLibrary "LineGetPriceOnLogScale"
This library provides a way to calculate the y-coordinate of a line on a specified bar when the chart scale is Log.
The built-in `line.get_price()` function only works with linear scale and gives incorrect results when the chart is in Log scale.
The library only works with `bar_index` values and `xloc.bar_index`-based lines, `time`-based lines will cause errors to appear.
coordGetPriceLog(x1, y1, x2, y2, xi) Calculates the y-coordinate on the specified bar on the logarithmic scale.
Only coordinates based on bar index are applicable, bar time will throw an error.
Parameters:
x1 : First X coordinate of a line, index of the bar where the line starts.
y1 : First Y coordinate of a line, price on the price scale.
x2 : Second X coordinate of a line, index of the bar where the line ends.
y2 : Second Y coordinate of a line, price on the price scale.
xi : Index of the bar for which the price should be calculated.
Returns: Price of the line on the bar specified in `xi`, on the logarithmic scale.
lineGetPriceLog(_line, xi) Calculates the y-coordinate on the specified bar for the logarithmic scale. Takes a line.
Only lines drawn based on `xloc.bar_index` are applicable, `xloc.bar_time` will throw and error.
Parameters:
_line : The line for which the price is calculated.
xi : Index of the bar for which the bar should calculate the price.
Returns: Price of the line on the bar specified in `xi`, on the logarithmic scale.