> ## Documentation Index
> Fetch the complete documentation index at: https://edgeful.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Use the optimizer

> All Access optimizer access through MCP and API keys, with compact results and bounded asynchronous runs.

An active, unpaused **All Access** membership includes optimizer access through your API key or MCP connection. Enable writes in the API dashboard to start or cancel jobs. Reads work with read-only credentials.

Your existing in-app limits stay the same. The app and integrations share one active server job per member. You can observe and cancel an externally started job in the app.

## Find results first

Ask your connected AI to search optimizer templates for a ticker and strategy. The tools are:

| Tool | Purpose |
| - | - |
| `describe_optimizer` | Supported inputs, a request template matching in-app defaults and current limits |
| `list_optimizer_records` | Search templates or list your own runs, saved results and favorites |
| `read_optimizer_result` | Ranked summaries, then selected-result settings, trades or charts |
| `submit_optimizer_job` | Start an asynchronous run with a stable UUID request ID |
| `get_optimizer_job` | Status by job ID or request ID |
| `cancel_optimizer_job` | Cancel your queued or running job |

Template discovery lists the current published generation. Previously published template IDs remain readable so saved links continue to work.

The request template uses the same starting inputs as a fresh in-app optimizer for the selected strategy: one year of data, full default sweep ranges and directions, matching durations and chart timeframes, contract sizing, and disabled filters with their preset values. Holdout validation is off by default; enable it explicitly when wanted (the default split is 80% training / 20% holdout). These are starting defaults, not your saved in-app settings.

Start with a summary page, then select a candidate ID for more detail. Responses fit 48,000 bytes: five results by default, twenty maximum, up to 100 trades per page, or 200 equity/drawdown points. Follow `page.next_offset` when present. Record lists are newest first; newly created or deleted records can change list offsets. Candidate/trade offsets refer to the stored, immutable result.

A run can succeed and keep no candidates. Its summary then returns an empty `items` list with `empty_result`: the reason (`filters_unreachable`, `filters_conflict` or `no_trades`), how many strategies were tested, and for each enabled filter the threshold against the best value any strategy achieved. Loosen the filters marked `unreachable` first.

## Charts and interpretation

Request `section=equity`, `drawdown`, `monthly` or `weekday` for one candidate. The response includes data and presentation hints: chart type, axes, units and references to the returned values. Your AI/client renders it; Edgeful does not generate an image or run another simulation. A table works if your client cannot render charts.

Training and holdout are labeled separately. Read `base_dataset` in summaries and `dataset` in detail responses: templates, template favorites and results without holdout validation use `full_period` for their base data, including when requested with `dataset=training`. Template holdout is a subset of that full period; never append it again or present full-period metrics as training-only. Training-only template metrics are not computed by this API. Sampled curves can omit extremes, so use stored metrics for authoritative drawdown and performance. Monthly/weekday charts use full stored aggregates. Finite metrics are numbers. Missing legacy values are `null`; nonfinite values are `{ "value": null, "status": "unavailable" | "positive_infinity" | "negative_infinity" }`. Chart y values remain numeric or `null`, with `value_status` explaining missing or nonfinite points. Template list rows additionally label a null profit factor as nonfinite (no losing trades), matching the app. None of these become zero. `drawdownProfitPct` is max drawdown as a percentage of net profit, matching the app's DD/profit column; it is `null` when the period was not profitable. Simulations have no starting balance, so there is no drawdown percentage of an account. Retain warnings, date range, sizing and validation context when presenting results.

## Start and resume work

For REST, send `Authorization: Bearer YOUR_EDGEFUL_API_KEY`. Fetch `GET /v1/optimizer/options` for the current input contract and runnable `request_template`, then submit:

```json theme={null}
{
  "request_id": "a UUID generated once for this request",
  "request_snapshot": "the request_template object, with your settings"
}
```

`POST /v1/optimizer/jobs` returns HTTP 202 with a durable job ID. Poll `GET /v1/optimizer/jobs/{job_id}` every ten seconds. If you cannot wait, keep the ID and resume later. On success, use `run_id` as `id` with `GET /v1/optimizer/results?source=run&id=...`.

Statuses `succeeded`, `failed` and `cancelled` are terminal; stop polling when `poll_after_seconds` is null. `failure_kind=request` means revise settings; `infrastructure` means you may retry the settings with a new ID and quota. A polling 429 does not fail the job.

`origin` identifies app or external jobs. Wait for an active app job to finish; cancel it only when you want it stopped, not just to free the shared slot. `result_expired=true` means a succeeded job's result has been removed; `payload_expired` separately identifies cleanup of the job's request/progress payload.

If the response was lost, repeat the same request ID and settings or use `GET /v1/optimizer/jobs/by-request/{request_id}`. An identical retry returns the original job, even after failure or cleanup. Changed settings with an accepted ID return HTTP 409 without `Retry-After`; use a new ID for new work. An active-job conflict returns 409 with `Retry-After`; keep the same ID and retry later. Rejected submissions do not bind the ID. A failed/cancelled accepted job requires a fresh ID and quota to try again.

## Shared external limits

All API keys and MCP connections belonging to one member share these budgets:

| Operation | Limit |
| - | - |
| New jobs | 10 seconds between admissions; 60 per rolling hour; 300 per rolling day |
| Submission attempts | 10 per minute; 240 per hour, including invalid requests and retries |
| Read attempts | 60 per minute, including busy/rejected reads |
| Status | 60 per minute/member and 12 per minute/job |
| Cancellation | 12 per minute, independent of submission quota |

Request windows start with the first request and expire after the named interval. New-job windows are rolling. Existing overall credential limits still apply. REST rejections include `Retry-After`; MCP errors state the retry interval. External result lists/details share one concurrent read slot across the service. If they are busy, retry after two seconds. When capacity or admission controls are unavailable, new external work is rejected temporarily. Preserve your request ID when retrying.

External jobs have bounded search dimensions, dates, price-bar workload, queue time and runtime. Discovery returns the enforced values. Reduce the requested sweep when preflight rejects it. Accepted failures/cancellations do not refund quota.

The queue deadline is five minutes. A job can expire before execution when preceding jobs run long or a worker is unavailable; admission does not guarantee execution before that deadline.

External history retains fifty unprotected runs separately from app history. Terminal job payloads expire after thirty days; already-deleted unreferenced external results have a thirty-day purge grace. Saved/favorite references protect results. Compact retry receipts remain for the life of your account, and expired payloads are labeled explicitly.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.