Limitations

Introduction

As mentioned on our Welcome page:

Because each script uses computational resources in the cloud, we must impose limits to share these resources fairly among our users. We strive to set as few limits as possible, but we will, of course, need to implement as many as necessary for the platform to run smoothly. Limitations apply to the amount of data requested from additional symbols, execution time, memory usage, and script size.

If you develop complex scripts using Lipi Script, sooner or later, you will encounter some of the limitations we impose. This section provides an overview of the limitations you may face. Currently, there are no means for Lipi Script programmers to get data on the resources consumed by their scripts. We hope this will change in the future.

In the meantime, when considering large projects, it is safest to create a proof of concept to assess the likelihood of your script running into limitations later in your project.

Below, we describe the limits imposed in the Lipi Script environment.

Time

Script Compilation

Scripts must compile before they are executed on charts. Compilation occurs when you save a script from the Lipi Editor or when you add a script to the chart. A two-minute limit is imposed on compilation time, which will depend on the size and complexity of your script and whether or not a cached version of a previous compilation is available. If a compile exceeds the two-minute limit, a warning is issued. Heed that warning by shortening your script because after three consecutive warnings, a one-hour ban on compilation attempts is enforced. The first step to consider when optimizing code is to avoid repetitions by using functions to encapsulate frequently used segments and call functions instead of repeating code.

Script Execution

Once a script is compiled, it can be executed. See the Events triggering the execution of a script for a list of the events that trigger the execution of a script. The time allotted for the script to execute on all bars of a dataset varies with account types. The limit is 20 seconds for basic accounts and 40 seconds for others.

Loop Execution

The execution time for any loop on a single bar is limited to 500 milliseconds. The outer loop of embedded loops counts as one loop, so it will time out first. Keep in mind that even if a loop executes within the 500 ms time limit on a given bar, the total time it takes to execute on all bars of the dataset may still cause your script to exceed the total execution time limit. For example, the limit on total execution time will make it impossible for your script to execute a 400 ms loop on each bar of a 20,000-bar dataset, as your script would then need 8000 seconds to execute.

Chart Visuals

Plot Limits

A maximum of 64 plot counts are allowed per script. The functions that generate plot counts are:

  • plot()
  • plotarrow()
  • plotbar()
  • plotcandle()
  • plotchar()
  • plotshape()
  • bgcolor()
  • fill(), but only if its color is of the series form.

One function call can generate up to seven plot counts, depending on the function and how it is called. When your script exceeds the maximum of 64 plot counts, a runtime error message will display the plot count generated by your script. Once you reach that point, you can determine how many plot counts a function call generates by commenting it out in a script. As long as your script still throws an error, you will be able to see how the actual plot count decreases after you have commented out a line.

The following example shows different function calls and the number of plot counts each one will generate:

indicator("Plot count example")
 
bool isUp = close > open
color isUpColor = isUp ? color.green : color.red
bool isDn = not isUp
color isDnColor = isDn ? color.red : color.green
 
// Uses one plot count each.
p1 = plot(close, color = color.white)
p2 = plot(open, color = na)
 
// Uses two plot counts for the `close` and `color` series.
plot(close, color = isUpColor)
 
// Uses one plot count for the `close` series.
plotarrow(close, colorup = color.green, colordown = color.red)
 
// Uses two plot counts for the `close` and `colorup` series.
plotarrow(close, colorup = isUpColor)
 
// Uses three plot counts for the `close`, `colorup`, and the `colordown` series.
plotarrow(close - open, colorup = isUpColor, colordown = isDnColor)
 
// Uses four plot counts for the `open`, `high`, `low`, and `close` series.
plotbar(open, high, low, close, color = color.white)
 
// Uses five plot counts for the `open`, `high`, `low`, `close`, and `color` series.
plotbar(open, high, low, close, color = isUpColor)
 
// Uses four plot counts for the `open`, `high`, `low`, and `close` series.
plotcandle(open, high, low, close, color = color.white, wickcolor = color.white, bordercolor = color.purple)
 
// Uses five plot counts for the `open`, `high`, `low`, `close`, and `color` series.
plotcandle(open, high, low, close, color = isUpColor, wickcolor = color.white, bordercolor = color.purple)
 
// Uses six plot counts for the `open`, `high`, `low`, `close`, `color`, and `wickcolor` series.
plotcandle(open, high, low, close, color = isUpColor, wickcolor = isUpColor , bordercolor = color.purple)
 
// Uses seven plot counts for the `open`, `high`, `low`, `close`, `color`, `wickcolor`, and `bordercolor` series.
plotcandle(open, high, low, close, color = isUpColor, wickcolor = isUpColor , bordercolor = isUp ? color.lime : color.maroon)
 
// Uses one plot count for the `close` series.
plotchar(close, color = color.white, text = "|", textcolor = color.white)
 
// Uses two plot counts for the `close`` and `color` series.
plotchar(close, color = isUpColor, text = "—", textcolor = color.white)
 
// Uses three plot counts for the `close`, `color`, and `textcolor` series.
plotchar(close, color = isUpColor, text = "O", textcolor = isUp ? color.yellow : color.white)
 
// Uses one plot count for the `close` series.
plotshape(close, color = color.white, textcolor = color.white)
 
// Uses two plot counts for the `close` and `color` series.
plotshape(close, color = isUpColor, textcolor = color.white)
 
// Uses three plot counts for the `close`, `color`, and `textcolor` series.
plotshape(close, color = isUpColor, textcolor = isUp ? color.yellow : color.white)
 
// Uses one plot count.
bgcolor(isUp ? color.yellow : color.white)
 
// Uses one plot count for the `color` series.
fill(p1, p2, color = isUpColor)

This example generates a plot count of 56. If we were to add two more instances of the last call to plotcandle(), the script would throw an error stating that the script now uses 70 plot counts, as each additional call to plotcandle() generates seven plot counts, and (56 + (7 \times 2) = 70).

Script Size and Memory

Compiled Tokens

Before the execution of a script, the compiler translates it into a tokenized Intermediate Language (IL). Using an IL allows Lipi Script™ to accommodate larger scripts by applying various memory and performance optimizations. The compiler determines the size of a script based on the number of tokens in its IL form, not the number of characters or lines in the code viewable in the Lipi Editor.

The compiled form of each indicator is limited to 80,000 tokens. There is no way to inspect a script’s compiled form or its IL token count. As such, you will only know your script exceeds the size limit when the compiler reaches it.

In most cases, a script’s compiled size will likely not reach the limit. However, if a compiled script does reach the token limit, the most effective ways to decrease compiled tokens are to reduce repetitive code, encapsulate redundant calls within functions.

It’s important to note that the compilation process omits any unused variables, functions, types, etc., from the final IL form, where “unused” refers to anything that does not affect the script’s outputs. This optimization prevents superfluous elements in the code from contributing to the script’s IL token count.

Variables Per Scope

Scripts can contain up to 1,000 variables in each of its scopes. Lipi scripts always contain one global scope, represented by non-indented code, and they may contain zero or more local scopes. Local scopes are sections of indented code representing procedures executed within functions and methods, as well as if and while structures, which allow for one or more local blocks. Each local block counts as one local scope.

The branches of a conditional expression using the ?: ternary operator do not count as local blocks.

Scope Count

The total number of scopes in a script, including its global scope and each local scope from the user-defined functions, methods, and conditional structures it uses, cannot exceed 550.

For example, suppose we created a script with a global variable that depends on the local scopes of 300 if structures. The total scope count for this script is 301 (1 global scope + 300 local scopes):

indicator("Scopes demo")
 
var x = 0
 
if close > 0 {
    x += 0
}
if close > 1 {
    x += 1
}
// ... Repeat this `if close > n` pattern until `n = 299`.
if close > 299 {
    x += 299
}
plot(x)

Compilation Request Size

The size of the compilation request for a script cannot exceed 5MB. The compilation request is all of the information that is sent to the compiler. This information comprises the script itself and any libraries the script imports.

Unlike the limit for compiled tokens, the request size limit includes unused parts of the code. This is because the script is not compiled yet, so any unused code has not yet been optimized out.

**To reduce the compilation request size, you can:

  • Reduce the size of the script by optimizing the code.
  • Reduce the number of script inputs (script inputs are counted separately).
  • Remove any imported libraries that are not needed.

Other Limitations

Maximum Bars Back

References to past values using the [] history-referencing operator are dependent on the size of the historical buffer maintained by the Lipi Script™ runtime, which is limited to a maximum of 9,000 bars. This Help Center page discusses the historical buffer and how to change its size using either the max_bars_back parameter or the max_bars_back() function.

Maximum Bars Forward

When positioning drawings using xloc.bar_index, it is possible to use bar index values greater than that of the current bar as x coordinates. A maximum of 500 bars in the future can be referenced.

Chart Bars

The number of bars appearing on charts is dependent on the amount of historical data available for the chart’s symbol and timeframe. When the required historical data is available, the minimum number of chart bars is:

  • 9,000 historical bars for given intraday timeframe.