Run an options strategy over history and get back the equity curve, every trade, the positions
they belong to and the performance statistics.
Describe the strategy in the request body: the legs and how their strikes and expiries are chosen, how
positions are sized, when they are closed, and the cost model. See
Strategy specification for every field.
Denomination is coin. Inverse options are quoted and settled in the base coin, so equity, premiums
and P&L are in BTC (or ETH). equity_usd is a derived reading alongside.
Lookback.start must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on
quarterly, full history (from September 2021) on annual. An earlier start returns 403. The
Sandmark-Backtest-Window-Start response header gives your earliest allowed date.
Warnings are part of the result. Degraded fills, carried marks and bars the option chain could not
serve are counted in warnings and diagnostics. Read them before trusting a number.
Not decoration. Silent data holes are the main way an options backtest lies, so degraded fills, carried marks and bars the chain could not serve are counted here.
{
"statusCode": 429,
"message": "Rate limit is exceeded. Try again in 31 seconds."
}
{"docsConfig":{"theme":"maple","$schema":"https://mintlify.com/docs.json","name":"Sandmark API","description":"Volatility data and options backtesting for crypto, by Sandmark.","colors":{"primary":"#8A6D45","light":"#D5B17F","dark":"#8A6D45"},"logo":{"light":"https://mintcdn.com/sandmark-volatility/DfFiCOrERgX9yGgQ/logo/light.svg?fit=max\u0026auto=format\u0026n=DfFiCOrERgX9yGgQ\u0026q=85\u0026s=f6c18ca925e51a40b7c6b3b221000e0b","dark":"https://mintcdn.com/sandmark-volatility/DfFiCOrERgX9yGgQ/logo/dark.svg?fit=max\u0026auto=format\u0026n=DfFiCOrERgX9yGgQ\u0026q=85\u0026s=5ad9a39de9192b1c3d0c257654cf7fb4","href":"https://sandmark.com"},"favicon":"https://mintcdn.com/sandmark-volatility/DfFiCOrERgX9yGgQ/favicon.svg?fit=max\u0026auto=format\u0026n=DfFiCOrERgX9yGgQ\u0026q=85\u0026s=6bd620f27eb0b8bd4eba4fdd5802b4dd","api":{"openapi":["api-reference/openapi.json","api-reference/backtest-openapi.json"],"playground":{"display":"interactive"},"examples":{"languages":["curl","python","javascript"]}},"appearance":{"default":"dark"},"background":{"color":{"light":"#FBF9F6","dark":"#1A191D"}},"navbar":{"links":[{"href":"https://sandmark.com","label":"sandmark.com"}],"primary":{"type":"button","label":"Dashboard","href":"https://analytics.sandmark.com"}},"footer":{"links":[{"header":"Sandmark","items":[{"label":"Website","href":"https://sandmark.com"},{"label":"Analytics","href":"https://analytics.sandmark.com"},{"label":"Help","href":"https://analytics.sandmark.com/help"}]}]},"seo":{"metatags":{"og:site_name":"Sandmark API","canonical":"https://docs.sandmark.com"}},"fonts":{"heading":{"family":"Inter Tight","weight":600},"body":{"family":"Inter"}},"contextual":{"options":["copy","view","claude","chatgpt"],"display":"header"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"sandmark-volatility","hasAudioNarration":false,"actualSubdomain":"sandmark-volatility","customDomains":["docs.sandmark.com"],"gitSource":{"type":"artifacts","owner":"prod","repo":"6cf7fede4c79595fd5b4e2c2","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":"","_id":"6aee5b992fc7fbb43762d6c4"},"entitlements":{},"buildId":"6af19729b33f36baf0115023","clientVersion":"0.0.4088","searchFilterCounts":[{"language":"default","tag":"Guides","count":11},{"language":"default","tag":"Backtesting","count":9},{"language":"default","tag":"API reference","count":6},{"language":"default","tag":"Reference","count":4},{"language":"default","tag":"Reference data","count":3},{"language":"default","tag":"Get started","count":3},{"language":"default","tag":"Concepts","count":3},{"language":"default","tag":"Timeseries","count":2},{"language":"default","tag":"Operations","count":1}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":true},"customCss":[{"filePath":"style.css","content":":root{--sm-gold: #d5b17f;--sm-gold-deep: #8a6d45;--sm-ink: #252329;--sm-hairline: rgba(37, 35, 41, 0.1);--sm-hero-bg: radial-gradient(120% 140% at 0% 0%, #f7efe5 0%, #fbf9f6 55%);--sm-hero-text: #252329;--sm-hero-muted: #5a575e}:root.dark{--sm-hairline: rgba(244, 242, 244, 0.08);--sm-hero-bg: radial-gradient(120% 140% at 0% 0%, #3a3329 0%, #1a191d 60%);--sm-hero-text: #f4f2f4;--sm-hero-muted: #aeaeb2}.sm-hero{position:relative;overflow:hidden;margin:0 0 2.5rem;padding:3rem 2.5rem;border:1px solid var(--sm-hairline);border-radius:1.25rem;background:var(--sm-hero-bg)}.sm-hero::after{content:\"\";position:absolute;right:-6rem;top:-6rem;width:22rem;height:22rem;border-radius:50%;background:radial-gradient(closest-side, rgba(213, 177, 127, 0.18), transparent);pointer-events:none}.sm-eyebrow{margin:0 0 0.75rem;font-size:0.75rem;font-weight:600;letter-spacing:0.14em;text-transform:uppercase;color:var(--sm-gold-deep)}:root.dark .sm-eyebrow{color:var(--sm-gold)}.sm-hero-title{margin:0;max-width:34rem;font-family:\"Inter Tight\", Inter, sans-serif;font-size:clamp(1.9rem, 4vw, 2.75rem);font-weight:600;line-height:1.1;letter-spacing:-0.02em;color:var(--sm-hero-text)}.sm-hero-lede{margin:1.1rem 0 0;max-width:40rem;font-size:1.05rem;line-height:1.65;color:var(--sm-hero-muted)}.sm-hero-actions{display:flex;flex-wrap:wrap;gap:0.75rem;margin-top:1.75rem}.sm-btn{display:inline-flex;align-items:center;padding:0.6rem 1.3rem 0.7rem;border-radius:999px;font-size:0.95rem;font-weight:500;text-decoration:none!important;border-bottom:none!important;color:var(--sm-hero-text)!important;box-shadow:inset 0 0 0 1.5px var(--sm-hairline), inset 0 0 0 1.5px rgba(138, 109, 69, 0.45);transition:background 180ms cubic-bezier(0.4, 0, 0.2, 1), color 180ms cubic-bezier(0.4, 0, 0.2, 1)}.sm-btn:hover{background:rgba(213, 177, 127, 0.12)}.sm-btn-primary{background:var(--sm-gold);color:var(--sm-ink)!important;box-shadow:none}.sm-btn-primary:hover{background:#e2c49b}@media (max-width: 640px){.sm-hero{padding:2rem 1.25rem}}"}],"page":{"pagePath":"api-reference/run-backtest","slug":"/api-reference/run-backtest","pageMetadata":{"openapi":"api-reference/backtest-openapi.json POST /v1/backtest","title":"Run a backtest","description":"Run an options strategy over history and get back the equity curve, every trade, the positions\nthey belong to and the performance statistics.\n\nDescribe the strategy in the request body: the legs and how their strikes and expiries are chosen, how\npositions are sized, when they are closed, and the cost model. See\n[Strategy specification](/backtesting/strategy-spec) for every field.\n\n**Denomination is coin.** Inverse options are quoted and settled in the base coin, so equity, premiums\nand P\u0026L are in BTC (or ETH). `equity_usd` is a derived reading alongside.\n\n**Lookback.** `start` must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on\nquarterly, full history (from September 2021) on annual. An earlier `start` returns `403`. The\n`Sandmark-Backtest-Window-Start` response header gives your earliest allowed date.\n\n**Warnings are part of the result.** Degraded fills, carried marks and bars the option chain could not\nserve are counted in `warnings` and `diagnostics`. Read them before trusting a number.","href":"/api-reference/run-backtest"},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n a: \"a\",\n code: \"code\",\n p: \"p\",\n strong: \"strong\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsx(_components.p, {\n children: \"Run an options strategy over history and get back the equity curve, every trade, the positions\\nthey belong to and the performance statistics.\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Describe the strategy in the request body: the legs and how their strikes and expiries are chosen, how\\npositions are sized, when they are closed, and the cost model. See\\n\", _jsx(_components.a, {\n href: \"/backtesting/strategy-spec\",\n children: \"Strategy specification\"\n }), \" for every field.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Denomination is coin.\"\n }), \" Inverse options are quoted and settled in the base coin, so equity, premiums\\nand P\u0026L are in BTC (or ETH). \", _jsx(_components.code, {\n children: \"equity_usd\"\n }), \" is a derived reading alongside.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Lookback.\"\n }), \" \", _jsx(_components.code, {\n children: \"start\"\n }), \" must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on\\nquarterly, full history (from September 2021) on annual. An earlier \", _jsx(_components.code, {\n children: \"start\"\n }), \" returns \", _jsx(_components.code, {\n children: \"403\"\n }), \". The\\n\", _jsx(_components.code, {\n children: \"Sandmark-Backtest-Window-Start\"\n }), \" response header gives your earliest allowed date.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Warnings are part of the result.\"\n }), \" Degraded fills, carried marks and bars the option chain could not\\nserve are counted in \", _jsx(_components.code, {\n children: \"warnings\"\n }), \" and \", _jsx(_components.code, {\n children: \"diagnostics\"\n }), \". Read them before trusting a number.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,p:`p`,..._provideComponents(),...props.components},{Tip}=_components;if(!Tip)_missingMdxReference(`Tip`,true);return _jsx(Tip,{children:_jsxs(_components.p,{children:[`Start from a `,_jsx(_components.a,{href:`/backtesting/recipes`,children:`recipe`}),` rather than a blank spec, and see\n`,_jsx(_components.a,{href:`/backtesting/strategy-spec`,children:`Strategy specification`}),` for what every field does.`]})})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"openapi":"api-reference/backtest-openapi.json POST /v1/backtest","title":"Run a backtest","description":"Run an options strategy over history and get back the equity curve, every trade, the positions\nthey belong to and the performance statistics.\n\nDescribe the strategy in the request body: the legs and how their strikes and expiries are chosen, how\npositions are sized, when they are closed, and the cost model. See\n[Strategy specification](/backtesting/strategy-spec) for every field.\n\n**Denomination is coin.** Inverse options are quoted and settled in the base coin, so equity, premiums\nand P\u0026L are in BTC (or ETH). `equity_usd` is a derived reading alongside.\n\n**Lookback.** `start` must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on\nquarterly, full history (from September 2021) on annual. An earlier `start` returns `403`. The\n`Sandmark-Backtest-Window-Start` response header gives your earliest allowed date.\n\n**Warnings are part of the result.** Degraded fills, carried marks and bars the option chain could not\nserve are counted in `warnings` and `diagnostics`. Read them before trusting a number.","href":"/api-reference/run-backtest"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"operationId":"runBacktest","tags":["Backtesting"],"summary":"Run a backtest","description":"Run an options strategy over history and get back the equity curve, every trade, the positions\nthey belong to and the performance statistics.\n\nDescribe the strategy in the request body: the legs and how their strikes and expiries are chosen, how\npositions are sized, when they are closed, and the cost model. See\n[Strategy specification](/backtesting/strategy-spec) for every field.\n\n**Denomination is coin.** Inverse options are quoted and settled in the base coin, so equity, premiums\nand P\u0026L are in BTC (or ETH). `equity_usd` is a derived reading alongside.\n\n**Lookback.** `start` must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on\nquarterly, full history (from September 2021) on annual. An earlier `start` returns `403`. The\n`Sandmark-Backtest-Window-Start` response header gives your earliest allowed date.\n\n**Warnings are part of the result.** Degraded fills, carried marks and bars the option chain could not\nserve are counted in `warnings` and `diagnostics`. Read them before trusting a number.","parameters":["737a14bf-371d-49f0-9e58-07e7759e02b2","4f32a1d9-9af9-439c-98fa-779ce2f97179"],"requestBody":"5e0b5857-4285-4678-93f3-ea7ad3ad45fb","responses":{"200":"cd1bfed1-46e3-4ebc-8c07-752d8dde73fb","400":"9a228c62-9de8-40a4-b1f3-51792943bb2f","401":"57a1c2f3-77f5-48d1-9850-e9d54bba1360","403":"4267c587-adf0-4edb-9fa8-c07bcb425553","422":"66300027-4e1d-44b3-b8be-c6fcbed393e5","429":"9449cbfb-9d3a-4168-876c-be508f02d20b"},"method":"post","type":"path","servers":["5c242684-546d-45c8-b216-7dff445669a4"],"security":["c392e887-a03c-4c1f-9813-d9566cb91bd9"],"path":"/v1/backtest","baseUrlOptions":["https://api.sandmark.com/backtesting"],"title":"Run a backtest","codeSamples":[],"requestExampleLanguages":["bash","python","javascript"],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"737a14bf-371d-49f0-9e58-07e7759e02b2":{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","html","csv","xlsx"],"title":"FormatEnum","default":"json","isRequired":false,"description":"`json` for the full result, `html` for a self-contained report, `csv` for a zip of trades, positions and equity, `xlsx` for an Excel workbook.","uniqueKey":"","typeLabel":"enum\u003cstring>"},"description":"`json` for the full result, `html` for a self-contained report, `csv` for a zip of trades, positions and equity, `xlsx` for an Excel workbook."},"4f32a1d9-9af9-439c-98fa-779ce2f97179":{"name":"theme","in":"query","required":false,"schema":{"type":"string","enum":["light","dark"],"title":"ThemeEnum","default":"light","isRequired":false,"description":"Colour theme of the `html` report. Ignored for other formats.","uniqueKey":"","typeLabel":"enum\u003cstring>"},"description":"Colour theme of the `html` report. Ignored for other formats."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"start":{"type":"string","format":"date","title":"Start","description":"First day of the backtest, `YYYY-MM-DD`. Must fall inside your backtest lookback; data begins 2021-09-01.","isRequired":true,"uniqueKey":"start","typeLabel":"string\u003cdate>"},"end":{"type":"string","format":"date","title":"End","description":"Last day of the backtest, `YYYY-MM-DD`, inclusive.","isRequired":true,"uniqueKey":"end","typeLabel":"string\u003cdate>"},"structure":{"properties":{"legs":{"items":{"properties":{"id":{"type":"string","maxLength":40,"minLength":1,"title":"Id","description":"Your name for the leg, used by `shared_strike` and `leg:\u003cid>` rules.","isRequired":true,"uniqueKey":"structure.legs.items.[INDEX].id","typeLabel":"string"},"type":{"type":"string","enum":["call","put","future"],"title":"KindEnum","isRequired":true,"uniqueKey":"structure.legs.items.[INDEX].type","typeLabel":"enum\u003cstring>"},"direction":{"type":"string","enum":["long","short"],"title":"DirectionEnum","isRequired":true,"uniqueKey":"structure.legs.items.[INDEX].direction","typeLabel":"enum\u003cstring>"},"strike":{"oneOf":[{"type":"object","title":"StrikeSpec","description":"How the strike is chosen. Omit on a futures leg, which has none.","required":["value"],"properties":{"value":{"type":"number","title":"Value","description":"Delta, multiple of the forward, or price.","isRequired":true,"uniqueKey":"structure.legs.items.[INDEX].strike.oneOf.0.value","typeLabel":"number"},"by":{"type":"string","enum":["delta","moneyness","absolute"],"title":"StrikeByEnum","default":"delta","uniqueKey":"structure.legs.items.[INDEX].strike.oneOf.0.by","typeLabel":"enum\u003cstring>"}},"uniqueKey":"structure.legs.items.[INDEX].strike.oneOf.0","typeLabel":"StrikeSpec · object"},{"type":"null","description":"How the strike is chosen. Omit on a futures leg, which has none.","uniqueKey":"structure.legs.items.[INDEX].strike.oneOf.1","typeLabel":"null"}],"uniqueKey":"structure.legs.items.[INDEX].strike","typeLabel":"StrikeSpec · object | null"},"ratio":{"type":"number","exclusiveMinimum":0,"title":"Ratio","description":"Relative size. Sign lives in direction. Defaults to 1.0.","uniqueKey":"structure.legs.items.[INDEX].ratio","typeLabel":"number"},"expiry":{"oneOf":[{"type":"object","title":"ExpirySpec","description":"Per-leg override, which is what makes calendars expressible.","properties":{"by":{"type":"string","enum":["monthly","third_friday","listed"],"title":"ExpiryByEnum","default":"monthly","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.by","typeLabel":"enum\u003cstring>"},"nth":{"type":"integer","maximum":12,"minimum":1,"title":"Nth","description":"Defaults to 1.","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.nth","typeLabel":"integer"},"min_dte":{"type":"number","minimum":0,"title":"Min Dte","description":"Defaults to 0.0.","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.min_dte","typeLabel":"number"},"target_dte":{"oneOf":[{"type":"number","title":"Target Dte","description":"Aim for a tenor instead of clearing a floor. `min_dte` takes the first expiry above a threshold, which is right on an unbroken ladder; where the board thins out, a floor can land in a gap and silently take the far side of it. A target picks whichever listed expiry is nearest, so the realised tenor is the best the board can offer rather than an artifact of where the floor fell. Set this and `min_dte` becomes a floor the target is chosen above.","minimum":0,"uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.target_dte.oneOf.0","typeLabel":"number"},{"type":"null","title":"Target Dte","description":"Aim for a tenor instead of clearing a floor. `min_dte` takes the first expiry above a threshold, which is right on an unbroken ladder; where the board thins out, a floor can land in a gap and silently take the far side of it. A target picks whichever listed expiry is nearest, so the realised tenor is the best the board can offer rather than an artifact of where the floor fell. Set this and `min_dte` becomes a floor the target is chosen above.","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.target_dte.oneOf.1","typeLabel":"null"}],"uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.target_dte","typeLabel":"number | null"},"weekdays":{"oneOf":[{"type":"array","items":{"oneOf":[{"type":"string","title":"WeekdayEnum","description":"A day, by name, for the fields that gate on the calendar.\n\nThe numbers stay Monday 0, which is Python's own `date.weekday()` and what\nthese fields have always accepted. Names are here because a spec is read far\nmore often than it is written -- `[\"friday\"]` says what `[4]` only encodes,\nand the panel's Copy-spec payload is something a desk reads to work out what\nwas tested.","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],"uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.weekdays.oneOf.0.items.[INDEX].oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"integer","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.weekdays.oneOf.0.items.[INDEX].oneOf.1","typeLabel":"integer"}],"uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.weekdays.oneOf.0.items.[INDEX]","typeLabel":"enum\u003cstring> | integer"},"title":"Weekdays","description":"Settle only on these weekdays, by name or Monday-0 number. Deribit lists a daily contract alongside its weeklies and monthlies, so \"the Friday\" is not something a tenor can say on its own: at a 7-day target a Thursday daily is exactly as close as the Friday weekly. This narrows the ladder before anything else looks at it, so `nth`, `min_dte` and `target_dte` all count off what is left. Distinct from `by`, which picks a contract off the ladder rather than saying which contracts are on it: `by: listed` with `[\"friday\"]` is every Friday expiry, while `by: monthly` is the last Friday of each month. Omit for the whole ladder.","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.weekdays.oneOf.0","typeLabel":"(enum\u003cstring> | integer)[]"},{"type":"null","title":"Weekdays","description":"Settle only on these weekdays, by name or Monday-0 number. Deribit lists a daily contract alongside its weeklies and monthlies, so \"the Friday\" is not something a tenor can say on its own: at a 7-day target a Thursday daily is exactly as close as the Friday weekly. This narrows the ladder before anything else looks at it, so `nth`, `min_dte` and `target_dte` all count off what is left. Distinct from `by`, which picks a contract off the ladder rather than saying which contracts are on it: `by: listed` with `[\"friday\"]` is every Friday expiry, while `by: monthly` is the last Friday of each month. Omit for the whole ladder.","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.weekdays.oneOf.1","typeLabel":"null"}],"uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0.weekdays","typeLabel":"(enum\u003cstring> | integer)[] | null"}},"uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.0","typeLabel":"ExpirySpec · object"},{"type":"null","description":"Per-leg override, which is what makes calendars expressible.","uniqueKey":"structure.legs.items.[INDEX].expiry.oneOf.1","typeLabel":"null"}],"uniqueKey":"structure.legs.items.[INDEX].expiry","typeLabel":"ExpirySpec · object | null"}},"type":"object","required":["id","type","direction"],"title":"LegSpecModel","uniqueKey":"structure.legs.items.[INDEX]","typeLabel":"LegSpecModel · object"},"type":"array","maxItems":8,"minItems":1,"title":"Legs","isRequired":true,"uniqueKey":"structure.legs","typeLabel":"LegSpecModel · object[]"},"expiry":{"properties":{"by":{"type":"string","enum":["monthly","third_friday","listed"],"title":"ExpiryByEnum","default":"monthly","uniqueKey":"structure.expiry.by","typeLabel":"enum\u003cstring>"},"nth":{"type":"integer","maximum":12,"minimum":1,"title":"Nth","description":"Defaults to 1.","uniqueKey":"structure.expiry.nth","typeLabel":"integer"},"min_dte":{"type":"number","minimum":0,"title":"Min Dte","description":"Defaults to 0.0.","uniqueKey":"structure.expiry.min_dte","typeLabel":"number"},"target_dte":{"oneOf":[{"type":"number","title":"Target Dte","description":"Aim for a tenor instead of clearing a floor. `min_dte` takes the first expiry above a threshold, which is right on an unbroken ladder; where the board thins out, a floor can land in a gap and silently take the far side of it. A target picks whichever listed expiry is nearest, so the realised tenor is the best the board can offer rather than an artifact of where the floor fell. Set this and `min_dte` becomes a floor the target is chosen above.","minimum":0,"uniqueKey":"structure.expiry.target_dte.oneOf.0","typeLabel":"number"},{"type":"null","title":"Target Dte","description":"Aim for a tenor instead of clearing a floor. `min_dte` takes the first expiry above a threshold, which is right on an unbroken ladder; where the board thins out, a floor can land in a gap and silently take the far side of it. A target picks whichever listed expiry is nearest, so the realised tenor is the best the board can offer rather than an artifact of where the floor fell. Set this and `min_dte` becomes a floor the target is chosen above.","uniqueKey":"structure.expiry.target_dte.oneOf.1","typeLabel":"null"}],"uniqueKey":"structure.expiry.target_dte","typeLabel":"number | null"},"weekdays":{"oneOf":[{"type":"array","items":{"oneOf":[{"type":"string","title":"WeekdayEnum","description":"A day, by name, for the fields that gate on the calendar.\n\nThe numbers stay Monday 0, which is Python's own `date.weekday()` and what\nthese fields have always accepted. Names are here because a spec is read far\nmore often than it is written -- `[\"friday\"]` says what `[4]` only encodes,\nand the panel's Copy-spec payload is something a desk reads to work out what\nwas tested.","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],"uniqueKey":"structure.expiry.weekdays.oneOf.0.items.[INDEX].oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"integer","uniqueKey":"structure.expiry.weekdays.oneOf.0.items.[INDEX].oneOf.1","typeLabel":"integer"}],"uniqueKey":"structure.expiry.weekdays.oneOf.0.items.[INDEX]","typeLabel":"enum\u003cstring> | integer"},"title":"Weekdays","description":"Settle only on these weekdays, by name or Monday-0 number. Deribit lists a daily contract alongside its weeklies and monthlies, so \"the Friday\" is not something a tenor can say on its own: at a 7-day target a Thursday daily is exactly as close as the Friday weekly. This narrows the ladder before anything else looks at it, so `nth`, `min_dte` and `target_dte` all count off what is left. Distinct from `by`, which picks a contract off the ladder rather than saying which contracts are on it: `by: listed` with `[\"friday\"]` is every Friday expiry, while `by: monthly` is the last Friday of each month. Omit for the whole ladder.","uniqueKey":"structure.expiry.weekdays.oneOf.0","typeLabel":"(enum\u003cstring> | integer)[]"},{"type":"null","title":"Weekdays","description":"Settle only on these weekdays, by name or Monday-0 number. Deribit lists a daily contract alongside its weeklies and monthlies, so \"the Friday\" is not something a tenor can say on its own: at a 7-day target a Thursday daily is exactly as close as the Friday weekly. This narrows the ladder before anything else looks at it, so `nth`, `min_dte` and `target_dte` all count off what is left. Distinct from `by`, which picks a contract off the ladder rather than saying which contracts are on it: `by: listed` with `[\"friday\"]` is every Friday expiry, while `by: monthly` is the last Friday of each month. Omit for the whole ladder.","uniqueKey":"structure.expiry.weekdays.oneOf.1","typeLabel":"null"}],"uniqueKey":"structure.expiry.weekdays","typeLabel":"(enum\u003cstring> | integer)[] | null"}},"type":"object","title":"ExpirySpec","uniqueKey":"structure.expiry","typeLabel":"ExpirySpec · object"},"hedge":{"properties":{"enabled":{"type":"boolean","title":"Enabled","default":false,"uniqueKey":"structure.hedge.enabled","typeLabel":"boolean"},"greek":{"type":"string","enum":["delta","vega","gamma"],"title":"HedgeGreekEnum","description":"Which exposure to hedge. Delta uses dated futures. Vega and gamma cannot: a future's payoff is linear in spot, so its vega and gamma are zero and no quantity of it changes either -- those are hedged with a listed at-the-money option, and the delta that option carries is then hedged in futures underneath, so the run measures the exposure asked about rather than the direction the hedge added.","default":"delta","uniqueKey":"structure.hedge.greek","typeLabel":"enum\u003cstring>"},"option_delta":{"type":"number","exclusiveMaximum":1,"exclusiveMinimum":0,"title":"Option Delta","description":"Delta of the option used to hedge vega or gamma; 0.5 is at the money. Defaults to 0.5.","uniqueKey":"structure.hedge.option_delta","typeLabel":"number"},"option_min_dte":{"type":"number","minimum":0,"title":"Option Min Dte","description":"Floor on the hedge option's tenor, and the point it is rolled at. Worth setting per greek: vega lives in the back of the curve and gamma in the front. Defaults to 30.0.","uniqueKey":"structure.hedge.option_min_dte","typeLabel":"number"},"option_band":{"type":"number","minimum":0,"title":"Option Band","description":"Residual tolerated before rebalancing a vega or gamma hedge, as a fraction of the book's own greek. Relative because vega and gamma are not in comparable units; `band` stays absolute, for delta. Defaults to 0.1.","uniqueKey":"structure.hedge.option_band","typeLabel":"number"},"numeraire":{"type":"string","enum":["coin","usd"],"title":"NumeraireEnum","default":"coin","uniqueKey":"structure.hedge.numeraire","typeLabel":"enum\u003cstring>"},"band":{"type":"number","minimum":0,"title":"Band","description":"Drift tolerated before rebalancing. Defaults to 0.05.","uniqueKey":"structure.hedge.band","typeLabel":"number"},"holding_hedge_ratio":{"type":"number","maximum":1,"minimum":0,"title":"Holding Hedge Ratio","description":"Fraction of the coin balance to hedge on top of the option book. Only meaningful with numeraire=usd: in coin the holding has no delta, because one coin is always one coin. Defaults to 0.0.","uniqueKey":"structure.hedge.holding_hedge_ratio","typeLabel":"number"},"min_dte":{"type":"number","minimum":0,"title":"Min Dte","description":"Defaults to 1.0.","uniqueKey":"structure.hedge.min_dte","typeLabel":"number"},"match_expiry":{"type":"boolean","title":"Match Expiry","default":true,"uniqueKey":"structure.hedge.match_expiry","typeLabel":"boolean"},"allow_perpetual":{"type":"boolean","title":"Allow Perpetual","description":"Off by default: funding rates are absent from the warehouse, so a perpetual hedge carries a cost the backtest cannot see.","default":false,"uniqueKey":"structure.hedge.allow_perpetual","typeLabel":"boolean"}},"type":"object","title":"HedgeSpec","uniqueKey":"structure.hedge","typeLabel":"HedgeSpec · object"},"shared_strike":{"oneOf":[{"type":"string","title":"Shared Strike","description":"Id of the leg whose resolved strike every other leg adopts. This is what separates a straddle from a strangle: two legs asking for the same delta independently land on opposite sides of spot. Anchoring also makes the other leg's delta a consequence rather than a choice, so a straddle anchored on a 20-delta call carries an 80-delta put and is directional.","uniqueKey":"structure.shared_strike.oneOf.0","typeLabel":"string"},{"type":"null","title":"Shared Strike","description":"Id of the leg whose resolved strike every other leg adopts. This is what separates a straddle from a strangle: two legs asking for the same delta independently land on opposite sides of spot. Anchoring also makes the other leg's delta a consequence rather than a choice, so a straddle anchored on a 20-delta call carries an 80-delta put and is directional.","uniqueKey":"structure.shared_strike.oneOf.1","typeLabel":"null"}],"uniqueKey":"structure.shared_strike","typeLabel":"string | null"}},"type":"object","required":["legs"],"title":"StructureSpecModel","description":"The legs to trade, how their expiry is chosen, and an optional hedge.","isRequired":true,"uniqueKey":"structure","typeLabel":"StructureSpecModel · object"},"schema_version":{"type":"integer","maximum":1,"minimum":1,"title":"Schema Version","description":"Defaults to 1.","uniqueKey":"schema_version","typeLabel":"integer"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name","default":"backtest","uniqueKey":"name","typeLabel":"string"},"asset":{"type":"string","enum":["DER.BTC_USD","DER.ETH_USD","DER.SOL_USDC","DER.XRP_USDC"],"title":"AssetEnum","description":"Underlying to trade. Inverse BTC and ETH carry history from September 2021.","default":"DER.BTC_USD","uniqueKey":"asset","typeLabel":"enum\u003cstring>"},"clock":{"properties":{"decision_hour_utc":{"oneOf":[{"type":"integer","title":"Decision Hour Utc","description":"Hour the strategy looks, or null to look every hour. Defaults to expiry time, 08:00 UTC. Sampling one hour in twenty-four is what makes a multi-year run cheap: a year of BTC is 312k rows at one hour and 7.5M at all of them, 0.9s against 14s just to load. Null is therefore for short windows -- a run has 120 seconds in total.","maximum":23,"minimum":0,"uniqueKey":"clock.decision_hour_utc.oneOf.0","typeLabel":"integer"},{"type":"null","title":"Decision Hour Utc","description":"Hour the strategy looks, or null to look every hour. Defaults to expiry time, 08:00 UTC. Sampling one hour in twenty-four is what makes a multi-year run cheap: a year of BTC is 312k rows at one hour and 7.5M at all of them, 0.9s against 14s just to load. Null is therefore for short windows -- a run has 120 seconds in total.","uniqueKey":"clock.decision_hour_utc.oneOf.1","typeLabel":"null"}],"uniqueKey":"clock.decision_hour_utc","typeLabel":"integer | null"},"max_dte":{"oneOf":[{"type":"number","title":"Max Dte","description":"Prunes the load; contracts beyond this are never traded. Defaults to 400.","minimum":0,"exclusiveMinimum":true,"uniqueKey":"clock.max_dte.oneOf.0","typeLabel":"number"},{"type":"null","title":"Max Dte","description":"Prunes the load; contracts beyond this are never traded. Defaults to 400.","uniqueKey":"clock.max_dte.oneOf.1","typeLabel":"null"}],"uniqueKey":"clock.max_dte","typeLabel":"number | null"},"trim_to_first_trade":{"type":"boolean","title":"Trim To First Trade","description":"Start the reported curve at the first bar holding a position. A window opened before the data supports trading otherwise reports months of flat equity, inflating the duration and deflating the CAGR.","default":true,"uniqueKey":"clock.trim_to_first_trade","typeLabel":"boolean"}},"type":"object","title":"ClockSpec","description":"When the strategy looks at the market.","uniqueKey":"clock","typeLabel":"ClockSpec · object"},"capital":{"properties":{"initial_equity":{"type":"number","exclusiveMinimum":0,"title":"Initial Equity","description":"Denominated in coin. Defaults to 100.0.","uniqueKey":"capital.initial_equity","typeLabel":"number"},"sizing":{"properties":{"mode":{"type":"string","enum":["contracts","coin_notional","percent_of_equity","percent_of_initial_equity","premium_budget"],"title":"SizingModeEnum","default":"percent_of_equity","uniqueKey":"capital.sizing.mode","typeLabel":"enum\u003cstring>"},"value":{"type":"number","exclusiveMinimum":0,"title":"Value","description":"Defaults to 0.5.","uniqueKey":"capital.sizing.value","typeLabel":"number"},"lot_step":{"type":"number","exclusiveMinimum":0,"title":"Lot Step","description":"Defaults to 0.1.","uniqueKey":"capital.sizing.lot_step","typeLabel":"number"},"min_contracts":{"type":"number","exclusiveMinimum":0,"title":"Min Contracts","description":"Defaults to 0.1.","uniqueKey":"capital.sizing.min_contracts","typeLabel":"number"}},"type":"object","title":"SizingSpec","uniqueKey":"capital.sizing","typeLabel":"SizingSpec · object"}},"type":"object","title":"CapitalSpec","description":"Starting equity, in coin, and how each new position is sized.","uniqueKey":"capital","typeLabel":"CapitalSpec · object"},"lifecycle":{"properties":{"entry_weekdays":{"oneOf":[{"type":"array","items":{"oneOf":[{"type":"string","title":"WeekdayEnum","description":"A day, by name, for the fields that gate on the calendar.\n\nThe numbers stay Monday 0, which is Python's own `date.weekday()` and what\nthese fields have always accepted. Names are here because a spec is read far\nmore often than it is written -- `[\"friday\"]` says what `[4]` only encodes,\nand the panel's Copy-spec payload is something a desk reads to work out what\nwas tested.","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],"uniqueKey":"lifecycle.entry_weekdays.oneOf.0.items.[INDEX].oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"integer","uniqueKey":"lifecycle.entry_weekdays.oneOf.0.items.[INDEX].oneOf.1","typeLabel":"integer"}],"uniqueKey":"lifecycle.entry_weekdays.oneOf.0.items.[INDEX]","typeLabel":"enum\u003cstring> | integer"},"title":"Entry Weekdays","description":"By name, or Monday-0 number. Crypto trades continuously, so a calendar strategy must name its days rather than inherit a session.","uniqueKey":"lifecycle.entry_weekdays.oneOf.0","typeLabel":"(enum\u003cstring> | integer)[]"},{"type":"null","title":"Entry Weekdays","description":"By name, or Monday-0 number. Crypto trades continuously, so a calendar strategy must name its days rather than inherit a session.","uniqueKey":"lifecycle.entry_weekdays.oneOf.1","typeLabel":"null"}],"uniqueKey":"lifecycle.entry_weekdays","typeLabel":"(enum\u003cstring> | integer)[] | null"},"exit_weekdays":{"oneOf":[{"type":"array","items":{"oneOf":[{"type":"string","title":"WeekdayEnum","description":"A day, by name, for the fields that gate on the calendar.\n\nThe numbers stay Monday 0, which is Python's own `date.weekday()` and what\nthese fields have always accepted. Names are here because a spec is read far\nmore often than it is written -- `[\"friday\"]` says what `[4]` only encodes,\nand the panel's Copy-spec payload is something a desk reads to work out what\nwas tested.","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],"uniqueKey":"lifecycle.exit_weekdays.oneOf.0.items.[INDEX].oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"integer","uniqueKey":"lifecycle.exit_weekdays.oneOf.0.items.[INDEX].oneOf.1","typeLabel":"integer"}],"uniqueKey":"lifecycle.exit_weekdays.oneOf.0.items.[INDEX]","typeLabel":"enum\u003cstring> | integer"},"title":"Exit Weekdays","description":"By name, or Monday-0 number. Closes whatever is open on these days, at the run's decision hour.","uniqueKey":"lifecycle.exit_weekdays.oneOf.0","typeLabel":"(enum\u003cstring> | integer)[]"},{"type":"null","title":"Exit Weekdays","description":"By name, or Monday-0 number. Closes whatever is open on these days, at the run's decision hour.","uniqueKey":"lifecycle.exit_weekdays.oneOf.1","typeLabel":"null"}],"uniqueKey":"lifecycle.exit_weekdays","typeLabel":"(enum\u003cstring> | integer)[] | null"},"rules":{"items":{"properties":{"when":{"properties":{"any":{"oneOf":[{"type":"array","items":{"oneOf":[{}],"uniqueKey":"lifecycle.rules.items.[INDEX].when.any.oneOf.0.items.[INDEX]","typeLabel":"any"},"title":"Any","uniqueKey":"lifecycle.rules.items.[INDEX].when.any.oneOf.0","typeLabel":"any[]"},{"type":"null","title":"Any","uniqueKey":"lifecycle.rules.items.[INDEX].when.any.oneOf.1","typeLabel":"null"}],"uniqueKey":"lifecycle.rules.items.[INDEX].when.any","typeLabel":"any[] | null"},"all":{"oneOf":[{"type":"array","items":{"oneOf":[{}],"uniqueKey":"lifecycle.rules.items.[INDEX].when.all.oneOf.0.items.[INDEX]","typeLabel":"any"},"title":"All","uniqueKey":"lifecycle.rules.items.[INDEX].when.all.oneOf.0","typeLabel":"any[]"},{"type":"null","title":"All","uniqueKey":"lifecycle.rules.items.[INDEX].when.all.oneOf.1","typeLabel":"null"}],"uniqueKey":"lifecycle.rules.items.[INDEX].when.all","typeLabel":"any[] | null"},"predicate":{"oneOf":[{"type":"object","title":"PredicateSpec","required":["metric","value"],"properties":{"metric":{"type":"string","enum":["premium","pnl","pnl_pct","delta","contract_delta","gamma","vega","theta","iv","underlying_price","dte","days_held","equity"],"title":"Metric","description":"What to measure on `subject`. Position metrics: `premium`, `pnl`, `pnl_pct`, `delta`, `contract_delta`, `gamma`, `vega`, `theta`, `iv`, `dte`, `days_held`; market and account: `underlying_price`, `equity`.","isRequired":true,"uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.0.metric","typeLabel":"enum\u003cstring>"},"value":{"type":"number","title":"Value","isRequired":true,"uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.0.value","typeLabel":"number"},"subject":{"type":"string","title":"Subject","description":"`leg:\u003cid>`, `structure`, `underlying` or `portfolio`.","default":"structure","uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.0.subject","typeLabel":"string"},"op":{"type":"string","enum":["above","below","crosses_above","crosses_below"],"title":"Op","default":"above","description":"`above` / `below` test the level; `crosses_above` / `crosses_below` fire only on the bar it is crossed.","uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.0.op","typeLabel":"enum\u003cstring>"},"unit":{"type":"string","enum":["absolute","percent","coin","ticks","days","vol_points"],"title":"Unit","default":"absolute","description":"How `value` is read. `absolute` is the metric itself; `percent` is a fractional change from `reference` (`-0.75` is a 75% fall); `coin`, `ticks`, `days` and `vol_points` are changes in those units.","uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.0.unit","typeLabel":"enum\u003cstring>"},"reference":{"type":"string","enum":["absolute","entry","prev_bar","high_water","low_water"],"title":"Reference","default":"absolute","description":"What a change is measured from: `absolute` (no reference), `entry` (when the position opened), `prev_bar`, `high_water` or `low_water` (best or worst since entry).","uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.0.reference","typeLabel":"enum\u003cstring>"}},"uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.0","typeLabel":"PredicateSpec · object"},{"type":"null","uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate.oneOf.1","typeLabel":"null"}],"uniqueKey":"lifecycle.rules.items.[INDEX].when.predicate","typeLabel":"PredicateSpec · object | null"}},"type":"object","title":"ConditionSpec","description":"A predicate, or a boolean combination of them.","isRequired":true,"uniqueKey":"lifecycle.rules.items.[INDEX].when","typeLabel":"ConditionSpec · object"},"name":{"type":"string","maxLength":40,"minLength":1,"title":"Name","default":"rule","uniqueKey":"lifecycle.rules.items.[INDEX].name","typeLabel":"string"},"do":{"properties":{"action":{"type":"string","enum":["close","close_all"],"title":"Action","default":"close_all","description":"`close_all` closes the whole structure; `close` closes only `target`.","uniqueKey":"lifecycle.rules.items.[INDEX].do.action","typeLabel":"enum\u003cstring>"},"target":{"type":"string","title":"Target","description":"`structure` or `leg:\u003cid>`.","default":"structure","uniqueKey":"lifecycle.rules.items.[INDEX].do.target","typeLabel":"string"}},"type":"object","title":"ActionSpec","uniqueKey":"lifecycle.rules.items.[INDEX].do","typeLabel":"ActionSpec · object"}},"type":"object","required":["when"],"title":"RuleSpec","uniqueKey":"lifecycle.rules.items.[INDEX]","typeLabel":"RuleSpec · object"},"type":"array","maxItems":16,"title":"Rules","description":"Evaluated in order; the first to fire owns a leg.","uniqueKey":"lifecycle.rules","typeLabel":"RuleSpec · object[]"}},"type":"object","title":"LifecycleSpec","description":"When positions are opened and closed. With no rules, positions are held to expiry.","uniqueKey":"lifecycle","typeLabel":"LifecycleSpec · object"},"costs":{"properties":{"fill":{"type":"string","enum":["mark","bid_ask"],"title":"FillEnum","default":"mark","uniqueKey":"costs.fill","typeLabel":"enum\u003cstring>"},"slippage_bps":{"type":"number","maximum":1000,"minimum":0,"title":"Slippage Bps","description":"Defaults to 0.0.","uniqueKey":"costs.slippage_bps","typeLabel":"number"},"fallback_spread_pct":{"type":"number","maximum":1,"minimum":0,"title":"Fallback Spread Pct","description":"Defaults to 0.05.","uniqueKey":"costs.fallback_spread_pct","typeLabel":"number"},"taker_fee_rate":{"type":"number","maximum":0.01,"minimum":0,"title":"Taker Fee Rate","description":"Defaults to 0.0003.","uniqueKey":"costs.taker_fee_rate","typeLabel":"number"},"fee_premium_cap":{"type":"number","maximum":1,"minimum":0,"title":"Fee Premium Cap","description":"Defaults to 0.125.","uniqueKey":"costs.fee_premium_cap","typeLabel":"number"}},"type":"object","title":"CostsSpec","description":"Fill model and fees.","uniqueKey":"costs","typeLabel":"CostsSpec · object"}},"type":"object","required":["start","end","structure"],"title":"BacktestRequest","uniqueKey":"","typeLabel":"BacktestRequest · object"},"example":{"name":"BTC 20-delta covered call","asset":"DER.BTC_USD","start":"2026-05-01","end":"2026-10-31","capital":{"initial_equity":1,"sizing":{"mode":"contracts","value":1}},"structure":{"expiry":{"by":"monthly","min_dte":20},"legs":[{"id":"call","type":"call","direction":"short","strike":{"by":"delta","value":0.2}}]},"lifecycle":{"rules":[{"name":"take_profit_75","when":{"predicate":{"subject":"structure","metric":"premium","op":"below","value":-0.75,"unit":"percent","reference":"entry"}},"do":{"action":"close_all"}},{"name":"delta_stop","when":{"predicate":{"subject":"leg:call","metric":"contract_delta","op":"above","value":0.45}},"do":{"action":"close_all"}},{"name":"roll_before_expiry","when":{"predicate":{"subject":"structure","metric":"dte","op":"below","value":2}},"do":{"action":"close_all"}}]}},"examples":{"Example":{"title":"Example","value":{"name":"BTC 20-delta covered call","asset":"DER.BTC_USD","start":"2026-05-01","end":"2026-10-31","capital":{"initial_equity":1,"sizing":{"mode":"contracts","value":1}},"structure":{"expiry":{"by":"monthly","min_dte":20},"legs":[{"id":"call","type":"call","direction":"short","strike":{"by":"delta","value":0.2}}]},"lifecycle":{"rules":[{"name":"take_profit_75","when":{"predicate":{"subject":"structure","metric":"premium","op":"below","value":-0.75,"unit":"percent","reference":"entry"}},"do":{"action":"close_all"}},{"name":"delta_stop","when":{"predicate":{"subject":"leg:call","metric":"contract_delta","op":"above","value":0.45}},"do":{"action":"close_all"}},{"name":"roll_before_expiry","when":{"predicate":{"subject":"structure","metric":"dte","op":"below","value":2}},"do":{"action":"close_all"}}]}}}},"exampleType":"examples"}},"exampleType":"examples"},"responses":{"cd1bfed1-46e3-4ebc-8c07-752d8dde73fb":{"description":"The backtest result, in the requested `format`.","headers":{"Sandmark-Backtest-Window-Start":{"description":"Earliest `start` your add-on allows, `YYYY-MM-DD`, or `2021-09-01` on full history.","schema":{"type":"string","format":"date"}}},"content":{"application/json":{"schema":{"properties":{"name":{"type":"string","title":"Name","isRequired":true,"uniqueKey":"name","typeLabel":"string"},"asset":{"type":"string","title":"Asset","isRequired":true,"uniqueKey":"asset","typeLabel":"string"},"bars":{"type":"integer","title":"Bars","isRequired":true,"uniqueKey":"bars","typeLabel":"integer"},"runtime_seconds":{"type":"number","title":"Runtime Seconds","isRequired":true,"uniqueKey":"runtime_seconds","typeLabel":"number"},"stats":{"properties":{"start":{"type":"string","title":"Start","isRequired":true,"uniqueKey":"stats.start","typeLabel":"string"},"end":{"type":"string","title":"End","isRequired":true,"uniqueKey":"stats.end","typeLabel":"string"},"duration_days":{"type":"number","title":"Duration Days","isRequired":true,"uniqueKey":"stats.duration_days","typeLabel":"number"},"initial_equity":{"type":"number","title":"Initial Equity","isRequired":true,"uniqueKey":"stats.initial_equity","typeLabel":"number"},"final_equity":{"type":"number","title":"Final Equity","isRequired":true,"uniqueKey":"stats.final_equity","typeLabel":"number"},"total_return":{"type":"number","title":"Total Return","isRequired":true,"uniqueKey":"stats.total_return","typeLabel":"number"},"cagr":{"type":"number","title":"Cagr","isRequired":true,"uniqueKey":"stats.cagr","typeLabel":"number"},"volatility":{"type":"number","title":"Volatility","isRequired":true,"uniqueKey":"stats.volatility","typeLabel":"number"},"sharpe":{"type":"number","title":"Sharpe","isRequired":true,"uniqueKey":"stats.sharpe","typeLabel":"number"},"sortino":{"type":"number","title":"Sortino","isRequired":true,"uniqueKey":"stats.sortino","typeLabel":"number"},"calmar":{"type":"number","title":"Calmar","isRequired":true,"uniqueKey":"stats.calmar","typeLabel":"number"},"drawdown":{"properties":{"max_drawdown":{"type":"number","title":"Max Drawdown","isRequired":true,"uniqueKey":"stats.drawdown.max_drawdown","typeLabel":"number"},"avg_drawdown":{"type":"number","title":"Avg Drawdown","isRequired":true,"uniqueKey":"stats.drawdown.avg_drawdown","typeLabel":"number"},"longest_underwater_days":{"type":"number","title":"Longest Underwater Days","isRequired":true,"uniqueKey":"stats.drawdown.longest_underwater_days","typeLabel":"number"},"max_drawdown_start":{"oneOf":[{"type":"string","title":"Max Drawdown Start","isRequired":true,"uniqueKey":"stats.drawdown.max_drawdown_start.oneOf.0","typeLabel":"string"},{"type":"null","title":"Max Drawdown Start","isRequired":true,"uniqueKey":"stats.drawdown.max_drawdown_start.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"stats.drawdown.max_drawdown_start","typeLabel":"string | null"},"max_drawdown_trough":{"oneOf":[{"type":"string","title":"Max Drawdown Trough","isRequired":true,"uniqueKey":"stats.drawdown.max_drawdown_trough.oneOf.0","typeLabel":"string"},{"type":"null","title":"Max Drawdown Trough","isRequired":true,"uniqueKey":"stats.drawdown.max_drawdown_trough.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"stats.drawdown.max_drawdown_trough","typeLabel":"string | null"}},"type":"object","required":["max_drawdown","avg_drawdown","longest_underwater_days","max_drawdown_start","max_drawdown_trough"],"title":"DrawdownModel","isRequired":true,"uniqueKey":"stats.drawdown","typeLabel":"DrawdownModel · object"},"trades":{"properties":{"count":{"type":"integer","title":"Count","isRequired":true,"uniqueKey":"stats.trades.count","typeLabel":"integer"},"winners":{"type":"integer","title":"Winners","isRequired":true,"uniqueKey":"stats.trades.winners","typeLabel":"integer"},"losers":{"type":"integer","title":"Losers","isRequired":true,"uniqueKey":"stats.trades.losers","typeLabel":"integer"},"win_rate":{"type":"number","title":"Win Rate","isRequired":true,"uniqueKey":"stats.trades.win_rate","typeLabel":"number"},"avg_pnl":{"type":"number","title":"Avg Pnl","isRequired":true,"uniqueKey":"stats.trades.avg_pnl","typeLabel":"number"},"avg_win":{"type":"number","title":"Avg Win","isRequired":true,"uniqueKey":"stats.trades.avg_win","typeLabel":"number"},"avg_loss":{"type":"number","title":"Avg Loss","isRequired":true,"uniqueKey":"stats.trades.avg_loss","typeLabel":"number"},"best":{"type":"number","title":"Best","isRequired":true,"uniqueKey":"stats.trades.best","typeLabel":"number"},"worst":{"type":"number","title":"Worst","isRequired":true,"uniqueKey":"stats.trades.worst","typeLabel":"number"},"profit_factor":{"type":"number","title":"Profit Factor","isRequired":true,"uniqueKey":"stats.trades.profit_factor","typeLabel":"number"},"avg_holding_days":{"type":"number","title":"Avg Holding Days","isRequired":true,"uniqueKey":"stats.trades.avg_holding_days","typeLabel":"number"},"total_fees":{"type":"number","title":"Total Fees","isRequired":true,"uniqueKey":"stats.trades.total_fees","typeLabel":"number"}},"type":"object","required":["count","winners","losers","win_rate","avg_pnl","avg_win","avg_loss","best","worst","profit_factor","avg_holding_days","total_fees"],"title":"TradeStatsModel","isRequired":true,"uniqueKey":"stats.trades","typeLabel":"TradeStatsModel · object"},"structures":{"oneOf":[{"type":"object","title":"StructureStatsModel","required":["count","win_rate","avg_pnl","best","worst","profit_factor","avg_legs","avg_holding_days"],"properties":{"count":{"type":"integer","title":"Count","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.count","typeLabel":"integer"},"win_rate":{"type":"number","title":"Win Rate","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.win_rate","typeLabel":"number"},"avg_pnl":{"type":"number","title":"Avg Pnl","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.avg_pnl","typeLabel":"number"},"best":{"type":"number","title":"Best","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.best","typeLabel":"number"},"worst":{"type":"number","title":"Worst","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.worst","typeLabel":"number"},"profit_factor":{"type":"number","title":"Profit Factor","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.profit_factor","typeLabel":"number"},"avg_legs":{"type":"number","title":"Avg Legs","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.avg_legs","typeLabel":"number"},"avg_holding_days":{"type":"number","title":"Avg Holding Days","isRequired":true,"uniqueKey":"stats.structures.oneOf.0.avg_holding_days","typeLabel":"number"}},"isRequired":true,"uniqueKey":"stats.structures.oneOf.0","typeLabel":"StructureStatsModel · object"},{"type":"null","isRequired":true,"uniqueKey":"stats.structures.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"stats.structures","typeLabel":"StructureStatsModel · object | null"},"yearly_returns":{"additionalProperties":{"type":"number","uniqueKey":"stats.yearly_returns.additionalProperties","typeLabel":"number"},"type":"object","title":"Yearly Returns","isRequired":true,"uniqueKey":"stats.yearly_returns","typeLabel":"Yearly Returns · object"}},"type":"object","required":["start","end","duration_days","initial_equity","final_equity","total_return","cagr","volatility","sharpe","sortino","calmar","drawdown","trades","structures","yearly_returns"],"title":"StatsModel","isRequired":true,"uniqueKey":"stats","typeLabel":"StatsModel · object"},"equity":{"items":{"properties":{"timestamp":{"type":"string","title":"Timestamp","isRequired":true,"uniqueKey":"equity.items.[INDEX].timestamp","typeLabel":"string"},"equity":{"type":"number","title":"Equity","isRequired":true,"uniqueKey":"equity.items.[INDEX].equity","typeLabel":"number"},"equity_usd":{"oneOf":[{"type":"number","title":"Equity Usd","isRequired":true,"uniqueKey":"equity.items.[INDEX].equity_usd.oneOf.0","typeLabel":"number"},{"type":"null","title":"Equity Usd","isRequired":true,"uniqueKey":"equity.items.[INDEX].equity_usd.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"equity.items.[INDEX].equity_usd","typeLabel":"number | null"},"cash":{"type":"number","title":"Cash","isRequired":true,"uniqueKey":"equity.items.[INDEX].cash","typeLabel":"number"},"positions_value":{"type":"number","title":"Positions Value","isRequired":true,"uniqueKey":"equity.items.[INDEX].positions_value","typeLabel":"number"},"spot":{"oneOf":[{"type":"number","title":"Spot","isRequired":true,"uniqueKey":"equity.items.[INDEX].spot.oneOf.0","typeLabel":"number"},{"type":"null","title":"Spot","isRequired":true,"uniqueKey":"equity.items.[INDEX].spot.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"equity.items.[INDEX].spot","typeLabel":"number | null"},"open_positions":{"type":"integer","title":"Open Positions","isRequired":true,"uniqueKey":"equity.items.[INDEX].open_positions","typeLabel":"integer"}},"type":"object","required":["timestamp","equity","equity_usd","cash","positions_value","spot","open_positions"],"title":"EquityPointModel","uniqueKey":"equity.items.[INDEX]","typeLabel":"EquityPointModel · object"},"type":"array","title":"Equity","isRequired":true,"uniqueKey":"equity","typeLabel":"EquityPointModel · object[]"},"positions":{"items":{"properties":{"position":{"oneOf":[{"type":"string","title":"Position","isRequired":true,"uniqueKey":"positions.items.[INDEX].position.oneOf.0","typeLabel":"string"},{"type":"null","title":"Position","isRequired":true,"uniqueKey":"positions.items.[INDEX].position.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"positions.items.[INDEX].position","typeLabel":"string | null"},"entry_time":{"type":"string","title":"Entry Time","isRequired":true,"uniqueKey":"positions.items.[INDEX].entry_time","typeLabel":"string"},"exit_time":{"type":"string","title":"Exit Time","isRequired":true,"uniqueKey":"positions.items.[INDEX].exit_time","typeLabel":"string"},"legs":{"type":"integer","title":"Legs","isRequired":true,"uniqueKey":"positions.items.[INDEX].legs","typeLabel":"integer"},"expiry":{"type":"string","title":"Expiry","isRequired":true,"uniqueKey":"positions.items.[INDEX].expiry","typeLabel":"string"},"net_premium":{"type":"number","title":"Net Premium","isRequired":true,"uniqueKey":"positions.items.[INDEX].net_premium","typeLabel":"number"},"fees":{"type":"number","title":"Fees","isRequired":true,"uniqueKey":"positions.items.[INDEX].fees","typeLabel":"number"},"pnl":{"type":"number","title":"Pnl","isRequired":true,"uniqueKey":"positions.items.[INDEX].pnl","typeLabel":"number"},"reason":{"type":"string","title":"Reason","isRequired":true,"uniqueKey":"positions.items.[INDEX].reason","typeLabel":"string"}},"type":"object","required":["position","entry_time","exit_time","legs","expiry","net_premium","fees","pnl","reason"],"title":"PositionModel","uniqueKey":"positions.items.[INDEX]","typeLabel":"PositionModel · object"},"type":"array","title":"Positions","isRequired":true,"uniqueKey":"positions","typeLabel":"PositionModel · object[]"},"trades":{"items":{"properties":{"instrument":{"type":"string","title":"Instrument","isRequired":true,"uniqueKey":"trades.items.[INDEX].instrument","typeLabel":"string"},"type":{"type":"string","title":"Type","isRequired":true,"uniqueKey":"trades.items.[INDEX].type","typeLabel":"string"},"strike":{"oneOf":[{"type":"integer","title":"Strike","isRequired":true,"uniqueKey":"trades.items.[INDEX].strike.oneOf.0","typeLabel":"integer"},{"type":"null","title":"Strike","isRequired":true,"uniqueKey":"trades.items.[INDEX].strike.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].strike","typeLabel":"integer | null"},"expiry":{"type":"string","title":"Expiry","isRequired":true,"uniqueKey":"trades.items.[INDEX].expiry","typeLabel":"string"},"entry_time":{"type":"string","title":"Entry Time","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_time","typeLabel":"string"},"exit_time":{"type":"string","title":"Exit Time","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_time","typeLabel":"string"},"quantity":{"type":"number","title":"Quantity","isRequired":true,"uniqueKey":"trades.items.[INDEX].quantity","typeLabel":"number"},"entry_price":{"type":"number","title":"Entry Price","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_price","typeLabel":"number"},"exit_price":{"type":"number","title":"Exit Price","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_price","typeLabel":"number"},"fees":{"type":"number","title":"Fees","isRequired":true,"uniqueKey":"trades.items.[INDEX].fees","typeLabel":"number"},"pnl":{"type":"number","title":"Pnl","isRequired":true,"uniqueKey":"trades.items.[INDEX].pnl","typeLabel":"number"},"entry_dte":{"oneOf":[{"type":"number","title":"Entry Dte","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_dte.oneOf.0","typeLabel":"number"},{"type":"null","title":"Entry Dte","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_dte.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_dte","typeLabel":"number | null"},"exit_dte":{"oneOf":[{"type":"number","title":"Exit Dte","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_dte.oneOf.0","typeLabel":"number"},{"type":"null","title":"Exit Dte","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_dte.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_dte","typeLabel":"number | null"},"holding_days":{"type":"number","title":"Holding Days","isRequired":true,"uniqueKey":"trades.items.[INDEX].holding_days","typeLabel":"number"},"reason":{"type":"string","title":"Reason","isRequired":true,"uniqueKey":"trades.items.[INDEX].reason","typeLabel":"string"},"position":{"oneOf":[{"type":"string","title":"Position","isRequired":true,"uniqueKey":"trades.items.[INDEX].position.oneOf.0","typeLabel":"string"},{"type":"null","title":"Position","isRequired":true,"uniqueKey":"trades.items.[INDEX].position.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].position","typeLabel":"string | null"},"tags":{"items":{"type":"string","uniqueKey":"trades.items.[INDEX].tags.items.[INDEX]","typeLabel":"string"},"type":"array","title":"Tags","isRequired":true,"uniqueKey":"trades.items.[INDEX].tags","typeLabel":"string[]"},"entry_delta":{"oneOf":[{"type":"number","title":"Entry Delta","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_delta.oneOf.0","typeLabel":"number"},{"type":"null","title":"Entry Delta","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_delta.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_delta","typeLabel":"number | null"},"exit_delta":{"oneOf":[{"type":"number","title":"Exit Delta","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_delta.oneOf.0","typeLabel":"number"},{"type":"null","title":"Exit Delta","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_delta.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_delta","typeLabel":"number | null"},"entry_iv":{"oneOf":[{"type":"number","title":"Entry Iv","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_iv.oneOf.0","typeLabel":"number"},{"type":"null","title":"Entry Iv","isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_iv.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].entry_iv","typeLabel":"number | null"},"exit_iv":{"oneOf":[{"type":"number","title":"Exit Iv","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_iv.oneOf.0","typeLabel":"number"},{"type":"null","title":"Exit Iv","isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_iv.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"trades.items.[INDEX].exit_iv","typeLabel":"number | null"}},"type":"object","required":["instrument","type","strike","expiry","entry_time","exit_time","quantity","entry_price","exit_price","fees","pnl","entry_dte","exit_dte","holding_days","reason","position","tags","entry_delta","exit_delta","entry_iv","exit_iv"],"title":"TradeModel","uniqueKey":"trades.items.[INDEX]","typeLabel":"TradeModel · object"},"type":"array","title":"Trades","isRequired":true,"uniqueKey":"trades","typeLabel":"TradeModel · object[]"},"strategy":{"oneOf":[{"type":"object","title":"StrategyDescriptionModel","description":"What the strategy does, derived from its configuration rather than its\nname, so it cannot describe something other than what ran.","required":["headline"],"properties":{"headline":{"type":"string","title":"Headline","isRequired":true,"uniqueKey":"strategy.oneOf.0.headline","typeLabel":"string"},"legs":{"items":{"properties":{"id":{"type":"string","title":"Id","isRequired":true,"uniqueKey":"strategy.oneOf.0.legs.items.[INDEX].id","typeLabel":"string"},"direction":{"type":"string","title":"Direction","isRequired":true,"uniqueKey":"strategy.oneOf.0.legs.items.[INDEX].direction","typeLabel":"string"},"kind":{"type":"string","title":"Kind","isRequired":true,"uniqueKey":"strategy.oneOf.0.legs.items.[INDEX].kind","typeLabel":"string"},"strike":{"type":"string","title":"Strike","isRequired":true,"uniqueKey":"strategy.oneOf.0.legs.items.[INDEX].strike","typeLabel":"string"},"expiry":{"type":"string","title":"Expiry","isRequired":true,"uniqueKey":"strategy.oneOf.0.legs.items.[INDEX].expiry","typeLabel":"string"},"ratio":{"type":"number","title":"Ratio","isRequired":true,"uniqueKey":"strategy.oneOf.0.legs.items.[INDEX].ratio","typeLabel":"number"},"sentence":{"type":"string","title":"Sentence","isRequired":true,"uniqueKey":"strategy.oneOf.0.legs.items.[INDEX].sentence","typeLabel":"string"}},"type":"object","required":["id","direction","kind","strike","expiry","ratio","sentence"],"title":"LegDescriptionModel","uniqueKey":"strategy.oneOf.0.legs.items.[INDEX]","typeLabel":"LegDescriptionModel · object"},"type":"array","title":"Legs","uniqueKey":"strategy.oneOf.0.legs","typeLabel":"LegDescriptionModel · object[]"},"lifecycle":{"items":{"type":"string","uniqueKey":"strategy.oneOf.0.lifecycle.items.[INDEX]","typeLabel":"string"},"type":"array","title":"Lifecycle","uniqueKey":"strategy.oneOf.0.lifecycle","typeLabel":"string[]"},"sizing":{"type":"string","title":"Sizing","default":"","uniqueKey":"strategy.oneOf.0.sizing","typeLabel":"string"},"hedge":{"oneOf":[{"type":"string","title":"Hedge","uniqueKey":"strategy.oneOf.0.hedge.oneOf.0","typeLabel":"string"},{"type":"null","title":"Hedge","uniqueKey":"strategy.oneOf.0.hedge.oneOf.1","typeLabel":"null"}],"uniqueKey":"strategy.oneOf.0.hedge","typeLabel":"string | null"},"costs":{"type":"string","title":"Costs","default":"","uniqueKey":"strategy.oneOf.0.costs","typeLabel":"string"}},"uniqueKey":"strategy.oneOf.0","typeLabel":"StrategyDescriptionModel · object"},{"type":"null","uniqueKey":"strategy.oneOf.1","typeLabel":"null"}],"uniqueKey":"strategy","typeLabel":"StrategyDescriptionModel · object | null"},"warnings":{"items":{"type":"string","uniqueKey":"warnings.items.[INDEX]","typeLabel":"string"},"type":"array","title":"Warnings","description":"Not decoration. Silent data holes are the main way an options backtest lies, so degraded fills, carried marks and bars the chain could not serve are counted here.","uniqueKey":"warnings","typeLabel":"string[]"},"diagnostics":{"additionalProperties":{"type":"number","uniqueKey":"diagnostics.additionalProperties","typeLabel":"number"},"type":"object","title":"Diagnostics","uniqueKey":"diagnostics","typeLabel":"Diagnostics · object"}},"type":"object","required":["name","asset","bars","runtime_seconds","stats","equity","positions","trades"],"title":"BacktestResponse","uniqueKey":"","typeLabel":"BacktestResponse · object"},"example":{"name":"BTC 20-delta covered call","asset":"DER.BTC_USD","bars":183,"runtime_seconds":0.149,"strategy":{"headline":"Short call","legs":[{"id":"call","direction":"Short","kind":"call","strike":"20 delta","expiry":"front monthly (last Friday) at least 20 days out","ratio":1,"sentence":"Short 20 delta call, front monthly (last Friday) at least 20 days out"}],"lifecycle":["enter whenever flat","close the position when the structure's premium falls -75% below entry","close the position when the call leg's delta rises above 0.45","close the position when days to expiry falls below 2"],"sizing":"1 contracts, fixed","hedge":null,"costs":"filled at mark, 0.03% taker fee, capped at 12.5% of premium"},"stats":{"start":"2026-05-01T08:00:00+00:00","end":"2026-10-30T08:00:00+00:00","duration_days":182,"initial_equity":0.9997,"final_equity":0.998437,"total_return":-0.001263,"cagr":-0.002531,"volatility":0.09877,"sharpe":0.024579,"sortino":0.026966,"calmar":-0.028629,"drawdown":{"max_drawdown":-0.088411,"avg_drawdown":-0.038878,"longest_underwater_days":75,"max_drawdown_start":"2026-08-16T08:00:00+00:00","max_drawdown_trough":"2026-09-23T08:00:00+00:00"},"trades":{"count":14,"winners":11,"losers":3,"win_rate":0.785714,"avg_pnl":-0.000112,"avg_win":0.009131,"avg_loss":-0.034,"best":0.01155,"worst":-0.0764,"profit_factor":0.984681,"avg_holding_days":13,"total_fees":0.008063},"structures":{"count":14,"win_rate":0.785714,"avg_pnl":-0.000112,"best":0.01155,"worst":-0.0764,"profit_factor":0.984681,"avg_legs":1,"avg_holding_days":13},"yearly_returns":{"2026":-0.001263}},"equity":[{"timestamp":"2026-05-01T08:00:00+00:00","equity":0.9997,"equity_usd":77088.725817,"cash":1.0111,"positions_value":-0.0114,"spot":77111.859375,"open_positions":1},{"timestamp":"2026-05-02T08:00:00+00:00","equity":0.9974,"equity_usd":78011.633222,"cash":1.0111,"positions_value":-0.0137,"spot":78214.992188,"open_positions":1}],"positions":[{"position":"BTC 20-delta covered call-00001","entry_time":"2026-05-01T08:00:00","exit_time":"2026-05-18T08:00:00","legs":1,"expiry":"2026-05-29T08:00:00","net_premium":0.0114,"fees":0.000588,"pnl":0.008513,"reason":"take_profit_75"}],"trades":[{"instrument":"BTC-29MAY26-84000-C","type":"C","strike":84000,"expiry":"2026-05-29T08:00:00","entry_time":"2026-05-01T08:00:00","exit_time":"2026-05-18T08:00:00","quantity":-1,"entry_price":0.0114,"exit_price":0.0023,"fees":0.000588,"pnl":0.008513,"entry_dte":28,"exit_dte":11,"holding_days":17,"reason":"take_profit_75","position":"BTC 20-delta covered call-00001","tags":["call"],"entry_delta":0.21217,"exit_delta":0.08431,"entry_iv":0.3584,"exit_iv":0.3539}],"warnings":["only 14 positions: ratio estimates are dominated by noise below ~30"],"diagnostics":{"fills_total":28,"fills_degraded":0,"fills_degraded_pct":0}},"examples":{"Example":{"title":"Example","value":{"name":"BTC 20-delta covered call","asset":"DER.BTC_USD","bars":183,"runtime_seconds":0.149,"strategy":{"headline":"Short call","legs":[{"id":"call","direction":"Short","kind":"call","strike":"20 delta","expiry":"front monthly (last Friday) at least 20 days out","ratio":1,"sentence":"Short 20 delta call, front monthly (last Friday) at least 20 days out"}],"lifecycle":["enter whenever flat","close the position when the structure's premium falls -75% below entry","close the position when the call leg's delta rises above 0.45","close the position when days to expiry falls below 2"],"sizing":"1 contracts, fixed","hedge":null,"costs":"filled at mark, 0.03% taker fee, capped at 12.5% of premium"},"stats":{"start":"2026-05-01T08:00:00+00:00","end":"2026-10-30T08:00:00+00:00","duration_days":182,"initial_equity":0.9997,"final_equity":0.998437,"total_return":-0.001263,"cagr":-0.002531,"volatility":0.09877,"sharpe":0.024579,"sortino":0.026966,"calmar":-0.028629,"drawdown":{"max_drawdown":-0.088411,"avg_drawdown":-0.038878,"longest_underwater_days":75,"max_drawdown_start":"2026-08-16T08:00:00+00:00","max_drawdown_trough":"2026-09-23T08:00:00+00:00"},"trades":{"count":14,"winners":11,"losers":3,"win_rate":0.785714,"avg_pnl":-0.000112,"avg_win":0.009131,"avg_loss":-0.034,"best":0.01155,"worst":-0.0764,"profit_factor":0.984681,"avg_holding_days":13,"total_fees":0.008063},"structures":{"count":14,"win_rate":0.785714,"avg_pnl":-0.000112,"best":0.01155,"worst":-0.0764,"profit_factor":0.984681,"avg_legs":1,"avg_holding_days":13},"yearly_returns":{"2026":-0.001263}},"equity":[{"timestamp":"2026-05-01T08:00:00+00:00","equity":0.9997,"equity_usd":77088.725817,"cash":1.0111,"positions_value":-0.0114,"spot":77111.859375,"open_positions":1},{"timestamp":"2026-05-02T08:00:00+00:00","equity":0.9974,"equity_usd":78011.633222,"cash":1.0111,"positions_value":-0.0137,"spot":78214.992188,"open_positions":1}],"positions":[{"position":"BTC 20-delta covered call-00001","entry_time":"2026-05-01T08:00:00","exit_time":"2026-05-18T08:00:00","legs":1,"expiry":"2026-05-29T08:00:00","net_premium":0.0114,"fees":0.000588,"pnl":0.008513,"reason":"take_profit_75"}],"trades":[{"instrument":"BTC-29MAY26-84000-C","type":"C","strike":84000,"expiry":"2026-05-29T08:00:00","entry_time":"2026-05-01T08:00:00","exit_time":"2026-05-18T08:00:00","quantity":-1,"entry_price":0.0114,"exit_price":0.0023,"fees":0.000588,"pnl":0.008513,"entry_dte":28,"exit_dte":11,"holding_days":17,"reason":"take_profit_75","position":"BTC 20-delta covered call-00001","tags":["call"],"entry_delta":0.21217,"exit_delta":0.08431,"entry_iv":0.3584,"exit_iv":0.3539}],"warnings":["only 14 positions: ratio estimates are dominated by noise below ~30"],"diagnostics":{"fills_total":28,"fills_degraded":0,"fills_degraded_pct":0}}}},"exampleType":"examples"},"text/html":{"schema":{"type":"string","uniqueKey":"","typeLabel":"string"},"examples":{"Example":{"title":"Example","value":"\u003cstring>"}},"exampleType":"generated"},"application/zip":{"schema":{"type":"string","format":"binary","uniqueKey":"","typeLabel":"file"},"examples":{"Example":{"title":"Example","value":"\u003cstring>"}},"exampleType":"generated"},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary","uniqueKey":"","typeLabel":"file"},"examples":{"Example":{"title":"Example","value":"\u003cstring>"}},"exampleType":"generated"}},"exampleType":"examples"},"9a228c62-9de8-40a4-b1f3-51792943bb2f":{"description":"The body is not valid JSON, or `start` is not a `YYYY-MM-DD` date.","content":{"application/json":{"schema":{"type":"object","required":["statusCode","message"],"properties":{"statusCode":{"type":"integer","isRequired":true,"uniqueKey":"statusCode","typeLabel":"integer"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"example":{"statusCode":400,"message":"start must be a date such as 2025-11-01"},"examples":{"Example":{"title":"Example","value":{"statusCode":400,"message":"start must be a date such as 2025-11-01"}}},"exampleType":"examples"}},"exampleType":"examples"},"57a1c2f3-77f5-48d1-9850-e9d54bba1360":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["statusCode","message"],"properties":{"statusCode":{"type":"integer","isRequired":true,"uniqueKey":"statusCode","typeLabel":"integer"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"example":{"statusCode":401,"message":"Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription."},"examples":{"Example":{"title":"Example","value":{"statusCode":401,"message":"Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription."}}},"exampleType":"examples"}},"exampleType":"examples"},"4267c587-adf0-4edb-9fa8-c07bcb425553":{"description":"`start` is before your backtest lookback.","content":{"application/json":{"schema":{"type":"object","required":["statusCode","message"],"properties":{"statusCode":{"type":"integer","isRequired":true,"uniqueKey":"statusCode","typeLabel":"integer"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"example":{"statusCode":403,"message":"start is before your backtest lookback, which begins 2025-11-07"},"examples":{"Example":{"title":"Example","value":{"statusCode":403,"message":"start is before your backtest lookback, which begins 2025-11-07"}}},"exampleType":"examples"}},"exampleType":"examples"},"66300027-4e1d-44b3-b8be-c6fcbed393e5":{"description":"The strategy specification failed validation. `detail` names each field.","content":{"application/json":{"schema":{"properties":{"detail":{"items":{"properties":{"loc":{"items":{"oneOf":[{"type":"string","uniqueKey":"detail.items.[INDEX].loc.items.[INDEX].oneOf.0","typeLabel":"string"},{"type":"integer","uniqueKey":"detail.items.[INDEX].loc.items.[INDEX].oneOf.1","typeLabel":"integer"}],"uniqueKey":"detail.items.[INDEX].loc.items.[INDEX]","typeLabel":"string | integer"},"type":"array","title":"Location","isRequired":true,"uniqueKey":"detail.items.[INDEX].loc","typeLabel":"(string | integer)[]"},"msg":{"type":"string","title":"Message","isRequired":true,"uniqueKey":"detail.items.[INDEX].msg","typeLabel":"string"},"type":{"type":"string","title":"Error Type","isRequired":true,"uniqueKey":"detail.items.[INDEX].type","typeLabel":"string"},"input":{"oneOf":[{"title":"Input"}],"uniqueKey":"detail.items.[INDEX].input","typeLabel":"any"},"ctx":{"type":"object","title":"Context","uniqueKey":"detail.items.[INDEX].ctx","typeLabel":"Context · object"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError","uniqueKey":"detail.items.[INDEX]","typeLabel":"ValidationError · object"},"type":"array","title":"Detail","uniqueKey":"detail","typeLabel":"ValidationError · object[]"}},"type":"object","title":"HTTPValidationError","uniqueKey":"","typeLabel":"HTTPValidationError · object"},"examples":{"Example":{"title":"Example","value":{"detail":[{"loc":["\u003cstring>"],"msg":"\u003cstring>","type":"\u003cstring>","input":"\u003cunknown>","ctx":{}}]}}},"exampleType":"generated"}},"exampleType":"generated"},"9449cbfb-9d3a-4168-876c-be508f02d20b":{"description":"Rate limit exceeded (10 backtests per minute). Retry after `Retry-After` seconds.","content":{"application/json":{"schema":{"type":"object","required":["statusCode","message"],"properties":{"statusCode":{"type":"integer","isRequired":true,"uniqueKey":"statusCode","typeLabel":"integer"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"example":{"statusCode":429,"message":"Rate limit is exceeded. Try again in 31 seconds."},"examples":{"Example":{"title":"Example","value":{"statusCode":429,"message":"Rate limit is exceeded. Try again in 31 seconds."}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"c392e887-a03c-4c1f-9813-d9566cb91bd9":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your Sandmark Backtesting API key.","scopes":[],"schemeName":"apiKey"}}},"servers":{"5c242684-546d-45c8-b216-7dff445669a4":{"url":"https://api.sandmark.com/backtesting","description":"Production"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your Sandmark Backtesting API key.","scopes":[],"schemeName":"apiKey"},"schema":{"title":"X-API-Key","type":"string","description":"Your Sandmark Backtesting API key.","isRequired":true,"typeLabel":"string","deprecated":false},"schemeName":"apiKey","name":"X-API-Key"}],"title":"apiKey"}]},"originalFileLocation":"api-reference/backtest-openapi.json"},"subdomain":"sandmark-volatility","siteName":"Sandmark API","title":"Run a backtest - Sandmark API","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-07T20:57:20.030Z","originalFileLocation":"api-reference/run-backtest.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"dark\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Run an options strategy over history and get back the equity curve, every trade, the positions they belong to and the performance statistics. Describe the strategy in the request body: the legs and how their strikes and expiries are chosen, how positions are sized, when they are closed, and the cost model. See Strategy specification for every field. Denomination is coin. Inverse options are quoted and settled in the base coin, so equity, premiums and P\u0026amp;L are in BTC (or ETH). equity_usd is a derived reading alongside. Lookback. start must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on quarterly, full history (from September 2021) on annual. An earlier start returns 403. The Sandmark-Backtest-Window-Start response header gives your earliest allowed date. Warnings are part of the result. Degraded fills, carried marks and bars the option chain could not serve are counted in warnings and diagnostics. Read them before trusting a number.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Sandmark API\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Run a backtest - Sandmark API\">\u003cmeta data-mint-head property=\"og:description\" content=\"Run an options strategy over history and get back the equity curve, every trade, the positions they belong to and the performance statistics. Describe the strategy in the request body: the legs and how their strikes and expiries are chosen, how positions are sized, when they are closed, and the cost model. See Strategy specification for every field. Denomination is coin. Inverse options are quoted and settled in the base coin, so equity, premiums and P\u0026amp;L are in BTC (or ETH). equity_usd is a derived reading alongside. Lookback. start must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on quarterly, full history (from September 2021) on annual. An earlier start returns 403. The Sandmark-Backtest-Window-Start response header gives your earliest allowed date. Warnings are part of the result. Degraded fills, carried marks and bars the option chain could not serve are counted in warnings and diagnostics. Read them before trusting a number.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Sandmark API\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.sandmark.com/api-reference/run-backtest\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://sandmark-volatility.mintlify.site/_mintlify/api/og/v2?division=Backtesting\u0026amp;title=Run+a+backtest\u0026amp;description=Run+an+options+strategy+over+history+and+get+back+the+equity+curve%2C+every+trade%2C+the+positions%0Athey+belong+to+and+the+performance+statistics.%0A%0ADescribe+the+stra\u0026amp;theme=1a10e1cc5be9c260fa6df3cc\u0026amp;signature=9dc448782c5f54c4398b9f69cb916b4fd1e89fd7b9f7ee0779a469a33bb83a50\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Run a backtest - Sandmark API\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Run an options strategy over history and get back the equity curve, every trade, the positions they belong to and the performance statistics. Describe the strategy in the request body: the legs and how their strikes and expiries are chosen, how positions are sized, when they are closed, and the cost model. See Strategy specification for every field. Denomination is coin. Inverse options are quoted and settled in the base coin, so equity, premiums and P\u0026amp;L are in BTC (or ETH). equity_usd is a derived reading alongside. Lookback. start must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on quarterly, full history (from September 2021) on annual. An earlier start returns 403. The Sandmark-Backtest-Window-Start response header gives your earliest allowed date. Warnings are part of the result. Degraded fills, carried marks and bars the option chain could not serve are counted in warnings and diagnostics. Read them before trusting a number.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://sandmark-volatility.mintlify.site/_mintlify/api/og/v2?division=Backtesting\u0026amp;title=Run+a+backtest\u0026amp;description=Run+an+options+strategy+over+history+and+get+back+the+equity+curve%2C+every+trade%2C+the+positions%0Athey+belong+to+and+the+performance+statistics.%0A%0ADescribe+the+stra\u0026amp;theme=1a10e1cc5be9c260fa6df3cc\u0026amp;signature=9dc448782c5f54c4398b9f69cb916b4fd1e89fd7b9f7ee0779a469a33bb83a50\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/sandmark-volatility/FWAIgz2Ubron_OFi/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Sandmark API\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#8A6D45\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.sandmark.com/api-reference/run-backtest\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/run-backtest.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.sandmark.com/#organization\",\"name\":\"Sandmark API\",\"url\":\"https://docs.sandmark.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/sandmark-volatility/DfFiCOrERgX9yGgQ/logo/light.svg?fit=max\u0026auto=format\u0026n=DfFiCOrERgX9yGgQ\u0026q=85\u0026s=f6c18ca925e51a40b7c6b3b221000e0b\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.sandmark.com#website\",\"name\":\"Sandmark API\",\"url\":\"https://docs.sandmark.com\",\"publisher\":{\"@id\":\"https://docs.sandmark.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.sandmark.com/api-reference/run-backtest#webpage\",\"url\":\"https://docs.sandmark.com/api-reference/run-backtest\",\"name\":\"Run a backtest\",\"description\":\"Run an options strategy over history and get back the equity curve, every trade, the positions they belong to and the performance statistics. Describe the strategy in the request body: the legs and how their strikes and expiries are chosen, how positions are sized, when they are closed, and the cost model. See Strategy specification for every field. Denomination is coin. Inverse options are quoted and settled in the base coin, so equity, premiums and P\u0026L are in BTC (or ETH). equity_usd is a derived reading alongside. Lookback. start must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on quarterly, full history (from September 2021) on annual. An earlier start returns 403. The Sandmark-Backtest-Window-Start response header gives your earliest allowed date. Warnings are part of the result. Degraded fills, carried marks and bars the option chain could not serve are counted in warnings and diagnostics. Read them before trusting a number.\",\"dateModified\":\"2026-11-07T20:57:20.030Z\",\"isPartOf\":{\"@id\":\"https://docs.sandmark.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.sandmark.com/api-reference/run-backtest#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.sandmark.com/api-reference/run-backtest#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Sandmark API\",\"item\":\"https://docs.sandmark.com\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Run a backtest\",\"item\":\"https://docs.sandmark.com/api-reference/run-backtest\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.sandmark.com/api-reference/run-backtest#apireference\",\"headline\":\"Run a backtest\",\"name\":\"Run a backtest\",\"description\":\"Run an options strategy over history and get back the equity curve, every trade, the positions they belong to and the performance statistics. Describe the strategy in the request body: the legs and how their strikes and expiries are chosen, how positions are sized, when they are closed, and the cost model. See Strategy specification for every field. Denomination is coin. Inverse options are quoted and settled in the base coin, so equity, premiums and P\u0026L are in BTC (or ETH). equity_usd is a derived reading alongside. Lookback. start must fall inside your backtest lookback: 1 year on the monthly add-on, 3 years on quarterly, full history (from September 2021) on annual. An earlier start returns 403. The Sandmark-Backtest-Window-Start response header gives your earliest allowed date. Warnings are part of the result. Degraded fills, carried marks and bars the option chain could not serve are counted in warnings and diagnostics. Read them before trusting a number.\",\"url\":\"https://docs.sandmark.com/api-reference/run-backtest\",\"mainEntityOfPage\":{\"@id\":\"https://docs.sandmark.com/api-reference/run-backtest#webpage\"},\"dateModified\":\"2026-11-07T20:57:20.030Z\",\"publisher\":{\"@id\":\"https://docs.sandmark.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.sandmark.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Sandmark API\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Sandmark API","nav":{"global":null,"tabs":[{"tab":"Guides","pages":[{"title":"Guides","href":""}]},{"tab":"Backtesting","pages":[{"title":"Backtesting","href":"/backtesting/overview"}]},{"tab":"API reference","groups":[{"group":"Reference data","pages":[{"openapi":"GET /v1/assets","title":"List assets","href":"/api-reference/list-assets"},{"openapi":"GET /v1/frequencies","title":"List frequencies","href":"/api-reference/list-frequencies"},{"openapi":"GET /v1/expiries","title":"List expiries","href":"/api-reference/list-expiries"}]},{"group":"Timeseries","pages":[{"openapi":"GET /v1/timeseries/iv","title":"Implied volatility","href":"/api-reference/implied-volatility"},{"openapi":"GET /v1/timeseries/rv","title":"Realised volatility","description":"Annualised realised volatility of the underlying index over a rolling lookback. `lookback_days=30` is 30-day realised vol, directly comparable with 1m implied vol. Values are decimal.\n\n**History window.** How far back you can read depends on your billing plan: 1 month on monthly billing, 1 year on quarterly, 3 years on annual. A `start` earlier than your window (or no `start` at all) is moved forward to the window start, and the `Sandmark-Data-Window-Start` response header says where it began. An `end` before the window start returns `403`.","href":"/api-reference/realized-volatility"}]},{"group":"Backtesting","pages":[{"openapi":"api-reference/backtest-openapi.json POST /v1/backtest","title":"Run a backtest","href":"/api-reference/run-backtest"}]}]}]},"basePath":"","title":"Run a backtest - Sandmark API","buildId":"dpl_DTau1J5HqS9UTgVSDwGksstFWtPa","deploymentId":"dpl_DTau1J5HqS9UTgVSDwGksstFWtPa","dynamics":["c2aa737661","b0f84f53ff","a9bb46feb3","2b790eda92"],"chunks":["OpenApiReferenceProvider-5FCzAcfS.js","utils-SLtAG4EZ.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-2DZi8ZMu.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-D7J3nkzE.js","snippetPresets-D0Alv0AH.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","conditional-requirements-CFM0id0Q.js","Page-D9ithiIZ.js","ApiExamples-BI4qNJ2c.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-BD3uyr8j.js","shallow-D8iEBr5z.js","getApiPlaygroundDisplay-CgNP4lzR.js","CodeSnippet-CX-QHuMs.js","CodeSnippets-VlXE-ZUf.js","getPastedJson-DYNQkZ1M.js","icon-CzacdwOi.js","MethodPill-2JVqoYKi.js","DuplicateIcon-_xVXs-U8.js","createIcon-BRHrweLo.js","DynamicMarkdown-mQG_iQiE.js","SectionHeading-DMpJzv8f.js","axios-vUo_bRtp.js","Markdown-5FGIym-8.js","clsx-D-TRO5q5.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-CdrJecqK.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-CHlcWBLM.js"]}