Type System
Introduction
The Lipi Script type system determines the compatibility of a script’s values with various functions and operations. While it’s possible to write simple scripts without knowing anything about the type system, a reasonable understanding of it is necessary to achieve any degree of proficiency with the language, and an in-depth knowledge of its subtleties allows programmers to harness its full potential.
Lipi Script uses types to classify all values, and it uses qualifiers to determine whether values and references are constant, established on the first script execution, or dynamic across executions. This system applies to all Lipi values and references, including literals, variables, expressions, function returns, and function arguments.
The type system closely intertwines with Lipi’s execution model and time series concepts. Understanding all three is essential for making the most of the power of Lipi Script.
For the sake of brevity, we often use “type” to refer to a “qualified type”
Qualifiers
Lipi Script qualifiers identify when values are accessible to a script:
- Values and references qualified as const are established at compile time (i.e., when saving the script in the Lipi Editor or adding it to the chart).
- Values qualified as input are established at input time (i.e., when confirming values based on user input, primarily from the “Settings/Inputs” tab).
- Values qualified as simple are established at bar zero (i.e., the first script execution).
- Values qualified as series can change throughout the script’s executions.
Lipi Script bases the dominance of type qualifiers on the following hierarchy: const < input < simple < series
, where “const” is the weakest qualifier and “series” is the strongest. The qualifier hierarchy translates to this rule: whenever a variable, function, or operation is compatible with a specific qualified type, values with weaker qualifiers are also allowed.
Scripts always qualify their expressions’ returned types based on the dominant qualifier in their calculations. For example, evaluating an expression that involves “input” and “series” values will return a value qualified as “series”. Furthermore, scripts cannot change a value’s qualifier to one that’s lower on the hierarchy. If a value acquires a stronger qualifier (e.g., a value initially inferred as “simple” becomes “series” later in the script’s executions), that state is irreversible.
It’s important to note that “series” values are the only ones that can change across script executions, including those from various built-ins, such as close and volume, as well as the results of expressions involving “series” values. All values qualified as “const”, “input”, or “simple” remain consistent across all script executions.
const
Values or references qualified as “const” are established at compile time, before the script starts its executions. Compilation initially occurs when saving a script in the Lipi Editor, which does not require it to run on a chart. Values or references with the “const” qualifier never change between script executions, not even on the first execution.
All literal values and the results returned by expressions involving only values qualified as “const” automatically adopt the “const” qualifier.
Here are some examples of literal values:
- literal int: 1, -1, 42
- literal float: 1., 1.0, 3.14, 6.02E-23, 3e8
- literal bool: true, false
- literal color: #FF55C6, #FF55C6ff
- literal string: “A text literal”, “Embedded single quotes ‘text’”, ‘Embedded double quotes “text”’
Our Style guide recommends using uppercase SNAKE_CASE to name “const” variables for readability. While not a requirement, one can also use the static keyword when declaring “const” variables so the script only initializes them on the first bar of the dataset. See this section of our User Manual for more information.
Below is an example that uses “const” values within the indicator() and plot() functions, which both require a value of the “const string” qualified type as their title argument:
// The following global variables are all of the "const string" qualified type:
//@variable The title of the indicator.
INDICATOR_TITLE = "const demo"
//@variable The title of the first plot.
static PLOT1_TITLE = "High"
//@variable The title of the second plot.
string PLOT2_TITLE = "Low"
//@variable The title of the third plot.
PLOT3_TITLE = "Midpoint between " + PLOT1_TITLE + " and " + PLOT2_TITLE
indicator(INDICATOR_TITLE, overlay = true)
plot(high, PLOT1_TITLE)
plot(low, PLOT2_TITLE)
plot(hl2, PLOT3_TITLE)
The example below will result in a compilation error because it utilizes syminfo.ticker, which yields a “simple” value due to its reliance on chart information that is only available after the script’s initial execution.
//@variable The title in the `indicator()` call.
static NAME = "My indicator for " + syminfo.ticker;
indicator(NAME, "", true); // Causes an error because `NAME` is qualified as a "simple string".
plot(close);
The const keyword enables the declaration of variables and parameters that are assigned constant values. When a variable is declared using this keyword, it instructs the script to prevent any reassignment or compound assignment operations. For instance, the following script declares the variable myVar using this keyword and then tries to assign a new “float” value to it using the addition assignment operator (+=), which leads to a compilation error:
indicator("Cannot reassign const demo")
//@variable A "float" variable declared as `const`, preventing reassignment.
const float myVar = 0.0
// Causes an error. Reassignment and compound assignments are not allowed on `const` variables.
myVar += 1.0
plot(myVar)
It is important to understand that declaring a variable with the const keyword enforces a constant reference to the value produced by a specific expression; however, this does not define the characteristics of the assigned value.
Most values qualified as “input” are set after initialization through the input.*() functions. These functions generate values that users can adjust within the “Inputs” tab of the script’s settings. When any values in this tab are modified, the script restarts from the beginning of the chart’s history to ensure that its inputs remain consistent throughout its executions. Additionally, some of Lipi’s built-in variables, such as chart.bg_color, also utilize the “input” qualifier, even though input.*() functions do not directly return them, as the script obtains their values at input time.
The input.source()
functions are exceptions
in the input.*()
namespace, as they do not return values qualified
as “input”. The input.source()
function returns “series”
values since built-in variables such as open and close, as well
as the values from another script’s plots, have the “series”
qualifier. See this manual’s Inputs page for more information.
simple
Values classified as “simple” are accessible during the first script execution and remain consistent in subsequent executions.
Users can explicitly declare variables and parameters that accept “simple” values by including the simple keyword in their declarations.
Many built-in variables return values qualified as “simple” because they rely on information that a script can only acquire once it starts running on the chart. Furthermore, numerous built-in functions require “simple” arguments that do not change over time. Whenever a script permits “simple” values, it can also accept values qualified as “input” or “const.”
The following script changes the background color to alert users that they are utilizing a non-standard chart type. It calculates the isNonStandard variable using the value of chart.is_standard and then employs that variable’s value to determine a warningColor that also references a “simple” value. The color parameter of bgcolor() accepts a “series color” argument, which means it can also take a “simple color” value since “simple” is lower in the hierarchy:
indicator("simple demo", overlay = true)
//@variable Is `true` when the current chart is non-standard. Qualified as "simple bool".
isNonStandard = not chart.is_standard
//@variable Is orange when the the current chart is non-standard. Qualified as "simple color".
simple color warningColor = isNonStandard ? color.new(color.orange, 70) : na
// Colors the chart's background to warn that it's a non-standard chart type.
bgcolor(warningColor, title = "Non-standard chart color")
Series
Values classified as series offer maximum flexibility in scripts, as they can vary across executions.
To define variables and parameters that accept “series” values, users can specify the series
keyword in their declarations.
Certain built-in variables—like open
, high
, low
, close
, volume
, time
, and bar_index
—and any expressions using these variables, are categorized as series. Results from any function or operation that yields dynamic values are also classified as series, as are values accessed using the history-referencing operator []
to retrieve historical data. Where a script permits series values, it will also accept values with any other qualifier, as series is the highest qualifier in the hierarchy.
This script demonstrates displaying the highest and lowest values of sourceInput
over lengthInput
bars. The highest
and lowest
variables are of the series float type, allowing them to update throughout the script’s execution:
indicator("series demo", overlay = true)
//@variable The source value to calculate on. Qualified as "series float".
float sourceInput = input.source(close, "Source")
//@variable The number of bars in the calculation. Qualified as "input int".
lengthInput = input.int(20, "Length")
//@variable The highest `sourceInput` value over `lengthInput` bars. Qualified as "series float".
float highest = talib.highest(sourceInput, lengthInput)
//@variable The lowest `sourceInput` value over `lengthInput` bars. Qualified as "series float".
lowest = talib.lowest(sourceInput, lengthInput)
plot(highest, "Highest source", color.green)
plot(lowest, "Lowest source", color.red)
Types
Lipi Script types categorize values and define the functions and operations they support. The types include:
- Fundamental types: int, float, bool, color, and string
- Special types: plot, hline, line, linefill, box, polyline, label, table, chart.point,
- User-defined types (UDTs)
- Enums
- void
Fundamental types describe the basic nature of a value. For example, a value of 1
is of the int type, 1.0
is of the float type, and "AAPL"
is of the string type. Special types and user-defined types rely on IDs that represent specific object types. For instance, a value of the label type contains an ID that functions as a pointer to a label object. The void type refers to the output of a function or method that does not return a usable value.
Lipi Script can automatically convert some values between types, following the rule: int → float → bool. For more details, refer to the Type casting section.
Generally, Lipi Script automatically identifies a value’s type. However, type keywords can be used to explicitly define types, enhancing readability and supporting code that requires precise type declarations (e.g., when assigning a variable to na
). For example:
indicator("Types demo", overlay = true)
//@variable A value of the "const string" type for the `ma` plot's title.
string MA_TITLE = "MA"
//@variable A value of the "input int" type. Controls the length of the average.
int lengthInput = input.int(100, "Length", minval = 2)
//@variable A "series float" value representing the last `close` that crossed over the `ma`.
static float crossValue = na
//@variable A "series float" value representing the moving average of `close`.
float ma = talib.sma(close, lengthInput)
//@variable A "series bool" value that's `true` when the `close` crosses over the `ma`.
bool crossUp = talib.crossover(close, ma)
//@variable A "series color" value based on whether `close` is above or below its `ma`.
color maColor = close > ma ? color.lime : color.red
// Update the `crossValue`.
if crossUp {
crossValue := close
}
plot(ma, MA_TITLE, maColor)
plot(crossValue, "Cross value", style = plotStyle.scatter)
plotchar(crossUp, "Cross Up", "▲", location.belowbar, size = size.small)
int
Values of the int type represent integers, which are whole numbers without fractions.
Integer literals are numbers written in decimal form. For example:
1
- 1;
750;
Built-in variables like bar_index, time, timenow, dayofmonth all return values of the int type.
float
Values of the float type represent floating-point numbers, which include both whole and fractional parts.
Floating-point literals are numbers written with a .
as a decimal separator. They can also include the symbols e
or E
(representing “10 raised to the power of X,” where X is the number following the e
or E
). For example:
// Rounded value of Pi (π)
3.14159 -
3.0;
// 6.02 * 10^23 (a very large value)
6.02e23;
// 1.6 * 10^-19 (a very small value)
1.6e-19;
The internal precision of float values in Lipi Script is 1e-16
.
Built-in variables like close, hlcc4, volume, talib.vwap, and strategy.position_size return values of the float type.
bool
Values of the bool type represent the truth value of a condition or comparison, which can be used in conditional structures and other expressions within scripts.
There are only two literals representing boolean values:
// true value
true;
// false value
false;
When an expression of the “bool” type returns na, scripts treat its value as false when evaluating conditional statements and operators.
Built-in variables such as barstate.isfirst, chart.is_heikinashi, session.ismarket, and timeframe.isdaily all return values of the “bool” type.
color Color literals have the following format: #RRGGBB or #RRGGBBAA. The letter pairs represent hexadecimal values between 00 and FF (0 to 255 in decimal) where:
RR, GG and BB pairs respectively represent the values for the color’s red, green and blue components. AA is an optional value for the color’s opacity (or alpha component) where 00 is invisible and FF opaque. When the literal does not include an AA pair, the script treats it as fully opaque (the same as using FF). The hexadecimal letters in the literals can be uppercase or lowercase. These are examples of “color” literals:
#000000 // black color
#FF0000 // red color
#00FF00 // green color
#0000FF // blue color
#FFFFFF // white color
#808080 // gray color
#3ff7a0 // some custom color
#FF000080 // 50% transparent red color
#FF0000ff // same as #FF0000, fully opaque red color
#FF000000 // completely transparent red color
Lipi Script includes built-in color constants, such as color.green, color.red, color.orange, and color.blue (the default color in plot() functions and many default color settings in drawing types).
When using these built-in color constants, you can apply transparency using the color.new() function.
When defining red, green, or blue components in color.* functions, we use int or float arguments ranging from 0
to 255
. For transparency, values range from 0
to 100
, where 0
is fully opaque and 100
is fully transparent. For example:
indicator("Shading the chart's background", overlay = true)
//@variable A "const color" value representing the base for each day's color.
color BASE_COLOR = color.rgb(0, 99, 165)
//@variable A "series int" value that modifies the transparency of the `BASE_COLOR` in `color.new()`.
int transparency = 50 + int(40 * dayofweek / 7)
// Color the background using the modified `BASE_COLOR`.
bgcolor(color.new(BASE_COLOR, transparency))
string
Values of the string type represent sequences of letters, numbers, symbols, spaces, and other characters.
In Lipi Script, string literals are characters enclosed in either single or double quotation marks. For example:
"This is a string literal using double quotes.";
"This is a string literal using single quotes.";
Single and double quotation marks are interchangeable in Lipi Script. A string enclosed in double quotation marks can contain any number of single quotation marks, and vice versa:
"It's an example";
'The "Star" indicator';
Scripts can escape the enclosing delimiter in a string using the backslash character (\
). For example:
'It\'s an example';
"The \"Star\" indicator";
We can create string values that include the new line escape character (\n
) to display multi-line text with plot() and log.() functions, as well as with objects of drawing types. For example:
"This\nString\nHas\nOne\nWord\nPer\nLine";
We can use the + operator to concatenate “string” values:
"This is a " + "concatenated string.";
The built-in functions in the str.* namespace generate string values using specific operations.
Built-in variables like syminfo.tickerid, syminfo.currency, and timeframe.period return values of the string type.
plot and hline
The plot() and hline() functions in Lipi Script return IDs that reference instances of the plot and hline types, respectively. These types are used to display calculated values and horizontal levels on the chart. You can assign their IDs to variables for use with the built-in fill() function.
For example, this script plots two EMAs on the chart and fills the area between them using a fill() call:
indicator("plot fill demo", overlay = true)
//@variable A "series float" value representing a 10-bar EMA of `close`.
float emaFast = talib.ema(close, 10)
//@variable A "series float" value representing a 20-bar EMA of `close`.
float emaSlow = talib.ema(close, 20)
//@variable The plot of the `emaFast` value.
emaFastPlot = plot(emaFast, "Fast EMA", color.orange, 3)
//@variable The plot of the `emaSlow` value.
emaSlowPlot = plot(emaSlow, "Slow EMA", color.gray, 3)
// Fill the space between the `emaFastPlot` and `emaSlowPlot`.
fill(emaFastPlot, emaSlowPlot, color = color.new(color.purple, .5), title = "EMA Fill")
It’s important to note that, unlike other special types, there are no plot or hline keywords in Lipi Script to explicitly declare a variable’s type as plot or hline.
Users can manage the display location of their script’s plots using the variables in the display.* namespace and the force_overlay parameter of the plot() function. Furthermore, one script can utilize the values from another script’s plots as external inputs through the input.source() function.
User-Defined Types
The type keyword enables the creation of user-defined types (UDTs), which scripts can utilize to create objects. UDTs are composite types that can consist of an arbitrary number of fields, each of which can be of any type, including other user-defined types.
The syntax for declaring a user-defined type is as follows:
[export ]type <UDT_identifier>
<field_type> <field_name>[ = <value>]
...
where:
- export is the keyword that a library script uses to export the user-defined type. To learn more about exporting UDTs, refer to the Libraries page in our User Manual.
<UDT_identifier>
is the name of the user-defined type.<field_type>
is the type of the field.<field_name>
is the name of the field.<value>
is an optional default value for the field, which the script assigns when creating new objects of that UDT. If no value is provided, the default for the field is na. The same rules governing the default values of parameters in function signatures apply to the default values of fields. For example, a UDT’s default values cannot use results from the history-referencing operator [] or expressions.
This example declares a pivotPoint UDT with an int pivotTime field and a float priceLevel field, which will hold time and price information about a calculated pivot:
//@type A user-defined type containing pivot information.
//@field pivotTime Contains time information about the pivot.
//@field priceLevel Contains price information about the pivot.
type pivotPoint {
int pivotTime
float priceLevel
}
User-defined types support type recursion, meaning that the fields of a UDT can reference objects of the same UDT. In this example, we have added a nextPivot field to our previous pivotPoint type, which references another instance of pivotPoint:
//@type A user-defined type containing pivot information.
//@field pivotTime Contains time information about the pivot.
//@field priceLevel Contains price information about the pivot.
//@field nextPivot A `pivotPoint` instance containing additional pivot information.
type pivotPoint {
int pivotTime
float priceLevel
pivotPoint nextPivot
}
Scripts can use two built-in methods to create and copy UDTs: new() and copy().
void
In Lipi Script, there exists a “void” type. Functions that perform only side effects and do not return any usable result are classified as returning the “void” type. An example of such a function is alert(); it performs an action (triggers an alert event) but does not yield any usable value.
Scripts cannot utilize “void” results in expressions or assign them to variables. Additionally, there is no void keyword in Lipi Script since one cannot declare a variable of the “void” type.
na
value
There is a special value in Lipi Script known as na, which stands for not available. We use na to signify an undefined value from a variable or expression. It is akin to null in Java and None in Python.
Scripts can automatically cast na values to nearly any type. However, in certain cases, the compiler may be unable to infer the type associated with an na value due to the applicability of multiple type-casting rules. For instance:
// Compilation error!
myVar = na;
The line of code above results in a compilation error because the compiler cannot ascertain the nature of the myVar variable. Specifically, it is unclear whether the variable will refer to numeric values for plotting, string values for setting text in a label, or other values for different purposes later in the script’s execution.
To address such errors, we need to explicitly declare the type associated with the variable. For instance, if the myVar variable is intended to reference “float” values in subsequent iterations of the script, we can resolve the error by declaring the variable with the float keyword:
float myVar = na
or by explicitly casting the na value to the “float” type via the float() function:
myVar = float(na);
To test if the value from a variable or expression is na, we call the na() function, which returns true if the value is undefined. For example:
//@variable Is 0 if the `myVar` is `na`, `close` otherwise.
float myClose = na(myVar) ? 0 : close
Do not use the == comparison operator to test for na values, as scripts cannot determine the equality of an undefined value:
//@variable Returns the `close` value. The script cannot compare the equality of `na` values, as they're undefined.
float myClose = myVar == na ? 0 : close
Best coding practices often involve handling na values to prevent undefined values in calculations.
For example, this line of code checks if the close value on the current bar is greater than the previous bar’s value:
//@variable Is `true` when the `close` exceeds the last bar's `close`, `false` otherwise.
bool risingClose = close > close[1]
On the first chart bar, the value of risingClose is na since there is no past close value to reference.
We can ensure the expression also returns an actionable value on the first bar by replacing the undefined past value with a value from the current bar. This line of code uses the nz() function to replace the past bar’s close with the current bar’s open when the value is na:
//@variable Is `true` when the `close` exceeds the last bar's `close` (or the current `open` if the value is `na`).
bool risingClose = close > nz(close[1], open)
Protecting scripts against na instances helps to prevent undefined values from propagating in a calculation’s results. For example, this script declares an allTimeHigh variable on the first bar. It then uses the math.max() between the allTimeHigh and the bar’s high to update the allTimeHigh throughout its execution:
indicator("na protection demo", overlay = true)
//@variable The result of calculating the all-time high price with an initial value of `na`.
static float allTimeHigh = na
// Reassign the value of the `allTimeHigh`.
// Returns `na` on all bars because `math.max()` can't compare the `high` to an undefined value.
allTimeHigh := math.max(allTimeHigh, high)
Plots `na` on all bars.
plot(allTimeHigh) //
This script plots a value of na on all bars, as we have not included any na protection in the code. To fix the behavior and plot the intended result (i.e., the all-time high of the chart’s prices), we can use nz() to replace na values in the allTimeHigh series:
indicator("na protection demo", overlay = true)
//@variable The result of calculating the all-time high price with an initial value of `na`.
static float allTimeHigh = na
// Reassign the value of the `allTimeHigh`.
// We've used `nz()` to prevent the initial `na` value from persisting throughout the calculation.
allTimeHigh := math.max(nz(allTimeHigh), high)
plot(allTimeHigh)
Type Casting
Lipi Script features an automatic type-casting mechanism that converts “int” values to “float” when necessary. Variables or expressions that require “float” values can also utilize “int” values since any integer can be represented as a floating-point number with its fractional part equal to 0.
For backward compatibility, Lipi Script also automatically casts “int” and “float” values to “bool” when necessary. When passing numeric values to the parameters of functions and operations expecting “bool” types, Lipi auto-casts them to “bool”. However, it is not recommended to rely on this behavior. Most scripts that automatically cast numeric values to the “bool” type will generate a compiler warning. You can avoid this warning and enhance code readability by using the bool() function, which explicitly converts a numeric value to the “bool” type.
When casting an “int” or “float” to “bool”, a value of 0 converts to false, while any other numeric value always converts to true.
The following code demonstrates the deprecated auto-casting behavior in Lipi. It creates a randomValue variable with a “series float” value on every bar, which it then passes to the condition parameter in an if structure and the series parameter in a plotchar() function call. Since both parameters accept “bool” values, the script automatically casts randomValue to “bool” during evaluation:
indicator("Auto-casting demo", overlay = true)
//@variable A random rounded value between -1 and 1.
float randomValue = math.round(math.random(-1, 1))
//@variable The color of the chart background.
color bgColor = na
// This raises a compiler warning since `randomValue` is a "float", but `if` expects a "bool".
if randomValue {
bgColor := color.new(color.blue, 60)
}
// This does not raise a warning, as the `bool()` function explicitly casts the `randomValue` to "bool".
if bool(randomValue) {
bgColor := color.new(color.blue, 60)
}
// Display unicode characters on the chart based on the `randomValue`.
// Whenever `math.random()` returns 0, no character will appear on the chart because 0 converts to `false`.
plotchar(randomValue)
// We recommend explicitly casting the number with the `bool()` function to make the type transformation more obvious.
plotchar(bool(randomValue))
// Highlight the background with the `bgColor`.
bgcolor(bgColor)
It is sometimes necessary to cast one type to another when the auto-casting rules do not suffice. For such cases, the following type-casting functions are available: int(), float(), bool(), color(), string(), line(), linefill(), label(), box(), and table().
The example below demonstrates a code snippet that attempts to use a “const float” value as the length argument in the talib.sma() function call. The script will fail to compile, as it cannot automatically convert the “float” value to the required “int” type:
indicator("Explicit casting demo", overlay = true)
//@variable The length of the SMA calculation. Qualified as "const float".
float LENGTH = 10.0
float sma = talib.sma(close, LENGTH) // Compilation error. The `length` parameter requires an "int" value.
plot(sma)
The code raises the following error: “Cannot call ‘talib.sma’ with argument ‘length’=‘LENGTH’. An argument of ‘const float’ type was used but a ‘series int’ is expected.”
The compiler is telling us that the code is using a “float” value where an “int” is required. There is no auto-casting rule to cast a “float” to an “int”, so we must do the job ourselves. In this version of the code, we’ve used the int() function to explicitly convert our “float” LENGTH value to the “int” type within the talib.sma() call:
indicator("explicit casting demo")
//@variable The length of the SMA calculation. Qualified as "const float".
float LENGTH = 10.0
// Compiles successfully since we've converted the `LENGTH` to "int".
float sma = talib.sma(close, math.floor(LENGTH))
plot(sma)
Explicit type casting is also handy when declaring variables assigned to na, as explained in the previous section.
For example, once could explicitly declare a variable with a value of na as a “label” type in either of the following, equivalent ways:
// Explicitly specify that the variable references "label" objects:
label myLabel = na
// Explicitly cast the `na` value to the "label" type:
myLabel = label(na)
Tuples
A tuple is defined as a set of expressions separated by commas and enclosed in brackets. When a function, method, or local block returns multiple values, those values are returned as a tuple.
For instance, the following user-defined function returns both the sum and the product of two “float” values:
//@function Calculates the sum and product of two values.
calcSumAndProduct(float a, float b) =>
//@variable The sum of `a` and `b`.
float sum = a + b
//@variable The product of `a` and `b`.
float product = a * b
// Return a tuple containing the `sum` and `product`.
[sum, product]
When we call this function later in the script, we use a tuple declaration to declare multiple variables corresponding to the values returned by the function call:
// Declare a tuple containing the sum and product of the `high` and `low`, respectively.
[hlSum, hlProduct] = calcSumAndProduct(high, low);
Note: Unlike declaring individual variables, we cannot explicitly specify the types for the variables in a tuple (such as hlSum and hlProduct in this case). The compiler automatically infers the types associated with the variables within the tuple.
In the example above, the resulting tuple consists of values of the same type (“float”). However, it’s crucial to recognize that tuples can contain values of multiple types. For instance, the chartInfo() function below returns a tuple comprising “int”, “float”, “bool”, “color”, and “string” values:
//@function Returns information about the current chart.
chartInfo() =>
//@variable The first visible bar's UNIX time value.
int firstVisibleTime = chart.left_visible_bar_time
//@variable The `close` value at the `firstVisibleTime`.
float firstVisibleClose = talib.valuewhen(talib.cross(time, firstVisibleTime), close, 0)
//@variable Is `true` when using a standard chart type, `false` otherwise.
bool isStandard = chart.is_standard
//@variable The foreground color of the chart.
color fgColor = chart.fg_color
//@variable The ticker ID of the current chart.
string symbol = syminfo.tickerid
// Return a tuple containing the values.
[firstVisibleTime, firstVisibleClose, isStandard, fgColor, symbol]
Local blocks of conditional structures, if
statements, can return tuples. For example:
[v1, v2] = if close > open {
[high, close]
} else {
[close, low
}
However, ternaries cannot contain tuples, as the return values in a ternary statement are not considered local blocks:
// Not allowed.
[v1, v2] = close > open ? [high, close] : [close, low];
Note that all items within a tuple returned from a function are qualified as “simple” or “series”, depending on its contents. If a tuple contains a “series” value, all other elements within the tuple will also adopt the “series” qualifier.