VOOZH about

URL: https://www.tradingview.com/script/QNGQtaZJ-ExprLib/

⇱ ExprLib — Library by A1trdX — TradingView


Editors' picksPINE LIBRARY

ExprLib

3 606
ExprLib is a library for parsing and evaluating string expressions. It allows scripts to expose configurable logic by letting users define custom conditions and calculations based on available data.


█  KEY FEATURES

• Rich expression support:
    • Built-in constants (e.g., `10`, `2.5`, `5e-2`, `true`, `false`, `na`)
    • Custom constants
    • Variables
    • Arithmetic operators: `+`, `-`, `*`, `/`, `%`
    • Comparison operators: `>`, `<`, `>=`, `<=`, `==`, `!=`
    • Logical operators: `AND`, `OR`, `NOT` (with aliases)
    • Ternary operator: `condition ? if_true : if_false`
    • Parentheses: `(`, `)`
    • Built-in functions: `na()`, `nz()`, `max()`, `pow()`, `sqrt()`, `random()`, and more!
• Graceful error handling during parsing and evaluation
• Optimized for evaluation performance (RPN-based approach)


█  NOTE

Since the library description cannot be changed or removed after publication, some information here may be outdated. However, you can always get the latest version of the documentation at the bottom of the source code.


█  QUICK START

An example of an indicator that colors areas on a chart where the expression evaluates to `true`:
//@version=6 indicator("Quick Start", overlay = true) import A1trdX/ExprLib/1 as ExprLib // --------------- // INPUTS // --------------- // Let the user customize the expression inputExpressionStr = input.text_area("trend_up AND (rsi < 50 OR close < open)", "Expression") // ------------------- // CALCULATION // ------------------- // Prepare some data to use in the expression. rsi = ta.rsi(close, 14) ema = ta.ema(close, 200) isTrendUp = close > ema isTrendDown = close < ema // Step 0: Prepare the parser and evaluator. var parser = ExprLib.createExpressionParser() var evaluator = ExprLib.createExpressionEvaluator() // Step 1: Parse the expression string. var expression = parser.parse(inputExpressionStr) // Step 2 (Recommended): Verify whether the expression was parsed without errors. if not parser.isParsed // You can define your own logic to handle errors runtime.error("Failed to parse expression: " + parser.error.message) // Step 3: Assign values to variables. Both numbers and booleans are supported. expression.setVariable("open", open) expression.setVariable("close", close) expression.setVariable("rsi", rsi) expression.setVariable("trend_up", isTrendUp) expression.setVariable("trend_down", isTrendDown) // Step 4: Evaluate the expression. bool result = evaluator.evaluateToBool(expression) // Step 4 (Alternative): If you expect a numeric result, use `evaluate()` instead. // float result = evaluator.evaluate(expression) // Step 5 (Recommended): Verify whether the expression was evaluated without errors. if not evaluator.isEvaluated // You can define your own logic to handle errors runtime.error("Failed to evaluate expression: " + evaluator.error.message) // ---------------- // GRAPHICS // ---------------- // Highlight bars where the expression returns `true` bgcolor(result ? color.new(color.green, 90) : na)


█  EXPRESSION SYNTAX REFERENCE

❱❱  Components

An expression can include:
• Constants
• Variables
• Operators
• Functions
• Parentheses
• Spaces, tabs, or newlines


❱❱  Data Types

Constants and variables can have the following data types:
• Numeric (`int`, `float`)
• Boolean (`bool`)
• Undefined (`na`)


❱❱  Identifiers

Identifiers are names used to refer to named constants, variables, and functions.

Identifier naming rules:
• Must start with a letter (`a-z`, `A-Z`) or underscore (`_`).
• May contain letters (`a-z`, `A-Z`), digits (`0-9`), and underscores (`_`).

Identifiers cannot contain spaces or other characters.

Identifiers are case-sensitive.


❱❱  Constants

Numeric Constants

Examples:
+-----------+--------------+ | Constant | Plain Value | +-----------+--------------+ | 12 | 12.00 | | 0.05 | 0.05 | | .05 | 0.05 | | 5e-2 | 0.05 | | 5E-2 | 0.05 | | 1.2e4 | 12000.00 | +-----------+--------------+

Named Constants

Available built-in named constants:
+----------+-------------------------------------+-------------------------+ | Name | Description | Pine Script Equivalent | +----------+-------------------------------------+-------------------------+ | `true` | Boolean TRUE | `true` | | `false` | Boolean FALSE | `false` | | `na` | Undefined value | `na` | | `pi` | Pi (~3.14159) | `math.pi` | | `e` | Euler's number (~2.71828) | `math.e` | | `phi` | Golden ratio (~1.61803) | `math.phi` | | `rphi` | Golden ratio conjugate (~0.61803) | `math.rphi` | +----------+-------------------------------------+-------------------------+

It is possible to add custom constants.


❱❱  Variables

It is possible to add variables, just like custom constants, except that variable values can be changed before each evaluation.


❱❱  Operators

The following operators are supported:
+--------------+-------------+-------------------------+-------------+------------------+-------------+ | Type | Operator | Name | Aliases | Example #1 | Example #2 | +--------------+-------------+-------------------------+-------------+------------------+-------------+ | Arithmetic | `+` | Add | | `a + b` | | | Arithmetic | `-` | Subtract | | `a - b` | | | Arithmetic | `*` | Multiply | | `a * b` | | | Arithmetic | `/` | Divide | | `a / b` | | | Arithmetic | `%` | Modulo | | `a % b` | | | Comparison | `>` | Greater than | | `a > b` | | | Comparison | `<` | Less than | | `a < b` | | | Comparison | `>=` | Greater than or equal | | `a >= b` | | | Comparison | `<=` | Less than or equal | | `a <= b` | | | Comparison | `==` | Equal | | `a == b` | | | Comparison | `!=` | Not equal | | `a != b` | | | Logical | `AND` | Logical AND | `&&`, `&` | `a AND b` | `a && b` | | Logical | `OR` | Logical OR | `||`, `|` | `a OR b` | `a || b` | | Logical | `NOT` | Logical NOT | `!` | `NOT x` | `!x` | | Conditional | `?:` | Ternary | | `cond ? x : y` | | | Unary | Unary `+` | Unary plus | | `+x` | | | Unary | Unary `-` | Unary minus | | `-x` | | +--------------+-------------+-------------------------+-------------+------------------+-------------+

Logical operator names are case-insensitive.

Operator precedence:
+------------+-----------------------------+ | Precedence | Operators | +------------+-----------------------------+ | 8 | Unary `-`, Unary `+`, `NOT` | | 7 | `*`, `/`, `%` | | 6 | `+`, `-` | | 5 | `>`, `<`, `>=`, `<=` | | 4 | `==`, `!=` | | 3 | `AND` | | 2 | `OR` | | 1 | `?:` | +------------+-----------------------------+

Operator associativity:
• Unary `+`, Unary `-`, `NOT`, and ternary are right-associative
• Other operators are left-associative


❱❱  Parentheses

Parentheses are used to group sub-expressions and override the default operator precedence.

Example:
((a + b) * c + 1) * d


❱❱  Functions

Functions are called by an identifier followed immediately by parentheses: `func(arg1, arg2)`.

Arguments are separated by commas. Each argument can be any valid expression, including another function call.

Available built-in functions:
+-------------------------------+----------+------------------------------------------------------------------------+ | Function | Args | Description | +-------------------------------+----------+------------------------------------------------------------------------+ | `na(x)` | 1 | Returns `true` when `x` is `na`, `false` otherwise. | | `nz(x, fallback)` | 2 | Returns `x` when it is not `na`, `fallback` otherwise. | | `max(x1, x2, ...)` | 2..999 | Returns the largest argument. | | `min(x1, x2, ...)` | 2..999 | Returns the smallest argument. | | `pow(base, exponent)` | 2 | Returns `base` raised to `exponent`. | | `sqrt(x)` | 1 | Returns the square root of `x`. | | `clamp(x, min, max)` | 3 | Restricts `x` to the `[min, max]` range. | | `abs(x)` | 1 | Returns the absolute value of `x`. | | `ceil(x)` | 1 | Rounds `x` up to the nearest integer. | | `floor(x)` | 1 | Rounds `x` down to the nearest integer. | | `round(x)` | 1 | Rounds `x` to the nearest integer. | | `round_to_mintick(x)` | 1 | Rounds `x` to the symbol's minimum tick precision. | | `log(x)` | 1 | Returns the natural logarithm of `x`. | | `log10(x)` | 1 | Returns the base-10 logarithm of `x`. | | `sign(x)` | 1 | Returns the sign of `x`: `1`, `0`, or `-1`. | | `cos(x)` | 1 | Returns the cosine of `x` in radians. | | `sin(x)` | 1 | Returns the sine of `x` in radians. | | `tan(x)` | 1 | Returns the tangent of `x` in radians. | | `acos(x)` | 1 | Returns the arccosine of `x` in radians. | | `asin(x)` | 1 | Returns the arcsine of `x` in radians. | | `atan(x)` | 1 | Returns the arctangent of `x` in radians. | | `deg(x)` | 1 | Converts radians to degrees. | | `rad(x)` | 1 | Converts degrees to radians. | | `random(min, max, seed)` | 0..3 | Returns a random float. Bounds default to 0 and 1. Seed is optional. | | `random_int(min, max, seed)` | 2..3 | Returns a random integer. Seed is optional. | | `random_bool(seed)` | 0..1 | Returns a random boolean value. Seed is optional. | +-------------------------------+----------+------------------------------------------------------------------------+

The number of arguments can be either fixed or variable.

For example, the `max(x1, x2, ...)` function supports 2 to 999 arguments, so the following calls to this function are valid:
max(x1, x2) max(x1, x2, x3) max(x1, x2, x3, x4, x5)

Other functions may have optional arguments. For example, the following calls to the `random(min, max, seed)` function are valid:
random() // Random float from 0 to 1 random(0.5) // Random float from 0.5 to 1 random(0.5, 2) // Random float from 0.5 to 2 random(0.5, 2, 777) // Random float from 0.5 to 2 with a specific seed


❱❱  Whitespace

Spaces, tabs, and line breaks are ignored between symbols. For example, an expression can be formatted across multiple lines:
price > ema_slow AND ema_fast > ema_slow AND (bb_lo_up OR rsi_lo_up)


█  PARSING

❱❱  Workflow

Before evaluating an expression, it must be parsed. To do this:
• Create a parser in advance using the `createExpressionParser()` function.
• Call the `parse()` method, passing the expression string as an argument.

Example:
var parser = ExprLib.createExpressionParser() var expr1 = parser.parse("a + 2") var expr2 = parser.parse("a + b * c")


❱❱  Error Handling

A user may enter an invalid expression. In this case, the parser will return `na` instead of a valid expression object. The parser stores the result of the last parse. You can use that result to retrieve the status and error information.

Parser and error field structures:
type ExpressionParser bool isParsed // `true` if the last parse completed successfully, `false` otherwise. ParseError error // Error from the last parse attempt. If the last parse was successful, then this field is `na`. type ParseError string message // Error message. int index // Character index where the parser detected the error.

For example, suppose we want to display an error message on the chart if one of the expressions is invalid:
//@version=6 indicator("Parser Error Handling") import A1trdX/ExprLib/1 as ExprLib inputExpr1 = input.text_area("a + 2", "Expression 1") inputExpr2 = input.text_area("a + b * c /", "Expression 2") displayErrorMessage(string errorMessage) => var table errorMessageTable = na if na(errorMessageTable) errorMessageTable := table.new(position.top_right, 1, 1) errorMessageTable.cell(0, 0, errorMessage, bgcolor = color.red, text_color = color.white, text_halign = text.align_left, text_formatting = text.format_bold) checkParsed(ExprLib.ExpressionParser parser, string prefix) => if not parser.isParsed displayErrorMessage(prefix + parser.error.message) var parser = ExprLib.createExpressionParser() var expr1 = parser.parse(inputExpr1) checkParsed(parser, "Failed to parse expression #1:\n") var expr2 = parser.parse(inputExpr2) checkParsed(parser, "Failed to parse expression #2:\n")

A blank expression (e.g., "") is allowed and will evaluate to `na` (or `false` when returning a boolean value).


❱❱  Custom Constants

You can add your own named constants during the parsing stage. To do this:
• Create a constant pool in advance using the `createConstantPool()` function.
• Set constants and their values using the `set()` method.
• Pass the constant pool to the `parse()` method.

Example:
var constantPool = ExprLib.createConstantPool() if barstate.isfirst constantPool.set("one", 1) constantPool.set("two", 2) constantPool.set("three_p_one", 3.1) constantPool.set("yes", true) constantPool.set("no", false) var parser = ExprLib.createExpressionParser() var expr = parser.parse("one + two", constantPool)

The `set()` method returns the same constant pool object, so you can chain calls together. This is more convenient and more elegant:
var constantPool = ExprLib.createConstantPool() .set("one", 1) .set("two", 2) .set("three_p_one", 3.1) .set("yes", true) .set("no", false) // Note that the indentation is 7 spaces (not a multiple of 4) var parser = ExprLib.createExpressionParser() var expr = parser.parse("one + two", constantPool)

You can also override built-in constants:
var constantPool = ExprLib.createConstantPool() .set("true", false) .set("false", -1) .set("na", 0.0)


█  EVALUATION

❱❱  Type Coercion

An expression can consist of values of different data types. ExprLib does not have strict data type checking. Instead, all values are converted to `float` and then back if necessary.

Converting `bool` to `float`:
• `true` -> `1.0`
• `false` -> `0.0`

Converting `float` to `bool`:
• `0.0` or `na` -> `false`
• Any other value -> `true`

Thus, expressions that incorrectly combine different data types are allowed. For example, `true + 2` will return `3.0`. Strict typing requires additional memory as well as additional computational resources during evaluation, which is a critical concern. Therefore, it was decided not to implement it.

As in Pine Script, most operations with an `na` operand results in `na` or `false`, but logical operations first convert `na` to `false`, so their result follows boolean logic. For example:
• `3 - na` returns `na`
• `3 > na` returns `false`
• `3 <= na` also returns `false`
• `na AND true` returns `false`
• `na OR true` returns `true`
• `NOT na` returns `true`


❱❱  Workflow

To evaluate an expression:
• Create an evaluator in advance using the `createExpressionEvaluator()` function.
• Set variables and their values in the expression using the `setVariable()` method.
• Call the `evaluate()` or `evaluateToBool()` method, passing the expression as an argument.

The `evaluate()` and `evaluateToBool()` methods differ in their return types. The former returns a `float` result, while the latter returns a `bool` result. The method to call depends on the expected result type.

Example:
// Parsed expressions: // - expr1 <= "(H - L) / 2 + L" // - expr2 <= "rsi_oversold AND close > open" // Initialize evaluator var evaluator = ExprLib.createExpressionEvaluator() // Set variables and evaluate the first expression expr1.setVariable("H", high) expr1.setVariable("L", low) float result1 = evaluator.evaluate(expr1) // Set variables and evaluate the second expression rsi = ta.rsi(close, 14) expr2.setVariable("open", open) expr2.setVariable("close", close) expr2.setVariable("rsi_oversold", rsi < 30) expr2.setVariable("rsi_overbought", rsi > 70) bool result2 = evaluator.evaluateToBool(expr2)


❱❱  Variables

If an expression contains an identifier that is neither a function nor a constant, and this identifier has not been assigned a variable value, then this identifier is considered a constant with the value `na` (or `false` in boolean operations).

The `setVariable()` method overrides existing constants (both built-in and custom). For example, by default, the identifier `e` is used as the constant Euler's number (~2.71828). However, you can make `e` your own variable:
// Parsed expressions: // - expr <= "e + 1" expr.setVariable("e", 5) // Now `e` is equal to `5` instead of `2.7182818284590452` result = evaluator.evaluate(expr) // `6.0`

The `setVariable()` method does not need to be called on each bar if the variable's value does not change. The expression always stores and uses the last value set.

You can clear all previously set variables using the `clearVariables()` method. This can be useful if you have many variables and want to reset them all and set values for only a small subset.


❱❱  Error Handling

In some cases (for example, when dividing by zero), evaluation results in an error. In this case, `evaluate()` will return `na`, and `evaluateToBool()` will return `false`. Like the parser, the evaluator stores the result of the last evaluation.

Evaluator and error field structures:
type ExpressionEvaluator bool isEvaluated // `true` if the last evaluation completed successfully, `false` otherwise. EvaluationError error // Error from the last evaluation attempt. If the last evaluation was successful, then this field is `na`. type EvaluationError EvaluationErrorReason reason // Error reason. string message // Error message. enum EvaluationErrorReason DIVISION_BY_ZERO

Example:
//@version=6 indicator("Evaluator Error Handling") import A1trdX/ExprLib/1 as ExprLib inputExpr1 = input.text_area("a + 2", "Expression 1") inputExpr2 = input.text_area("a + b / c", "Expression 2") displayErrorMessage(string errorMessage) => var table errorMessageTable = na if na(errorMessageTable) errorMessageTable := table.new(position.top_right, 1, 1) errorMessageTable.cell(0, 0, errorMessage, bgcolor = color.red, text_color = color.white, text_halign = text.align_left, text_formatting = text.format_bold) // Parse checkParsed(ExprLib.ExpressionParser parser, string prefix) => if not parser.isParsed displayErrorMessage(prefix + parser.error.message) var parser = ExprLib.createExpressionParser() var expr1 = parser.parse(inputExpr1) checkParsed(parser, "Failed to parse expression #1:\n") var expr2 = parser.parse(inputExpr2) checkParsed(parser, "Failed to parse expression #2:\n") // Evaluate checkEvaluated(ExprLib.ExpressionEvaluator evaluator, string prefix) => if not evaluator.isEvaluated displayErrorMessage(prefix + evaluator.error.message) var evaluator = ExprLib.createExpressionEvaluator() expr1.setVariable("a", open) expr1.setVariable("b", close) expr1.setVariable("c", 0) result1 = evaluator.evaluate(expr1) checkEvaluated(evaluator, "Failed to evaluate expression #1:\n") expr2.setVariable("a", open) expr2.setVariable("b", close) expr2.setVariable("c", 0) result2 = evaluator.evaluate(expr2) checkEvaluated(evaluator, "Failed to evaluate expression #2:\n")

Currently, the only possible cause of this error is division by zero. You can disable this error and have the evaluator interpret the result of division by zero as `na`. To do this, disable the corresponding flag in the evaluator:
evaluator.setFailOnDivisionByZero(false)

Thus, an expression like `na(5 / 0) ? 1 : 2` will return `1` instead of an error.


█  BEST PRACTICES

• Reuse `ExpressionParser` and `ExpressionEvaluator` objects whenever possible.
• Parse expressions only once, and evaluate them as needed. Parsing is slow. Evaluation is fast.
• If certain variable values change rarely, call `setVariable()` only when necessary.
• Try to avoid excessive numbers of variables whose values ​​change frequently. This can impact performance even if they're not used in the expression.


█  API REFERENCE

❱❱  Expression Parser

ExpressionParser
  Expression parser.
  Fields:
isParsed (series bool): `true` if the last parse completed successfully, `false` otherwise.
error (ParseError): Error from the last parse attempt. If the last parse was successful, then this field is `na`.

createExpressionParser()
  Creates an expression parser.
  Returns: Expression parser.

method parse(parser, exprStr, constantPool)
  Parses an expression.
  Namespace types: ExpressionParser
  Parameters:
parser (ExpressionParser): Expression parser.
exprStr (string): Expression string. Can be empty, blank, or 'na'. That way expression is valid and will return `na` on evaluation.
constantPool (ExpressionConstantPool): (Optional) Named constants.
  Returns: Parsed expression. If an error occurs during parsing, then the returned expression will be `na`.
You can check validity and error details accessing parser's `isParsed` and `error` fields.


❱❱  Expression

Expression
  Parsed expression.

method setVariable(expr, identifier, value)
  Assigns a numeric value to a variable.
  Namespace types: Expression
  Parameters:
expr (Expression): Expression.
identifier (string): Variable name.
value (float): Value.
  Returns: This expression.

method setVariable(expr, identifier, value)
  Assigns a boolean value to a variable.
  Namespace types: Expression
  Parameters:
expr (Expression): Expression.
identifier (string): Variable name.
value (bool): Value.
  Returns: This expression.

method clearVariables(expr)
  Clears all variable values.
  Namespace types: Expression
  Parameters:
expr (Expression): Expression.
  Returns: This expression.


❱❱  Constant Pool

ExpressionConstantPool
  Expression constant pool.

createConstantPool()
  Creates an expression constant pool.
  Returns: Expression constant pool.

method set(pool, identifier, value)
  Assigns a numeric constant value.
  Namespace types: ExpressionConstantPool
  Parameters:
pool (ExpressionConstantPool): Expression constant pool.
identifier (string): Constant name.
value (float): Value.
  Returns: This expression constant pool.

method set(pool, identifier, value)
  Assigns a boolean constant value.
  Namespace types: ExpressionConstantPool
  Parameters:
pool (ExpressionConstantPool): Expression constant pool.
identifier (string): Constant name.
value (bool): Value.
  Returns: This expression constant pool.

method clear(pool)
  Clears all constants.
  Namespace types: ExpressionConstantPool
  Parameters:
pool (ExpressionConstantPool): Expression constant pool.
  Returns: This expression constant pool.


❱❱  Expression Evaluator

ExpressionEvaluator
  Expression evaluator.
  Fields:
isEvaluated (series bool): `true` if the last evaluation completed successfully, `false` otherwise.
error (EvaluationError): Error from the last evaluation attempt. If the last evaluation was successful, then this field is `na`.
result (series float): Numeric result of the last evaluation.
boolResult (series bool): Boolean result of the last evaluation.

createExpressionEvaluator()
  Creates an expression evaluator.
  Returns: Expression evaluator.

method evaluate(evaluator, expr)
  Evaluates an expression.
  Namespace types: ExpressionEvaluator
  Parameters:
evaluator (ExpressionEvaluator): Expression evaluator.
expr (Expression): Expression to evaluate.
  Returns: Numeric evaluation result.
For boolean-result expressions `1.0` means `true` and `0.0` means `false`.
Returns `na` if expression is empty.

method evaluateToBool(evaluator, expr)
  Evaluates an expression.
  Namespace types: ExpressionEvaluator
  Parameters:
evaluator (ExpressionEvaluator): Expression evaluator.
expr (Expression): Expression to evaluate.
  Returns: Boolean evaluation result.
Returns `false` if expression is empty.

method setFailOnDivisionByZero(evaluator, value)
  Sets whether division or modulo by zero should fail evaluation.
  Namespace types: ExpressionEvaluator
  Parameters:
evaluator (ExpressionEvaluator): Expression evaluator.
value (bool): If `true`, division or modulo by zero fails evaluation. If `false`, it produces `na`.
  Returns: This expression evaluator.


❱❱  Errors

ParseError
  Error that occurred during expression parsing.
  Fields:
message (series string): Error message.
index (series int): Character index where the parser detected the error.

EvaluationError
  Error that occurred during expression evaluation.
  Fields:
reason (series EvaluationErrorReason): Error reason.
message (series string): Error message.

Pine library

In true TradingView spirit, the author has published this Pine code as an open-source library so that other Pine programmers from our community can reuse it. Cheers to the author! You may use this library privately or in other open-source publications, but reuse of this code in publications is governed by House Rules.


expressionMATHparserstringstringstokenizer

Disclaimer

The information and publications are not meant to be, and do not constitute, financial, investment, trading, or other types of advice or recommendations supplied or endorsed by TradingView. Read more in the Terms of Use.
expressionMATHparserstringstringstokenizer

Pine library

In true TradingView spirit, the author has published this Pine code as an open-source library so that other Pine programmers from our community can reuse it. Cheers to the author! You may use this library privately or in other open-source publications, but reuse of this code in publications is governed by House Rules.

Disclaimer

The information and publications are not meant to be, and do not constitute, financial, investment, trading, or other types of advice or recommendations supplied or endorsed by TradingView. Read more in the Terms of Use.