Script Engine
MesoSim uses Lua expressions to select contracts, filter trades, size positions, and define adjustment and exit rules. Expressions return a number for quantities and thresholds, or a boolean for conditions.
This page covers the language and the values available to expressions. The Strategy Definition Reference explains which fields accept expressions and when they run. Names, dates, and enum settings remain literal values.
Write and validate expressions in the AI Job Editor, or work with AI Agents. For full strategies with analysis, visit the Deltaray blog.
Write an expression
Enter the expression directly in the relevant Strategy Definition field. For example:
| Field | Expression | Purpose |
|---|---|---|
Entry.Conditions[] | underlying_price < underlying_today_open | Allow an entry on a down day |
Entry.AbortConditions[] | pos_theta < 20 | Reject a selected structure with insufficient Theta |
Entry.VarDefines.initial_theta | pos_theta | Capture Theta at entry |
Exit.Conditions[] | pos_theta < initial_theta * 0.25 | Exit when Theta falls below 25% of the captured value |
The exit example assumes initial_theta was defined at entry as shown. Use the exact field and variable names, including capitalization. See Filter entries by Implied Volatility and Set quantities dynamically for more examples.
- Comparisons use
<,<=,>,>=,==, and~=(not equal). - Combine requirements with
and, alternatives withor, and negate a condition withnot. - Use parentheses to make grouping explicit, such as
(a or b) and c. - Call functions with parentheses, such as
abs(pos_delta).
Separate items in Entry.Conditions are OR alternatives. To require several criteria at once, combine them with and in one expression. See Entry conditions.
For language syntax, see the official Lua reference. MesoSim exposes the functions and modules described below.
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 | Returns the first operand if it is false or nil; otherwise returns the second |
or | Logical | Returns the first operand unless it is false or nil; otherwise returns the second |
not | Logical | Negates input (true → false, false → true) |
In Lua logical expressions, only nil and false are false; even 0 is truthy. MesoSim converts a final numeric condition result of zero to false. Use explicit comparisons such as my_signal == 1 when combining numeric signals with and or or.
Built-in Functions
Call these functions directly, for example abs(pos_delta) or min(leg_short_put_delta, 10). Replace short_put with a leg name in your strategy.
| 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 |
log(x[, base]) -> number | Natural logarithm by default; specify a base for another logarithm |
exp(x) -> number | e raised to x |
random() -> number | Random number from 0 inclusive to 1 exclusive |
random(n) -> integer | Random integer from 1 through positive integer n |
random(m, n) -> integer | Random integer from m through n, including both bounds |
int(x) -> integer | Truncate toward zero: int(2.8) is 2 and int(-2.8) is −2 |
The constant pi is also available. Use ^ for powers, such as 2 ^ 3. For a base-10 logarithm, log(100, 10) returns 2. See Add randomness to entries for a trading example using random().
Variables
Variable availability depends on the expression field and execution stage. Where a name contains placeholders, replace them with your own names (e.g., leg_<name>_delta).
Variable availability
| Expression stage | Available values |
|---|---|
Before selection: Entry.Conditions, ReentryDays, and Concurrency | Account, underlying, calendar/session timing, and loaded external-data values; selected legs, expirations, and position Greeks are not available yet |
| Expiration and leg selection | Values introduced by earlier selections, in definition order |
| Sizing and entry checks | Selected-leg and position values; Entry.QtyMultiplier runs before Entry.VarDefines, then abort conditions can use the defined variables |
| Adjustment and exit | Current position values and custom variables that have already been defined |
Entry.VarDefines evaluates definitions in order before abort checks and again after entry fills. Entry.QtyMultiplier is evaluated again when an adjustment adds legs. See QtyMultiplier and Variable update timing for the detailed sequence.
Variables introduced by a conditional adjustment are available only after that adjustment runs. For example, if an adjustment defines adjusted_delta, an exit condition can check it safely with:
adjusted_delta ~= nil and abs(adjusted_delta) > 10
Choose custom names such as initial_delta and initial_theta; avoid simulator variables, module names, and reserved keywords. Use Entry.VarDefines to capture values needed later, and Events export for guidance on recording them for analysis.
Settings expressions have their own context. For example, order-based slippage uses order.leg_spread, rather than general strategy variables.
Expiration
Variables related to expiration selection. Replace EXPNAME with the expiration alias, such as front.
| Name | Description |
|---|---|
expiration_EXPNAME_dte | Days to expiration for alias EXPNAME (auto‑updated) |
expiration_EXPNAME_min | Minimum DTE constraint for EXPNAME; available only during selection |
expiration_EXPNAME_max | Maximum DTE constraint for EXPNAME; available only during selection |
Leg
Quotes, Greeks, and properties for legs defined in the structure and adjustments. Replace LEGNAME with the leg name, such as short_put.
| Name | Description |
|---|---|
leg_LEGNAME_price | Current price used to value closing the leg, according to the fill model |
leg_LEGNAME_bid | Current bid price |
leg_LEGNAME_ask | Current ask price |
leg_LEGNAME_qty | Signed quantity: negative for short legs, positive for long legs, 0 for marker legs |
leg_LEGNAME_count | Number of legs represented by this name in the current evaluation context |
leg_LEGNAME_iv | Implied Volatility in percent; 20 means 20% |
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 | DTE-weighted vega (quantity-scaled; per contract for marker legs) |
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 | PnL for the current leg |
Leg Greeks include quantity and direction. Marker Legs expose per-contract Greeks despite having zero quantity; they contribute zero to position Greeks. If one name represents multiple legs, quantity and Greeks are aggregated, while single-contract values such as price and strike are unavailable.
Position
Position Greeks, PnL, and exit thresholds are commonly used in exit conditions and conditional adjustments.
| Name | Description |
|---|---|
profit_target | Profit target initialized at entry, when configured |
stop_loss | Stop loss initialized at entry, when configured |
max_days_in_trade | Maximum days-in-trade threshold initialized at entry, when configured |
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 using the configured Reg-T or PM-like model, when 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 currently open positions |
Underlying
Current underlying price and volatility measures available throughout the run; often used in Entry and Adjustment conditions. See also: Implied and Historical Volatility.
| Name | Description |
|---|---|
underlying_price | Current underlying price |
underlying_today_open | Session-opening reference price from the selected market-data resolution (if available) |
underlying_prevday_close | Previous trading day’s closing price (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
Load a CSV through ExternalData.CsvUrl to use its numeric columns as named variables. Each value becomes available according to the CSV timestamp. See Use External Data for preparation, publishing, and availability rules.
The AI Job Editor lists the loaded variables under External Data. To explore how a captured entry variable relates to final position PnL, see Analytics with DataVoyager.
Modules
The Timing and Options Valuation modules provide calendar calculations and scenario analysis. The Slippage settings describe the separate order context.
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.”
Read current timing values as properties: timing.day_of_week, timing.year, timing.month, timing.day, timing.minutes_after_open, timing.minutes_before_close, and timing.days_in_trade. For example, an exit condition can use:
timing.days_in_trade >= 5
timing.days_in_trade requires an open position and can be fractional. Property access has no parentheses; calendar calculations below are function calls. See Timing for anchors and boundaries.
Available Functions:
| Signature | Description |
|---|---|
timing.trading_days_until(anchor, [boundary]) -> decimal | Trading days from now until the selected anchor boundary |
timing.trading_days_after(anchor, [boundary]) -> decimal | Trading days elapsed since the selected anchor boundary, including fractional sessions |
timing.calendar_days_until(anchor, [boundary]) -> decimal | Calendar days from now until the selected anchor boundary |
timing.calendar_days_after(anchor, [boundary]) -> decimal | Calendar days elapsed since the selected anchor boundary, including fractional days |
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 period anchors, boundary defaults to first. Both *_days_after functions return 0 until the selected boundary is reached; both *_days_until functions return 0 once it is reached.
For example, timing.trading_days_until(monthly_opex) counts trading days until the monthly options expiration. See Timing for more examples.
Options Valuation
Project Greeks and PnL at a time anchor or a number of days from now, or scan an underlying-price range to find a target value or an extremum. Useful for gating entries, shaping adjustments, or early exits based on how the Risk Graph changes.
See Options Valuation Model for parameter definitions, supported metrics, and examples.
Available Functions:
| Signature | Description |
|---|---|
options.model(target, dteDaysOrAnchor, underlyingPrice, metric[, model_params]) -> number or nil | Evaluate position/leg at a time anchor or a number of days from now using a scenario underlying price and return the selected metric |
options.model_solver(target, dteOrKey, start, end, metric, goal, result[, solver_params]) -> number or nil | Scan a price range to minimize/maximize/zero a metric and return value or price per result |
Check an expression
- Validate in the editor. Check spelling, capitalization, parentheses, and the expected result type.
- Check variable availability. A valid name may still be unavailable at the field’s execution stage. Use
Entry.AbortConditionsfor filters that need selected legs, and guard values introduced by conditional adjustments. - Inspect a focused backtest. Use the Events Viewer to inspect selected legs, entry and exit signals, and captured values. Change one rule at a time using Clone.
For assistance writing an expression, see AI Assistant. For full strategies with analysis, visit the Deltaray blog.