1"use strict";(self.webpackChunkmesosim_docs=self.webpackChunkmesosim_docs||[]).push([[623,9809],{9678:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>d,default:()=>h,frontMatter:()=>l,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"strategy-definition-reference","title":"Strategy Definition Reference","description":"Configure MesoSim structures, entry and exit rules, adjustments, expressions and simulator settings, with field timing and validation guidance.","source":"@site/docs/strategy-definition-reference.md","sourceDirName":".","slug":"/strategy-definition-reference","permalink":"/strategy-definition-reference","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":7,"frontMatter":{"title":"Strategy Definition Reference","description":"Configure MesoSim structures, entry and exit rules, adjustments, expressions and simulator settings, with field timing and validation guidance.","sidebar_label":"Strategy Definition","sidebar_position":7,"NOTE_NOTE_NOTE":"the h1 (#) is set to empty purposedly so that this page renders nicely when included in mesosim job editor"},"sidebar":"tutorialSidebar","previous":{"title":"Reference","permalink":"/category/about-the-simulator"},"next":{"title":"Script Engine","permalink":"/about-the-simulator/scriptengine"}}');var s=t(4848),r=t(8453);const l={title:"Strategy Definition Reference",description:"Configure MesoSim structures, entry and exit rules, adjustments, expressions and simulator settings, with field timing and validation guidance.",sidebar_label:"Strategy Definition",sidebar_position:7,NOTE_NOTE_NOTE:"the h1 (#) is set to empty purposedly so that this page renders nicely when included in mesosim job editor"},d="",a={},o=[{value:"Strategy Definition Reference",id:"strategy-definition-reference",level:2},{value:"Find a section",id:"find-a-section",level:3},{value:"Full Strategy Definition",id:"full-strategy-definition",level:2},{value:"Sections",id:"sections",level:2},{value:"Top level fields",id:"top-level-fields",level:3},{value:"Backtest",id:"backtest",level:3},{value:"Expressions in this section",id:"expressions-in-this-section",level:4},{value:"Structure",id:"structure",level:3},{value:"Expirations",id:"expirations",level:4},{value:"Legs",id:"legs",level:4},{value:"Expressions in this section",id:"expressions-in-this-section-1",level:4},{value:"Entry",id:"entry",level:3},{value:"Schedule",id:"schedule",level:4},{value:"Conditions",id:"conditions",level:4},{value:"Expressions in this section",id:"expressions-in-this-section-2",level:4},{value:"Variable Definitions",id:"variable-definitions",level:4},{value:"AbortConditions",id:"abortconditions",level:4},{value:"QtyMultiplier",id:"qtymultiplier",level:4},{value:"ReentryDays",id:"reentrydays",level:4},{value:"Concurrency",id:"concurrency",level:4},{value:"Fractional entry delays",id:"fractional-entry-delays",level:4},{value:"Exit",id:"exit",level:3},{value:"Schedule",id:"schedule-1",level:4},{value:"Maximum days in trade",id:"maximum-days-in-trade",level:4},{value:"Profit target",id:"profit-target",level:4},{value:"Stop loss",id:"stop-loss",level:4},{value:"Conditions",id:"conditions-1",level:4},{value:"Expressions in this section",id:"expressions-in-this-section-3",level:4},{value:"Adjustment",id:"adjustment",level:3},{value:"MoveLegAdjustment",id:"movelegadjustment",level:4},{value:"RemoveLegsAdjustment",id:"removelegadjustment",level:4},{value:"AddLegsAdjustment",id:"addlegsadjustment",level:4},{value:"UpdateVarsAdjustment",id:"updatevarsadjustment",level:4},{value:"Variable update timing",id:"variable-update-timing",level:4},{value:"Expressions in this section",id:"expressions-in-this-section-4",level:4},{value:"Indicators",id:"indicators",level:3},{value:"External CSV Data",id:"external-csv-data",level:3},{value:"Settings",id:"settings",level:3},{value:"Margin (Core)",id:"margin-core",level:5},{value:"Commission:",id:"commission",level:5},{value:"FillModel (Sim)",id:"fillmodel-sim",level:5},{value:"Settings.Core.ExpirationSelectionConstraint",id:"settingscoreexpirationselectionconstraint",level:4},{value:"Settings.Core.LegSelectionConstraint",id:"settingscorelegselectionconstraint",level:4},{value:"PositionMonitor",id:"positionmonitor",level:5},{value:"Expressions in this section",id:"expressions-in-this-section-5",level:4},{value:"Legacy crypto settings",id:"legacy-crypto-settings",level:4},{value:"Expressions Quick Reference",id:"expressions-quick-reference",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h
15:"h5",header:"header",li:"li",mdxAdmonitionTitle:"mdxAdmonitionTitle",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components},{Details:t}=n;return t||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:""})}),"\n",(0,s.jsx)(n.h2,{id:"strategy-definition-reference",children:"Strategy Definition Reference"}),"\n",(0,s.jsx)(n.p,{children:"This page explains every part of a strategy definition: how to describe your structure, control entry/adjustment/exit behavior, bring in external data, and configure simulator/core settings."}),"\n",(0,s.jsxs)(n.p,{children:["Coming from an older version? See the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/migration-guide",children:"Migration Guide"})," for v1\u2192v2 and v2\u2192v3 changes. Many fields accept expressions evaluated by the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/scriptengine",children:"Script Engine"}),"; time windows and anchors are described in ",(0,s.jsx)(n.a,{href:"/about-the-simulator/timing",children:"Timing"}),"; valuation tools are covered in ",(0,s.jsx)(n.a,{href:"/about-the-simulator/options-valuation",children:"Options Valuation Model"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Use the ",(0,s.jsx)(n.a,{href:"https://mesosim.io/backtest/run/jobeditor",children:"AI Job Editor"})," or work with ",(0,s.jsx)(n.a,{href:"/ai-agent",children:"AI Agents"})," to configure these fields. For a guided first run, see ",(0,s.jsx)(n.a,{href:"/first-backtest",children:"Create and run a backtest"}),"; for full strategies with analysis, visit the ",(0,s.jsx)(n.a,{href:"https://blog.deltaray.io/",children:"Deltaray blog"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"find-a-section",children:"Find a section"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Section"}),(0,s.jsx)(n.th,{children:"What it controls"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#top-level-fields",children:"Top level fields"})}),(0,s.jsx)(n.td,{children:"Strategy name, description, and symbol selection"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#backtest",children:"Backtest"})}),(0,s.jsx)(n.td,{children:"Run name, dates, and starting capital"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#structure",children:"Structure"})}),(0,s.jsx)(n.td,{children:"Expirations, legs, quantities, and strike selection"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#entry",children:"Entry"})}),(0,s.jsx)(n.td,{children:"Entry schedule, filters, sizing, and captured variables"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#exit",children:"Exit"})}),(0,s.jsx)(n.td,{children:"Profit target, stop loss, maximum duration, and exit conditions"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#adjustment",children:"Adjustment"})}),(0,s.jsx)(n.td,{children:"Conditions for moving, removing, or adding legs and updating variables"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#external-csv-data",children:"External CSV Data"})}),(0,s.jsx)(n.td,{children:"Imported signals and indicators"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#settings",children:"Settings"})}),(0,s.jsx)(n.td,{children:"Fills, costs, position monitoring, margin, and selection constraints"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.a,{href:"#expressions-quick-reference",children:"Expressions Quick Reference"})}),(0,s.jsx)(n.td,{children:"Expression types and evaluation timing"})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["When schedules coincide at the same simulation timestamp, MesoSim processes ",(0,s.jsx)(n.strong,{children:"exits \u2192 adjustments \u2192 entries"}),". Each operation still follows its own schedule and conditions."]}),"\n",(0,s.jsx)(n.p,{children:"The examples below show either a complete illustrative definition or selected sections. Merge section examples into your strategy while retaining its other required fields."}),"\n",(0,s.jsx)(n.h2,{id:"full-strategy-definition",children:"Full Strategy Definition"}),"\n",(0,s.jsxs)(n.p,{children:["This illustrative definition shows how the main sections fit together. For a runnable starting point, choose a built-in strategy from the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/strategy-library",children:"Strategy Library"}),"."]}),"\n",(0,s.jsxs)(t,{children:[(0,s.jsx)("summary",{children:"Complete Strategy Definition"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "StrategyName": "[FULL]",\n "Description": "",\n "Backtest": {\n "Name": "generate",\n "Start": "2021-01-01T00:00:00",\n "End": "2021-12-31T00:00:00",\n "Cash": 10000.0\n },\n "Symbol": "SPX",\n "Structure": {\n "Name": "ShortStrangle",\n "Expirations": [\n {\n "Name": "exp",\n "DTE": "160",\n "Min": 140,\n "Max": 190,\n "Roots": {\n "Include": [\n "SPXW",\n "SPX"\n ],\n "Exclude": null\n }\n }\n ],\n "Legs": [\n {\n "Name": "short_call",\n "Qty": "-1",\n "ExpirationName": "exp",\n "StrikeSelector": {\n "Min": 5,\n "Max": 15,\n "BidPrice": null,\n "AskPrice": null,\n "MidPrice": null,\n "Delta": "10",\n "StrikePrice": null,\n "Complex": null\n },\n "OptionType": "Call"\n },\n {\n "Name": "short_put",\n "Qty": "-1",\n "ExpirationName": "exp",\n "StrikeSelector": {\n "Min": 5,\n "Max": 15,\n "BidPrice": null,\n "AskPrice": null,\n "MidPrice": null,\n "Delta": "-1 * leg_short_call_delta",\n "StrikePrice": null,\n "Complex": null\n },\n "OptionType": "Put"\n }\n ]\n },\n "Entry": {\n "Schedule": {\n "AfterMarketOpenMinutes": null,\n "BeforeMarketCloseMinutes": 30,\
1n "Every": "day"\n },\n "Conditions": [],\n "VarDefines": {\n "initial_theta": "pos_theta"\n },\n "AbortConditions": [\n "pos_theta < 20"\n ],\n "QtyMultiplier": "1",\n "ReentryDays": 1,\n "Concurrency": {\n "MaxPositionsInFlight": 2,\n "EntryShiftDays": 3\n }\n },\n "Adjustment": {\n "Schedule": {\n "AfterMarketOpenMinutes": null,\n "BeforeMarketCloseMinutes": 30,\n "Every": "day"\n },\n "ConditionalAdjustments": {\n "pos_delta > 5": {\n "MoveLegAdjustment": {\n "LegName": "short_call",\n "ExpirationName": null,\n "Expirations": null,\n "StrikeSelector": {\n "Min": null,\n "Max": null,\n "BidPrice": null,\n "AskPrice": null,\n "MidPrice": null,\n "Delta": "abs(pos_delta - leg_short_call_delta) / abs(leg_short_call_qty)",\n "StrikePrice": null,\n "Complex": null\n }\n },\n "RemoveLegsAdjustment": null,\n "AddLegsAdjustment": null,\n "UpdateVarsAdjustment": null\n },\n "pos_delta < -5": {\n "MoveLegAdjustment": {\n "LegName": "short_put",\n "ExpirationName": null,\n "Expirations": null,\n "StrikeSelector": {\n "Min": null,\n "Max": null,\n "BidPrice": null,\n "AskPrice": null,\n "MidPrice": null,\n "Delta": "abs(pos_delta - leg_short_put_delta) / abs(leg_short_put_qty)",\n "StrikePrice": null,\n "Complex": null\n }\n },\n "RemoveLegsAdjustment": null,\n "AddLegsAdjustment": null,\n "UpdateVarsAdjustment": null\n }\n },\n "MaxAdjustmentCount": 5\n },\n "Exit": {\n "Schedule": {\n "AfterMarketOpenMinutes": null,\n "BeforeMarketCloseMinutes": 30,\n "Every": "day"\n },\n "MaxDaysInTrade": 90,\n "ProfitTarget": "pos_theta * 160 * 0.5",\n "StopLoss": "pos_theta * 160 * 0.5 * 3",\n "Conditions": [\n "initial_theta > pos_theta * 4"\n ]\n },\n "ExternalData": null,\n "Settings": {\n "Sim": {\n "FillModel": "AtMidPrice",\n "SlippageAmt": 0,\n "Commission": {\n "CommissionModel": "FixedFee",\n "OptionFee": 1.5,\n "DeribitCommissionSettings": null\n },\n "PositionMonitor": {\n "TraceCollectionInterval": "Hourly"\n }\n },\n "Core": {\n "LegSelectionConstraint": "UniqueInPosition",\n "ExpirationSelectionConstraint": "AbortOnReuse",\n "Margin": {\n "Model": "RegT",\n "HouseMultiplier": null,\n "RegTMode": "CBOEPermissive",\n "PMConfig": null\n }\n },\n "User": null\n },\n "MesoSimVersion": "__VERSION__"\n}\n'})})]}),"\n",(0,s.jsx)(n.h2,{id:"sections",children:"Sections"}),"\n",(0,s.jsx)(n.h3,{id:"top-level-fields",children:"Top level fields"}),"\n",(0,s.jsx)(n.p,{children:"The following top-level fields and sections control the job:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"StrategyName"}),": ",(0,s.jsx)("br",{})," The name of the strategy."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Description"}),": ",(0,s.jsx)("br",{})," Optional description of the strategy."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Symbol"}),": ",(0,s.jsx)("br",{})," Specifies the underlying of the trade."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"MesoSimVersion"}),": ",(0,s.jsx)("br",{})," Execution engine\u2019s version. Automatically populated."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"backtest",children:"Backtest"}),"\n",(0,s.jsx)(n.p,{children:"Controls the backtest run itself:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Name"}),": ",(0,s.jsx)("br",{})," User-provided name of the backtest. If set to ",(0,s.jsx)(n.code,{children:"generate"}),", a memorable name is created."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Start"}),": ",(0,s.jsx)("br",{})," First date and time of the simulation. Format: ",(0,s.jsx)(n.code,{children:"YYYY-MM-DDTHH:mm:ss"})]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"End"}),": ",(0,s.jsx)("br",{})," Last date and time of the simulation. Format: ",(0,s.jsx)(n.code,{children:"YYYY-MM-DDTHH:mm:ss"})]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Cash"}),": ",(0,s.jsx)("br",{})," Initial cash (expression). Must evaluate to a number greater than 0."]}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"expressions-in-this-section",children:"Expressions in this section"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"When evaluated"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Backtest.Cash"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At validation and job start"}),(0,s.jsx)(n.td,{children:"Must be > 0; expression allowed"})]})})]}),"\n",(0,s.jsx)(n.h3,{id:"structure",children:"Structure"}),"\n",(0,s.jsx)(n.p,{children:"This section defines the combination of option contracts that are traded together to create a structure."}),"\n",(0,s.jsx)(n.p,{children:"Each Option Contract is uniquely defined by its:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Underlying instrument (such as SPX, GLD, or RUT)"}),"\n",(0,s.jsx)(n.li,{children:"Expiration (e.g., 2022-05-18)"}),"\n",(0,s.jsx)(n.li,{children:"Type: Put or Call"}),"\n",(0,s.jsx)(n.li,{children:"Strike (e.g., 3500)"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Currently, MesoSim doesn't support structures created for multiple Underlyings; hence the underlying instrument can be defined top-level via the ",(0,s.jsx)(n.code,{children:"Symbol"})," parameter."]}),"\n",(0,s.jsx)(n.h4,{id:"expirations",children:"Expirations"}),"\n",(0,s.jsx)(n.p,{children:"Expiration selection is made dynamically during options trading. Similarly, during backtesting, the traded expirations are dynamically selected at a given simulation time.\nMesoSim specifies expiries by adding calendar days to the current simulation time. That is if we started our simulation back in 2008. January 2, and we specify that we are\nplanning to trade options 30 days out (DTE: days till expiration), then option contracts will be selected that expire around 2008 February."}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Structure.Expirations"})," define a list of expirations that are used during trading. At least one should be provided, but multiple expiries are also supported:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Expirations": [\n {\n "Name": "front",\n "DTE": "90",\n "Min": 50,\n "Max": null\n },\n {\n "Name": "back",\n "DTE": "expiration_front_dte + 60",\n "Min": 140,\n "Max": 190\n }\n ]\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The above snippet defines two expirations with unique names: ",(0,s.jsx)(n.code,{children:"front"})," and ",(0,s.jsx)(n.code,{children:"back"}),".\nLater, during leg definitions, these names will be used to refer to expiries defined in this section\n(",(0,s.jsx)(n.code,{children:"Structure.Legs.ExpirationName"})," references ",(0,s.jsx)(n.code,{children:"Structure.Expirations"}),").\nIt is a good practice to keep things simple and expressive; hence front is considered a good name.\nThe ",(0,s.jsx)(n.code,{children:"Name"})," field is mandatory for every Expiration."]}),"\n",(0,s.jsxs)(n.p,{children:["The DTE field defines how many days out should an option contract be selected. As simulation time passes and entry is considered, the DTE statement is evaluated (by the Lua Script Engine) to find an option contract to trade.\nNote that expiry selection using DTE is not strict: the closest expiry will be chosen for the given DTE.\nReferring to other leg's DTE field is possible via the ",(0,s.jsx)(n.code,{children:"expiration_NAME_dte"})," variable.\nAs defined above, the ",(0,s.jsx)(n.code,{children:"back"})," DTE will be calculated once the ",(0,s.jsx)(n.code,{children:"front"})," 's exact DTE is found by adding 60 days to it."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"DTE"})," field is mandatory for every Expiration."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Min"})," and ",(0,s.jsx)(n.code,{children:"Max"})," are optional fields and are used to create a subset of the available expirations at any given time.\nUsing these fields, one can avoid choosing expiries that are either too far out or too close to the current simulation time.\nDefining a narrow range will result in less (or zero) trades than a loose range.\nAs Min and Max are both optional, they can be turned off by setting them to ",(0,s.jsx)(n.code,{children:"null"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Roots"})," field enables users to filter (include or exclude) specific ",(0,s.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Option_symbol",children:"OCC Option Symbols"}),", such as SPXW, SPX,\nor - in early days - SPXPM, SZP, etc."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Include"})," field doubles as a Priority List:\nThe order of the listed symbols is taken into account during Expiration selection.\nFor example, when the following root filter is specified:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Roots": {\n "Include": [\n "SPXW",\n "SPX"\n ],\n "Exclude": null\n }\n}\n'})}
1),"\n",(0,s.jsx)(n.p,{children:"Then, in case of multiple matching Expirations at the given DTE, the first item in the Include list will be chosen: SPXW."}),"\n",(0,s.jsx)(n.p,{children:"When no Include has been specified, the Roots are ordered in the following manner:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"SPX"}),": SPXW, SPX, lexicographic order of the rest"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"GLD"}),": single root: GLD"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"RUT"}),": RUTW, RUT, lexicographic order of the rest"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"VIX"}),": VIX, lexicographic order of the rest"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["For historical crypto conventions, see ",(0,s.jsx)(n.a,{href:"#legacy-crypto-settings",children:"Legacy crypto settings"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"legs",children:"Legs"}),"\n",(0,s.jsxs)(n.p,{children:["The section \u201cLegs\u201d defines option contracts to trade as part of the structure.\nEach leg has its unique ",(0,s.jsx)(n.code,{children:"Name"}),", associated expiration (",(0,s.jsx)(n.code,{children:"ExpirationName"}),"), option type (",(0,s.jsx)(n.code,{children:"OptionType"}),"), target quantity (",(0,s.jsx)(n.code,{children:"Qty"}),"), and a strike selector (",(0,s.jsx)(n.code,{children:"StrikeSelector"}),"):"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Legs": [\n {\n "Name": "short_call",\n "Qty": "-1",\n "ExpirationName": "front",\n "StrikeSelector": {\n "Min": 5,\n "Max": 15,\n "BidPrice": null,\n "AskPrice": null,\n "MidPrice": null,\n "Delta": "10",\n "StrikePrice": null,\n "Complex": null\n },\n "OptionType": "Call"\n }\n ]\n}\n'})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Name"}),": ",(0,s.jsx)("br",{}),"The unique name of the leg. Later, this name will be used when adjustments are made to the structure. Additionally, it makes job inspection and debugging easier."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Qty"}),": ",(0,s.jsx)("br",{}),"Defines the number of contracts to be traded. If negative, a short position is taken. Index and equity options trade in whole contracts."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"ExpirationName"}),": ",(0,s.jsx)("br",{}),"Reference back to the expiration defined in the ",(0,s.jsx)(n.code,{children:"Expirations"})," section."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"OptionType"}),": ",(0,s.jsx)("br",{}),"Defines the option type to be traded. Either ",(0,s.jsx)(n.code,{children:"Put"})," or ",(0,s.jsx)(n.code,{children:"Call"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"StrikeSelector"}),": ",(0,s.jsx)("br",{}),"Defines how strikes are selected. Exactly one selector must be defined per leg."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Min / Max"}),": ",(0,s.jsx)("br",{}),"Optional constraints referring to the selector\u2019s metric (price or delta). Set to ",(0,s.jsx)(n.code,{children:"null"})," to disable."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"BidPrice / AskPrice / MidPrice"}),": ",(0,s.jsx)("br",{}),"Select the strike closest to the specified quote-based value. For an adjustment after Entry.VarDefines has defined initial_theta, an example target is: ",(0,s.jsx)(n.code,{children:"BidPrice=(initial_theta * 60 * 0.33) / 100"})]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Delta"}),": ",(0,s.jsx)("br",{}),"Select the strike closest to a non-negative, per-contract delta magnitude on the 0\u2013100 scale. For example, ",(0,s.jsx)(n.code,{children:"10"})," targets an absolute contract delta of 0.10. Leg and position delta variables include quantity and sign; convert them to a per-contract magnitude when using them as a target."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"StrikePrice"}),": ",(0,s.jsx)("br",{}),"Directly target a strike by expression. See ",(0,s.jsx)(n.a,{href:"/faq/ch
1oose-legs-pts-away",children:"Select a leg at a fixed strike distance"})," for an example."]}),"\n",(0,s.jsx)(n.p,{children:"Example \u2013 StrikePrice selector to offset another leg by 25 points:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "StrikePrice": "leg_short_put_strike + 25"\n}\n'})}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Complex"}),": ",(0,s.jsx)("br",{}),"The complex strike selector iterates through all the contracts within the given expiration and chooses the strike that best aligns with the specified criteria.\xa0"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Complex": {\n "Statement": "leg_long_strike",\n "Target": "underlying_price + 20",\n "Constraints": [\n "leg_long_strike > underlying_price"\n ]\n }\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The processing begins with walking through all contracts within the specified expiration and the ",(0,s.jsx)(n.code,{children:"Constraints"})," are evaluated (if they present).\nIf all Constraints evaluate to true (or no if constraints are specified) then the ",(0,s.jsx)(n.code,{children:"Statement"})," is calculated and stored in the inclusion list.\nOnce all contracts are processed, the ",(0,s.jsx)(n.code,{children:"Target"})," statement is evaluated. Finally, the contract that is closest to the Target is selected from the inclusion list."]}),"\n",(0,s.jsx)(n.p,{children:"The Complex StrikeSelector snippet shown above selects contracts that are 20 points higher than the At The Money strike, while ensuring that the chosen\ncontract will always have a strike price higher than the current price of the underlying.\xa0"}),"\n",(0,s.jsx)(n.admonition,{title:"Complex Strike Selector Note",type:"note",children:(0,s.jsxs)(n.p,{children:["This selector iterates over all contracts it can be used to create spreads dynamically and balance more complex structures (such as BWBs) based on custom criteria.\nFor examples, see ",(0,s.jsx)(n.a,{href:"/faq/finding-spreads",children:"Finding Spreads"}),"."]})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"expressions-in-this-section-1",children:"Expressions in this section"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"When evaluated"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Expirations[].DTE"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"During structure resolution"}),(0,s.jsx)(n.td,{children:"Target DTE per alias; must be \u2265 0"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Expirations[].Min / Max"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"During structure resolution"}),(0,s.jsx)(n.td,{children:"Optional DTE constraints; non\u2011negative; Min \u2264 Max"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Legs[].Qty"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Entry and AddLegs adjustment"}),(0,s.jsx)(n.td,{children:"Base quantity, scaled by Entry.QtyMultiplier"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Legs[].LegGroupId"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Entry and adjustments"}),(0,s.jsx)(n.td,{children:"Integer order-group identifier, including order-based slippage groups"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Legs[].StrikeSelector.[BidPrice / AskPrice / MidPrice / Delta / StrikePrice]"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"When selecting strikes"}),(0,s.jsx)(n.td,{children:"Exactly one selector per leg"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Legs[].StrikeSelector.Min / Max"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"When selecting strikes"}),(0,s.jsx)(n.td,{children:"Optional constraints for strike selection"})]})]})]}),"\n",(0,s.jsx)(n.h3,{id:"entry",children:"Entry"}),"\n",(0,s.jsxs)(n.p,{children:["The Entry section specifies when and how entries are made. A schedule is required. ",(0,s.jsx)(n.a,{href:"#reentrydays",children:"ReentryDays"})," controls the delay after an exit, while ",(0,s.jsx)(n.a,{href:"#concurrency",children:"EntryShiftDays"})," spaces entries apart. Both accept fractional days."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Entry": {\n "Schedule": {\n "AfterMarketOpenMinutes": null,\n "BeforeMarketCloseMinutes": 30,\
1n "Every": "day"\n },\n "Conditions": [],\n "QtyMultiplier": "1",\n "VarDefines": {\n "initial_theta": "pos_theta"\n },\n "ReentryDays": 1\n }\n}\n'})}),"\n",(0,s.jsx)(n.h4,{id:"schedule",children:"Schedule"}),"\n",(0,s.jsxs)(n.p,{children:["Defines when entry is considered using time relative to the session open (",(0,s.jsx)(n.code,{children:"AfterMarketOpenMinutes"}),") or close (",(0,s.jsx)(n.code,{children:"BeforeMarketCloseMinutes"}),"). These anchors follow the exchange session, including early closes. Choose offsets and a cadence compatible with the selected market-data resolution; execution is limited to its supported times. See ",(0,s.jsx)(n.a,{href:"/about-the-simulator/timing",children:"Timing"})," for timing functions."]}),"\n",(0,s.jsxs)(n.p,{children:["Daily and weekday schedules require exactly one of ",(0,s.jsx)(n.code,{children:"AfterMarketOpenMinutes"})," or ",(0,s.jsx)(n.code,{children:"BeforeMarketCloseMinutes"}),". Intraday schedules can use both to bound a window, one to bound one side, or neither for the regular session. A window must contain a supported execution time. Offset expressions are evaluated when the schedule is initialized; use conditions for changing intraday rules."]}),"\n",(0,s.jsxs)(n.p,{children:["Intraday cadence is anchored to the session open; the bounds filter that cadence rather than restart it. For example, ",(0,s.jsx)(n.code,{children:'Every: "30min"'})," with ",(0,s.jsx)(n.code,{children:"AfterMarketOpenMinutes: 45"})," first considers an equity/index entry 60 minutes after open."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Every"})," field defines the frequency when entry is attempted:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"day"}),": For strategies running once a day"]}),"\n",(0,s.jsxs)(n.li,{children:["A comma-separated weekday list, such as ",(0,s.jsx)(n.code,{children:"mon,wed,fri"}),": once on each selected trading day."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"5min"}),": Intra-day mode, the Entry, Exit or Adjustment is considered every 5 minutes"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"30min"}),": Intra-day mode, the Entry, Exit or Adjustment is considered every 30 minutes"]}),"\n",(0,s.jsxs)(n.li,{children:["Other positive ",(0,s.jsx)(n.code,{children:"Nmin"})," intervals must be compatible with the selected market-data resolution."]}),"\n"]}),"\n",(0,s.jsx)("b",{children:"Examples:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:"Try to enter every day, 30 minutes before close:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Schedule": {\n "AfterMarketOpenMinutes": null,\n "BeforeMarketCloseMinutes": 30,\n "Every": "day"\n }\n}\n'})}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(n.p,{children:"Try to enter 30 minutes after open every Mon, Wed, Fri:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Schedule": {\n "AfterMarketOpenMinutes": 30,\n "BeforeMarketCloseMinutes": null,\n "Every": "mon,wed,fri"\n }\n}\n'})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"conditions",children:"Conditions"}),"\n",(0,s.jsxs)(n.p,{children:["This section specifies a list of statements, any of which need to become true to enter the position.\nThis field can filter trades based on the variables available via the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/scriptengine",children:"Script Engine"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"For example, using conditions, it becomes possible to enter only on down days:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Conditions": [\n "underlying_price < underlying_today_open"\n ]\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Conditions are combined with ",(0,s.jsx)(n.strong,{children:"OR"}),": any true expression allows an entry attempt. An empty list imposes no additional condition; the schedule, concurrency, re-entry delay and other entry checks still apply. To require several criteria together, combine them in one expression with Lua ",(0,s.jsx)(n.code,{children:"and"}),". For example, when ",(0,s.jsx)(n.code,{children:"my_entry_signal"})," is supplied by ",(0,s.jsx)(n.a,{href:"/faq/use-external-data",children:"Exter
1nal Data"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Conditions": [\n "underlying_price < underlying_today_open and my_entry_signal == 1"\n ]\n}\n'})}),"\n",(0,s.jsx)(n.h4,{id:"expressions-in-this-section-2",children:"Expressions in this section"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"When evaluated"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Schedule.AfterMarketOpenMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Schedule.BeforeMarketCloseMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Conditions[]"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"On Entry schedule"}),(0,s.jsx)(n.td,{children:"Any true triggers entry attempt"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.AbortConditions[]"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"After leg selection, sizing and Entry.VarDefines"}),(0,s.jsx)(n.td,{children:"Checked before placing orders; any true aborts entry"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.VarDefines{}"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before abort checks and again after entry fills"}),(0,s.jsxs)(n.td,{children:["Records variables for later use (e.g., ",(0,s.jsx)(n.code,{children:"initial_theta"}),")"]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.QtyMultiplier"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"After selection at entry and again when adding legs"}),(0,s.jsx)(n.td,{children:"Scales new leg quantities using current values"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.ReentryDays"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before entry selection"}),(0,s.jsx)(n.td,{children:"Minimum elapsed days since the last exit; fractions allowed"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Concurrency.MaxPositionsInFlight"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"On Entry schedule"}),(0,s.jsx)(n.td,{children:"Governs maximum concurrent positions"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Concurrency.EntryShiftDays"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"On Entry schedule"}),(0,s.jsx)(n.td,{children:"Minimum elapsed days since the last entry; fractions allowed"})]})]})]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"Entry.Conditions, ReentryDays and Concurrency are checked before legs are selected. Selected-leg, expiration and position variables are unavailable there; they are not zero-valued placeholders. Use Entry.AbortConditions for filters based on the selected structure."})}),"\n",(0,s.jsx)(n.h4,{id:"variable-definitions",children:"Variable Definitions"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"VarDefines"})," section enables the user to capture the state during entry.\nDefinitions are evaluated in order before AbortConditions, then evaluated again after entry fills. A later definition can use an earlier one. The resulting values are available for later Adjustment and Exit expressions."]}),"\n",(0,s.jsx)(n.p,{children:"For example, capture the structure\u2019s Theta at entry, then compare it with the current Theta in an adjustment or exit condition:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "VarDefines": {\n "initial_theta": "pos_theta"\n }\n}\n'})}),"\n",(0,s.jsx)(n.h4,{id:"abortconditions",children:"AbortConditions"}),"\n",(0,s.jsx)(n.p,{children:"This section specifies a list of statements; when any of which evaluates to true, the entry is aborted.\nThis field is evaluated after the leg selection is complete. Therefore, it can filter trades based on the initial\nstate of the structure to be taken."}),"\n",(0,s.jsx)(n.p,{children:"For example, using AbortConditions, it becomes possible to enter only when a reasonable amount of Theta is gained:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "AbortConditions": [\n "pos_theta < 40"\n ]\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"When multiple conditions are specified, the entry is aborted when any of the statements become true."}),"\n",(0,s.jsx)(n.h4,{id:"qtymultiplier",children:"QtyMultiplier"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"Entry.QtyMultiplier"})," scales the selected legs\u2019 quantities using an expression, for example to size a structure from account NAV. At initial entry it runs after leg selection and before ",(0,s.jsx)(n.code,{children:"Entry.VarDefines"}),", so it can use selected-leg and position variables but cannot use a variable first defined in that entry\u2019s ",(0,s.jsx)(n.code,{children:"VarDefines"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The same expression is evaluated again when ",(0,s.jsx)(n.a,{href:"#addlegs
1adjustment",children:"AddLegsAdjustment"})," sizes new legs, using values available at that time. It is not a multiplier fixed for the position\u2019s lifetime. ",(0,s.jsx)(n.a,{href:"#movelegadjustment",children:"MoveLegAdjustment"})," preserves the moved leg\u2019s existing quantity."]}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"/faq/set-qty-dynamically",children:"Set quantities dynamically"})," for sizing examples."]}),"\n",(0,s.jsx)(n.h4,{id:"reentrydays",children:"ReentryDays"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"Entry.ReentryDays"})," sets the minimum elapsed time since the last position exit before another entry is allowed. It defaults to ",(0,s.jsx)(n.code,{children:"0"})," and accepts fractional days: ",(0,s.jsx)(n.code,{children:"1"})," means 24 hours, while ",(0,s.jsx)(n.code,{children:"0.5"})," means 12 hours. See the ",(0,s.jsx)(n.a,{href:"#fractional-entry-delays",children:"fractional-day guidance"})," below when choosing a value for live trading."]}),"\n",(0,s.jsx)(n.h4,{id:"concurrency",children:"Concurrency"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Entry.Concurrency"})," section contains the settings for the parallel positions in flight. The way of concurrency is controlled using two variables:"]}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"MaxPositionsInFlight"}),": ",(0,s.jsx)("br",{})," Defines how many parallel positions should be taken at the maximum. The number of parallel positions can be less than this if the entry conditions do not enable position entry."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"EntryShiftDays"}),": ",(0,s.jsx)("br",{})," Minimum elapsed days between entries. Fractional values are valid: ",(0,s.jsx)(n.code,{children:"1"})," requires 24 hours after the last entry, while ",(0,s.jsx)(n.code,{children:"0.5"})," requires 12 hours."]}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Entry": {\n "Concurrency": {\n "MaxPositionsInFlight": 4,\n "EntryShiftDays": 3\n }\n }\n}\n'})}),"\n",(0,s.jsx)(n.h4,{id:"fractional-entry-delays",children:"Fractional entry delays"}),"\n",(0,s.jsxs)(n.p,{children:["Both delays use elapsed time rather than calendar dates. With a daily entry schedule, ",(0,s.jsx)(n.code,{children:"1"})," allows the next day's entry only once a full 24 hours has passed since the relevant entry or exit."]}),"\n",(0,s.jsxs)(n.admonition,{title:"Allow time for live execution",type:"tip",children:[(0,s.jsxs)(n.p,{children:["For daily strategies in live trading, a fractional value such as ",(0,s.jsx)(n.code,{children:"0.5"})," is often a better choice than ",(0,s.jsx)(n.code,{children:"1"}),". If an entry scheduled for 10:00 is recorded at 10:01, ",(0,s.jsx)(n.code,{children:"EntryShiftDays: 1"})," blocks the next day's 10:00 entry because only 23 hours and 59 minutes have passed. The same elapsed-time rule applies to ",(0,s.jsx)(n.code,{children:"ReentryDays"}),", measured from the last exit."]}),(0,s.jsxs)(n.p,{children:["Using ",(0,s.jsx)(n.code,{children:"0.5"})," gives room for the time needed to enter or exit. Keep the daily entry schedule to control when an entry is considered; with an intraday schedule, a shorter delay can also allow another entry within the same day."]})]}),"\n",(0,s.jsx)(n.h3,{id:"exit",children:"Exit"}),"\n",(0,s.jsxs)(n.p,{children:["Exit is optional. It defines early-exit criteria for a position; without it, normal expiration and settlement still apply. An Exit closes the remaining structure. To remove selected legs, use ",(0,s.jsx)(n.a,{href:"#removelegadjustment",children:"RemoveLegsAdjustment"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"schedule-1",children:"Schedule"}),"\n",(0,s.jsxs)(n.p,{children:["Exit schedules follow the same rules as the ",(0,s.jsx)(n.a,{href:"#schedule",children:"Entry schedule"}),".\nAdditional to the schedule specification described in the Entry selection, it is possible to run the algorithm in intraday mode and find\nexits opportunistically by specifying a ",(0,s.jsx)(n.code,{children:"5min"})," value for the Every field:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Schedule": {\n "AfterMarketOpenMinutes": 30,\
1n "BeforeMarketCloseMinutes": null,\n "Every": "5min"\n }\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["ProfitTarget, StopLoss and MaxDaysInTrade are initialized at entry. Their expressions are not recalculated at every exit check. Use Exit.Conditions for rules that must follow changing values. For a normal close, ",(0,s.jsx)(n.code,{children:"Exit.VarDefines"})," runs after the exit decision and before closing fills; for a position closed by expiration, it runs after settlement. It does not supply inputs to the exit decision."]}),"\n",(0,s.jsx)(n.h4,{id:"maximum-days-in-trade",children:"Maximum days in trade"}),"\n",(0,s.jsx)(n.p,{children:"Trades will be held for this many days unless other conditions (Profit Target, Stop Loss, Conditions) cause an early exit."}),"\n",(0,s.jsx)(n.h4,{id:"profit-target",children:"Profit target"}),"\n",(0,s.jsx)(n.p,{children:"The desired profit target where a trade should be exited. This field takes an expression, which allows describing complex scenarios. As an example:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "ProfitTarget": "pos_theta * 160 * 0.5"\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"Defines a profit target as the projected total theta obtained by holding to the position for 160 days multiplied by a 50% discount factor."}),"\n",(0,s.jsx)(n.h4,{id:"stop-loss",children:"Stop loss"}),"\n",(0,s.jsx)(n.p,{children:"When the loss of our overall structure reaches the value defined by the stop loss expression, an early exit will be performed.\nIt is a common practice to set the StopLoss to a multiplier of the Profit Target:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "StopLoss": "pos_theta * 160 * 0.5 * 3"\n}\n'})}),"\n",(0,s.jsx)(n.h4,{id:"conditions-1",children:"Conditions"}),"\n",(0,s.jsx)(n.p,{children:"Exit conditions are defined similarly to Entry conditions. Let\u2019s say we want to exit when the theta potential of the position degrades to 25%.\nThis could be achieved by defining a variable at entry, then using that variable in the exit condition:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Entry": {\n "VarDefines": {\n "initial_theta": "pos_theta"\n }\n },\n "Exit": {\n "Conditions": [\n "initial_theta > pos_theta * 4"\n ]\n }\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["When comparing timing values (e.g., ",(0,s.jsx)(n.code,{children:"leg_*_dte"}),", ",(0,s.jsx)(n.code,{children:"days_in_trade"}),"), avoid exact equality checks because these are decimals; prefer tolerant comparisons (for example, ",(0,s.jsx)(n.code,{children:"leg_long_put_dte <= 1"}),") or cast to integer (",(0,s.jsx)(n.code,{children:"int(leg_long_put_dte) == 1"}),")."]}),"\n",(0,s.jsx)(n.h4,{id:"expressions-in-this-section-3",children:"Expressions in this section"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"When evaluated"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.Schedule.AfterMarketOpenMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.Schedule.BeforeMarketCloseMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.MaxDaysInTrade"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Initialized at entry; checked on Exit schedule"}),(0,s.jsx)(n.td,{children:"Must be > 0"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.ProfitTarget"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Initialized at entry; checked on Exit schedule"}),(0,s.jsx)(n.td,{children:"Exit threshold (profit)"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.StopLoss"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Initialized at entry; checked on Exit schedule"}),(0,s.jsx)(n.td,{children:"Exit threshold (loss)"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.Conditions[]"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"On Exit schedule"}),(0,s.jsx)(n.td,{children:"Any true expression triggers exit"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.VarDefines{}"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before normal closing fills; after settlement when the position has expired"}),(0,s.jsx)(n.td,{children:"Record variables at exit"})]})]})]}
1),"\n",(0,s.jsx)(n.h3,{id:"adjustment",children:"Adjustment"}),"\n",(0,s.jsxs)(n.p,{children:["The optional ",(0,s.jsx)(n.code,{children:"Adjustment"})," section changes an open position or updates its variables when a ",(0,s.jsx)(n.code,{children:"ConditionalAdjustments"})," condition is met. It requires a schedule, using the same rules as the ",(0,s.jsx)(n.a,{href:"#schedule",children:"Entry schedule"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"MaxAdjustmentCount"})," limits adjustment actions, including ",(0,s.jsx)(n.code,{children:"UpdateVarsAdjustment"}),". A block containing several actions can consume several counts. Before each matching block, MesoSim checks the count: if it has already reached the limit, the position is closed instead of executing that block."]}),"\n",(0,s.jsxs)(n.p,{children:["The following snippet contains two conditional adjustments.\nPlease note that not all the fields of the StrikeSelector are shown.\nFor the strike-selector fields, see ",(0,s.jsx)(n.a,{href:"#legs",children:"Legs"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Adjustment": {\n "Schedule": {\n "BeforeMarketCloseMinutes": 30,\n "Every": "day"\n },\n "ConditionalAdjustments": {\n "pos_delta > 5": {\n "MoveLegAdjustment": {\n "LegName": "short_call",\n "StrikeSelector": {\n "Delta": "abs(pos_delta - leg_short_call_delta) / abs(leg_short_call_qty)"\n }\n }\n },\n "pos_delta < -5": {\n "MoveLegAdjustment": {\n "LegName": "short_put",\n "StrikeSelector": {\n "Delta": "abs(pos_delta - leg_short_put_delta) / abs(leg_short_put_qty)"\n }\n }\n }\n },\n "MaxAdjustmentCount": 5\n }\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"In the above example, we create two Conditional Adjustments."}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ConditionalAdjustments"})," section is a JSON Map (aka. dictionary), which maps keys\n(such as the ",(0,s.jsx)(n.code,{children:"pos_delta < -5"})," statement) to values (such as ",(0,s.jsx)(n.code,{children:"MoveLegAdjustment"})," structure)."]}),"\n",(0,s.jsxs)(n.p,{children:["In MesoSim, the keys of this map are statements executed by the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/scriptengine",children:"Script Engine"}),".\nThe statements must evaluate to bool (true or false) to signal the simulator if the adjustment should be activated or not.\nIn the above example, we have two entries (key-value pairs) in the map:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["When the structure delta moves beyond 5, we move the ",(0,s.jsx)(n.code,{children:"short_call"})," leg."]}),"\n",(0,s.jsxs)(n.li,{children:["When the structure delta moves below -5, we move the ",(0,s.jsx)(n.code,{children:"short_put"})," leg."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"ConditionalAdjustments are evaluated in their definition order. All conditions are checked before the matching adjustment blocks execute in that order. A change made by one block does not cause another condition to be rechecked during that pass."}),"\n",(0,s.jsxs)(n.p,{children:["Within each matching block, actions run in this order: ",(0,s.jsx)(n.strong,{children:"RemoveLegsAdjustment \u2192 MoveLegAdjustment \u2192 AddLegsAdjustment \u2192 UpdateVarsAdjustment"}),". If removing legs closes the whole position, no later action in that block runs. The ",(0,s.jsx)(n.code,{children:"[FEAT-MultiLegAdjustment]"})," template in the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/strategy-library",children:"Strategy Library"})," demonstrates multiple adjustments."]}),"\n",(0,s.jsx)(n.h4,{id:"movelegadjustment",children:"MoveLegAdjustment"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"MoveLegAdjustment"})," closes the named leg and replaces it using a new strike selector. It can change the strike, the expiration, or both, while preserving the leg\u2019s quantity."]}),"\n",(0,s.jsxs)(n.p,{children:["The delta-balancing examples above use the same targets as the built-in ",(0,s.jsx)(n.code,{children:"SPX-ShortStrangle-Adjusting"})," template. To move the short call, subtract its current delta from the position delta, then take the absolute value and divi
1de by its absolute quantity:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-lua",children:"abs(pos_delta - leg_short_call_delta) / abs(leg_short_call_qty)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["For example, a short put with total delta ",(0,s.jsx)(n.strong,{children:"+10"})," and two short calls with combined delta ",(0,s.jsx)(n.strong,{children:"\u22124"})," give ",(0,s.jsx)(n.code,{children:"pos_delta = +6"}),". The target is ",(0,s.jsx)(n.code,{children:"abs(6 - (-4)) / abs(-2) = 5"})," per call contract. Replacing the calls near that delta brings their combined delta near ",(0,s.jsx)(n.strong,{children:"\u221210"}),", balancing the put. The available strikes determine how close the result is to neutral."]}),"\n",(0,s.jsx)(n.p,{children:"The mandatory StrikeSelector is used to specify the new strike, while the optional Expirations and ExpirationName can move the leg in time."}),"\n",(0,s.jsx)(n.p,{children:"For example:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "ConditionalAdjustments": {\n "pos_delta > 5": {\n "MoveLegAdjustment": {\n "LegName": "short_call",\n "StrikeSelector": {\n "Delta": "abs(pos_delta - leg_short_call_delta) / abs(leg_short_call_qty)"\n },\n "ExpirationName": "exp2",\n "Expirations": [\n {\n "Name": "exp2",\n "DTE": "100",\n "Min": 80,\n "Max": 120,\n "Roots": null\n }\n ]\n },\n "RemoveLegsAdjustment": null,\n "AddLegsAdjustment": null\n }\n }\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Check the resulting Greeks in ",(0,s.jsx)(n.a,{href:"/backtest-results",children:"Backtest Results"})," and inspect the action and captured variables in the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/events-viewer",children:"Events Viewer"}),". See ",(0,s.jsx)(n.a,{href:"/faq/delta-hedging#rebalance-delta-with-adjustments",children:"Rebalance delta with Adjustments"})," for a worked strategy."]}),"\n",(0,s.jsx)(n.h4,{id:"removelegadjustment",children:"RemoveLegsAdjustment"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"RemoveLegsAdjustment"})," closes the named legs, realizing their profit or loss. Supply the names in ",(0,s.jsx)(n.code,{children:"LegNames"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "RemoveLegsAdjustment": {\n "LegNames": [\n "shorts"\n ]\n }\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"If all remaining legs are removed, the position closes. Any subsequent entry must still meet the entry schedule and rules."}),"\n",(0,s.jsx)(n.p,{children:"RemoveLegsAdjustment can be combined with MoveLegAdjustment. If the two are coupled together, then first, the RemoveLeg action will be taken, then the MoveLeg will be executed.\nThis setup enables balancing the structure after the leg is removed."}),"\n",(0,s.jsx)(n.h4,{id:"addlegsadjustment",children:"AddLegsAdjustment"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"AddLegsAdjustment"})," adds one or more legs, with optional ",(0,s.jsx)(n.code,{children:"Expirations"}),", ",(0,s.jsx)(n.code,{children:"AbortConditions"})," and ",(0,s.jsx)(n.code,{children:"VarDefines"}),". It selects and sizes the new legs before checking abort conditions; any true abort condition prevents the addition. ",(0,s.jsx)(n.code,{children:"VarDefines"})," runs after the new-leg fills, so a variable first defined there cannot be used in the same action\u2019s abort condition."]}),"\n",(0,s.jsxs)(n.p,{children:["This example adds a long put only when its price does not exceed the short put\u2019s price captured at entry. First add this variable to ",(0,s.jsx)(n.code,{children:"Entry.VarDefines"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Entry": {\n "VarDefines": {\n "initial_short_put_price": "leg_short_put_price"\n }\n }\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"Then place the following action under your adjustment condition:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "AddLegsAdjustment": {\n "Legs": [\n {\n "Name": "long_put",\n "Qty": "1",\n "ExpirationName": "exp2",\n "StrikeSelector": {\n "StrikePrice": "leg_short_put_strike + 25"\n },\n "OptionType": "Put"\n }\n ],\n "Expirations": [\n {\n "Name": "exp2",\n "DTE": "100",\n "Min": 90,\n "Max": 110,\n "Roots": null\n }\n ],\n "AbortConditions": [\n "leg_long_put_price > initial_short_put_price"\n ]\n }\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"The selection fields follow the corresponding top-level definitions:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Legs"}),": matches ",(0,s.jsx)(n.a,{href:"#legs",children:"Structure.Legs"})]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Expirations"}),": matches ",(0,s.jsx)(n.a,{href:"#expirations",children:"Structure.Expirations"})]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"AbortConditions"}),": matches ",(0,s.jsx)(n.a,{href:"#abortconditions",children:"Entry.AbortConditions"})]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["New legs are scaled by ",(0,s.jsx)(n.a,{href:"#qtymultiplier",children:"Entry.QtyMultiplier"}),", re-evaluated at adjustment time. When ",(0,s.jsx)(n.code,{children:"Expirations"})," is omitted, use an expiration name already defined for the position."]}),"\n",(0,s.jsx)(n.p,{children:"The following built-in templates demonstrate the Add Legs Adjustment functionality:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"SPX-AddLegAdjustment"}),"\n",(0,s.jsx)(n.li,{children:"SPX-AddPDSAdjustment"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["For additional patterns to construct and balance multi\u2011leg structures dynamically, see ",(0,s.jsx)(n.a,{href:"/faq/finding-spreads",children:"Finding Spreads"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"updatevarsadjustment",children:"UpdateVarsAdjustment"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"UpdateVarsAdjustment"})," records or updates custom variables without placing an order. It runs when its condition matches on the adjustment schedule. For example, capture the current Greeks when the absolute position delta exceeds 10:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "ConditionalAdjustments": {\n "abs(pos_delta) >
1 10": {\n "UpdateVarsAdjustment": {\n "VarDefines": {\n "observed_delta": "pos_delta",\n "observed_theta": "pos_theta"\n }\n }\n }\n }\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Each matching execution updates these values and counts toward ",(0,s.jsx)(n.code,{children:"MaxAdjustmentCount"}),". This records the state; it does not rebalance the position. To capture state specifically after moving a leg, put ",(0,s.jsx)(n.code,{children:"VarDefines"})," directly in ",(0,s.jsx)(n.code,{children:"MoveLegAdjustment"}),", as shown in ",(0,s.jsx)(n.a,{href:"/about-the-simulator/event-log-export#capture-state-when-rebalancing-delta",children:"Events export"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"variable-update-timing",children:"Variable update timing"}),"\n",(0,s.jsxs)(n.p,{children:["Each adjustment action accepts ",(0,s.jsx)(n.code,{children:"VarDefines"}),". Definitions run in their written order, so later definitions can use earlier ones."]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Action"}),(0,s.jsxs)(n.th,{children:["When its ",(0,s.jsx)(n.code,{children:"VarDefines"})," runs"]})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"RemoveLegsAdjustment"})}),(0,s.jsx)(n.td,{children:"After the specified legs have been closed and removed"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"MoveLegAdjustment"})}),(0,s.jsx)(n.td,{children:"After the replacement leg fills"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"AddLegsAdjustment"})}),(0,s.jsx)(n.td,{children:"After the added legs fill, following that action\u2019s abort checks"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"UpdateVarsAdjustment"})}),(0,s.jsx)(n.td,{children:"In its action slot, after any other actions in the same block"})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["For captures at the beginning or end of a position, use ",(0,s.jsx)(n.a,{href:"#variable-definitions",children:"Entry.VarDefines"})," or ",(0,s.jsx)(n.a,{href:"#exit",children:"Exit.VarDefines"}),". Record only the variables needed for your analysis; see ",(0,s.jsx)(n.a,{href:"/about-the-simulator/event-log-export#capture-the-variables-you-need",children:"Events export"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"expressions-in-this-section-4",children:"Expressions in this section"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"When evaluated"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Adjustment.Schedule.AfterMarketOpenMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Adjustment.Schedule.BeforeMarketCloseMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Adjustment.ConditionalAdjustments{ condition }"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"On Adjustment schedule"}),(0,s.jsx)(n.td,{children:"Key is a condition; true triggers adjustments"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"MoveLegAdjustment.StrikeSelector.[\u2026]"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"When selecting strikes"}),(0,s.jsx)(n.td,{children:"Same semantics as Structure.Legs[].StrikeSelector"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"AddLegsAdjustment.Expirations[].(DTE/Min/Max)"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"During adjustment expiration resolution"}),(0,s.jsx)(n.td,{children:"Same semantics as Structure.Expirations"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"AddLegsAdjustment.Legs[].(Qty/StrikeSelector)"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"When selecting and sizing legs"}),(0,s.jsx)(n.td,{children:"Same semantics as Structure.Legs"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"AddLegsAdjustment.AbortConditions[]"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"After new-leg selection and sizing, before fills"}),(0,s.jsx)(n.td,{children:"Any true expression aborts the addition"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"*.VarDefines{}"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"In the action\u2019s variable-update phase, as listed above"}),(0,s.jsx)(n.td,{children:"Update or record variables"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Adjustment.MaxAdjustmentCount"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before each matching adjustment block"}),(0,s.jsx)(n.td,{children:"Must be \u2265 0; counts actions, including variable updates"})]})]})]}),"\n",(0,s.jsx)(n.h3,{id:"indicators",children:"Indicators"}),"\n",(0,s.jsxs)(n.p,{children:["Indicators were removed in v3 (see the ",(0,s.jsx)(n.a,{href:"/about-the-simulator/migration-guide",children:"Migration Guide"}),"). Use ",(0,s.jsx)(n.a,{href:"#external-csv-data",children:"Exter
1nal CSV Data"})," to bring your own variables into the simulation."]}),"\n",(0,s.jsx)(n.h3,{id:"external-csv-data",children:"External CSV Data"}),"\n",(0,s.jsx)(n.p,{children:"Load data from the CSV file and make it available to the backtest."}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ExternalData.CsvUrl"})," allows users to bring their data and use it in the backtest.\nThe CSV columns become variables in the supported expression scopes after the file is loaded. See ",(0,s.jsx)(n.a,{href:"/about-the-simulator/scriptengine#variable-availability",children:"variable availability"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Requirements:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"The CSV file must have a header row with the names of the columns/variables."}),"\n",(0,s.jsxs)(n.li,{children:["The first column must be named ",(0,s.jsx)(n.code,{children:"date"})," or ",(0,s.jsx)(n.code,{children:"datetime"})," and can contain date or datetime values"]}),"\n",(0,s.jsx)(n.li,{children:"The rest of the columns must have unique Lua variable names (letters, digits and underscores, starting with a letter or underscore) that do not conflict with the simulator's internal variables"}),"\n",(0,s.jsx)(n.li,{children:"The CSV file must be at most 2 MiB"}),"\n",(0,s.jsx)(n.li,{children:'The CSV file must be publicly accessible either via Github Gist or Google Sheets\'s "Publish to the web" feature'}),"\n",(0,s.jsx)(n.li,{children:"Data columns must contain numeric values, and timestamps must be strictly increasing."}),"\n",(0,s.jsx)(n.li,{children:"Include data at least two days before the backtest start and two days after its end. A sample more than five days old causes a data error."}),"\n"]}),"\n",(0,s.jsxs)(n.admonition,{title:"Behavior",type:"tip",children:[(0,s.jsx)(n.p,{children:"A date-only value or a midnight timestamp is treated as sampled at EOD.\nTherefore, the values set for the day will be available the next day."}),(0,s.jsx)(n.p,{children:"For other timestamps, the value is available at that timestamp and afterward until a newer sample is available. Supply data with timestamps that reflect when the information was actually available."})]}),"\n",(0,s.jsx)(n.p,{children:"The system caches the CSV file for 1 minute between validations and downloads to avoid excessive requests.\nFor public Gist and Google Sheets URLs this is a sliding cache: repeated requests can delay refresh. After changing the file, allow at least one minute without requesting the same URL, or use a new URL."}),"\n",(0,s.jsx)(n.p,{children:"Further references:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["The ",(0,s.jsx)(n.code,{children:"[FEAT-ExternalData-Csv]"})," template demonstrates the usage of this feature"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"/faq/use-external-data",children:"Use External Data"})," explains how to prepare, publish, and use a CSV."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"settings",children:"Settings"}),"\n",(0,s.jsxs)(n.p,{children:["Simulation and core configuration are defined in the Settings object. ",(0,s.jsx)(n.code,{children:"Settings.Sim.TearsheetGeneration"})," is deprecated and ignored; see ",(0,s.jsx)(n.a,{href:"/tearsheets",children:"Tearsheets"})," for on-demand reports."]}),"\n",(0,s.jsxs)(n.admonition,{type:"tip",children:[(0,s.jsx)(n.mdxAdmonitionTitle,{}),(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"/about-the-simulator/preferences",children:"Preferences"})," supply saved simulation settings for a ",(0,s.jsx)(n.strong,{children:"Templated run"}),". Review the Core settings in the Strategy Definition."]})]}),"\n",(0,s.jsx)(n.p,{children:"Settings definition:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Settings": {\n "Sim": {\n "FillModel": "AtMidPrice",\n "SlippageAmt": 0,\n "Commission": {\n "CommissionModel": "FixedFee",\n "OptionFee": 1.5\n },\n "PositionMonitor": {\n "TraceCollectionInterval": "Hourly"\n }\n },\n "Core": {\n "LegSelectionConstraint": "UniqueInPosition",\n "ExpirationSelectionConstraint": "AbortOnReuse",\n "Margin": {\n "Model": "RegT",\n "HouseMultiplier": null,\n "RegTMode": "CBOEPermissive"\n }\n }\n }\n}\n'})}),"\n",(0,s.jsx)(n.h5,{id:"margin-core",children:"Margin (Core)"}),"\n",(0,s.jsx)(n.p,{children:"Margin controls the margin calculation used during the simulation."}),"\n",(0,s.jsxs)(n.p,{children:["The Reg-T margin model enables the calculation and capturing of the margin requirement of complex options positions\nbased on ",(0,s.jsx)(n.a,{href:"https://cdn.cboe.com/resources/membership/Margin_Manual.pdf",children:"CBOE's Margin Manual"}),". The margin requirement for each position is calculated in every simulation step and\nmade accessible to the user through the ",(0,s.jsx)(n.code,{children:"pos_margin"})," variable. The sum of all position margins is used to calculate\naccount-level reporting. Use ",(0,s.jsx)(n.code,{children:"pos_margin"})," for the current position; see ",(0,s.jsx)(n.a,{href:"/about-the-simulator/margin-report",children:"Margin Report"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"The PM-Like margin model tries to approximate brokerages' Portfolio Margin mode by projecting the Risk Graph's T+0 line\nto the user-specified boun
1daries (haircuts). The Portfolio Margin calculation is a highly complex subject and brokerages\ndo not fully disclose their calculations, therefore the calculated margin using this mode is only an approximation."}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Settings.Core.Margin.Model"}),": ",(0,s.jsx)("br",{}),'When set to "None", no margin calculation is performed. "RegT" uses CBOE\u2019s rules. "PMLike" approximates portfolio margin via T+0 projections.']}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"These margin parameters are literal settings, not Lua expressions:"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.th,{children:["Field under ",(0,s.jsx)(n.code,{children:"Settings.Core.Margin"})]}),(0,s.jsx)(n.th,{children:"Value"}),(0,s.jsx)(n.th,{children:"Meaning"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"HouseMultiplier"})}),(0,s.jsxs)(n.td,{children:["Number or ",(0,s.jsx)(n.code,{children:"null"})]}),(0,s.jsxs)(n.td,{children:["Scales the margin requirement; ",(0,s.jsx)(n.code,{children:"null"})," uses 1.0"]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"RegTMode"})}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"CBOEVanilla"})," or ",(0,s.jsx)(n.code,{children:"CBOEPermissive"})]}),(0,s.jsx)(n.td,{children:"Selects the Reg-T calculation mode"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"PMConfig.LowerBoundPct"})}),(0,s.jsxs)(n.td,{children:["Number; default ",(0,s.jsx)(n.code,{children:"10"})]}),(0,s.jsx)(n.td,{children:"Lower price boundary, as a percentage below the current underlying price"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"PMConfig.UpperBoundPct"})}),(0,s.jsxs)(n.td,{children:["Number; default ",(0,s.jsx)(n.code,{children:"10"})]}),(0,s.jsx)(n.td,{children:"Upper price boundary, as a percentage above the current underlying price"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"PMConfig.IncludeRealizedPnL"})}),(0,s.jsxs)(n.td,{children:["Boolean; default ",(0,s.jsx)(n.code,{children:"false"})]}),(0,s.jsx)(n.td,{children:"Includes the position\u2019s realized P&L in the T+0 projection used for PM-like margin"})]})]})]}),"\n",(0,s.jsx)(n.p,{children:"For example:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "PMConfig": {\n "LowerBoundPct": 10,\n "UpperBoundPct": 10,\n "IncludeRealizedPnL": false\n }\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"/about-the-simulator/margin-report",children:"Margin Report"})," to interpret the captured results."]}),"\n",(0,s.jsx)(n.h5,{id:"commission",children:"Commission:"}),"\n",(0,s.jsxs)(n.p,{children:["Use the ",(0,s.jsx)(n.code,{children:"FixedFee"})," commission model for index and equity options. Each contract traded is charged the amount specified in ",(0,s.jsx)(n.code,{children:"OptionFee"}),". For the historical Deribit model, see ",(0,s.jsx)(n.a,{href:"#legacy-crypto-settings",children:"Legacy crypto settings"}),"."]}),"\n",(0,s.jsx)(n.h5,{id:"fillmodel-sim",children:"FillModel (Sim)"}),"\n",(0,s.jsx)(n.p,{children:"The FillModel parameter controls how fills are calculated for every entry, exit and NAV calculation:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"AtBidAsk"})," provides a pessimistic approach to fills"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"AtMidPrice"})," is filling in the mid-point of the Bid-Ask spread."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Slippage is applied per contract. A numeric expression without order references is evaluated at job initialization. An expression using ",(0,s.jsx)(n.code,{children:"order"})," is evaluated for each fill, in its order context."]}),"\n",(0,s.jsxs)(n.p,{children:["For example, ",(0,s.jsx)(n.code,{children:'"SlippageAmt": "order.leg_spread / 2"'})," uses half that leg's bid/ask spread. Available order properties are ",(0,s.jsx)(n.code,{children:"order.leg_spread"}),", ",(0,s.jsx)(n.code,{children:"order.combo_group_spread"}),", ",(0,s.jsx)(n.code,{children:"order.combo_group_leg_cnt"})," and ",(0,s.jsx)(n.code,{children:"order.price_increment"}),". Use property syntax, not a function call. General strategy variables are not available in this settings expression."]}),"\n",(0,s.jsx)(n.h4,{id:"settingscoreexpirationselectionconstraint",children:"Settings.Core.ExpirationSelectionConstraint"}),"\n",(0,s.jsxs)(n.p,{children:["The default, ",(0,s.jsx)(n.code,{children:"AbortOnReuse"}),", aborts initial entry when distinct expiration aliases resolve to the same expiration. Use ",(0,s.jsx)(n.code,{children:"AllowReuse"})," when those aliases may select the same expiration."]}),"\n",(0,s.jsx)(n.h4,{id:"settingscorelegselectionconstraint",children:"Settings.Core.LegSelectionConstraint"}),"\n",(0,s.jsxs)(n.p,{children:["LegSelectionConstraint controls how contracts are chosen for each leg of a position.\nWhen set to ",(0,s.jsx)(n.code,{children:"FullyUnique"}),", then each leg of every position must be unique.\nThis holds true for position initiation and adjustment as well. In this behavior, if the\nStrikeSelector selects a contract that is already in use by another position, then the next closest\ncontract is selected."]}),"\n",(0,s.jsxs)(n.p,{children:["The default, ",(0,s.jsx)(n.code,{children:"UniqueInPosition"}),", is less restrictive than FullyUnique: contracts for legs can be shared across\nmultiple positions, but within a position, each leg must remain unique. This restriction holds true for entry\nand adjustments as well."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"None"})," option enables the least restrictive mode of operation:\nit allows strike sharing within and across positions. When enabled, entries and adjustments can re-use strikes\nfrom existing legs (that is: two legs can end up in the same contract)."]}),"\n",(0,s.jsx)(n.p,{children:"Please note that when an offsetting position is made, it is not closing the affected leg,\nbut the two legs are tracked as separate entities."}),"\n",(0,s.jsx)(n.h5,{id:"positionmonitor",children:"PositionMonitor"}),"\n",(0,s.jsx)(n.p,{children:"The trace collection interval can be specified via the PositionMonitor settings:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "PositionMonitor": {\n "TraceCollectionInterval": "Hourly"\n }\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:"Valid values for TraceCollectionInterval:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Off"})," : Fastest"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Daily"}),": Fast"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)("b",{children:"Hourly"})," : Most resource intensive"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"/about-the-simulator/position-monitor",children:"Position Monitor"})," for sampling and chart guidance."]}),"\n",(0,s.jsx)(n.h4,{id:"expressions-in-this-section-5",children:"Expressions in this section"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field"}),(0,s.jsx)(n.th,{children:"Type"}),(0,s.jsx)(n.th,{children:"When evaluated"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Settings.Sim.SlippageAmt"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Job initialization, or each fill when using order properties"}),(0,s.jsx)(n.td,{children:"Must be \u2265 0; dedicated order context"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Settings.Sim.Commission.OptionFee"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Validation and job start"}),(0,s.jsx)(n.td,{children:"Must be \u2265 0 when provided; expression allowed"})]})]})]}),"\n",(0,s.jsx)(n.h4,{id:"legacy-crypto-settings",children:"Legacy crypto settings"}),"\n",(0,s.jsxs)(t,{children:[(0,s.jsx)("summary",{children:"Historical crypto conventions and commission settings"}),(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"/about-the-simulator/crypto-simulation",children:"Crypto Simulation"})," for the legacy instrument model. The following conventions apply to those historical simulations:"]}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Quantities:"})," fractional contracts are supported."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Schedules:"})," UTC 00:00 is the session anchor; weekday lists can include ",(0,s.jsx)(n.code,{children:"sat"})," and ",(0,s.jsx)(n.code,{children:"sun"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Roots:"})," the default order is ",(0,s.jsx)(n.code,{children:"BTCD, BTCW, BTCM, BTCQ"})," for BTCUSD and ",(0,s.jsx)(n.code,{children:"ETHD, ETHW, ETHM, ETHQ"})," for ETHUSD. The final letter denotes daily, weekly, monthly or quarterly expiration."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Theta-based targets:"})," Theta is quoted in USD while option prices use the underlying cryptocurrency. Convert with ",(0,s.jsx)(n.code,{children:"pos_theta / underlying_price"})," when expressing a target in that cryptocurrency."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Commission:"})," ",(0,s.jsx)(n.code,{children:"Deribit"})," uses the following configurable fee model. Values are simulation inputs for the historical period."]}),"\n"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "Commission": {\n "CommissionModel": "Deribit",\n "OptionFee": null,\n "DeribitCommissionSettings": {\
1n "MakerFeePctPerContract": 0.03,\n "TakerFeePctPerContract": 0.03,\n "MaxFeePctPerContract": 12.5,\n "DeliveryFeePctPerContract": 0.015,\n "WaiveBuySellComboOneSide": true,\n "WaiveDailyOptionsDeliveryFees": true\n }\n }\n}\n'})}),(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"WaiveBuySellComboOneSide"})," waives the cheaper side\u2019s commission for a combo containing both buys and sells. ",(0,s.jsx)(n.code,{children:"WaiveDailyOptionsDeliveryFees"})," waives delivery fees for daily options held to expiration."]})]}),"\n",(0,s.jsx)(n.h2,{id:"expressions-quick-reference",children:"Expressions Quick Reference"}),"\n",(0,s.jsxs)(n.p,{children:["Many fields accept ",(0,s.jsx)(n.a,{href:"/about-the-simulator/scriptengine",children:"Script Engine"})," expressions. This table summarizes where expressions go, what type they must return, and when they are evaluated."]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Field (path)"}),(0,s.jsx)(n.th,{children:"Expected type"}),(0,s.jsx)(n.th,{children:"When evaluated"}),(0,s.jsx)(n.th,{children:"Notes"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Backtest.Cash"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At validation and job start"}),(0,s.jsx)(n.td,{children:"Must be > 0; expression allowed"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Schedule.AfterMarketOpenMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Schedule.BeforeMarketCloseMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Conditions[]"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"On Entry schedule"}),(0,s.jsx)(n.td,{children:"If any condition is true, an entry is attempted"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.AbortConditions[]"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"After leg selection, sizing and Entry.VarDefines"}),(0,s.jsx)(n.td,{children:"Checked before placing orders; if any true, the entry is aborted"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.VarDefines{}"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before abort checks and again after entry fills"}),(0,s.jsxs)(n.td,{children:["Records variables for later use (e.g., ",(0,s.jsx)(n.code,{children:"initial_theta"}),")"]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.QtyMultiplier"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"After selection at entry and again when adding legs"}),(0,s.jsx)(n.td,{children:"Scales new leg quantities using current values"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.ReentryDays"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before entry selection"}),(0,s.jsx)(n.td,{children:"Minimum elapsed days since the last exit; fractions allowed"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Concurrency.MaxPositionsInFlight"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"On Entry schedule"}),(0,s.jsx)(n.td,{children:"Governs maximum concurrent positions"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Entry.Concurrency.EntryShiftDays"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"On Entry schedule"}),(0,s.jsx)(n.td,{children:"Minimum elapsed days since the last entry; fractions allowed"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Expirations[].DTE"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"During structure resolution"}),(0,s.jsx)(n.td,{children:"Controls target DTE for alias"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Expirations[].Min / Max"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"During structure resolution"}),(0,s.jsx)(n.td,{children:"Optional constraints for DTE selection"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Legs[].Qty"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Entry and adjustments (add\u2011legs)"}),(0,s.jsx)(n.td,{children:"Leg quantity expression"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Legs[].StrikeSelector.[BidPrice / AskPrice / MidPrice / Delta / StrikePrice]"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"When selecting strikes"}),(0,s.jsx)(n.td,{children:"Specify exactly one selector per leg"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Structure.Legs[].StrikeSelector.Min / Max"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"When selecting strikes"}),(0,s.jsx)(n.td,{children:"Optional constraints for strike selection"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Adjustment.ConditionalAdjustments{ key }"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"On Adjustment schedule"}),(0,s.jsx)(n.td,{children:"Each key is a condition; true triggers the associated adjustments"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Adjustment.*.VarDefines{}"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsxs)(n.td,{children:["See ",(0,s.jsx)(n.a,{href:"#variable-update-timing",children:"Variable update timing"})]}),(0,s.jsx)(n.td,{children:"Includes UpdateVarsAdjustment"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Adjustment.MaxAdjustmentCount"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before each matching adjustment block"}),(0,s.jsx)(n.td,{children:"Counts actions, including variable updates"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.Schedule.AfterMarketOpenMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.Schedule.BeforeMarketCloseMinutes"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"At schedule initialization"}),(0,s.jsx)(n.td,{children:"Relative offset applied to each session"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.MaxDaysInTrade"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Initialized at entry; checked on Exit schedule"}),(0,s.jsx)(n.td,{children:"Maximum days in trade before forced exit"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.ProfitTarget"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Initialized at entry; checked on Exit schedule"}),(0,s.jsx)(n.td,{children:"Exit threshold (profit)"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.StopLoss"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Initialized at entry; checked on Exit schedule"}),(0,s.jsx)(n.td,{children:"Exit threshold (loss)"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.Conditions[]"})}),(0,s.jsx)(n.td,{children:"boolean"}),(0,s.jsx)(n.td,{children:"On Exit schedule"}),(0,s.jsx)(n.td,{children:"Any true expression triggers exit"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Exit.VarDefines{}"})}),(0,s.jsx)(n.td,{children:"number"}),(0,s.jsx)(n.td,{children:"Before normal closing fills; after settlement when the position has expired"}),(0,s.jsx)(n.td,{children:"Record variables at exit"})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["Timing variables such as ",(0,s.jsx)(n.code,{children:"days_in_trade"})," and ",(0,s.jsx)(n.code,{children:"leg_*_dte"})," can be fractional. Use comparisons such as ",(0,s.jsx)(n.code,{children:"days_in_trade >= 5"})," when defining a threshold; see ",(0,s.jsx)(n.a,{href:"/about-the-simulator/timing",children:"Timing"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},5904:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>a,default:()=>x,frontMatter:()=>d,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"strategy-definition-standalone","title":"","description":"","source":"@site/docs/strategy-definition-standalone.md","sourceDirName":".","slug":"/strategy-definition-standalone","permalink":"/strategy-definition-standalone","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":8,"frontMatter":{"sidebar_position":8,"sidebar_class_name":"hidden","title":""}}');var s=t(4848),r=t(8453),l=t(9678);const d={sidebar_position:8,sidebar_class_name:"hidden",title:""},a=void 0,o={},c=[...l.toc];function h(e){return(0,s.jsx)(l.default,{})}function x(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h()}},8453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>d});var i=t(6540);const s={},r=i.createContext(s);function l(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.