Live Execution

Start a strategy on a live market feed

Changed on

Starts your strategy against a live market feed. A new run begins in the sandbox stage — a short trial that compares an independent second execution against the first for agreement — before it is eligible for promotion to the live stage where it actually publishes signals other systems can act on. Poll GET /strategy/{strategyId}/live (or PATCH/DELETE /live/{runId} once you have the runId) to watch stage move from SANDBOX to LIVE.

A strategy that has already been through that trial does not go through it again. When an earlier run of yours of the same compiled strategy was promoted to LIVE, and none of that compilation's runs was stopped for using more resources than allowed, the new run starts in LIVE at once: the response says stage: LIVE and carries the earlier verdict in gate. The parameters, sources and instruments may differ from the earlier run. Submitting the strategy again (POST /strategy) compiles it anew, and a new compilation goes through the sandbox like a first run. Send sandbox: true to start in the sandbox anyway — for example to read the run's signals back over the connection while you debug it, which the live stage does not keep.

Only one run per strategy at a time — starting again while one is already running is 409; stop the current one first.

sources takes exactly one entry today (multi-source strategies are not supported yet). type is ticker or kline; anything else is rejected. Both connect to the lightest (fastest) cadence available for the exchange — today that is 1 tick/second on every supported exchange; choosing among several cadences is not offered yet.

instruments can be left out. A QTScript strategy can declare which instruments it accepts with an instruments line in its source; when the compilation of the strategy records that selection as a list of pairs, a start that leaves instruments out, or sends ["*"], takes that list, and otherwise the run reads every instrument the exchange/segment offers. A list you send is taken as sent. Either side of an entry can be * (any base paired with USDT). The instruments the run reads come back in sources. See the "Live execution" guide, "Sources".

params is passed straight through to the strategy at start — the same free-form object POST /strategy/{strategyId}/validate and the backtest endpoints already accept. To change a parameter while the run is live, use PUT /live/{runId}/params instead; this endpoint only sets the values a run starts with.

Consuming a run's own output — its signals, and updating its parameters over a live connection instead of polling — is a WebSocket protocol on top of these REST endpoints; see the "Live execution" guide linked from this tag's description for the full flow (minting a connection token, the channel and RPC method).

Paper trading. Pass a paper block to have the run's hints executed in simulation from its first tick, as a backtest would execute them: fills, closed trades, equity and KPIs, with one simulated account per quote currency. Omitted, the run has no paper trading. It takes the same economics as a backtest's baseConfig plus where its output goes; read it back with GET /live/{runId}/paper. A strategy that listens to its own execution events (it overrides getExecutionCallback()) has no other execution venue, so it cannot start without a paper block.

Warming up. Pass warmFrom to choose how many seconds before its start the run replays the market feed from, so that its indicators and windows have history when the first live tick arrives. 0 replays nothing: the run delivers its first signal as soon as it is running, but its indicators start empty and the first bar of a window can be partial. Omitted, the platform replays from the start of the current 15-minute block, which is between 0 and 900 seconds before the run's start, so the first bar of a 15-minute window is complete. The value in effect, yours or the platform's, comes back as warmFrom. It can be set only here, when the run is started. See the "Live execution" guide, "Warming up".

A plain WebSocket stream. Pass stream: true to get a secret URL for this run's signals that a simple client, or a service that passes them on to others, can open as an ordinary WebSocket, from the sandbox stage on. The URL is in the response (streamUrl) and in GET /strategy/{strategyId}/live; treat it like a password. See the "Live execution" guide.

post/strategy/{strategyId}/live

Request

  • Base URL: https://api.qtsurfer.net/v1
  • URL: https://api.qtsurfer.net/v1/strategy/{strategyId}/live
  • Auth: HTTP bearer

Path parameters

strategyIdstring required

Unique identifier for a compiled strategy, derived from the source itself: the same code always yields the same id, for every caller. How much formatting the id ignores depends on the language — see POST /strategy for exactly which rewrites preserve it and which do not.

Example:6bsh31ikwkuivhtgcoa6s4

The id returned by POST /strategy

Request body

paramsobject

Strategy parameters to start with. Opaque key/value pairs — see this strategy's own declaredProperties (from POST /strategy) for the keys it accepts.

visibility'private' | 'public'

A public run appears in GET /live/public and its signal channel accepts subscriptions from anyone, not only you — from the moment it is in the live stage, which is when it is promoted or, for a run that starts there, at once. While it is a sandbox trial, public is only what you asked for, and only you can read it.

relayboolean

Request that this run's signals be relayed over its WebSocket channel, from its first signal — in the sandbox stage too, where only you can subscribe to it. See the "Live execution" guide.

sandboxboolean

Start in the sandbox stage even though an earlier run of yours already took this compiled strategy through it. Without it, such a strategy starts in LIVE at once; with true it starts in SANDBOX like a first run, which is how to read its signals back over the connection (history, kept for the sandbox stage only) while you debug it. For a strategy that has not been through the sandbox it changes nothing: it always starts there. Anything other than true or false is 400.

streamboolean

Ask for a stream URL: a secret address that a simple client, or a service that passes your signals on to others, can open as a plain WebSocket to receive this run's signals as they are produced, one JSON text frame per signal, with none of the live-execution protocol around it. The URL comes back as streamUrl in the response to this call. Available from the sandbox stage on, on the plans that may broadcast; any other plan gets 429. It can be asked for only when the run is started (not added later), and it also turns relay on. See the "Live execution" guide, "A plain WebSocket stream of a run".

warmFrominteger

How many seconds before the run's start to replay the market feed from, so the strategy's indicators and windows have history when its first live tick arrives. 0 replays nothing: the run delivers its first signal as soon as it is running, but its indicators start empty and the first bar of a window can be partial. Omitted, the platform replays from the start of the current 15-minute block: between 0 and 900 seconds before the run's start, depending on when it starts (0 if it starts exactly on a quarter hour), so the first bar of a 15-minute window is complete. The value in effect, the one you sent or the one the platform chose, is reported back as warmFrom on the run. Signals about the replayed time are not pushed on the run's channel or stream: they describe events from before the run started. It can be set only when the run is started: it is not a parameter of PUT /live/{runId}/params, and changing it means stopping the run and starting it again. Anything that is not an integer from 0 to 3600 is 400. See the "Live execution" guide, "Warming up".

namestring
descriptionstring

Example request

{
  "sources": [
    {
      "venueType": "cx",
      "exchange": "binance",
      "segment": "spot",
      "instruments": [
        "BTC/USDT"
      ]
    }
  ]
}

Response

Started — the run's own state, in the sandbox stage (in the live stage for a strategy that has already been through the sandbox), with its streamUrl when you asked for a stream

strategyIdstring required

Unique identifier for a compiled strategy, derived from the source itself: the same code always yields the same id, for every caller. How much formatting the id ignores depends on the language — see POST /strategy for exactly which rewrites preserve it and which do not.

runIdstring required

This run's own id — its canonical identity for PATCH/PUT .../params and for GET /live/public.

namestring
descriptionstring
visibility'private' | 'public' required
stage'SANDBOX' | 'LIVE' required

A new run starts SANDBOX, a 24-hour trial in which it is compared against a second execution and checked for resource use and stability. A run that passes moves to LIVE automatically when the 24 hours are up. A run of a strategy that an earlier run of yours already took through the trial starts LIVE, unless you started it with sandbox: true.

statestring required

The run's health right now: STARTING (no runner has reported on it yet), RUNNING, LAGGING (behind the market data, usually while catching up; clears by itself), HUNG (stuck inside one strategy call for longer than allowed; clears when it returns), DEGRADED (its independent executions produced different signals), FAILED (refused, could not start or failed while running; reason says why) or STOPPED. LAGGING, HUNG and DEGRADED come and go on a running run. The set may grow: read an unknown value as a running run with something to look at. See the Live execution guide.

desired'RUNNING' | 'STOPPED' required

What you last asked for. state can lag this briefly after DELETE.

reasonstring

Why the run stopped or failed, when there is something to say; absent otherwise. It is never a stack trace or an internal message. Either resource: ... (the platform stopped the run for exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for a FAILED run: the strategy cannot consume the source type the run was started with, the run's definition was refused, the run could not start after several attempts, the strategy failed while processing data, the run lost its data feed, or the generic The run failed.. The set may grow: read an unrecognised sentence as a failure and do not parse it. A FAILED run usually stays desired: RUNNING until you stop it, and counts as active (409 on a new start, and toward your live-run limit) until then; one that can never run because its strategy cannot consume its source type is stopped by the platform itself (desired: STOPPED), so it holds no place.

paramsobject required
paramsVersioninteger required

Increments on every accepted PUT .../params call, including one that resends the current values.

relayboolean required

Whether this run's signals are relayed over the WebSocket channel described in the "Live execution" guide. It is the value requested at start, in either stage.

startedAtMsinteger required

Epoch milliseconds.

gateobject

The sandbox trial's promotion verdict. Absent for the whole 24-hour trial and present once it ends, so an absent gate means the trial has not finished. A run that started in LIVE without a trial has it from the start: the verdict of the earlier run it relies on, with inheritedFrom naming that run. passed is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API: treat it as opaque.

warmFrominteger

The warmFrom in effect for this run, in seconds: the one requested when the run was started or, when none was, the one the platform chose (the distance from the run's start back to the start of the current 15-minute block, 0 to 900). It is never null. It is present on every run started since the field exists and absent from a run started before it existed. It never changes while the run exists.

streamUrlstring uri

The run's secret stream URL (wss://…). Treat it like a password: anyone who holds it can read this run's signals, from the sandbox stage on. Present only when the run was started with stream: true, is wanted running, has not had its stream revoked, and your plan still lets you broadcast; absent otherwise (a plan that lets you broadcast again gets the same URL back). Rotate it with POST /live/{runId}/stream if it leaks, revoke it with DELETE /live/{runId}/stream.

Example response

{
  "strategyId": "6bsh31ikwkuivhtgcoa6s4",
  "sources": [
    {
      "venueType": "cx",
      "exchange": "binance",
      "segment": "spot",
      "instruments": [
        "BTC/USDT"
      ]
    }
  ]
}

Changes