@qtsurfer/api-client 0.15.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.
@@ -9,6 +9,10 @@ import type {
9
9
  AuthenticateData,
10
10
  AuthenticateResponse,
11
11
  AuthenticateError,
12
+ GetAccountData,
13
+ GetAccountResponse,
14
+ GetAccountUsageData,
15
+ GetAccountUsageResponse,
12
16
  ListExchangesData,
13
17
  ListExchangesResponse,
14
18
  ListInstrumentsData,
@@ -96,6 +100,29 @@ import type {
96
100
  GetDatasetImportData,
97
101
  GetDatasetImportResponse,
98
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,
99
126
  } from "./types.gen";
100
127
  import { client as _heyApiClient } from "./client.gen";
101
128
 
@@ -147,6 +174,60 @@ export const authenticate = <ThrowOnError extends boolean = false>(
147
174
  });
148
175
  };
149
176
 
177
+ /**
178
+ * Get your account's identity and tier limits
179
+ * Your userId, current tier, and that tier's limits — no database call, safe to fetch on
180
+ * every page load. For live usage against these limits, see `_links.usage`
181
+ * (`GET /account/usage`).
182
+ *
183
+ */
184
+ export const getAccount = <ThrowOnError extends boolean = false>(
185
+ options?: Options<GetAccountData, ThrowOnError>
186
+ ) => {
187
+ return (options?.client ?? _heyApiClient).get<
188
+ GetAccountResponse,
189
+ unknown,
190
+ ThrowOnError
191
+ >({
192
+ security: [
193
+ {
194
+ scheme: "bearer",
195
+ type: "http",
196
+ },
197
+ ],
198
+ url: "/account",
199
+ ...options,
200
+ });
201
+ };
202
+
203
+ /**
204
+ * Get your live storage usage
205
+ * How much of your account's shared storage pool (`GET /account`'s `maxTotalStorageBytes`)
206
+ * you're currently using. Datasets, strategy-execution signals, and registered strategies
207
+ * all count against the same total — they compete for the same underlying storage, so
208
+ * there's one number to watch, not one per resource type. Not guaranteed real-time — a
209
+ * just-completed upload or strategy execution may take a short moment to be reflected here.
210
+ *
211
+ */
212
+ export const getAccountUsage = <ThrowOnError extends boolean = false>(
213
+ options?: Options<GetAccountUsageData, ThrowOnError>
214
+ ) => {
215
+ return (options?.client ?? _heyApiClient).get<
216
+ GetAccountUsageResponse,
217
+ unknown,
218
+ ThrowOnError
219
+ >({
220
+ security: [
221
+ {
222
+ scheme: "bearer",
223
+ type: "http",
224
+ },
225
+ ],
226
+ url: "/account/usage",
227
+ ...options,
228
+ });
229
+ };
230
+
150
231
  /**
151
232
  * List the available exchanges
152
233
  */
@@ -308,22 +389,35 @@ export const listStrategies = <ThrowOnError extends boolean = false>(
308
389
  * Compile and register a strategy
309
390
  * Compiles raw strategy source and registers it, returning its `strategyId`.
310
391
  *
311
- * **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
312
400
  * back the id — nothing more. Whether the class can actually run is
313
401
  * `POST /strategy/{strategyId}/validate`, and everything known about a strategy, validation
314
402
  * included, is read from `GET /strategy/{strategyId}`. One place to ask, so there is no second
315
403
  * answer to keep in step.
316
404
  *
317
- * The `strategyId` is derived from what the code *means*, not from how it is written. Adding a
318
- * comment, inserting a blank line, re-indenting, reordering imports, or moving a method around
319
- * all return the **same** id — you have not created a second strategy. Renaming a variable,
320
- * changing an identifier's case, reordering fields, or reordering statements inside a method
321
- * 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.
322
416
  *
323
417
  * Two rules follow, and they are worth designing around:
324
418
  *
325
- * - re-submitting a strategy you have only reformatted is free, and gives you back the id you
326
- * 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;
327
421
  * - the id says nothing about *behaviour*. Two sources that compute the same thing by
328
422
  * different means are two strategies, because deciding otherwise would mean deciding program
329
423
  * equivalence.
@@ -489,6 +583,10 @@ export const getStrategyCode = <ThrowOnError extends boolean = false>(
489
583
  * The same params always return the same `jobId` (idempotent). Repeated calls with identical
490
584
  * params do not enqueue duplicate work — they reuse the existing job.
491
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
+ *
492
590
  * **`exchangeId: user` is reserved for your own uploaded data.** Instead of a managed
493
591
  * exchange, it prepares from a dataset you created via `POST /datasets` (see the **Dataset**
494
592
  * endpoints) — send `datasetId` in place of `instrument`. See `PrepareRequest` below for the
@@ -552,6 +650,10 @@ export const getPrepareStatus = <ThrowOnError extends boolean = false>(
552
650
  * The backend expands and executes the matrix internally; clients poll the returned
553
651
  * `sweepId` for incremental results.
554
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
+ *
555
657
  * Supplying `walkForward` runs the sweep in a different mode entirely. Instead of scoring
556
658
  * every parameter vector once over the whole range, the data is split into F sequential
557
659
  * folds; each fold optimizes the full grid on its own window and then scores only its winner
@@ -749,6 +851,11 @@ export const getSweepRunEquityCurve = <ThrowOnError extends boolean = false>(
749
851
  * Returns immediately with a `jobId`; poll `GET /backtest/{exchangeId}/{type}/execute/{jobId}`
750
852
  * for the result.
751
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
+ *
752
859
  * Optionally takes `params`: strategy properties for this one run, applied without
753
860
  * recompiling. This is how a sweep leaderboard winner gets re-run for its `equityCurve` —
754
861
  * a sweep row carries the ten ranking metrics but never a curve, whatever its size. Compile
@@ -895,16 +1002,21 @@ export const listDatasets = <ThrowOnError extends boolean = false>(
895
1002
  * response. `instrument` must be a plain spot pair (`BASE/QUOTE`, exactly one `/`); derivative
896
1003
  * forms (e.g. `BTC/USDT:USDT`) are rejected.
897
1004
  *
898
- * **Upload format.** A CSV with a header row, or a parquet file with the same columns by
899
- * name. Required: `timestamp` (ISO-8601, or numeric epoch seconds/millis/micros — detected
900
- * from the first row, then enforced for every later row), `close`. Optional: `open`, `high`,
901
- * `low`, `volume`, `quoteVolume`, `bid`, `bidSize`, `ask`, `askSize`. Cadence and timestamp
902
- * unit are discovered from the data, not declared.
1005
+ * **Upload format.** A CSV with a header row, a parquet file with the same columns by
1006
+ * name, or a lastra file — our own native columnar format, the same one a dataset's
1007
+ * `dataUrl` hands back by default, so a downloaded dataset can be handed to another user to
1008
+ * upload with no conversion in between. For CSV/parquet, required: `timestamp` (ISO-8601, or
1009
+ * numeric epoch seconds/millis/micros — detected from the first row, then enforced for every
1010
+ * later row), `close`. Optional: `open`, `high`, `low`, `volume`, `quoteVolume`, `bid`,
1011
+ * `bidSize`, `ask`, `askSize`. A lastra upload carries its own fixed column set instead and
1012
+ * only needs a timestamp series and a close series present. Cadence and timestamp unit are
1013
+ * discovered from the data, not declared, for all three.
903
1014
  *
904
1015
  * A CSV upload is converted to our native columnar format (`lastra`) for storage. A parquet
905
- * upload is stored as-is today. Either way, always check `dataFormat` on
1016
+ * or lastra upload is stored as-is today. Either way, always check `dataFormat` on
906
1017
  * `GET /datasets/{datasetId}` and `GET /datasets/{datasetId}/uploads/{uploadId}` for which
907
- * one `dataUrl` actually is, rather than assuming from how you uploaded it.
1018
+ * one `dataUrl` actually is, rather than assuming from how you uploaded it (a converted CSV
1019
+ * and an uploaded lastra file both report `dataFormat: "lastra"`).
908
1020
  *
909
1021
  * The bytes PUT to `upload.url` may be that file directly, gzipped (`.gz`), or zipped
910
1022
  * (`.zip`, exactly one file inside — a dataset is one file regardless of how it travels).
@@ -1146,3 +1258,272 @@ export const getDatasetImport = <ThrowOnError extends boolean = false>(
1146
1258
  ...options,
1147
1259
  });
1148
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
+ };