Expressions and Functions

Expressions contain only two data types: double-precision real numbers and strings. Even if a block exposes an integer value (for example the length of an RSI), that value is treated as a real variable when used in an expression. Results of comparisons and logical operations are also reals equal to 0 or 1. Missing values are represented as NaN. When an expression is used as a boolean guard in [[condition]] or [[if]], 0.0 and NaN are treated as false. Any other non-zero value is treated as true.

Where should you enter expressions?

Expressions can be entered in several parts of a TOML strategy. General rule: an expression field accepts either an unquoted number (TOML integer or floating-point) or a string (TOML string). Exception: in [[objective]], formula must be written as a TOML string.

In custom series calculations

Custom series use a formula to compute a new series from available price series, indicator outputs, and the variables they expose. These variables include for example fast.length, fast.type, fast.symbol, and fast.timeframe. The formula is compiled at load time, then evaluated while the series is being computed. In [[custom_series]], only symbols available at indicator stage can be used. Runtime backtest, portfolio, order, and trade variables are not available there.

[[custom_series]]
id      = "mad"
formula = "fast / slow"

In combination filtering

Combination filtering uses a condition expression to remove hyperparameter combinations that do not match your criteria. This expression is evaluated for each combination before that backtest run starts.

[constraints]
condition = "fast.length < slow.length and fast.type = slow.type"

In objective definitions

The objective uses a formula to turn result metrics into a score. The formula is compiled before execution and evaluated after each backtest. In this block, formula is always read as a TOML string.

[[objective]]
id        = "risk_adjusted_return"
formula   = "(grossprofit_percent - grossloss_percent) / max_drawdown_percent"
ascending = false

In conditional blocks

Conditional blocks use expressions to decide which execution path to follow. Depending on the block type, an expression is evaluated either when the block executes or on candle updates to maintain cross-candle state.

[[condition]]
id            = "entry_filter"
condition     = "fast > slow and fast[1] <= slow[1]"
next_block_id = "enter_long"

In variable calculations

The [[variable]] block uses two expressions: an initialization and an update formula. initialization is evaluated once at backtest startup, then formula is evaluated each time the block is visited.

[[variable]]
id             = "variable_trend_streak"
variable       = "trend_streak"
initialization = 0
formula        = "close > ema_200 ? trend_streak + 1 : 0"
next_block_id  = "check_entry"

Order blocks can use expressions for quantity and price values. These values are evaluated when the order block is triggered, right before order submission or order synchronization.

[[entry]]
id            = "enter_long"
order_id      = "main"
qty_percent   = 50
limit         = "close * 0.995"
stop          = "close * 1.005"
next_block_id = "watch_exit"

Precision and rounding

All expressions are evaluated as double-precision reals. Market constraints (price tick, quantity tick, minimum size) are not applied during expression evaluation; they are applied during order execution.

Constants

The following math constants are available. Their names are reserved and cannot be used as variable identifiers.

ConstantDescription
eulerBase of natural logarithms
piPi constant
phiGolden ratio
rphiInverse golden ratio

Series and fields

Expressions can use the standard price series open, high, low, close, volume, hl2, hlc3, ohlc4, and hlcc4. Indicator blocks expose their series as variables, whose names match the block identifier (or distinct identifiers if the block produces multiple outputs).

To access a series’ history, add an index in brackets: series[n] refers to the value n bars in the past (0 is the current bar, 1 the previous bar, etc.). Direct access, for example close, is equivalent to close[0]. If the index exceeds the available history, the returned value is NaN. In [[condition]] and [[if]], such a value does not validate the condition until the required history is available.

Example: detect a bullish crossover of a fast moving average above a slow one (the fast MA moves from below to above between the previous and current bars):

[[condition]]
condition = "ema_fast > ema_slow and ema_fast[1] <= ema_slow[1]"

Strings

Some variables expose strings, for example ticker and tickerid or block metadata. Strings can be compared with == or != and concatenated with +.

String literals use single quotes.

[[condition]]
condition = "tickerid == 'BINANCE:BTCUSDT'"

You can extract a substring with s[start:stop]. The form s[] returns the length.

Operators

Expressions support the following operators. Examples use real values and return real values (comparisons and logic return 0 or 1).

Arithmetic

SymbolName
+Addition
-Subtraction
*Multiplication
/Division
%Modulo
^Power

Comparisons (return 0.0 or 1.0)

SymbolName
<Less than
<=Less or equal
>Greater than
>=Greater or equal
==Equal
!=Not equal

The operators = and <> are accepted as aliases for == and !=.

Logical (return 0.0 or 1.0)

Logical operators treat any non-zero value as true and zero as false. They return 1.0 for true and 0.0 for false.

SymbolName
andAND
orOR
notNOT
nandNAND
norNOR
xorXOR
xnorXNOR

Example usage:

Suppose we want an entry condition that is true only if the RSI is below 30 and the closing price is above the ema_200 moving average.

[[condition]]
id        = "entry_condition"
condition = "rsi_value < 30 and close > ema_200"

The condition expression will evaluate to 1.0 (true) only if both comparisons are true. If either is false, the result will be 0.0 (false).

Ternary

SymbolName
cond ? a : bTernary

Unary

SymbolName
+xUnary plus
-xUnary minus
not xLogical negation

Update semantics in variable blocks

In a variable block, the variable is declared by the variable key. Then initialization and formula must be provided as single expressions, and the engine applies the variable update internally.

To keep PineScript export unambiguous, initialization and formula must not contain statement separators (;) or assignment operators (:=, +=, -=, *=, /=, %=).

Available functions

Missing-value handling

NameDescription
na(x)1 if x is missing, else 0
nz(x)0 if x is missing, else x
bool(x)1 if x is defined and non-zero, else 0

Basic math

NameDescription
abs(x)Absolute value
ceil(x)Ceiling
floor(x)Floor
exp(x)Exponential
log(x)Natural logarithm
log10(x)Base-10 logarithm
pow(a,b)Power
round(x)Round to nearest
sqrt(x)Square root
sign(x)Sign of x (-1, 0, 1)
min(...)Minimum (at least 2 values)
max(...)Maximum (at least 2 values)
avg(...)Average (at least 2 values)
clamp(min, x, max)Clamp x to [min, max]
inrange(min, x, max)1 if x is inside the range, else 0
random(...)Uniform random number in a range

Accepted forms: random(), random(min), random(min, max), and random(min, max, seed). Without seed, the generator is initialized at runtime, so two separate backtests may produce different values.

Trigonometry and angles

NameDescription
sin(x)Sine
cos(x)Cosine
tan(x)Tangent
asin(x)Arc-sine
acos(x)Arc-cosine
atan(x)Arc-tangent
atan2(y,x)Arc-tangent with quadrants
sinh(x)Hyperbolic sine
cosh(x)Hyperbolic cosine
tanh(x)Hyperbolic tangent
asinh(x)Inverse hyperbolic sine
acosh(x)Inverse hyperbolic cosine
atanh(x)Inverse hyperbolic tangent
todegrees(x)Convert radians to degrees
toradians(x)Convert degrees to radians