@qtsurfer/api-client 0.23.1 → 0.25.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.
@@ -12,6 +12,38 @@ export type ResponseError = {
12
12
  * Error description
13
13
  */
14
14
  message: string;
15
+ /**
16
+ * A stable token naming the cause, for a client to branch on without reading `message`.
17
+ * Present only on an error that has one, and each operation that can return one lists
18
+ * the values it uses. A client treats a value it does not know like an absent `reason`.
19
+ *
20
+ */
21
+ reason?: string;
22
+ next?: ErrorNextCall;
23
+ };
24
+
25
+ /**
26
+ * The call that gets past an error, ready to send: a client that wants the same thing by
27
+ * another route makes this request. Present only on an error that has one.
28
+ *
29
+ */
30
+ export type ErrorNextCall = {
31
+ /**
32
+ * HTTP method of the call.
33
+ */
34
+ method: "GET" | "POST" | "PUT" | "DELETE";
35
+ /**
36
+ * Path of the call, relative to the server URL (the one that already ends in `/v1`).
37
+ */
38
+ path: string;
39
+ /**
40
+ * JSON body of the call, when it has one. Whatever depends on the caller and cannot be
41
+ * known here (such as the `name` of a dataset) is left for the client to add.
42
+ *
43
+ */
44
+ body?: {
45
+ [key: string]: unknown;
46
+ };
15
47
  };
16
48
 
17
49
  /**
@@ -24,6 +56,15 @@ export type ScalarStrategyParamValue = number | string | boolean;
24
56
  */
25
57
  export type Instrument = string;
26
58
 
59
+ /**
60
+ * An exchange's instrument catalogue: centralized-exchange instruments or decentralized-exchange
61
+ * pools. Read `meta.venueType` to distinguish `cex` from `dex`, including when `data` is empty.
62
+ *
63
+ */
64
+ export type InstrumentCatalogueResponse =
65
+ | InstrumentListResponse
66
+ | PoolListResponse;
67
+
27
68
  /**
28
69
  * HAL-style response envelope for the instruments listing
29
70
  */
@@ -52,6 +93,10 @@ export type InstrumentListMeta = {
52
93
  * The market segment served in `data`
53
94
  */
54
95
  segment: "spot" | "futures";
96
+ /**
97
+ * The venue type of the exchange, as `GET /exchanges` lists it. Always `cex` here; a listing of pools says `dex`.
98
+ */
99
+ venueType: "cex";
55
100
  };
56
101
 
57
102
  /**
@@ -72,6 +117,115 @@ export type InstrumentLinks = {
72
117
  futures?: HalLink;
73
118
  };
74
119
 
120
+ /**
121
+ * HAL-style response envelope for the instruments listing of a decentralized exchange, whose instruments are pools
122
+ */
123
+ export type PoolListResponse = {
124
+ /**
125
+ * The pools worth running, the most traded in the last 24 hours first
126
+ */
127
+ data: Array<PoolDetail>;
128
+ meta: PoolListMeta;
129
+ _links: PoolLinks;
130
+ };
131
+
132
+ /**
133
+ * Metadata describing the pools listing of a decentralized exchange
134
+ */
135
+ export type PoolListMeta = {
136
+ /**
137
+ * When this listing was last refreshed. It is refreshed every hour, and the `lastPrice` of each pool is as of this time.
138
+ */
139
+ updatedAt: string;
140
+ /**
141
+ * The exchange the pools belong to
142
+ */
143
+ exchange: string;
144
+ /**
145
+ * The protocol served in `data`, one of the exchange's `segments`
146
+ */
147
+ segment: string;
148
+ /**
149
+ * The venue type of the exchange, as `GET /exchanges` lists it. Always `dex` here; a listing of instruments of a centralized exchange says `cex`.
150
+ */
151
+ venueType: "dex";
152
+ /**
153
+ * A pool with less liquidity than this (in US dollars) is not listed
154
+ */
155
+ minTvlUsd: number;
156
+ /**
157
+ * The most pools the listing has
158
+ */
159
+ limit: number;
160
+ };
161
+
162
+ /**
163
+ * HAL `_links` — protocol discovery for the pools listing of a decentralized exchange
164
+ */
165
+ export type PoolLinks = {
166
+ /**
167
+ * Link to this listing
168
+ */
169
+ self: HalLink;
170
+ [key: string]: HalLink;
171
+ };
172
+
173
+ /**
174
+ * A pool of a decentralized exchange that a live run can read. The listing is a place to start, not the
175
+ * whole market: a live run can read any pool of the protocol, listed or not.
176
+ *
177
+ */
178
+ export type PoolDetail = {
179
+ /**
180
+ * The pool's address, in lower case. It is the value to put in `instruments` of a live run's source.
181
+ */
182
+ id: string;
183
+ /**
184
+ * The pair written `BASE/QUOTE`, the way the signals of a run on this pool name it (`instrument`)
185
+ */
186
+ symbol: string;
187
+ /**
188
+ * Symbol of the base token
189
+ */
190
+ base: string;
191
+ /**
192
+ * Symbol of the quote token
193
+ */
194
+ quote: string;
195
+ /**
196
+ * Address of the base token, in lower case
197
+ */
198
+ baseAddress: string;
199
+ /**
200
+ * Address of the quote token, in lower case
201
+ */
202
+ quoteAddress: string;
203
+ /**
204
+ * The pool's fee tier, in percent (`0.05` is a 0.05 % fee). A protocol can have several pools of the same pair, one per fee tier.
205
+ */
206
+ feePercent: number;
207
+ /**
208
+ * The price of one base token in the quote token, as the signals of a run on this pool name the pair. It is as of `meta.updatedAt`, so up to one hour old. Absent when there is no price for the pool.
209
+ */
210
+ lastPrice?: number;
211
+ /**
212
+ * What traded in the pool over the last 24 hours, in the quote token, the same meaning as `volume24h` of an instrument of a centralized exchange. Absent when the quote token has no dollar price to convert from.
213
+ */
214
+ volume24h?: number;
215
+ /**
216
+ * The liquidity held by the pool, in US dollars
217
+ */
218
+ tvlUsd: number;
219
+ /**
220
+ * What traded in the pool over the last 24 hours, in US dollars
221
+ */
222
+ volume24hUsd: number;
223
+ /**
224
+ * When the pool was created. Absent when it is not known
225
+ */
226
+ createdAt?: string;
227
+ };
228
+
75
229
  /**
76
230
  * HAL `_links` for a strategy — present on a full `StrategyState` body (`GET
77
231
  * /strategy/{strategyId}`, and `POST /strategy/{strategyId}/validate`'s already-validated
@@ -119,6 +273,7 @@ export type Account = {
119
273
  * Your current subscription tier.
120
274
  */
121
275
  tier: string;
276
+ scopes: KeyScopes;
122
277
  /**
123
278
  * Maximum number of strategy executions (and sweeps) you can have running at the same time
124
279
  * through the API. Starting one past this number is answered with `429`, whose message
@@ -238,6 +393,10 @@ export type InstrumentDetail = {
238
393
  * Instrument identifier (e.g. currency pair)
239
394
  */
240
395
  id: string;
396
+ /**
397
+ * The instrument's name, the same as `id`. A pool of a decentralized exchange has the same field (`PoolDetail`), so both listings are read alike.
398
+ */
399
+ symbol: string;
241
400
  /**
242
401
  * Base currency
243
402
  */
@@ -246,13 +405,17 @@ export type InstrumentDetail = {
246
405
  * Quote currency
247
406
  */
248
407
  quote: string;
408
+ /**
409
+ * Settlement currency. Present on a futures instrument only.
410
+ */
411
+ settle?: string;
249
412
  coverage?: InstrumentCoverage;
250
413
  /**
251
- * Last traded price
414
+ * Last traded price. Absent for an instrument with no recent price.
252
415
  */
253
416
  lastPrice?: number;
254
417
  /**
255
- * Trading volume in the last 24 hours (in quote currency)
418
+ * Trading volume in the last 24 hours (in quote currency). Absent for an instrument with no recent volume.
256
419
  */
257
420
  volume24h?: number;
258
421
  };
@@ -305,6 +468,18 @@ export type Exchange = {
305
468
  * Description of the exchange
306
469
  */
307
470
  description?: string;
471
+ /**
472
+ * Venue category, written as the `venueType` of a live run's source: `cex` is a centralized exchange and `dex` a decentralized one. A `dex` exchange has no market data to prepare or backtest, so its id is not valid in the routes that take an `exchangeId`, except the two instruments routes, which list its pools (the instrument of a run on it is a pool's address).
473
+ */
474
+ venueType: "cex" | "dex";
475
+ /**
476
+ * The segments the exchange offers, written as in the path of `GET /exchange/{exchangeId}/{segment}/instruments` and as the `segment` of a live run's source. For a `cex` exchange, its market segments (`spot`, `futures`: the ones its instrument catalogues are served under); for a `dex` exchange, the protocols whose pools a run can read.
477
+ */
478
+ segments: Array<string>;
479
+ /**
480
+ * The segments among `segments` for which live data is published, so the ones a live run can read: a live run on any other segment of the exchange is refused with `400`. It can be empty (an exchange whose live data is not published yet).
481
+ */
482
+ liveSegments: Array<string>;
308
483
  };
309
484
 
310
485
  /**
@@ -372,11 +547,10 @@ export type PrepareRequest = {
372
547
  * * Managed exchange, `ticker` or `funding` — one of `1s`, `5s`, `1m`, `3m`, `5m`, `15m`,
373
548
  * `30m`, `1h`, `2h`, `4h`, `8h`, `12h`, `1d`, `1w`, `1q`; any other label returns `400`.
374
549
  * Omitted = `1s`, the publisher's native cadence.
375
- * * Managed exchange, `kline` — one of `1s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d`;
376
- * any other label, including `5s`, `3m` and `8h`, returns `400` and names the accepted
377
- * ones. Omitted = `1s`. This is the width of the bars a run reads: it is chosen here,
378
- * once, and the same strategy can be run at several cadences by preparing the range at
379
- * each.
550
+ * * Managed exchange, `kline` — the same labels as above, `1s` to `1q`; a label that is
551
+ * not a whole number of seconds returns `400`. Omitted = `1s`. This is the width of the
552
+ * bars a run reads: it is chosen here, once, and the same strategy can be run at
553
+ * several cadences by preparing the range at each.
380
554
  * * Dataset (`exchangeId: user`) — omitted = the dataset version's own discovered
381
555
  * `cadence` (see `DatasetVersion.cadence`), served as-is. Any cadence equal to or
382
556
  * coarser than it and an exact multiple of it is accepted, including ones outside the
@@ -1340,9 +1514,11 @@ export type Dataset = {
1340
1514
  */
1341
1515
  name: string;
1342
1516
  /**
1343
- * `ticker` for an upload or a `dex` import with no `cadence` requested (native per-trade
1344
- * data). `klines` for a `dex` import that requested a candle `cadence` — pre-aggregated
1345
- * bars rather than raw ticks. Purely informational; both shapes are read the same way.
1517
+ * `ticker` for an upload, a `dex` import with no `cadence` requested (native per-trade
1518
+ * data) or a `cex` import with `dataType: ticker`. `klines` for a `dex` import that
1519
+ * requested a candle `cadence` — pre-aggregated bars rather than raw ticks — or a `cex`
1520
+ * import with `dataType: klines`. Purely informational; both shapes are read the same
1521
+ * way.
1346
1522
  *
1347
1523
  */
1348
1524
  type: "ticker" | "klines";
@@ -1534,11 +1710,12 @@ export type DatasetVersion = {
1534
1710
  rows?: number;
1535
1711
  /**
1536
1712
  * The cadence discovered from the data's own timestamps. Either a fixed grid — `1s`,
1537
- * `5s`, `15s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d` — when at least half the
1538
- * intervals between consecutive rows fall on that step (small clock jitter tolerated), or
1539
- * `rt`: native data at the rate it was captured, each row at its own timestamp with no
1540
- * fixed step — per-trade on-chain swaps, block-spaced or sub-second ticks, irregular
1541
- * intervals. An `rt` dataset can be resampled to any fixed cadence at prepare time.
1713
+ * `5s`, `15s`, `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `8h`, `12h`, `1d`,
1714
+ * `1w` — when at least half the intervals between consecutive rows fall on that step
1715
+ * (small clock jitter tolerated), or `rt`: native data at the rate it was captured, each
1716
+ * row at its own timestamp with no fixed step — per-trade on-chain swaps, block-spaced
1717
+ * or sub-second ticks, irregular intervals. An `rt` dataset can be resampled to any
1718
+ * fixed cadence at prepare time.
1542
1719
  *
1543
1720
  */
1544
1721
  cadence?: string;
@@ -1613,7 +1790,8 @@ export type DatasetUploadState = {
1613
1790
 
1614
1791
  /**
1615
1792
  * `POST /datasets/imports`'s request body. A common block plus one type-specific block,
1616
- * selected by `type` — `dex` is the only value today.
1793
+ * selected by `type`: `dex` (block `dex`) or `cex` (block `cex`), the two `venueType`s of
1794
+ * `GET /exchanges`.
1617
1795
  *
1618
1796
  */
1619
1797
  export type DatasetImportRequest = {
@@ -1633,21 +1811,54 @@ export type DatasetImportRequest = {
1633
1811
  */
1634
1812
  to: string;
1635
1813
  /**
1636
- * Optional. Omitted/blank keeps native per-trade event cadence — each swap at its own
1637
- * timestamp, so the resulting version's `cadence` is `rt` unless the swaps happen to sit
1638
- * on a fixed grid (see `DatasetVersion.cadence`). Set to `1s`, `1m` or
1639
- * `5m` instead to get pre-aggregated candles at that width rather than raw trades (the
1640
- * resulting dataset's `type` becomes `klines`); any other value is `400`. Not every
1641
- * network supports every cadence — an unsupported combination fails asynchronously, not
1642
- * at request time (see `DatasetImportState.error`).
1814
+ * Optional; what it means, and what it accepts, depends on `type`. Any other value is
1815
+ * `400`.
1816
+ *
1817
+ * * `dex` — omitted/blank keeps native per-trade event cadence: each swap at its own
1818
+ * timestamp, so the resulting version's `cadence` is `rt` unless the swaps happen to
1819
+ * sit on a fixed grid (see `DatasetVersion.cadence`). Set to `1s`, `1m` or `5m`
1820
+ * instead to get pre-aggregated candles at that width rather than raw trades (the
1821
+ * resulting dataset's `type` becomes `klines`). Not every network supports every
1822
+ * cadence — an unsupported combination fails asynchronously, not at request time (see
1823
+ * `DatasetImportState.error`).
1824
+ * * `cex` — one of `1s`, `5s`, `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `8h`,
1825
+ * `12h`, `1d`, `1w`, `1q`, whether `dataType` is `ticker` or `klines`. Omitted = the
1826
+ * finest cadence every part of the range holds.
1827
+ *
1828
+ * For `cex` the bars are built from the finest data every part of the range holds. A
1829
+ * `cadence` finer than that, or not an exact multiple of it, fails the import
1830
+ * asynchronously (`failed`; the `error` names the finest cadence the range holds) rather
1831
+ * than returning a dataset with a different cadence from the one asked for. So a range
1832
+ * whose history changes cadence part-way (from `1m` to `1s`, say) comes out entirely at
1833
+ * the coarser one when `cadence` is omitted: the dataset has no gap that is only a
1834
+ * change of cadence.
1643
1835
  *
1644
1836
  */
1645
- cadence?: "1s" | "1m" | "5m";
1646
- /**
1647
- * The source to fetch from. `dex` is the only value today.
1837
+ cadence?:
1838
+ | "1s"
1839
+ | "5s"
1840
+ | "1m"
1841
+ | "3m"
1842
+ | "5m"
1843
+ | "15m"
1844
+ | "30m"
1845
+ | "1h"
1846
+ | "2h"
1847
+ | "4h"
1848
+ | "8h"
1849
+ | "12h"
1850
+ | "1d"
1851
+ | "1w"
1852
+ | "1q";
1853
+ /**
1854
+ * The kind of venue to import from, the same two values as the `venueType` of
1855
+ * `GET /exchanges`: `dex` — a pool/pair's own on-chain market (block `dex`) — or `cex` —
1856
+ * a centralized exchange's market history (block `cex`).
1857
+ *
1648
1858
  */
1649
- type: "dex";
1859
+ type: "dex" | "cex";
1650
1860
  dex?: DatasetImportDexRequest;
1861
+ cex?: DatasetImportCexRequest;
1651
1862
  };
1652
1863
 
1653
1864
  /**
@@ -1691,6 +1902,33 @@ export type DatasetImportDexRequest = {
1691
1902
  factory?: string;
1692
1903
  };
1693
1904
 
1905
+ /**
1906
+ * The `cex` source's own fields — required when `type` is `cex`. They name a market the way
1907
+ * `GET /exchanges` and the instruments routes do: `exchange` is the `id` of a centralized
1908
+ * exchange, `segment` one of its `segments`.
1909
+ *
1910
+ */
1911
+ export type DatasetImportCexRequest = {
1912
+ /**
1913
+ * The id of a centralized exchange (`venueType` `cex`) of `GET /exchanges`, lower-case.
1914
+ * A decentralized exchange's id is `400`: import its pools with `type: dex`.
1915
+ *
1916
+ */
1917
+ exchange: string;
1918
+ /**
1919
+ * The market segment, one of the exchange's `segments`. `spot` is the only segment a
1920
+ * `cex` import takes today, which matches `instrument` being a plain spot pair.
1921
+ *
1922
+ */
1923
+ segment: "spot";
1924
+ /**
1925
+ * What to import, and the resulting dataset's `type`: `ticker` — the exchange's ticker
1926
+ * series — or `klines` — its aggregated bars (open, high, low, close and volume).
1927
+ *
1928
+ */
1929
+ dataType: "ticker" | "klines";
1930
+ };
1931
+
1694
1932
  /**
1695
1933
  * The response to `POST /datasets/imports` — the dataset now exists, and its fetch has started.
1696
1934
  */
@@ -1739,7 +1977,8 @@ export type DatasetImportState = {
1739
1977
  /**
1740
1978
  * A human-readable reason, present when `status` is `failed` — an unresolvable
1741
1979
  * pool/pair, no data in the requested range, a range older than the configured source
1742
- * retains, the fetch exceeding your tier's time ceiling, or any of
1980
+ * retains, a `cex` `cadence` finer than the range holds (the message names the finest
1981
+ * one), the fetch exceeding your tier's time ceiling, or any of
1743
1982
  * `DatasetUploadState.error`'s own ingest-side reasons once fetching hands off to it.
1744
1983
  * Durably recorded, same as on the upload path.
1745
1984
  *
@@ -1751,6 +1990,19 @@ export type DatasetImportState = {
1751
1990
  version?: DatasetVersion;
1752
1991
  };
1753
1992
 
1993
+ /**
1994
+ * What your API key may do, as a map from a resource to the actions allowed on it. Names are
1995
+ * lower case: `{ "backtests": ["read", "write", "execute"], "exchanges": ["read"] }`. A scope
1996
+ * is a resource and an action: a resource is listed only with at least one action, and a key
1997
+ * with no scope is `{}`. `GET /account` and `POST /auth/token` return the same map for the
1998
+ * same key. The API reports the scopes of a key; it does not yet refuse an operation because
1999
+ * a scope is missing.
2000
+ *
2001
+ */
2002
+ export type KeyScopes = {
2003
+ [key: string]: Array<string>;
2004
+ };
2005
+
1754
2006
  export type AuthTokenResponse = {
1755
2007
  /**
1756
2008
  * Short-lived HS256 JWT. Send as `Authorization: Bearer <token>` on all other endpoints.
@@ -1764,10 +2016,7 @@ export type AuthTokenResponse = {
1764
2016
  * Seconds until the JWT expires (typically 3600).
1765
2017
  */
1766
2018
  expires_in: number;
1767
- /**
1768
- * Scopes granted to this token. Reserved for future use; currently always empty.
1769
- */
1770
- scopes?: Array<string>;
2019
+ scopes?: KeyScopes;
1771
2020
  /**
1772
2021
  * Subscription tier this token was issued for. Drives rate limits and feature flags on downstream endpoints.
1773
2022
  */
@@ -1775,13 +2024,17 @@ export type AuthTokenResponse = {
1775
2024
  };
1776
2025
 
1777
2026
  /**
1778
- * Error envelope returned by `POST /auth/token` when the API key is rejected.
2027
+ * Error envelope returned by `POST /auth/token` when the API key is rejected (`401`) or carries no scopes where scopes are required (`403`).
1779
2028
  */
1780
2029
  export type AuthTokenError = {
1781
2030
  /**
1782
2031
  * Machine-readable error reason.
1783
2032
  */
1784
- code: "invalid_apikey" | "apikey_revoked" | "apikey_expired";
2033
+ code:
2034
+ | "invalid_apikey"
2035
+ | "apikey_revoked"
2036
+ | "apikey_expired"
2037
+ | "apikey_without_scopes";
1785
2038
  /**
1786
2039
  * Human-readable description of the failure.
1787
2040
  */
@@ -1793,17 +2046,23 @@ export type AuthTokenError = {
1793
2046
  */
1794
2047
  export type LiveSource = {
1795
2048
  /**
1796
- * Venue category. `cx` (centralized exchange) is the only one live runs support today.
2049
+ * Venue category. `cex` is a centralized exchange and `dex` is one pool on a decentralized exchange, which takes its own `exchange`, `segment`, `type` and `instruments` (see "Sources" in the Live execution guide). `cx` and `dx`, the spellings used before, are still read as `cex` and `dex`; the run always reports the new ones.
2050
+ */
2051
+ venueType: "cex" | "dex";
2052
+ /**
2053
+ * The exchange id, as `GET /exchanges` lists it. For a `dex` source, the chain the pool is on; `robinhood` is the only one today.
1797
2054
  */
1798
- venueType: string;
1799
2055
  exchange: string;
2056
+ /**
2057
+ * The segment, as `GET /exchanges` lists it for that exchange, among its `liveSegments` (a segment with no live data is refused with `400`). For a `cex` source, the market segment (`spot` today); for a `dex` source, the protocol of the pool, `uniswap-v3` the only one today.
2058
+ */
1800
2059
  segment: string;
1801
2060
  /**
1802
- * Both `ticker` and `kline` connect to the lightest (fastest) cadence available for the exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet.
2061
+ * Both `ticker` and `kline` connect to the lightest (fastest) cadence available for the exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet. A `dex` source supports only `kline`: one candle per second of the pool's trades.
1803
2062
  */
1804
2063
  type: "ticker" | "kline";
1805
2064
  /**
1806
- * The instruments the run reads. For a run started with a list, that list as sent; for one started without `instruments`, or with `["*"]`, what the start resolved: the list of pairs the compilation of the strategy records as the instruments it accepts, when it records one, or `["*"]` for every instrument the exchange/segment offers (tier-gated). An entry is written `BASE/QUOTE` and either side can be `*` to mean any, such as any base paired with USDT. Symbols are not case-sensitive and spaces around them are ignored, so `btc/usdt` and `BTC/USDT` are the same instrument.
2065
+ * The instruments the run reads. For a run started with a list, that list as sent; for one started without `instruments`, or with `["*"]`, what the start resolved: the list of pairs the compilation of the strategy records as the instruments it accepts, when it records one, or `["*"]` for every instrument the exchange/segment offers (tier-gated). An entry is written `BASE/QUOTE` and either side can be `*` to mean any, such as any base paired with USDT. Symbols are not case-sensitive and spaces around them are ignored, so `btc/usdt` and `BTC/USDT` are the same instrument. A `dex` source holds exactly one entry, the address of its pool.
1807
2066
  */
1808
2067
  instruments: Array<string>;
1809
2068
  };
@@ -1813,17 +2072,23 @@ export type LiveSource = {
1813
2072
  */
1814
2073
  export type LiveSourceRequest = {
1815
2074
  /**
1816
- * Venue category. `cx` (centralized exchange) is the only one live runs support today.
2075
+ * Venue category. `cex` is a centralized exchange and `dex` is one pool on a decentralized exchange, which takes its own `exchange`, `segment`, `type` and `instruments` (see "Sources" in the Live execution guide). `cx` and `dx`, the spellings used before, are still read as `cex` and `dex`; the run always reports the new ones.
2076
+ */
2077
+ venueType: "cex" | "dex";
2078
+ /**
2079
+ * The exchange id, as `GET /exchanges` lists it. For a `dex` source, the chain the pool is on; `robinhood` is the only one today.
1817
2080
  */
1818
- venueType: string;
1819
2081
  exchange: string;
2082
+ /**
2083
+ * The segment, as `GET /exchanges` lists it for that exchange, among its `liveSegments` (a segment with no live data is refused with `400`). For a `cex` source, the market segment (`spot` today); for a `dex` source, the protocol of the pool, `uniswap-v3` the only one today.
2084
+ */
1820
2085
  segment: string;
1821
2086
  /**
1822
- * Both `ticker` and `kline` connect to the lightest (fastest) cadence available for the exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet.
2087
+ * Both `ticker` and `kline` connect to the lightest (fastest) cadence available for the exchange — today, 1 tick/second on every supported exchange. Choosing a specific cadence is not offered yet. A `dex` source supports only `kline`: one candle per second of the pool's trades.
1823
2088
  */
1824
2089
  type: "ticker" | "kline";
1825
2090
  /**
1826
- * Which instruments the run reads. 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, leaving `instruments` out, or sending `["*"]`, takes that list; otherwise the run reads every instrument the exchange/segment offers. A list of instruments is taken as sent, and `[]` and `null` are refused with `400`. An entry is written `BASE/QUOTE`; either side can be `*` to mean any: any base can be paired with USDT, and BTC can be paired with any quote. Entries are not case-sensitive and spaces around them are ignored, so `btc/usdt` and `BTC/USDT` are the same instrument. An entry that is not of that form (no `/`, an empty side, a `.` or a space inside a side, or a `*` mixed with other characters of a side) makes the run fail when it starts. Plan limits: a list with an entry that has a `*` on a side counts like `["*"]` and only plans that include the wildcard accept it; the other entries are counted one by one. The instruments the run actually reads come back in the run's `sources`.
2091
+ * Which instruments the run reads. 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, leaving `instruments` out, or sending `["*"]`, takes that list; otherwise the run reads every instrument the exchange/segment offers. A list of instruments is taken as sent, and `[]` and `null` are refused with `400`. An entry is written `BASE/QUOTE`; either side can be `*` to mean any: any base can be paired with USDT, and BTC can be paired with any quote. Entries are not case-sensitive and spaces around them are ignored, so `btc/usdt` and `BTC/USDT` are the same instrument. An entry that is not of that form (no `/`, an empty side, a `.` or a space inside a side, or a `*` mixed with other characters of a side) makes the run fail when it starts. Plan limits: a list with an entry that has a `*` on a side counts like `["*"]` and only plans that include the wildcard accept it; the other entries are counted one by one. The instruments the run actually reads come back in the run's `sources`. A `dex` source needs exactly one entry, the address of its pool (`0x` and 40 hexadecimal digits, not case-sensitive): it cannot be left out and `*` is not accepted.
1827
2092
  */
1828
2093
  instruments?: Array<string>;
1829
2094
  };
@@ -1837,13 +2102,22 @@ export type StartLiveRequest = {
1837
2102
  [key: string]: unknown;
1838
2103
  };
1839
2104
  /**
1840
- * A `public` run appears in `GET /live/public` and its signal channel accepts subscriptions from anyone, not only you — from the moment it is promoted to `live`. While it is a `sandbox` trial, `public` is only what you asked for, and only you can read it.
2105
+ * 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.
1841
2106
  */
1842
2107
  visibility?: "private" | "public";
1843
2108
  /**
1844
2109
  * 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.
1845
2110
  */
1846
2111
  relay?: boolean;
2112
+ /**
2113
+ * Start in the `sandbox` stage even though an earlier run of yours already took this compiled strategy
2114
+ * through it. Without it, such a strategy starts in `LIVE` at once; with `true` it starts in `SANDBOX` like
2115
+ * a first run, which is how to read its signals back over the connection (`history`, kept for the
2116
+ * `sandbox` stage only) while you debug it. For a strategy that has not been through the sandbox it
2117
+ * changes nothing: it always starts there. Anything other than `true` or `false` is `400`.
2118
+ *
2119
+ */
2120
+ sandbox?: boolean;
1847
2121
  /**
1848
2122
  * Ask for a **stream URL**: a secret address that a simple client, or a service that passes your signals
1849
2123
  * on to others, can open as a plain WebSocket to receive this run's signals as they are produced, one JSON
@@ -1955,7 +2229,7 @@ export type LiveRun = {
1955
2229
  description?: string;
1956
2230
  visibility: "private" | "public";
1957
2231
  /**
1958
- * A new run always 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.
2232
+ * 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`.
1959
2233
  */
1960
2234
  stage: "SANDBOX" | "LIVE";
1961
2235
  /**
@@ -1971,12 +2245,15 @@ export type LiveRun = {
1971
2245
  * stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
1972
2246
  * exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
1973
2247
  * a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
1974
- * definition was refused, the run could not start after several attempts, the strategy failed while
1975
- * processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
2248
+ * definition was refused, the pool address of a `dex` run is not a pool of its protocol on its chain,
2249
+ * the platform has no room to follow the pool of a `dex` run, the run could not start after several
2250
+ * attempts, the strategy failed while processing data, the run lost its data feed, or the generic
2251
+ * `The run failed.`. The set may grow:
1976
2252
  * read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
1977
2253
  * `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
1978
- * live-run limit) until then; one that can never run because its strategy cannot consume its source
1979
- * type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
2254
+ * live-run limit) until then; one that cannot run, and will not by waiting, because its strategy cannot
2255
+ * consume its source type or because the pool of a `dex` run is not a pool or has no room to be followed,
2256
+ * is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
1980
2257
  *
1981
2258
  */
1982
2259
  reason?: string;
@@ -1997,7 +2274,7 @@ export type LiveRun = {
1997
2274
  */
1998
2275
  startedAtMs: number;
1999
2276
  /**
2000
- * 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. `passed` is the verdict; the rest is diagnostic detail whose shape is not yet stabilized as public API: treat it as opaque.
2277
+ * 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.
2001
2278
  */
2002
2279
  gate?: {
2003
2280
  [key: string]: unknown;
@@ -2137,7 +2414,7 @@ export type LiveRunSummary = {
2137
2414
  description?: string;
2138
2415
  visibility: "private" | "public";
2139
2416
  /**
2140
- * A new run always 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.
2417
+ * 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`.
2141
2418
  */
2142
2419
  stage: "SANDBOX" | "LIVE";
2143
2420
  /**
@@ -2153,12 +2430,15 @@ export type LiveRunSummary = {
2153
2430
  * stack trace or an internal message. Either `resource: ...` (the platform stopped the run for
2154
2431
  * exceeding its resource allowance; the text says which limit) or one of a fixed set of sentences for
2155
2432
  * a `FAILED` run: the strategy cannot consume the source type the run was started with, the run's
2156
- * definition was refused, the run could not start after several attempts, the strategy failed while
2157
- * processing data, the run lost its data feed, or the generic `The run failed.`. The set may grow:
2433
+ * definition was refused, the pool address of a `dex` run is not a pool of its protocol on its chain,
2434
+ * the platform has no room to follow the pool of a `dex` run, the run could not start after several
2435
+ * attempts, the strategy failed while processing data, the run lost its data feed, or the generic
2436
+ * `The run failed.`. The set may grow:
2158
2437
  * read an unrecognised sentence as a failure and do not parse it. A `FAILED` run usually stays
2159
2438
  * `desired: RUNNING` until you stop it, and counts as active (`409` on a new start, and toward your
2160
- * live-run limit) until then; one that can never run because its strategy cannot consume its source
2161
- * type is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
2439
+ * live-run limit) until then; one that cannot run, and will not by waiting, because its strategy cannot
2440
+ * consume its source type or because the pool of a `dex` run is not a pool or has no room to be followed,
2441
+ * is stopped by the platform itself (`desired: STOPPED`), so it holds no place.
2162
2442
  *
2163
2443
  */
2164
2444
  reason?: string;
@@ -2443,6 +2723,10 @@ export type AuthenticateErrors = {
2443
2723
  * API key is invalid, revoked, or expired.
2444
2724
  */
2445
2725
  401: AuthTokenError;
2726
+ /**
2727
+ * The API key is valid but carries no scopes, and this deployment requires them.
2728
+ */
2729
+ 403: AuthTokenError;
2446
2730
  /**
2447
2731
  * Rate limit exceeded for this API key.
2448
2732
  */
@@ -2525,7 +2809,11 @@ export type ListInstrumentsData = {
2525
2809
 
2526
2810
  export type ListInstrumentsErrors = {
2527
2811
  /**
2528
- * Exchange not found or instrument catalog not available
2812
+ * The exchange is not one `GET /exchanges` lists
2813
+ */
2814
+ 400: ResponseError;
2815
+ /**
2816
+ * The instrument catalog is not available
2529
2817
  */
2530
2818
  404: ResponseError;
2531
2819
  };
@@ -2535,9 +2823,9 @@ export type ListInstrumentsError =
2535
2823
 
2536
2824
  export type ListInstrumentsResponses = {
2537
2825
  /**
2538
- * The default (spot) segment's instruments in `data`, `meta`, and HAL `_links` (self + spot/futures segment discovery)
2826
+ * The default (spot) segment's instruments in `data`, `meta`, and HAL `_links` (self + spot/futures segment discovery); for a decentralized exchange, its pools
2539
2827
  */
2540
- 200: InstrumentListResponse;
2828
+ 200: InstrumentCatalogueResponse;
2541
2829
  };
2542
2830
 
2543
2831
  export type ListInstrumentsResponse =
@@ -2551,9 +2839,9 @@ export type ListSegmentInstrumentsData = {
2551
2839
  */
2552
2840
  exchangeId: string;
2553
2841
  /**
2554
- * Market segment to list instruments for
2842
+ * The segment to list instruments for, one of the exchange's `segments` in `GET /exchanges`; `spot` or `futures` for a centralized exchange, a protocol (`uniswap-v3`) for a decentralized one
2555
2843
  */
2556
- segment: "spot" | "futures";
2844
+ segment: string;
2557
2845
  };
2558
2846
  query?: never;
2559
2847
  url: "/exchange/{exchangeId}/{segment}/instruments";
@@ -2561,7 +2849,11 @@ export type ListSegmentInstrumentsData = {
2561
2849
 
2562
2850
  export type ListSegmentInstrumentsErrors = {
2563
2851
  /**
2564
- * Exchange, segment, or instrument catalog not found
2852
+ * The exchange is not one `GET /exchanges` lists, or the segment is not one the exchange has (`spot` or `futures` for a centralized exchange, a protocol for a decentralized one)
2853
+ */
2854
+ 400: ResponseError;
2855
+ /**
2856
+ * The instrument catalog is not available
2565
2857
  */
2566
2858
  404: ResponseError;
2567
2859
  };
@@ -2573,7 +2865,7 @@ export type ListSegmentInstrumentsResponses = {
2573
2865
  /**
2574
2866
  * An object with a `data` array of instrument details (each with per-data-type coverage) and a `meta` block
2575
2867
  */
2576
- 200: InstrumentListResponse;
2868
+ 200: InstrumentCatalogueResponse;
2577
2869
  };
2578
2870
 
2579
2871
  export type ListSegmentInstrumentsResponse =
@@ -2615,17 +2907,29 @@ export type DownloadTickersData = {
2615
2907
 
2616
2908
  export type DownloadTickersErrors = {
2617
2909
  /**
2618
- * Missing or malformed parameters (e.g. `hour` not `YYYY-MM-DDTHH`).
2910
+ * Missing or malformed parameters (e.g. `hour` not `YYYY-MM-DDTHH`), an `hour` in the
2911
+ * future, or an hour older than the last 7 days (`reason: OUTSIDE_WINDOW`, with `next`).
2912
+ *
2619
2913
  */
2620
2914
  400: ResponseError;
2621
2915
  /**
2622
- * No Lastra segment exists for the requested instrument/hour.
2916
+ * No segment for the requested instrument/hour. `reason: NOT_YET_AVAILABLE` — the hour
2917
+ * is not stored yet and no provisional answer was given for it (the answer carries
2918
+ * `Retry-After`); `reason: NO_DATA` — the hour is stored and holds nothing for this
2919
+ * instrument.
2920
+ *
2623
2921
  */
2624
2922
  404: ResponseError;
2625
2923
  /**
2626
2924
  * Unexpected I/O error serving the file.
2627
2925
  */
2628
2926
  500: ResponseError;
2927
+ /**
2928
+ * Reads are being limited (of stored or of provisional data) and this one was not served
2929
+ * (`reason: TEMPORARILY_UNAVAILABLE`). Ask again after the `Retry-After` delay.
2930
+ *
2931
+ */
2932
+ 503: ResponseError;
2629
2933
  };
2630
2934
 
2631
2935
  export type DownloadTickersError =
@@ -2634,9 +2938,10 @@ export type DownloadTickersError =
2634
2938
  export type DownloadTickersResponses = {
2635
2939
  /**
2636
2940
  * One hour of tickers for the instrument. `Content-Type` is
2637
- * `application/vnd.lastra` by default or
2941
+ * `application/vnd.qtsurfer.lastra` by default or
2638
2942
  * `application/vnd.apache.parquet` when `format=parquet` was
2639
- * requested.
2943
+ * requested. The hour in progress, or one that has ended and is not stored yet, may be
2944
+ * provisional where the service gives provisional answers: see `X-Data-Status`.
2640
2945
  *
2641
2946
  */
2642
2947
  200: Blob | File;
@@ -2680,17 +2985,29 @@ export type DownloadKlinesData = {
2680
2985
 
2681
2986
  export type DownloadKlinesErrors = {
2682
2987
  /**
2683
- * Missing or malformed parameters (e.g. `hour` not `YYYY-MM-DDTHH`).
2988
+ * Missing or malformed parameters (e.g. `hour` not `YYYY-MM-DDTHH`), an `hour` in the
2989
+ * future, or an hour older than the last 7 days (`reason: OUTSIDE_WINDOW`, with `next`).
2990
+ *
2684
2991
  */
2685
2992
  400: ResponseError;
2686
2993
  /**
2687
- * No Lastra segment exists for the requested instrument/hour.
2994
+ * No segment for the requested instrument/hour. `reason: NOT_YET_AVAILABLE` — the hour
2995
+ * is not stored yet and no provisional answer was given for it (the answer carries
2996
+ * `Retry-After`); `reason: NO_DATA` — the hour is stored and holds nothing for this
2997
+ * instrument.
2998
+ *
2688
2999
  */
2689
3000
  404: ResponseError;
2690
3001
  /**
2691
3002
  * Unexpected I/O error serving the file.
2692
3003
  */
2693
3004
  500: ResponseError;
3005
+ /**
3006
+ * Reads are being limited (of stored or of provisional data) and this one was not served
3007
+ * (`reason: TEMPORARILY_UNAVAILABLE`). Ask again after the `Retry-After` delay.
3008
+ *
3009
+ */
3010
+ 503: ResponseError;
2694
3011
  };
2695
3012
 
2696
3013
  export type DownloadKlinesError =
@@ -2699,8 +3016,10 @@ export type DownloadKlinesError =
2699
3016
  export type DownloadKlinesResponses = {
2700
3017
  /**
2701
3018
  * One hour of klines for the instrument. `Content-Type` is
2702
- * `application/vnd.lastra` by default or
2703
- * `application/vnd.apache.parquet` when `format=parquet`.
3019
+ * `application/vnd.qtsurfer.lastra` by default or
3020
+ * `application/vnd.apache.parquet` when `format=parquet` was
3021
+ * requested. The hour in progress, or one that has ended and is not stored yet, may be
3022
+ * provisional where the service gives provisional answers: see `X-Data-Status`.
2704
3023
  *
2705
3024
  */
2706
3025
  200: Blob | File;
@@ -3732,6 +4051,15 @@ export type ImportDatasetErrors = {
3732
4051
  * `cadence`, whether that combination is actually servable on the requested `network` —
3733
4052
  * is checked later, asynchronously — see the `failed` status on the poll endpoint below.
3734
4053
  *
4054
+ * For `type: cex`: no `cex` block, or its `exchange` is not a centralized exchange of
4055
+ * `GET /exchanges` (a decentralized one is `400` too — use `type: dex`), `segment` is not
4056
+ * `spot` (the only segment a `cex` import takes today), `dataType` is not `ticker` or
4057
+ * `klines`, or
4058
+ * `cadence` is not one of the values a `cex` import takes (see `DatasetImportRequest`).
4059
+ * Whether the range holds data, and whether it holds data fine enough for the `cadence`
4060
+ * asked, is checked later, asynchronously — see the `failed` status on the poll endpoint
4061
+ * below.
4062
+ *
3735
4063
  */
3736
4064
  400: ResponseError;
3737
4065
  /**
@@ -3870,7 +4198,7 @@ export type StartLiveData = {
3870
4198
 
3871
4199
  export type StartLiveErrors = {
3872
4200
  /**
3873
- * Malformed `sources` (not exactly one entry, missing field, unsupported `type`), a `type` the strategy cannot consume (a ticker strategy with a `kline` source, or the reverse; the message names both), an invalid `visibility`, an invalid `paper` block (an unknown field, a wrong type or an out-of-range value), or no `paper` block for a strategy that listens to its own execution events. A `relay` or `stream` that is not `true` or `false`, or a `stream` where streams are not available yet. A `warmFrom` that is not an integer from 0 to 3600. An `instruments` that is empty or `null`.
4201
+ * Malformed `sources` (not exactly one entry, missing field, unsupported `type`), a `venueType`, `exchange` and `segment` that `GET /exchanges` does not list together, or a segment with no live data (the message names what it lists), a `type` the strategy cannot consume (a ticker strategy with a `kline` source, or the reverse; the message names both), an invalid `visibility`, an invalid `paper` block (an unknown field, a wrong type or an out-of-range value), or no `paper` block for a strategy that listens to its own execution events. A `relay` or `stream` that is not `true` or `false`, or a `stream` where streams are not available yet. A `warmFrom` that is not an integer from 0 to 3600. An `instruments` that is empty or `null`.
3874
4202
  */
3875
4203
  400: ResponseError;
3876
4204
  /**
@@ -3895,7 +4223,7 @@ export type StartLiveError = StartLiveErrors[keyof StartLiveErrors];
3895
4223
 
3896
4224
  export type StartLiveResponses = {
3897
4225
  /**
3898
- * Started — the run's own state, in the sandbox stage, with its `streamUrl` when you asked for a stream
4226
+ * 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
3899
4227
  */
3900
4228
  201: LiveRunWithStream;
3901
4229
  };