{"openapi":"3.1.0","info":{"title":"TextToQuant API","version":"1.1.0","description":"Parse plain-English trading strategies, run backtests, manage custom indicators, read results — and read and control a live trading account under /v1/trading.\n\nEvery response uses one envelope: {success, data} on success, {success:false, code, error} on failure. Branch on `code`, never on the message text.\n\nLIVE TRADING — two things to know before you call anything under /v1/trading:\n1. Scopes. Those routes need `trading:read` on the API key, and `trading:write` to act. The default is neither: a key issued before this surface existed reaches none of it until the scope is granted at Account → API keys. A missing scope is a 403 `insufficient_scope`, not a 401. Each operation names its requirement in `x-ttq-scope`. A paid plan with live trading is required on top.\n2. What the writes can do — and cannot. Every write REDUCES risk: pause, cancel, close, protect, halt. There is deliberately NO endpoint that opens a position, places a resting order, or moves funds between venues or out of an account. An automated caller acquiring new exposure is a different risk class, so those stay in the UI. The worst outcome of a mistaken call here is being flat, protected or paused.\n\nFull guide: https://docs.texttoquant.com"},"servers":[{"url":"https://app.texttoquant.com/api","description":"v1 REST API base (hosted MCP at https://www.texttoquant.com/api/mcp, served by this API at /api/v1/mcp)"}],"security":[{"apiKey":[]},{"bearer":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"ttq_… key from Account → API Keys"},"bearer":{"type":"http","scheme":"bearer","description":"Authorization: Bearer ttq_…"}},"schemas":{"Error":{"type":"object","required":["success","code","error"],"properties":{"success":{"type":"boolean","const":false},"code":{"type":"string","description":"Stable machine readable error code: branch on this."},"error":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string","description":"Echo of X-Request-Id: quote when contacting support."}}},"SymbolRefusal":{"allOf":[{"$ref":"#/components/schemas/Error"},{"type":"object","properties":{"code":{"type":"string","enum":["SYMBOL_UNRESOLVED","SYMBOL_AMBIGUOUS"]},"retryable":{"type":"boolean","const":false},"asset":{"type":"string","description":"The symbol as sent, or as the condition that reads it resolves it."},"scope":{"type":"string","enum":["condition"],"description":"Present when a condition reads the symbol, not the run's asset: fix it in that condition and leave asset as it is."},"suggestion":{"type":["object","null"],"description":"SYMBOL_UNRESOLVED only: the near company, {listing, name}, or null."},"candidates":{"type":"object","description":"SYMBOL_AMBIGUOUS only: the two readings, {crypto: pair, stock: ticker}."},"storedRun":{"type":"boolean","description":"Present on a re-run of a saved backtest. With scope \"condition\" there is nothing to patch in place: edit that condition and run the strategy as a new backtest."},"details":{"type":"object","properties":{"blockers":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"The repair card: code, term, headline, explain, candidates[{id, label, plain, patch}]; for a condition symbol (scope \"condition\") locator, guard and candidates[{id, label, plain, condition}] instead, or no candidates."}}}}}}]},"ParsedQuery":{"type":"object","additionalProperties":true,"description":"The structured strategy returned by POST /v1/parse: pass verbatim to POST /v1/backtests."},"BacktestRow":{"type":"object","additionalProperties":true,"description":"A saved run: scalar metrics (total_return, sharpe_ratio, max_drawdown, win_rate, …), grade, effective params (timeframe, stop_loss, fees_bps, …), edit lineage (strategy_session_id, iteration_label). winning_trades / losing_trades: on runs saved before 2026-08-30 the stored counts can be 0 beside a real win_rate; such rows are served with counts approximated as round(win_rate × total_trades / 100) and carry trade_counts_approximated: true. Rows with persisted counts never carry the field."}}},"paths":{"/v1/backtests/{id}/sweep/options":{"get":{"summary":"Sweepable parameter ids for this backtest (quota free)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/sweep":{"post":{"summary":"Start a 5-run sensitivity sweep (bills one credit)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"parameterId":{"type":"string","description":"e.g. entry.0.threshold, risk.stopLoss (see /sweep/options)"},"min":{"type":"number"},"max":{"type":"number"}}}}}},"responses":{"200":{"description":"Job started — returns {jobId}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}}}}},"/v1/backtests/{id}/sweep/{jobId}":{"get":{"summary":"Poll the sweep job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Progress while running; full result when done","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/grid":{"post":{"summary":"Start a 5×5 two-parameter grid (power tier; billed as 5)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","required":["xParameterId","yParameterId"],"properties":{"xParameterId":{"type":"string","description":"e.g. entry.0.threshold, risk.stopLoss (see /sweep/options)"},"yParameterId":{"type":"string","description":"e.g. entry.0.threshold, risk.stopLoss (see /sweep/options)"},"minX":{"type":"number"},"maxX":{"type":"number"},"minY":{"type":"number"},"maxY":{"type":"number"},"resolution":{"type":"integer","enum":[5,7,9]}}}}}},"responses":{"200":{"description":"Job started — returns {jobId}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}}}}},"/v1/backtests/{id}/grid/{jobId}":{"get":{"summary":"Poll the grid job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Progress while running; full result when done","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/walk-forward":{"post":{"summary":"Start anchored walk-forward optimization (power tier)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"parameterId":{"type":"string","description":"e.g. entry.0.threshold, risk.stopLoss (see /sweep/options)"}}}}}},"responses":{"200":{"description":"Job started — returns {jobId}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}}}}},"/v1/backtests/{id}/walk-forward/{jobId}":{"get":{"summary":"Poll the walk-forward job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Progress while running; full result when done","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/joint-sweep":{"post":{"summary":"Start a 3-parameter joint sweep (power tier)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","required":["parameterIds"],"properties":{"parameterIds":{"type":"array","minItems":3,"maxItems":3,"items":{"type":"string","description":"e.g. entry.0.threshold, risk.stopLoss (see /sweep/options)"}}}}}}},"responses":{"200":{"description":"Job started — returns {jobId}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}}}}},"/v1/backtests/{id}/joint-sweep/{jobId}":{"get":{"summary":"Poll the joint-sweep job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Progress while running; full result when done","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/multi-asset":{"post":{"summary":"Re-run across peer assets/timeframes (power tier)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"assets":{"type":"array","maxItems":4,"items":{"type":"string"},"description":"Peer markets to test INSTEAD of the curated per class pool, e.g. [\"ETH\",\"SOL\"]. Omit for the automatic peers. The backtest's own market, duplicates and nonsymbols are rejected before billing. The timeframe leg is unaffected, and the run is billed as 5 backtests either way."}}}}}},"responses":{"200":{"description":"Job started — returns {jobId}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}}}}},"/v1/backtests/{id}/multi-asset/{jobId}":{"get":{"summary":"Poll the multi-asset job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Progress while running; full result when done","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/robustness-screen":{"post":{"summary":"Start the Robustness Screen: samples every dimension in one job (power tier; billed as 5)","description":"One job that samples the sweep, peer market and walk forward dimensions and returns a single gated verdict. Billed as 5 backtests. One screen at a time per account. Send an `Idempotency-Key` header (or `idempotency_key` in the body) to make a retry replay the ORIGINAL job: the reply then carries `reused: true` and nothing is billed a second time.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Screen started — returns {jobId, totalCells}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}},"403":{"description":"power_tier_required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"a screen is already in progress for this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"plan quota exhausted while billing the screen — nothing was charged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/robustness-screen/{jobId}":{"get":{"summary":"Poll the Robustness Screen job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Progress while running; full result when done","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/context":{"get":{"summary":"Context performance insights (why trades won/lost by regime); may be {pending:true}","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/context/trades":{"get":{"summary":"Paginated per trade context rows","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/context/bucket-trades":{"post":{"summary":"Paginated trades inside ONE context bucket (relabels stored trades; quota free)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["dimensions","context_key"],"properties":{"dimensions":{"type":"array","minItems":1,"maxItems":5,"items":{"type":"object","properties":{"id":{"type":"string"}}}},"context_key":{"type":"string","maxLength":512},"mode":{"type":"string","enum":["entry","exit"]},"page":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":100}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/rephrase":{"post":{"summary":"Rewrite a query into clearer, parser friendly phrasing (metered per plan; cached repeats free)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":10,"maxLength":10000}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/runs/{runId}/indicators/{name}":{"get":{"summary":"Plotted values of one indicator on a run (names in the backtest row indicator_names)","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"name","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9._-]+$","maxLength":128}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/{id}/test":{"post":{"summary":"Fire a signed webhook.test event once (no retries): verify your receiver + signature handling","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"status":{"type":"integer"},"delivered":{"type":"boolean"}}}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/context-run":{"post":{"summary":"Re-run gated on a pre-entry context filter (BILLS one credit)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","required":["contextFilter"],"properties":{"contextFilter":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Job started — returns {jobId}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}}}}},"/v1/backtests/{id}/tags":{"patch":{"summary":"Replace the run's organization tags (max 10 × 24 chars)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","maxItems":10,"items":{"type":"string","maxLength":24}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/indicators/validate":{"post":{"summary":"Validate a Pine script (compile check only, no run)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pine_code"],"properties":{"pine_code":{"type":"string"}}}}}},"responses":{"200":{"description":"Answers {success, meta, indicator, diagnostics} at the top level (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success"],"properties":{"success":{"type":"boolean","const":true},"meta":{"type":"object","additionalProperties":true,"description":"The compiled script's schema (inputs, plots)."},"indicator":{"type":"object","additionalProperties":true,"description":"The same schema as meta, kept for older clients."},"diagnostics":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/v1/indicators/lint":{"post":{"summary":"Offline Pine diagnostics (quota free)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pine_code"],"properties":{"pine_code":{"type":"string"}}}}}},"responses":{"200":{"description":"Answers {success, diagnostics, clean} at the top level (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","diagnostics","clean"],"properties":{"success":{"type":"boolean","const":true},"diagnostics":{"type":"array","items":{"type":"object","additionalProperties":true}},"clean":{"type":"boolean","description":"True when no diagnostic is an error."}}}}}}}}},"/v1/indicators/preview":{"post":{"summary":"Compile + run a Pine script against real data (async; no persist)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pine_code"],"properties":{"pine_code":{"type":"string"},"symbol":{"type":"string","default":"BTCUSDT"},"timeframe":{"type":"string","default":"1d"},"bars":{"type":"integer","default":5000}}}}}},"responses":{"202":{"description":"Answers {success, jobId, status} at the top level (no data wrapper): poll /v1/indicators/preview/{jobId}","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","jobId","status"],"properties":{"success":{"type":"boolean","const":true},"jobId":{"type":"string"},"status":{"type":"string","enum":["running"]}}}}}}}}},"/v1/indicators/preview/{jobId}":{"get":{"summary":"Poll a Pine preview job","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Answers {success, status, elapsedMs, result} at the top level (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","status"],"properties":{"success":{"type":"boolean","const":true},"status":{"type":"string","description":"running while the job works, then its final status."},"elapsedMs":{"type":"integer"},"result":{"type":"object","additionalProperties":true,"description":"Present once the job finished: the compiled run (plots, rows, graphics)."},"offloaded":{"type":"boolean","description":"True when the result was too large to inline; read resultUrl."},"resultUrl":{"type":"string","description":"Present only when offloaded."}}}}}},"403":{"description":"Not your preview job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Preview job not found or expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/export/pine":{"post":{"summary":"Convert a parsedQuery, or an existing backtest by id, into a TradingView Pine v6 strategy() script (pure transform, not billed; plans with data exports)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"parsedQuery":{"type":"object","additionalProperties":true},"backtestId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"script":{"type":"string"},"unsupported":{"type":"array","items":{"type":"string"}}}}}}}}},"403":{"description":"feature_not_available — the plan does not carry data exports; the message names the tier that does","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/overfit":{"get":{"summary":"Overfitting verdict: Deflated Sharpe + PBO, deflated by the configs tried on the strategy session (quota free; plans with the overfitting verdict)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"feature_not_available — the plan does not carry the overfitting verdict; the message names the tier that does","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/condition-insights":{"post":{"summary":"Forward outcome base rates for ONE entry condition (a filter probe, not a backtest; workload capped, quota free)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["condition"],"properties":{"condition":{"type":"object","additionalProperties":true},"asset":{"type":"string"},"timeframe":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/gallery":{"get":{"summary":"Showcase strategies to start from","description":"Public, opted in shared runs. Each card carries `author`: `{handle, kind}` where kind is \"username\" (the author chose a handle), \"email\" or \"anonymous\" (they did not, and the server fallback decides which), or null when authorship cannot be resolved. No user ids.","parameters":[{"name":"sort","in":"query","schema":{"type":"string","enum":["sharpe","return","dsr"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":60}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/strategy-templates":{"get":{"summary":"The categorised strategy template library (trend, mean reversion, breakout, momentum, risk managed, macro) as worked examples","description":"A committed copy of the /templates page rows: id, title, category, difficulty, the plain English `query`, suggestedAsset, suggestedTimeframe, freeRunnable. freeRunnable=true (default) keeps the rows a Free account can run (crypto USDT, 1h to 1w, at most three years); false returns every row with `plan`, the lowest plan that runs it, and `planReason`. Pure, no credit.","parameters":[{"name":"category","in":"query","schema":{"type":"string","enum":["trend","mean_reversion","breakout","momentum","risk_managed","macro"]}},{"name":"freeRunnable","in":"query","schema":{"type":"boolean","default":true}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":24,"default":12}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/notification-channels":{"get":{"summary":"Which alert channels will deliver (Telegram linked? email?): client safe shape","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/portfolio/runs/{id}/analysis":{"get":{"summary":"A completed book's analysis layer: metrics, grade, per asset attribution, benchmark, Monte Carlo, walk forward, out of sample (quota free)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/portfolio/sweep":{"post":{"summary":"Rerun a whole book across 2 to 5 values of one book level knob (BILLS K×N credits; async → jobId). Idempotency-Key supported","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["config","parameter"],"properties":{"config":{"type":"object","additionalProperties":true},"parameter":{"type":"object","required":["key","values"],"properties":{"key":{"type":"string","enum":["initialCapital","maxConcurrentPositions","bookMaxDrawdownPct","totalExposureCapPct"]},"values":{"type":"array","minItems":2,"maxItems":5,"items":{"type":"number"}}}},"idempotency_key":{"type":"string","maxLength":128}}}}}},"responses":{"202":{"description":"Returns {jobId, credits}","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"config/parameter missing or malformed (see error for which), or SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Error"},{"$ref":"#/components/schemas/SymbolRefusal"}]}}}},"402":{"description":"PORTFOLIO_SWEEP_QUOTA_EXCEEDED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"PORTFOLIO_SWEEP_RETRY_ORIGINAL_FAILED — an Idempotency-Key replay whose original request threw; retry with a new key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"PORTFOLIO_SWEEP_DISABLED — disabled in production unless PORTFOLIO_SWEEP_ENABLED=true","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/portfolio/sweep/{jobId}":{"get":{"summary":"Poll a portfolio sweep (per value cells + best once done)","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/portfolio/sweep/{jobId}/cancel":{"post":{"summary":"Cancel a running sweep. Every not yet run book is refunded","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screener/scan":{"get":{"summary":"The tradable crypto universe with per token strength scores (cache fresh, ~5 min)","description":"Optional EMA cross filter: emaFast and emaSlow together keep only the tokens whose fast EMA crossed the slow EMA in emaDirection (default bullish) within the last emaWithin closed bars (default 3) on emaTimeframe (default 1d). The 100 most traded tokens of the scan are read; kept rows carry `emaCross {fast, slow, direction, crossedAt, barsAgo}` and `data.emaCross` summarises the pass. Without the pair the response is unchanged.","parameters":[{"name":"minVolume","in":"query","schema":{"type":"integer","minimum":0}},{"name":"barCount","in":"query","schema":{"type":"integer","minimum":10,"maximum":200}},{"name":"emaFast","in":"query","schema":{"type":"integer","minimum":2,"maximum":199}},{"name":"emaSlow","in":"query","schema":{"type":"integer","minimum":3,"maximum":200}},{"name":"emaDirection","in":"query","schema":{"type":"string","enum":["bullish","bearish","any"],"default":"bullish"}},{"name":"emaWithin","in":"query","schema":{"type":"integer","minimum":1,"maximum":20,"default":3}},{"name":"emaTimeframe","in":"query","schema":{"type":"string","enum":["1h","4h","12h","1d","3d","1w"],"default":"1d"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"EMA cross filter: the candle store did not answer in time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screener/rsps":{"get":{"summary":"Market regime verdict per timeframe: RUN | REVIEW | SKIP","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/token-stats":{"get":{"summary":"Per token forward outcome base rates for a tf + signal condition","parameters":[{"name":"tf","in":"query","schema":{"type":"string"}},{"name":"condition","in":"query","schema":{"type":"string","enum":["all","sol_beta","btc_beta","eth_beta"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/sectors":{"get":{"summary":"Crypto sector performance (optional date, else latest)","parameters":[{"name":"date","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/rsps/matrix":{"get":{"summary":"Pairwise RSPS dominance for the top-k tokens","parameters":[{"name":"tf","in":"query","schema":{"type":"string"}},{"name":"k","in":"query","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/custom-benchmark":{"get":{"summary":"Correlation + beta of the universe vs a chosen benchmark (workload capped)","parameters":[{"name":"benchmark","in":"query","required":true,"schema":{"type":"string"}},{"name":"tf","in":"query","schema":{"type":"string"}},{"name":"barCount","in":"query","schema":{"type":"integer","minimum":5,"maximum":200}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/token-multitf":{"get":{"summary":"One token's recent OHLCV + multi TF screener rows (capped; workload capped)","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string"}},{"name":"tf","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string"},"description":"Inclusive lower bound on open_time; scopes the OHLCV/screener window instead of always returning the tail of full history."},{"name":"to","in":"query","schema":{"type":"string"},"description":"Inclusive upper bound on open_time."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":2000}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/profiler":{"post":{"summary":"Start the Perfect Token Profiler (async → poll /v1/screener/profiler/{jobId}; workload capped)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["h"],"properties":{"h":{"type":"integer","minimum":1,"maximum":100},"tf":{"type":"string"},"topN":{"type":"integer","minimum":1,"maximum":50},"stride":{"type":"integer","minimum":1,"maximum":200},"minDollarVolume":{"type":"number","minimum":0}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/profiler/{jobId}":{"get":{"summary":"Poll a profiler run (full result once status=done)","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screener/saved-scans":{"get":{"summary":"Your saved screener filters","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}},"post":{"summary":"Save a screener filter (upsert by name; filter_json ≤ 32KB)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","filter_json"],"properties":{"name":{"type":"string","maxLength":100},"filter_json":{"type":"object","additionalProperties":true},"notes":{"type":"string","maxLength":400}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/saved-scans/{id}":{"delete":{"summary":"Delete a saved scan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/screener/scan-alerts":{"get":{"summary":"Your scan alerts","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}},"post":{"summary":"Create a scan alert (paid plans; Telegram else email delivery; max 25 active)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","conditions"],"properties":{"name":{"type":"string","maxLength":100},"conditions":{"type":"object","additionalProperties":true},"interval_minutes":{"type":"integer","minimum":1,"maximum":10080},"notes":{"type":"string","maxLength":400}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"402":{"description":"payment_required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/monthly-returns":{"get":{"summary":"Returns calendar (run_id comes from GET /v1/backtests/{id})","description":"Period over period returns as a grid: rows x columns plus a compounded row total, with best/worst cell and the green cell rate. Computed from the FULL equity curve, never paged, because a partial window would compute a different grid. The bucket ADAPTS: decades when the run is too long to show by month, months from half a year up, otherwise days, otherwise hours, and never finer than the bar interval. Read `granularity` before interpreting a cell. `columns` labels the cells left to right; `totalLabel` names the trailing total (DECADE/YTD/MTD/DAY). The run's first bucket measures from inception and is therefore partial. `data` is null when the run is too short to grid at any bucket.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"granularity","in":"query","required":false,"schema":{"type":"string","enum":["year","month","day","hour"]},"description":"Pin the bucket instead of letting it adapt (e.g. month on a run that rolled up to decades)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":["object","null"],"properties":{"granularity":{"type":"string","enum":["year","month","day","hour"]},"totalRows":{"type":"integer","description":"Rows the data produced; equals rows.length unless a display bound applied."},"basis":{"type":"string"},"columns":{"type":"array","items":{"type":"string"},"description":"Column headers left to right: Jan..Dec, 1..31, or 00..23."},"totalLabel":{"type":"string","enum":["YTD","MTD","DAY"]},"rows":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","description":"Row label: \"2024\" | \"Mar 2024\" | \"12 Mar\"."},"cells":{"type":"array","items":{"type":["number","null"]},"description":"Return in percent per column; null where the curve has no point there."},"totalPct":{"type":["number","null"],"description":"The row's cells compounded."}}}},"bestCell":{"type":["object","null"],"properties":{"cell":{"type":"string"},"pct":{"type":"number"}}},"worstCell":{"type":["object","null"],"properties":{"cell":{"type":"string"},"pct":{"type":"number"}}},"greenCells":{"type":"integer","description":"Cells that closed above where they opened."},"redCells":{"type":"integer","description":"Cells that closed below."},"flatCells":{"type":"integer","description":"Cells the curve covered but the strategy never moved through: no position, and so no outcome to be green or red about. On a selective strategy this is most of the calendar."},"activeCells":{"type":"integer","description":"greenCells + redCells. The denominator for greenRatePct."},"totalCells":{"type":"integer","description":"greenCells + redCells + flatCells."},"greenRatePct":{"type":["number","null"],"description":"Green share of the ACTIVE cells, not of the calendar. A strategy in the market one day in four is not \"green 19% of the time\"; it is green 19% of all days and 69% of the days it held a position, and only the second is a statement about the strategy."},"seasonality":{"type":["object","null"],"description":"Whether one slice of the calendar (day of week for a daily grid, month of year for a monthly one, hour of day for an hourly one) differs from the typical slice by more than chance produces. Carries `headline` (the finding as a sentence, with its own evidence), `basis` (how to read it), `method`, and per group means, q values and verdicts. A null `verdict` is a REFUSAL for want of sample. Report it as \"no verdict\", never as \"no effect\". Null for a decade grid, which has no season."}}}}}}}},"404":{"description":"not_found (run not owned, expired, or no equity curve)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/candles":{"get":{"summary":"Run dataset: candles (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/candles` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/equity":{"get":{"summary":"Run dataset: equity (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/equity` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/buy-and-hold-equity":{"get":{"summary":"Run dataset: buy-and-hold-equity (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/buy-and-hold-equity` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/trades":{"get":{"summary":"Run dataset: trades (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/trades` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call. Each element is one closed trade. Runs saved since 2026-09-14 also carry `entryRegimePostHoc` / `exitRegimePostHoc`: the price action block at the entry / exit bar (1 Trend Up, -1 Trend Down, 0 Quiet Range, 2 Volatile Chop). POST HOC: classified with confirmed pivots, i.e. with bars after the trade opened; not knowable at entry; attribution and display only; never a signal. null = the classifier saw the bar and left it unlabelled; a missing key = never computed (older run): fall back to metrics.regimeBreakdown.segments, never read a missing key as \"unclassified\".","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/chart-markers":{"get":{"summary":"Run dataset: chart-markers (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/chart-markers` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/monte-carlo":{"get":{"summary":"Run dataset: monte-carlo (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/monte-carlo` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/condition-logs/entry":{"get":{"summary":"Run dataset: condition-logs/entry (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/condition-logs/entry` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/condition-logs/exit":{"get":{"summary":"Run dataset: condition-logs/exit (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/condition-logs/exit` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/regime-segments":{"get":{"summary":"Run dataset: regime-segments (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/regime-segments` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call. The price action regime block timeline as run length spans {start, end, state} (epoch ms, end inclusive; 1 Trend Up, -1 Trend Down, 0 Quiet Range, 2 Volatile Chop; gaps = bars the classifier declined to label). Its own dataset since 2026-09-14: metrics.regimeBreakdown carries only segmentCount. Chart data for the regime tinted views; per trade attribution is on the trade rows.","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/runs/{runId}/equity-display":{"get":{"summary":"Run dataset: equity-display (run_id comes from GET /v1/backtests/{id})","description":"The numbers behind a finished run. Requires the `resultsHistory` plan feature. The same data is served to the app at `/api/runs/{runId}/equity-display` under a session JWT; this is the key-authed mirror. Page with `offset`+`limit`, or ask for `maxPoints` to get an even downsample of the WHOLE range in one call. The equity curve at DISPLAY resolution: up to ~4,000 calendar aligned buckets (hours, days or months, whichever the run's span affords), each contributing its first, lowest, highest and last bar as real {date, equity, drawdown} points, so the line and the drawdown strip are exact at this resolution and the last bar of every period is present. Runs saved since 2026-09-14. Read `equity` for the per bar series (rolling statistics, bar exact windows).","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"start","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"end","in":"query","description":"ISO 8601 — clip the range","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"First N rows (truncates a long run to its beginning)","schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"maxPoints","in":"query","description":"Even downsample to at most N rows across the whole range","schema":{"type":"integer","minimum":2,"maximum":50000}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":100000000}},{"name":"raw","in":"query","description":"Gzip passthrough opt-in; only the literal \"1\" enables it","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_feature_required (resultsHistory)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found (run not owned or expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me":{"get":{"summary":"Identify the key's owner","description":"Returns `userId` and `username`: the public handle shown as the author on runs this account publishes, or null if none is set.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Missing/invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage":{"get":{"summary":"Plan tier + backtest credit usage","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"tier":{"type":"string"},"backtestLimit":{"type":["integer","null"]},"backtestsUsed":{"type":["integer","null"]},"backtestsRemaining":{"type":["integer","null"]},"currentPeriodEnd":{"type":["string","null"]}}}}}}}}}}},"/v1/parse":{"post":{"summary":"Plain English → structured strategy (bills one LLM parse)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":10,"maxLength":10000},"customIndicatorHints":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Saved custom indicator names referenced in the query (see GET /v1/indicators)."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ParsedQuery"}}}}}},"422":{"description":"clarification_needed | missing_parameters | invalid_strategy — nothing billed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests":{"post":{"summary":"Run a backtest (bills one credit; idempotency supported)","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":128},"description":"Replay safe retries: same key + same body → the original run, no second credit."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["parsedQuery"],"properties":{"parsedQuery":{"$ref":"#/components/schemas/ParsedQuery"},"savedIndicatorMapping":{"type":"object","additionalProperties":{"type":"string"},"description":"parsedName → saved indicator name (explicit timeConstraint dates required)."},"customIndicatorHints":{"type":"array","maxItems":20,"items":{"type":"string"}},"idempotency_key":{"type":"string","maxLength":128},"wait":{"type":"boolean","default":true,"description":"false → 202 immediately after enqueue; poll /status."}}}}}},"responses":{"200":{"description":"Run finished within the sync window","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/BacktestRow"}}}}}},"202":{"description":"Still running — poll GET /v1/backtests/{id}/status; the credit stands and the result is saved","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"analysisId":{"type":["string","null"]},"status":{"type":"string","const":"running"},"message":{"type":"string"}}}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}},"409":{"description":"idempotency_key_reuse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"cannot_execute | custom_indicator_required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"QUEUE_BACKPRESSURE | queue_unavailable — retryable; credit refunded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"Run history (filterable, sortable, paginated)","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"sort","in":"query","schema":{"type":"string","enum":["created_at","total_return","win_rate","total_trades","sharpe_ratio","max_drawdown","profit_factor","execution_time_ms"]}},{"name":"order","in":"query","schema":{"type":"string","enum":["asc","desc"]}},{"name":"search","in":"query","schema":{"type":"string","maxLength":200}},{"name":"asset","in":"query","schema":{"type":"string"},"description":"Symbol or comma list"},{"name":"timeframe","in":"query","schema":{"type":"string"}},{"name":"tag","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["completed","failed","running","pending"]}},{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}":{"delete":{"summary":"Delete a saved backtest: permanent, and its datasets go with it","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"One run in full","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/BacktestRow"}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/status":{"get":{"summary":"Cheap progress poll (completed | running | failed | cancelled)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"analysisId":{"type":"string"},"status":{"type":"string","enum":["completed","running","failed","cancelled"]},"stage":{"type":["string","null"]},"percent":{"type":["number","null"]}}}}}}}},"404":{"description":"not_found (unknown id or progress window expired)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/cancel":{"post":{"summary":"Cancel a queued run and refund its credit (queued only)","description":"Cancels a run that is still queued and refunds the credit it was metered at enqueue. A run already computing is not stopped (status: running); a finished run is never refunded (status: completed).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"analysisId":{"type":"string"},"status":{"type":"string","enum":["cancelled","running","completed","failed","not_found"]},"refunded":{"type":"boolean"},"reason":{"type":"string"}}}}}}}}}}},"/v1/backtests/{id}/share":{"post":{"summary":"Mint the public share link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Revoke the share link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/chart-share":{"post":{"summary":"Publish a public chart link for a run","description":"Builds the price chart with its trades and indicators from the layout the owner last saved for the run (a default layout when none is saved) and publishes it at a short /c/ URL anyone can open. The strategy rules are hidden unless `rules` is true.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"boolean","default":false,"description":"Publish the strategy rules on the page."},"title":{"type":"string","maxLength":120}}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"id":{"type":"string","pattern":"^[A-Za-z0-9]{12}$"},"url":{"type":"string"},"status":{"type":"string","enum":["live"]},"version":{"type":"integer"},"layout":{"type":"string","enum":["stored","default"]},"rules":{"type":"boolean"},"title":{"type":["string","null"]}}}}}}}},"400":{"description":"invalid_query","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"CHART_SHARE_LIMIT","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"CHART_SHARE_TOO_LARGE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"CHART_SHARE_RATE_LIMITED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/chart-shares":{"get":{"summary":"List the chart links of a run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/chart-shares/{shareId}":{"delete":{"summary":"Revoke a chart link","parameters":[{"name":"shareId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9]{12}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/strategies/{id}/iterations":{"get":{"summary":"Edit/version history of a strategy session","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators":{"get":{"summary":"List saved custom indicators","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}},"post":{"summary":"Compile a custom indicator and save it. One of four source languages","description":"One endpoint, four source types: send exactly one of pine_code (compiled via the TV Oracle), js_code, py_code, or csv_data (precomputed values). Whichever is present decides the compile pipeline; sending zero or more than one is a validation error.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":255},"pine_code":{"type":"string","maxLength":100000,"description":"Pine Script source. Exactly one of pine_code/js_code/py_code/csv_data is required."},"js_code":{"type":"string","maxLength":131072,"description":"JavaScript indicator source (sandboxed), under 128KB."},"py_code":{"type":"string","maxLength":131072,"description":"Python indicator source (sandboxed), under 128KB."},"csv_data":{"type":"string","maxLength":1500000,"description":"Precomputed indicator values as CSV text, under 1.5MB once JSON encoded."},"symbol":{"type":"string","default":"BTCUSDT"},"timeframe":{"type":"string","default":"1d"},"bars":{"type":"integer","minimum":1,"maximum":50000,"default":5000}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error — zero or more than one source field, or a field over its size cap","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"feature_not_included — the plan gate for the language sent (customIndicators for js/py/csv, pineIndicators for pine_code)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Compile/validation failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators/{name}":{"get":{"summary":"One saved indicator (metadata)","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a saved indicator","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Answers {success, message} (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success"],"properties":{"success":{"type":"boolean","const":true},"message":{"type":"string"}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators/{name}/data":{"get":{"summary":"A saved indicator's plotted series over a date range","description":"JavaScript and Python indicators are computed for the symbol and timeframe given. A Pine indicator is rerun by the Oracle when chartOracle=1 (with symbol, timeframe and bars, counted back from now), else its stored rows are returned. A CSV indicator returns its own rows. Rows are keyed by plot name.","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"startDate","in":"query","required":true,"schema":{"type":"string"}},{"name":"endDate","in":"query","required":true,"schema":{"type":"string"}},{"name":"symbol","in":"query","required":false,"schema":{"type":"string"}},{"name":"timeframe","in":"query","required":false,"schema":{"type":"string"}},{"name":"bars","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50000}},{"name":"chartOracle","in":"query","required":false,"schema":{"type":"string","enum":["1","true"]}},{"name":"jsParams","in":"query","required":false,"schema":{"type":"string"},"description":"JSON object of INPUTS overrides for a JavaScript or Python indicator."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"402":{"description":"feature_not_included — customIndicators","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"NO_DATE_OVERLAP — the stored rows do not cover the range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The indicator failed to compute (stage, line and message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Indicator engine rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators/compute":{"post":{"summary":"Compute one built in study over a symbol, timeframe and range","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","symbol","timeframe","startDate","endDate"],"properties":{"type":{"type":"string","description":"Study id, e.g. rsi, ema, macd, bollinger_bands"},"params":{"type":"object","description":"Study parameters, e.g. {\"period\": 21}"},"symbol":{"type":"string"},"timeframe":{"type":"string"},"chartTimeframe":{"type":"string","description":"Step the series onto this timeframe's bars (no lookahead)"},"startDate":{"type":"string"},"endDate":{"type":"string"}}}}}},"responses":{"200":{"description":"Answers {success, type, params, paneType, series: {<key>: [{t, v}]}, barCount} at the top level (no data wrapper), plus notes when the pane has something to say about its data","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","type","paneType","series","barCount"],"properties":{"success":{"type":"boolean","const":true},"type":{"type":"string"},"params":{"type":"object","additionalProperties":true,"description":"The parameters the study was computed with."},"paneType":{"type":"string","enum":["overlay","oscillator"]},"series":{"type":"object","description":"One array of {t, v} per output, keyed by output name or period."},"barCount":{"type":"integer"},"graphics":{"type":"object","additionalProperties":true,"description":"Present only for zone studies: the boxes and labels to draw."},"sourceTimeframe":{"type":"string","description":"Present only when chartTimeframe stepped the series onto other bars."},"warmupBars":{"type":"integer","description":"Bar index where the warm up ends (the largest over the outputs)."},"warmupBarsByOutput":{"type":"object","additionalProperties":true,"description":"The same boundary per output."},"notes":{"type":"array","description":"Present only when the pane has something to say about its data. ORDER_FLOW_PREPARING: an order flow study (cvd, volume_delta) over a period whose trade archives are not stored yet. The series is empty, nothing is charged, and the period is queued for preparation: ask again after retryAfterMinutes.","items":{"type":"object","required":["code","message","retryAfterMinutes"],"properties":{"code":{"type":"string","enum":["ORDER_FLOW_PREPARING"]},"message":{"type":"string","description":"Plain words for the person looking at the pane."},"retryAfterMinutes":{"type":"integer","minimum":1}}}}}}}}},"402":{"description":"feature_not_included — chartStudies","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No candle data for the range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Range too large for this timeframe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks":{"post":{"summary":"Register a webhook receiver (max 3; secret shown once)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"HTTPS URL on a public host"},"events":{"type":"array","items":{"type":"string","enum":["backtest.completed","backtest.failed"]},"default":["backtest.completed"]}}}}}},"responses":{"201":{"description":"Created — includes the one-time signing secret","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"409":{"description":"webhook_limit_reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List webhook receivers (secrets never included)","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/webhooks/{id}":{"delete":{"summary":"Remove a webhook receiver","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/portfolio/parse":{"post":{"summary":"Parse a plain English multi asset portfolio prompt into per asset strategies + book level settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string"},"period":{"type":"string","description":"Optional date range, e.g. \"last 2 years\"."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Could not be parsed into a book","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/portfolio/execute":{"post":{"summary":"Run a multi asset portfolio backtest: BILLS ONE CREDIT PER ASSET","description":"Async: returns a jobId to poll at GET /v1/portfolio/execute/{jobId}. All or nothing, if the account cannot cover every asset the run is refused, not partially executed. Send Idempotency-Key to make a retry safe.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":128},"description":"Replaying a key returns the original run instead of billing again."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["assets"],"properties":{"assets":{"type":"array","items":{"type":"object","additionalProperties":true}},"initialCapital":{"type":"number"},"settings":{"type":"object","additionalProperties":true},"advanced":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"202":{"description":"Accepted — poll jobId","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}},"402":{"description":"insufficient_credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/portfolio/execute/{jobId}":{"get":{"summary":"Poll an async portfolio run (owner scoped, does not consume quota)","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/portfolio/runs":{"get":{"summary":"List saved portfolio runs","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/portfolio/runs/{id}/share":{"post":{"summary":"Create a public share link for a portfolio run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Revoke a portfolio run share link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators/js/validate":{"post":{"summary":"Validate JavaScript indicator source without loading bars","description":"Shape check only. Returns { ok, diagnostics[] }: a compile failure is a 200 with ok:false, not an HTTP error.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["js_code"],"properties":{"js_code":{"type":"string","maxLength":131072}}}}}},"responses":{"200":{"description":"Answers {success, ok, diagnostics, contract, stats} at the top level (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","ok","diagnostics"],"properties":{"success":{"type":"boolean","const":true},"ok":{"type":"boolean"},"diagnostics":{"type":"array","items":{"type":"object","additionalProperties":true}},"contract":{"type":"object","additionalProperties":true,"description":"The declared inputs, plots and visuals."},"stats":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators/js/preview":{"post":{"summary":"Compile and run JavaScript indicator source against real bars (nothing is saved)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["js_code"],"properties":{"js_code":{"type":"string","maxLength":131072},"symbol":{"type":"string","default":"BTCUSDT"},"timeframe":{"type":"string","default":"1d"},"bars":{"type":"integer","minimum":1,"maximum":5000,"default":500},"params":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Answers {success, ok, diagnostics, warnings, contract, series, ...} at the top level (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","ok","diagnostics"],"properties":{"success":{"type":"boolean","const":true},"ok":{"type":"boolean","description":"False when the source failed to compile or run; see diagnostics."},"diagnostics":{"type":"array","items":{"type":"object","additionalProperties":true}},"warnings":{"type":"array","items":{"type":"object","additionalProperties":true}},"contract":{"type":"object","additionalProperties":true,"description":"The declared inputs, plots and visuals."},"series":{"type":["object","null"],"description":"One array of {t, v} per plot, the same shape POST /v1/indicators/compute answers; null when ok is false."},"colorSeries":{"type":["object","null"]},"candles":{"type":["array","null"],"items":{"type":"object","additionalProperties":true}},"stats":{"type":"object","additionalProperties":true},"cost":{"type":["object","null"]},"window":{"type":"object","additionalProperties":true,"description":"The bars the preview compiled against: requested, loaded, used, first and last bar time."}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No data for the symbol and timeframe in the window","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The bars to test against could not be loaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators/py/validate":{"post":{"summary":"Validate Python indicator source without loading bars","description":"Shape check only. Returns { ok, diagnostics[] }: a compile failure is a 200 with ok:false, not an HTTP error.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["py_code"],"properties":{"py_code":{"type":"string","maxLength":131072}}}}}},"responses":{"200":{"description":"Answers {success, ok, diagnostics, contract, stats} at the top level (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","ok","diagnostics"],"properties":{"success":{"type":"boolean","const":true},"ok":{"type":"boolean"},"diagnostics":{"type":"array","items":{"type":"object","additionalProperties":true}},"contract":{"type":"object","additionalProperties":true,"description":"The declared inputs, plots and visuals."},"stats":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/indicators/py/preview":{"post":{"summary":"Compile and run Python indicator source against real bars (nothing is saved)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["py_code"],"properties":{"py_code":{"type":"string","maxLength":131072},"symbol":{"type":"string","default":"BTCUSDT"},"timeframe":{"type":"string","default":"1d"},"bars":{"type":"integer","minimum":1,"maximum":5000,"default":500},"params":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Answers {success, ok, diagnostics, warnings, contract, series, ...} at the top level (no data wrapper)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["success","ok","diagnostics"],"properties":{"success":{"type":"boolean","const":true},"ok":{"type":"boolean","description":"False when the source failed to compile or run; see diagnostics."},"diagnostics":{"type":"array","items":{"type":"object","additionalProperties":true}},"warnings":{"type":"array","items":{"type":"object","additionalProperties":true}},"contract":{"type":"object","additionalProperties":true,"description":"The declared inputs, plots and visuals."},"series":{"type":["object","null"],"description":"One array of {t, v} per plot, the same shape POST /v1/indicators/compute answers; null when ok is false."},"colorSeries":{"type":["object","null"]},"candles":{"type":["array","null"],"items":{"type":"object","additionalProperties":true}},"stats":{"type":"object","additionalProperties":true},"cost":{"type":["object","null"]},"window":{"type":"object","additionalProperties":true,"description":"The bars the preview compiled against: requested, loaded, used, first and last bar time."}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No data for the symbol and timeframe in the window","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The bars to test against could not be loaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/markets":{"get":{"summary":"The tradable market universe (symbols, asset classes, exchanges)","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/open-interest/scan":{"get":{"summary":"Coins ranked by open interest change","description":"Change in open interest in coin terms over a window, like for like across Bybit, OKX, Bitget, Hyperliquid and KuCoin, with price change and the positioning regime.","parameters":[{"name":"window","in":"query","schema":{"type":"string","enum":["1h","4h","24h","7d"]}},{"name":"sort","in":"query","schema":{"type":"string","enum":["oi_move","oi_change","oi_drop","open_interest"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50}},{"name":"minOpenInterestUsd","in":"query","schema":{"type":"number"}},{"name":"regime","in":"query","schema":{"type":"string","enum":["new_longs","short_covering","new_shorts","long_liquidation","flat"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"upstream","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/positioning":{"get":{"summary":"Derivatives positioning for one coin","description":"Open interest and its regime, funding (per 8 hours, weighted by open interest), long and short liquidations over the same window, and the Binance long/short ratio, on one clock, with a plain summary. Crypto perps only.","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string"},"description":"BTCUSDT, ETH, SOLUSDT …"},{"name":"tf","in":"query","schema":{"type":"string","enum":["15m","30m","1h","2h","4h","6h","8h","12h","1d"]},"description":"Default 4h; the read covers the last 24 bars."},{"name":"from","in":"query","schema":{"type":"string"},"description":"Optional ISO date or timestamp."},{"name":"to","in":"query","schema":{"type":"string"},"description":"Optional ISO date or timestamp."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"not_applicable — the symbol has no perpetual futures","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"upstream","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/open-interest":{"get":{"summary":"Crypto perpetual open interest history","description":"Open interest aggregated across exchanges as OHLC bars, the series backtests read for aggregated_open_interest. A busy shared data budget is not an error: the answer is 200 with complete:false, missingRanges ([from, to, reason]) and retryAfterSeconds. Crypto perps only.","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string"},"description":"BTCUSDT, ETH, 1000PEPEUSDT …"},{"name":"tf","in":"query","required":true,"schema":{"type":"string","enum":["5m","15m","30m","45m","1h","2h","4h","6h","8h","12h","1d","3d","1w","1M"]}},{"name":"from","in":"query","required":true,"schema":{"type":"string"},"description":"ISO date or timestamp."},{"name":"to","in":"query","required":true,"schema":{"type":"string"},"description":"ISO date or timestamp."},{"name":"unit","in":"query","schema":{"type":"string","enum":["usd","coin"]},"description":"Default usd."},{"name":"breakdown","in":"query","schema":{"type":"string","enum":["1","true","yes"]},"description":"Add byVenue: each exchange's one-sided open interest at bar close (1h and slower)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error — a missing/invalid parameter or an unsupported timeframe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Requested range is too large; raise the timeframe or shorten the range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"not_applicable — the symbol has no perpetual futures (a stock, index, forex or metal)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"upstream — open interest could not be loaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/candles":{"get":{"summary":"Raw OHLCV for any symbol/timeframe/range","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string"}},{"name":"tf","in":"query","required":true,"schema":{"type":"string"},"description":"Timeframe, e.g. 4h."},{"name":"from","in":"query","required":true,"schema":{"type":"string"},"description":"ISO date or timestamp."},{"name":"to","in":"query","required":true,"schema":{"type":"string"},"description":"ISO date or timestamp."},{"name":"exchange","in":"query","schema":{"type":"string"}},{"name":"requireComplete","in":"query","schema":{"type":"string","enum":["1","true","yes"]},"description":"Refuse a short read: answer 409 INCOMPLETE_RANGE instead of 200 with a partial series. Omit it to accept whatever the cache and the feed can serve, and read `complete` / `missingRanges` yourself."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error — a missing/invalid parameter, or symbol_not_found (the ticker has no market data; do not retry)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No candle data exists for that symbol/timeframe in the requested range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"INCOMPLETE_RANGE — requireComplete was set and part of the range is missing; the gaps are listed in missingRanges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Requested range is too large — this endpoint buffers the whole series in one body; raise the timeframe or shorten the range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited — the market-data provider quota is exhausted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}}},"502":{"description":"upstream_unavailable — the market-data provider failed; retry later","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/candles/export":{"get":{"summary":"A whole window of OHLCV as one CSV or JSONL file, behind a short lived signed link (synchronous)","description":"The bulk path: /v1/candles and get_candles are for inspection. The answer carries the link (url, expires_at), the row count, the file sha256 and candles_sha256, the hash a server lab run records as window_sha256 for the same market and dates. The whole export runs inside this request; for long or cold windows use POST /v1/candles/export, which runs it as a background job. A closed window (its end day before today UTC and its last bar closed) that was exported before is served from the stored file without loading bars (`reused: true`).","parameters":[{"name":"symbol","in":"query","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","required":true,"schema":{"type":"string"},"description":"e.g. 1h."},{"name":"start","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"First day, YYYY-MM-DD."},{"name":"end","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"Last day, YYYY-MM-DD (included)."},{"name":"format","in":"query","schema":{"type":"string","enum":["csv","jsonl"]},"description":"Default csv."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"invalid_request: a missing or malformed parameter | symbol_ambiguous: the ticker names both a coin and a stock | symbol_unresolved: not a listed ticker, crypto pair or known company name; the message suggests the listing or how to write it (NASDAQ:AAPL, a USDT pair), do not retry unchanged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"symbol_not_found: no feed has that ticker; check it with GET /v1/markets, do not retry | no_candles: no data for that symbol and timeframe in the window","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"export_too_large: the window holds more bars than one export allows (the message gives the computed count and the limit); split it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: too many exports this minute (the message says how many seconds) | market_data_busy: the market data provider is busy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}}},"502":{"description":"market_data_unavailable: the market data provider failed; retry later","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"export_storage_unavailable: file storage is not configured or failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Start a candle export as a background job; poll GET /v1/candles/export/{exportId}","description":"Same request fields as the GET, in the JSON body (or the query). Answers 202 { exportId, status: \"queued\", estimatedSeconds }, or 200 { status: \"done\", url, ... } at once when the window is closed and already built. The same request from the same account while one is in flight (or within a few minutes after it finished) returns that export (`deduplicated: true`) and is not counted by the per account limit, which counts requests that start new work.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["symbol","timeframe","start","end"],"properties":{"symbol":{"type":"string"},"timeframe":{"type":"string"},"start":{"type":"string","format":"date"},"end":{"type":"string","format":"date"},"format":{"type":"string","enum":["csv","jsonl"]}}}}}},"responses":{"200":{"description":"done: the closed window was already built; the link is in the answer","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"202":{"description":"queued or running: { exportId, status, estimatedSeconds, deduplicated }","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"invalid_request | symbol_ambiguous","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"export_too_large: the message gives the computed bar count and the limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: too many new exports this minute; the message says how many seconds to wait","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}}},"500":{"description":"internal_error: the export could not be started; retryable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"export_queue_unavailable: the export could not be queued and nothing was started; retryable, retry in a moment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/candles/export/{exportId}":{"get":{"summary":"Poll a candle export","description":"status queued | running (progress: fetched_bars, expected_bars, percent; retryAfterSeconds) | done (the file fields and a link signed afresh on every poll) | failed (error: { code, message, retryable, retryAfter? }, e.g. symbol_not_found, market_data_busy, export_timeout) | cancelled. Exports are kept a day; another account's id answers 404.","parameters":[{"name":"exportId","in":"path","required":true,"schema":{"type":"string","pattern":"^cex_[a-f0-9]{24}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"invalid_query: not an export id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"export_not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal_error: the export could not be read; retryable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/candles/export/{exportId}/cancel":{"post":{"summary":"Cancel a candle export (a queued one never starts; a running one stops and uploads nothing)","parameters":[{"name":"exportId","in":"path","required":true,"schema":{"type":"string","pattern":"^cex_[a-f0-9]{24}$"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"invalid_query: not an export id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan does not include marketData","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"export_not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal_error: the cancel could not be recorded; retryable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/plans":{"get":{"summary":"Public plan tiers, prices and per tier limits","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/compare/entitlement":{"get":{"summary":"Whether the plan includes strategy comparison (power tier); 403 naming the tier otherwise","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"plan_required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/chart":{"get":{"summary":"Rendered chart image for a run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"PNG image","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/variants":{"post":{"summary":"Start a strategy variant comparison job (power tier; billed as 5)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Accepted — returns {jobId}; poll the sibling GET","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"SYMBOL_UNRESOLVED (no market and no company name match) or SYMBOL_AMBIGUOUS (a crypto token and a listed share use the same symbol, e.g. CAT). Refused before billing, nothing is charged. details.blockers[0] is the repair card. For the run's own asset each candidates[].patch.asset is a one tap fix (the near company listing, or the token pair and the share listings): resend with the chosen asset. With scope \"condition\" the symbol is read by a condition (another market's indicator, a ratio, a correlation), not the run's asset: never change asset. Write the chosen symbol in that condition. When one entry or exit condition holds it, the card has a locator {section, index} and each candidates[].condition is that whole condition with its symbol field rewritten: replace the condition at the locator and resend. On a rerun of a saved backtest (storedRun true) a condition card has no candidates: the saved run cannot be changed in place, so edit that condition in the strategy and run it as a new backtest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SymbolRefusal"}}}},"403":{"description":"power_tier_required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"a variants run is already in progress for this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"plan quota exhausted while billing the run — nothing was charged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/variants/{jobId}":{"get":{"summary":"Poll a strategy variant job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/robustness-store":{"get":{"summary":"The persisted robustness results on a backtest (null per kind that never ran); no billing","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/backtests/{id}/gallery":{"post":{"summary":"Publish or unpublish a run in the public gallery","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"public":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/context/dimensions":{"get":{"summary":"List the dimension ids accepted by context reanalysis","description":"The built in indicators a run's trades can be bucketed by, each with its default period, output lines and a paste ready `builtin_<indicator>_<period>[_<output>]` id. The reanalyse validator accepts any well FORMED id, so check an id against this list before using it: one that is merely well formed validates but buckets no trades.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}}}}},"/v1/backtests/{id}/context/reanalyse":{"post":{"summary":"Rebucket a run's trades against a different context indicator or bucket count","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/regime-breakdown":{"post":{"summary":"Price action regime segmentation (trend up/down, quiet range, volatile chop) for a symbol and range","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"validation_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/strategies/{id}/session-label":{"patch":{"summary":"Rename a strategy session","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label"],"properties":{"label":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/strategies/iterations/{id}/label":{"patch":{"summary":"Rename one iteration in a strategy's edit history","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label"],"properties":{"label":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/screener/scan-alerts/{id}":{"patch":{"summary":"Update a scan alert (pause, rename, change conditions or interval)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a scan alert","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/accounts":{"get":{"summary":"Connected exchange accounts: id, venue, label, testnet, active, stream state, master/sub. The connectionId every other trading route takes. Credentials are never returned (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/balances":{"get":{"summary":"Per-account balances (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/positions":{"get":{"summary":"Open positions across every connected account: side, size, entry, unrealized P&L, leverage, liquidation price where the venue reports one (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/orders":{"get":{"summary":"Resting (still working) orders (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/orders/history":{"get":{"summary":"Every order placed on the connected accounts in ANY state (filled, cancelled, rejected), newest first. Read from the platform ledger, not fanned out to the venues; each row is annotated with the `deploymentId` that owns it, or none if placed by hand. A manual order the exchange refused at placement never received an exchange order id: its row has `id: null`, keeps `clientOrderId`, and carries `placementRejected: true` (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200},"description":"Default 100."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/fills":{"get":{"summary":"Execution feed across accounts, newest first: price, quantity, fee, side, timestamp. What actually happened, as opposed to what was asked for (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500},"description":"Default 100."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/symbols":{"get":{"summary":"Tradable symbols, across every account or on one (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"connectionId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/accounts/{connectionId}/symbol-info":{"get":{"summary":"Venue trading filters for one symbol: tickSize, stepSize, minQty, maxQty, minNotional, precision, and the perp maintenance-margin rate. Read before sizing anything (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"connectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"symbol","in":"query","schema":{"type":"string"}},{"name":"marketType","in":"query","schema":{"type":"string","enum":["perp","spot"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/accounts/{connectionId}/funding":{"get":{"summary":"Normalized perp funding payments for one symbol. Funding is a real cash flow and is NOT in a trade's price P&L (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"connectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"symbol","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"integer"},"description":"unix-ms"},{"name":"to","in":"query","schema":{"type":"integer"},"description":"unix-ms"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/trades":{"get":{"summary":"Closed trades — one row per round trip with realised P&L net of fees and funding. Cursor-paged: echo BOTH nextCursor (as before) and nextCursorId (as before_id), or trades sharing a close time are skipped across the page boundary (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"source","in":"query","schema":{"type":"string","enum":["live","paper","manual","all"]},"description":"Which ledger. \"live\" means real money and expands to live+manual; \"paper\" is simulated."},{"name":"deployment_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"before","in":"query","schema":{"type":"string","format":"date-time"},"description":"Cursor: nextCursor from the previous page."},{"name":"before_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor tie-break: nextCursorId from the previous page."},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window start."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window end."},{"name":"symbols","in":"query","schema":{"type":"string"},"description":"Comma-separated venue symbols, e.g. BTCUSDT,ETHUSDT."},{"name":"direction","in":"query","schema":{"type":"string","enum":["long","short"]}},{"name":"result","in":"query","schema":{"type":"string","enum":["win","loss"]}},{"name":"dows","in":"query","schema":{"type":"string"},"description":"Days of week, 0=Sun..6=Sat, e.g. 1,2,3. Listing all seven is treated as no filter."},{"name":"hour_from","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session start hour. IGNORED unless hour_to is sent too — a lone bound is not guessed at."},{"name":"hour_to","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session end hour. Required alongside hour_from."},{"name":"tz","in":"query","schema":{"type":"string"},"description":"IANA timezone for day/hour bucketing."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"trades":{"type":"array","items":{"type":"object","additionalProperties":true}},"nextCursor":{"type":["string","null"]},"nextCursorId":{"type":["string","null"]}}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/trades/stats":{"get":{"summary":"Win rate, profit factor, expectancy, average win/loss over the same filters as the list. Computed over ALL matching trades, not a page (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"source","in":"query","schema":{"type":"string","enum":["live","paper","manual","all"]},"description":"Which ledger. \"live\" means real money and expands to live+manual; \"paper\" is simulated."},{"name":"deployment_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window start."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window end."},{"name":"symbols","in":"query","schema":{"type":"string"},"description":"Comma-separated venue symbols, e.g. BTCUSDT,ETHUSDT."},{"name":"direction","in":"query","schema":{"type":"string","enum":["long","short"]}},{"name":"result","in":"query","schema":{"type":"string","enum":["win","loss"]}},{"name":"dows","in":"query","schema":{"type":"string"},"description":"Days of week, 0=Sun..6=Sat, e.g. 1,2,3. Listing all seven is treated as no filter."},{"name":"hour_from","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session start hour. IGNORED unless hour_to is sent too — a lone bound is not guessed at."},{"name":"hour_to","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session end hour. Required alongside hour_from."},{"name":"tz","in":"query","schema":{"type":"string"},"description":"IANA timezone for day/hour bucketing."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/trades/{id}/timeline":{"get":{"summary":"One trade's full event history: signal, orders, fills, protective legs, scale-outs, exit (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/portfolio/equity":{"get":{"summary":"Account equity curve from recorded snapshots (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"mode","in":"query","schema":{"type":"string","enum":["paper","live"]},"description":"Restrict to paper or live. Omit for both."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":10000}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/portfolio/snapshot":{"get":{"summary":"Point-in-time equity, allocated capital, open exposure and position count against the portfolio caps (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/portfolio/daily-pnl":{"get":{"summary":"Realised P&L per calendar day. Days with no closed trade are absent, not zero (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"mode","in":"query","schema":{"type":"string","enum":["paper","live"]},"description":"Restrict to paper or live. Omit for both."},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window start."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window end."},{"name":"symbols","in":"query","schema":{"type":"string"},"description":"Comma-separated venue symbols, e.g. BTCUSDT,ETHUSDT."},{"name":"direction","in":"query","schema":{"type":"string","enum":["long","short"]}},{"name":"result","in":"query","schema":{"type":"string","enum":["win","loss"]}},{"name":"dows","in":"query","schema":{"type":"string"},"description":"Days of week, 0=Sun..6=Sat, e.g. 1,2,3. Listing all seven is treated as no filter."},{"name":"hour_from","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session start hour. IGNORED unless hour_to is sent too — a lone bound is not guessed at."},{"name":"hour_to","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session end hour. Required alongside hour_from."},{"name":"tz","in":"query","schema":{"type":"string"},"description":"IANA timezone for day/hour bucketing."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/portfolio/pnl-breakdown":{"get":{"summary":"Realised P&L split by symbol, side, hour of day and weekday (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"mode","in":"query","schema":{"type":"string","enum":["paper","live"]},"description":"Restrict to paper or live. Omit for both."},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window start."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window end."},{"name":"symbols","in":"query","schema":{"type":"string"},"description":"Comma-separated venue symbols, e.g. BTCUSDT,ETHUSDT."},{"name":"direction","in":"query","schema":{"type":"string","enum":["long","short"]}},{"name":"result","in":"query","schema":{"type":"string","enum":["win","loss"]}},{"name":"dows","in":"query","schema":{"type":"string"},"description":"Days of week, 0=Sun..6=Sat, e.g. 1,2,3. Listing all seven is treated as no filter."},{"name":"hour_from","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session start hour. IGNORED unless hour_to is sent too — a lone bound is not guessed at."},{"name":"hour_to","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session end hour. Required alongside hour_from."},{"name":"tz","in":"query","schema":{"type":"string"},"description":"IANA timezone for day/hour bucketing."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/portfolio/attribution":{"get":{"summary":"Realised P&L attributed per deployment/strategy, net of fees and funding (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"mode","in":"query","schema":{"type":"string","enum":["paper","live"]},"description":"Restrict to paper or live. Omit for both."},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window start."},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"},"description":"ISO-8601 window end."},{"name":"symbols","in":"query","schema":{"type":"string"},"description":"Comma-separated venue symbols, e.g. BTCUSDT,ETHUSDT."},{"name":"direction","in":"query","schema":{"type":"string","enum":["long","short"]}},{"name":"result","in":"query","schema":{"type":"string","enum":["win","loss"]}},{"name":"dows","in":"query","schema":{"type":"string"},"description":"Days of week, 0=Sun..6=Sat, e.g. 1,2,3. Listing all seven is treated as no filter."},{"name":"hour_from","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session start hour. IGNORED unless hour_to is sent too — a lone bound is not guessed at."},{"name":"hour_to","in":"query","schema":{"type":"integer","minimum":0,"maximum":23},"description":"Session end hour. Required alongside hour_from."},{"name":"tz","in":"query","schema":{"type":"string"},"description":"IANA timezone for day/hour bucketing."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/portfolio/risk-budget":{"get":{"summary":"Active risk (distance-to-stop × size, summed) against the self-imposed cap, plus how many open positions carry NO stop and are therefore unbounded (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"mode","in":"query","schema":{"type":"string","enum":["paper","live"]},"description":"Restrict to paper or live. Omit for both."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments":{"get":{"summary":"Every strategy deployment with its live runtime state: mode, status, position, execution state, quarantine flag, consecutive losses (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}":{"get":{"summary":"One deployment: full config plus live runtime state (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/position":{"get":{"summary":"That deployment's OWN open position. Not redundant with /trading/positions, which reads the VENUE and therefore shows nothing for a paper deployment however large its paper position (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/trades":{"get":{"summary":"That deployment's closed trades (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/orders":{"get":{"summary":"PAPER-engine orders for that deployment. Empty for a LIVE deployment — its real orders are on the account, at /v1/trading/orders/history (annotated with deploymentId) (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/fills":{"get":{"summary":"PAPER-engine fills for that deployment. Empty for a LIVE deployment — its real executions are at /v1/trading/fills, which carry `orderId` but no deployment: match that against /v1/trading/orders/history on the same connectionId and symbol to find the owner (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/health":{"get":{"summary":"Runtime health per deployment: market-data liveness, execution state, in-flight orders, quarantine, open-position consistency. Defaults to limit=25 — page for a larger account (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500},"description":"Default 25."},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}},{"name":"mode","in":"query","schema":{"type":"string","enum":["paper","live"]},"description":"Restrict to paper or live. Omit for both."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/risk-config/{deploymentId}":{"get":{"summary":"Effective risk limits for one deployment (scope: trading:read)","x-ttq-scope":"trading:read","parameters":[{"name":"deploymentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/quarantines":{"get":{"summary":"Deployments the runtime has fenced off because it could not reconcile their state. A quarantined deployment is NOT trading, and its `status` alone would read as healthy (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/pause":{"patch":{"summary":"Stop a deployment acting on new signals. Does NOT close an open position (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"description":"Recorded in the operator audit log. Say why — an automated pause with no explanation is the entry someone will need to understand later."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/pause-entries":{"patch":{"summary":"Stop a deployment OPENING anything while leaving its exits armed (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"description":"Recorded in the operator audit log. Say why — an automated pause with no explanation is the entry someone will need to understand later."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/resume":{"patch":{"summary":"Undo a pause (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"description":"Recorded in the operator audit log. Say why — an automated pause with no explanation is the entry someone will need to understand later."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/deployments/{id}/close":{"post":{"summary":"Close the deployment's open position at the market (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"fraction":{"type":"number","exclusiveMinimum":0,"maximum":1,"description":"Portion to close. Omit = all of it."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/orders/{orderId}":{"delete":{"summary":"Cancel one resting order (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"orderId","in":"path","required":true,"schema":{"type":"string"}},{"name":"connectionId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"symbol","in":"query","required":true,"schema":{"type":"string"},"description":"Venues address an order by (symbol, market), not by id alone — a mismatch is a silent no-op, not an error."},{"name":"marketType","in":"query","schema":{"type":"string","enum":["perp","spot"]},"description":"The book the order was placed on. Default perp."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/orders/cancel-all":{"post":{"summary":"Cancel every resting order EXCEPT protective SL/TP legs on symbols that still hold a position (reported per connection in `preserved[]`; strategy-owned stops are always kept). Does NOT close positions. `includeProtective` is not honoured on this surface (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"Limit to one account. Omit = every connected account."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/positions/{symbol}":{"delete":{"summary":"Close a position held on the ACCOUNT (manual, or the remainder no strategy owns) (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"symbol","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["connectionId","side"],"properties":{"connectionId":{"type":"string","format":"uuid"},"side":{"type":"string","enum":["long","short"]},"fraction":{"type":"number","exclusiveMinimum":0,"maximum":1,"description":"Share of the WHOLE venue position — would also flatten a strategy's share."},"quantity":{"type":"number","exclusiveMinimum":0,"description":"Exact base amount, capped at the live size. Use this when only part of the position is yours to close."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/positions/close-all":{"post":{"summary":"Flatten every open position at the market. The strategies that opened them keep running unless paused (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"Limit to one account. Omit = every connected account."}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/positions/{symbol}/protection":{"patch":{"summary":"Set or replace the exchange-side stop-loss and/or take-profit on an open position. Sending one leg leaves the other untouched; neither is refused (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"symbol","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["connectionId","side"],"properties":{"connectionId":{"type":"string","format":"uuid"},"side":{"type":"string","enum":["long","short"]},"stopLoss":{"type":"number","minimum":0},"takeProfit":{"type":"number","minimum":0}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/kill-switch":{"get":{"summary":"Active kill switches and their scope (scope: trading:read)","x-ttq-scope":"trading:read","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"HALT trading over a deployment, an account, or everything this user runs. Halting is not closing — open positions stay open (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scopeType"],"properties":{"scopeType":{"type":"string","enum":["user","deployment","connection","global"],"description":"\"global\" is admin-only and is refused for an API key."},"scopeId":{"type":"string","format":"uuid","description":"Required for deployment and connection scope; authorized against the caller."},"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/trading/kill-switch/{id}":{"delete":{"summary":"Release a kill switch so the deployments it halted may act again (scope: trading:write)","x-ttq-scope":"trading:write","description":"Risk-reducing only. Nothing on the trading surface can open a position, place a resting order, or move funds. Rate-limited to 30 live-account actions per minute per user.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":true}}}}}},"403":{"description":"insufficient_scope — the key lacks trading:read/trading:write; or upgrade_required — the plan has no live trading","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"plan_unavailable — the plan could not be resolved; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}