Compile and register source, returning its id and declared parameter hints.
Create a dataset and return the one-time presigned upload session.
Soft-delete a dataset. Existing backtests remain unaffected.
Release a registered strategy: removes it from both QTSurfer.getStrategy and QTSurfer.getStrategies.
Backtests already run against this strategy are unaffected, and re-submitting the same source afterwards registers a new strategy with a new id rather than undeleting this one. Deleting your own copy of a strategy never affects anyone else's copy of the same source (e.g. a shared/marketplace listing).
the id returned when the strategy was compiled
Download one hour of klines for an instrument as a Blob.
Download one hour of raw tickers for an instrument as a Blob.
Defaults to Lastra; pass { format: 'parquet' } for Parquet.
Run a backtest end-to-end: compile the strategy, prepare the requested
data range, execute it, and resolve with the result once execution
completes. See the underlying backtest workflow for the
stage-by-stage error and retry semantics.
Optionalopts: BacktestOptionsQueue ingest after the upload PUT succeeds; poll QTSurfer.getDatasetUpload.
Read one dataset and its current-version metadata.
List datasets owned by the authenticated caller.
Read ingestion state for one upload session.
List an exchange's instruments, each with the per-data-type coverage
that says which date windows are actually downloadable.
Omitting segment asks for the exchange's default segment, which is
'spot' today. The API answers with a HAL envelope that this method
unwraps to the instrument array, so the envelope's meta.segment,
meta.updatedAt and segment-discovery _links do not reach you: if you
need certainty about which segment you are looking at, pass segment
explicitly rather than relying on the default.
exchange identifier, e.g. binance
Optionalsegment: InstrumentSegmentList every strategy you have registered and not deleted, most recently
compiled first. Never 404s — an empty array means you have none.
Each entry deliberately omits validation; check a specific strategy's
verdict with QTSurfer.getStrategy. See StrategySummary.
Read everything the platform records about a strategy: whether it is
registered at all, its validation verdict, the market data its compiled
class requires, and any engine notices the check raised. This is what to
poll after QTSurfer.validateStrategy returns queued: true, and
the only place a verdict is read from.
Check compiledAt against validatedAt before trusting a verdict: the
strategy may have been recompiled since it was recorded, in which case
the verdict describes bytecode that is no longer what would run.
See StrategyState for why even a fresh 'passed' is a floor
rather than a guarantee.
the id returned when the strategy was compiled
Read back the exact source last submitted for a strategy id, whitespace and comments included.
A 404 (carried on status) covers two indistinguishable cases: the id
was never registered by you, or it resolves only through a shared/
marketplace reference that carries no source of its own.
the id returned when the strategy was compiled
Use QTSurfer.getDatasets.
Optionalsegment: InstrumentSegmentOpen or recover an upload session for another version of a dataset.
Run the full compile → prepare → executeSweep pipeline and resolve once the platform has accepted the sweep, handing back a Sweep that keeps polling the leaderboard in the background.
The whole sweep is one call because the execute-sweep endpoint is addressed by the id of an already-prepared dataset: exposing the stages separately would hand dataset lifecycle to the caller and buy nothing. Preparing is idempotent, so sweeping the same window twice prepares it once.
The returned promise rejects with QTSStrategyCompileError if
compilation fails, QTSPreparationError if data preparation fails,
QTSExecutionError if the platform rejects the sweep — an expanded
grid over the server limit, or a walk-forward request whose fold count
multiplies past the sweep budget, both answer 400 — QTSTimeoutError
if a stage exceeds timeoutMs, or QTSCanceledError if the caller's
signal fires before the sweep is accepted. A plain QTSError means
the request itself is malformed (an empty grid, a non-positive step, a
walk-forward block with fewer than two folds, or naming both/neither of
instrument/datasetId) and never reached the network.
What the sweep found arrives through Sweep.result, which is also where the semantics of the leaderboard are documented. Acceptance already answers three things worth reading before any result exists — the effective seed, whether this submission enqueued anything, and whether this is a walk-forward sweep — see Sweep.accepted.
const handle = await qts.sweep({
strategy: source,
exchangeId: 'binance',
instrument: 'BTC/USDT',
from: '2026-01-01T00:00:00Z',
to: '2026-02-01T00:00:00Z',
params: { rsiPeriod: { from: 7, to: 28, step: 1 } },
});
const leaderboard = await handle.result;
Optionalopts: SweepOptionsPUT raw CSV bytes to a dataset upload session's presigned URL.
Ask the platform to check that a registered strategy can actually run: it instantiates the compiled class and drives it through a bounded synthetic series, so a wiring fault surfaces here instead of at the first backtest.
Idempotent, and two-outcome. queued: false means a verdict already
existed for the current compilation and came back unchanged in state —
nothing was queued. queued: true means a check was just started, and is
not terminal: poll QTSurfer.getStrategy until validation
leaves 'pending'. The discriminant reports whether work was started,
not whether a verdict exists, because a queued: false answer can
itself carry validation: 'pending' from a check an earlier call queued;
state.validation is what tells you that.
Poll with a deadline of your own. 'pending' is not guaranteed to
resolve — a queued check can go unreported for far longer than one takes,
which the platform eventually flags as validationStalled. Nothing about
the strategy is disproved when that happens, but a caller that waits for
a terminal verdict without a timeout can wait forever. This SDK ships no
polling helper for that reason: the timeout is the caller's policy.
Whatever the verdict, it is a floor rather than a guarantee — see StrategyState.
the id returned when the strategy was compiled
Thin, stateless wrapper over
@qtsurfer/api-clientthat exposes the SDK's workflow methods (backtest,sweep,downloadTickers,downloadKlines), the platform catalog (getExchanges,getInstruments) and the strategy surface (compileStrategy,validateStrategy,getStrategy,getStrategies,deleteStrategy,getStrategyCode). Constructing an instance reconfigures the underlying api-client singleton, so avoid holding twoQTSurfers with differentbaseUrls or tokens alive in the same process — they will race. Prefer theauthenticate()helper over this constructor unless you already manage the JWT lifecycle yourself.