Named option structures¶
Language status: named structures are approved for TradeScript authoring. This is not a default-simulator options backtest or production-host approval. Use the Python builders for shared recipe construction; they do not themselves supply option execution either.
Define what to trade in a structure block, when and in which direction
in entry:, and when to close the held recipe in exit:. Use one entry and
one exit block, with as many named rules as needed.
This path compiles to typed option intents for a separately adopting host. It does not enable option quote fills in the default Atom simulator or certify a broker integration. The host must supply qualified dated contracts, market and owned position views, and the exact pinned policy. Older hosts refuse before conditions run. Validation and source export alone cannot qualify a deployment.
Language approval does not supply option quotes, fills or an adopting host.
Your first spread¶
//@version=1
options: $XYZ
run: each bar
size: 2 structures
policy: recording@1
structure bull_call: call_vertical
expiry: dte 45 within 7 days
place: atm
width: 5 points
entry:
buy bull_call when: close > 95
exit:
close bull_call when: profit >= 50% or days_to_expiry <= 7
XYZ is an illustrative underlying, not a real security recommendation.
recording@1 is the offline test policy, not a production trading policy. An
integrator must supply its own approved policy and matching host support.
At spot 100, a fully covered chain with 100/105 calls can produce buy two 100 calls and sell two 105 calls. Even with multiplier 100, these are two contracts per unit leg, not 200 contracts. The multiplier remains a product term. No fill price, debit, cash balance or P&L follows from selection alone.
The declaration does not open anything. The entry requires a flat view for this
strategy and recipe, a true condition, complete selection and host acknowledgement.
Choose a unique public identifier that does not shadow a keyword, provider or
formula name (bull_call here, not the provider name spread).
Write buy bull_call when: ..., not buy 10 units when: ...: quantity belongs
in size: N structures. Numeric buy/sell phrases report TS-OPTION-ACTION.
An older inline phrase is not a runnable alternative to a declared structure.
The exit reads the held recipe's P&L/DTE. It reverses its actual IDs, sides and
counts, even when today's chain would select different strikes. A close never
creates a new spread to guess what is held.
Close rules run before entries. Only the first acknowledged action for a recipe can submit within a callback; closing cannot reopen it on that callback. The host must deduplicate repeated intent IDs across callbacks and restart. A rejection stops the callback with an essential error; earlier acknowledged intents are not rolled back. A host can withhold close permission while an earlier close is pending.
Choose placement, distance and expiry¶
| Field | Accepted forms and units |
|---|---|
place: |
atm, strike 100, delta 0.16, delta 0.16 within 0.03, 5 points OTM, 2 strikes OTM, 5% OTM |
width: / wings: |
A positive point distance, or a positive whole listed-strike count, such as 5 points or 1 strike. No delta or percentage widths. |
expiry: |
dte 45, dte 45 within 7 days, or an exact date such as 2027-01-15. near: is refused; replace it with expiry:. |
far: |
Another explicit DTE/date target for calendars and diagonals; selected expiry must be later than near. |
size: |
A positive whole recipe count, 1 structure or 2 structures. No percentages, units, lots or local quantity overrides in this scope. |
Omitted placement is ATM; omitted expiry is 45 calendar DTE within seven days. DTE uses the decision instant's UTC date, not the machine or venue-local date. A naive decision timestamp means UTC; changing the run's market timezone cannot change the selected day. A supplied chain must cover the entire requested expiry interval. Selection does not widen an interval or use the earliest listing as a fallback. Closest DTE wins, with earlier expiry on a tie, trying complete geometry.
The complete recipe must accept the authored contract counts under every leg's
lot step. Selection skips an ineligible anchor or wing and tries the next ranked
geometry; it never rounds the count or silently changes size:. For one call
vertical of width 5 on strikes 100/105/110, if the 100 call requires multiples of
three contracts but the others accept one, selection uses 105/110. If no eligible
geometry exists, ATOM-OPTION-NO-MATCH refuses the entry. A butterfly's two-unit
body is checked as two contracts per recipe, not one.
When distinct contract IDs share a strike, ties still use contract ID order,
but an ineligible ID cannot hide an eligible alternative at that same strike.
ATM ranks by distance from spot, then lower strike and contract ID. A constrained recipe can try another ranked anchor to obtain its full geometry. An exact strike must exist. Delta is a positive magnitude from 0 to 1: the supplied call delta is positive and put delta negative. Default tolerance is inclusive 0.05. Missing deltas or model identity cannot qualify delta selection.
Points and percentages OTM move calls above spot and puts below it; selection uses the first listing at least that far outward. Listed-strike steps follow the actual distinct strike grid from ATM. They do not assume constant spacing. Wings follow the selected anchor, not another independent delta search. Point widths must match exactly. Butterflies and iron condors also require equal economic wing widths; equal step counts on an uneven grid may not satisfy that. Selected strike and spot currencies must agree. Named geometry also requires compatible multipliers, currency, exercise and settlement.
Distances preserve the supplied decimal values without depending on the host's
numeric precision settings. For spot 100.2, place: 0.01 points OTM on calls
requires a strike at least 100.21. If the listings are 100.2 and 100.25, it selects
100.25, never the ATM contract. A requested exact wing width still has no nearest-
strike fallback, even when the strike and width have very different magnitudes.
Pick a family and direction¶
The table gives the BUY recipe. sell NAME reverses every sign. A plus means
buy contracts; a minus means sell contracts. Ratios multiply size: once.
| Family | BUY legs / additional fields |
|---|---|
call, put |
One bought option. |
call_vertical |
Buy anchor call, sell higher call; width: required. |
put_vertical |
Buy anchor put, sell lower put; width: required. |
straddle |
Buy call and put at the same strike/expiry. |
strangle |
Buy lower put and higher call. |
iron_condor |
Sell outer put, buy inner put and inner call, sell outer call; wings: required. |
iron_butterfly |
Sell outer put, buy same-strike body put/call, sell outer call; wings: required. |
call_butterfly, put_butterfly |
Same-right ordered strikes with ratios +1, -2, +1; width: required. |
call_condor, put_condor |
Same-right ordered strikes with ratios +1, -1, -1, +1 and equal outer widths; width: required. |
call_calendar, put_calendar |
Sell near, buy far at the same strike; far: required. |
call_diagonal, put_diagonal |
Sell near, buy far with the call strike higher / put strike lower by width:; far: required. Listed-step widths require the anchor strike in the far grid. |
double_calendar |
Lower put and higher call calendars; sell both near legs, buy both far legs; far: required. |
For conventional short-premium iron condors/butterflies use sell, not buy:
options: $XYZ
run: each bar
size: 2 structures
policy: recording@1
structure income: iron_condor
place: 5 points OTM
wings: 5 points
entry:
sell income when: close > 95
exit:
close income when: profit >= 50% or loss >= 200% or days_to_expiry <= 7
On a 90/95/105/110 chain this emits buy two 90 puts, sell two 95 puts, sell two 105 calls and buy two 110 calls. The host must separately admit short-option risk; a family name, matching policy string or recording test is not margin proof.
Describe explicit signed legs¶
Use structure NAME: legs and open, not buy/sell, when you choose the signs
yourself. open preserves those signs and ratios rather than inverting them.
options: $XYZ
run: each bar
size: 2 structures
policy: recording@1
structure custom: legs
legs:
body: sell 2 put at strike 95 expiry 2026-02-15
wing: buy put at body.strike - 1 strike expiry body.expiry
entry:
open custom when: close > 95
exit:
close custom when: days_to_expiry <= 7
With a prior listed put strike of 90, two recipe units mean sell four 95 puts and buy two 90 puts. This unequal ratio is deliberate, not a defined-risk spread claim. The dated fixture is illustrative; a host refuses expired selection.
Omitting a leg ratio means one. Each alias is unique and references only earlier
legs. body.strike means exactly that strike; +/- N points/strikes adds an
explicit distance. expiry body.expiry takes its selected expiry. Without an
expiry override, a relative strike inherits the referenced leg's expiry; other
legs inherit the group expiry. An explicit target overrides that inheritance.
Put group fields before legs:. There are at most 16 legs. Each recipe resolution
has a shared 100,000-unit logical-work budget across chain preprocessing,
selectors, rejected candidates and expiry retries; custom recursion also retains
its 10,000-node ceiling. ATOM-OPTION-SEARCH-LIMIT means the search was too broad,
not proof that no matching recipe exists. Narrow the expiry/placement inputs or
supply a smaller qualified snapshot. This is a deterministic work bound, not a
wall-clock or memory-performance promise.
Named recipes also backtrack when a candidate's multiplier, currency, exercise or settlement terms conflict. For calls at 100 (multiplier 10), 105 and 110 (multiplier 100), an ATM five-point vertical selects 105/110 instead of returning an incompatible 100/105 pair. It never rounds quantities or mixes economic terms to force a match. Required wings and far-expiry legs also search identities at the same strike: if the first 105 call has multiplier 10 and another has 100, a multiplier-100 anchor selects the latter rather than discarding the geometry. If no compatible geometry exists, selection refuses. Named and custom recipes first exclude contracts outside the supplied spot currency. A foreign-currency ID cannot hide a valid same-strike identity or insert a false step into relative strike selection. Atom does not convert currencies to manufacture a match.
Read held state and limits honestly¶
profit >= 50% means a nonnegative profit fraction of at least 0.5; loss >= 200%
means loss fraction at least 2. The host supplies both under the pinned policy's
lifetime accounting definition. Bare 50 or .5 is rejected here. DTE takes a
whole day literal. Percent literals use ordinary decimals, not hexadecimal or
scientific notation, and are bounded to 256 characters to prevent underflow.
These fields are recipe-local values, not callable providers
or reusable global definitions. flat and holding also refer to that recipe.
Missing state stays unavailable, including through not; it cannot authorize a
close. Normal indicator/price conditions and define composition still apply.
The host must qualify providers, their history/readiness, clocks, data provenance, capital and execution. Callable presence does not establish those guarantees. Indicator inputs use shared automatic readiness; this does not qualify an option chain or supply a pricing/Greek model. Source/model names in supplied views are assertions, not independent provenance.
Rolls, shifts, reductions, leg-out, mixed stock/future/perp legs, weekly/nth-expiry
selectors, leg overrides on named families, session-range definitions, generic
stop/target/trail/risk sizing and hedge: are unsupported in this path. They do
not silently fall back to equity orders. Same-day openings, adjusted and nonlinear
contracts also refuse. Existing symbol/universe strategies retain their own
supported forms. See supported combinations and
Python option builders.