> ## 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.

# Lipi keywords

> Reference for the 24 keywords of Lipi v2: and, break, case, const and 20 more, each with its definition and an example.

> [!NOTE]
>
> Language version: 2 · Reference version: 2.7 · Date: 2026-10-25 · Compiler build: df7b3b14 · Entries: 24

## `and` (keyword)

**Definition**

True when both of its operands are true.

It has a symbol spelling as well, and the two are the same token to the lexer. There is no difference in behaviour to weigh up, so pick one spelling for a script and keep to it.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
expr0 && expr1 | expr0 and expr1
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("and Example", overlay=true)
// Both conditions must hold: an up bar on above-average volume
strongUp = close > open and volume > talib.sma(volume, 20)
bgcolor(strongUp ? color.new(color.green, 0.2) : na)
```

## `break` (keyword)

**Definition**

Leaves the innermost `for` or `while` loop at once.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
break
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("break Example")
float s = 0
for i = 0 to 9 {
    if i == 5 {
        break // stop the loop at 5
    }
    s += i
}
plot(s)
```

## `case` (keyword)

**Definition**

Starts one block of a `switch`: `case <value>:` runs its block when the value of the `switch` equals `<value>`.

The first case that matches runs, and the `switch` ends: the next case does not run. A case takes one value, so `case 1, 2:` is a syntax error. The value must have the type of the `switch` value (an int fits a float `switch`); otherwise the compiler stops with "Case condition is not compatible with switch condition." and the two types.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
case <value>: <statement>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("case Example")
int k = 2
float x = 0
switch k {
    case 1: x := 10
    case 2: x := 20
    default: x := 0
}
plot(x)
```

## `const` (keyword)

**Definition**

A qualifier written before the type of a parameter of your own function. A `const` parameter takes only a value that is known when the script is compiled, such as `2.0` or `10 * 2`.

A value that changes, such as `close`, is refused with "Cannot call `<function>` with argument `<name>`=`<value>`. An argument of `series float` type was used but a `const float` is expected." The word is not allowed before a variable declaration.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
func <name>(const <data_type> <parameter_name>) => <expression>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("const Example")
func scaled(series float x, const float k) => x * k
plot(scaled(close, 2.0))
```

## `continue` (keyword)

**Definition**

Skips the rest of the current pass of the innermost `for` or `while` loop and starts the next pass.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
continue
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("continue Example")
float s = 0
for i = 0 to 9 {
    if i == 5 {
        continue // skip 5
    }
    s += i
}
plot(s)
```

## `def` (keyword)

**Definition**

Declares a **type function** (method on a type): the **first parameter** is the receiver — its declared type is the type the method belongs to.

You must list **at least one** parameter (the receiver). Use `func` (or a declaration with no leading keyword) for ordinary functions, including `func name() => …` with zero parameters.

`def` is not interchangeable with `func` when the parameter list is empty.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
def <function_name>(<data_type> <param_name> [= <default_value>], ...) {
	<function_body>
}
		
func <function_name>(<data_type> <param_name> [= <default_value>], ...) => <expression>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("def type function Example", overlay=true)
def spread(float h, float l) {
    return h - l
}
plot(spread(high, low), title="Bar spread", color=color.blue)
```

## `default` (keyword)

**Definition**

Runs its block when no `case` of the `switch` matches.

A `switch` takes at most one `default`: a second one stops the compiler with "Only one `default` case is allowed in a switch statement."

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
default: <statement>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("default Example")
float k = close > open ? 1.0 : 2.0
float x = 0
switch k {
    case 1: x := 10
    case 2: x := 20
    default: x := 0
}
plot(x)
```

## `else` (keyword)

**Definition**

Runs a block when the condition of the `if` before it is false.

It follows the closing `}` of the `if` block, on the same line or on the next, and can be chained as `else if <condition> { ... }`.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
if <condition> {
	...
} else {
	...
}
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("else Example")
float level = 0
if close > open {
    level := 1
} else if close < open {
    level := -1
} else {
    level := 0
}
plot(level)
```

## `enum` (keyword)

**Definition**

Declares an enum of your own, as a braced block of members, one per line.

A member may carry something after `=`. Note what that is: a title, not a value.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
enum <enum_name> {
	<enum_field> [= <title>]
	...
}
```

**Example**

```lipi wrap theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("enum Example", overlay=true)
// Each member may carry a title after =, shown in the settings dropdown
enum Signal {
    buy = "Buy"
    sell = "Sell"
    neutral = "Neutral"
}
signal = close > open ? Signal.buy : close < open ? Signal.sell : Signal.neutral
bgcolor(signal == Signal.buy ? color.new(color.green, 0.15) : signal == Signal.sell ? color.new(color.red, 0.15) : na)
```

## `for in` (keyword)

**Definition**

Loops over each element of an array. The name after `in` must be a variable that holds an array; the loop variable is assigned the current element on every pass.

`break` leaves the loop and `continue` starts the next element. Like `while` and `for ... to`, the loop body is a braced block.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
for <identifier> in <identifier> {
	...
	break
	...
	continue
	...
}
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("for in Example", overlay=false)
values = array.from(1, 2, 3, 4, 5)
sum = 0
for v in values {
    sum += v
}
plot(sum, title="Sum of array", color=color.blue)
```

## `for to` (keyword)

**Definition**

Counts from a start value to an end value, using a counter variable. The end value is included (for `1 to 5` the counter takes 1, 2, 3, 4 and 5), except when the start and the end are equal: then the body does not run at all. Both bounds are expressions; the counter is a simple identifier assigned on each pass.

An optional `step` expression changes the increment (negative steps count down). `break` leaves the loop and `continue` starts the next iteration.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
for <identifier> = <expression> to <expression> [step <expression>] {
	...
	break
	...
	continue
	...
}
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("for to Example", overlay=false)
total = 0
for i = 1 to 5 {
    total += i
}
// Same total with an explicit step
for j = 0 to 10 step 2 {
    total += 1
}
plot(total, title="Running total", color=color.orange)
```

## `func` (keyword)

**Definition**

Declares an ordinary user function (not a type method). The parameter list may be empty, e.g. `func pi() => 3.14159`.

Use `def` when the first parameter is a typed receiver for a type function; use `func` for everything else.

A body is either a braced block or a single expression after an arrow; the arrow form may return a tuple for multiple values.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
func <function_name>(<data_type> <param_name> [= <default_value>], ...) {
	<function_body>
}
		
func <function_name>(<data_type> <param_name> [= <default_value>], ...) => <expression>
```

**Notes**

* A function body may call a drawing function such as `label.new`; it compiles. The chart-output calls listed under `if`, for example `plot`, are rejected inside a function.
* A braced body with no `return` is valid: the function returns nothing. A function that returns a value must end every path in a `return`; otherwise the compiler says "The `<name>()` function is missing return statement."

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("func Example", overlay=true)
// A braced body
func spread(float h, float l) {
    return h - l
}
// An arrow body returning two values
func bounds(int len) => [talib.highest(high, len), talib.lowest(low, len)]
[upper, lower] = bounds(20)
plot(upper, title="Upper", color=color.green)
plot(lower, title="Lower", color=color.red)
plot(lower + spread(upper, lower) / 2, title="Middle", color=color.gray)
```

## `if` (keyword)

**Definition**

Chooses which block of statements runs. Any number of `else if` arms may follow, and one `else` arm may close it; both are optional.

It is a statement, not an expression: it decides which block runs rather than producing a value. And it opens a scope of its own, which is why a chart-output call placed inside one is rejected — put the condition in an argument instead, and leave the call at the top level.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
if <condition> {
	<true_block>
} else if <condition> {
	<true_block>
} else {
	<false_block>
}
```

**Notes**

* A drawing call such as `label.new` compiles inside an `if` block. The chart-output calls `plot`, `plotshape`, `plotchar`, `plotarrow`, `plotbar`, `plotcandle`, `bgcolor`, `barcolor`, `hline`, `fill` and `alertcondition` are rejected there; `alert` is accepted.
* `switch <value> { case <value>: ... default: ... }` also chooses a block and compiles.

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("If Function Example - Moving Average Strategy", overlay=true)
// Define Moving Averages
shortMA = talib.sma(close, 10)
longMA = talib.sma(close, 50)
// Function to determine signal color
func getSignalColor() {
    if shortMA > longMA {
        return color.green
    } else {
        return color.blue
    }
}
// Plot Moving Averages
plot(shortMA, title="Short MA (10)", color=color.blue)
plot(longMA, title="Long MA (50)", color=color.orange)
bgcolor(getSignalColor())
```

## `intra` (keyword)

**Definition**

The second of the two persistence keywords the grammar accepts, and the only other one.

A value declared `intra` is kept across the repeated runs of the bar that is still forming, and is cleared when a new bar starts: the next bar starts from the initializer again. Use it to carry something across recalculations of one bar; use `static` to carry something across bars.

The difference from `static` is when a value is committed, not only how long it lives. A `static` value is stored when a bar is confirmed, so each run of a forming bar starts from the value stored when the last bar closed; an `intra` value is kept between the runs of the same bar and dropped when the next bar starts. On historical bars a bar usually runs once, so `intra` then behaves like an ordinary variable; a strategy with `calc_on_order_fills=true` runs a historical bar again after a fill, and an `intra` value carries across those runs until the bar finishes.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
intra <data_type> <variable_name> = <expression>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("intra Example", overlay=false)
// Declare a persistent variable that resets each new bar
intra int count = 0
// Increase count on each price update within the same bar
count := count + 1
// Plot the intrabar update count as a line
plot(count, title="Intrabar Execution Count", color=color.blue)
```

## `not` (keyword)

**Definition**

Negates the expression that follows it.

The third of the three logical operators with two spellings, and the only one that takes a single operand rather than two.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
!expr0 | not expr0
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("not Example", overlay=true)
aboveMA = close > talib.sma(close, 50)
// not inverts the condition
bgcolor(not aboveMA ? color.new(color.red, 0.15) : na)
```

## `or` (keyword)

**Definition**

True when either of its operands is true.

Like `and`, it has a symbol spelling that lexes to the same token.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
expr0 || expr1 | expr0 or expr1
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("or Example", overlay=true)
// Either condition is enough: a new 20-bar high or a new 20-bar low
extreme = high == talib.highest(high, 20) or low == talib.lowest(low, 20)
bgcolor(extreme ? color.new(color.orange, 0.2) : na)
```

## `return` (keyword)

**Definition**

Hands a value back from a braced function body. It takes an expression, which may be left out: a bare `return` ends a function that returns no value, and the result of such a function cannot be assigned ("Cannot assign void value.").

A tuple is written as a bracketed list, so a function can return several values at once. The arrow body form needs no `return` — the expression after the arrow is the result.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
return [<expression>]
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("Return Example", overlay=true)
func getSquare(float x) {
    // Returns the square of x
    return x * x
}
plot(getSquare(close), title="Squared Close Price", color=color.blue)
```

## `series` (keyword)

**Definition**

A qualifier written before the type of a parameter of your own function. A `series` parameter takes a value that may change from bar to bar, and any value of the other qualifiers.

A parameter written with no qualifier is `series`: `func passthru(float k) => k` returns a `series float`, which a `plot(linewidth=...)` argument refuses. The word is not allowed before a variable declaration.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
func <name>(series <data_type> <parameter_name>) => <expression>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("series Example")
func change2(series float x, series int n) => x - x[n]
plot(change2(close, bar_index % 3 + 1))
```

## `simple` (keyword)

**Definition**

A qualifier written before the type of a parameter of your own function. A `simple` parameter takes a value that is known on the first bar and stays fixed, such as `syminfo.mintick`, and any `const` or `input` value.

A value that changes from bar to bar, such as `close`, is refused with "Cannot call `<function>` with argument `<name>`=`<value>`. An argument of `series float` type was used but a `simple float` is expected." The word is not allowed before a variable declaration.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
func <name>(simple <data_type> <parameter_name>) => <expression>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("simple Example")
func ticks(series float x, simple float tickSize) => x / tickSize
plot(ticks(close, syminfo.mintick))
```

## `static` (keyword)

**Definition**

Declares a value that survives from one bar to the next. Without it, a declaration is made again on every bar, because your script is evaluated once per bar.

The initializer runs when execution first reaches the declaration and no value has been stored for it, which is ordinarily the first bar. Reassign a `static` value with `:=` and the new value carries forward, but a change is kept only when the bar is confirmed: while a bar is still forming and the script runs again on each update, every run starts from the value stored when the last bar closed, and what the earlier runs of that bar changed is discarded. Its store is never cleared while the script runs, which is what separates it from `intra`.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
static <data_type> <variable_name> = <expression>
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("static Example - First Close", overlay=true)
// Store the first close price only once
static float firstClose = close
// Plot the first close price as a horizontal line
plot(firstClose, "First Close", color=color.blue)
```

## `step` (keyword)

**Definition**

The optional increment of a counted `for` loop: `for i = 0 to 10 step 2`.

`step` is a reserved word. It cannot be used as the name of a variable.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
for <identifier> = <expression> to <expression> step <expression> {
	...
}
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("step Example")
float s = 0
for i = 0 to 10 step 2 {
    s += i
}
plot(s)
```

## `switch` (keyword)

**Definition**

Chooses one block by the value of an expression.

Each `case <value>:` starts a block, and `default:` runs when no case matches.

`switch` is a statement. It does not produce a value, so it cannot be assigned.

Do not use it inside a function body. A `switch` there passes the editor's check but is refused when the script is added to the chart, with the bare message `Not Implemented`; a function that holds a `switch` but is never called compiles. Use `if` and `else if` inside functions. A function whose `switch` returns in every `case` and in `default`, with no `return` after it, fails both checks with "The `f()` function is missing return statement.", and adding a `return` after it only brings back `Not Implemented` on the chart.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
switch <value> {
	case <value>: ...
	default: ...
}
```

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("switch Example")
int k = 2
float x = 0
switch k {
    case 1: x := 10
    case 2: x := 20
    default: x := 0
}
plot(x)
```

## `type` (keyword)

**Definition**

Declares an object type of your own: a name, then a braced block with one typed field per line. A field may carry a default value, and at least one field is required.

A field's data type may carry type arguments in angle brackets, as in `array<float> xs`.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
type <type_name> {
	<data_type> <field_name> [= <default_value>]
	...
}
```

**Notes**

* A user-defined type can be the type argument of an array: `array.new<Zone>()` compiles when `Zone` is declared with `type`.
* A `type` block with no field is rejected.
* Create an instance with `<type_name>.new(...)`, giving the arguments by position or by field name: `Zone.new(high, 0)` and `Zone.new(top=high, touches=0)` are both accepted. Calling the type name without `.new`, as in `Zone(high, low)`, is rejected.
* A field is read as `z.top` and written with `:=`, as in `z.touches := z.touches + 1`.

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("type Example", overlay=true)
// An object type with two typed fields, one with a default
type Swing {
    float price
    int barIndex = 0
}
static Swing lastHigh = Swing.new(high, bar_index)
if high > lastHigh.price {
    lastHigh := Swing.new(high, bar_index)
}
plot(lastHigh.price, title="Highest High So Far", color=color.green)
```

## `while` (keyword)

**Definition**

Repeats a block for as long as a condition holds. `break` leaves the loop and `continue` starts the next pass.

Give it an exit you control. A loop that passes the script's resource limits stops with a diagnostic rather than a partial result, and a `break` outside a loop is rejected.

**Syntax**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
while <condition> {
	...
	break
	...
	continue
	...
}
```

**Notes**

* The counted loop `for i = 0 to <n> { ... }`, with an optional `step <m>`, and the iteration loop `for x in <array> { ... }` also compile.

**Example**

```lipi theme={"languages":{"custom":["/languages/lipi.json","/languages/lipi-invalid.json"]}}
//@lipi=2
indicator("While Loop Example", overlay=true)
// Initialize a counter variable
static int count = 0
// Run while loop until count reaches 5
while count < 5 {
    count := count + 1
}
// Plot the final count
plot(count, title="Counter", color=color.blue)
```


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