{"name":"io.github.austin-starks/nexustrade-mcp","slug":"austin-starks-nexustrade-mcp","title":"NexusTrade Financial MCP","description":"Quant research, backtesting, marketplace subscriptions, editable forks, copy trading, and execution.","url":"https://mcp.market/server/austin-starks-nexustrade-mcp","rating":null,"grade":"A","score":97,"certified":false,"status":"active","category":"other","tags":[],"presence":{"score":33,"stars":10,"forks":0,"downloads_week":null,"last_push_at":"2026-10-30T21:19:02.000Z","license":"MIT"},"uptime":{"percent":100,"checks":28,"ok":28,"last_checked_at":"2026-11-04T05:40:33.650Z","last_ok_at":"2026-11-04T05:40:33.650Z","latency_ms":104},"claimed":false,"transport":"remote","callable_via_gateway":true,"default_price_micros":0,"repository":"https://github.com/austin-starks/nexustrade-ts","website":"https://nexustrade.io/developers","version":"1.0.1","remotes":[{"type":"streamable-http","url":"https://nexustrade.io/api/mcp"}],"packages":[],"tools":[{"name":"approve_agent_plan","description":"⚠ INDIRECTLY COSTS LLM CREDITS — approving the plan unfreezes the agent which then runs more planning + execution LLM calls. Manual approval required; do NOT call unless the user explicitly told you to advance their Aurora agent. Approve a semi-automated agent that is waiting in pending_plan_approval or pending_action_approval. Auto-detects which approval the agent needs and emits the matching state-machine event so the agent resumes execution. Returns 400 if the agent is not in a pending-approval state.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id to approve"}},"required":["agentId"]}},{"name":"archive_agent","description":"Aurora agent surface (no LLM cost — pure DB write). Only relevant when managing Aurora agents. Archive an agent (soft-delete). The agent remains in the database but is hidden from default listings. Address by agentId OR exact title (XOR).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id to archive (XOR with title)"},"title":{"type":"string","description":"Exact case-insensitive user-assigned title (XOR with agentId)"}},"required":[]}},{"name":"backtest_portfolio","description":"Submit an asynchronous historical backtest for a portfolio over a date range. Minute interval: first-look default is the last 90 inclusive calendar days; the selected range plus minute-indicator warmup cannot exceed 730 days of minute data, so a multi-year Minute window up to that span is allowed — do not emit 2010, and never split a longer span into yearly Minute jobs. Daily equity may use a long window. Set baseline_symbol to match the book — underlying ticker for single-name options (AAPL→AAPL), per-underlying baselines or equal-weight universe B&H for multi-name options; SPY only for broad equity. Returns a backtest ID immediately; poll query_backtest_status, then query_backtest_history (zero-LLM). Aurora may also use Read Backtest for an LLM narrative once complete.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"portfolio_id":{"type":"string","description":"Portfolio ID (live, paper, or chat — from fetch_portfolios or create_portfolio). Server resolves the collection automatically."},"start_date":{"type":"string","description":"Backtest start date (ISO format, e.g. 2024-01-01). For interval=Minute, default first-look is the last 90 inclusive calendar days and the selected range plus minute-indicator warmup cannot exceed 730 days of minute data. Do not use 2010-01-01 on Minute.","pattern":"^\\d{4}-\\d{2}-\\d{2}"},"end_date":{"type":"string","description":"Backtest end date (ISO format, e.g. 2024-12-31). Minute allows up to 730 days of minute data from start_date, counting minute-indicator warmup; never split a longer span into yearly Minute jobs.","pattern":"^\\d{4}-\\d{2}-\\d{2}"},"baseline_symbol":{"type":"string","description":"Benchmark for comparisonValue (buy-and-hold of this ticker). Defaults to SPY if omitted — use SPY only for broad equity/market strategies. For single-name options, set to that underlying (AAPL options → AAPL). For multi-name options books, run separate backtests with each material underlying as baseline (AAPL for AAPL sleeve, MSFT for MSFT), or equal-weight B&H of the traded universe — do not default to SPY.","pattern":"^[A-Za-z]{1,5}$"},"interval":{"type":"string","description":"Time interval: Day or Minute (default Day). Minute is a daytrade tape. 730 days of minute data (selected range plus warmup) is the HARD CAP; 90 days is only the DEFAULT when you name no dates. Name the dates you actually want — certifying a candidate on a full year or two is a normal second backtest, not an escalation.","enum":["Day","Minute"]},"initial_value":{"type":"number","description":"Starting portfolio value (default 10000)","minimum":1},"generate_events":{"type":"boolean","description":"Generate detailed event data (signals, orders, audits) during backtest. Costs 5x research tokens. Events are Mongo hot-store traces retained for 3 days. Use query_backtest_events to explore them while retained."},"fee_config":{"type":"object","description":"Optional fee contract keyed by AssetTypeEnum (Stock/Cryptocurrency/Option) with {amount, type: percent|dollars}. Omit for shared defaults (Option $0.65/contract). For replay of an optimizer/walk-forward study, pass that study's persisted feeConfig. Option fill slippage (OptionSlippageFraction) is not set here — engine default 0.5 applies.","additionalProperties":true}},"required":["start_date","end_date"]}},{"name":"build_portfolio","description":"Preview/builder twin of create_portfolio. Runs the SAME construction + per-strategy validation (Portfolio/Strategy/Condition/Indicator) as create_portfolio but PERSISTS NOTHING. Accepts the same IPortfolio JSON (all fields optional so partial drafts can be checked). Returns the canonicalized portfolio plus a per-component issue list (path + component + message) so you can see exactly which strategy/condition/indicator is wrong before committing. A draft that previews clean cannot fail on create_portfolio. Zero research token cost.\n\nCustom data sources: none yet.\nCreate one with run_compute (pass name and point_kind to promote its signal output directly), or use dataset_to_indicator with a saved dataset; then reference customIndicatorId in create_portfolio.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Portfolio name (required)."},"initialValue":{"type":"number","minimum":0,"description":"Starting cash (default 10000). Use 0 for agent-only / LaunchAgent portfolios that never trade capital."},"strategies":{"type":"array","description":"Array of strategies. Each strategy is { name, condition, action, orderExecution? }. RebalanceOption actions may include action.positionScope (portfolio | strategy). Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price. See $defs.strategy / $defs.condition / $defs/indicator.","items":{"type":"object","description":"A trading strategy: a trigger condition + an action to take when the condition is true. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","properties":{"name":{"type":"string","description":"Human-readable strategy name."},"condition":{"$ref":"#/$defs/condition"},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"active":{"type":"boolean","description":"Whether the strategy is active (default true)."},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]}},"required":["name","condition","action"],"additionalProperties":true},"minItems":1},"main":{"type":"boolean","description":"Mark as main portfolio (optional)."},"supportsFractionalShares":{"type":"boolean"},"supportsCrypto":{"type":"boolean"},"alertsEnabled":{"type":"boolean"},"message":{"type":"string","description":"OPTIONAL natural-language fallback. If provided WITHOUT name/strategies, the server runs a paid LLM to translate NL→portfolio. Prefer the structured fields (no LLM cost)."}},"required":[],"additionalProperties":true,"$defs":{"indicator":{"type":"object","description":"An indicator. Single permissive shape — the 'type' field selects one of ~90 indicator kinds; other fields are required only when that kind needs them. Server-side IndicatorFactory.validate enforces per-type rules. PoliticalTrades needs targetAsset, filer, metric, windowDays, amountBasis, instrument, and chamber; House and Senate are unified, so use chamber All unless explicitly filtering. Equity excludes confirmed option disclosures. Amount metrics use disclosed ranges and default to conservative LowerBound. CustomIndicator (alt-data): REQUIRED customIndicatorId (24-char hex ObjectId from list_custom_indicators or MCP session catalog); optional customIndicatorName is display-only. In DynamicRebalance/RebalanceOption/OpenOption pipelines omit targetAsset on asset-scoped CustomIndicators (binds per candidate). RebalanceDecisionMetric reads the prospective DynamicRebalance/RebalanceOption plan computed before the strategy condition and requires metric allocationDrift, plannedTurnover, estimatedCost, expectedBenefit, or netBenefit. Common kinds: Value (numeric constant; needs 'value'), Price (current asset price; needs 'targetAsset'), SimpleMovingAverage/ExponentialMovingAverage/RelativeStrengthIndex/BollingerBand/MaxDrawdown/MaxDrawup/MinimumPrice/MaximumPrice/PriceStandardDeviation/PriceMeanAbsoluteDeviation/PriceRateOfChange (need targetAsset+window; BollingerBand also numStandardDeviations), MovingAverageConvergenceDivergence (MACD; needs targetAsset; optional fastLength/slowLength/signalLength defaulting to 12/26/9 with slowLength > fastLength, interval Day|Hour|Minute default Day, and line macd|signal|histogram selecting which of the three MACD outputs to emit), AverageDirectionalIndex (Wilder ADX trend-strength system 0-100; needs targetAsset+window; optional line adx|plusDi|minusDi — ADX measures strength, +DI/-DI direction), RelativeVolume (RVOL; needs targetAsset+window; current bar volume divided by the mean volume of the trailing N completed bars, ~1.0 is its recent pace), Stochastic (needs targetAsset+window; optional smoothK/smoothD defaulting to 3/3 and line k|d), CommodityChannelIndex (CCI; needs targetAsset+window; optional constant defaulting to 0.015), WilliamsR (needs targetAsset+window; −100 to 0 scale), MoneyFlowIndex (MFI; needs targetAsset+window; volume-weighted 0-100), OnBalanceVolume (OBV; needs targetAsset; optional interval default Day), AccumulationDistribution (ADL; needs targetAsset; optional interval default Day), ChaikinMoneyFlow (CMF; needs targetAsset+window; −1 to +1 scale), DonchianChannel (needs targetAsset+window; optional line upper|lower|middle default upper), KeltnerChannel (needs targetAsset+window; optional multiplier default 2 and line upper|middle|lower default middle), Supertrend (needs targetAsset+window; optional multiplier default 3 and line value|direction default value, direction reads +1 up / −1 down), IchimokuCloud (needs targetAsset+window; optional spanLength default 52 and line tenkan|kijun|senkouA|senkouB|chikou default tenkan; lines unshifted), ParabolicSar (needs targetAsset; optional interval default Day, step default 0.02, maximum default 0.2), TrueRange/AverageTrueRange (need targetAsset; ATR also window), VWAP (needs targetAsset; resets each trading day), Plus/Minus/Multiply/Divide/Max/Min (need 'indicators' array of 2 sub-indicators), Negative/AbsoluteValue/SquareRoot (need 1 sub-indicator), Log (needs base + 1 sub-indicator), Exponentiation (needs exponent + 1 sub-indicator), CrossAbove/CrossBelow (need 2 sub-indicators), Correlation (rolling Pearson of two sub-indicators' returns; needs 2 sub-indicators + window with length >= 2), TrailingSum/IndicatorWindowAgo/IndicatorAtMinutesAfterOpen (compound; need indicators + window/length/minutesAfterOpen), IndicatorAtEntry (compound; the operand's value frozen at the last matching fill — needs 1 nested indicator + targetAsset + side + orderStatus), Fundamental/CompoundAnnualGrowthRate (need targetAsset + metric; CAGR also needs years), Economic/Index (need metric), DaysSinceOrder/MinutesSinceOrder/SumOrderQuantity/SumOrderAmount/LastOrderPrice (need targetAssets/targetAsset + side + orderStatus), DaysSinceStrategyFired/DaysSinceLastRebalanceOptionOrder (no fields), DaysSinceTransaction (transactionType + transactionStatus), IsAsset/IsNotAsset/IsAssetType/IsIndustry/IsIndexMember (need targetAsset + matchAsset/assetType/industry/index), OptionPositionValue/OptionPositionCount/OptionPositionPercentChange/OptionPositionMaxDrawdown/OptionDaysToExpiration/OptionDaysHeld/OptionCollateral/OptionSpreadCount/OptionSpreadEntryPrice/OptionUnrealizedPnL (optional underlying + optionType + direction + spreadType filters; OptionSpreadEntryPrice is the contract-weighted net entry price per share of the matching open spreads, positive for a debit and negative for a credit, with no value when none match), OptionRealizedPnL (net realized P&L on CLOSED option positions; the same optional underlying/optionType/direction/spreadType filters + optional lookbackDays), OptionRealizedPremium (realized premium still available to spend: closed short-option P&L minus premium already spent by 'percent of realized premium' opens; optional underlying + optional lookbackDays ONLY, and it rejects optionType/direction/spreadType), OptionGrossExposurePercent (no fields), DaysSinceAgent/MinutesSinceAgent/DaysSinceAlert/MinutesSinceAlert, Day/Month/Year/Date/CurrentTimeHours/CurrentTimeMinutes/CurrentTimeSeconds/MinutesAfterOpen/MinutesUntilClose, PortfolioValue/BuyingPower/InitialValue, PositionValue/PositionPercentChange/PositionMaxDrawdown/PositionMaxDrawup/UnderlyingMaxDrawdown.","properties":{"type":{"type":"string","enum":["DaysSinceAgent","MinutesSinceAgent","DaysSinceAlert","MinutesSinceAlert","StockReport","DaysUntilEarnings","DaysSinceEarnings","ImpliedVolatility","IVRank","IVPercentile","IVHVRatio","LastOrderPrice","Fundamental","Economic","CustomIndicator","Index","BollingerBand","RelativeStrengthIndex","MovingAverageConvergenceDivergence","AverageDirectionalIndex","RelativeVolume","Stochastic","CommodityChannelIndex","WilliamsR","MoneyFlowIndex","OnBalanceVolume","AccumulationDistribution","ChaikinMoneyFlow","DonchianChannel","KeltnerChannel","Supertrend","IchimokuCloud","ParabolicSar","PriceMeanAbsoluteDeviation","ExponentialMovingAverage","SimpleMovingAverage","PriceStandardDeviation","PriceRateOfChange","MaxDrawdown","MaxDrawup","MinimumPrice","MaximumPrice","IndicatorMeanAbsoluteDeviation","IndicatorExponentialMovingAverage","IndicatorSimpleMovingAverage","IndicatorStandardDeviation","IndicatorRateOfChange","DaysSinceOrder","DaysSinceOptionOrder","DaysSinceStrategyFired","DaysSinceLastRebalanceOptionOrder","MinutesSinceOptionOrder","MinutesSinceOrder","DaysSinceTransaction","InitialValue","BuyingPower","PositionValue","PositionPercentChange","PortfolioValue","RebalanceDecisionMetric","Value","Price","Plus","Minus","Multiply","Divide","Negative","AbsoluteValue","SquareRoot","Max","Min","Day","Month","Date","Year","CurrentTimeSeconds","CurrentTimeMinutes","CurrentTimeHours","TrailingSum","CompoundAnnualGrowthRate","Log","Exponentiation","SumOrderQuantity","SumOrderAmount","MinutesAfterOpen","OpeningPrice","PreviousClosingPrice","HighOfDay","LowOfDay","MinutesUntilClose","PriceChangeSinceOpen","GapSize","GapPercentage","TrueRange","AverageTrueRange","Volume","VWAP","BullishFairValueGap","BearishFairValueGap","IndicatorAtMinutesAfterOpen","IndicatorWindowAgo","IndicatorAtEntry","IsIndexMember","PoliticalTrades","InsiderTrades","IsIndustry","IsAssetType","IsAsset","IsNotAsset","CrossAbove","CrossBelow","Correlation","PositionMaxDrawdown","PositionMaxDrawup","UnderlyingMaxDrawdown","ConsecutiveTrue","CountTrue","OptionPositionValue","OptionPositionCount","OptionPositionPercentChange","OptionPositionMaxDrawdown","OptionDaysToExpiration","OptionDaysHeld","OptionCollateral","OptionSpreadCount","OptionSpreadEntryPrice","OptionUnrealizedPnL","OptionRealizedPnL","OptionRealizedPremium","OptionGrossExposurePercent"]},"name":{"type":"string","description":"Optional human-readable name. Auto-derived if omitted."},"customIndicatorId":{"type":"string","description":"REQUIRED when type is CustomIndicator. Mongo ObjectId hex string for the owned custom data source (see list_custom_indicators or MCP session instructions). Never omit — display name alone is rejected."},"customIndicatorName":{"type":"string","description":"Optional display label for CustomIndicator. Ignored for lookup; customIndicatorId is authoritative."},"value":{"type":"number","description":"Required for Value indicators (numeric constant)."},"targetAsset":{"type":"object","description":"The asset this indicator measures (most price/option indicators).","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"targetAssets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"description":"Multi-asset variant (position / order indicators)."},"matchAsset":{"type":"object","description":"IsAsset / IsNotAsset: the asset to match against.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"window":{"type":"object","description":"Rolling time window. e.g. {length:14, interval:'Day'} = trailing 14 trading days.","properties":{"length":{"type":"number","minimum":1},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]},"length":{"type":"number","description":"TrailingSum and similar — window length in days."},"indicators":{"type":"array","items":{"$ref":"#/$defs/indicator"},"description":"Sub-indicators for compound types (Plus, CrossAbove, etc.)."},"numStandardDeviations":{"type":"number","description":"BollingerBand: e.g. 2."},"metric":{"type":"string","description":"PoliticalTrades: NetAmount, BuyAmount, SellAmount, BuyCount, SellCount, DistinctBuyers. Fundamental/CompoundAnnualGrowthRate: financial metric (e.g. 'peRatio'). Economic: economic indicator (e.g. 'UNRATE'). Index: index symbol (e.g. 'VIX', 'SPX'). RebalanceDecisionMetric: allocationDrift, plannedTurnover, estimatedCost, expectedBenefit, or netBenefit."},"windowDays":{"type":"integer","minimum":1,"maximum":3650,"description":"PoliticalTrades / InsiderTrades trailing calendar days."},"filer":{"type":"string","description":"PoliticalTrades member full or last name; empty means all members."},"amountBasis":{"type":"string","enum":["LowerBound","Midpoint","UpperBound"],"description":"PoliticalTrades disclosed range endpoint. LowerBound is conservative."},"instrument":{"type":"string","enum":["Equity","Option","All"],"description":"PoliticalTrades instrument class. Equity excludes confirmed options."},"chamber":{"type":"string","enum":["All","House","Senate"],"description":"PoliticalTrades optional cohort filter. All combines House and Senate."},"years":{"type":"number","description":"CompoundAnnualGrowthRate: years over which to compute CAGR."},"base":{"type":"number","description":"Log: logarithm base (>0, ≠1)."},"exponent":{"type":"number","description":"Exponentiation: power exponent."},"minutesAfterOpen":{"type":"number","minimum":0,"maximum":390,"description":"IndicatorAtMinutesAfterOpen: 0–390."},"side":{"type":"string","enum":["Buy","Sell"],"description":"Order-side indicators: Buy or Sell."},"orderStatus":{"type":"string","enum":["Pending","Accepted","Pending User Approval","Canceled","Filled","Partially Filled"],"description":"Order-side indicators: filter by status."},"transactionType":{"type":"string","enum":["Deposit","Withdraw"],"description":"DaysSinceTransaction: Deposit or Withdraw."},"transactionStatus":{"type":"string","enum":["Pending","Canceled","Completed"],"description":"DaysSinceTransaction: transaction status."},"index":{"type":"string","enum":["SP500","NASDAQ100","DJIA"],"description":"IsIndexMember: point-in-time index id ('SP500', 'NASDAQ100', or 'DJIA')."},"industry":{"type":"string","description":"IsIndustry: industry tag."},"assetType":{"type":"string","description":"IsAssetType: e.g. 'Stock', 'Cryptocurrency'."},"message":{"type":"string","description":"DaysSinceAlert / MinutesSinceAlert: alert message to match."},"underlying":{"type":"string","description":"Option* indicators: underlying ticker (e.g. 'SPY')."},"optionType":{"type":"string","enum":["call","put"],"description":"Option* indicators: call or put."},"direction":{"type":"string","enum":["long","short"],"description":"Option* indicators: long or short."},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"],"description":"Option* indicators: vertical, ironCondor, etc."},"minOrMax":{"type":"string","enum":["min","max"],"description":"OptionDaysToExpiration / OptionDaysHeld: aggregate selector."},"positionEffect":{"type":"string","description":"Option* indicators: open or close."},"minDte":{"type":"number","description":"Option* indicators: min days to expiration."},"maxDte":{"type":"number","description":"Option* indicators: max days to expiration."},"lookbackDays":{"type":"integer","minimum":1,"maximum":36500,"description":"OptionRealizedPnL / OptionRealizedPremium: only count activity within this many days of the evaluation date. Omit for the whole life of the book."},"condition":{"$ref":"#/$defs/condition","description":"ConsecutiveTrue / CountTrue: the condition to evaluate over the window."},"compound":{"type":"boolean"},"form":{"type":"object","description":"Optional auto-generated form metadata. Usually omit; the server fills this.","additionalProperties":true}},"required":["type"],"additionalProperties":true},"condition":{"type":"object","description":"A condition tree (Bridge pattern). type='Base' compares lhs vs rhs with a comparator; type='And'/'Or' combine an array of nested conditions; type='Multi' fires when N nested conditions are true (count vs threshold); type='Then' is sequential — it fires when the last nested condition is true now and each earlier one was true at a strictly earlier tick within 'window' of the next, so it needs at least 2 conditions and a window with length > 0.","properties":{"type":{"type":"string","enum":["And","Or","Base","Multi","Then"]},"name":{"type":"string","description":"Optional name; auto-derived if omitted."},"lhs":{"$ref":"#/$defs/indicator","description":"Base only: left-hand indicator."},"rhs":{"$ref":"#/$defs/indicator","description":"Base only: right-hand indicator."},"comparison":{"type":"string","enum":["lessThan","greaterThan","lessThanOrEqual","greaterThanOrEqual","equal","notEqual"],"description":"Base / Multi only: how to compare."},"conditions":{"type":"array","items":{"$ref":"#/$defs/condition"},"description":"And / Or / Multi / Then only: nested conditions. Then reads them in order (at least 2)."},"value":{"type":"number","description":"Multi only: threshold count (>=1)."},"window":{"type":"object","description":"Then only: how long each step has to be followed by the next one, e.g. {length: 30, interval: 'Minute'}. length must be > 0.","properties":{"length":{"type":"number"},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]}},"required":["type"],"additionalProperties":true},"strategy":{"type":"object","description":"A trading strategy: a trigger condition + an action to take when the condition is true. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","properties":{"name":{"type":"string","description":"Human-readable strategy name."},"condition":{"$ref":"#/$defs/condition"},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"active":{"type":"boolean","description":"Whether the strategy is active (default true)."},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]}},"required":["name","condition","action"],"additionalProperties":true},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"asset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"window":{"type":"object","description":"Rolling time window. e.g. {length:14, interval:'Day'} = trailing 14 trading days.","properties":{"length":{"type":"number","minimum":1},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]},"deploymentBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"optionStructureTemplate":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"rebalanceOptionSleeve":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}}}},{"name":"clone_strategies_to_portfolio","description":"Replace a deployed (paper/live) portfolio's entire strategy set with deep copies of a source portfolio's strategy objects (by reference, not YAML). Source is a chat or deployed portfolio; the target MUST be a real deployed portfolio (chat portfolios are immutable and cannot be a target). Use this to deploy a chat portfolio's strategies onto a live/paper portfolio without re-describing them. Do NOT automatically backtest after clone — only backtest when the user asked for research validation. The source's prior backtest does not validate the target (different objects), but deploy-only asks should stop at clone/deploy.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"target_portfolio_id":{"type":"string","description":"Deployed portfolio ID (from fetch_portfolios — paper or live) whose strategy set will be REPLACED by default. Keeps its identity, brokerage, deployment, and history. Must be a real portfolio; chat portfolios are immutable and cannot be a target."},"source_portfolio_id":{"type":"string","description":"Source portfolio ID (live, paper, or chat) to copy strategies FROM."},"preserve_existing":{"type":"boolean","description":"When true, APPEND the source strategies to the target's existing strategy set instead of replacing it. Existing strategies (and their open system orders) are kept untouched — useful when the target has position-specific exit rules tied to current open positions. Defaults to false (legacy REPLACE semantics: all prior strategies are archived and their open system orders cancelled)."}},"required":["target_portfolio_id"]}},{"name":"create_agent","description":"⚠ COSTS LLM CREDITS on the NexusTrade account — spins up an Aurora agent via Router V5 classification + ReAct execution loops, billed per token. **Manual approval required**: do NOT call unless the user explicitly asked to launch an Aurora agent. For strategy creation/backtesting/analysis prefer no-LLM tools: structured create_portfolio (pass full IPortfolio JSON), backtest_portfolio, query_backtest_history, query_*, fetch_portfolios. Create a new autonomous Aurora agent using the same body shape as POST /api/agent. When maxIterations or automationMode are omitted, applies the user's saved ChatSettings. Agent models are product-locked (openai/gpt-5.6-luna planner, xiaomi/mimo-v2.6-flash executor, and the platform tool-role defaults) and cannot be overridden. Pass attachment_ids from upload_chat_attachment (READY) to bind files onto the last user message — same as the web FILES tab. Use this for a method-brief PDF plus a short analyze/report request.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"messages":{"type":"array","description":"ChatMessage array, e.g. [{\"sender\":\"User\",\"content\":\"...\"}]","items":{"type":"object","properties":{"sender":{"type":"string","description":"Message sender, usually User"},"content":{"type":"string","description":"Message content"},"timestamp":{"type":"string","description":"Optional ISO timestamp"},"data":{"type":"object","description":"Optional message metadata"}},"required":["sender","content"]}},"conversationId":{"type":"string","description":"Optional NexusGenAI conversation id"},"maxIterations":{"type":"number","description":"Max agent iterations. When omitted, uses the user's saved ChatSettings.agentIterations (same as the web UI)."},"automationMode":{"type":"string","enum":["automated","semi-automated"],"description":"automated | semi-automated. When omitted, uses ChatSettings.agentAutomationMode."},"session_depth":{"type":"string","enum":["smart","deep"],"description":"Deprecated compatibility field. Both values use Aurora's adaptive routing policy."},"title":{"type":"string","description":"Optional user-assigned display name for the new agent (max 100 chars). Enables later lookup via title on get_agent / send_agent_message / etc."},"idempotencyKey":{"type":"string","description":"Caller-chosen token that makes this create retry-safe. Creation runs the router and the planner and regularly takes longer than the transport will wait, so a call that times out has usually SUCCEEDED. Pass a unique key, and if the call appears to fail, retry with the SAME key: you get the agent the first call created, never a second billed run. A key reused for a different prompt is rejected rather than silently replayed."},"attachment_ids":{"type":"array","items":{"type":"string"},"description":"READY chat-attachment ids from upload_chat_attachment. Bound onto the last user message as fileAttachments (same refs as the web FILES tab)."}},"required":[]}},{"name":"create_portfolio","description":"Create an algorithmic trading portfolio. **PREFERRED PATH (no LLM cost): pass a fully-structured IPortfolio JSON payload** — see inputSchema for name + strategies[] with nested condition/action/indicator objects and optional strategy-owned orderExecution. Omit orderExecution for the explicit Market default; true waiting Limits use UnitPrice for shares/crypto or MinimumNetCredit/MaximumNetDebit for options, whose amount may be an indicator (such as OptionSpreadEntryPrice plus a Value) evaluated when the strategy fires. CustomIndicator nodes MUST include customIndicatorId from list_custom_indicators. Validate without saving by calling build_portfolio with the same JSON first. Fallback NL path `{ message: \"...\" }` costs LLM credits and should only be used when structured JSON is impractical.\n\nCustom data sources: none yet.\nCreate one with run_compute (pass name and point_kind to promote its signal output directly), or use dataset_to_indicator with a saved dataset; then reference customIndicatorId in create_portfolio.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Portfolio name (required)."},"initialValue":{"type":"number","minimum":0,"description":"Starting cash (default 10000). Use 0 for agent-only / LaunchAgent portfolios that never trade capital."},"strategies":{"type":"array","description":"Array of strategies. Each strategy is { name, condition, action, orderExecution? }. RebalanceOption actions may include action.positionScope (portfolio | strategy). Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price. See $defs.strategy / $defs.condition / $defs/indicator.","items":{"type":"object","description":"A trading strategy: a trigger condition + an action to take when the condition is true. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","properties":{"name":{"type":"string","description":"Human-readable strategy name."},"condition":{"$ref":"#/$defs/condition"},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"active":{"type":"boolean","description":"Whether the strategy is active (default true)."},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]}},"required":["name","condition","action"],"additionalProperties":true},"minItems":1},"main":{"type":"boolean","description":"Mark as main portfolio (optional)."},"supportsFractionalShares":{"type":"boolean"},"supportsCrypto":{"type":"boolean"},"alertsEnabled":{"type":"boolean"},"message":{"type":"string","description":"OPTIONAL natural-language fallback. If provided WITHOUT name/strategies, the server runs a paid LLM to translate NL→portfolio. Prefer the structured fields (no LLM cost)."}},"required":["name","strategies"],"additionalProperties":true,"$defs":{"indicator":{"type":"object","description":"An indicator. Single permissive shape — the 'type' field selects one of ~90 indicator kinds; other fields are required only when that kind needs them. Server-side IndicatorFactory.validate enforces per-type rules. PoliticalTrades needs targetAsset, filer, metric, windowDays, amountBasis, instrument, and chamber; House and Senate are unified, so use chamber All unless explicitly filtering. Equity excludes confirmed option disclosures. Amount metrics use disclosed ranges and default to conservative LowerBound. CustomIndicator (alt-data): REQUIRED customIndicatorId (24-char hex ObjectId from list_custom_indicators or MCP session catalog); optional customIndicatorName is display-only. In DynamicRebalance/RebalanceOption/OpenOption pipelines omit targetAsset on asset-scoped CustomIndicators (binds per candidate). RebalanceDecisionMetric reads the prospective DynamicRebalance/RebalanceOption plan computed before the strategy condition and requires metric allocationDrift, plannedTurnover, estimatedCost, expectedBenefit, or netBenefit. Common kinds: Value (numeric constant; needs 'value'), Price (current asset price; needs 'targetAsset'), SimpleMovingAverage/ExponentialMovingAverage/RelativeStrengthIndex/BollingerBand/MaxDrawdown/MaxDrawup/MinimumPrice/MaximumPrice/PriceStandardDeviation/PriceMeanAbsoluteDeviation/PriceRateOfChange (need targetAsset+window; BollingerBand also numStandardDeviations), MovingAverageConvergenceDivergence (MACD; needs targetAsset; optional fastLength/slowLength/signalLength defaulting to 12/26/9 with slowLength > fastLength, interval Day|Hour|Minute default Day, and line macd|signal|histogram selecting which of the three MACD outputs to emit), AverageDirectionalIndex (Wilder ADX trend-strength system 0-100; needs targetAsset+window; optional line adx|plusDi|minusDi — ADX measures strength, +DI/-DI direction), RelativeVolume (RVOL; needs targetAsset+window; current bar volume divided by the mean volume of the trailing N completed bars, ~1.0 is its recent pace), Stochastic (needs targetAsset+window; optional smoothK/smoothD defaulting to 3/3 and line k|d), CommodityChannelIndex (CCI; needs targetAsset+window; optional constant defaulting to 0.015), WilliamsR (needs targetAsset+window; −100 to 0 scale), MoneyFlowIndex (MFI; needs targetAsset+window; volume-weighted 0-100), OnBalanceVolume (OBV; needs targetAsset; optional interval default Day), AccumulationDistribution (ADL; needs targetAsset; optional interval default Day), ChaikinMoneyFlow (CMF; needs targetAsset+window; −1 to +1 scale), DonchianChannel (needs targetAsset+window; optional line upper|lower|middle default upper), KeltnerChannel (needs targetAsset+window; optional multiplier default 2 and line upper|middle|lower default middle), Supertrend (needs targetAsset+window; optional multiplier default 3 and line value|direction default value, direction reads +1 up / −1 down), IchimokuCloud (needs targetAsset+window; optional spanLength default 52 and line tenkan|kijun|senkouA|senkouB|chikou default tenkan; lines unshifted), ParabolicSar (needs targetAsset; optional interval default Day, step default 0.02, maximum default 0.2), TrueRange/AverageTrueRange (need targetAsset; ATR also window), VWAP (needs targetAsset; resets each trading day), Plus/Minus/Multiply/Divide/Max/Min (need 'indicators' array of 2 sub-indicators), Negative/AbsoluteValue/SquareRoot (need 1 sub-indicator), Log (needs base + 1 sub-indicator), Exponentiation (needs exponent + 1 sub-indicator), CrossAbove/CrossBelow (need 2 sub-indicators), Correlation (rolling Pearson of two sub-indicators' returns; needs 2 sub-indicators + window with length >= 2), TrailingSum/IndicatorWindowAgo/IndicatorAtMinutesAfterOpen (compound; need indicators + window/length/minutesAfterOpen), IndicatorAtEntry (compound; the operand's value frozen at the last matching fill — needs 1 nested indicator + targetAsset + side + orderStatus), Fundamental/CompoundAnnualGrowthRate (need targetAsset + metric; CAGR also needs years), Economic/Index (need metric), DaysSinceOrder/MinutesSinceOrder/SumOrderQuantity/SumOrderAmount/LastOrderPrice (need targetAssets/targetAsset + side + orderStatus), DaysSinceStrategyFired/DaysSinceLastRebalanceOptionOrder (no fields), DaysSinceTransaction (transactionType + transactionStatus), IsAsset/IsNotAsset/IsAssetType/IsIndustry/IsIndexMember (need targetAsset + matchAsset/assetType/industry/index), OptionPositionValue/OptionPositionCount/OptionPositionPercentChange/OptionPositionMaxDrawdown/OptionDaysToExpiration/OptionDaysHeld/OptionCollateral/OptionSpreadCount/OptionSpreadEntryPrice/OptionUnrealizedPnL (optional underlying + optionType + direction + spreadType filters; OptionSpreadEntryPrice is the contract-weighted net entry price per share of the matching open spreads, positive for a debit and negative for a credit, with no value when none match), OptionRealizedPnL (net realized P&L on CLOSED option positions; the same optional underlying/optionType/direction/spreadType filters + optional lookbackDays), OptionRealizedPremium (realized premium still available to spend: closed short-option P&L minus premium already spent by 'percent of realized premium' opens; optional underlying + optional lookbackDays ONLY, and it rejects optionType/direction/spreadType), OptionGrossExposurePercent (no fields), DaysSinceAgent/MinutesSinceAgent/DaysSinceAlert/MinutesSinceAlert, Day/Month/Year/Date/CurrentTimeHours/CurrentTimeMinutes/CurrentTimeSeconds/MinutesAfterOpen/MinutesUntilClose, PortfolioValue/BuyingPower/InitialValue, PositionValue/PositionPercentChange/PositionMaxDrawdown/PositionMaxDrawup/UnderlyingMaxDrawdown.","properties":{"type":{"type":"string","enum":["DaysSinceAgent","MinutesSinceAgent","DaysSinceAlert","MinutesSinceAlert","StockReport","DaysUntilEarnings","DaysSinceEarnings","ImpliedVolatility","IVRank","IVPercentile","IVHVRatio","LastOrderPrice","Fundamental","Economic","CustomIndicator","Index","BollingerBand","RelativeStrengthIndex","MovingAverageConvergenceDivergence","AverageDirectionalIndex","RelativeVolume","Stochastic","CommodityChannelIndex","WilliamsR","MoneyFlowIndex","OnBalanceVolume","AccumulationDistribution","ChaikinMoneyFlow","DonchianChannel","KeltnerChannel","Supertrend","IchimokuCloud","ParabolicSar","PriceMeanAbsoluteDeviation","ExponentialMovingAverage","SimpleMovingAverage","PriceStandardDeviation","PriceRateOfChange","MaxDrawdown","MaxDrawup","MinimumPrice","MaximumPrice","IndicatorMeanAbsoluteDeviation","IndicatorExponentialMovingAverage","IndicatorSimpleMovingAverage","IndicatorStandardDeviation","IndicatorRateOfChange","DaysSinceOrder","DaysSinceOptionOrder","DaysSinceStrategyFired","DaysSinceLastRebalanceOptionOrder","MinutesSinceOptionOrder","MinutesSinceOrder","DaysSinceTransaction","InitialValue","BuyingPower","PositionValue","PositionPercentChange","PortfolioValue","RebalanceDecisionMetric","Value","Price","Plus","Minus","Multiply","Divide","Negative","AbsoluteValue","SquareRoot","Max","Min","Day","Month","Date","Year","CurrentTimeSeconds","CurrentTimeMinutes","CurrentTimeHours","TrailingSum","CompoundAnnualGrowthRate","Log","Exponentiation","SumOrderQuantity","SumOrderAmount","MinutesAfterOpen","OpeningPrice","PreviousClosingPrice","HighOfDay","LowOfDay","MinutesUntilClose","PriceChangeSinceOpen","GapSize","GapPercentage","TrueRange","AverageTrueRange","Volume","VWAP","BullishFairValueGap","BearishFairValueGap","IndicatorAtMinutesAfterOpen","IndicatorWindowAgo","IndicatorAtEntry","IsIndexMember","PoliticalTrades","InsiderTrades","IsIndustry","IsAssetType","IsAsset","IsNotAsset","CrossAbove","CrossBelow","Correlation","PositionMaxDrawdown","PositionMaxDrawup","UnderlyingMaxDrawdown","ConsecutiveTrue","CountTrue","OptionPositionValue","OptionPositionCount","OptionPositionPercentChange","OptionPositionMaxDrawdown","OptionDaysToExpiration","OptionDaysHeld","OptionCollateral","OptionSpreadCount","OptionSpreadEntryPrice","OptionUnrealizedPnL","OptionRealizedPnL","OptionRealizedPremium","OptionGrossExposurePercent"]},"name":{"type":"string","description":"Optional human-readable name. Auto-derived if omitted."},"customIndicatorId":{"type":"string","description":"REQUIRED when type is CustomIndicator. Mongo ObjectId hex string for the owned custom data source (see list_custom_indicators or MCP session instructions). Never omit — display name alone is rejected."},"customIndicatorName":{"type":"string","description":"Optional display label for CustomIndicator. Ignored for lookup; customIndicatorId is authoritative."},"value":{"type":"number","description":"Required for Value indicators (numeric constant)."},"targetAsset":{"type":"object","description":"The asset this indicator measures (most price/option indicators).","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"targetAssets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"description":"Multi-asset variant (position / order indicators)."},"matchAsset":{"type":"object","description":"IsAsset / IsNotAsset: the asset to match against.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"window":{"type":"object","description":"Rolling time window. e.g. {length:14, interval:'Day'} = trailing 14 trading days.","properties":{"length":{"type":"number","minimum":1},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]},"length":{"type":"number","description":"TrailingSum and similar — window length in days."},"indicators":{"type":"array","items":{"$ref":"#/$defs/indicator"},"description":"Sub-indicators for compound types (Plus, CrossAbove, etc.)."},"numStandardDeviations":{"type":"number","description":"BollingerBand: e.g. 2."},"metric":{"type":"string","description":"PoliticalTrades: NetAmount, BuyAmount, SellAmount, BuyCount, SellCount, DistinctBuyers. Fundamental/CompoundAnnualGrowthRate: financial metric (e.g. 'peRatio'). Economic: economic indicator (e.g. 'UNRATE'). Index: index symbol (e.g. 'VIX', 'SPX'). RebalanceDecisionMetric: allocationDrift, plannedTurnover, estimatedCost, expectedBenefit, or netBenefit."},"windowDays":{"type":"integer","minimum":1,"maximum":3650,"description":"PoliticalTrades / InsiderTrades trailing calendar days."},"filer":{"type":"string","description":"PoliticalTrades member full or last name; empty means all members."},"amountBasis":{"type":"string","enum":["LowerBound","Midpoint","UpperBound"],"description":"PoliticalTrades disclosed range endpoint. LowerBound is conservative."},"instrument":{"type":"string","enum":["Equity","Option","All"],"description":"PoliticalTrades instrument class. Equity excludes confirmed options."},"chamber":{"type":"string","enum":["All","House","Senate"],"description":"PoliticalTrades optional cohort filter. All combines House and Senate."},"years":{"type":"number","description":"CompoundAnnualGrowthRate: years over which to compute CAGR."},"base":{"type":"number","description":"Log: logarithm base (>0, ≠1)."},"exponent":{"type":"number","description":"Exponentiation: power exponent."},"minutesAfterOpen":{"type":"number","minimum":0,"maximum":390,"description":"IndicatorAtMinutesAfterOpen: 0–390."},"side":{"type":"string","enum":["Buy","Sell"],"description":"Order-side indicators: Buy or Sell."},"orderStatus":{"type":"string","enum":["Pending","Accepted","Pending User Approval","Canceled","Filled","Partially Filled"],"description":"Order-side indicators: filter by status."},"transactionType":{"type":"string","enum":["Deposit","Withdraw"],"description":"DaysSinceTransaction: Deposit or Withdraw."},"transactionStatus":{"type":"string","enum":["Pending","Canceled","Completed"],"description":"DaysSinceTransaction: transaction status."},"index":{"type":"string","enum":["SP500","NASDAQ100","DJIA"],"description":"IsIndexMember: point-in-time index id ('SP500', 'NASDAQ100', or 'DJIA')."},"industry":{"type":"string","description":"IsIndustry: industry tag."},"assetType":{"type":"string","description":"IsAssetType: e.g. 'Stock', 'Cryptocurrency'."},"message":{"type":"string","description":"DaysSinceAlert / MinutesSinceAlert: alert message to match."},"underlying":{"type":"string","description":"Option* indicators: underlying ticker (e.g. 'SPY')."},"optionType":{"type":"string","enum":["call","put"],"description":"Option* indicators: call or put."},"direction":{"type":"string","enum":["long","short"],"description":"Option* indicators: long or short."},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"],"description":"Option* indicators: vertical, ironCondor, etc."},"minOrMax":{"type":"string","enum":["min","max"],"description":"OptionDaysToExpiration / OptionDaysHeld: aggregate selector."},"positionEffect":{"type":"string","description":"Option* indicators: open or close."},"minDte":{"type":"number","description":"Option* indicators: min days to expiration."},"maxDte":{"type":"number","description":"Option* indicators: max days to expiration."},"lookbackDays":{"type":"integer","minimum":1,"maximum":36500,"description":"OptionRealizedPnL / OptionRealizedPremium: only count activity within this many days of the evaluation date. Omit for the whole life of the book."},"condition":{"$ref":"#/$defs/condition","description":"ConsecutiveTrue / CountTrue: the condition to evaluate over the window."},"compound":{"type":"boolean"},"form":{"type":"object","description":"Optional auto-generated form metadata. Usually omit; the server fills this.","additionalProperties":true}},"required":["type"],"additionalProperties":true},"condition":{"type":"object","description":"A condition tree (Bridge pattern). type='Base' compares lhs vs rhs with a comparator; type='And'/'Or' combine an array of nested conditions; type='Multi' fires when N nested conditions are true (count vs threshold); type='Then' is sequential — it fires when the last nested condition is true now and each earlier one was true at a strictly earlier tick within 'window' of the next, so it needs at least 2 conditions and a window with length > 0.","properties":{"type":{"type":"string","enum":["And","Or","Base","Multi","Then"]},"name":{"type":"string","description":"Optional name; auto-derived if omitted."},"lhs":{"$ref":"#/$defs/indicator","description":"Base only: left-hand indicator."},"rhs":{"$ref":"#/$defs/indicator","description":"Base only: right-hand indicator."},"comparison":{"type":"string","enum":["lessThan","greaterThan","lessThanOrEqual","greaterThanOrEqual","equal","notEqual"],"description":"Base / Multi only: how to compare."},"conditions":{"type":"array","items":{"$ref":"#/$defs/condition"},"description":"And / Or / Multi / Then only: nested conditions. Then reads them in order (at least 2)."},"value":{"type":"number","description":"Multi only: threshold count (>=1)."},"window":{"type":"object","description":"Then only: how long each step has to be followed by the next one, e.g. {length: 30, interval: 'Minute'}. length must be > 0.","properties":{"length":{"type":"number"},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]}},"required":["type"],"additionalProperties":true},"strategy":{"type":"object","description":"A trading strategy: a trigger condition + an action to take when the condition is true. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","properties":{"name":{"type":"string","description":"Human-readable strategy name."},"condition":{"$ref":"#/$defs/condition"},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"active":{"type":"boolean","description":"Whether the strategy is active (default true)."},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]}},"required":["name","condition","action"],"additionalProperties":true},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"asset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"window":{"type":"object","description":"Rolling time window. e.g. {length:14, interval:'Day'} = trailing 14 trading days.","properties":{"length":{"type":"number","minimum":1},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]},"deploymentBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"optionStructureTemplate":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"rebalanceOptionSleeve":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}}}},{"name":"create_portfolio_variant","description":"Deep-copy a source portfolio (chat OR deployed) into a NEW chat portfolio with fresh strategy IDs and no YAML/NL re-authoring. Use this — NOT create_portfolio — whenever an existing portfolio must remain the exact semantic baseline. Omit patches (or pass []) for a clone-only control; supply RFC-6902 JSON-Pointer patches (op/path/value) only for deliberate surgical changes. Patch paths target the IPortfolio shape and are action-type-specific: DynamicRebalance cash/deploy → `/strategies/0/action/deploymentPercent` (number 0–100); RebalanceOption book budget → `/strategies/0/action/totalBudget/amount`. Never put totalBudget on DynamicRebalance or deploymentPercent on RebalanceOption — validation rejects the wrong field. Requires source_portfolio_id and name. Pass dry_run:true to validate without persisting. Result is an independent chat portfolio; backtest it to evaluate.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"source_portfolio_id":{"type":"string","description":"Source portfolio ID (live, paper, or chat) to deep-copy."},"name":{"type":"string","description":"Required new portfolio name."},"patches":{"type":"array","description":"RFC6902-style ops against canonical IPortfolio JSON. Omit or pass [] for an exact semantic clone."},"dry_run":{"type":"boolean","description":"Resolve, diff and validate without persisting."}},"required":["source_portfolio_id","name"],"additionalProperties":false}},{"name":"fetch_portfolios","description":"List or search your portfolios with lightweight metadata (strategy id + name). Matches portfolio name, strategy names, and tickers — same workspace search as the dashboard / GET /api/chat-portfolio. include_chat_portfolios returns workspace DRAFTS only (excludes deployedMirror rows). Recover a past chat draft: include_paper=false, include_live=false, include_chat_portfolios=true, search=\"Delta 0.07\" (then get_portfolio for full strategy JSON). Returns an object: { portfolios, page, limit, total, totalPages, scopes }. Deployed and draft rows page as one list (all deployed, then all drafts), so every row is reachable by walking pages. When search is set, include_positions defaults to false. Use analyze_portfolios only when you need LLM-written analysis.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"portfolio_ids":{"type":"array","description":"Specific portfolio IDs to fetch (omit for all)","items":{"type":"string"}},"search":{"type":"string","description":"Free-text search (max 100 chars) over portfolio name, strategy names, and tickers, ranked by relevance. Matches stemmed whole words (Postgres full-text) and case-insensitive substrings of 3+ characters (so prefixes like \"neckb\" find \"Neckbeard\"). Omit for list/paginate mode. Matches the dashboard workspace search — not condition-field values."},"include_inactive":{"type":"boolean","description":"Include inactive portfolios (default true)"},"include_paper":{"type":"boolean","description":"Include paper portfolios (default true)"},"include_live":{"type":"boolean","description":"Include live trading portfolios (default true)"},"include_chat_portfolios":{"type":"boolean","description":"Include workspace draft chat portfolios (default false). Excludes deployedMirror. Set true with include_paper=false and include_live=false for draft-only search."},"include_positions":{"type":"boolean","description":"Include positions + spread-grouped holdings (default true when not searching; default false when search is set). cash and buyingPower are always returned for deployed portfolios regardless of this flag."},"limit":{"type":"number","description":"Max portfolios to return (default 20, max 50)"},"page":{"type":"number","description":"Page number (default 1)"}},"required":[]}},{"name":"fork_shared_portfolio","description":"⚠ MUTATING — creates or modifies a portfolio. Fork strategies from a shared portfolio into the user's account. target: 'new' creates a chat portfolio; 'existing' patches a deployed portfolio. mode: 'replace' (default) removes old strategies, 'append' keeps them. For monetized portfolios, subscribe first. Returns { forkSharedPortfolioResult: { portfolioId, name, addedCount, removedCount, ... } }. Prefer fork when the user wants to edit/customize strategies.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"shared_portfolio_id":{"type":"string","description":"ID of the accessible marketplace portfolio to fork into a one-time editable copy. This does not keep strategies synchronized; use copy_trade_shared for continuous mirroring."},"target":{"type":"string","description":"Create a new chat portfolio or update an existing portfolio.","enum":["new","existing"]},"target_portfolio_id":{"type":"string","description":"Required when target is existing."},"name":{"type":"string","description":"Name for a new portfolio."},"mode":{"type":"string","description":"Replace existing strategies or append to them.","enum":["replace","append"]}},"required":["shared_portfolio_id","target"],"additionalProperties":false}},{"name":"get_agent","description":"Aurora agent surface (no LLM cost on this call — pure DB read). Only relevant when the user is actively working with an Aurora agent. Returns status, plan, messages, config. Address by agentId OR by exact title (case-insensitive); provide exactly one. Duplicate titles fail closed with candidate ids. Polling/liveness: use agent.lastProgressAt (advances during sandbox steps, tool cards, LLM rounds, and — while waiting_for_subagents — when children progress) — NOT agent.updatedAt (state transitions only; stays frozen by design while parked on subagents so the waiting-no-wake detector can prefilter). For waiting_for_subagents, a frozen lastProgressAt means children stopped progressing; confirm via child agent statuses. Sandbox step detail: agent.messages[*].data.steps. Poll until status is terminal (complete/stopped/error).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id (XOR with title)"},"title":{"type":"string","description":"Exact case-insensitive user-assigned title (XOR with agentId). Fails if 0 or >1 matches."}},"required":[]}},{"name":"get_agent_trajectory","description":"Aurora agent surface (no LLM cost on this call — pure DB read). Only relevant when inspecting an Aurora agent run. Raw trace / trajectory events for an agent (for inspection or building evaluator input). Address by agentId OR exact title (XOR).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id (XOR with title)"},"title":{"type":"string","description":"Exact case-insensitive user-assigned title (XOR with agentId)"}},"required":[]}},{"name":"get_portfolio","description":"Fetch one portfolio with full strategy objects (condition, action, indicators), positions, and spread-grouped holdings. Zero LLM cost — same data path as GET /api/portfolio/:portfolioId. Resolves deployed paper/live portfolios first, then chat portfolios. Use fetch_portfolios to discover IDs. Response includes conditionFieldAudit (comparison, value, window.length per base condition) — use that for Gate-7/Gate-8 deploy verification, NOT strategy.name or condition.name (those may be stale after GA mutation).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"portfolio_id":{"type":"string","description":"Portfolio ID (deployed paper/live or chat portfolio ID from fetch_portfolios / create_portfolio)."}},"required":["portfolio_id"]}},{"name":"list_agents","description":"Aurora agent surface (no LLM cost on this call itself — pure DB read). Useful only when the user is actively operating an Aurora agent. For strategy creation/backtesting prefer the structured no-LLM tools (create_portfolio with full JSON payload, backtest_portfolio, query_*, fetch_portfolios). List your Aurora agents with pagination using the same query shape as the agent controller.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"page":{"type":"number","description":"Page number (default 1)"},"limit":{"type":"number","description":"Page size (default 10, max 100)"},"portfolioId":{"type":"string","description":"Optional portfolio id or alias to filter agents"},"includeArchived":{"type":"boolean","description":"Include archived agents. Default false"},"starredOnly":{"type":"boolean","description":"Return only starred top-level agents, sorted by starredOrder asc then starredAt desc. Default false"},"search":{"type":"string","description":"Case-insensitive substring match over title and initialPrompt"}},"required":[]}},{"name":"query_backtest_history","description":"Return a time series of {time, value, cash, positionValue, comparisonValue, reservedCollateral} per tick for a completed backtest. Reads from the backtesthistories collection (full minute-resolution; 30-day TTL). Use this to find suspicious single-tick portfolio value jumps without needing the codebase — feed the result through your own jump-detection logic. Cash is derived as value minus Σ(position.quantity × lastPrice). `reservedCollateral` is the collateral locked by open positions at that tick, as the engine computed it; it reads `null` for a run made before collateral reporting existed, which is NOT zero. Never re-derive it from cash − buyingPower. Zero research token cost.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"backtest_id":{"type":"string","description":"Backtest ID (required). Must be owned by the calling MCP user."},"start_date":{"type":"string","description":"ISO date filter start (e.g. 2024-10-07). Inclusive."},"end_date":{"type":"string","description":"ISO date filter end (e.g. 2024-10-18). Inclusive; T23:59:59.999Z is appended if a bare date is given."},"jump_bps_threshold":{"type":"number","description":"If set, the response appends a 'Suspicious jumps' section listing every single-tick Δvalue whose magnitude exceeds this many basis points of the FIRST point's value. E.g. 50 = flag any >0.5% move between consecutive ticks. Useful for mark-to-market bug hunts. Default: omitted (no jump scan)."},"page":{"type":"number","description":"Page number (default 1)"},"page_size":{"type":"number","description":"Rows per page (default 500, max 5000). Larger than events because history is plain numbers — cheap to emit."}},"required":["backtest_id"]}},{"name":"query_backtest_status","description":"Return the parent backtest document's status, error, interval, timestamps, elapsed time, and completed statistics without reading history/events. Use immediately after backtest_portfolio or before query_backtest_history so ERROR/PENDING/RUNNING states are explicit. Statistics include peakReservedCollateral and medianReservedCollateral — how much capital the book actually had on the line, which a percentage return does not say. Both read \"not recorded\" for a run made before collateral reporting existed; that is not zero, so do not report it as such. Zero research token cost.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"backtest_id":{"type":"string","description":"Backtest ID (required). Must be owned by the calling MCP user."}},"required":["backtest_id"]}},{"name":"reject_agent_action","description":"Aurora agent surface (minimal LLM cost — state transition, no re-planning). Only relevant when actively managing an Aurora agent. Reject a semi-automated agent that is waiting in pending_plan_approval or pending_action_approval. Mirrors POST /api/agent/:agentId/reject, marks the latest assistant message as errored, transitions through the state machine, traces the rejection, and publishes a websocket update.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id to reject"}},"required":["agentId"]}},{"name":"search_public_portfolios","description":"Search and browse publicly shared portfolios from other NexusTrade users, sorted by performance metrics. Optional profileId filters to one creator's public/monetized books (from Search Creators / /p/:profileId).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"sort_by":{"type":"string","description":"Sort field: week, month, threeMonths, sixMonths, year, ytd, allTime, followerCount, bookmarkCount, maxDrawdown, sharpeRatio. maxDrawdown ranks lowest |drawdown| first and excludes 0 (idle books). sharpeRatio ranks highest first.","enum":["week","month","threeMonths","sixMonths","year","ytd","allTime","followerCount","bookmarkCount","maxDrawdown","sharpeRatio"]},"sort_order":{"type":"string","description":"Sort order: 1 or -1 (default -1, or 1 when sort_by is maxDrawdown)","enum":["1","-1"]},"min_followers":{"type":"number","description":"Minimum follower count filter (default 0)","minimum":0},"max_drawdown":{"type":"number","description":"Keep listings whose |max drawdown| is at most this percent. Idle books with max drawdown of 0 are excluded. Combine with min_sharpe.","exclusiveMinimum":0},"min_sharpe":{"type":"number","description":"Minimum Sharpe ratio filter. Combine with max_drawdown."},"trading_type":{"type":"string","description":"Trading type: paper-trading or live-trading","enum":["paper-trading","live-trading"]},"profile_id":{"type":"string","description":"Optional public creator profileId (from search_creators / /p/:profileId). When set, returns only that creator's public/monetized shared portfolios."},"limit":{"type":"number","description":"Results per page (default 20, max 100)","minimum":1,"maximum":100},"page":{"type":"integer","description":"Page number (default 1)","minimum":1}},"required":[]}},{"name":"send_agent_message","description":"⚠ COSTS LLM CREDITS — re-runs the Aurora planner LLM after appending the user's follow-up. Manual approval required; do NOT call unless the user explicitly asked to push a message into an active Aurora agent. Address by agentId OR exact title (XOR). Send a follow-up user message to an agent and re-run the planner, matching POST /api/agent/:agentId/message. This can charge planning tokens, rejects actively running/approved states, may recover terminal states, may transition the agent, and publishes websocket updates. It is not an append-only operation.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id to send the message to (XOR with title)"},"title":{"type":"string","description":"Exact case-insensitive user-assigned title (XOR with agentId)"},"content":{"type":"string","description":"The user message text to append to the conversation"}},"required":["content"]}},{"name":"send_chat_message","description":"⚠ COSTS LLM CREDITS — same path as POST /api/chat. Router V5 classifies the message: Ask Clarity (persisted), Create Agent (spawns Aurora research), or single-tool fulfill (queued prompt job). Use this for chat turns; use create_agent only when you explicitly want agent spawn without single-tool fulfill. Aurora chooses the complete route adaptively.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"messages":{"type":"array","description":"Full or partial ChatMessage array, e.g. [{\"sender\":\"User\",\"content\":\"...\"}]","items":{"type":"object","properties":{"sender":{"type":"string"},"content":{"type":"string"},"timestamp":{"type":"string"},"data":{"type":"object"}},"required":["sender","content"]}},"conversationId":{"type":"string","description":"Optional NexusGenAI conversation id"},"session_depth":{"type":"string","enum":["smart","deep"],"description":"Deprecated compatibility field. Both values use Aurora's adaptive routing policy."},"attachment_ids":{"type":"array","items":{"type":"string"},"description":"READY chat-attachment ids from upload_chat_attachment. Bound onto the last user message as fileAttachments."}},"required":["messages"]}},{"name":"star_agent","description":"Aurora agent surface (no LLM cost — pure DB write). Star or unstar a top-level agent for quick sidebar access. Mirrors PATCH /api/agent/:agentId/star. Address by agentId OR exact title (XOR). Omit starred to toggle.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id to star or unstar (XOR with title)"},"title":{"type":"string","description":"Exact case-insensitive user-assigned title (XOR with agentId)"},"starred":{"type":"boolean","description":"Optional explicit star state. Omit to toggle the current state."}},"required":[]}},{"name":"stop_agent","description":"Aurora agent surface (no LLM cost — pure state transition). Only relevant when actively managing an Aurora agent. Stop a running agent. Sends a cancellation request and cascades to all descendant subagents. The agent must be in an active state (running, initializing, pending approval, etc.).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id to stop"}},"required":["agentId"]}},{"name":"unarchive_agent","description":"Aurora agent surface (no LLM cost — pure DB write). Only relevant when managing Aurora agents. Restore an archived agent so it appears in default agent listings again. Address by agentId OR exact title (XOR).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"agentId":{"type":"string","description":"MongoDB agent _id to unarchive (XOR with title)"},"title":{"type":"string","description":"Exact case-insensitive user-assigned title (XOR with agentId)"}},"required":[]}},{"name":"update_portfolio","description":"Deploy, undeploy, rename, delete, add/remove/replace strategies, or set deployment frequency on portfolios. **rename** requires a non-empty `name` on the operation. **delete** permanently removes a chat, paper, or live portfolio (archives deployed paper/live books; deleting a chat portfolio also archives linked deployments). Pass confirmLive:true only after explicit user confirmation when deleting an active live portfolio. **Structured path (zero LLM cost):** pass an `operations` array — see inputSchema. Use `replaceStrategy` / `replaceStrategies` with full `{name, condition, action, orderExecution?}` strategyObjects (same shape as create_portfolio). `orderExecution` defaults to Market; true waiting Limits use UnitPrice for shares/crypto or MinimumNetCredit/MaximumNetDebit for options, whose amount may be an indicator (such as OptionSpreadEntryPrice plus a Value) evaluated when the strategy fires. QuoteRelative normally executes immediately at the snapshotted quote. RebalanceOption: set `action.positionScope` to `portfolio` (single-book — closes/orphans all option spreads in the portfolio) or `strategy` (multi-strategy book).","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"operations":{"type":"array","description":"Array of edit operations. Each operation needs \"portfolioId\" (live, paper, or chat — server resolves automatically). Supported types include \"rename\" (requires non-empty \"name\"), \"delete\" (permanently remove a chat/paper/live portfolio; archives deployed books; pass confirmLive:true only after explicit user confirmation when deleting an active live portfolio). DEPLOY SAFETY: deploying a chat portfolio ID creates a NEW PAPER-TRADING portfolio (simulated money, no broker order ever placed). It cannot place real-money trades. A LIVE/real-brokerage deployment only happens when the target is an EXISTING real-brokerage portfolio (re-activating it, or addStrategies/replaceStrategies on a portfolio already connected to a live broker). You cannot create a live brokerage account from a chat portfolio through this tool. Fetch the portfolio first and use strategy IDs from the returned \"strategies\" array for removals. To add/replace strategies, pass FINISHED strategy objects ({name, condition, action, orderExecution?} — same shape as create_portfolio.strategies) via \"strategyObjects\" (or \"strategyObject\" for replaceStrategy). These are ingested deterministically with zero LLM cost; prefer them. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price. RebalanceOption `action.positionScope`: `\"portfolio\"` (default for single-book portfolios — rotation-close and open-skip span all option spreads in the portfolio) or `\"strategy\"` (only spreads this strategy opened; use when multiple RebalanceOption strategies share one portfolio). Set on `create_portfolio` strategies[].action or on `update_portfolio` replaceStrategy/replaceStrategies `strategyObject.action`. Examples: [{\"type\":\"deploy\",\"portfolioId\":\"id\"}, {\"type\":\"undeploy\",\"portfolioId\":\"id\"}, {\"type\":\"delete\",\"portfolioId\":\"id\"}, {\"type\":\"addStrategies\",\"portfolioId\":\"id\",\"strategyObjects\":[{\"name\":\"...\",\"condition\":{...},\"action\":{...},\"orderExecution\":{\"type\":\"Limit\",\"price\":{\"type\":\"UnitPrice\",\"amount\":150},\"workingTime\":{\"type\":\"Day\"}}}]}, {\"type\":\"removeStrategies\",\"portfolioId\":\"id\",\"strategyIds\":[\"strategyId\"]}, {\"type\":\"replaceStrategy\",\"portfolioId\":\"id\",\"targetStrategyId\":\"strategyId\",\"strategyObject\":{\"name\":\"...\",\"condition\":{...},\"action\":{\"type\":\"RebalanceOption\",\"positionScope\":\"portfolio\",...}}}, {\"type\":\"replaceStrategies\",\"portfolioId\":\"id\",\"strategyObjects\":[{\"name\":\"...\",\"condition\":{...},\"action\":{...}}]}, {\"type\":\"setDeploymentFrequency\",\"portfolioId\":\"id\",\"deploymentFrequency\":\"Constant\"}, {\"type\":\"rename\",\"portfolioId\":\"id\",\"name\":\"New Portfolio Name\"}]","items":{"type":"object","properties":{"type":{"type":"string","enum":["deploy","undeploy","addStrategies","removeStrategies","replaceStrategy","replaceStrategies","setDeploymentFrequency","rename","delete"]},"portfolioId":{"type":"string"},"name":{"type":"string"},"strategyObjects":{"type":"array","items":{"type":"object","description":"A trading strategy: a trigger condition + an action to take when the condition is true. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","properties":{"name":{"type":"string","description":"Human-readable strategy name."},"condition":{"$ref":"#/$defs/condition"},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"active":{"type":"boolean","description":"Whether the strategy is active (default true)."},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]}},"required":["name","condition","action"],"additionalProperties":true}},"strategyObject":{"type":"object","description":"A trading strategy: a trigger condition + an action to take when the condition is true. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","properties":{"name":{"type":"string","description":"Human-readable strategy name."},"condition":{"$ref":"#/$defs/condition"},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"active":{"type":"boolean","description":"Whether the strategy is active (default true)."},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]}},"required":["name","condition","action"],"additionalProperties":true},"strategyIds":{"type":"array","items":{"type":"string"}},"targetStrategyId":{"type":"string"},"targetStrategyName":{"type":"string"},"deploymentFrequency":{"type":"string","enum":["Constant","OpenClose"]},"confirmLive":{"type":"boolean"}},"required":["type","portfolioId"],"additionalProperties":false},"minItems":1,"maxItems":20}},"required":["operations"],"$defs":{"indicator":{"type":"object","description":"An indicator. Single permissive shape — the 'type' field selects one of ~90 indicator kinds; other fields are required only when that kind needs them. Server-side IndicatorFactory.validate enforces per-type rules. PoliticalTrades needs targetAsset, filer, metric, windowDays, amountBasis, instrument, and chamber; House and Senate are unified, so use chamber All unless explicitly filtering. Equity excludes confirmed option disclosures. Amount metrics use disclosed ranges and default to conservative LowerBound. CustomIndicator (alt-data): REQUIRED customIndicatorId (24-char hex ObjectId from list_custom_indicators or MCP session catalog); optional customIndicatorName is display-only. In DynamicRebalance/RebalanceOption/OpenOption pipelines omit targetAsset on asset-scoped CustomIndicators (binds per candidate). RebalanceDecisionMetric reads the prospective DynamicRebalance/RebalanceOption plan computed before the strategy condition and requires metric allocationDrift, plannedTurnover, estimatedCost, expectedBenefit, or netBenefit. Common kinds: Value (numeric constant; needs 'value'), Price (current asset price; needs 'targetAsset'), SimpleMovingAverage/ExponentialMovingAverage/RelativeStrengthIndex/BollingerBand/MaxDrawdown/MaxDrawup/MinimumPrice/MaximumPrice/PriceStandardDeviation/PriceMeanAbsoluteDeviation/PriceRateOfChange (need targetAsset+window; BollingerBand also numStandardDeviations), MovingAverageConvergenceDivergence (MACD; needs targetAsset; optional fastLength/slowLength/signalLength defaulting to 12/26/9 with slowLength > fastLength, interval Day|Hour|Minute default Day, and line macd|signal|histogram selecting which of the three MACD outputs to emit), AverageDirectionalIndex (Wilder ADX trend-strength system 0-100; needs targetAsset+window; optional line adx|plusDi|minusDi — ADX measures strength, +DI/-DI direction), RelativeVolume (RVOL; needs targetAsset+window; current bar volume divided by the mean volume of the trailing N completed bars, ~1.0 is its recent pace), Stochastic (needs targetAsset+window; optional smoothK/smoothD defaulting to 3/3 and line k|d), CommodityChannelIndex (CCI; needs targetAsset+window; optional constant defaulting to 0.015), WilliamsR (needs targetAsset+window; −100 to 0 scale), MoneyFlowIndex (MFI; needs targetAsset+window; volume-weighted 0-100), OnBalanceVolume (OBV; needs targetAsset; optional interval default Day), AccumulationDistribution (ADL; needs targetAsset; optional interval default Day), ChaikinMoneyFlow (CMF; needs targetAsset+window; −1 to +1 scale), DonchianChannel (needs targetAsset+window; optional line upper|lower|middle default upper), KeltnerChannel (needs targetAsset+window; optional multiplier default 2 and line upper|middle|lower default middle), Supertrend (needs targetAsset+window; optional multiplier default 3 and line value|direction default value, direction reads +1 up / −1 down), IchimokuCloud (needs targetAsset+window; optional spanLength default 52 and line tenkan|kijun|senkouA|senkouB|chikou default tenkan; lines unshifted), ParabolicSar (needs targetAsset; optional interval default Day, step default 0.02, maximum default 0.2), TrueRange/AverageTrueRange (need targetAsset; ATR also window), VWAP (needs targetAsset; resets each trading day), Plus/Minus/Multiply/Divide/Max/Min (need 'indicators' array of 2 sub-indicators), Negative/AbsoluteValue/SquareRoot (need 1 sub-indicator), Log (needs base + 1 sub-indicator), Exponentiation (needs exponent + 1 sub-indicator), CrossAbove/CrossBelow (need 2 sub-indicators), Correlation (rolling Pearson of two sub-indicators' returns; needs 2 sub-indicators + window with length >= 2), TrailingSum/IndicatorWindowAgo/IndicatorAtMinutesAfterOpen (compound; need indicators + window/length/minutesAfterOpen), IndicatorAtEntry (compound; the operand's value frozen at the last matching fill — needs 1 nested indicator + targetAsset + side + orderStatus), Fundamental/CompoundAnnualGrowthRate (need targetAsset + metric; CAGR also needs years), Economic/Index (need metric), DaysSinceOrder/MinutesSinceOrder/SumOrderQuantity/SumOrderAmount/LastOrderPrice (need targetAssets/targetAsset + side + orderStatus), DaysSinceStrategyFired/DaysSinceLastRebalanceOptionOrder (no fields), DaysSinceTransaction (transactionType + transactionStatus), IsAsset/IsNotAsset/IsAssetType/IsIndustry/IsIndexMember (need targetAsset + matchAsset/assetType/industry/index), OptionPositionValue/OptionPositionCount/OptionPositionPercentChange/OptionPositionMaxDrawdown/OptionDaysToExpiration/OptionDaysHeld/OptionCollateral/OptionSpreadCount/OptionSpreadEntryPrice/OptionUnrealizedPnL (optional underlying + optionType + direction + spreadType filters; OptionSpreadEntryPrice is the contract-weighted net entry price per share of the matching open spreads, positive for a debit and negative for a credit, with no value when none match), OptionRealizedPnL (net realized P&L on CLOSED option positions; the same optional underlying/optionType/direction/spreadType filters + optional lookbackDays), OptionRealizedPremium (realized premium still available to spend: closed short-option P&L minus premium already spent by 'percent of realized premium' opens; optional underlying + optional lookbackDays ONLY, and it rejects optionType/direction/spreadType), OptionGrossExposurePercent (no fields), DaysSinceAgent/MinutesSinceAgent/DaysSinceAlert/MinutesSinceAlert, Day/Month/Year/Date/CurrentTimeHours/CurrentTimeMinutes/CurrentTimeSeconds/MinutesAfterOpen/MinutesUntilClose, PortfolioValue/BuyingPower/InitialValue, PositionValue/PositionPercentChange/PositionMaxDrawdown/PositionMaxDrawup/UnderlyingMaxDrawdown.","properties":{"type":{"type":"string","enum":["DaysSinceAgent","MinutesSinceAgent","DaysSinceAlert","MinutesSinceAlert","StockReport","DaysUntilEarnings","DaysSinceEarnings","ImpliedVolatility","IVRank","IVPercentile","IVHVRatio","LastOrderPrice","Fundamental","Economic","CustomIndicator","Index","BollingerBand","RelativeStrengthIndex","MovingAverageConvergenceDivergence","AverageDirectionalIndex","RelativeVolume","Stochastic","CommodityChannelIndex","WilliamsR","MoneyFlowIndex","OnBalanceVolume","AccumulationDistribution","ChaikinMoneyFlow","DonchianChannel","KeltnerChannel","Supertrend","IchimokuCloud","ParabolicSar","PriceMeanAbsoluteDeviation","ExponentialMovingAverage","SimpleMovingAverage","PriceStandardDeviation","PriceRateOfChange","MaxDrawdown","MaxDrawup","MinimumPrice","MaximumPrice","IndicatorMeanAbsoluteDeviation","IndicatorExponentialMovingAverage","IndicatorSimpleMovingAverage","IndicatorStandardDeviation","IndicatorRateOfChange","DaysSinceOrder","DaysSinceOptionOrder","DaysSinceStrategyFired","DaysSinceLastRebalanceOptionOrder","MinutesSinceOptionOrder","MinutesSinceOrder","DaysSinceTransaction","InitialValue","BuyingPower","PositionValue","PositionPercentChange","PortfolioValue","RebalanceDecisionMetric","Value","Price","Plus","Minus","Multiply","Divide","Negative","AbsoluteValue","SquareRoot","Max","Min","Day","Month","Date","Year","CurrentTimeSeconds","CurrentTimeMinutes","CurrentTimeHours","TrailingSum","CompoundAnnualGrowthRate","Log","Exponentiation","SumOrderQuantity","SumOrderAmount","MinutesAfterOpen","OpeningPrice","PreviousClosingPrice","HighOfDay","LowOfDay","MinutesUntilClose","PriceChangeSinceOpen","GapSize","GapPercentage","TrueRange","AverageTrueRange","Volume","VWAP","BullishFairValueGap","BearishFairValueGap","IndicatorAtMinutesAfterOpen","IndicatorWindowAgo","IndicatorAtEntry","IsIndexMember","PoliticalTrades","InsiderTrades","IsIndustry","IsAssetType","IsAsset","IsNotAsset","CrossAbove","CrossBelow","Correlation","PositionMaxDrawdown","PositionMaxDrawup","UnderlyingMaxDrawdown","ConsecutiveTrue","CountTrue","OptionPositionValue","OptionPositionCount","OptionPositionPercentChange","OptionPositionMaxDrawdown","OptionDaysToExpiration","OptionDaysHeld","OptionCollateral","OptionSpreadCount","OptionSpreadEntryPrice","OptionUnrealizedPnL","OptionRealizedPnL","OptionRealizedPremium","OptionGrossExposurePercent"]},"name":{"type":"string","description":"Optional human-readable name. Auto-derived if omitted."},"customIndicatorId":{"type":"string","description":"REQUIRED when type is CustomIndicator. Mongo ObjectId hex string for the owned custom data source (see list_custom_indicators or MCP session instructions). Never omit — display name alone is rejected."},"customIndicatorName":{"type":"string","description":"Optional display label for CustomIndicator. Ignored for lookup; customIndicatorId is authoritative."},"value":{"type":"number","description":"Required for Value indicators (numeric constant)."},"targetAsset":{"type":"object","description":"The asset this indicator measures (most price/option indicators).","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"targetAssets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"description":"Multi-asset variant (position / order indicators)."},"matchAsset":{"type":"object","description":"IsAsset / IsNotAsset: the asset to match against.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"window":{"type":"object","description":"Rolling time window. e.g. {length:14, interval:'Day'} = trailing 14 trading days.","properties":{"length":{"type":"number","minimum":1},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]},"length":{"type":"number","description":"TrailingSum and similar — window length in days."},"indicators":{"type":"array","items":{"$ref":"#/$defs/indicator"},"description":"Sub-indicators for compound types (Plus, CrossAbove, etc.)."},"numStandardDeviations":{"type":"number","description":"BollingerBand: e.g. 2."},"metric":{"type":"string","description":"PoliticalTrades: NetAmount, BuyAmount, SellAmount, BuyCount, SellCount, DistinctBuyers. Fundamental/CompoundAnnualGrowthRate: financial metric (e.g. 'peRatio'). Economic: economic indicator (e.g. 'UNRATE'). Index: index symbol (e.g. 'VIX', 'SPX'). RebalanceDecisionMetric: allocationDrift, plannedTurnover, estimatedCost, expectedBenefit, or netBenefit."},"windowDays":{"type":"integer","minimum":1,"maximum":3650,"description":"PoliticalTrades / InsiderTrades trailing calendar days."},"filer":{"type":"string","description":"PoliticalTrades member full or last name; empty means all members."},"amountBasis":{"type":"string","enum":["LowerBound","Midpoint","UpperBound"],"description":"PoliticalTrades disclosed range endpoint. LowerBound is conservative."},"instrument":{"type":"string","enum":["Equity","Option","All"],"description":"PoliticalTrades instrument class. Equity excludes confirmed options."},"chamber":{"type":"string","enum":["All","House","Senate"],"description":"PoliticalTrades optional cohort filter. All combines House and Senate."},"years":{"type":"number","description":"CompoundAnnualGrowthRate: years over which to compute CAGR."},"base":{"type":"number","description":"Log: logarithm base (>0, ≠1)."},"exponent":{"type":"number","description":"Exponentiation: power exponent."},"minutesAfterOpen":{"type":"number","minimum":0,"maximum":390,"description":"IndicatorAtMinutesAfterOpen: 0–390."},"side":{"type":"string","enum":["Buy","Sell"],"description":"Order-side indicators: Buy or Sell."},"orderStatus":{"type":"string","enum":["Pending","Accepted","Pending User Approval","Canceled","Filled","Partially Filled"],"description":"Order-side indicators: filter by status."},"transactionType":{"type":"string","enum":["Deposit","Withdraw"],"description":"DaysSinceTransaction: Deposit or Withdraw."},"transactionStatus":{"type":"string","enum":["Pending","Canceled","Completed"],"description":"DaysSinceTransaction: transaction status."},"index":{"type":"string","enum":["SP500","NASDAQ100","DJIA"],"description":"IsIndexMember: point-in-time index id ('SP500', 'NASDAQ100', or 'DJIA')."},"industry":{"type":"string","description":"IsIndustry: industry tag."},"assetType":{"type":"string","description":"IsAssetType: e.g. 'Stock', 'Cryptocurrency'."},"message":{"type":"string","description":"DaysSinceAlert / MinutesSinceAlert: alert message to match."},"underlying":{"type":"string","description":"Option* indicators: underlying ticker (e.g. 'SPY')."},"optionType":{"type":"string","enum":["call","put"],"description":"Option* indicators: call or put."},"direction":{"type":"string","enum":["long","short"],"description":"Option* indicators: long or short."},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"],"description":"Option* indicators: vertical, ironCondor, etc."},"minOrMax":{"type":"string","enum":["min","max"],"description":"OptionDaysToExpiration / OptionDaysHeld: aggregate selector."},"positionEffect":{"type":"string","description":"Option* indicators: open or close."},"minDte":{"type":"number","description":"Option* indicators: min days to expiration."},"maxDte":{"type":"number","description":"Option* indicators: max days to expiration."},"lookbackDays":{"type":"integer","minimum":1,"maximum":36500,"description":"OptionRealizedPnL / OptionRealizedPremium: only count activity within this many days of the evaluation date. Omit for the whole life of the book."},"condition":{"$ref":"#/$defs/condition","description":"ConsecutiveTrue / CountTrue: the condition to evaluate over the window."},"compound":{"type":"boolean"},"form":{"type":"object","description":"Optional auto-generated form metadata. Usually omit; the server fills this.","additionalProperties":true}},"required":["type"],"additionalProperties":true},"condition":{"type":"object","description":"A condition tree (Bridge pattern). type='Base' compares lhs vs rhs with a comparator; type='And'/'Or' combine an array of nested conditions; type='Multi' fires when N nested conditions are true (count vs threshold); type='Then' is sequential — it fires when the last nested condition is true now and each earlier one was true at a strictly earlier tick within 'window' of the next, so it needs at least 2 conditions and a window with length > 0.","properties":{"type":{"type":"string","enum":["And","Or","Base","Multi","Then"]},"name":{"type":"string","description":"Optional name; auto-derived if omitted."},"lhs":{"$ref":"#/$defs/indicator","description":"Base only: left-hand indicator."},"rhs":{"$ref":"#/$defs/indicator","description":"Base only: right-hand indicator."},"comparison":{"type":"string","enum":["lessThan","greaterThan","lessThanOrEqual","greaterThanOrEqual","equal","notEqual"],"description":"Base / Multi only: how to compare."},"conditions":{"type":"array","items":{"$ref":"#/$defs/condition"},"description":"And / Or / Multi / Then only: nested conditions. Then reads them in order (at least 2)."},"value":{"type":"number","description":"Multi only: threshold count (>=1)."},"window":{"type":"object","description":"Then only: how long each step has to be followed by the next one, e.g. {length: 30, interval: 'Minute'}. length must be > 0.","properties":{"length":{"type":"number"},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]}},"required":["type"],"additionalProperties":true},"strategy":{"type":"object","description":"A trading strategy: a trigger condition + an action to take when the condition is true. Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","properties":{"name":{"type":"string","description":"Human-readable strategy name."},"condition":{"$ref":"#/$defs/condition"},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"active":{"type":"boolean","description":"Whether the strategy is active (default true)."},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]}},"required":["name","condition","action"],"additionalProperties":true},"orderExecution":{"type":"object","description":"Optional strategy-level `orderExecution` defaults to `{type:\"Market\"}`. For a true waiting Limit, use `{type:\"Limit\",price:{type:\"UnitPrice\",amount:...},workingTime:{type:\"Day\"|\"Minutes\",minutes?:...}}` on Buy/Sell stock or crypto strategies; use `MinimumNetCredit` or `MaximumNetDebit` for OpenOption/CloseOption. An option net limit `amount` may be an indicator instead of a number; it is evaluated when the strategy fires, e.g. `{type:\"Plus\",indicators:[{type:\"OptionSpreadEntryPrice\",underlying:\"SPX\",optionType:\"call\",direction:\"long\",spreadType:\"vertical\"},{type:\"Value\",value:0.5}]}` waits for a credit of at least the held debit spread's fill plus $0.50, and no order is placed when it has no positive value. `QuoteRelative` snapshots the current executable quote when the strategy fires, so it caps execution but normally does not wait for a user-named price.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Market"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Limit"},"price":{"oneOf":[{"type":"object","description":"Buy/Sell only. The maximum unit price for a buy or minimum unit price for a sell. Supports stocks and crypto.","properties":{"type":{"type":"string","const":"UnitPrice"},"amount":{"type":"number","minimum":1e-8}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for at least this net credit per share.","properties":{"type":{"type":"string","const":"MinimumNetCredit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"OpenOption/CloseOption only. Wait until the complete option structure can execute for no more than this net debit per share.","properties":{"type":{"type":"string","const":"MaximumNetDebit"},"amount":{"description":"Dollars per share: a positive number, or an indicator evaluated when the strategy fires (for example Plus of OptionSpreadEntryPrice and Value to price one spread off another spread's fill).","oneOf":[{"type":"number","minimum":1e-8},{"$ref":"#/$defs/indicator"}]}},"required":["type","amount"],"additionalProperties":false},{"type":"object","description":"Snapshot a marketable Limit from the current executable quote when the strategy fires. Valid for all order-producing strategy actions; this is a protection cap, not a user-named waiting price.","properties":{"type":{"type":"string","const":"QuoteRelative"},"reference":{"type":"string","const":"Current"}},"required":["type","reference"],"additionalProperties":false}]},"workingTime":{"oneOf":[{"type":"object","description":"Stocks/options expire after the current regular US session; crypto expires after a rolling 24 hours.","properties":{"type":{"type":"string","const":"Day"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"Minutes"},"minutes":{"type":"number","minimum":1}},"required":["type","minutes"],"additionalProperties":false}]}},"required":["type","price"],"additionalProperties":false}]},"action":{"type":"object","description":"The action to execute when the strategy's condition triggers. One of: Buy/Sell (stock or crypto with targetAsset+amount), Deposit/Withdraw (cash flow), Alert (send a message), DynamicRebalance (universe→pipeline→weightIndicator), LaunchAgent (spin up an Aurora agent), RebalanceOption (rank universe, rotate option book via structureTemplates; pair with CloseOption lifecycle exits), OpenOption (open via OptionsBuilder), CloseOption (close positions filtered by triggers).","oneOf":[{"type":"object","description":"Buy or Sell a stock/crypto position.","properties":{"type":{"type":"string","enum":["Buy","Sell"]},"targetAsset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"amount":{"type":"object","description":"Buy/Sell allocation. type: 'percent of portfolio', 'percent of buying power', 'percent of current positions', 'dollars', or 'number of assets'. amount: the value (e.g. amount:25, type:'percent of buying power').","properties":{"type":{"type":"string","enum":["percent of portfolio","percent of buying power","percent of current positions","dollars","number of assets"]},"amount":{"type":"number"}},"required":["type","amount"]}},"required":["type","targetAsset","amount"],"additionalProperties":true},{"type":"object","description":"Send an alert message (no order).","properties":{"type":{"type":"string","const":"Alert"},"message":{"type":"string"}},"required":["type","message"],"additionalProperties":true},{"type":"object","description":"Dynamic rebalance: filter/rank a universe by a pipeline, then allocate the selected equities. Without allocationPolicy, weightIndicator supplies score weights. With allocationPolicy, weightIndicator remains required for deterministic ranking and warmup fallback while the joint policy sizes selected names. exposurePolicy may independently scale total risky exposure. Book-level cash/deploy is deploymentPercent (0–100 number) — NOT totalBudget (RebalanceOption-only). perNameAllocation caps any single name. canSell optionally gates non-target full equity exits; target-weight trims remain enabled. A strategy condition may compare RebalanceDecisionMetric values because the prospective plan is computed before condition evaluation.","properties":{"type":{"type":"string","const":"DynamicRebalance"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"deploymentPercent":{"type":"number","minimum":0,"maximum":100,"description":"Percent of portfolio NAV to deploy (remainder cash). Do not use totalBudget here."},"perNameAllocation":{"type":"object","description":"Per-name cap for DynamicRebalance. type: 'percent of portfolio' or 'dollars' only — contracts, percent of buying power and percent of realized premium are rejected.","properties":{"type":{"type":"string","enum":["percent of portfolio","dollars"]},"amount":{"type":"number","exclusiveMinimum":0}},"required":["type","amount"],"additionalProperties":true},"canSell":{"$ref":"#/$defs/condition","description":"Candidate-bound condition evaluated for each held equity leaving the selected set. False or unavailable retains the position. Example: PositionPercentChange(candidate) >= 0 implements rotate winners only. Does not gate trims of still-selected names; deploymentPercent=0 overrides it for a full cash-out."},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator"],"additionalProperties":true},{"type":"object","description":"Launch an Aurora agent (paid LLM action — costs research tokens per run; ensure cooldownMinutes is sensible).","properties":{"type":{"type":"string","const":"LaunchAgent"},"planningModel":{"type":"string"},"executionModel":{"type":"string"},"initialMessage":{"type":"string"},"maxIterations":{"type":"number","minimum":1},"includeMarketData":{"type":"boolean"},"continueExisting":{"type":"boolean"},"skipPlanning":{"type":"boolean"},"cooldownMinutes":{"type":"number","minimum":0}},"required":["type","planningModel","executionModel","initialMessage","maxIterations","includeMarketData","continueExisting","skipPlanning"],"additionalProperties":true},{"type":"object","description":"Open a new options position via the OptionsBuilder. Use 'against' to write a leg against an existing parent option position.","properties":{"type":{"type":"string","const":"OpenOption"},"builder":{"type":"object","description":"OpenOption builder: resolve contracts at execution time. Use underlyingSymbol for a fixed ticker, OR dynamicUnderlying for per-strategy universe selection. For coordinated multi-name option rotation with shared totalBudget and ranked selection, use action type RebalanceOption instead.","properties":{"underlyingSymbol":{"type":"string"},"dynamicUnderlying":{"type":"object","properties":{"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"limit":{"type":"number","minimum":1}},"required":["universe"],"additionalProperties":true},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"allocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"against":{"type":"object","additionalProperties":true,"description":"Optional parent-position selector (e.g. for covered calls)."}},"required":["type","builder"],"additionalProperties":true},{"type":"object","description":"RebalanceOption: filter/rank a universe, select top-N by weightIndicator (ranking score, not sizing weight), then allocate per-underlying premium budgets. allocationPolicy may jointly size the selected underlyings; exposurePolicy may independently scale the total premium budget using selected-underlying volatility (not option-P&L volatility). Use DaysSinceLastRebalanceOptionOrder in strategy conditions for shared rebalance cadence. A condition may also compare RebalanceDecisionMetric values because the prospective plan is computed first. Keep take-profit/stop-loss/DTE/short-leg exits in separate CloseOption strategies — not inside RebalanceOption. For unequal per-name sizing without a policy, use sleeves (each with its own perNameAllocation) under one totalBudget.","properties":{"type":{"type":"string","const":"RebalanceOption"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"totalBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1},"positionScope":{"type":"string","enum":["portfolio","strategy"],"description":"Which option spreads this rebalance manages. portfolio: rotation-close and open-skip apply portfolio-wide (recommended for single-book portfolios). strategy: only spreads opened by this strategy (multi-strategy books). Omit on new strategies → portfolio in TS/UI; legacy persisted docs without this field deserialize to strategy in Rust until backfilled."},"sleeves":{"type":"array","items":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}},"allocationPolicy":{"description":"Optional joint allocator applied after universe filtering/ranking. Supports MeanVariance, RiskParity, and MaximumDiversification using point-in-time completed daily returns. Selection remains the pipeline/weightIndicator responsibility; this policy sizes the selected names. If warmup history is insufficient, the existing score-weighted allocator is used deterministically.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"MeanVariance"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"riskAversion":{"type":"number","minimum":0,"maximum":1000},"expectedReturnShrinkage":{"type":"number","minimum":0,"maximum":1},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","riskAversion","expectedReturnShrinkage","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"RiskParity"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"MaximumDiversification"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"turnoverPenalty":{"type":"number","minimum":0,"maximum":10000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","turnoverPenalty","estimatedTransactionCostBps"],"additionalProperties":false}]},"exposurePolicy":{"type":"object","description":"Optional volatility-target exposure overlay, independent from allocationPolicy. Scales risky weights or option premium budgets down using selected-underlying historical volatility; never adds leverage beyond the action cap. For RebalanceOption this targets underlying volatility and scales premium budget, not option-P&L volatility.","properties":{"type":{"type":"string","const":"VolatilityTarget"},"lookbackPeriods":{"type":"integer","minimum":2,"maximum":5000},"minimumObservations":{"type":"integer","minimum":2,"maximum":5000},"covarianceShrinkage":{"type":"number","minimum":0,"maximum":1},"targetAnnualizedVolatilityPercent":{"type":"number","minimum":0,"maximum":1000},"estimatedTransactionCostBps":{"type":"number","minimum":0,"maximum":10000}},"required":["type","lookbackPeriods","minimumObservations","covarianceShrinkage","targetAnnualizedVolatilityPercent","estimatedTransactionCostBps"],"additionalProperties":false}},"required":["type","universe","pipeline","weightIndicator","structureTemplates"],"additionalProperties":true},{"type":"object","description":"Close existing options positions. Position selectors (underlyings, optionType, direction, spreadType) are AND gates; triggers[] groups are OR gates.","properties":{"type":{"type":"string","const":"CloseOption"},"underlyings":{"type":"array","items":{"type":"string"}},"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"closeScope":{"type":"string","enum":["spread","leg"]},"triggers":{"type":"array","items":{"type":"object","description":"Close trigger for an options exit. Triggers within an array are OR-gated.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"pnl"},"minPnlPercent":{"type":"number"},"maxPnlPercent":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"dte"},"minDte":{"type":"number"},"maxDte":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"daysHeld"},"minDaysHeld":{"type":"number"},"maxDaysHeld":{"type":"number"}},"required":["type"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"greeks"},"minSpreadDelta":{"type":"number"},"maxSpreadDelta":{"type":"number"},"minIv":{"type":"number"},"maxIv":{"type":"number"},"minSpreadTheta":{"type":"number"},"maxSpreadTheta":{"type":"number"}},"required":["type"],"additionalProperties":true}]}},"quantity":{"type":"object","description":"How many contracts to close. Defaults to all matching when omitted.","additionalProperties":true}},"required":["type"],"additionalProperties":true}]},"asset":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true},"window":{"type":"object","description":"Rolling time window. e.g. {length:14, interval:'Day'} = trailing 14 trading days.","properties":{"length":{"type":"number","minimum":1},"interval":{"type":"string","enum":["Day","Hour","Minute"]}},"required":["length","interval"]},"deploymentBudget":{"type":"object","description":"Book-level deployment cap for RebalanceOption (totalBudget). percent of portfolio: fraction of NAV; dollars: fixed dollars.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio"]},"amount":{"type":"number","minimum":0}},"required":["type","amount"],"additionalProperties":true},"optionStructureTemplate":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"rebalanceOptionSleeve":{"type":"object","description":"RebalanceOption sleeve for heterogeneous universe/ranking/sizing groups sharing one action-level totalBudget (sleeves cannot define totalBudget).","properties":{"name":{"type":"string"},"universe":{"type":"object","description":"Universe of candidate assets. source ALL_US_STOCKS or CRYPTO needs no other field. SPECIFIC_ASSETS requires assets[].","properties":{"source":{"type":"string","enum":["ALL_US_STOCKS","SP500","NASDAQ100","DJIA","CRYPTO","SPECIFIC_ASSETS"]},"assets":{"type":"array","items":{"type":"object","description":"Asset reference. Stock/Crypto/Option/Other. Stocks use {type:'Stock', symbol:'AAPL', name:'Apple Inc.'}.","properties":{"type":{"type":"string","enum":["Stock","Cryptocurrency","Option","Other"]},"symbol":{"type":"string"},"name":{"type":"string"}},"required":["type","symbol"],"additionalProperties":true}}},"required":["source"],"additionalProperties":true},"pipeline":{"type":"array","items":{"type":"object","description":"Universe pipeline stage (DynamicRebalance and RebalanceOption). Filter: applies a condition. SelectTop: keeps top-N ranked by an indicator. SelectPercentile: keeps assets at/above a percentile.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"Filter"},"condition":{"$ref":"#/$defs/condition"}},"required":["type","condition"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectTop"},"metric":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","limit","direction"],"additionalProperties":true},{"type":"object","properties":{"type":{"type":"string","const":"SelectPercentile"},"metric":{"$ref":"#/$defs/indicator"},"percentile":{"type":"number","minimum":0,"maximum":100},"direction":{"type":"string","enum":["Highest","Lowest"]}},"required":["type","metric","percentile","direction"],"additionalProperties":true}]}},"weightIndicator":{"$ref":"#/$defs/indicator"},"limit":{"type":"number","minimum":1},"perNameAllocation":{"type":"object","description":"Allocation for an options position (OpenOption.allocation) or per-name cap (RebalanceOption.perNameAllocation). On OpenOption.allocation, type 'percent of realized premium' spends a percent of the OptionRealizedPremium balance (closed short-option P&L minus premium already spent this way, never gross premium collected) and resolves to 0 while that balance is not positive, so it needs no separate balance condition. Its amount must be at most 100, because more would spend more than the realized balance. DynamicRebalance also takes a `perNameAllocation`, but only accepts type 'percent of portfolio' or 'dollars'.","properties":{"type":{"type":"string","enum":["dollars","percent of portfolio","percent of buying power","contracts","percent of realized premium"]},"amount":{"type":"number"}},"required":["type","amount"],"additionalProperties":true},"structureTemplates":{"type":"array","items":{"type":"object","description":"RebalanceOption structure template. Optional eligibility gates the template; legs define the spread; templates are tried in order — at most one open per underlying per rebalance pass.","properties":{"name":{"type":"string"},"eligibility":{"$ref":"#/$defs/condition"},"legs":{"type":"array","items":{"type":"object","description":"Single leg of an option builder.","properties":{"optionType":{"type":"string","enum":["call","put"]},"direction":{"type":"string","enum":["long","short"]},"expirationSelector":{"type":"object","properties":{"minDaysToExpiration":{"type":"number","minimum":0},"maxDaysToExpiration":{"type":"number","minimum":0},"preference":{"type":"string","enum":["nearest","middle","furthest"]}},"required":["minDaysToExpiration","maxDaysToExpiration","preference"]},"strikeSelector":{"type":"object","properties":{"distanceType":{"type":"string","description":"'percent', 'dollars', or 'delta' — how strike distance is measured from ATM."},"distance":{"type":"number","description":"Distance from ATM. Calls: positive = OTM (higher strike). Puts: positive = OTM (lower strike). 0 = ATM. For 'percent' this is a WHOLE-NUMBER percent — 15 means 15% OTM; 0.15 is rejected, not read as 15%. For 'delta' it is the absolute target delta (0-1, exclusive)."}},"required":["distanceType","distance"]},"fallbackStrikeSelector":{"type":"object","description":"Non-delta fallback used when distanceType is 'delta' and no contract resolves close enough to the requested delta. The resolver's own rejection names this field: \"Set a fallbackStrikeSelector (percent or dollars) to keep thin chains tradeable.\" Without it a thin chain fails the leg outright. distanceType here must be 'percent' or 'dollars' — a delta fallback is rejected.","properties":{"distanceType":{"type":"string","enum":["percent","dollars"]},"distance":{"type":"number"}},"required":["distanceType","distance"],"additionalProperties":false},"strikeRange":{"type":"object","description":"Optional fallback search window used when the target strike is unaffordable. startDistance/endDistance are %-OTM offsets measured from ATM, in the same units and sign as strikeSelector.distance (positive = OTM for calls and puts alike) — NOT offsets from the target strike.","additionalProperties":true},"ratio":{"type":"number"},"greekFilter":{"type":"object","description":"Optional min/max constraints on Greeks during resolution.","additionalProperties":true},"liquidityFilter":{"type":"object","description":"Optional bid/ask constraints during resolution. maxSpreadPct is (ask-bid)/mid and is preferred over maxSpreadAbsolute, since $0.50 is 50% of a $1.00 contract and 1.7% of a $30.00 one; when both are set both must pass. minBid excludes contracts that cannot be sold into. Contracts with no real NBBO quote are always rejected.","properties":{"maxSpreadPct":{"type":"number"},"maxSpreadAbsolute":{"type":"number"},"minBid":{"type":"number"}},"additionalProperties":false},"expirationRange":{"type":"object","additionalProperties":true}},"required":["optionType","direction","expirationSelector","strikeSelector"],"additionalProperties":true},"minItems":1},"spreadType":{"type":"string","enum":["vertical","calendar","diagonal","ironCondor","straddle","strangle","custom"]},"widthConstraint":{"type":"object","description":"Minimum realised strike width, checked AFTER contracts resolve. Each leg snaps independently to the nearest listed strike, so the authored offsets and the width you actually get differ by up to a full strike-grid step in either direction — a 3% short-leg offset on LLY's $20 Mar-2027 grid resolved to one $20 step, 1.76% of spot. minWidthPercent is a WHOLE-NUMBER percent of spot (4 = 4%). When both bounds are set, both must pass. A structure below the floor is rejected and the next structureTemplate in the ladder is tried; single-leg structures have no width and are exempt.","properties":{"minWidthPercent":{"type":"number","exclusiveMinimum":0},"minWidthDollars":{"type":"number","exclusiveMinimum":0}},"additionalProperties":false}},"required":["legs"],"additionalProperties":true},"minItems":1}},"required":["name"],"additionalProperties":true}}}}],"scan":{"score":97,"grade":"A","scanned_at":"2026-11-03T19:43:08.024Z","report":{"scannerVersion":"0.1.10","scannedAt":"2026-11-03T19:43:07.974Z","components":{"code":{"score":-1,"max":25,"notes":["remote-only server, no package to scan"]},"reliability":{"score":20,"max":20,"notes":["remote reachable in 211ms (auth required)"]},"poisoning":{"score":-1,"max":15,"notes":["tools not inspected (endpoint requires auth); not counted"]},"auth":{"score":15,"max":15,"notes":["OAuth resource metadata advertised on 401"]},"maintenance":{"score":15,"max":15,"notes":["last push 4 days ago"]},"identity":{"score":8,"max":10,"notes":["registry namespace matches repository owner","GitHub account older than a year"]}},"findings":[],"inputs":{"probes":[{"url":"https://nexustrade.io/api/mcp","reachable":true,"authRequired":true,"latencyMs":211,"authScheme":"oauth"}],"packages":[],"repo":{"found":true,"owner":"austin-starks","repo":"nexustrade-ts","archived":false,"pushedAt":"2026-10-30T21:19:02Z","stars":10,"forks":0,"openIssues":0,"ownerType":"User","ownerAvatarUrl":"https://avatars.githubusercontent.com/u/53793927?v=4","ownerCreatedAt":"2019-08-05T18:46:15Z","license":"MIT"},"icon":{"url":"https://nexustrade.io/logo192.jpeg","source":"registry"},"presence":{"stars":10,"forks":0,"downloadsWeek":null,"license":"MIT","lastPushAt":"2026-10-30T21:19:02.000Z","score":33}}}},"grade_history":[{"kind":"restore","fromGrade":"B","toGrade":"A","reason":"score 97","createdAt":"2026-11-03T19:43:08.426Z"}],"reviews":[]}