> ## Documentation Index
> Fetch the complete documentation index at: https://gocharting.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Execution and types across languages

> How Lipi maps to MQL4, MQL5, NinjaScript, Pine Script and thinkScript for execution and types: bar-by-bar evaluation, declare an indicator, declare a strategy, price pane or own pane, recalculate on every update, language version header and more, with the differences that matter when converting.

How a script runs and the kinds of values it works with. Each row maps one concept from Lipi to the other languages; the word in a cell is the relation, explained in the [language map overview](https://gocharting.com/docs/scripting/reference/language-map.md#relations).

| Concept | Lipi | MQL4 | MQL5 | NinjaScript | Pine Script | thinkScript |
| - | - | - | - | - | - | - |
| [Bar-by-bar evaluation](#exec-bar-by-bar) | Syntax | Differs | Differs | Caveat | Exact | Caveat |
| [Declare an indicator](#exec-declare-indicator) | `indicator` | Caveat | Caveat | Caveat | Caveat | Caveat |
| [Declare a strategy](#exec-declare-strategy) | `strategy` | Absent | Caveat | Caveat | Caveat | Absent |
| [Price pane or own pane](#exec-overlay) | `indicator` | Caveat | Caveat | Caveat | Exact | Caveat |
| [Recalculate on every update](#exec-every-tick) | `indicator`, `barstate.isconfirmed` | Differs | Absent | Caveat | Caveat | Caveat |
| [Language version header](#exec-version-header) | `@lipi=` | Differs | Absent | Absent | Caveat | Absent |
| [Basic value types](#types-basic) | `int`, `float`, `bool`, `string`, `color` | Caveat | Caveat | Caveat | Caveat | Caveat |
| [Missing value](#types-missing-value) | `na`, `nz`, `fixnan` | Differs | Differs | Differs | Caveat | Composite |
| [Value qualifiers](#types-qualifiers) | `const`, `simple`, `series` | Differs | Differs | Absent | Caveat | Absent |
| [Type conversion](#types-conversion) | `int`, `float`, `bool`, `str.tostring`, `str.tonumber` | Caveat | Caveat | Caveat | Caveat | Composite |
| [Declare and assign a variable](#decl-variable) | Syntax | Caveat | Caveat | Caveat | Exact | Caveat |
| [Your own enumeration](#decl-enum) | `enum` | Caveat | Caveat | Caveat | Caveat | Caveat |
| [Your own object type](#decl-user-type) | `type` | Caveat | Caveat | Caveat | Caveat | Absent |
| [Several values at once](#decl-tuple) | Syntax | Absent | Absent | Caveat | Exact | Caveat |

Each section below gives the Lipi construct first, then the construct in each language, with a note wherever behaviour differs. The language name links to the documentation the row was checked against.

## Bar-by-bar evaluation

The script body runs once for every bar, oldest first, and then again as the live bar updates.

In Lipi this is written with the language's own syntax. A closed bar runs once. A forming live bar reruns on every tick only if calc\_on\_every\_tick is true; those reruns do not advance history.

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("Bars seen so far")
static int seen = 0
seen += 1
plot(seen, title="Bars")
```

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/function/events) | `OnTick / OnCalculate` | Looks alike, behaves differently | Handler runs per incoming tick (Expert Advisor) or per calculate call (indicator), not once per bar; indicator code loops over bars itself using prev\_calculated. Bar timing: No automatic oldest-first pass per bar; prev\_calculated tells the loop where to start. |
| [MQL5](https://www.mql5.com/en/docs/event_handlers/oncalculate) | OnCalculate; OnTick | Looks alike, behaves differently | The handler receives whole arrays per call, not one bar; your own loop starts at prev\_calculated. Expert Advisors run OnTick once per tick. Bar timing: Calculate fires on new ticks or price-data changes; one call may cover many bars. State and side effects: Locals vanish after each call; globals persist between calls. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/onbarupdate.htm) | `OnBarUpdate()` | Equivalent, with a caveat | A method override runs once per bar on history; live it follows the Calculate setting. One-time setup belongs in OnStateChange(), not here. Bar timing: Multi-series scripts get one call per Bars object; filter with BarsInProgress or logic runs several times per bar. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/language/execution-model/) | script body runs once per bar; on the open realtime bar it reruns on every update (indicators) | Exact | |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/tutorials/Basic/Chapter-1---Defining-Variables) | `(implicit per-bar series evaluation)` | Equivalent, with a caveat | Values are computed per bar from the first bar and the last bar is recalculated on updates; negative indexes can read later bars. Bar timing: A negative index lets a bar read later bars, so evaluation is not strictly oldest-first causal as in Lipi. |

## Declare an indicator

A statement that names the script as an indicator and sets its display options.

In Lipi: `indicator`. `title` is the only required argument. The call must be at top level. Title and shorttitle max 128 characters, checked on Add to chart.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/preprosessor/compilation) | #property indicator\_chart\_window / indicator\_separate\_window / indicator\_buffers | Equivalent, with a caveat | No single declaration statement; #property lines set window and buffer count, and the OnCalculate handler marks the program as an indicator. |
| [MQL5](https://www.mql5.com/en/docs/basis/preprosessor/compilation) | #property indicator\_chart\_window; #property indicator\_separate\_window; #property indicator\_buffers; #property indicator\_plots | Equivalent, with a caveat | No declaration call: the program is an indicator because it defines OnCalculate; display options and buffer counts come from #property lines. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/indicator.htm) | class derived from Indicator, defaults set in OnStateChange() during State.SetDefaults | Equivalent, with a caveat | Declared as a C# class; defaults are pushed from OnStateChange. Display options are separate properties (IsOverlay, AddPlot, DrawOnPricePanel), not arguments of one call. |
| [Pine Script](https://www.tradingview.com/pine-script-reference/v6/#fun_indicator) | `indicator()` | Equivalent, with a caveat | Lipi's indicator takes fewer arguments: no timeframe, timeframe\_gaps, max\_bars\_back, explicit\_plot\_zorder or dynamic\_requests. Title is the only required argument in both. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Reserved-Words/declare) | `declare` | Equivalent, with a caveat | No title statement: declare only sets display or recalculation behaviour; a script is a study by being added on the Studies tab. |

## Declare a strategy

A statement that names the script as a strategy and sets its simulation options.

In Lipi: `strategy`. No slippage, currency or margin arguments. default\_qty\_type is an unchecked string; only strategy.fixed exists as a constant, "cash" and "percent\_of\_equity" are strings.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/preprosessor/compilation) | | Not in MQL4 | No strategy declaration or simulation options in code; the #property list has no capital or commission setting. A strategy is an Expert Advisor with OnTick. |
| [MQL5](https://www.mql5.com/en/docs/runtime/running) | `Expert Advisor with OnTick` | Equivalent, with a caveat | No strategy statement: an Expert Advisor is its own program type run per tick, and it sends real trade requests. State and side effects: The same code trades live; the Strategy Tester only supplies simulated history and server. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/strategy.htm) | class derived from Strategy, defaults set in OnStateChange() during State.SetDefaults | Equivalent, with a caveat | Simulation options are individual properties (EntriesPerDirection, EntryHandling, DefaultQuantity, Slippage, IncludeCommission) rather than arguments of one declaration call. |
| [Pine Script](https://www.tradingview.com/pine-script-reference/v6/#fun_strategy) | `strategy()` | Equivalent, with a caveat | Lipi's strategy lacks slippage, currency, margin\_long, margin\_short, close\_entries\_rule, use\_bar\_magnifier and other Pine arguments, and several defaults differ (see strat.settings). |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/tutorials/Basic/Chapter-7---Creating-Strategies) | | Not in thinkScript | No strategy statement: any script that calls AddOrder acts as a strategy and is added on the Strategies tab; settings live in the UI. |

## Price pane or own pane

Whether the script draws on the price chart or in a separate pane below it.

In Lipi: `indicator`. Default is overlay=false (own pane). `force_overlay=true` on a plot, label or box puts it on the price pane; line.new spells it `forceOverlay`.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/preprosessor/compilation) | #property indicator\_chart\_window / #property indicator\_separate\_window | Equivalent, with a caveat | Two property names choose main chart or subwindow; subwindow scale is fixed with indicator\_minimum and indicator\_maximum. |
| [MQL5](https://www.mql5.com/en/docs/basis/preprosessor/compilation) | #property indicator\_chart\_window; #property indicator\_separate\_window | Equivalent, with a caveat | Two separate properties instead of one boolean; a separate window can also get a fixed height and minimum/maximum scale. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/isoverlay.htm) | `IsOverlay` | Equivalent, with a caveat | Same on/off flag with default false; set only in State.SetDefaults. True also allows use as a SuperDOM indicator. |
| [Pine Script](https://www.tradingview.com/pine-script-reference/v6/) | `overlay argument of indicator() and strategy()` | Exact | |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Declarations/upper) | declare lower; declare upper; declare on\_volume; | Equivalent, with a caveat | Default is the price chart (upper), the opposite of Lipi's default own pane; lower gives a separate pane and on\_volume the volume pane. |

## Recalculate on every update

Whether the live bar is recalculated on each price update or only when the bar closes.

In Lipi: `indicator`, `barstate.isconfirmed`. Indicator default is calc\_on\_every\_tick=true, strategy default false. An indicator with false is skipped on every unconfirmed bar.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/function/events) | `OnTick / OnCalculate` | Looks alike, behaves differently | Always recalculates on every tick; there is no close-only mode. To act once per bar, compare Time\[0] with a saved bar time. Bar timing: No setting to wait for bar close; every price update runs the handler. |
| [MQL5](https://www.mql5.com/en/docs/runtime/event_fire) | | Not in MQL5 | No switch: indicators recalculate when new ticks arrive and Expert Advisors run OnTick per tick; bar-close-only logic needs your own new-bar test. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/calculate.htm) | `Calculate` | Equivalent, with a caveat | Default is OnBarClose, whereas Lipi indicators default to every tick. OnPriceChange is a third mode. History ignores it unless Tick Replay is used. Bar timing: OnPriceChange skips repeat prices and can miss volume updates; Lipi has no such mode. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/language/execution-model/#executions-on-realtime-bars) | indicator() (always reruns on each realtime update); strategy(calc\_on\_every\_tick) | Equivalent, with a caveat | A Pine indicator has no per-tick switch and always reruns on every update; gate with barstate.isconfirmed. Only strategy() takes calc\_on\_every\_tick, default false. Bar timing: Lipi's indicator accepts calc\_on\_every\_tick=false to skip unconfirmed bars; a Pine indicator cannot opt out of per-tick execution. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Declarations/once-per-bar) | `declare once_per_bar` | Equivalent, with a caveat | Default recalculates the last bar on every tick; declare once\_per\_bar restricts that to once per bar, without saying whether at open or close. Bar timing: The docs do not say when in the bar the single recalculation happens; Lipi's off mode runs the script at bar close. |

## Language version header

A line at the top of the file that selects which version of the language compiles the script.

In Lipi: `@lipi=`. `//@lipi=2` is required on the v2 stack. The first match anywhere in the file counts; case and spaces around `=` are free.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/preprosessor/compilation) | #property strict | Looks alike, behaves differently | strict switches on stricter compilation; #property version is only the program's own version label, not a language-version selector. |
| [MQL5](https://www.mql5.com/en/docs/basis/preprosessor/compilation) | | Not in MQL5 | #property version only labels the program (maximum 31 characters); no property selects a language version. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/alphabetical_reference.htm) | | Not in NinjaScript | No per-script language-version directive appears in the language reference index; scripts follow the installed NinjaTrader release. |
| [Pine Script](https://www.tradingview.com/pine-script-reference/v6/) | `//@version=6` | Equivalent, with a caveat | Pine's directive is //@version=N and Lipi's is //@lipi=2; the numbers are unrelated. Pine allows it anywhere but recommends the top line. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Declarations) | | Not in thinkScript | The declarations list has no version or dialect selector; scripts carry no version line. |

## Basic value types

Whole numbers, decimal numbers, true/false values, text and colours.

In Lipi: `int`, `float`, `bool`, `string`, `color`. Colour literals are #RRGGBB or #RRGGBBAA, alpha last. No hex numbers or digit separators; string escapes such as \n are not translated.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/types/integer/color) | int, double, bool, string, color (also char, short, long, float, datetime) | Equivalent, with a caveat | color is a 4-byte integer holding blue-green-red bytes with no alpha; datetime is an integer count of seconds since 1970. Numbers and types: color has no alpha byte; datetime is whole seconds, not milliseconds. |
| [MQL5](https://www.mql5.com/en/docs/basis/types/integer/integertypes) | int, long, double, float, bool, string, color, datetime | Equivalent, with a caveat | Sized integers (int 32-bit, long 64-bit), float and double, and a separate datetime type; color carries no alpha channel. Numbers and types: int is 32-bit; large counts and volumes need long. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/basic_syntax.htm) | `int, double, bool, string, Brush` | Equivalent, with a caveat | Statically typed C#: float maps to double, text to string, and colours are WPF Brush objects (Brushes.Red), not a colour value. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/migration-guides/to-pine-version-6/#explicit-bool-casting) | `int, float, bool, string, color` | Equivalent, with a caveat | In v6 a bool is never na and numbers no longer cast implicitly to bool; Lipi accepts nonzero numbers where a bool is expected. Numbers and types: Pine v6 migration notes remove implicit number-to-bool casts; Lipi conditions and typed bool declarations accept numbers. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Data-Types/Data-Conversion) | `int, double, boolean, String, CustomColor` | Equivalent, with a caveat | Types are inferred, never written on declarations. float is called double, colour is CustomColor, and booleans convert to numbers freely. Numbers and types: yes/no convert to 1.0/0.0 and back; zero and NaN count as false, so booleans act as numbers. |

## Missing value

A value that stands for "no value on this bar", and the functions that test for it or replace it.

In Lipi: `na`, `nz`, `fixnan`. Arithmetic with na gives na, as does division or modulo by zero. `and`/`or` do not short-circuit, and `na and false` is na.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/constants/namedconstants/otherconstants#EMPTY_VALUE) | `EMPTY_VALUE, MathIsValidNumber` | Looks alike, behaves differently | EMPTY\_VALUE is an ordinary integer sentinel (2147483647) that does not propagate through arithmetic; there is no nz or fixnan, test with ==. Warm-up and missing values: Leading bars hold the sentinel, not a missing marker; calculations on it give garbage rather than missing. |
| [MQL5](https://www.mql5.com/en/docs/constants/namedconstants/otherconstants) | EMPTY\_VALUE; MathIsValidNumber; PLOT\_EMPTY\_VALUE | Looks alike, behaves differently | No na literal, nz or fixnan: empty plot slots hold EMPTY\_VALUE (DBL\_MAX), and invalid reals (NaN) are tested with MathIsValidNumber. Warm-up and missing values: EMPTY\_VALUE is an ordinary number (DBL\_MAX), not a propagating missing value. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/isvaliddatapoint.htm) | `ISeries<T>.IsValidDataPoint(barsAgo)` | Looks alike, behaves differently | No na value is documented. IsValidDataPoint(barsAgo) reports whether a slot was set; it works only on infinite-lookback series. Warm-up and missing values: An unset slot reports false; the page does not say what value a read returns, so test first. A 256-lookback series throws. |
| [Pine Script](https://www.tradingview.com/pine-script-reference/v6/) | `na, na(), nz(), fixnan()` | Equivalent, with a caveat | nz fills a missing color with transparent #00000000, Lipi with #483D8B. In v6 na(), nz() and fixnan() reject bool; Lipi's nz accepts it. Warm-up and missing values: Default replacement for a missing color differs: Pine #00000000 (transparent), Lipi #483D8B. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/tutorials/Appendices/Appendix-D---Using-NaN-and-Infinity-Constants) | `Double.NaN, IsNaN()` | Built from several Lipi constructs | No nz or fixnan: replace NaN with if IsNaN(x) then 0 else x, and carry the last value with CompoundValue and a self-reference. Warm-up and missing values: NaN spreads through arithmetic and recursion, and an if-expression on a NaN condition returns NaN; comparing with Double.NaN never works. |

## Value qualifiers

Markers that say whether a value is fixed at compile time, fixed after the first bar, or may change on every bar.

In Lipi: `const`, `simple`, `series`. const fits any parameter, series only a series one. Titles must be const, linewidth input. Reassigning inside if, for or switch makes a variable series.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/variables) | `const` | Looks alike, behaves differently | const only forbids reassignment after initialisation; there is no compile-time, per-script or per-bar evaluation class like const, simple, series. |
| [MQL5](https://www.mql5.com/en/docs/basis/variables) | `const` | Looks alike, behaves differently | const only forbids changing a variable at run time; simple and series qualifiers do not exist. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/basic_syntax.htm) | | Not in NinjaScript | No const, simple or series keywords; every value is an ordinary C# value. Per-bar history exists only through Series\<T> and ISeries objects. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/language/type-system/#qualifiers) | const, simple, series keywords (input is implicit) | Equivalent, with a caveat | Pine accepts qualifier keywords on variable declarations (const float x = 1) and parameters; Lipi only on parameters. The hierarchy matches. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Data-Types) | | Not in thinkScript | No qualifier keywords exist; the type is inferred from assignment and values are per-bar series. |

## Type conversion

Turning a value of one type into another, such as a decimal into a whole number or a number into text.

In Lipi: `int`, `float`, `bool`, `str.tostring`, `str.tonumber`. int() truncates toward zero; casts take numbers only. `+` does not join a string and a number: use str.tostring.

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/types/casting) | `(int)x, int(x), DoubleToString, StringToDouble, StringToInteger` | Equivalent, with a caveat | Casting a decimal to int cuts off the fraction instead of rounding; text conversion uses named functions, and string + number joins automatically. Numbers and types: Decimal to int truncates; out-of-range casts wrap around silently. |
| [MQL5](https://www.mql5.com/en/docs/basis/types/casting) | (int)x; int(x); DoubleToString; IntegerToString; StringToDouble; StringToInteger | Equivalent, with a caveat | Casting a real to an integer drops the fraction; MathRound rounds instead. Text conversion uses named functions such as DoubleToString and StringToDouble. Numbers and types: Mixed operands are promoted to the higher-priority type; string outranks numbers. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/basic_syntax.htm) | C# casts and .ToString() | Equivalent, with a caveat | Plain C# conversions; the closest page shows ToString(). Casting and parsing are standard C#, with no str.tonumber-style helper documented. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/language/type-system/#type-casting) | `int(), float(), bool(), str.tostring(), str.tonumber()` | Equivalent, with a caveat | Pine's bool(na) is false; Lipi's bool(na) is na, so test na() first. int() truncates toward zero in both. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Data-Types/Data-Conversion) | `AsText, implicit conversion` | Built from several Lipi constructs | No cast functions: numbers and booleans convert implicitly, ints truncate toward zero; AsText or + builds text; docs list no text-to-number function. |

## Declare and assign a variable

Giving a name to a value, and giving the name a new value later.

In Lipi this is written with the language's own syntax. `=` declares, `:=` assigns. A variable keeps the type of its first value (x = 0 is an int); na cannot start an untyped variable.

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("Variables")
spread = high - low
smooth = spread
smooth := talib.sma(spread, 5)
plot(smooth, title="Average spread")
```

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/variables) | type name = value; | Equivalent, with a caveat | A type is required at declaration and = both declares and reassigns; there is no separate := reassign operator. |
| [MQL5](https://www.mql5.com/en/docs/basis/variables/global) | type name = value; | Equivalent, with a caveat | The type is mandatory and a variable must be declared before use; locals are rebuilt on every function call, globals live for the whole program. State and side effects: Globals keep values across OnCalculate calls (ticks); Lipi variables are re-declared on every bar. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/basic_syntax.htm) | type name = value; | Equivalent, with a caveat | Needs an explicit type; one '=' both declares and reassigns, with no ':=' split. Locals vanish after each method call. State and side effects: Only class-level fields keep values between bars; method locals are rebuilt on every OnBarUpdate call. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/language/operators/) | name = value; name := value; var | Exact | |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Reserved-Words/def) | `def` | Equivalent, with a caveat | def values are per-bar series; a later assignment fills the definition inside branches, not a mutable update; self-reference starts from 0. Warm-up and missing values: A self-referencing def starts from 0, not na. State and side effects: Assignment defines the series for the bar; there is no rebinding with :=. |

## Your own enumeration

A named set of fixed options declared by the script.

In Lipi: `enum`. One member per line; no one-line form. Read a member as Name.A. An enum cannot be passed to str.tostring.

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("Enum")
enum Mode {
    Fast
    Slow
}
mode = input.enum(Mode.Fast, "Mode")
plot(mode == Mode.Fast ? 1 : 2)
```

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/variables/inputvariables) | `enum` | Equivalent, with a caveat | Members are integers that can be assigned values; // comments on members become dropdown labels when the enum is used as an input. |
| [MQL5](https://www.mql5.com/en/docs/basis/types/integer/enumeration) | `enum` | Equivalent, with a caveat | Members are named integers, numbered from 0 unless set; there are no title strings, though member comments label the input dropdown. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/creating_a_user-defined_parame.htm) | enum (C#) used as a public property type | Equivalent, with a caveat | Plain C# enum; as a public property it presents the user with hard-coded choices. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/language/type-system/#enum-types) | `enum` | Equivalent, with a caveat | Pine lists enum members as indented lines without braces, and allows str.tostring on enum members, which Lipi rejects. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Reserved-Words/def) | def \<name> = \{default a, b, c} | Equivalent, with a caveat | Values are strings, the enumeration belongs to one variable (no reusable named type), allows one assignment statement, and two enumerations are not interchangeable. |

## Your own object type

A named group of fields declared by the script, with objects created from it.

In Lipi: `type`. A field default is a literal, na or a built-in variable. Assigning an object (q = p) shares it; Pt.copy(p) makes a shallow copy.

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("Type")
type Span {
    float top
    float bottom
}
s = Span.new(high, low)
plot(s.top - s.bottom, title="Span")
```

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/types/classes) | `struct, class` | Equivalent, with a caveat | Fields declared in struct or class; variables of these types are passed by reference, and class objects can be created with new. |
| [MQL5](https://www.mql5.com/en/docs/basis/types/classes) | struct; class | Equivalent, with a caveat | Members accessed with a dot; both can hold methods, constructors and destructors; new works for classes only, not structures. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/considerations_for_compiled_assemblies.htm) | class or struct (C#) | Equivalent, with a caveat | Ordinary C# classes with fields and methods, created with new. The help guide shows classes only in passing; it has no tutorial for them. |
| [Pine Script](https://www.tradingview.com/pine-script-reference/v6/#kw_type) | `type` | Equivalent, with a caveat | Pine type bodies are indented fields built with Name.new(); a field can be declared varip. Lipi uses braces and static for persistence. |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/Data-Types) | | Not in thinkScript | Data types are the fixed built-in list; scripts cannot declare their own object types. |

## Several values at once

Returning or receiving more than one value from a single call.

In Lipi this is written with the language's own syntax. Counts must match: talib.macd and talib.bb return three values, talib.supertrend two. A tuple cannot be stored in one variable.

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("Tuple")
[macdLine, signalLine, hist] = talib.macd(close, 12, 26, 9)
plot(hist, title="Histogram")
```

| Language | Construct | Relation | Note |
| - | - | - | - |
| [MQL4](https://docs.mql4.com/basis/function/parameterpass) | | Not in MQL4 | A function returns one value; extra results go back through reference (&) parameters or a struct. |
| [MQL5](https://www.mql5.com/en/docs/basis/function) | | Not in MQL5 | A function returns one value and cannot return arrays or class objects; pass extra results out through reference (&) parameters or a simple struct. |
| [NinjaScript](https://ninjatrader.com/support/helpGuides/nt8/order_flow_volumetric_bars2.htm) | out parameters (C# tuples also available) | Equivalent, with a caveat | NinjaScript APIs return extra values through out parameters. Tuple returns are plain C#; the help guide documents no unpacking form. |
| [Pine Script](https://www.tradingview.com/pine-script-docs/language/type-system/#tuples) | `[a, b] = f()` | Exact | |
| [thinkScript](https://toslc.thinkorswim.com/center/reference/thinkScript/tutorials/Advanced/Chapter-13---Referencing-Other-Data) | script with several plots, read as name(args).plotName | Equivalent, with a caveat | A script block can expose several plots, read as name(args).plot; no multi-value assignment form is documented. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.