Script Engine
Updated for v3 · Migration Guide
MesoSim's Script Engine allows you to express trading logic with Lua expressions that control leg selections, entries, trade adjustments and exits. Every field in the Strategy Definition is evaluated by the ScriptEngine during simulation, allowing the users to create trading strategies with minimal code.
The fields in the Strategy Definition can reference live variables (underlying, legs, position, account, timing, and external data) and they can use the provided Options Valuation and Timing modules to create sophisticated trading logic.
This page introduces the expression language, operators, variables, and a high‑level overview of Timing and Options Valuation functions.
For where expressions are used and when they are evaluated, see Expressions Quick Reference.
Language Primer: Lua
Expressions use the Lua language syntax. You don’t need full programs — just expressions that evaluate to a number (for quantities/thresholds) or boolean (for conditions).
- Comparisons:
< <= > >= == ~=(not equal) - Logical operators:
and,or,not(note:nilbehaves as false) - Use parentheses to control precedence, e.g.,
(a and b) or c - Function calls:
fn(arg1, arg2)
Lua language reference: https://www.lua.org/manual/5.4/ Learn Lua in 15 minutes: https://tylerneylon.com/a/learn-lua/
Operations
Common arithmetic and logical operators for expressions.
| Operator | Category | Description |
|---|---|---|
+ | Arithmetic | Addition |
- | Arithmetic | Subtraction |
* | Arithmetic | Multiplication |
/ | Arithmetic | Float division |
// | Arithmetic | Floor division |
% | Arithmetic | Modulo |
^ | Arithmetic | Exponentiation |
- (unary) | Arithmetic | Unary minus |
and | Logical | True if both operands are true, else false |
or | Logical | True if at least one operand is true, else false |
not | Logical | Negates input (true → false, false → true) |
Note: In logical operations, nil evaluates to false.
Built-in Functions
Use standard Lua call syntax, for example: abs(leg_short_delta).
| Signature | Description |
|---|---|
abs(x) -> number | Absolute value |
min(a, b, ...) -> number | Minimum of arguments |
max(a, b, ...) -> number | Maximum of arguments |
floor(x) -> number | Largest integer ≤ x |
ceil(x) -> number | Smallest integer ≥ x |
sqrt(x) -> number | Square root |
pow(x, y) -> number | Power function x^y (you can also use ^) |
log(x) -> number | Natural logarithm (base e) |
log10(x) -> number | Base‑10 logarithm |
exp(x) -> number | e raised to x |
random([m[, n]]) -> number | Random integer in [m, n] if bounds provided; otherwise (0,1) |
int(x) -> int | Truncate toward zero (floor for positive, ceil for negative) |
Variables
The following variables are available during a backtest and can be used anywhere the ScriptEngine evaluates expressions
(Entry, Exit, Adjustments, selectors, etc.). Where a name contains placeholders, replace them with your own names (e.g., leg_<name>_delta).
Expiration
Variables related to Expiration targets.
| Name | Description |
|---|---|
expiration_EXPNAME_dte | Days to expiration for alias EXPNAME (auto‑updated) |
expiration_EXPNAME_min | Minimum allowed days when selecting EXPNAME (constraint) |
expiration_EXPNAME_max | Maximum allowed days when selecting EXPNAME (constraint) |
Leg
Per-leg quotes, greeks, and properties for legs defined in the structure and adjustments.
| Name | Description |
|---|---|
leg_LEGNAME_price | Mark price used for liquidation semantics |
leg_LEGNAME_bid | Current bid price |
leg_LEGNAME_ask | Current ask price |
leg_LEGNAME_qty | Quantity of the leg (0 for marker legs) |
leg_LEGNAME_iv | Implied volatility (percent) |
leg_LEGNAME_delta | Leg delta (qty‑scaled; per‑1‑unit for marker legs) |
leg_LEGNAME_gamma | Leg gamma (qty‑scaled; per‑1‑unit for marker legs) |
leg_LEGNAME_theta | Leg theta (qty‑scaled; per‑1‑unit for marker legs) |
leg_LEGNAME_vega | Leg vega (qty‑scaled; per‑1‑unit for marker legs) |
leg_LEGNAME_wvega | Weighted vega using option DTE (qty‑scaled) |
leg_LEGNAME_rho | Leg rho (qty‑scaled; per‑1‑unit for marker legs) |
leg_LEGNAME_dit | Days in trade for this leg since creation (decimal days) |
leg_LEGNAME_dte | Days to expiration for this leg (decimal days) |
leg_LEGNAME_strike | Strike price for the option contract |
leg_LEGNAME_pnl | Leg PnL including realized amounts (where applicable) |
Position
Aggregated greeks, PnL, and position-level thresholds computed across all open legs; commonly used in exit conditions, and conditional adjustments .
| Name | Description |
|---|---|
profit_target | User‑defined profit target for the position |
stop_loss | User‑defined stop loss for the position |
pos_pnl | Total position PnL (open + realized) |
pos_realized_pnl | Cumulative realized PnL for the position |
pos_delta | Sum of leg deltas (qty‑scaled) |
pos_gamma | Sum of leg gammas (qty‑scaled) |
pos_theta | Sum of leg thetas (qty‑scaled) |
pos_vega | Sum of leg vegas (qty‑scaled) |
pos_wvega | Position weighted vega (DTE‑weighted) |
pos_rho | Sum of leg rhos (qty‑scaled) |
pos_margin | Estimated position margin (PM‑like model if enabled) |
open_legs_cnt | Number of currently open legs in the position |
Account
Account-level balances and counts useful for sizing, gating, and concurrency; often applied in Entry sizing (QtyMultiplier) and concurrency
| Name | Description |
|---|---|
nav | Net Asset Value of the account |
initial_cash | Initial cash configured for the backtest run |
pos_in_flight | Number of positions currently in‑flight (open or in progress) |
Underlying
Current underlying price and volatility measures available throughout the run; often used in Entry and Adjustment conditions. See also: Implied & Historical Volatility.
| Name | Description |
|---|---|
underlying_price | Current underlying price |
underlying_today_open | Today’s opening price (if available) |
underlying_prevday_close | Previous day’s close (if available) |
underlying_iv | Underlying implied volatility (percent) |
underlying_iv_rank | IV rank (0–100) at current implied volatility |
underlying_iv_pct | IV percentile (0–100) versus lookback window |
underlying_hv | Underlying historical volatility (percent) |
External Data Variables
If you specify External CSV data in the Strategy Definition, each CSV column becomes a variable available to expressions for the corresponding dates. The variable names are shown in the Job Editor under “External Data from CSV”.
For examples and setup, see FAQs Use External Data and Share External Data.
Modules
Modules provide specialized functions for common tasks. Two modules are available:
Timing
Timing functions help you count trading or calendar days relative to key anchors (weeks, months, option expirations, and other events) to build rules like “enter only in the first N trading days of the month.”
See the Timing Module documentation for details.
Available Functions:
| Signature | Description |
|---|---|
timing.trading_days_until(anchor, [boundary]) -> decimal | Trading days from now until anchor (optional boundary) |
timing.trading_days_after(anchor, [boundary]) -> decimal | Trading days after anchor up to boundary (optional) |
timing.calendar_days_until(anchor, [boundary]) -> decimal | Calendar days from now until anchor (optional boundary) |
timing.calendar_days_after(anchor, [boundary]) -> decimal | Calendar days after anchor up to boundary (optional) |
timing.trading_days_in(anchorA, [anchorB], [a_boundary], [b_boundary]) -> decimal | Trading‑day count within a window |
timing.calendar_days_in(anchorA, [anchorB], [a_boundary], [b_boundary]) -> decimal | Calendar‑day count within a window |
For timing variables, anchors/boundaries, examples, and best practices, see Timing Module
Options Valuation
Project greeks and PnL at future anchors/DTEs or scan a price range to locate minima/maxima or roots. Useful for gating entries, shaping adjustments, or early exits based on how the Risk Graph changes.
For full documentation please refer to the Options Valuation page.
Available Functions:
| Signature | Description |
|---|---|
options.model(target, dteDaysOrAnchor, underlyingPrice, metric[, model_params]) -> number | Evaluate position/leg at a time anchor or DTE using a scenario underlying price and return the selected metric |
options.model_solver(target, dteOrKey, start, end, metric, goal, result[, solver_params]) -> number | Scan a price range to minimize/maximize/zero a metric and return value or price per result |
Best Practices
- Prefer simple, readable expressions; use parentheses to make intent clear.
- Use Entry.VarDefines to capture initial values for later comparisons (e.g.,
initial_theta). - When Expression fails to evaluate: check variable names, parentheses, and types.