@qtsurfer/api-client 0.1.2 → 0.3.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.
package/README.md CHANGED
@@ -41,12 +41,35 @@ if (error) throw error;
41
41
  console.log(exchanges);
42
42
  ```
43
43
 
44
+ ### API key → JWT
45
+
46
+ Every endpoint above expects a short-lived JWT in `Authorization: Bearer …`.
47
+ Exchange a long-lived API key for one via `auth`:
48
+
49
+ ```ts
50
+ import { auth } from '@qtsurfer/api-client';
51
+
52
+ const { data, error } = await auth({
53
+ baseUrl: 'https://api.qtsurfer.com/v1',
54
+ headers: { 'X-API-Key': process.env.QTSURFER_APIKEY! },
55
+ });
56
+ if (error) throw error;
57
+
58
+ const { access_token: jwt } = data; // feed to client.setConfig() for the rest
59
+ ```
60
+
61
+ For production use, prefer the [`@qtsurfer/sdk`](https://github.com/QTSurfer/sdk-ts)
62
+ `auth(apikey)` helper — it returns a session that refreshes the JWT
63
+ transparently, reads `QTSURFER_APIKEY` from the environment, and supports
64
+ pluggable token stores so callers don't reinvent that plumbing.
65
+
44
66
  ## API surface
45
67
 
46
68
  All operations are exported as standalone functions; every operation accepts an `Options` object and returns `{ data, error, response }`.
47
69
 
48
70
  | Function | Method | Path | Purpose |
49
71
  | -------- | ------ | ---- | ------- |
72
+ | `auth` | POST | `/auth/token` | Exchange an API key for a short-lived JWT |
50
73
  | `getExchanges` | GET | `/exchanges` | List available exchanges |
51
74
  | `getInstruments` | GET | `/exchange/{exchangeId}/instruments` | List instruments for an exchange |
52
75
  | `getExchangeTickersHour` | GET | `/exchange/{exchangeId}/tickers/{base}/{quote}` | Download one hour of tickers as Lastra/Parquet |
package/dist/index.d.ts CHANGED
@@ -19,7 +19,65 @@ type ResponseError = {
19
19
  */
20
20
  type Instrument = string;
21
21
  /**
22
- * Exchange instrument with data availability and market info
22
+ * HAL-style response envelope for the instruments listing
23
+ */
24
+ type InstrumentListResponse = {
25
+ /**
26
+ * The list of instruments for the segment
27
+ */
28
+ data: Array<InstrumentDetail>;
29
+ meta: InstrumentListMeta;
30
+ _links: InstrumentLinks;
31
+ };
32
+ /**
33
+ * Metadata describing the instruments listing
34
+ */
35
+ type InstrumentListMeta = {
36
+ /**
37
+ * When this listing was last refreshed
38
+ */
39
+ updatedAt: string;
40
+ /**
41
+ * The exchange the instruments belong to
42
+ */
43
+ exchange: string;
44
+ /**
45
+ * The market segment served in `data`
46
+ */
47
+ segment: 'spot' | 'futures';
48
+ };
49
+ /**
50
+ * HAL `_links` — segment discovery for the instruments listing
51
+ */
52
+ type InstrumentLinks = {
53
+ /**
54
+ * Link to this listing
55
+ */
56
+ self: HalLink;
57
+ /**
58
+ * Link to the spot instruments listing. Present when the exchange has a spot segment.
59
+ */
60
+ spot?: HalLink;
61
+ /**
62
+ * Link to the futures instruments listing. Present only when the exchange has a futures segment.
63
+ */
64
+ futures?: HalLink;
65
+ };
66
+ /**
67
+ * A HAL link object (Hypertext Application Language)
68
+ */
69
+ type HalLink = {
70
+ /**
71
+ * The link target as an absolute-path URI reference (resolve against the API base). A URI Template (RFC 6570) when `templated` is true.
72
+ */
73
+ href: string;
74
+ /**
75
+ * True when `href` is an RFC 6570 URI Template.
76
+ */
77
+ templated?: boolean;
78
+ };
79
+ /**
80
+ * Exchange instrument with per-data-type coverage and market info
23
81
  */
24
82
  type InstrumentDetail = {
25
83
  /**
@@ -34,14 +92,7 @@ type InstrumentDetail = {
34
92
  * Quote currency
35
93
  */
36
94
  quote: string;
37
- /**
38
- * Earliest timestamp with quality-verified data available for backtesting
39
- */
40
- dataFrom?: string;
41
- /**
42
- * Latest timestamp with quality-verified data available for backtesting
43
- */
44
- dataTo?: string;
95
+ coverage?: InstrumentCoverage;
45
96
  /**
46
97
  * Last traded price
47
98
  */
@@ -51,6 +102,36 @@ type InstrumentDetail = {
51
102
  */
52
103
  volume24h?: number;
53
104
  };
105
+ /**
106
+ * Time coverage of available data for this instrument, per data type
107
+ */
108
+ type InstrumentCoverage = {
109
+ /**
110
+ * Coverage of ticker data
111
+ */
112
+ tickers?: CoverageWindow;
113
+ /**
114
+ * Coverage of kline (candlestick) data
115
+ */
116
+ klines?: CoverageWindow;
117
+ };
118
+ /**
119
+ * The time range of available data for a single data type
120
+ */
121
+ type CoverageWindow = {
122
+ /**
123
+ * Earliest timestamp with data available
124
+ */
125
+ from?: string;
126
+ /**
127
+ * Latest timestamp with data available
128
+ */
129
+ to?: string;
130
+ /**
131
+ * If the instrument stopped producing this data type (delisted/inactive), the timestamp it went inactive. Optional — omitted while the instrument is active.
132
+ */
133
+ inactiveSince?: string;
134
+ };
54
135
  /**
55
136
  * Exchange service provider
56
137
  */
@@ -128,7 +209,7 @@ type BacktestJobResult = {
128
209
  state: JobState;
129
210
  };
130
211
  /**
131
- * Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, totalTrades, winRate, etc.) are present when the strategy emitted at least one trade. When signal storage is enabled, includes signal fields described below.
212
+ * Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy emitted at least one trade. When signal storage is enabled, includes signal fields described below.
132
213
  */
133
214
  type ResultMap = {
134
215
  /**
@@ -151,6 +232,10 @@ type ResultMap = {
151
232
  * Total profit and loss in the output currency
152
233
  */
153
234
  pnlTotal?: number;
235
+ /**
236
+ * Total PnL as a percentage of the initial capital (`backtestFunding`). Zero when `backtestFunding` is 0.
237
+ */
238
+ pnlTotalPercent?: number;
154
239
  /**
155
240
  * Total number of trades executed by the strategy
156
241
  */
@@ -179,6 +264,10 @@ type ResultMap = {
179
264
  * Maximum percentage drawdown from peak equity
180
265
  */
181
266
  maxDrawdownPercent?: number;
267
+ /**
268
+ * Equity curve over the backtest. Element 0 is an anchor at the backtest `from` with `initialCapital`; the remaining points are one sample per emitted yield, in order. Use it to plot the strategy's running equity without re-deriving it from the yield history.
269
+ */
270
+ equityCurve?: Array<EquityPoint>;
182
271
  /**
183
272
  * Number of signals emitted during strategy execution
184
273
  */
@@ -204,10 +293,82 @@ type ResultMap = {
204
293
  */
205
294
  signalsUploadReason?: string;
206
295
  };
296
+ /**
297
+ * Single sample of the running equity at a yield event.
298
+ */
299
+ type EquityPoint = {
300
+ /**
301
+ * Epoch milliseconds. The first point in an equity curve is anchored at the backtest `from`; subsequent points carry the timestamp of each emitted yield.
302
+ */
303
+ timestamp: number;
304
+ /**
305
+ * Running equity at this point (`initialCapital + cumulativePnl`).
306
+ */
307
+ equity: number;
308
+ };
207
309
  /**
208
310
  * Unique identifier for a compiled strategy
209
311
  */
210
312
  type StrategyId = string;
313
+ type AuthTokenResponse = {
314
+ /**
315
+ * Short-lived HS256 JWT. Send as `Authorization: Bearer <token>` on all other endpoints.
316
+ */
317
+ access_token: string;
318
+ /**
319
+ * Always `Bearer`.
320
+ */
321
+ token_type: 'Bearer';
322
+ /**
323
+ * Seconds until the JWT expires (typically 3600).
324
+ */
325
+ expires_in: number;
326
+ /**
327
+ * Scopes granted to this token. Reserved for future use; currently always empty.
328
+ */
329
+ scopes?: Array<string>;
330
+ /**
331
+ * Subscription tier this token was issued for. Drives rate limits and feature flags on downstream endpoints.
332
+ */
333
+ tier: 'free' | 'basic' | 'pro' | 'elite';
334
+ };
335
+ /**
336
+ * Error envelope returned by `POST /auth/token` when the API key is rejected.
337
+ */
338
+ type AuthTokenError = {
339
+ /**
340
+ * Machine-readable error reason.
341
+ */
342
+ code: 'invalid_apikey' | 'apikey_revoked' | 'apikey_expired';
343
+ /**
344
+ * Human-readable description of the failure.
345
+ */
346
+ message: string;
347
+ };
348
+ type AuthData = {
349
+ body?: never;
350
+ path?: never;
351
+ query?: never;
352
+ url: '/auth/token';
353
+ };
354
+ type AuthErrors = {
355
+ /**
356
+ * API key is invalid, revoked, or expired.
357
+ */
358
+ 401: AuthTokenError;
359
+ /**
360
+ * Rate limit exceeded for this API key.
361
+ */
362
+ 429: unknown;
363
+ };
364
+ type AuthError = AuthErrors[keyof AuthErrors];
365
+ type AuthResponses = {
366
+ /**
367
+ * API key accepted; JWT returned.
368
+ */
369
+ 200: AuthTokenResponse;
370
+ };
371
+ type AuthResponse = AuthResponses[keyof AuthResponses];
211
372
  type GetExchangesData = {
212
373
  body?: never;
213
374
  path?: never;
@@ -241,11 +402,40 @@ type GetInstrumentsErrors = {
241
402
  type GetInstrumentsError = GetInstrumentsErrors[keyof GetInstrumentsErrors];
242
403
  type GetInstrumentsResponses = {
243
404
  /**
244
- * A JSON array of Instrument details with data availability
405
+ * The default (spot) segment's instruments in `data`, `meta`, and HAL `_links` (self + spot/futures segment discovery)
245
406
  */
246
- 200: Array<InstrumentDetail>;
407
+ 200: InstrumentListResponse;
247
408
  };
248
409
  type GetInstrumentsResponse = GetInstrumentsResponses[keyof GetInstrumentsResponses];
410
+ type GetSegmentInstrumentsData = {
411
+ body?: never;
412
+ path: {
413
+ /**
414
+ * ID of the exchange to retrieve instruments for
415
+ */
416
+ exchangeId: string;
417
+ /**
418
+ * Market segment to list instruments for
419
+ */
420
+ segment: 'spot' | 'futures';
421
+ };
422
+ query?: never;
423
+ url: '/exchange/{exchangeId}/{segment}/instruments';
424
+ };
425
+ type GetSegmentInstrumentsErrors = {
426
+ /**
427
+ * Exchange, segment, or instrument catalog not found
428
+ */
429
+ 404: ResponseError;
430
+ };
431
+ type GetSegmentInstrumentsError = GetSegmentInstrumentsErrors[keyof GetSegmentInstrumentsErrors];
432
+ type GetSegmentInstrumentsResponses = {
433
+ /**
434
+ * An object with a `data` array of instrument details (each with per-data-type coverage) and a `meta` block
435
+ */
436
+ 200: InstrumentListResponse;
437
+ };
438
+ type GetSegmentInstrumentsResponse = GetSegmentInstrumentsResponses[keyof GetSegmentInstrumentsResponses];
249
439
  type GetExchangeTickersHourData = {
250
440
  body?: never;
251
441
  path: {
@@ -677,14 +867,41 @@ type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean
677
867
  */
678
868
  meta?: Record<string, unknown>;
679
869
  };
870
+ /**
871
+ * Exchange API key for a short-lived JWT
872
+ * Exchanges a long-lived API key for a short-lived JWT used by every other
873
+ * endpoint. This is the only endpoint that accepts an API key directly —
874
+ * callers should obtain a JWT here, then send it as `Authorization: Bearer
875
+ * <token>` to all other operations.
876
+ *
877
+ * The returned JWT carries the caller's subscription `tier` as a claim and
878
+ * expires after `expires_in` seconds. Callers should refresh the token
879
+ * before expiry (or on a `401` response) by calling this endpoint again.
880
+ *
881
+ */
882
+ declare const auth: <ThrowOnError extends boolean = false>(options?: Options<AuthData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<AuthTokenResponse, unknown, ThrowOnError>;
680
883
  /**
681
884
  * Get a list of available exchanges
682
885
  */
683
886
  declare const getExchanges: <ThrowOnError extends boolean = false>(options?: Options<GetExchangesData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<Exchange[], unknown, ThrowOnError>;
684
887
  /**
685
- * Get a list of Instruments from a specific exchange
888
+ * Get an exchange's instruments (default spot segment)
889
+ * "Give me binance instruments" — returns the exchange's DEFAULT segment (`spot`)
890
+ * in `data`, each instrument with per-data-type coverage and market info. `meta`
891
+ * confirms the served `segment` (`spot`); HAL `_links` carry `self` plus the
892
+ * `spot` / `futures` segment-discovery links.
893
+ *
894
+ */
895
+ declare const getInstruments: <ThrowOnError extends boolean = false>(options: Options<GetInstrumentsData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<InstrumentListResponse, ResponseError, ThrowOnError>;
896
+ /**
897
+ * Get the instruments for a specific exchange segment
898
+ * Returns the instruments for one market segment of the exchange, each with
899
+ * per-data-type coverage and market info. HAL `_links` carry `self` plus the
900
+ * `spot` / `futures` segment-discovery links; the default-segment shortcut is
901
+ * `GET /exchange/{exchangeId}/instruments` (spot).
902
+ *
686
903
  */
687
- declare const getInstruments: <ThrowOnError extends boolean = false>(options: Options<GetInstrumentsData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<InstrumentDetail[], ResponseError, ThrowOnError>;
904
+ declare const getSegmentInstruments: <ThrowOnError extends boolean = false>(options: Options<GetSegmentInstrumentsData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<InstrumentListResponse, ResponseError, ThrowOnError>;
688
905
  /**
689
906
  * Download one hour of tickers for an instrument as a Lastra segment
690
907
  * Serves exactly one hour of raw ticker data for the given instrument on the
@@ -808,4 +1025,4 @@ declare const getExecutionResult: <ThrowOnError extends boolean = false>(options
808
1025
 
809
1026
  declare const client: _hey_api_client_fetch.Client;
810
1027
 
811
- export { type AcceptedJob, type BacktestJobResult, type CancelExecutionData, type CancelExecutionError, type CancelExecutionErrors, type CancelExecutionResponse, type CancelExecutionResponses, type ClientOptions, type DataSourceType, type Exchange, type ExecuteBacktestingData, type ExecuteBacktestingError, type ExecuteBacktestingErrors, type ExecuteBacktestingResponse, type ExecuteBacktestingResponses, type GetExchangeKlinesHourData, type GetExchangeKlinesHourError, type GetExchangeKlinesHourErrors, type GetExchangeKlinesHourResponse, type GetExchangeKlinesHourResponses, type GetExchangeTickersHourData, type GetExchangeTickersHourError, type GetExchangeTickersHourErrors, type GetExchangeTickersHourResponse, type GetExchangeTickersHourResponses, type GetExchangesData, type GetExchangesResponse, type GetExchangesResponses, type GetExecutionResultData, type GetExecutionResultError, type GetExecutionResultErrors, type GetExecutionResultResponse, type GetExecutionResultResponses, type GetInstrumentsData, type GetInstrumentsError, type GetInstrumentsErrors, type GetInstrumentsResponse, type GetInstrumentsResponses, type GetPreparationStatusData, type GetPreparationStatusError, type GetPreparationStatusErrors, type GetPreparationStatusResponse, type GetPreparationStatusResponses, type GetStrategyStatusData, type GetStrategyStatusError, type GetStrategyStatusErrors, type GetStrategyStatusResponse, type GetStrategyStatusResponses, type Instrument, type InstrumentDetail, type JobState, type Options, type PostStrategyData, type PostStrategyError, type PostStrategyErrors, type PostStrategyResponse, type PostStrategyResponses, type PrepareBacktestingData, type PrepareBacktestingError, type PrepareBacktestingErrors, type PrepareBacktestingResponse, type PrepareBacktestingResponses, type ResponseError, type ResultMap, type StrategyId, cancelExecution, client, executeBacktesting, getExchangeKlinesHour, getExchangeTickersHour, getExchanges, getExecutionResult, getInstruments, getPreparationStatus, getStrategyStatus, postStrategy, prepareBacktesting };
1028
+ export { type AcceptedJob, type AuthData, type AuthError, type AuthErrors, type AuthResponse, type AuthResponses, type AuthTokenError, type AuthTokenResponse, type BacktestJobResult, type CancelExecutionData, type CancelExecutionError, type CancelExecutionErrors, type CancelExecutionResponse, type CancelExecutionResponses, type ClientOptions, type CoverageWindow, type DataSourceType, type EquityPoint, type Exchange, type ExecuteBacktestingData, type ExecuteBacktestingError, type ExecuteBacktestingErrors, type ExecuteBacktestingResponse, type ExecuteBacktestingResponses, type GetExchangeKlinesHourData, type GetExchangeKlinesHourError, type GetExchangeKlinesHourErrors, type GetExchangeKlinesHourResponse, type GetExchangeKlinesHourResponses, type GetExchangeTickersHourData, type GetExchangeTickersHourError, type GetExchangeTickersHourErrors, type GetExchangeTickersHourResponse, type GetExchangeTickersHourResponses, type GetExchangesData, type GetExchangesResponse, type GetExchangesResponses, type GetExecutionResultData, type GetExecutionResultError, type GetExecutionResultErrors, type GetExecutionResultResponse, type GetExecutionResultResponses, type GetInstrumentsData, type GetInstrumentsError, type GetInstrumentsErrors, type GetInstrumentsResponse, type GetInstrumentsResponses, type GetPreparationStatusData, type GetPreparationStatusError, type GetPreparationStatusErrors, type GetPreparationStatusResponse, type GetPreparationStatusResponses, type GetSegmentInstrumentsData, type GetSegmentInstrumentsError, type GetSegmentInstrumentsErrors, type GetSegmentInstrumentsResponse, type GetSegmentInstrumentsResponses, type GetStrategyStatusData, type GetStrategyStatusError, type GetStrategyStatusErrors, type GetStrategyStatusResponse, type GetStrategyStatusResponses, type HalLink, type Instrument, type InstrumentCoverage, type InstrumentDetail, type InstrumentLinks, type InstrumentListMeta, type InstrumentListResponse, type JobState, type Options, type PostStrategyData, type PostStrategyError, type PostStrategyErrors, type PostStrategyResponse, type PostStrategyResponses, type PrepareBacktestingData, type PrepareBacktestingError, type PrepareBacktestingErrors, type PrepareBacktestingResponse, type PrepareBacktestingResponses, type ResponseError, type ResultMap, type StrategyId, auth, cancelExecution, client, executeBacktesting, getExchangeKlinesHour, getExchangeTickersHour, getExchanges, getExecutionResult, getInstruments, getPreparationStatus, getSegmentInstruments, getStrategyStatus, postStrategy, prepareBacktesting };
package/dist/index.js CHANGED
@@ -5,6 +5,18 @@ var client = createClient(createConfig({
5
5
  }));
6
6
 
7
7
  // src/generated/sdk.gen.ts
8
+ var auth = (options) => {
9
+ return (options?.client ?? client).post({
10
+ security: [
11
+ {
12
+ name: "X-API-Key",
13
+ type: "apiKey"
14
+ }
15
+ ],
16
+ url: "/auth/token",
17
+ ...options
18
+ });
19
+ };
8
20
  var getExchanges = (options) => {
9
21
  return (options?.client ?? client).get({
10
22
  url: "/exchanges",
@@ -17,6 +29,12 @@ var getInstruments = (options) => {
17
29
  ...options
18
30
  });
19
31
  };
32
+ var getSegmentInstruments = (options) => {
33
+ return (options.client ?? client).get({
34
+ url: "/exchange/{exchangeId}/{segment}/instruments",
35
+ ...options
36
+ });
37
+ };
20
38
  var getExchangeTickersHour = (options) => {
21
39
  return (options.client ?? client).get({
22
40
  url: "/exchange/{exchangeId}/tickers/{base}/{quote}",
@@ -127,6 +145,7 @@ var getExecutionResult = (options) => {
127
145
  });
128
146
  };
129
147
  export {
148
+ auth,
130
149
  cancelExecution,
131
150
  client,
132
151
  executeBacktesting,
@@ -136,6 +155,7 @@ export {
136
155
  getExecutionResult,
137
156
  getInstruments,
138
157
  getPreparationStatus,
158
+ getSegmentInstruments,
139
159
  getStrategyStatus,
140
160
  postStrategy,
141
161
  prepareBacktesting
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/generated/client.gen.ts","../src/generated/sdk.gen.ts"],"sourcesContent":["// This file is auto-generated by @hey-api/openapi-ts\n\nimport type { ClientOptions } from './types.gen';\nimport { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-fetch';\n\n/**\n * The `createClientConfig()` function will be called on client initialization\n * and the returned object will become the client's initial configuration.\n *\n * You may want to initialize your client this way instead of calling\n * `setConfig()`. This is useful for example if you're using Next.js\n * to ensure your client always has the correct values.\n */\nexport type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;\n\nexport const client = createClient(createConfig<ClientOptions>({\n baseUrl: 'https://api.staging.qtsurfer.com/v1'\n}));","// This file is auto-generated by @hey-api/openapi-ts\n\nimport type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch';\nimport type { GetExchangesData, GetExchangesResponse, GetInstrumentsData, GetInstrumentsResponse, GetInstrumentsError, GetExchangeTickersHourData, GetExchangeTickersHourResponse, GetExchangeTickersHourError, GetExchangeKlinesHourData, GetExchangeKlinesHourResponse, GetExchangeKlinesHourError, PostStrategyData, PostStrategyResponse, PostStrategyError, GetStrategyStatusData, GetStrategyStatusResponse, GetStrategyStatusError, PrepareBacktestingData, PrepareBacktestingResponse, PrepareBacktestingError, GetPreparationStatusData, GetPreparationStatusResponse, GetPreparationStatusError, ExecuteBacktestingData, ExecuteBacktestingResponse, ExecuteBacktestingError, CancelExecutionData, CancelExecutionResponse, CancelExecutionError, GetExecutionResultData, GetExecutionResultResponse, GetExecutionResultError } from './types.gen';\nimport { client as _heyApiClient } from './client.gen';\n\nexport type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {\n /**\n * You can provide a client instance returned by `createClient()` instead of\n * individual options. This might be also useful if you want to implement a\n * custom client.\n */\n client?: Client;\n /**\n * You can pass arbitrary values through the `meta` object. This can be\n * used to access values that aren't defined as part of the SDK function.\n */\n meta?: Record<string, unknown>;\n};\n\n/**\n * Get a list of available exchanges\n */\nexport const getExchanges = <ThrowOnError extends boolean = false>(options?: Options<GetExchangesData, ThrowOnError>) => {\n return (options?.client ?? _heyApiClient).get<GetExchangesResponse, unknown, ThrowOnError>({\n url: '/exchanges',\n ...options\n });\n};\n\n/**\n * Get a list of Instruments from a specific exchange\n */\nexport const getInstruments = <ThrowOnError extends boolean = false>(options: Options<GetInstrumentsData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetInstrumentsResponse, GetInstrumentsError, ThrowOnError>({\n url: '/exchange/{exchangeId}/instruments',\n ...options\n });\n};\n\n/**\n * Download one hour of tickers for an instrument as a Lastra segment\n * Serves exactly one hour of raw ticker data for the given instrument on the\n * requested exchange. The payload is a native [Lastra](https://github.com/QTSurfer/lastra-java)\n * file — QTSurfer's columnar format for tick-precision timeseries — with\n * no JSON envelope.\n *\n * One segment = one hour, aligned to UTC. The `hour` query parameter selects\n * the segment and must match `YYYY-MM-DDTHH` (no minutes/seconds, no timezone\n * suffix). Example: `hour=2026-01-15T10` returns `h10.lastra` for\n * 2026-01-15, covering `[10:00:00Z, 11:00:00Z)`. Hours not yet available\n * return `404`.\n *\n * A `format=parquet` query parameter switches the response to on-the-fly\n * Parquet conversion via [lastra-convert](https://github.com/QTSurfer/lastra-convert)\n * for clients that don't yet read Lastra. Lastra is the primary format\n * and cheaper when the client can consume it.\n *\n * Clients:\n * - [lastra-java](https://github.com/QTSurfer/lastra-java) — reference\n * Java reader/writer with per-column codecs (ALP, Gorilla, delta-varint,\n * ZSTD) and CRC32 integrity.\n * - [lastra-ts](https://github.com/QTSurfer/lastra-ts) — TypeScript reader\n * (~4 kB bundle, browser + Node.js).\n * - [duckdb-lastra](https://github.com/QTSurfer/duckdb-lastra) — DuckDB\n * extension for ad-hoc SQL over Lastra files.\n * - [lastra-convert](https://github.com/QTSurfer/lastra-convert) — CLI + Java\n * API for converting to/from Parquet, Reef, and CSV.\n * - `curl -OJ` for offline dumps (the `Content-Disposition` header sets a\n * descriptive filename).\n *\n */\nexport const getExchangeTickersHour = <ThrowOnError extends boolean = false>(options: Options<GetExchangeTickersHourData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetExchangeTickersHourResponse, GetExchangeTickersHourError, ThrowOnError>({\n url: '/exchange/{exchangeId}/tickers/{base}/{quote}',\n ...options\n });\n};\n\n/**\n * Download one hour of klines for an instrument as a Lastra segment\n * Same shape and semantics as `/exchange/{exchangeId}/tickers/{base}/{quote}`,\n * but serves klines (aggregated bars) instead of raw ticks. One\n * [Lastra](https://github.com/QTSurfer/lastra-java) segment = one hour of\n * klines at the exchange's native kline cadence, aligned to UTC.\n *\n * Klines use the same columnar layout as tickers — readers that handle one\n * format read the other with the same code. Use this endpoint when a\n * per-tick payload would be too large for the window of interest.\n *\n */\nexport const getExchangeKlinesHour = <ThrowOnError extends boolean = false>(options: Options<GetExchangeKlinesHourData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetExchangeKlinesHourResponse, GetExchangeKlinesHourError, ThrowOnError>({\n url: '/exchange/{exchangeId}/klines/{base}/{quote}',\n ...options\n });\n};\n\n/**\n * Compile a strategy from source code\n * Submits raw strategy source for compilation. By default the call is synchronous and returns\n * the `strategyId` once compilation succeeds. Set the header `X-Compile-Async: true` to enqueue\n * the compile task and return immediately with a `jobId` — poll\n * `GET /strategy/{strategyId}` to check status.\n *\n * The `strategyId` is deterministic: the same source for the same user always produces the\n * same id.\n *\n */\nexport const postStrategy = <ThrowOnError extends boolean = false>(options: Options<PostStrategyData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<PostStrategyResponse, PostStrategyError, ThrowOnError>({\n bodySerializer: null,\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/strategy',\n ...options,\n headers: {\n 'Content-Type': 'text/plain',\n ...options?.headers\n }\n });\n};\n\n/**\n * Get the status of an async compile task\n * Polls the status of a strategy compilation. Useful when the strategy was submitted with\n * `X-Compile-Async: true`. Returns the resolved `strategyId` once compilation completes.\n *\n */\nexport const getStrategyStatus = <ThrowOnError extends boolean = false>(options: Options<GetStrategyStatusData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetStrategyStatusResponse, GetStrategyStatusError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/strategy/{strategyId}',\n ...options\n });\n};\n\n/**\n * Prepare backtesting data\n * Enqueues a prepare task over the requested date range. Returns immediately with a `jobId`;\n * poll `GET /backtest/{exchangeId}/{type}/prepare/{jobId}` for completion.\n *\n * The same params always return the same `jobId` (idempotent). Repeated calls with identical\n * params do not enqueue duplicate work — they reuse the existing job.\n *\n */\nexport const prepareBacktesting = <ThrowOnError extends boolean = false>(options: Options<PrepareBacktestingData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<PrepareBacktestingResponse, PrepareBacktestingError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/prepare',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Get the status of a prepare job\n * Retrieves the current state of the prepare job identified by `jobId`.\n * Poll until `status` is `Completed`, `Failed`, or `Aborted`.\n *\n */\nexport const getPreparationStatus = <ThrowOnError extends boolean = false>(options: Options<GetPreparationStatusData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetPreparationStatusResponse, GetPreparationStatusError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/prepare/{jobId}',\n ...options\n });\n};\n\n/**\n * Execute a compiled strategy against a prepared dataset\n * Enqueues an execute task that runs the strategy identified by `strategyId` over the data\n * prepared by the prepare job identified by `prepareJobId`. The instrument and date range are\n * recovered from the prepare job — they do not need to be sent again.\n *\n * Returns immediately with a `jobId`; poll `GET /backtest/{exchangeId}/{type}/execute/{jobId}`\n * for the result.\n *\n * The same params (same `prepareJobId`, `strategyId`, `storeSignals`) always return the same\n * `jobId` (idempotent).\n *\n */\nexport const executeBacktesting = <ThrowOnError extends boolean = false>(options: Options<ExecuteBacktestingData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<ExecuteBacktestingResponse, ExecuteBacktestingError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/execute',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Cancel a running backtest execution\n * Requests cancellation of the specified execution. The execution\n * status will transition to `Aborted` once the cancellation is\n * processed. Cancellation is asynchronous — poll the GET endpoint\n * to confirm the final status.\n *\n */\nexport const cancelExecution = <ThrowOnError extends boolean = false>(options: Options<CancelExecutionData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).delete<CancelExecutionResponse, CancelExecutionError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/execute/{jobId}',\n ...options\n });\n};\n\n/**\n * Get the result of a backtest execution job\n * Retrieves the current state and results of the execute job identified by `jobId`.\n * Poll until `state.status` is `Completed`, `Failed`, or `Aborted`.\n *\n */\nexport const getExecutionResult = <ThrowOnError extends boolean = false>(options: Options<GetExecutionResultData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetExecutionResultResponse, GetExecutionResultError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/execute/{jobId}',\n ...options\n });\n};"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/generated/client.gen.ts","../src/generated/sdk.gen.ts"],"sourcesContent":["// This file is auto-generated by @hey-api/openapi-ts\n\nimport type { ClientOptions } from './types.gen';\nimport { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-fetch';\n\n/**\n * The `createClientConfig()` function will be called on client initialization\n * and the returned object will become the client's initial configuration.\n *\n * You may want to initialize your client this way instead of calling\n * `setConfig()`. This is useful for example if you're using Next.js\n * to ensure your client always has the correct values.\n */\nexport type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;\n\nexport const client = createClient(createConfig<ClientOptions>({\n baseUrl: 'https://api.staging.qtsurfer.com/v1'\n}));","// This file is auto-generated by @hey-api/openapi-ts\n\nimport type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch';\nimport type { AuthData, AuthResponse, AuthError, GetExchangesData, GetExchangesResponse, GetInstrumentsData, GetInstrumentsResponse, GetInstrumentsError, GetSegmentInstrumentsData, GetSegmentInstrumentsResponse, GetSegmentInstrumentsError, GetExchangeTickersHourData, GetExchangeTickersHourResponse, GetExchangeTickersHourError, GetExchangeKlinesHourData, GetExchangeKlinesHourResponse, GetExchangeKlinesHourError, PostStrategyData, PostStrategyResponse, PostStrategyError, GetStrategyStatusData, GetStrategyStatusResponse, GetStrategyStatusError, PrepareBacktestingData, PrepareBacktestingResponse, PrepareBacktestingError, GetPreparationStatusData, GetPreparationStatusResponse, GetPreparationStatusError, ExecuteBacktestingData, ExecuteBacktestingResponse, ExecuteBacktestingError, CancelExecutionData, CancelExecutionResponse, CancelExecutionError, GetExecutionResultData, GetExecutionResultResponse, GetExecutionResultError } from './types.gen';\nimport { client as _heyApiClient } from './client.gen';\n\nexport type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {\n /**\n * You can provide a client instance returned by `createClient()` instead of\n * individual options. This might be also useful if you want to implement a\n * custom client.\n */\n client?: Client;\n /**\n * You can pass arbitrary values through the `meta` object. This can be\n * used to access values that aren't defined as part of the SDK function.\n */\n meta?: Record<string, unknown>;\n};\n\n/**\n * Exchange API key for a short-lived JWT\n * Exchanges a long-lived API key for a short-lived JWT used by every other\n * endpoint. This is the only endpoint that accepts an API key directly —\n * callers should obtain a JWT here, then send it as `Authorization: Bearer\n * <token>` to all other operations.\n *\n * The returned JWT carries the caller's subscription `tier` as a claim and\n * expires after `expires_in` seconds. Callers should refresh the token\n * before expiry (or on a `401` response) by calling this endpoint again.\n *\n */\nexport const auth = <ThrowOnError extends boolean = false>(options?: Options<AuthData, ThrowOnError>) => {\n return (options?.client ?? _heyApiClient).post<AuthResponse, AuthError, ThrowOnError>({\n security: [\n {\n name: 'X-API-Key',\n type: 'apiKey'\n }\n ],\n url: '/auth/token',\n ...options\n });\n};\n\n/**\n * Get a list of available exchanges\n */\nexport const getExchanges = <ThrowOnError extends boolean = false>(options?: Options<GetExchangesData, ThrowOnError>) => {\n return (options?.client ?? _heyApiClient).get<GetExchangesResponse, unknown, ThrowOnError>({\n url: '/exchanges',\n ...options\n });\n};\n\n/**\n * Get an exchange's instruments (default spot segment)\n * \"Give me binance instruments\" — returns the exchange's DEFAULT segment (`spot`)\n * in `data`, each instrument with per-data-type coverage and market info. `meta`\n * confirms the served `segment` (`spot`); HAL `_links` carry `self` plus the\n * `spot` / `futures` segment-discovery links.\n *\n */\nexport const getInstruments = <ThrowOnError extends boolean = false>(options: Options<GetInstrumentsData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetInstrumentsResponse, GetInstrumentsError, ThrowOnError>({\n url: '/exchange/{exchangeId}/instruments',\n ...options\n });\n};\n\n/**\n * Get the instruments for a specific exchange segment\n * Returns the instruments for one market segment of the exchange, each with\n * per-data-type coverage and market info. HAL `_links` carry `self` plus the\n * `spot` / `futures` segment-discovery links; the default-segment shortcut is\n * `GET /exchange/{exchangeId}/instruments` (spot).\n *\n */\nexport const getSegmentInstruments = <ThrowOnError extends boolean = false>(options: Options<GetSegmentInstrumentsData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetSegmentInstrumentsResponse, GetSegmentInstrumentsError, ThrowOnError>({\n url: '/exchange/{exchangeId}/{segment}/instruments',\n ...options\n });\n};\n\n/**\n * Download one hour of tickers for an instrument as a Lastra segment\n * Serves exactly one hour of raw ticker data for the given instrument on the\n * requested exchange. The payload is a native [Lastra](https://github.com/QTSurfer/lastra-java)\n * file — QTSurfer's columnar format for tick-precision timeseries — with\n * no JSON envelope.\n *\n * One segment = one hour, aligned to UTC. The `hour` query parameter selects\n * the segment and must match `YYYY-MM-DDTHH` (no minutes/seconds, no timezone\n * suffix). Example: `hour=2026-01-15T10` returns `h10.lastra` for\n * 2026-01-15, covering `[10:00:00Z, 11:00:00Z)`. Hours not yet available\n * return `404`.\n *\n * A `format=parquet` query parameter switches the response to on-the-fly\n * Parquet conversion via [lastra-convert](https://github.com/QTSurfer/lastra-convert)\n * for clients that don't yet read Lastra. Lastra is the primary format\n * and cheaper when the client can consume it.\n *\n * Clients:\n * - [lastra-java](https://github.com/QTSurfer/lastra-java) — reference\n * Java reader/writer with per-column codecs (ALP, Gorilla, delta-varint,\n * ZSTD) and CRC32 integrity.\n * - [lastra-ts](https://github.com/QTSurfer/lastra-ts) — TypeScript reader\n * (~4 kB bundle, browser + Node.js).\n * - [duckdb-lastra](https://github.com/QTSurfer/duckdb-lastra) — DuckDB\n * extension for ad-hoc SQL over Lastra files.\n * - [lastra-convert](https://github.com/QTSurfer/lastra-convert) — CLI + Java\n * API for converting to/from Parquet, Reef, and CSV.\n * - `curl -OJ` for offline dumps (the `Content-Disposition` header sets a\n * descriptive filename).\n *\n */\nexport const getExchangeTickersHour = <ThrowOnError extends boolean = false>(options: Options<GetExchangeTickersHourData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetExchangeTickersHourResponse, GetExchangeTickersHourError, ThrowOnError>({\n url: '/exchange/{exchangeId}/tickers/{base}/{quote}',\n ...options\n });\n};\n\n/**\n * Download one hour of klines for an instrument as a Lastra segment\n * Same shape and semantics as `/exchange/{exchangeId}/tickers/{base}/{quote}`,\n * but serves klines (aggregated bars) instead of raw ticks. One\n * [Lastra](https://github.com/QTSurfer/lastra-java) segment = one hour of\n * klines at the exchange's native kline cadence, aligned to UTC.\n *\n * Klines use the same columnar layout as tickers — readers that handle one\n * format read the other with the same code. Use this endpoint when a\n * per-tick payload would be too large for the window of interest.\n *\n */\nexport const getExchangeKlinesHour = <ThrowOnError extends boolean = false>(options: Options<GetExchangeKlinesHourData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetExchangeKlinesHourResponse, GetExchangeKlinesHourError, ThrowOnError>({\n url: '/exchange/{exchangeId}/klines/{base}/{quote}',\n ...options\n });\n};\n\n/**\n * Compile a strategy from source code\n * Submits raw strategy source for compilation. By default the call is synchronous and returns\n * the `strategyId` once compilation succeeds. Set the header `X-Compile-Async: true` to enqueue\n * the compile task and return immediately with a `jobId` — poll\n * `GET /strategy/{strategyId}` to check status.\n *\n * The `strategyId` is deterministic: the same source for the same user always produces the\n * same id.\n *\n */\nexport const postStrategy = <ThrowOnError extends boolean = false>(options: Options<PostStrategyData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<PostStrategyResponse, PostStrategyError, ThrowOnError>({\n bodySerializer: null,\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/strategy',\n ...options,\n headers: {\n 'Content-Type': 'text/plain',\n ...options?.headers\n }\n });\n};\n\n/**\n * Get the status of an async compile task\n * Polls the status of a strategy compilation. Useful when the strategy was submitted with\n * `X-Compile-Async: true`. Returns the resolved `strategyId` once compilation completes.\n *\n */\nexport const getStrategyStatus = <ThrowOnError extends boolean = false>(options: Options<GetStrategyStatusData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetStrategyStatusResponse, GetStrategyStatusError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/strategy/{strategyId}',\n ...options\n });\n};\n\n/**\n * Prepare backtesting data\n * Enqueues a prepare task over the requested date range. Returns immediately with a `jobId`;\n * poll `GET /backtest/{exchangeId}/{type}/prepare/{jobId}` for completion.\n *\n * The same params always return the same `jobId` (idempotent). Repeated calls with identical\n * params do not enqueue duplicate work — they reuse the existing job.\n *\n */\nexport const prepareBacktesting = <ThrowOnError extends boolean = false>(options: Options<PrepareBacktestingData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<PrepareBacktestingResponse, PrepareBacktestingError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/prepare',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Get the status of a prepare job\n * Retrieves the current state of the prepare job identified by `jobId`.\n * Poll until `status` is `Completed`, `Failed`, or `Aborted`.\n *\n */\nexport const getPreparationStatus = <ThrowOnError extends boolean = false>(options: Options<GetPreparationStatusData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetPreparationStatusResponse, GetPreparationStatusError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/prepare/{jobId}',\n ...options\n });\n};\n\n/**\n * Execute a compiled strategy against a prepared dataset\n * Enqueues an execute task that runs the strategy identified by `strategyId` over the data\n * prepared by the prepare job identified by `prepareJobId`. The instrument and date range are\n * recovered from the prepare job — they do not need to be sent again.\n *\n * Returns immediately with a `jobId`; poll `GET /backtest/{exchangeId}/{type}/execute/{jobId}`\n * for the result.\n *\n * The same params (same `prepareJobId`, `strategyId`, `storeSignals`) always return the same\n * `jobId` (idempotent).\n *\n */\nexport const executeBacktesting = <ThrowOnError extends boolean = false>(options: Options<ExecuteBacktestingData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<ExecuteBacktestingResponse, ExecuteBacktestingError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/execute',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Cancel a running backtest execution\n * Requests cancellation of the specified execution. The execution\n * status will transition to `Aborted` once the cancellation is\n * processed. Cancellation is asynchronous — poll the GET endpoint\n * to confirm the final status.\n *\n */\nexport const cancelExecution = <ThrowOnError extends boolean = false>(options: Options<CancelExecutionData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).delete<CancelExecutionResponse, CancelExecutionError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/execute/{jobId}',\n ...options\n });\n};\n\n/**\n * Get the result of a backtest execution job\n * Retrieves the current state and results of the execute job identified by `jobId`.\n * Poll until `state.status` is `Completed`, `Failed`, or `Aborted`.\n *\n */\nexport const getExecutionResult = <ThrowOnError extends boolean = false>(options: Options<GetExecutionResultData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetExecutionResultResponse, GetExecutionResultError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/backtest/{exchangeId}/{type}/execute/{jobId}',\n ...options\n });\n};"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qtsurfer/api-client",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "Auto-generated TypeScript API client for the QTSurfer API (from OpenAPI 3.1 spec)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,8 +24,105 @@ export const InstrumentSchema = {
24
24
  example: 'BTC/USDT'
25
25
  } as const;
26
26
 
27
+ export const InstrumentListResponseSchema = {
28
+ description: 'HAL-style response envelope for the instruments listing',
29
+ type: 'object',
30
+ required: ['data', 'meta', '_links'],
31
+ properties: {
32
+ data: {
33
+ type: 'array',
34
+ description: 'The list of instruments for the segment',
35
+ items: {
36
+ '$ref': '#/components/schemas/InstrumentDetail'
37
+ }
38
+ },
39
+ meta: {
40
+ '$ref': '#/components/schemas/InstrumentListMeta'
41
+ },
42
+ _links: {
43
+ '$ref': '#/components/schemas/InstrumentLinks'
44
+ }
45
+ }
46
+ } as const;
47
+
48
+ export const InstrumentListMetaSchema = {
49
+ description: 'Metadata describing the instruments listing',
50
+ type: 'object',
51
+ required: ['updatedAt', 'exchange', 'segment'],
52
+ properties: {
53
+ updatedAt: {
54
+ type: 'string',
55
+ format: 'date-time',
56
+ description: 'When this listing was last refreshed',
57
+ example: '2026-07-09T19:09:07Z'
58
+ },
59
+ exchange: {
60
+ type: 'string',
61
+ description: 'The exchange the instruments belong to',
62
+ example: 'binance'
63
+ },
64
+ segment: {
65
+ type: 'string',
66
+ enum: ['spot', 'futures'],
67
+ description: 'The market segment served in `data`',
68
+ example: 'spot'
69
+ }
70
+ }
71
+ } as const;
72
+
73
+ export const InstrumentLinksSchema = {
74
+ description: 'HAL `_links` — segment discovery for the instruments listing',
75
+ type: 'object',
76
+ required: ['self'],
77
+ properties: {
78
+ self: {
79
+ allOf: [
80
+ {
81
+ '$ref': '#/components/schemas/HalLink'
82
+ }
83
+ ],
84
+ description: 'Link to this listing'
85
+ },
86
+ spot: {
87
+ allOf: [
88
+ {
89
+ '$ref': '#/components/schemas/HalLink'
90
+ }
91
+ ],
92
+ description: 'Link to the spot instruments listing. Present when the exchange has a spot segment.'
93
+ },
94
+ futures: {
95
+ allOf: [
96
+ {
97
+ '$ref': '#/components/schemas/HalLink'
98
+ }
99
+ ],
100
+ description: 'Link to the futures instruments listing. Present only when the exchange has a futures segment.'
101
+ }
102
+ }
103
+ } as const;
104
+
105
+ export const HalLinkSchema = {
106
+ description: 'A HAL link object (Hypertext Application Language)',
107
+ type: 'object',
108
+ required: ['href'],
109
+ properties: {
110
+ href: {
111
+ type: 'string',
112
+ format: 'uri-reference',
113
+ description: 'The link target as an absolute-path URI reference (resolve against the API base). A URI Template (RFC 6570) when `templated` is true.',
114
+ example: '/v1/exchange/binance/spot/instruments'
115
+ },
116
+ templated: {
117
+ type: 'boolean',
118
+ description: 'True when `href` is an RFC 6570 URI Template.',
119
+ example: false
120
+ }
121
+ }
122
+ } as const;
123
+
27
124
  export const InstrumentDetailSchema = {
28
- description: 'Exchange instrument with data availability and market info',
125
+ description: 'Exchange instrument with per-data-type coverage and market info',
29
126
  type: 'object',
30
127
  required: ['id', 'base', 'quote'],
31
128
  properties: {
@@ -44,17 +141,8 @@ export const InstrumentDetailSchema = {
44
141
  description: 'Quote currency',
45
142
  example: 'USDT'
46
143
  },
47
- dataFrom: {
48
- type: 'string',
49
- format: 'date-time',
50
- description: 'Earliest timestamp with quality-verified data available for backtesting',
51
- example: '2026-03-17T00:00:00Z'
52
- },
53
- dataTo: {
54
- type: 'string',
55
- format: 'date-time',
56
- description: 'Latest timestamp with quality-verified data available for backtesting',
57
- example: '2026-03-31T18:00:00Z'
144
+ coverage: {
145
+ '$ref': '#/components/schemas/InstrumentCoverage'
58
146
  },
59
147
  lastPrice: {
60
148
  type: 'number',
@@ -71,6 +159,54 @@ export const InstrumentDetailSchema = {
71
159
  }
72
160
  } as const;
73
161
 
162
+ export const InstrumentCoverageSchema = {
163
+ description: 'Time coverage of available data for this instrument, per data type',
164
+ type: 'object',
165
+ properties: {
166
+ tickers: {
167
+ allOf: [
168
+ {
169
+ '$ref': '#/components/schemas/CoverageWindow'
170
+ }
171
+ ],
172
+ description: 'Coverage of ticker data'
173
+ },
174
+ klines: {
175
+ allOf: [
176
+ {
177
+ '$ref': '#/components/schemas/CoverageWindow'
178
+ }
179
+ ],
180
+ description: 'Coverage of kline (candlestick) data'
181
+ }
182
+ }
183
+ } as const;
184
+
185
+ export const CoverageWindowSchema = {
186
+ description: 'The time range of available data for a single data type',
187
+ type: 'object',
188
+ properties: {
189
+ from: {
190
+ type: 'string',
191
+ format: 'date-time',
192
+ description: 'Earliest timestamp with data available',
193
+ example: '2026-04-10T21:00:00Z'
194
+ },
195
+ to: {
196
+ type: 'string',
197
+ format: 'date-time',
198
+ description: 'Latest timestamp with data available',
199
+ example: '2026-07-09T20:31:08Z'
200
+ },
201
+ inactiveSince: {
202
+ type: 'string',
203
+ format: 'date-time',
204
+ description: 'If the instrument stopped producing this data type (delisted/inactive), the timestamp it went inactive. Optional — omitted while the instrument is active.',
205
+ example: '2026-06-30T12:00:00Z'
206
+ }
207
+ }
208
+ } as const;
209
+
74
210
  export const ExchangeSchema = {
75
211
  description: 'Exchange service provider',
76
212
  type: 'object',
@@ -185,7 +321,7 @@ export const BacktestJobResultSchema = {
185
321
 
186
322
  export const ResultMapSchema = {
187
323
  type: 'object',
188
- description: 'Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, totalTrades, winRate, etc.) are present when the strategy emitted at least one trade. When signal storage is enabled, includes signal fields described below.',
324
+ description: 'Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy emitted at least one trade. When signal storage is enabled, includes signal fields described below.',
189
325
  required: ['strategyId', 'instrument'],
190
326
  properties: {
191
327
  hostName: {
@@ -215,6 +351,12 @@ export const ResultMapSchema = {
215
351
  description: 'Total profit and loss in the output currency',
216
352
  example: 42.75
217
353
  },
354
+ pnlTotalPercent: {
355
+ type: 'number',
356
+ format: 'double',
357
+ description: 'Total PnL as a percentage of the initial capital (`backtestFunding`). Zero when `backtestFunding` is 0.',
358
+ example: 42.75
359
+ },
218
360
  totalTrades: {
219
361
  type: 'integer',
220
362
  format: 'int64',
@@ -257,6 +399,27 @@ export const ResultMapSchema = {
257
399
  description: 'Maximum percentage drawdown from peak equity',
258
400
  example: 8.75
259
401
  },
402
+ equityCurve: {
403
+ type: 'array',
404
+ description: "Equity curve over the backtest. Element 0 is an anchor at the backtest `from` with `initialCapital`; the remaining points are one sample per emitted yield, in order. Use it to plot the strategy's running equity without re-deriving it from the yield history.",
405
+ items: {
406
+ '$ref': '#/components/schemas/EquityPoint'
407
+ },
408
+ example: [
409
+ {
410
+ timestamp: 1700000000000,
411
+ equity: 100
412
+ },
413
+ {
414
+ timestamp: 1700000060000,
415
+ equity: 110.5
416
+ },
417
+ {
418
+ timestamp: 1700000120000,
419
+ equity: 90.25
420
+ }
421
+ ]
422
+ },
260
423
  signalCount: {
261
424
  type: 'integer',
262
425
  description: 'Number of signals emitted during strategy execution',
@@ -293,8 +456,80 @@ export const ResultMapSchema = {
293
456
  }
294
457
  } as const;
295
458
 
459
+ export const EquityPointSchema = {
460
+ type: 'object',
461
+ description: 'Single sample of the running equity at a yield event.',
462
+ required: ['timestamp', 'equity'],
463
+ properties: {
464
+ timestamp: {
465
+ type: 'integer',
466
+ format: 'int64',
467
+ description: 'Epoch milliseconds. The first point in an equity curve is anchored at the backtest `from`; subsequent points carry the timestamp of each emitted yield.',
468
+ example: 1700000000000
469
+ },
470
+ equity: {
471
+ type: 'number',
472
+ format: 'double',
473
+ description: 'Running equity at this point (`initialCapital + cumulativePnl`).',
474
+ example: 110.5
475
+ }
476
+ }
477
+ } as const;
478
+
296
479
  export const strategyIdSchema = {
297
480
  description: 'Unique identifier for a compiled strategy',
298
481
  type: 'string',
299
482
  example: '6bsh31ikwkuivhtgcoa6s4'
483
+ } as const;
484
+
485
+ export const AuthTokenResponseSchema = {
486
+ type: 'object',
487
+ required: ['access_token', 'token_type', 'expires_in', 'tier'],
488
+ properties: {
489
+ access_token: {
490
+ type: 'string',
491
+ description: 'Short-lived HS256 JWT. Send as `Authorization: Bearer <token>` on all other endpoints.'
492
+ },
493
+ token_type: {
494
+ type: 'string',
495
+ enum: ['Bearer'],
496
+ description: 'Always `Bearer`.'
497
+ },
498
+ expires_in: {
499
+ type: 'integer',
500
+ description: 'Seconds until the JWT expires (typically 3600).',
501
+ example: 3600
502
+ },
503
+ scopes: {
504
+ type: 'array',
505
+ description: 'Scopes granted to this token. Reserved for future use; currently always empty.',
506
+ items: {
507
+ type: 'string'
508
+ },
509
+ example: []
510
+ },
511
+ tier: {
512
+ type: 'string',
513
+ enum: ['free', 'basic', 'pro', 'elite'],
514
+ description: 'Subscription tier this token was issued for. Drives rate limits and feature flags on downstream endpoints.',
515
+ example: 'free'
516
+ }
517
+ }
518
+ } as const;
519
+
520
+ export const AuthTokenErrorSchema = {
521
+ type: 'object',
522
+ required: ['code', 'message'],
523
+ description: 'Error envelope returned by `POST /auth/token` when the API key is rejected.',
524
+ properties: {
525
+ code: {
526
+ type: 'string',
527
+ enum: ['invalid_apikey', 'apikey_revoked', 'apikey_expired'],
528
+ description: 'Machine-readable error reason.'
529
+ },
530
+ message: {
531
+ type: 'string',
532
+ description: 'Human-readable description of the failure.'
533
+ }
534
+ }
300
535
  } as const;
@@ -1,7 +1,7 @@
1
1
  // This file is auto-generated by @hey-api/openapi-ts
2
2
 
3
3
  import type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch';
4
- import type { GetExchangesData, GetExchangesResponse, GetInstrumentsData, GetInstrumentsResponse, GetInstrumentsError, GetExchangeTickersHourData, GetExchangeTickersHourResponse, GetExchangeTickersHourError, GetExchangeKlinesHourData, GetExchangeKlinesHourResponse, GetExchangeKlinesHourError, PostStrategyData, PostStrategyResponse, PostStrategyError, GetStrategyStatusData, GetStrategyStatusResponse, GetStrategyStatusError, PrepareBacktestingData, PrepareBacktestingResponse, PrepareBacktestingError, GetPreparationStatusData, GetPreparationStatusResponse, GetPreparationStatusError, ExecuteBacktestingData, ExecuteBacktestingResponse, ExecuteBacktestingError, CancelExecutionData, CancelExecutionResponse, CancelExecutionError, GetExecutionResultData, GetExecutionResultResponse, GetExecutionResultError } from './types.gen';
4
+ import type { AuthData, AuthResponse, AuthError, GetExchangesData, GetExchangesResponse, GetInstrumentsData, GetInstrumentsResponse, GetInstrumentsError, GetSegmentInstrumentsData, GetSegmentInstrumentsResponse, GetSegmentInstrumentsError, GetExchangeTickersHourData, GetExchangeTickersHourResponse, GetExchangeTickersHourError, GetExchangeKlinesHourData, GetExchangeKlinesHourResponse, GetExchangeKlinesHourError, PostStrategyData, PostStrategyResponse, PostStrategyError, GetStrategyStatusData, GetStrategyStatusResponse, GetStrategyStatusError, PrepareBacktestingData, PrepareBacktestingResponse, PrepareBacktestingError, GetPreparationStatusData, GetPreparationStatusResponse, GetPreparationStatusError, ExecuteBacktestingData, ExecuteBacktestingResponse, ExecuteBacktestingError, CancelExecutionData, CancelExecutionResponse, CancelExecutionError, GetExecutionResultData, GetExecutionResultResponse, GetExecutionResultError } from './types.gen';
5
5
  import { client as _heyApiClient } from './client.gen';
6
6
 
7
7
  export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
@@ -18,6 +18,31 @@ export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends
18
18
  meta?: Record<string, unknown>;
19
19
  };
20
20
 
21
+ /**
22
+ * Exchange API key for a short-lived JWT
23
+ * Exchanges a long-lived API key for a short-lived JWT used by every other
24
+ * endpoint. This is the only endpoint that accepts an API key directly —
25
+ * callers should obtain a JWT here, then send it as `Authorization: Bearer
26
+ * <token>` to all other operations.
27
+ *
28
+ * The returned JWT carries the caller's subscription `tier` as a claim and
29
+ * expires after `expires_in` seconds. Callers should refresh the token
30
+ * before expiry (or on a `401` response) by calling this endpoint again.
31
+ *
32
+ */
33
+ export const auth = <ThrowOnError extends boolean = false>(options?: Options<AuthData, ThrowOnError>) => {
34
+ return (options?.client ?? _heyApiClient).post<AuthResponse, AuthError, ThrowOnError>({
35
+ security: [
36
+ {
37
+ name: 'X-API-Key',
38
+ type: 'apiKey'
39
+ }
40
+ ],
41
+ url: '/auth/token',
42
+ ...options
43
+ });
44
+ };
45
+
21
46
  /**
22
47
  * Get a list of available exchanges
23
48
  */
@@ -29,7 +54,12 @@ export const getExchanges = <ThrowOnError extends boolean = false>(options?: Opt
29
54
  };
30
55
 
31
56
  /**
32
- * Get a list of Instruments from a specific exchange
57
+ * Get an exchange's instruments (default spot segment)
58
+ * "Give me binance instruments" — returns the exchange's DEFAULT segment (`spot`)
59
+ * in `data`, each instrument with per-data-type coverage and market info. `meta`
60
+ * confirms the served `segment` (`spot`); HAL `_links` carry `self` plus the
61
+ * `spot` / `futures` segment-discovery links.
62
+ *
33
63
  */
34
64
  export const getInstruments = <ThrowOnError extends boolean = false>(options: Options<GetInstrumentsData, ThrowOnError>) => {
35
65
  return (options.client ?? _heyApiClient).get<GetInstrumentsResponse, GetInstrumentsError, ThrowOnError>({
@@ -38,6 +68,21 @@ export const getInstruments = <ThrowOnError extends boolean = false>(options: Op
38
68
  });
39
69
  };
40
70
 
71
+ /**
72
+ * Get the instruments for a specific exchange segment
73
+ * Returns the instruments for one market segment of the exchange, each with
74
+ * per-data-type coverage and market info. HAL `_links` carry `self` plus the
75
+ * `spot` / `futures` segment-discovery links; the default-segment shortcut is
76
+ * `GET /exchange/{exchangeId}/instruments` (spot).
77
+ *
78
+ */
79
+ export const getSegmentInstruments = <ThrowOnError extends boolean = false>(options: Options<GetSegmentInstrumentsData, ThrowOnError>) => {
80
+ return (options.client ?? _heyApiClient).get<GetSegmentInstrumentsResponse, GetSegmentInstrumentsError, ThrowOnError>({
81
+ url: '/exchange/{exchangeId}/{segment}/instruments',
82
+ ...options
83
+ });
84
+ };
85
+
41
86
  /**
42
87
  * Download one hour of tickers for an instrument as a Lastra segment
43
88
  * Serves exactly one hour of raw ticker data for the given instrument on the
@@ -20,7 +20,69 @@ export type ResponseError = {
20
20
  export type Instrument = string;
21
21
 
22
22
  /**
23
- * Exchange instrument with data availability and market info
23
+ * HAL-style response envelope for the instruments listing
24
+ */
25
+ export type InstrumentListResponse = {
26
+ /**
27
+ * The list of instruments for the segment
28
+ */
29
+ data: Array<InstrumentDetail>;
30
+ meta: InstrumentListMeta;
31
+ _links: InstrumentLinks;
32
+ };
33
+
34
+ /**
35
+ * Metadata describing the instruments listing
36
+ */
37
+ export type InstrumentListMeta = {
38
+ /**
39
+ * When this listing was last refreshed
40
+ */
41
+ updatedAt: string;
42
+ /**
43
+ * The exchange the instruments belong to
44
+ */
45
+ exchange: string;
46
+ /**
47
+ * The market segment served in `data`
48
+ */
49
+ segment: 'spot' | 'futures';
50
+ };
51
+
52
+ /**
53
+ * HAL `_links` — segment discovery for the instruments listing
54
+ */
55
+ export type InstrumentLinks = {
56
+ /**
57
+ * Link to this listing
58
+ */
59
+ self: HalLink;
60
+ /**
61
+ * Link to the spot instruments listing. Present when the exchange has a spot segment.
62
+ */
63
+ spot?: HalLink;
64
+ /**
65
+ * Link to the futures instruments listing. Present only when the exchange has a futures segment.
66
+ */
67
+ futures?: HalLink;
68
+ };
69
+
70
+ /**
71
+ * A HAL link object (Hypertext Application Language)
72
+ */
73
+ export type HalLink = {
74
+ /**
75
+ * The link target as an absolute-path URI reference (resolve against the API base). A URI Template (RFC 6570) when `templated` is true.
76
+ */
77
+ href: string;
78
+ /**
79
+ * True when `href` is an RFC 6570 URI Template.
80
+ */
81
+ templated?: boolean;
82
+ };
83
+
84
+ /**
85
+ * Exchange instrument with per-data-type coverage and market info
24
86
  */
25
87
  export type InstrumentDetail = {
26
88
  /**
@@ -35,14 +97,7 @@ export type InstrumentDetail = {
35
97
  * Quote currency
36
98
  */
37
99
  quote: string;
38
- /**
39
- * Earliest timestamp with quality-verified data available for backtesting
40
- */
41
- dataFrom?: string;
42
- /**
43
- * Latest timestamp with quality-verified data available for backtesting
44
- */
45
- dataTo?: string;
100
+ coverage?: InstrumentCoverage;
46
101
  /**
47
102
  * Last traded price
48
103
  */
@@ -53,6 +108,38 @@ export type InstrumentDetail = {
53
108
  volume24h?: number;
54
109
  };
55
110
 
111
+ /**
112
+ * Time coverage of available data for this instrument, per data type
113
+ */
114
+ export type InstrumentCoverage = {
115
+ /**
116
+ * Coverage of ticker data
117
+ */
118
+ tickers?: CoverageWindow;
119
+ /**
120
+ * Coverage of kline (candlestick) data
121
+ */
122
+ klines?: CoverageWindow;
123
+ };
124
+
125
+ /**
126
+ * The time range of available data for a single data type
127
+ */
128
+ export type CoverageWindow = {
129
+ /**
130
+ * Earliest timestamp with data available
131
+ */
132
+ from?: string;
133
+ /**
134
+ * Latest timestamp with data available
135
+ */
136
+ to?: string;
137
+ /**
138
+ * If the instrument stopped producing this data type (delisted/inactive), the timestamp it went inactive. Optional — omitted while the instrument is active.
139
+ */
140
+ inactiveSince?: string;
141
+ };
142
+
56
143
  /**
57
144
  * Exchange service provider
58
145
  */
@@ -135,7 +222,7 @@ export type BacktestJobResult = {
135
222
  };
136
223
 
137
224
  /**
138
- * Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, totalTrades, winRate, etc.) are present when the strategy emitted at least one trade. When signal storage is enabled, includes signal fields described below.
225
+ * Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy emitted at least one trade. When signal storage is enabled, includes signal fields described below.
139
226
  */
140
227
  export type ResultMap = {
141
228
  /**
@@ -158,6 +245,10 @@ export type ResultMap = {
158
245
  * Total profit and loss in the output currency
159
246
  */
160
247
  pnlTotal?: number;
248
+ /**
249
+ * Total PnL as a percentage of the initial capital (`backtestFunding`). Zero when `backtestFunding` is 0.
250
+ */
251
+ pnlTotalPercent?: number;
161
252
  /**
162
253
  * Total number of trades executed by the strategy
163
254
  */
@@ -186,6 +277,10 @@ export type ResultMap = {
186
277
  * Maximum percentage drawdown from peak equity
187
278
  */
188
279
  maxDrawdownPercent?: number;
280
+ /**
281
+ * Equity curve over the backtest. Element 0 is an anchor at the backtest `from` with `initialCapital`; the remaining points are one sample per emitted yield, in order. Use it to plot the strategy's running equity without re-deriving it from the yield history.
282
+ */
283
+ equityCurve?: Array<EquityPoint>;
189
284
  /**
190
285
  * Number of signals emitted during strategy execution
191
286
  */
@@ -212,11 +307,91 @@ export type ResultMap = {
212
307
  signalsUploadReason?: string;
213
308
  };
214
309
 
310
+ /**
311
+ * Single sample of the running equity at a yield event.
312
+ */
313
+ export type EquityPoint = {
314
+ /**
315
+ * Epoch milliseconds. The first point in an equity curve is anchored at the backtest `from`; subsequent points carry the timestamp of each emitted yield.
316
+ */
317
+ timestamp: number;
318
+ /**
319
+ * Running equity at this point (`initialCapital + cumulativePnl`).
320
+ */
321
+ equity: number;
322
+ };
323
+
215
324
  /**
216
325
  * Unique identifier for a compiled strategy
217
326
  */
218
327
  export type StrategyId = string;
219
328
 
329
+ export type AuthTokenResponse = {
330
+ /**
331
+ * Short-lived HS256 JWT. Send as `Authorization: Bearer <token>` on all other endpoints.
332
+ */
333
+ access_token: string;
334
+ /**
335
+ * Always `Bearer`.
336
+ */
337
+ token_type: 'Bearer';
338
+ /**
339
+ * Seconds until the JWT expires (typically 3600).
340
+ */
341
+ expires_in: number;
342
+ /**
343
+ * Scopes granted to this token. Reserved for future use; currently always empty.
344
+ */
345
+ scopes?: Array<string>;
346
+ /**
347
+ * Subscription tier this token was issued for. Drives rate limits and feature flags on downstream endpoints.
348
+ */
349
+ tier: 'free' | 'basic' | 'pro' | 'elite';
350
+ };
351
+
352
+ /**
353
+ * Error envelope returned by `POST /auth/token` when the API key is rejected.
354
+ */
355
+ export type AuthTokenError = {
356
+ /**
357
+ * Machine-readable error reason.
358
+ */
359
+ code: 'invalid_apikey' | 'apikey_revoked' | 'apikey_expired';
360
+ /**
361
+ * Human-readable description of the failure.
362
+ */
363
+ message: string;
364
+ };
365
+
366
+ export type AuthData = {
367
+ body?: never;
368
+ path?: never;
369
+ query?: never;
370
+ url: '/auth/token';
371
+ };
372
+
373
+ export type AuthErrors = {
374
+ /**
375
+ * API key is invalid, revoked, or expired.
376
+ */
377
+ 401: AuthTokenError;
378
+ /**
379
+ * Rate limit exceeded for this API key.
380
+ */
381
+ 429: unknown;
382
+ };
383
+
384
+ export type AuthError = AuthErrors[keyof AuthErrors];
385
+
386
+ export type AuthResponses = {
387
+ /**
388
+ * API key accepted; JWT returned.
389
+ */
390
+ 200: AuthTokenResponse;
391
+ };
392
+
393
+ export type AuthResponse = AuthResponses[keyof AuthResponses];
394
+
220
395
  export type GetExchangesData = {
221
396
  body?: never;
222
397
  path?: never;
@@ -256,13 +431,47 @@ export type GetInstrumentsError = GetInstrumentsErrors[keyof GetInstrumentsError
256
431
 
257
432
  export type GetInstrumentsResponses = {
258
433
  /**
259
- * A JSON array of Instrument details with data availability
434
+ * The default (spot) segment's instruments in `data`, `meta`, and HAL `_links` (self + spot/futures segment discovery)
260
435
  */
261
- 200: Array<InstrumentDetail>;
436
+ 200: InstrumentListResponse;
262
437
  };
263
438
 
264
439
  export type GetInstrumentsResponse = GetInstrumentsResponses[keyof GetInstrumentsResponses];
265
440
 
441
+ export type GetSegmentInstrumentsData = {
442
+ body?: never;
443
+ path: {
444
+ /**
445
+ * ID of the exchange to retrieve instruments for
446
+ */
447
+ exchangeId: string;
448
+ /**
449
+ * Market segment to list instruments for
450
+ */
451
+ segment: 'spot' | 'futures';
452
+ };
453
+ query?: never;
454
+ url: '/exchange/{exchangeId}/{segment}/instruments';
455
+ };
456
+
457
+ export type GetSegmentInstrumentsErrors = {
458
+ /**
459
+ * Exchange, segment, or instrument catalog not found
460
+ */
461
+ 404: ResponseError;
462
+ };
463
+
464
+ export type GetSegmentInstrumentsError = GetSegmentInstrumentsErrors[keyof GetSegmentInstrumentsErrors];
465
+
466
+ export type GetSegmentInstrumentsResponses = {
467
+ /**
468
+ * An object with a `data` array of instrument details (each with per-data-type coverage) and a `meta` block
469
+ */
470
+ 200: InstrumentListResponse;
471
+ };
472
+
473
+ export type GetSegmentInstrumentsResponse = GetSegmentInstrumentsResponses[keyof GetSegmentInstrumentsResponses];
474
+
266
475
  export type GetExchangeTickersHourData = {
267
476
  body?: never;
268
477
  path: {