@qtsurfer/sdk
    Preparing search index...

    Interface Sweep

    Handle for a running parameter sweep, returned by QTSurfer.sweep once the platform has accepted it. The leaderboard keeps being polled in the background.

    interface Sweep {
        accepted: ExecuteSweepAccepted;
        requestId: string;
        result: Promise<ExecuteSweepResult>;
        state: SweepState;
        strategyId: string;
        sweepId: string;
        equityCurve(
            runIx: number,
            options?: EquityCurveOptions,
        ): Promise<EquityCurveResult>;
        getEquityCurve(
            runIx: number,
            options?: EquityCurveOptions,
        ): Promise<EquityCurveResult>;
        getResults(
            view?: { order?: SweepOrder; ranking?: SweepRanking },
        ): Promise<ExecuteSweepResult>;
        getSensitivity(objective?: SweepObjective): Promise<SweepSensitivity>;
        results(
            view?: { order?: SweepOrder; ranking?: SweepRanking },
        ): Promise<ExecuteSweepResult>;
        sensitivity(objective?: SweepObjective): Promise<SweepSensitivity>;
    }
    Index
    accepted: ExecuteSweepAccepted

    What acceptance already answered, before a single trial has run, exactly as the platform sent it.

    Three of its fields are the reason this is exposed rather than folded away:

    • seed — the effective seed, generated platform-side when the request omitted one. Submitting it again is what makes a randomly sampled sweep replayable.
    • queuedfalse means an identical sweep already existed and nothing new was enqueued. The handle is still valid and still resolves; it is just reading a sweep this call did not start.
    • walkForward — present exactly when this is a walk-forward sweep. It is the discriminator, and it is available here immediately, so code watching progress can branch on the answer's shape without waiting for Sweep.result.
    requestId: string

    The prepared dataset every trial ran against — the prepare jobId the workflow resolved before submitting, which is also what addresses this sweep on the wire.

    This is the value the workflow prepared with, not the acceptance echo of it. Sweep.accepted carries the echo, unmodified, for anyone who wants to compare the two.

    result: Promise<ExecuteSweepResult>

    Resolves with the final leaderboard once the sweep stops advancing.

    This resolves on every terminal status, cancellation included'COMPLETED', 'PARTIAL' and 'CANCELLED' all hand back the result rather than raising. That is a deliberate divergence from backtest(), which rejects with QTSCanceledError when its run is aborted: cancelling a sweep is documented as leaving completed rows readable, and throwing them away would lose the only reason to cancel a sweep late rather than early. Read status to find out which of the three you got. The promise rejects only for transport failures, HTTP errors, and stage timeouts.

    'PARTIAL' means at least one unit of work died and its runs are simply missing. There is no failed status for a sweep as a whole, so a sweep whose every shard died is 'PARTIAL' with an empty leaderboard — check leaderboardSize before reading anything into a top row.

    The default order is not the raw objective order. It is plateau order, and ranking on the result says which was actually applied — not always the one requested, because a sweep with no stored parameter grid cannot be plateau-ranked and falls back to raw. See SweepRanking.

    The default view is capped. When truncated is true, rows exist that the leaderboard does not carry — leaderboardSize counts what is available. Sweep.results with order: 'natural' is what returns all of them, in runIx order and with no ranking applied. That is a re-read of this same sweep, not a second one.

    plateauScore and neighbourCount are read together. A neighbour count of 0 means the point had no neighbours in the grid to compare against, so its plateau score is unevidenced rather than confirmed — on its own it is indistinguishable from a genuinely robust one.

    deflatedSharpe is the probability that a row's Sharpe reflects real edge rather than the best draw from however many vectors were tried. Around 0.95 and up it survives the multiple-testing correction; near 0.5 or below it is not distinguishable from the best of a pile of coin flips. It is absent on aborted runs, and on sweeps with too few trials to establish any dispersion to deflate against.

    pbo is the probability of backtest overfitting for the sweep as a whole: how often the configuration that won in-sample lands below median out-of-sample. Above roughly 0.5 the sweep is selecting noise, and that verdict is about the search, not about any one row — a high value discredits the top row however good it looks. It is computed once the last unit of work finishes, so it is absent while the sweep is still running and on sweeps too small for the statistic to mean anything.

    walkForward is the discriminator, and it appears as soon as the sweep is accepted — before any fold has finished — so it is safe to branch on while polling (it is also on Sweep.accepted). When it is present, the leaderboard is one row per completed fold: that fold's winner as it scored out-of-sample, with runIx carrying the fold index rather than a position in the grid. No plateau score, deflated Sharpe or PBO figure is reported for one — the out-of-sample numbers are already the honest measurement. See WalkForwardResult for why an absent paramDrift is not a zero.

    A sweep can finish having scored nothing, because every shard failed before producing a row. When that happens failReason carries the cause reported by the first shard to fail — typically something the whole grid would have hit, such as a strategy that could not be loaded. Read it before concluding that a sweep with no rows simply found nothing: those are different outcomes and the leaderboard alone cannot tell them apart. Only the first failure is recorded, so where several shards failed for different reasons this names one of them rather than summarising all — pair it with progress.failedShards for the count.

    state: SweepState

    Local snapshot of the sweep lifecycle; reading it does not contact the server.

    strategyId: string

    The compiled strategy every trial shares.

    sweepId: string

    Server-side sweep identifier.

    • Parameters

      • runIx: number
      • Optionaloptions: EquityCurveOptions

      Returns Promise<EquityCurveResult>

      Use Sweep.getEquityCurve.

    • Fetch a retained trial curve. A 404 means the run did not retain one.

      Parameters

      • runIx: number
      • Optionaloptions: EquityCurveOptions

      Returns Promise<EquityCurveResult>

    • Re-read this sweep's rows under a different view.

      This is a read, not a re-run. It compiles nothing, prepares nothing and submits nothing: the same sweep is asked for its rows again with different query parameters, so no second sweep is created and nothing is enqueued. The view a SweepOptions chose applies to the background poll behind Sweep.result; this is how to look at the same sweep another way afterwards.

      It is the route to rows the ranked view dropped. When truncated is true on a result, rows exist that the leaderboard does not carry; order: 'natural' returns every available row untruncated, in deterministic runIx order.

      ranking is ignored when order is 'natural' — that view is always ordered by runIx, and the response reports 'raw'. The platform accepts both rather than rejecting the pair, and answers with the ordering it actually applied.

      Readable while the sweep is still running, in which case it returns the rows finished so far — exactly like Sweep.sensitivity. Like every handle-scoped call, it does not take part in an AuthenticatedClient's refresh-on-401 policy.

      Parameters

      • Optionalview: { order?: SweepOrder; ranking?: SweepRanking }

        which view to read; an absent property takes the platform default (order: 'ranked', ranking: 'plateau')

      Returns Promise<ExecuteSweepResult>

      QTSError on any non-2xx response, with the HTTP status on status.

    • How the objective moves as each parameter moves — the question a leaderboard cannot answer. A leaderboard says which point won; a sweep can spend its whole budget on an axis that never moved the objective at all, and the top rows hide that completely.

      A marginal takes one axis and collapses every other one: for each value of that axis it aggregates every run that used it, whatever the rest of the parameters were. A flat marginal means the axis did not matter over the range swept. best, mean and worst are all reported because them disagreeing is the signal — a value with a high best and a poor mean only works in specific company, which is an interaction, and a single number would hide it. A heatmap does the same over a pair of axes, where that interaction is visible directly.

      Check heatmapsTruncated. Marginals are always complete; the pair surfaces are quadratic in the axis count and may be capped to stay inside the response budget. When the flag is true, at least one pair was left out, so the list you have is not the full set of interactions. This method hands back the whole SweepSensitivity rather than just its surfaces precisely so that flag cannot be lost on the way out.

      Readable while the sweep is still running, in which case the aggregates describe the runs finished so far and rowsAnalysed says how many that was. Aborted runs are excluded throughout: a run that threw measured nothing, and counting it as a bad outcome would invent evidence against a parameter value that was never really tested.

      Like every handle-scoped call, this does not take part in an AuthenticatedClient's refresh-on-401 policy.

      Parameters

      • Optionalobjective: SweepObjective

        which metric to aggregate; omit to use the objective the sweep was submitted with

      Returns Promise<SweepSensitivity>

      QTSError on any non-2xx response, with the HTTP status on status.