@qtsurfer/api-client 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -100,6 +100,29 @@ import type {
100
100
  GetDatasetImportData,
101
101
  GetDatasetImportResponse,
102
102
  GetDatasetImportError,
103
+ StopLiveData,
104
+ StopLiveResponse,
105
+ StopLiveError,
106
+ GetLiveData,
107
+ GetLiveResponse,
108
+ GetLiveError,
109
+ StartLiveData,
110
+ StartLiveResponse,
111
+ StartLiveError,
112
+ ListPublicLiveData,
113
+ ListPublicLiveResponse,
114
+ ListPublicLiveError,
115
+ UpdateLiveData,
116
+ UpdateLiveResponse,
117
+ UpdateLiveError,
118
+ UpdateLiveParamsData,
119
+ UpdateLiveParamsResponse,
120
+ UpdateLiveParamsError,
121
+ GetLiveRunSignalsData,
122
+ GetLiveRunSignalsResponse,
123
+ GetLiveRunSignalsError,
124
+ MintLiveConnectionTokenData,
125
+ MintLiveConnectionTokenResponse,
103
126
  } from "./types.gen";
104
127
  import { client as _heyApiClient } from "./client.gen";
105
128
 
@@ -366,22 +389,35 @@ export const listStrategies = <ThrowOnError extends boolean = false>(
366
389
  * Compile and register a strategy
367
390
  * Compiles raw strategy source and registers it, returning its `strategyId`.
368
391
  *
369
- * **This answers one question: is the source valid Java.** It compiles, registers, and hands
392
+ * The source is either **Java** — a class extending a strategy base class — or **QTScript**
393
+ * (beta), a compact strategy language whose braced bodies are plain Java. QTScript source
394
+ * begins with the `strategy` keyword — whitespace and comments (`//` or `* *`) before it
395
+ * are ignored — and that is how the two are told apart: there is no separate endpoint and
396
+ * no header to set. Once registered, a strategy is used the same way
397
+ * whichever language it was written in.
398
+ *
399
+ * **This answers one question: is the source valid.** It compiles, registers, and hands
370
400
  * back the id — nothing more. Whether the class can actually run is
371
401
  * `POST /strategy/{strategyId}/validate`, and everything known about a strategy, validation
372
402
  * included, is read from `GET /strategy/{strategyId}`. One place to ask, so there is no second
373
403
  * answer to keep in step.
374
404
  *
375
- * The `strategyId` is derived from what the code *means*, not from how it is written. Adding a
376
- * comment, inserting a blank line, re-indenting, reordering imports, or moving a method around
377
- * all return the **same** id — you have not created a second strategy. Renaming a variable,
378
- * changing an identifier's case, reordering fields, or reordering statements inside a method
379
- * return a **different** one.
405
+ * For **Java**, the `strategyId` is derived from what the code *means*, not from how it is
406
+ * written. Adding a comment, inserting a blank line, re-indenting, reordering imports, or
407
+ * moving a method around all return the **same** id — you have not created a second strategy.
408
+ * Renaming a variable, changing an identifier's case, reordering fields, or reordering
409
+ * statements inside a method return a **different** one.
410
+ *
411
+ * For **QTScript**, the id is derived from the text, because indentation is part of its
412
+ * grammar. Only differences that cannot change the strategy are ignored: a byte-order mark, the
413
+ * style of line endings, whitespace at the end of a line, and blank lines before the first and
414
+ * after the last line. Anything else — a comment, the indentation, a blank line in between —
415
+ * returns a **different** id.
380
416
  *
381
417
  * Two rules follow, and they are worth designing around:
382
418
  *
383
- * - re-submitting a strategy you have only reformatted is free, and gives you back the id you
384
- * already had, along with any validation already recorded against it;
419
+ * - re-submitting a Java strategy you have only reformatted is free, and gives you back the id
420
+ * you already had, along with any validation already recorded against it;
385
421
  * - the id says nothing about *behaviour*. Two sources that compute the same thing by
386
422
  * different means are two strategies, because deciding otherwise would mean deciding program
387
423
  * equivalence.
@@ -547,6 +583,10 @@ export const getStrategyCode = <ThrowOnError extends boolean = false>(
547
583
  * The same params always return the same `jobId` (idempotent). Repeated calls with identical
548
584
  * params do not enqueue duplicate work — they reuse the existing job.
549
585
  *
586
+ * Every source in `DataSourceType` can be prepared, but not every one can then be run: `funding`
587
+ * data can be prepared and is rejected by `execute` and `executeSweep`. A `kline` prepare takes
588
+ * the bar width from `cadence` — see `PrepareRequest`.
589
+ *
550
590
  * **`exchangeId: user` is reserved for your own uploaded data.** Instead of a managed
551
591
  * exchange, it prepares from a dataset you created via `POST /datasets` (see the **Dataset**
552
592
  * endpoints) — send `datasetId` in place of `instrument`. See `PrepareRequest` below for the
@@ -610,6 +650,10 @@ export const getPrepareStatus = <ThrowOnError extends boolean = false>(
610
650
  * The backend expands and executes the matrix internally; clients poll the returned
611
651
  * `sweepId` for incremental results.
612
652
  *
653
+ * `type` must be `ticker` or `kline`; a `kline` sweep, walk-forward included, runs over bars of
654
+ * the cadence the request was prepared at. `funding` can be prepared but not swept yet: it is
655
+ * rejected with `400` before anything is queued.
656
+ *
613
657
  * Supplying `walkForward` runs the sweep in a different mode entirely. Instead of scoring
614
658
  * every parameter vector once over the whole range, the data is split into F sequential
615
659
  * folds; each fold optimizes the full grid on its own window and then scores only its winner
@@ -807,6 +851,11 @@ export const getSweepRunEquityCurve = <ThrowOnError extends boolean = false>(
807
851
  * Returns immediately with a `jobId`; poll `GET /backtest/{exchangeId}/{type}/execute/{jobId}`
808
852
  * for the result.
809
853
  *
854
+ * `type` must be a source that can be executed: `ticker` or `kline`. A `kline` strategy is fed
855
+ * bars of the cadence its `prepareJobId` was prepared at — chosen by you when preparing, not by
856
+ * the strategy. `funding` can be prepared but not executed yet: it is rejected with `400`
857
+ * before anything is queued.
858
+ *
810
859
  * Optionally takes `params`: strategy properties for this one run, applied without
811
860
  * recompiling. This is how a sweep leaderboard winner gets re-run for its `equityCurve` —
812
861
  * a sweep row carries the ten ranking metrics but never a curve, whatever its size. Compile
@@ -1209,3 +1258,272 @@ export const getDatasetImport = <ThrowOnError extends boolean = false>(
1209
1258
  ...options,
1210
1259
  });
1211
1260
  };
1261
+
1262
+ /**
1263
+ * Stop this strategy's live run
1264
+ * Requests a stop. The run winds down at its own next check-in rather than instantly —
1265
+ * poll `GET`/`PATCH` `.../live` and expect `state` to remain `RUNNING` for a short window
1266
+ * after `desired` flips to `STOPPED`. Calling this again on an already-stopped run is not an
1267
+ * error; it returns the same (unchanged) state.
1268
+ *
1269
+ */
1270
+ export const stopLive = <ThrowOnError extends boolean = false>(
1271
+ options: Options<StopLiveData, ThrowOnError>
1272
+ ) => {
1273
+ return (options.client ?? _heyApiClient).delete<
1274
+ StopLiveResponse,
1275
+ StopLiveError,
1276
+ ThrowOnError
1277
+ >({
1278
+ security: [
1279
+ {
1280
+ scheme: "bearer",
1281
+ type: "http",
1282
+ },
1283
+ ],
1284
+ url: "/strategy/{strategyId}/live",
1285
+ ...options,
1286
+ });
1287
+ };
1288
+
1289
+ /**
1290
+ * Get this strategy's current (or most recent) live run
1291
+ * The run you last started for this strategy — its most complete state, including `params`
1292
+ * and the promotion `gate` once the sandbox trial has one to report. Returns the run's last
1293
+ * known state even after it has stopped; this endpoint never disappears history.
1294
+ *
1295
+ */
1296
+ export const getLive = <ThrowOnError extends boolean = false>(
1297
+ options: Options<GetLiveData, ThrowOnError>
1298
+ ) => {
1299
+ return (options.client ?? _heyApiClient).get<
1300
+ GetLiveResponse,
1301
+ GetLiveError,
1302
+ ThrowOnError
1303
+ >({
1304
+ security: [
1305
+ {
1306
+ scheme: "bearer",
1307
+ type: "http",
1308
+ },
1309
+ ],
1310
+ url: "/strategy/{strategyId}/live",
1311
+ ...options,
1312
+ });
1313
+ };
1314
+
1315
+ /**
1316
+ * Start a strategy on a live market feed
1317
+ * Starts your strategy against a live market feed. A new run always begins in the **sandbox**
1318
+ * stage — a short trial that compares an independent second execution against the first for
1319
+ * agreement — before it is eligible for promotion to the live stage where it actually
1320
+ * publishes signals other systems can act on. Poll `GET /strategy/{strategyId}/live` (or
1321
+ * `PATCH`/`DELETE` `/live/{runId}` once you have the `runId`) to watch `stage` move from
1322
+ * `SANDBOX` to `LIVE`.
1323
+ *
1324
+ * Only one run per strategy at a time — starting again while one is already running is `409`;
1325
+ * stop the current one first.
1326
+ *
1327
+ * `sources` takes exactly one entry today (multi-source strategies are not supported yet).
1328
+ * `type` is `ticker` or `kline`; anything else is rejected. Both connect to the lightest
1329
+ * (fastest) cadence available for the exchange — today that is 1 tick/second on every
1330
+ * supported exchange; choosing among several cadences is not offered yet.
1331
+ *
1332
+ * `params` is passed straight through to the strategy at start — the same free-form object
1333
+ * `POST /strategy/{strategyId}/validate` and the backtest endpoints already accept. To change
1334
+ * a parameter **while the run is live**, use `PUT /live/{runId}/params` instead; this endpoint
1335
+ * only sets the values a run starts with.
1336
+ *
1337
+ * Consuming a run's own output — its signals, and updating its parameters over a live
1338
+ * connection instead of polling — is a WebSocket protocol on top of these REST endpoints; see
1339
+ * the "Live execution" guide linked from this tag's description for the full flow (minting a
1340
+ * connection token, the channel and RPC method).
1341
+ *
1342
+ */
1343
+ export const startLive = <ThrowOnError extends boolean = false>(
1344
+ options: Options<StartLiveData, ThrowOnError>
1345
+ ) => {
1346
+ return (options.client ?? _heyApiClient).post<
1347
+ StartLiveResponse,
1348
+ StartLiveError,
1349
+ ThrowOnError
1350
+ >({
1351
+ security: [
1352
+ {
1353
+ scheme: "bearer",
1354
+ type: "http",
1355
+ },
1356
+ ],
1357
+ url: "/strategy/{strategyId}/live",
1358
+ ...options,
1359
+ headers: {
1360
+ "Content-Type": "application/json",
1361
+ ...options?.headers,
1362
+ },
1363
+ });
1364
+ };
1365
+
1366
+ /**
1367
+ * Browse public live runs
1368
+ * Every run whose owner marked it `public` and is currently live and running — anyone's,
1369
+ * yours included, and listed without revealing who owns it. Most recently started first.
1370
+ *
1371
+ * This is the only `Live Execution` endpoint that needs no `Authorization` header.
1372
+ *
1373
+ */
1374
+ export const listPublicLive = <ThrowOnError extends boolean = false>(
1375
+ options?: Options<ListPublicLiveData, ThrowOnError>
1376
+ ) => {
1377
+ return (options?.client ?? _heyApiClient).get<
1378
+ ListPublicLiveResponse,
1379
+ ListPublicLiveError,
1380
+ ThrowOnError
1381
+ >({
1382
+ url: "/live/public",
1383
+ ...options,
1384
+ });
1385
+ };
1386
+
1387
+ /**
1388
+ * Change a run's visibility, name, or description
1389
+ * Owner only, addressed by `runId` directly rather than through its strategy — this is a
1390
+ * run's own canonical identity, independent of which strategy started it.
1391
+ *
1392
+ * Setting `visibility` from `public` back to `private` also evicts anyone currently connected
1393
+ * to the run's live signal channel who is not its owner — best-effort; the change to this
1394
+ * record is not rolled back if that eviction fails.
1395
+ *
1396
+ */
1397
+ export const updateLive = <ThrowOnError extends boolean = false>(
1398
+ options: Options<UpdateLiveData, ThrowOnError>
1399
+ ) => {
1400
+ return (options.client ?? _heyApiClient).patch<
1401
+ UpdateLiveResponse,
1402
+ UpdateLiveError,
1403
+ ThrowOnError
1404
+ >({
1405
+ security: [
1406
+ {
1407
+ scheme: "bearer",
1408
+ type: "http",
1409
+ },
1410
+ ],
1411
+ url: "/live/{runId}",
1412
+ ...options,
1413
+ headers: {
1414
+ "Content-Type": "application/json",
1415
+ ...options?.headers,
1416
+ },
1417
+ });
1418
+ };
1419
+
1420
+ /**
1421
+ * Change a running strategy's parameters
1422
+ * Updates one or more parameters of a run **while it stays live** — unlike `params` on
1423
+ * `POST /strategy/{strategyId}/live`, which only sets the starting values. Owner only.
1424
+ *
1425
+ * Every key in `params` must be one your strategy declares (see `declaredProperties` on
1426
+ * `POST /strategy`) as of the compilation this run is executing — recompiling the strategy
1427
+ * later never changes what an already-running instance accepts; start a new run for that.
1428
+ *
1429
+ * The change does not take effect the instant this call returns: `effectiveAtMs` is the
1430
+ * earliest moment it is guaranteed to apply, a few seconds out, so both the REST and
1431
+ * WebSocket paths to this same update (see the "Live execution" guide) land on the exact same
1432
+ * value at the exact same moment.
1433
+ *
1434
+ */
1435
+ export const updateLiveParams = <ThrowOnError extends boolean = false>(
1436
+ options: Options<UpdateLiveParamsData, ThrowOnError>
1437
+ ) => {
1438
+ return (options.client ?? _heyApiClient).put<
1439
+ UpdateLiveParamsResponse,
1440
+ UpdateLiveParamsError,
1441
+ ThrowOnError
1442
+ >({
1443
+ security: [
1444
+ {
1445
+ scheme: "bearer",
1446
+ type: "http",
1447
+ },
1448
+ ],
1449
+ url: "/live/{runId}/params",
1450
+ ...options,
1451
+ headers: {
1452
+ "Content-Type": "application/json",
1453
+ ...options?.headers,
1454
+ },
1455
+ });
1456
+ };
1457
+
1458
+ /**
1459
+ * Read a run's signals
1460
+ * Returns one page of the signals a run has already produced, newest-last, optionally from a
1461
+ * given time and narrowed to one or more instruments.
1462
+ *
1463
+ * This is the counterpart to the real-time WebSocket channel: that channel only carries what
1464
+ * happens while you are connected, and only for a run that asked for `relay`. A run's signals
1465
+ * are recorded either way, so this endpoint serves them whether or not `relay` was ever on,
1466
+ * in both the `sandbox` and `live` stages — use it to catch up after a disconnect, to read a
1467
+ * run you never relayed, or to page back over what has already happened.
1468
+ *
1469
+ * **The available window moves.** Signals are kept for a limited span, and the oldest are
1470
+ * continuously discarded as new ones arrive, so how far back you can read is not a fixed
1471
+ * number of hours: on a busy run it can be a good deal shorter. Every response carries
1472
+ * `availableSinceMs`, the oldest moment that can still be answered for. Asking for a
1473
+ * `sinceMs` older than that is not an error — you get everything from `availableSinceMs`
1474
+ * onwards, and that field tells you it happened.
1475
+ *
1476
+ * **A cursor can expire, and on a busy run it expires quickly.** If the position a cursor
1477
+ * points at has since been discarded, the next page answers `410` rather than silently
1478
+ * serving a shortened page that looks complete. Treat that as a normal outcome: read
1479
+ * `availableSinceMs` from the error and start again from there.
1480
+ *
1481
+ * Readable by the run's owner, and by anyone if the run is `public` — the same rule the
1482
+ * signal channel applies to a subscription.
1483
+ *
1484
+ */
1485
+ export const getLiveRunSignals = <ThrowOnError extends boolean = false>(
1486
+ options: Options<GetLiveRunSignalsData, ThrowOnError>
1487
+ ) => {
1488
+ return (options.client ?? _heyApiClient).get<
1489
+ GetLiveRunSignalsResponse,
1490
+ GetLiveRunSignalsError,
1491
+ ThrowOnError
1492
+ >({
1493
+ security: [
1494
+ {
1495
+ scheme: "bearer",
1496
+ type: "http",
1497
+ },
1498
+ ],
1499
+ url: "/live/{runId}/signals",
1500
+ ...options,
1501
+ });
1502
+ };
1503
+
1504
+ /**
1505
+ * Mint a WebSocket connection token
1506
+ * Mints a short-lived token for the WebSocket connection used to receive a run's signals in
1507
+ * real time and to call `live.params` (the WebSocket form of `PUT /live/{runId}/params`) —
1508
+ * see the "Live execution" guide linked from this tag's description for the full protocol.
1509
+ * Carries no request body.
1510
+ *
1511
+ */
1512
+ export const mintLiveConnectionToken = <ThrowOnError extends boolean = false>(
1513
+ options?: Options<MintLiveConnectionTokenData, ThrowOnError>
1514
+ ) => {
1515
+ return (options?.client ?? _heyApiClient).post<
1516
+ MintLiveConnectionTokenResponse,
1517
+ unknown,
1518
+ ThrowOnError
1519
+ >({
1520
+ security: [
1521
+ {
1522
+ scheme: "bearer",
1523
+ type: "http",
1524
+ },
1525
+ ],
1526
+ url: "/live/token",
1527
+ ...options,
1528
+ });
1529
+ };