@qtsurfer/api-client 0.12.0 → 0.13.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
@@ -68,8 +68,8 @@ pluggable token stores so callers don't reinvent that plumbing.
68
68
 
69
69
  All operations are exported as standalone functions; every operation accepts an `Options` object and returns `{ data, error, response }`.
70
70
 
71
- The table is exhaustive: `src/generated/` is produced from the OpenAPI spec, so **all 28 operations**
72
- the spec declares are exported. The rows below describe **spec version 0.110.3**, which is versioned
71
+ The table is exhaustive: `src/generated/` is produced from the OpenAPI spec, so **all 29 operations**
72
+ the spec declares are exported. The rows below describe **spec version 0.111.2**, which is versioned
73
73
  independently of this package.
74
74
 
75
75
  | Function | Method | Path | Purpose |
@@ -100,6 +100,7 @@ independently of this package.
100
100
  | `createDataset` | POST | `/datasets` | Create a dataset and obtain its first upload session |
101
101
  | `deleteDataset` | DELETE | `/datasets/{datasetId}` | Soft-delete a dataset |
102
102
  | `getDataset` | GET | `/datasets/{datasetId}` | Get dataset metadata |
103
+ | `openDatasetUpload` | POST | `/datasets/{datasetId}/uploads` | Open an upload session for a later dataset version |
103
104
  | `finalizeDatasetUpload` | POST | `/datasets/{datasetId}/uploads/{uploadId}/finalize` | Queue ingest after uploading a file |
104
105
  | `getDatasetUpload` | GET | `/datasets/{datasetId}/uploads/{uploadId}` | Get an upload's ingestion state |
105
106
 
package/dist/index.d.ts CHANGED
@@ -1141,29 +1141,57 @@ type DatasetWithLinks = Dataset & {
1141
1141
  };
1142
1142
  };
1143
1143
  /**
1144
- * A `Dataset` plus the first upload session — the presigned URL to PUT the file to.
1144
+ * A presigned destination for uploading a raw dataset file directly to storage.
1145
+ */
1146
+ type DatasetUploadTarget = {
1147
+ /**
1148
+ * Presigned URL. `PUT` the raw CSV file here directly — no `Authorization` header,
1149
+ * no other API credentials.
1150
+ *
1151
+ */
1152
+ url: string;
1153
+ /**
1154
+ * How long `url` stays valid.
1155
+ */
1156
+ expiresInMinutes: number;
1157
+ };
1158
+ /**
1159
+ * An upload session — an id plus the presigned URL to PUT the raw file to. Returned both by
1160
+ * `POST /datasets` (as part of the new dataset) and by `POST /datasets/{datasetId}/uploads`
1161
+ * (on its own, for an existing one).
1145
1162
  *
1146
1163
  */
1147
- type DatasetCreated = Dataset & {
1164
+ type DatasetUploadSession = {
1148
1165
  /**
1149
1166
  * Identifies this upload session. Pass to
1150
1167
  * `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the PUT completes.
1151
1168
  *
1152
1169
  */
1153
1170
  uploadId: string;
1154
- upload: {
1155
- /**
1156
- * Presigned URL. `PUT` the raw CSV file here directly — no `Authorization`
1157
- * header, no other API credentials.
1158
- *
1159
- */
1160
- url: string;
1161
- /**
1162
- * How long `url` stays valid.
1163
- */
1164
- expiresInMinutes: number;
1165
- };
1171
+ upload: DatasetUploadTarget;
1166
1172
  };
1173
+ /**
1174
+ * The metadata available immediately after creating a dataset, plus its first upload
1175
+ * session — the presigned URL to PUT the file to. Version-derived fields such as
1176
+ * `createdAt`, `currentVersionId`, range, and cadence are available from `GET /datasets/{datasetId}`
1177
+ * after the relevant lifecycle stages, not in this creation response.
1178
+ *
1179
+ */
1180
+ type DatasetCreated = {
1181
+ /**
1182
+ * Opaque id of the newly created dataset.
1183
+ */
1184
+ datasetId: string;
1185
+ /**
1186
+ * Unique name of the newly created dataset.
1187
+ */
1188
+ name: string;
1189
+ /**
1190
+ * Always `ticker` in v1.
1191
+ */
1192
+ type: "ticker";
1193
+ instrument: Instrument;
1194
+ } & DatasetUploadSession;
1167
1195
  /**
1168
1196
  * One successfully ingested upload. Cadence and timestamp unit are discovered from the file,
1169
1197
  * not declared by the caller.
@@ -2147,6 +2175,31 @@ type GetDatasetResponses = {
2147
2175
  200: DatasetWithLinks;
2148
2176
  };
2149
2177
  type GetDatasetResponse = GetDatasetResponses[keyof GetDatasetResponses];
2178
+ type OpenDatasetUploadData = {
2179
+ body?: never;
2180
+ path: {
2181
+ /**
2182
+ * The id returned by `POST /datasets`
2183
+ */
2184
+ datasetId: string;
2185
+ };
2186
+ query?: never;
2187
+ url: "/datasets/{datasetId}/uploads";
2188
+ };
2189
+ type OpenDatasetUploadErrors = {
2190
+ /**
2191
+ * No such dataset for this user
2192
+ */
2193
+ 404: ResponseError;
2194
+ };
2195
+ type OpenDatasetUploadError = OpenDatasetUploadErrors[keyof OpenDatasetUploadErrors];
2196
+ type OpenDatasetUploadResponses = {
2197
+ /**
2198
+ * An upload session — new, or the one already open for this dataset
2199
+ */
2200
+ 201: DatasetUploadSession;
2201
+ };
2202
+ type OpenDatasetUploadResponse = OpenDatasetUploadResponses[keyof OpenDatasetUploadResponses];
2150
2203
  type FinalizeDatasetUploadData = {
2151
2204
  body?: never;
2152
2205
  path: {
@@ -2164,11 +2217,18 @@ type FinalizeDatasetUploadData = {
2164
2217
  };
2165
2218
  type FinalizeDatasetUploadErrors = {
2166
2219
  /**
2167
- * No such dataset for this user, or nothing was PUT to `upload.url` yet — a finalize with
2168
- * nothing to finalize.
2220
+ * No such dataset for this user; `uploadId` was not issued for this dataset (never
2221
+ * minted, or minted for a different one); or nothing was PUT to `upload.url` yet — a
2222
+ * finalize with nothing to finalize.
2169
2223
  *
2170
2224
  */
2171
2225
  404: ResponseError;
2226
+ /**
2227
+ * `uploadId` already produced a version. The error message names it. Open a new upload
2228
+ * session (`POST /datasets/{datasetId}/uploads`) for anything new.
2229
+ *
2230
+ */
2231
+ 409: ResponseError;
2172
2232
  /**
2173
2233
  * The uploaded file exceeds your tier's size limit for a dataset.
2174
2234
  */
@@ -2602,6 +2662,10 @@ declare const listDatasets: <ThrowOnError extends boolean = false>(options?: Opt
2602
2662
  * `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the upload completes to kick
2603
2663
  * off ingest.
2604
2664
  *
2665
+ * Losing this response loses nothing: calling this dataset's
2666
+ * `POST /datasets/{datasetId}/uploads` returns the very same upload session again rather than
2667
+ * opening a new one, as long as nothing has been finalized against it yet.
2668
+ *
2605
2669
  * v1 is ticker data only — `type` is not a request field, it is always `"ticker"` in the
2606
2670
  * response. `instrument` must be a plain spot pair (`BASE/QUOTE`, exactly one `/`); derivative
2607
2671
  * forms (e.g. `BTC/USDT:USDT`) are rejected.
@@ -2630,14 +2694,30 @@ declare const deleteDataset: <ThrowOnError extends boolean = false>(options: Opt
2630
2694
  * Detail for one dataset, plus a self link.
2631
2695
  */
2632
2696
  declare const getDataset: <ThrowOnError extends boolean = false>(options: Options<GetDatasetData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<DatasetWithLinks, ResponseError, ThrowOnError>;
2697
+ /**
2698
+ * Open a new upload session for an existing dataset
2699
+ * Get a fresh presigned URL to upload a new version into a dataset you already have — a
2700
+ * corrected file, or the next chunk of history. Behaves the same way `POST /datasets` does
2701
+ * for a brand-new dataset's own upload: at most one upload session is open per dataset at a
2702
+ * time, so calling this again before finalizing just hands back that same session rather
2703
+ * than opening a second one — safe to call repeatedly if a response gets lost.
2704
+ *
2705
+ * Once a session has been finalized (successfully or not), the next call here opens a
2706
+ * genuinely new one for that dataset's next version.
2707
+ *
2708
+ */
2709
+ declare const openDatasetUpload: <ThrowOnError extends boolean = false>(options: Options<OpenDatasetUploadData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<DatasetUploadSession, ResponseError, ThrowOnError>;
2633
2710
  /**
2634
2711
  * Finalize an uploaded file and start ingest
2635
- * Call once the file has been PUT to the `upload.url` from `POST /datasets`. Enqueues ingest
2636
- * and returns immediately; poll
2712
+ * Call once the file has been PUT to the `upload.url` from `POST /datasets` (or from
2713
+ * `POST /datasets/{datasetId}/uploads`). Enqueues ingest and returns immediately; poll
2637
2714
  * `GET /datasets/{datasetId}/uploads/{uploadId}` for the result.
2638
2715
  *
2639
- * Idempotent — a repeat finalize of the same upload returns the same `jobId` rather than
2640
- * enqueueing a second ingest.
2716
+ * Idempotent while the upload is still open — a repeat finalize before it has produced a
2717
+ * version returns the same `jobId` rather than enqueueing a second ingest. Once it HAS
2718
+ * produced a version, `uploadId` is spent: finalizing it again is a `409`, even with
2719
+ * different bytes freshly PUT to the same URL — open a new upload session instead
2720
+ * (`POST /datasets/{datasetId}/uploads`) rather than reusing a spent one.
2641
2721
  *
2642
2722
  */
2643
2723
  declare const finalizeDatasetUpload: <ThrowOnError extends boolean = false>(options: Options<FinalizeDatasetUploadData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<{
@@ -2653,4 +2733,4 @@ declare const getDatasetUpload: <ThrowOnError extends boolean = false>(options:
2653
2733
 
2654
2734
  declare const client: _hey_api_client_fetch.Client;
2655
2735
 
2656
- export { type AcceptedJob, type AuthTokenError, type AuthTokenResponse, type AuthenticateData, type AuthenticateError, type AuthenticateErrors, type AuthenticateResponse, type AuthenticateResponses, type BacktestJobResult, type CancelBacktestData, type CancelBacktestError, type CancelBacktestErrors, type CancelBacktestResponse, type CancelBacktestResponses, type CancelSweepData, type CancelSweepError, type CancelSweepErrors, type CancelSweepResponse, type CancelSweepResponses, type ClientOptions, type CompileStrategyData, type CompileStrategyError, type CompileStrategyErrors, type CompileStrategyResponse, type CompileStrategyResponses, type CoverageWindow, type CreateDatasetData, type CreateDatasetError, type CreateDatasetErrors, type CreateDatasetResponse, type CreateDatasetResponses, type DataSourceType, type Dataset, type DatasetCreated, type DatasetUploadState, type DatasetVersion, type DatasetWithLinks, type DeclaredProperty, type DeleteDatasetData, type DeleteDatasetError, type DeleteDatasetErrors, type DeleteDatasetResponse, type DeleteDatasetResponses, type DeleteStrategyData, type DeleteStrategyError, type DeleteStrategyErrors, type DeleteStrategyResponse, type DeleteStrategyResponses, type DownloadKlinesData, type DownloadKlinesError, type DownloadKlinesErrors, type DownloadKlinesResponse, type DownloadKlinesResponses, type DownloadTickersData, type DownloadTickersError, type DownloadTickersErrors, type DownloadTickersResponse, type DownloadTickersResponses, type EquityCurveMeta, type EquityCurveOptions, type EquityCurveOutMode, type EquityCurveRequest, type EquityCurveResult, type EquityPoint, type Exchange, type ExecuteBacktestData, type ExecuteBacktestError, type ExecuteBacktestErrors, type ExecuteBacktestResponse, type ExecuteBacktestResponses, type ExecuteSweepAccepted, type ExecuteSweepData, type ExecuteSweepError, type ExecuteSweepErrors, type ExecuteSweepRequest, type ExecuteSweepResponse, type ExecuteSweepResponses, type ExecuteSweepResult, type FinalizeDatasetUploadData, type FinalizeDatasetUploadError, type FinalizeDatasetUploadErrors, type FinalizeDatasetUploadResponse, type FinalizeDatasetUploadResponses, type GetBacktestResultData, type GetBacktestResultError, type GetBacktestResultErrors, type GetBacktestResultResponse, type GetBacktestResultResponses, type GetDatasetData, type GetDatasetError, type GetDatasetErrors, type GetDatasetResponse, type GetDatasetResponses, type GetDatasetUploadData, type GetDatasetUploadError, type GetDatasetUploadErrors, type GetDatasetUploadResponse, type GetDatasetUploadResponses, type GetPrepareStatusData, type GetPrepareStatusError, type GetPrepareStatusErrors, type GetPrepareStatusResponse, type GetPrepareStatusResponses, type GetStrategyCodeData, type GetStrategyCodeError, type GetStrategyCodeErrors, type GetStrategyCodeResponse, type GetStrategyCodeResponses, type GetStrategyData, type GetStrategyError, type GetStrategyErrors, type GetStrategyResponse, type GetStrategyResponses, type GetSweepResultData, type GetSweepResultError, type GetSweepResultErrors, type GetSweepResultResponse, type GetSweepResultResponses, type GetSweepRunEquityCurveData, type GetSweepRunEquityCurveError, type GetSweepRunEquityCurveErrors, type GetSweepRunEquityCurveResponse, type GetSweepRunEquityCurveResponses, type GetSweepSensitivityData, type GetSweepSensitivityError, type GetSweepSensitivityErrors, type GetSweepSensitivityResponse, type GetSweepSensitivityResponses, type HalLink, type Instrument, type InstrumentCoverage, type InstrumentDetail, type InstrumentLinks, type InstrumentListMeta, type InstrumentListResponse, type JobState, type ListDatasetsData, type ListDatasetsResponse, type ListDatasetsResponses, type ListExchangesData, type ListExchangesResponse, type ListExchangesResponses, type ListInstrumentsData, type ListInstrumentsError, type ListInstrumentsErrors, type ListInstrumentsResponse, type ListInstrumentsResponses, type ListSegmentInstrumentsData, type ListSegmentInstrumentsError, type ListSegmentInstrumentsErrors, type ListSegmentInstrumentsResponse, type ListSegmentInstrumentsResponses, type ListStrategiesData, type ListStrategiesResponse, type ListStrategiesResponses, type Notice, type Options, type PrepareBacktestData, type PrepareBacktestError, type PrepareBacktestErrors, type PrepareBacktestResponse, type PrepareBacktestResponses, type PrepareJobState, type PrepareRequest, type ResponseError, type ResultMap, type StrategyId, type StrategyLinks, type StrategyState, type StrategySummary, type SweepAxis, type SweepBaseConfig, type SweepHeatmap, type SweepHeatmapCell, type SweepMarginal, type SweepMarginalPoint, type SweepProgress, type SweepRunRow, type SweepSensitivity, type SweepSpecRequest, type ValidateStrategyData, type ValidateStrategyError, type ValidateStrategyErrors, type ValidateStrategyResponse, type ValidateStrategyResponses, type WalkForwardAccepted, type WalkForwardFold, type WalkForwardRequest, type WalkForwardResult, authenticate, cancelBacktest, cancelSweep, client, compileStrategy, createDataset, deleteDataset, deleteStrategy, downloadKlines, downloadTickers, executeBacktest, executeSweep, finalizeDatasetUpload, getBacktestResult, getDataset, getDatasetUpload, getPrepareStatus, getStrategy, getStrategyCode, getSweepResult, getSweepRunEquityCurve, getSweepSensitivity, listDatasets, listExchanges, listInstruments, listSegmentInstruments, listStrategies, prepareBacktest, validateStrategy };
2736
+ export { type AcceptedJob, type AuthTokenError, type AuthTokenResponse, type AuthenticateData, type AuthenticateError, type AuthenticateErrors, type AuthenticateResponse, type AuthenticateResponses, type BacktestJobResult, type CancelBacktestData, type CancelBacktestError, type CancelBacktestErrors, type CancelBacktestResponse, type CancelBacktestResponses, type CancelSweepData, type CancelSweepError, type CancelSweepErrors, type CancelSweepResponse, type CancelSweepResponses, type ClientOptions, type CompileStrategyData, type CompileStrategyError, type CompileStrategyErrors, type CompileStrategyResponse, type CompileStrategyResponses, type CoverageWindow, type CreateDatasetData, type CreateDatasetError, type CreateDatasetErrors, type CreateDatasetResponse, type CreateDatasetResponses, type DataSourceType, type Dataset, type DatasetCreated, type DatasetUploadSession, type DatasetUploadState, type DatasetUploadTarget, type DatasetVersion, type DatasetWithLinks, type DeclaredProperty, type DeleteDatasetData, type DeleteDatasetError, type DeleteDatasetErrors, type DeleteDatasetResponse, type DeleteDatasetResponses, type DeleteStrategyData, type DeleteStrategyError, type DeleteStrategyErrors, type DeleteStrategyResponse, type DeleteStrategyResponses, type DownloadKlinesData, type DownloadKlinesError, type DownloadKlinesErrors, type DownloadKlinesResponse, type DownloadKlinesResponses, type DownloadTickersData, type DownloadTickersError, type DownloadTickersErrors, type DownloadTickersResponse, type DownloadTickersResponses, type EquityCurveMeta, type EquityCurveOptions, type EquityCurveOutMode, type EquityCurveRequest, type EquityCurveResult, type EquityPoint, type Exchange, type ExecuteBacktestData, type ExecuteBacktestError, type ExecuteBacktestErrors, type ExecuteBacktestResponse, type ExecuteBacktestResponses, type ExecuteSweepAccepted, type ExecuteSweepData, type ExecuteSweepError, type ExecuteSweepErrors, type ExecuteSweepRequest, type ExecuteSweepResponse, type ExecuteSweepResponses, type ExecuteSweepResult, type FinalizeDatasetUploadData, type FinalizeDatasetUploadError, type FinalizeDatasetUploadErrors, type FinalizeDatasetUploadResponse, type FinalizeDatasetUploadResponses, type GetBacktestResultData, type GetBacktestResultError, type GetBacktestResultErrors, type GetBacktestResultResponse, type GetBacktestResultResponses, type GetDatasetData, type GetDatasetError, type GetDatasetErrors, type GetDatasetResponse, type GetDatasetResponses, type GetDatasetUploadData, type GetDatasetUploadError, type GetDatasetUploadErrors, type GetDatasetUploadResponse, type GetDatasetUploadResponses, type GetPrepareStatusData, type GetPrepareStatusError, type GetPrepareStatusErrors, type GetPrepareStatusResponse, type GetPrepareStatusResponses, type GetStrategyCodeData, type GetStrategyCodeError, type GetStrategyCodeErrors, type GetStrategyCodeResponse, type GetStrategyCodeResponses, type GetStrategyData, type GetStrategyError, type GetStrategyErrors, type GetStrategyResponse, type GetStrategyResponses, type GetSweepResultData, type GetSweepResultError, type GetSweepResultErrors, type GetSweepResultResponse, type GetSweepResultResponses, type GetSweepRunEquityCurveData, type GetSweepRunEquityCurveError, type GetSweepRunEquityCurveErrors, type GetSweepRunEquityCurveResponse, type GetSweepRunEquityCurveResponses, type GetSweepSensitivityData, type GetSweepSensitivityError, type GetSweepSensitivityErrors, type GetSweepSensitivityResponse, type GetSweepSensitivityResponses, type HalLink, type Instrument, type InstrumentCoverage, type InstrumentDetail, type InstrumentLinks, type InstrumentListMeta, type InstrumentListResponse, type JobState, type ListDatasetsData, type ListDatasetsResponse, type ListDatasetsResponses, type ListExchangesData, type ListExchangesResponse, type ListExchangesResponses, type ListInstrumentsData, type ListInstrumentsError, type ListInstrumentsErrors, type ListInstrumentsResponse, type ListInstrumentsResponses, type ListSegmentInstrumentsData, type ListSegmentInstrumentsError, type ListSegmentInstrumentsErrors, type ListSegmentInstrumentsResponse, type ListSegmentInstrumentsResponses, type ListStrategiesData, type ListStrategiesResponse, type ListStrategiesResponses, type Notice, type OpenDatasetUploadData, type OpenDatasetUploadError, type OpenDatasetUploadErrors, type OpenDatasetUploadResponse, type OpenDatasetUploadResponses, type Options, type PrepareBacktestData, type PrepareBacktestError, type PrepareBacktestErrors, type PrepareBacktestResponse, type PrepareBacktestResponses, type PrepareJobState, type PrepareRequest, type ResponseError, type ResultMap, type StrategyId, type StrategyLinks, type StrategyState, type StrategySummary, type SweepAxis, type SweepBaseConfig, type SweepHeatmap, type SweepHeatmapCell, type SweepMarginal, type SweepMarginalPoint, type SweepProgress, type SweepRunRow, type SweepSensitivity, type SweepSpecRequest, type ValidateStrategyData, type ValidateStrategyError, type ValidateStrategyErrors, type ValidateStrategyResponse, type ValidateStrategyResponses, type WalkForwardAccepted, type WalkForwardFold, type WalkForwardRequest, type WalkForwardResult, authenticate, cancelBacktest, cancelSweep, client, compileStrategy, createDataset, deleteDataset, deleteStrategy, downloadKlines, downloadTickers, executeBacktest, executeSweep, finalizeDatasetUpload, getBacktestResult, getDataset, getDatasetUpload, getPrepareStatus, getStrategy, getStrategyCode, getSweepResult, getSweepRunEquityCurve, getSweepSensitivity, listDatasets, listExchanges, listInstruments, listSegmentInstruments, listStrategies, openDatasetUpload, prepareBacktest, validateStrategy };
package/dist/index.js CHANGED
@@ -313,6 +313,18 @@ var getDataset = (options) => {
313
313
  ...options
314
314
  });
315
315
  };
316
+ var openDatasetUpload = (options) => {
317
+ return (options.client ?? client).post({
318
+ security: [
319
+ {
320
+ scheme: "bearer",
321
+ type: "http"
322
+ }
323
+ ],
324
+ url: "/datasets/{datasetId}/uploads",
325
+ ...options
326
+ });
327
+ };
316
328
  var finalizeDatasetUpload = (options) => {
317
329
  return (options.client ?? client).post({
318
330
  security: [
@@ -365,6 +377,7 @@ export {
365
377
  listInstruments,
366
378
  listSegmentInstruments,
367
379
  listStrategies,
380
+ openDatasetUpload,
368
381
  prepareBacktest,
369
382
  validateStrategy
370
383
  };
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 {\n type Config,\n type ClientOptions as DefaultClientOptions,\n createClient,\n createConfig,\n} 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> =\n (\n override?: Config<DefaultClientOptions & T>\n ) => Config<Required<DefaultClientOptions> & T>;\n\nexport const client = createClient(\n createConfig<ClientOptions>({\n baseUrl: \"https://api.qtsurfer.net/v1\",\n })\n);\n","// This file is auto-generated by @hey-api/openapi-ts\n\nimport type {\n Options as ClientOptions,\n TDataShape,\n Client,\n} from \"@hey-api/client-fetch\";\nimport type {\n AuthenticateData,\n AuthenticateResponse,\n AuthenticateError,\n ListExchangesData,\n ListExchangesResponse,\n ListInstrumentsData,\n ListInstrumentsResponse,\n ListInstrumentsError,\n ListSegmentInstrumentsData,\n ListSegmentInstrumentsResponse,\n ListSegmentInstrumentsError,\n DownloadTickersData,\n DownloadTickersResponse,\n DownloadTickersError,\n DownloadKlinesData,\n DownloadKlinesResponse,\n DownloadKlinesError,\n ListStrategiesData,\n ListStrategiesResponse,\n CompileStrategyData,\n CompileStrategyResponse,\n CompileStrategyError,\n ValidateStrategyData,\n ValidateStrategyResponse,\n ValidateStrategyError,\n DeleteStrategyData,\n DeleteStrategyResponse,\n DeleteStrategyError,\n GetStrategyData,\n GetStrategyResponse,\n GetStrategyError,\n GetStrategyCodeData,\n GetStrategyCodeResponse,\n GetStrategyCodeError,\n PrepareBacktestData,\n PrepareBacktestResponse,\n PrepareBacktestError,\n GetPrepareStatusData,\n GetPrepareStatusResponse,\n GetPrepareStatusError,\n ExecuteSweepData,\n ExecuteSweepResponse,\n ExecuteSweepError,\n CancelSweepData,\n CancelSweepResponse,\n CancelSweepError,\n GetSweepResultData,\n GetSweepResultResponse,\n GetSweepResultError,\n GetSweepSensitivityData,\n GetSweepSensitivityResponse,\n GetSweepSensitivityError,\n GetSweepRunEquityCurveData,\n GetSweepRunEquityCurveResponse,\n GetSweepRunEquityCurveError,\n ExecuteBacktestData,\n ExecuteBacktestResponse,\n ExecuteBacktestError,\n CancelBacktestData,\n CancelBacktestResponse,\n CancelBacktestError,\n GetBacktestResultData,\n GetBacktestResultResponse,\n GetBacktestResultError,\n ListDatasetsData,\n ListDatasetsResponse,\n CreateDatasetData,\n CreateDatasetResponse,\n CreateDatasetError,\n DeleteDatasetData,\n DeleteDatasetResponse,\n DeleteDatasetError,\n GetDatasetData,\n GetDatasetResponse,\n GetDatasetError,\n FinalizeDatasetUploadData,\n FinalizeDatasetUploadResponse,\n FinalizeDatasetUploadError,\n GetDatasetUploadData,\n GetDatasetUploadResponse,\n GetDatasetUploadError,\n} from \"./types.gen\";\nimport { client as _heyApiClient } from \"./client.gen\";\n\nexport type Options<\n TData extends TDataShape = TDataShape,\n ThrowOnError extends boolean = boolean\n> = 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 authenticate = <ThrowOnError extends boolean = false>(\n options?: Options<AuthenticateData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).post<\n AuthenticateResponse,\n AuthenticateError,\n ThrowOnError\n >({\n security: [\n {\n name: \"X-API-Key\",\n type: \"apiKey\",\n },\n ],\n url: \"/auth/token\",\n ...options,\n });\n};\n\n/**\n * List the available exchanges\n */\nexport const listExchanges = <ThrowOnError extends boolean = false>(\n options?: Options<ListExchangesData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).get<\n ListExchangesResponse,\n unknown,\n ThrowOnError\n >({\n url: \"/exchanges\",\n ...options,\n });\n};\n\n/**\n * List 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 listInstruments = <ThrowOnError extends boolean = false>(\n options: Options<ListInstrumentsData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n ListInstrumentsResponse,\n ListInstrumentsError,\n ThrowOnError\n >({\n url: \"/exchange/{exchangeId}/instruments\",\n ...options,\n });\n};\n\n/**\n * List an exchange segment's instruments\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 listSegmentInstruments = <ThrowOnError extends boolean = false>(\n options: Options<ListSegmentInstrumentsData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n ListSegmentInstrumentsResponse,\n ListSegmentInstrumentsError,\n ThrowOnError\n >({\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 downloadTickers = <ThrowOnError extends boolean = false>(\n options: Options<DownloadTickersData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n DownloadTickersResponse,\n DownloadTickersError,\n ThrowOnError\n >({\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 downloadKlines = <ThrowOnError extends boolean = false>(\n options: Options<DownloadKlinesData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n DownloadKlinesResponse,\n DownloadKlinesError,\n ThrowOnError\n >({\n url: \"/exchange/{exchangeId}/klines/{base}/{quote}\",\n ...options,\n });\n};\n\n/**\n * List your registered strategies\n * Every strategy you have registered and not deleted, most recently compiled first.\n *\n * Each entry carries the same provenance `GET /strategy/{strategyId}` does — `compiledAt`,\n * `requiredSources` — but not its validation state, so listing stays cheap regardless of how\n * many strategies you have. Check a specific strategy's validation with `GET\n * /strategy/{strategyId}`.\n *\n */\nexport const listStrategies = <ThrowOnError extends boolean = false>(\n options?: Options<ListStrategiesData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).get<\n ListStrategiesResponse,\n unknown,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategies\",\n ...options,\n });\n};\n\n/**\n * Compile and register a strategy\n * Compiles raw strategy source and registers it, returning its `strategyId`.\n *\n * **This answers one question: is the source valid Java.** It compiles, registers, and hands\n * back the id — nothing more. Whether the class can actually run is\n * `POST /strategy/{strategyId}/validate`, and everything known about a strategy, validation\n * included, is read from `GET /strategy/{strategyId}`. One place to ask, so there is no second\n * answer to keep in step.\n *\n * The `strategyId` is derived from what the code *means*, not from how it is written. Adding a\n * comment, inserting a blank line, re-indenting, reordering imports, or moving a method around\n * all return the **same** id — you have not created a second strategy. Renaming a variable,\n * changing an identifier's case, reordering fields, or reordering statements inside a method\n * return a **different** one.\n *\n * Two rules follow, and they are worth designing around:\n *\n * - re-submitting a strategy you have only reformatted is free, and gives you back the id you\n * already had, along with any validation already recorded against it;\n * - the id says nothing about *behaviour*. Two sources that compute the same thing by\n * different means are two strategies, because deciding otherwise would mean deciding program\n * equivalence.\n *\n * The response also lists `declaredProperties` — the sweep/execute param keys this strategy\n * is known to accept, so a caller can catch a typo'd key before submitting a sweep instead of\n * only learning it from a rejected one. See `DeclaredProperty`: best-effort, not exhaustive.\n *\n */\nexport const compileStrategy = <ThrowOnError extends boolean = false>(\n options: Options<CompileStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n CompileStrategyResponse,\n CompileStrategyError,\n ThrowOnError\n >({\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 * Check that a registered strategy can actually run\n * Instantiates the compiled class and drives it through a bounded synthetic series, so a wiring\n * fault surfaces here instead of at your first backtest. The verdict — pass or fail, plus any\n * engine notices — is recorded and served from `GET /strategy/{strategyId}`.\n *\n * **Idempotent.** If a verdict already exists for the current compilation it comes straight\n * back with `200` and nothing is queued. Otherwise the check is queued and this returns `202`;\n * poll `GET /strategy/{strategyId}` until `validation` is `passed` or `failed`.\n *\n * Recompiling supersedes a verdict, which makes this callable again — the old answer described\n * bytecode that is no longer what would run.\n *\n */\nexport const validateStrategy = <ThrowOnError extends boolean = false>(\n options: Options<ValidateStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n ValidateStrategyResponse,\n ValidateStrategyError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}/validate\",\n ...options,\n });\n};\n\n/**\n * Release a registered strategy\n * Removes a strategy from `GET /strategy/{strategyId}` and `GET /strategies`. This is not\n * undone by re-submitting the same source to `POST /strategy` — that registers a new\n * strategy, with a new id.\n *\n * **Backtests you already ran against this strategy are unaffected.** Deleting it stops it\n * from counting against your account and stops you from validating or re-running it under\n * this id — it does not erase what already happened.\n *\n * Only removes a strategy you registered yourself. If you copied someone else's strategy\n * (a shared/marketplace listing), deleting your copy never affects theirs, or anyone else's.\n *\n */\nexport const deleteStrategy = <ThrowOnError extends boolean = false>(\n options: Options<DeleteStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n DeleteStrategyResponse,\n DeleteStrategyError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}\",\n ...options,\n });\n};\n\n/**\n * Get a strategy by id, including its validation state\n * Reports that the strategy is registered — implied by a `200` at all — and what validating it\n * found.\n *\n * A `404` means one thing: no such registered strategy for this user. It is never a stale or\n * expired answer; registration and verdict are stored durably, not cached.\n *\n */\nexport const getStrategy = <ThrowOnError extends boolean = false>(\n options: Options<GetStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetStrategyResponse,\n GetStrategyError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}\",\n ...options,\n });\n};\n\n/**\n * Get a registered strategy's source, if you still have one to read\n * The exact source you last submitted for this id — the same text `POST /strategy` derives\n * `strategyId` from, whitespace and comments included.\n *\n * **\"If available\", not \"always\".** A strategy you resolve only through a shared/marketplace\n * listing you copied by reference carries no source of its own, and reads as a `404` here the\n * same as a `strategyId` you never registered — that is the honest answer either way, since\n * from this endpoint's point of view nothing is there to return.\n *\n */\nexport const getStrategyCode = <ThrowOnError extends boolean = false>(\n options: Options<GetStrategyCodeData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetStrategyCodeResponse,\n GetStrategyCodeError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}/code\",\n ...options,\n });\n};\n\n/**\n * Prepare backtest 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 * **`exchangeId: user` is reserved for your own uploaded data.** Instead of a managed\n * exchange, it prepares from a dataset you created via `POST /datasets` (see the **Dataset**\n * endpoints) — send `datasetId` in place of `instrument`. See `PrepareRequest` below for the\n * two request shapes.\n *\n */\nexport const prepareBacktest = <ThrowOnError extends boolean = false>(\n options: Options<PrepareBacktestData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n PrepareBacktestResponse,\n PrepareBacktestError,\n ThrowOnError\n >({\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 * For a dataset prepare (`exchangeId: user`), coverage is reported against the dataset's own\n * cadence grid instead of hours — see `cadence`/`gaps`/`largestGapSteps` on `PrepareJobState`.\n *\n */\nexport const getPrepareStatus = <ThrowOnError extends boolean = false>(\n options: Options<GetPrepareStatusData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetPrepareStatusResponse,\n GetPrepareStatusError,\n ThrowOnError\n >({\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 parameter sweep over prepared data\n * Runs a parameter matrix over the single immutable dataset identified by `requestId`.\n * The backend expands and executes the matrix internally; clients poll the returned\n * `sweepId` for incremental results.\n *\n * Supplying `walkForward` runs the sweep in a different mode entirely. Instead of scoring\n * every parameter vector once over the whole range, the data is split into F sequential\n * folds; each fold optimizes the full grid on its own window and then scores only its winner\n * on the window immediately after — data that winner was not chosen on. It answers a harder\n * question than a leaderboard: not \"which parameters won\", but \"does re-optimizing this\n * periodically actually work\". Omit the block and nothing changes, including the response.\n *\n * The cost is the reason it is opt-in rather than always on: F folds × N vectors, so a\n * 4-fold run over a 500-point grid is 2004 backtests where the plain sweep is 500. The\n * request is rejected when `folds × totalRuns` exceeds the server's sweep budget.\n *\n */\nexport const executeSweep = <ThrowOnError extends boolean = false>(\n options: Options<ExecuteSweepData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n ExecuteSweepResponse,\n ExecuteSweepError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}\",\n ...options,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n};\n\n/**\n * Cancel a running parameter sweep\n * Requests cancellation between parameter vectors. Completed rows remain readable.\n */\nexport const cancelSweep = <ThrowOnError extends boolean = false>(\n options: Options<CancelSweepData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n CancelSweepResponse,\n CancelSweepError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}\",\n ...options,\n });\n};\n\n/**\n * Get sweep progress and results\n * Returns incremental sweep progress. The default `ranked` view sorts and may truncate the\n * display leaderboard. `order=natural` returns every available row, untruncated, ordered by\n * deterministic `runIx`; use that view when materialising durable trial rows.\n *\n * The `ranked` view is ordered by **plateau score** by default, not by the raw objective. A\n * plateau score is the objective of the worst run in a parameter point's immediate\n * neighbourhood, so a point scores well only if the region around it also does — the highest\n * raw score is frequently a spike that does not survive the parameters moving slightly. Pass\n * `ranking=raw` for the unadjusted objective order.\n *\n * Rows in the `ranked` view carry `plateauScore` and `neighbourCount` when plateau ranking\n * applied. Read them together: `neighbourCount: 0` means the point had no neighbours to\n * compare against, so its plateau score is unevidenced rather than confirmed. Sweeps\n * submitted before plateau ranking existed have no stored parameter grid to rebuild a\n * neighbourhood from and are always ranked raw; the response's `ranking` field says which\n * ordering was actually used.\n *\n * A sweep submitted with `walkForward` answers in a different shape, and the `walkForward`\n * field on the response is what tells the two apart — it appears as soon as the sweep is\n * accepted, before any fold has finished, so it is safe to branch on while polling. There\n * the leaderboard is one row per completed fold: that fold's winner as it scored\n * **out-of-sample**, with `runIx` carrying the fold index rather than a grid position. The\n * in-sample runs behind those winners are not retained — they are an optimization's working\n * set, and only the winner survives its fold. `ranking` is always `raw` and no plateau, DSR\n * or PBO figure is reported: the out-of-sample scores are already the honest number, and\n * layering a certification computed over F observations on top of them would overstate what\n * was measured.\n *\n */\nexport const getSweepResult = <ThrowOnError extends boolean = false>(\n options: Options<GetSweepResultData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetSweepResultResponse,\n GetSweepResultError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}\",\n ...options,\n });\n};\n\n/**\n * Get sweep sensitivity surfaces\n * How the objective moves as each parameter moves — the question a leaderboard cannot answer.\n * A leaderboard says which point won; a sweep can spend its entire budget on an axis that\n * never moved the objective at all, and showing only the top rows hides that completely.\n *\n * A **marginal** takes one axis and collapses every other one: for each value of that axis,\n * it aggregates every run that used it, whatever the rest of the parameters were. A flat\n * marginal means the axis is irrelevant over the range swept. `best`, `mean` and `worst` are\n * all reported because them disagreeing is itself the signal — a value with a high `best` and\n * a poor `mean` works only in specific company, which is an interaction between parameters\n * and would be invisible behind a single number.\n *\n * A **heatmap** does the same over a pair of axes, where that interaction becomes visible\n * directly.\n *\n * Served from the sweep's stored rows: no re-run, no engine call, and it works on a sweep\n * still in flight — the aggregates then describe the runs finished so far. Aborted runs are\n * excluded throughout, since a run that threw measured nothing and counting it as a bad\n * outcome would invent evidence against a parameter value that was never really tested.\n *\n * This is a separate endpoint rather than extra fields on the result view because the\n * two-dimensional half is quadratic in the axis count (N axes give N(N-1)/2 surfaces, each\n * the product of two axes' value counts) and is not wanted on the poll that drives progress.\n *\n */\nexport const getSweepSensitivity = <ThrowOnError extends boolean = false>(\n options: Options<GetSweepSensitivityData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetSweepSensitivityResponse,\n GetSweepSensitivityError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}/sensitivity\",\n ...options,\n });\n};\n\n/**\n * Get one sweep trial's equity curve\n * The resource a leaderboard row's `equityCurve.url` points at — only reachable when that\n * trial's curve was actually selected (`equityCurve.mode: topN` or `topPct` on the sweep\n * submission, and this trial ranked among the winners). Returns the exact same\n * `{points|timestamps+equities, meta}` shape a plain backtest's inline `equityCurve` carries.\n *\n * Query params reshape the response the same way a plain backtest's `equityCurve` options do.\n * A param genuinely absent from the query string falls back to the `equityCurve` transform\n * preference the sweep was submitted with — a param\n * present but malformed does not fall back, it degrades the same way it always has. Above a\n * server-side size threshold, the shape is forced regardless of either — `meta.outMode` in\n * the response, not the query string or the submitted default, is the source of truth for\n * what shape actually came back.\n *\n */\nexport const getSweepRunEquityCurve = <ThrowOnError extends boolean = false>(\n options: Options<GetSweepRunEquityCurveData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetSweepRunEquityCurveResponse,\n GetSweepRunEquityCurveError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}/runs/{runIx}/equityCurve\",\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`, `equityCurve`) always\n * return the same `jobId` (idempotent) — a request that omits `equityCurve` dedupes exactly\n * as it did before that field existed.\n *\n * Works unchanged for a dataset-backed prepare (`exchangeId: user`) — the request body is\n * identical either way, since the instrument and range are recovered from `prepareJobId`.\n *\n */\nexport const executeBacktest = <ThrowOnError extends boolean = false>(\n options: Options<ExecuteBacktestData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n ExecuteBacktestResponse,\n ExecuteBacktestError,\n ThrowOnError\n >({\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 cancelBacktest = <ThrowOnError extends boolean = false>(\n options: Options<CancelBacktestData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n CancelBacktestResponse,\n CancelBacktestError,\n ThrowOnError\n >({\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 * A `202` means the result is not readable yet — keep polling. It is never a terminal\n * outcome, and it carries no `state`, so a poll loop that stops on a terminal status will\n * not stop on it.\n *\n */\nexport const getBacktestResult = <ThrowOnError extends boolean = false>(\n options: Options<GetBacktestResultData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetBacktestResultResponse,\n GetBacktestResultError,\n ThrowOnError\n >({\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 * List your datasets\n * Every dataset you have created and not deleted, most recently created first. Never a `404`\n * — an empty array if you have none, same convention as `GET /strategies`.\n *\n */\nexport const listDatasets = <ThrowOnError extends boolean = false>(\n options?: Options<ListDatasetsData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).get<\n ListDatasetsResponse,\n unknown,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets\",\n ...options,\n });\n};\n\n/**\n * Create a dataset and get a URL to upload it to\n * Creates a dataset AND its first upload session in one call — a presigned URL your client\n * PUTs the file to directly, no API credentials involved in that PUT. Call\n * `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the upload completes to kick\n * off ingest.\n *\n * v1 is ticker data only — `type` is not a request field, it is always `\"ticker\"` in the\n * response. `instrument` must be a plain spot pair (`BASE/QUOTE`, exactly one `/`); derivative\n * forms (e.g. `BTC/USDT:USDT`) are rejected.\n *\n * **Upload format.** A CSV with a header row. Required columns: `timestamp` (ISO-8601, or\n * numeric epoch seconds/millis/micros — detected from the first row, then enforced for every\n * later row), `close`. Optional columns: `open`, `high`, `low`, `volume`, `quoteVolume`,\n * `bid`, `bidSize`, `ask`, `askSize`. Cadence and timestamp unit are discovered from the data,\n * not declared.\n *\n */\nexport const createDataset = <ThrowOnError extends boolean = false>(\n options: Options<CreateDatasetData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n CreateDatasetResponse,\n CreateDatasetError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets\",\n ...options,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n};\n\n/**\n * Delete a dataset\n * Soft-delete — the dataset stops appearing in `GET /datasets`/`GET /datasets/{datasetId}` and\n * can no longer be prepared from, but its object data is reclaimed later rather than purged\n * inline, so a backtest already running against one of its versions is not disrupted.\n *\n */\nexport const deleteDataset = <ThrowOnError extends boolean = false>(\n options: Options<DeleteDatasetData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n DeleteDatasetResponse,\n DeleteDatasetError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}\",\n ...options,\n });\n};\n\n/**\n * Get a dataset by id\n * Detail for one dataset, plus a self link.\n */\nexport const getDataset = <ThrowOnError extends boolean = false>(\n options: Options<GetDatasetData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetDatasetResponse,\n GetDatasetError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}\",\n ...options,\n });\n};\n\n/**\n * Finalize an uploaded file and start ingest\n * Call once the file has been PUT to the `upload.url` from `POST /datasets`. Enqueues ingest\n * and returns immediately; poll\n * `GET /datasets/{datasetId}/uploads/{uploadId}` for the result.\n *\n * Idempotent — a repeat finalize of the same upload returns the same `jobId` rather than\n * enqueueing a second ingest.\n *\n */\nexport const finalizeDatasetUpload = <ThrowOnError extends boolean = false>(\n options: Options<FinalizeDatasetUploadData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n FinalizeDatasetUploadResponse,\n FinalizeDatasetUploadError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}/uploads/{uploadId}/finalize\",\n ...options,\n });\n};\n\n/**\n * Get the state of an upload/ingest\n * Poll after `POST .../finalize` until `status` is `ready` or `failed`. Also reports\n * `uploading` (finalize not called yet, but the file was PUT) before you finalize at all.\n *\n */\nexport const getDatasetUpload = <ThrowOnError extends boolean = false>(\n options: Options<GetDatasetUploadData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetDatasetUploadResponse,\n GetDatasetUploadError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}/uploads/{uploadId}\",\n ...options,\n });\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 {\n type Config,\n type ClientOptions as DefaultClientOptions,\n createClient,\n createConfig,\n} 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> =\n (\n override?: Config<DefaultClientOptions & T>\n ) => Config<Required<DefaultClientOptions> & T>;\n\nexport const client = createClient(\n createConfig<ClientOptions>({\n baseUrl: \"https://api.qtsurfer.net/v1\",\n })\n);\n","// This file is auto-generated by @hey-api/openapi-ts\n\nimport type {\n Options as ClientOptions,\n TDataShape,\n Client,\n} from \"@hey-api/client-fetch\";\nimport type {\n AuthenticateData,\n AuthenticateResponse,\n AuthenticateError,\n ListExchangesData,\n ListExchangesResponse,\n ListInstrumentsData,\n ListInstrumentsResponse,\n ListInstrumentsError,\n ListSegmentInstrumentsData,\n ListSegmentInstrumentsResponse,\n ListSegmentInstrumentsError,\n DownloadTickersData,\n DownloadTickersResponse,\n DownloadTickersError,\n DownloadKlinesData,\n DownloadKlinesResponse,\n DownloadKlinesError,\n ListStrategiesData,\n ListStrategiesResponse,\n CompileStrategyData,\n CompileStrategyResponse,\n CompileStrategyError,\n ValidateStrategyData,\n ValidateStrategyResponse,\n ValidateStrategyError,\n DeleteStrategyData,\n DeleteStrategyResponse,\n DeleteStrategyError,\n GetStrategyData,\n GetStrategyResponse,\n GetStrategyError,\n GetStrategyCodeData,\n GetStrategyCodeResponse,\n GetStrategyCodeError,\n PrepareBacktestData,\n PrepareBacktestResponse,\n PrepareBacktestError,\n GetPrepareStatusData,\n GetPrepareStatusResponse,\n GetPrepareStatusError,\n ExecuteSweepData,\n ExecuteSweepResponse,\n ExecuteSweepError,\n CancelSweepData,\n CancelSweepResponse,\n CancelSweepError,\n GetSweepResultData,\n GetSweepResultResponse,\n GetSweepResultError,\n GetSweepSensitivityData,\n GetSweepSensitivityResponse,\n GetSweepSensitivityError,\n GetSweepRunEquityCurveData,\n GetSweepRunEquityCurveResponse,\n GetSweepRunEquityCurveError,\n ExecuteBacktestData,\n ExecuteBacktestResponse,\n ExecuteBacktestError,\n CancelBacktestData,\n CancelBacktestResponse,\n CancelBacktestError,\n GetBacktestResultData,\n GetBacktestResultResponse,\n GetBacktestResultError,\n ListDatasetsData,\n ListDatasetsResponse,\n CreateDatasetData,\n CreateDatasetResponse,\n CreateDatasetError,\n DeleteDatasetData,\n DeleteDatasetResponse,\n DeleteDatasetError,\n GetDatasetData,\n GetDatasetResponse,\n GetDatasetError,\n OpenDatasetUploadData,\n OpenDatasetUploadResponse,\n OpenDatasetUploadError,\n FinalizeDatasetUploadData,\n FinalizeDatasetUploadResponse,\n FinalizeDatasetUploadError,\n GetDatasetUploadData,\n GetDatasetUploadResponse,\n GetDatasetUploadError,\n} from \"./types.gen\";\nimport { client as _heyApiClient } from \"./client.gen\";\n\nexport type Options<\n TData extends TDataShape = TDataShape,\n ThrowOnError extends boolean = boolean\n> = 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 authenticate = <ThrowOnError extends boolean = false>(\n options?: Options<AuthenticateData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).post<\n AuthenticateResponse,\n AuthenticateError,\n ThrowOnError\n >({\n security: [\n {\n name: \"X-API-Key\",\n type: \"apiKey\",\n },\n ],\n url: \"/auth/token\",\n ...options,\n });\n};\n\n/**\n * List the available exchanges\n */\nexport const listExchanges = <ThrowOnError extends boolean = false>(\n options?: Options<ListExchangesData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).get<\n ListExchangesResponse,\n unknown,\n ThrowOnError\n >({\n url: \"/exchanges\",\n ...options,\n });\n};\n\n/**\n * List 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 listInstruments = <ThrowOnError extends boolean = false>(\n options: Options<ListInstrumentsData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n ListInstrumentsResponse,\n ListInstrumentsError,\n ThrowOnError\n >({\n url: \"/exchange/{exchangeId}/instruments\",\n ...options,\n });\n};\n\n/**\n * List an exchange segment's instruments\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 listSegmentInstruments = <ThrowOnError extends boolean = false>(\n options: Options<ListSegmentInstrumentsData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n ListSegmentInstrumentsResponse,\n ListSegmentInstrumentsError,\n ThrowOnError\n >({\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 downloadTickers = <ThrowOnError extends boolean = false>(\n options: Options<DownloadTickersData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n DownloadTickersResponse,\n DownloadTickersError,\n ThrowOnError\n >({\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 downloadKlines = <ThrowOnError extends boolean = false>(\n options: Options<DownloadKlinesData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n DownloadKlinesResponse,\n DownloadKlinesError,\n ThrowOnError\n >({\n url: \"/exchange/{exchangeId}/klines/{base}/{quote}\",\n ...options,\n });\n};\n\n/**\n * List your registered strategies\n * Every strategy you have registered and not deleted, most recently compiled first.\n *\n * Each entry carries the same provenance `GET /strategy/{strategyId}` does — `compiledAt`,\n * `requiredSources` — but not its validation state, so listing stays cheap regardless of how\n * many strategies you have. Check a specific strategy's validation with `GET\n * /strategy/{strategyId}`.\n *\n */\nexport const listStrategies = <ThrowOnError extends boolean = false>(\n options?: Options<ListStrategiesData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).get<\n ListStrategiesResponse,\n unknown,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategies\",\n ...options,\n });\n};\n\n/**\n * Compile and register a strategy\n * Compiles raw strategy source and registers it, returning its `strategyId`.\n *\n * **This answers one question: is the source valid Java.** It compiles, registers, and hands\n * back the id — nothing more. Whether the class can actually run is\n * `POST /strategy/{strategyId}/validate`, and everything known about a strategy, validation\n * included, is read from `GET /strategy/{strategyId}`. One place to ask, so there is no second\n * answer to keep in step.\n *\n * The `strategyId` is derived from what the code *means*, not from how it is written. Adding a\n * comment, inserting a blank line, re-indenting, reordering imports, or moving a method around\n * all return the **same** id — you have not created a second strategy. Renaming a variable,\n * changing an identifier's case, reordering fields, or reordering statements inside a method\n * return a **different** one.\n *\n * Two rules follow, and they are worth designing around:\n *\n * - re-submitting a strategy you have only reformatted is free, and gives you back the id you\n * already had, along with any validation already recorded against it;\n * - the id says nothing about *behaviour*. Two sources that compute the same thing by\n * different means are two strategies, because deciding otherwise would mean deciding program\n * equivalence.\n *\n * The response also lists `declaredProperties` — the sweep/execute param keys this strategy\n * is known to accept, so a caller can catch a typo'd key before submitting a sweep instead of\n * only learning it from a rejected one. See `DeclaredProperty`: best-effort, not exhaustive.\n *\n */\nexport const compileStrategy = <ThrowOnError extends boolean = false>(\n options: Options<CompileStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n CompileStrategyResponse,\n CompileStrategyError,\n ThrowOnError\n >({\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 * Check that a registered strategy can actually run\n * Instantiates the compiled class and drives it through a bounded synthetic series, so a wiring\n * fault surfaces here instead of at your first backtest. The verdict — pass or fail, plus any\n * engine notices — is recorded and served from `GET /strategy/{strategyId}`.\n *\n * **Idempotent.** If a verdict already exists for the current compilation it comes straight\n * back with `200` and nothing is queued. Otherwise the check is queued and this returns `202`;\n * poll `GET /strategy/{strategyId}` until `validation` is `passed` or `failed`.\n *\n * Recompiling supersedes a verdict, which makes this callable again — the old answer described\n * bytecode that is no longer what would run.\n *\n */\nexport const validateStrategy = <ThrowOnError extends boolean = false>(\n options: Options<ValidateStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n ValidateStrategyResponse,\n ValidateStrategyError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}/validate\",\n ...options,\n });\n};\n\n/**\n * Release a registered strategy\n * Removes a strategy from `GET /strategy/{strategyId}` and `GET /strategies`. This is not\n * undone by re-submitting the same source to `POST /strategy` — that registers a new\n * strategy, with a new id.\n *\n * **Backtests you already ran against this strategy are unaffected.** Deleting it stops it\n * from counting against your account and stops you from validating or re-running it under\n * this id — it does not erase what already happened.\n *\n * Only removes a strategy you registered yourself. If you copied someone else's strategy\n * (a shared/marketplace listing), deleting your copy never affects theirs, or anyone else's.\n *\n */\nexport const deleteStrategy = <ThrowOnError extends boolean = false>(\n options: Options<DeleteStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n DeleteStrategyResponse,\n DeleteStrategyError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}\",\n ...options,\n });\n};\n\n/**\n * Get a strategy by id, including its validation state\n * Reports that the strategy is registered — implied by a `200` at all — and what validating it\n * found.\n *\n * A `404` means one thing: no such registered strategy for this user. It is never a stale or\n * expired answer; registration and verdict are stored durably, not cached.\n *\n */\nexport const getStrategy = <ThrowOnError extends boolean = false>(\n options: Options<GetStrategyData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetStrategyResponse,\n GetStrategyError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}\",\n ...options,\n });\n};\n\n/**\n * Get a registered strategy's source, if you still have one to read\n * The exact source you last submitted for this id — the same text `POST /strategy` derives\n * `strategyId` from, whitespace and comments included.\n *\n * **\"If available\", not \"always\".** A strategy you resolve only through a shared/marketplace\n * listing you copied by reference carries no source of its own, and reads as a `404` here the\n * same as a `strategyId` you never registered — that is the honest answer either way, since\n * from this endpoint's point of view nothing is there to return.\n *\n */\nexport const getStrategyCode = <ThrowOnError extends boolean = false>(\n options: Options<GetStrategyCodeData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetStrategyCodeResponse,\n GetStrategyCodeError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/strategy/{strategyId}/code\",\n ...options,\n });\n};\n\n/**\n * Prepare backtest 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 * **`exchangeId: user` is reserved for your own uploaded data.** Instead of a managed\n * exchange, it prepares from a dataset you created via `POST /datasets` (see the **Dataset**\n * endpoints) — send `datasetId` in place of `instrument`. See `PrepareRequest` below for the\n * two request shapes.\n *\n */\nexport const prepareBacktest = <ThrowOnError extends boolean = false>(\n options: Options<PrepareBacktestData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n PrepareBacktestResponse,\n PrepareBacktestError,\n ThrowOnError\n >({\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 * For a dataset prepare (`exchangeId: user`), coverage is reported against the dataset's own\n * cadence grid instead of hours — see `cadence`/`gaps`/`largestGapSteps` on `PrepareJobState`.\n *\n */\nexport const getPrepareStatus = <ThrowOnError extends boolean = false>(\n options: Options<GetPrepareStatusData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetPrepareStatusResponse,\n GetPrepareStatusError,\n ThrowOnError\n >({\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 parameter sweep over prepared data\n * Runs a parameter matrix over the single immutable dataset identified by `requestId`.\n * The backend expands and executes the matrix internally; clients poll the returned\n * `sweepId` for incremental results.\n *\n * Supplying `walkForward` runs the sweep in a different mode entirely. Instead of scoring\n * every parameter vector once over the whole range, the data is split into F sequential\n * folds; each fold optimizes the full grid on its own window and then scores only its winner\n * on the window immediately after — data that winner was not chosen on. It answers a harder\n * question than a leaderboard: not \"which parameters won\", but \"does re-optimizing this\n * periodically actually work\". Omit the block and nothing changes, including the response.\n *\n * The cost is the reason it is opt-in rather than always on: F folds × N vectors, so a\n * 4-fold run over a 500-point grid is 2004 backtests where the plain sweep is 500. The\n * request is rejected when `folds × totalRuns` exceeds the server's sweep budget.\n *\n */\nexport const executeSweep = <ThrowOnError extends boolean = false>(\n options: Options<ExecuteSweepData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n ExecuteSweepResponse,\n ExecuteSweepError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}\",\n ...options,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n};\n\n/**\n * Cancel a running parameter sweep\n * Requests cancellation between parameter vectors. Completed rows remain readable.\n */\nexport const cancelSweep = <ThrowOnError extends boolean = false>(\n options: Options<CancelSweepData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n CancelSweepResponse,\n CancelSweepError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}\",\n ...options,\n });\n};\n\n/**\n * Get sweep progress and results\n * Returns incremental sweep progress. The default `ranked` view sorts and may truncate the\n * display leaderboard. `order=natural` returns every available row, untruncated, ordered by\n * deterministic `runIx`; use that view when materialising durable trial rows.\n *\n * The `ranked` view is ordered by **plateau score** by default, not by the raw objective. A\n * plateau score is the objective of the worst run in a parameter point's immediate\n * neighbourhood, so a point scores well only if the region around it also does — the highest\n * raw score is frequently a spike that does not survive the parameters moving slightly. Pass\n * `ranking=raw` for the unadjusted objective order.\n *\n * Rows in the `ranked` view carry `plateauScore` and `neighbourCount` when plateau ranking\n * applied. Read them together: `neighbourCount: 0` means the point had no neighbours to\n * compare against, so its plateau score is unevidenced rather than confirmed. Sweeps\n * submitted before plateau ranking existed have no stored parameter grid to rebuild a\n * neighbourhood from and are always ranked raw; the response's `ranking` field says which\n * ordering was actually used.\n *\n * A sweep submitted with `walkForward` answers in a different shape, and the `walkForward`\n * field on the response is what tells the two apart — it appears as soon as the sweep is\n * accepted, before any fold has finished, so it is safe to branch on while polling. There\n * the leaderboard is one row per completed fold: that fold's winner as it scored\n * **out-of-sample**, with `runIx` carrying the fold index rather than a grid position. The\n * in-sample runs behind those winners are not retained — they are an optimization's working\n * set, and only the winner survives its fold. `ranking` is always `raw` and no plateau, DSR\n * or PBO figure is reported: the out-of-sample scores are already the honest number, and\n * layering a certification computed over F observations on top of them would overstate what\n * was measured.\n *\n */\nexport const getSweepResult = <ThrowOnError extends boolean = false>(\n options: Options<GetSweepResultData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetSweepResultResponse,\n GetSweepResultError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}\",\n ...options,\n });\n};\n\n/**\n * Get sweep sensitivity surfaces\n * How the objective moves as each parameter moves — the question a leaderboard cannot answer.\n * A leaderboard says which point won; a sweep can spend its entire budget on an axis that\n * never moved the objective at all, and showing only the top rows hides that completely.\n *\n * A **marginal** takes one axis and collapses every other one: for each value of that axis,\n * it aggregates every run that used it, whatever the rest of the parameters were. A flat\n * marginal means the axis is irrelevant over the range swept. `best`, `mean` and `worst` are\n * all reported because them disagreeing is itself the signal — a value with a high `best` and\n * a poor `mean` works only in specific company, which is an interaction between parameters\n * and would be invisible behind a single number.\n *\n * A **heatmap** does the same over a pair of axes, where that interaction becomes visible\n * directly.\n *\n * Served from the sweep's stored rows: no re-run, no engine call, and it works on a sweep\n * still in flight — the aggregates then describe the runs finished so far. Aborted runs are\n * excluded throughout, since a run that threw measured nothing and counting it as a bad\n * outcome would invent evidence against a parameter value that was never really tested.\n *\n * This is a separate endpoint rather than extra fields on the result view because the\n * two-dimensional half is quadratic in the axis count (N axes give N(N-1)/2 surfaces, each\n * the product of two axes' value counts) and is not wanted on the poll that drives progress.\n *\n */\nexport const getSweepSensitivity = <ThrowOnError extends boolean = false>(\n options: Options<GetSweepSensitivityData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetSweepSensitivityResponse,\n GetSweepSensitivityError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}/sensitivity\",\n ...options,\n });\n};\n\n/**\n * Get one sweep trial's equity curve\n * The resource a leaderboard row's `equityCurve.url` points at — only reachable when that\n * trial's curve was actually selected (`equityCurve.mode: topN` or `topPct` on the sweep\n * submission, and this trial ranked among the winners). Returns the exact same\n * `{points|timestamps+equities, meta}` shape a plain backtest's inline `equityCurve` carries.\n *\n * Query params reshape the response the same way a plain backtest's `equityCurve` options do.\n * A param genuinely absent from the query string falls back to the `equityCurve` transform\n * preference the sweep was submitted with — a param\n * present but malformed does not fall back, it degrades the same way it always has. Above a\n * server-side size threshold, the shape is forced regardless of either — `meta.outMode` in\n * the response, not the query string or the submitted default, is the source of truth for\n * what shape actually came back.\n *\n */\nexport const getSweepRunEquityCurve = <ThrowOnError extends boolean = false>(\n options: Options<GetSweepRunEquityCurveData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetSweepRunEquityCurveResponse,\n GetSweepRunEquityCurveError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}/runs/{runIx}/equityCurve\",\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`, `equityCurve`) always\n * return the same `jobId` (idempotent) — a request that omits `equityCurve` dedupes exactly\n * as it did before that field existed.\n *\n * Works unchanged for a dataset-backed prepare (`exchangeId: user`) — the request body is\n * identical either way, since the instrument and range are recovered from `prepareJobId`.\n *\n */\nexport const executeBacktest = <ThrowOnError extends boolean = false>(\n options: Options<ExecuteBacktestData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n ExecuteBacktestResponse,\n ExecuteBacktestError,\n ThrowOnError\n >({\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 cancelBacktest = <ThrowOnError extends boolean = false>(\n options: Options<CancelBacktestData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n CancelBacktestResponse,\n CancelBacktestError,\n ThrowOnError\n >({\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 * A `202` means the result is not readable yet — keep polling. It is never a terminal\n * outcome, and it carries no `state`, so a poll loop that stops on a terminal status will\n * not stop on it.\n *\n */\nexport const getBacktestResult = <ThrowOnError extends boolean = false>(\n options: Options<GetBacktestResultData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetBacktestResultResponse,\n GetBacktestResultError,\n ThrowOnError\n >({\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 * List your datasets\n * Every dataset you have created and not deleted, most recently created first. Never a `404`\n * — an empty array if you have none, same convention as `GET /strategies`.\n *\n */\nexport const listDatasets = <ThrowOnError extends boolean = false>(\n options?: Options<ListDatasetsData, ThrowOnError>\n) => {\n return (options?.client ?? _heyApiClient).get<\n ListDatasetsResponse,\n unknown,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets\",\n ...options,\n });\n};\n\n/**\n * Create a dataset and get a URL to upload it to\n * Creates a dataset AND its first upload session in one call — a presigned URL your client\n * PUTs the file to directly, no API credentials involved in that PUT. Call\n * `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the upload completes to kick\n * off ingest.\n *\n * Losing this response loses nothing: calling this dataset's\n * `POST /datasets/{datasetId}/uploads` returns the very same upload session again rather than\n * opening a new one, as long as nothing has been finalized against it yet.\n *\n * v1 is ticker data only — `type` is not a request field, it is always `\"ticker\"` in the\n * response. `instrument` must be a plain spot pair (`BASE/QUOTE`, exactly one `/`); derivative\n * forms (e.g. `BTC/USDT:USDT`) are rejected.\n *\n * **Upload format.** A CSV with a header row. Required columns: `timestamp` (ISO-8601, or\n * numeric epoch seconds/millis/micros — detected from the first row, then enforced for every\n * later row), `close`. Optional columns: `open`, `high`, `low`, `volume`, `quoteVolume`,\n * `bid`, `bidSize`, `ask`, `askSize`. Cadence and timestamp unit are discovered from the data,\n * not declared.\n *\n */\nexport const createDataset = <ThrowOnError extends boolean = false>(\n options: Options<CreateDatasetData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n CreateDatasetResponse,\n CreateDatasetError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets\",\n ...options,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n};\n\n/**\n * Delete a dataset\n * Soft-delete — the dataset stops appearing in `GET /datasets`/`GET /datasets/{datasetId}` and\n * can no longer be prepared from, but its object data is reclaimed later rather than purged\n * inline, so a backtest already running against one of its versions is not disrupted.\n *\n */\nexport const deleteDataset = <ThrowOnError extends boolean = false>(\n options: Options<DeleteDatasetData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).delete<\n DeleteDatasetResponse,\n DeleteDatasetError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}\",\n ...options,\n });\n};\n\n/**\n * Get a dataset by id\n * Detail for one dataset, plus a self link.\n */\nexport const getDataset = <ThrowOnError extends boolean = false>(\n options: Options<GetDatasetData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetDatasetResponse,\n GetDatasetError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}\",\n ...options,\n });\n};\n\n/**\n * Open a new upload session for an existing dataset\n * Get a fresh presigned URL to upload a new version into a dataset you already have — a\n * corrected file, or the next chunk of history. Behaves the same way `POST /datasets` does\n * for a brand-new dataset's own upload: at most one upload session is open per dataset at a\n * time, so calling this again before finalizing just hands back that same session rather\n * than opening a second one — safe to call repeatedly if a response gets lost.\n *\n * Once a session has been finalized (successfully or not), the next call here opens a\n * genuinely new one for that dataset's next version.\n *\n */\nexport const openDatasetUpload = <ThrowOnError extends boolean = false>(\n options: Options<OpenDatasetUploadData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n OpenDatasetUploadResponse,\n OpenDatasetUploadError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}/uploads\",\n ...options,\n });\n};\n\n/**\n * Finalize an uploaded file and start ingest\n * Call once the file has been PUT to the `upload.url` from `POST /datasets` (or from\n * `POST /datasets/{datasetId}/uploads`). Enqueues ingest and returns immediately; poll\n * `GET /datasets/{datasetId}/uploads/{uploadId}` for the result.\n *\n * Idempotent while the upload is still open — a repeat finalize before it has produced a\n * version returns the same `jobId` rather than enqueueing a second ingest. Once it HAS\n * produced a version, `uploadId` is spent: finalizing it again is a `409`, even with\n * different bytes freshly PUT to the same URL — open a new upload session instead\n * (`POST /datasets/{datasetId}/uploads`) rather than reusing a spent one.\n *\n */\nexport const finalizeDatasetUpload = <ThrowOnError extends boolean = false>(\n options: Options<FinalizeDatasetUploadData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).post<\n FinalizeDatasetUploadResponse,\n FinalizeDatasetUploadError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}/uploads/{uploadId}/finalize\",\n ...options,\n });\n};\n\n/**\n * Get the state of an upload/ingest\n * Poll after `POST .../finalize` until `status` is `ready` or `failed`. Also reports\n * `uploading` (finalize not called yet, but the file was PUT) before you finalize at all.\n *\n */\nexport const getDatasetUpload = <ThrowOnError extends boolean = false>(\n options: Options<GetDatasetUploadData, ThrowOnError>\n) => {\n return (options.client ?? _heyApiClient).get<\n GetDatasetUploadResponse,\n GetDatasetUploadError,\n ThrowOnError\n >({\n security: [\n {\n scheme: \"bearer\",\n type: \"http\",\n },\n ],\n url: \"/datasets/{datasetId}/uploads/{uploadId}\",\n ...options,\n });\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.12.0",
3
+ "version": "0.13.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",
@@ -2027,45 +2027,84 @@ export const DatasetWithLinksSchema = {
2027
2027
  ],
2028
2028
  } as const;
2029
2029
 
2030
+ export const DatasetUploadTargetSchema = {
2031
+ description:
2032
+ "A presigned destination for uploading a raw dataset file directly to storage.",
2033
+ type: "object",
2034
+ required: ["url", "expiresInMinutes"],
2035
+ properties: {
2036
+ url: {
2037
+ type: "string",
2038
+ description: `Presigned URL. \`PUT\` the raw CSV file here directly — no \`Authorization\` header,
2039
+ no other API credentials.
2040
+ `,
2041
+ example:
2042
+ "https://storage.qtsurfer.com/uploads/00000000-.../up_1a2b3c4d5e6f7a8b/raw.csv?X-Amz-...",
2043
+ },
2044
+ expiresInMinutes: {
2045
+ type: "integer",
2046
+ description: "How long `url` stays valid.",
2047
+ example: 15,
2048
+ },
2049
+ },
2050
+ } as const;
2051
+
2052
+ export const DatasetUploadSessionSchema = {
2053
+ description: `An upload session — an id plus the presigned URL to PUT the raw file to. Returned both by
2054
+ \`POST /datasets\` (as part of the new dataset) and by \`POST /datasets/{datasetId}/uploads\`
2055
+ (on its own, for an existing one).
2056
+ `,
2057
+ type: "object",
2058
+ required: ["uploadId", "upload"],
2059
+ properties: {
2060
+ uploadId: {
2061
+ type: "string",
2062
+ description: `Identifies this upload session. Pass to
2063
+ \`POST /datasets/{datasetId}/uploads/{uploadId}/finalize\` once the PUT completes.
2064
+ `,
2065
+ example: "up_1a2b3c4d5e6f7a8b",
2066
+ },
2067
+ upload: {
2068
+ $ref: "#/components/schemas/DatasetUploadTarget",
2069
+ },
2070
+ },
2071
+ } as const;
2072
+
2030
2073
  export const DatasetCreatedSchema = {
2031
- description: `A \`Dataset\` plus the first upload session — the presigned URL to PUT the file to.
2074
+ description: `The metadata available immediately after creating a dataset, plus its first upload
2075
+ session — the presigned URL to PUT the file to. Version-derived fields such as
2076
+ \`createdAt\`, \`currentVersionId\`, range, and cadence are available from \`GET /datasets/{datasetId}\`
2077
+ after the relevant lifecycle stages, not in this creation response.
2032
2078
  `,
2033
2079
  allOf: [
2034
- {
2035
- $ref: "#/components/schemas/Dataset",
2036
- },
2037
2080
  {
2038
2081
  type: "object",
2039
- required: ["uploadId", "upload"],
2082
+ required: ["datasetId", "name", "type", "instrument"],
2040
2083
  properties: {
2041
- uploadId: {
2084
+ datasetId: {
2042
2085
  type: "string",
2043
- description: `Identifies this upload session. Pass to
2044
- \`POST /datasets/{datasetId}/uploads/{uploadId}/finalize\` once the PUT completes.
2045
- `,
2046
- example: "up_1a2b3c4d5e6f7a8b",
2086
+ description: "Opaque id of the newly created dataset.",
2087
+ example: "ds_3f9a1c2e7b0d4a5f",
2047
2088
  },
2048
- upload: {
2049
- type: "object",
2050
- required: ["url", "expiresInMinutes"],
2051
- properties: {
2052
- url: {
2053
- type: "string",
2054
- description: `Presigned URL. \`PUT\` the raw CSV file here directly — no \`Authorization\`
2055
- header, no other API credentials.
2056
- `,
2057
- example:
2058
- "https://storage.qtsurfer.com/00000000-.../uploads/up_1a2b3c4d5e6f7a8b/raw.csv?X-Amz-...",
2059
- },
2060
- expiresInMinutes: {
2061
- type: "integer",
2062
- description: "How long `url` stays valid.",
2063
- example: 15,
2064
- },
2065
- },
2089
+ name: {
2090
+ type: "string",
2091
+ description: "Unique name of the newly created dataset.",
2092
+ example: "My BTC ticks",
2093
+ },
2094
+ type: {
2095
+ type: "string",
2096
+ enum: ["ticker"],
2097
+ description: "Always `ticker` in v1.",
2098
+ example: "ticker",
2099
+ },
2100
+ instrument: {
2101
+ $ref: "#/components/schemas/Instrument",
2066
2102
  },
2067
2103
  },
2068
2104
  },
2105
+ {
2106
+ $ref: "#/components/schemas/DatasetUploadSession",
2107
+ },
2069
2108
  ],
2070
2109
  } as const;
2071
2110
 
@@ -81,6 +81,9 @@ import type {
81
81
  GetDatasetData,
82
82
  GetDatasetResponse,
83
83
  GetDatasetError,
84
+ OpenDatasetUploadData,
85
+ OpenDatasetUploadResponse,
86
+ OpenDatasetUploadError,
84
87
  FinalizeDatasetUploadData,
85
88
  FinalizeDatasetUploadResponse,
86
89
  FinalizeDatasetUploadError,
@@ -859,6 +862,10 @@ export const listDatasets = <ThrowOnError extends boolean = false>(
859
862
  * `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the upload completes to kick
860
863
  * off ingest.
861
864
  *
865
+ * Losing this response loses nothing: calling this dataset's
866
+ * `POST /datasets/{datasetId}/uploads` returns the very same upload session again rather than
867
+ * opening a new one, as long as nothing has been finalized against it yet.
868
+ *
862
869
  * v1 is ticker data only — `type` is not a request field, it is always `"ticker"` in the
863
870
  * response. `instrument` must be a plain spot pair (`BASE/QUOTE`, exactly one `/`); derivative
864
871
  * forms (e.g. `BTC/USDT:USDT`) are rejected.
@@ -942,14 +949,48 @@ export const getDataset = <ThrowOnError extends boolean = false>(
942
949
  });
943
950
  };
944
951
 
952
+ /**
953
+ * Open a new upload session for an existing dataset
954
+ * Get a fresh presigned URL to upload a new version into a dataset you already have — a
955
+ * corrected file, or the next chunk of history. Behaves the same way `POST /datasets` does
956
+ * for a brand-new dataset's own upload: at most one upload session is open per dataset at a
957
+ * time, so calling this again before finalizing just hands back that same session rather
958
+ * than opening a second one — safe to call repeatedly if a response gets lost.
959
+ *
960
+ * Once a session has been finalized (successfully or not), the next call here opens a
961
+ * genuinely new one for that dataset's next version.
962
+ *
963
+ */
964
+ export const openDatasetUpload = <ThrowOnError extends boolean = false>(
965
+ options: Options<OpenDatasetUploadData, ThrowOnError>
966
+ ) => {
967
+ return (options.client ?? _heyApiClient).post<
968
+ OpenDatasetUploadResponse,
969
+ OpenDatasetUploadError,
970
+ ThrowOnError
971
+ >({
972
+ security: [
973
+ {
974
+ scheme: "bearer",
975
+ type: "http",
976
+ },
977
+ ],
978
+ url: "/datasets/{datasetId}/uploads",
979
+ ...options,
980
+ });
981
+ };
982
+
945
983
  /**
946
984
  * Finalize an uploaded file and start ingest
947
- * Call once the file has been PUT to the `upload.url` from `POST /datasets`. Enqueues ingest
948
- * and returns immediately; poll
985
+ * Call once the file has been PUT to the `upload.url` from `POST /datasets` (or from
986
+ * `POST /datasets/{datasetId}/uploads`). Enqueues ingest and returns immediately; poll
949
987
  * `GET /datasets/{datasetId}/uploads/{uploadId}` for the result.
950
988
  *
951
- * Idempotent — a repeat finalize of the same upload returns the same `jobId` rather than
952
- * enqueueing a second ingest.
989
+ * Idempotent while the upload is still open — a repeat finalize before it has produced a
990
+ * version returns the same `jobId` rather than enqueueing a second ingest. Once it HAS
991
+ * produced a version, `uploadId` is spent: finalizing it again is a `409`, even with
992
+ * different bytes freshly PUT to the same URL — open a new upload session instead
993
+ * (`POST /datasets/{datasetId}/uploads`) rather than reusing a spent one.
953
994
  *
954
995
  */
955
996
  export const finalizeDatasetUpload = <ThrowOnError extends boolean = false>(
@@ -1205,30 +1205,60 @@ export type DatasetWithLinks = Dataset & {
1205
1205
  };
1206
1206
 
1207
1207
  /**
1208
- * A `Dataset` plus the first upload session — the presigned URL to PUT the file to.
1208
+ * A presigned destination for uploading a raw dataset file directly to storage.
1209
+ */
1210
+ export type DatasetUploadTarget = {
1211
+ /**
1212
+ * Presigned URL. `PUT` the raw CSV file here directly — no `Authorization` header,
1213
+ * no other API credentials.
1214
+ *
1215
+ */
1216
+ url: string;
1217
+ /**
1218
+ * How long `url` stays valid.
1219
+ */
1220
+ expiresInMinutes: number;
1221
+ };
1222
+
1223
+ /**
1224
+ * An upload session — an id plus the presigned URL to PUT the raw file to. Returned both by
1225
+ * `POST /datasets` (as part of the new dataset) and by `POST /datasets/{datasetId}/uploads`
1226
+ * (on its own, for an existing one).
1209
1227
  *
1210
1228
  */
1211
- export type DatasetCreated = Dataset & {
1229
+ export type DatasetUploadSession = {
1212
1230
  /**
1213
1231
  * Identifies this upload session. Pass to
1214
1232
  * `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the PUT completes.
1215
1233
  *
1216
1234
  */
1217
1235
  uploadId: string;
1218
- upload: {
1219
- /**
1220
- * Presigned URL. `PUT` the raw CSV file here directly — no `Authorization`
1221
- * header, no other API credentials.
1222
- *
1223
- */
1224
- url: string;
1225
- /**
1226
- * How long `url` stays valid.
1227
- */
1228
- expiresInMinutes: number;
1229
- };
1236
+ upload: DatasetUploadTarget;
1230
1237
  };
1231
1238
 
1239
+ /**
1240
+ * The metadata available immediately after creating a dataset, plus its first upload
1241
+ * session — the presigned URL to PUT the file to. Version-derived fields such as
1242
+ * `createdAt`, `currentVersionId`, range, and cadence are available from `GET /datasets/{datasetId}`
1243
+ * after the relevant lifecycle stages, not in this creation response.
1244
+ *
1245
+ */
1246
+ export type DatasetCreated = {
1247
+ /**
1248
+ * Opaque id of the newly created dataset.
1249
+ */
1250
+ datasetId: string;
1251
+ /**
1252
+ * Unique name of the newly created dataset.
1253
+ */
1254
+ name: string;
1255
+ /**
1256
+ * Always `ticker` in v1.
1257
+ */
1258
+ type: "ticker";
1259
+ instrument: Instrument;
1260
+ } & DatasetUploadSession;
1261
+
1232
1262
  /**
1233
1263
  * One successfully ingested upload. Cadence and timestamp unit are discovered from the file,
1234
1264
  * not declared by the caller.
@@ -2381,6 +2411,38 @@ export type GetDatasetResponses = {
2381
2411
 
2382
2412
  export type GetDatasetResponse = GetDatasetResponses[keyof GetDatasetResponses];
2383
2413
 
2414
+ export type OpenDatasetUploadData = {
2415
+ body?: never;
2416
+ path: {
2417
+ /**
2418
+ * The id returned by `POST /datasets`
2419
+ */
2420
+ datasetId: string;
2421
+ };
2422
+ query?: never;
2423
+ url: "/datasets/{datasetId}/uploads";
2424
+ };
2425
+
2426
+ export type OpenDatasetUploadErrors = {
2427
+ /**
2428
+ * No such dataset for this user
2429
+ */
2430
+ 404: ResponseError;
2431
+ };
2432
+
2433
+ export type OpenDatasetUploadError =
2434
+ OpenDatasetUploadErrors[keyof OpenDatasetUploadErrors];
2435
+
2436
+ export type OpenDatasetUploadResponses = {
2437
+ /**
2438
+ * An upload session — new, or the one already open for this dataset
2439
+ */
2440
+ 201: DatasetUploadSession;
2441
+ };
2442
+
2443
+ export type OpenDatasetUploadResponse =
2444
+ OpenDatasetUploadResponses[keyof OpenDatasetUploadResponses];
2445
+
2384
2446
  export type FinalizeDatasetUploadData = {
2385
2447
  body?: never;
2386
2448
  path: {
@@ -2399,11 +2461,18 @@ export type FinalizeDatasetUploadData = {
2399
2461
 
2400
2462
  export type FinalizeDatasetUploadErrors = {
2401
2463
  /**
2402
- * No such dataset for this user, or nothing was PUT to `upload.url` yet — a finalize with
2403
- * nothing to finalize.
2464
+ * No such dataset for this user; `uploadId` was not issued for this dataset (never
2465
+ * minted, or minted for a different one); or nothing was PUT to `upload.url` yet — a
2466
+ * finalize with nothing to finalize.
2404
2467
  *
2405
2468
  */
2406
2469
  404: ResponseError;
2470
+ /**
2471
+ * `uploadId` already produced a version. The error message names it. Open a new upload
2472
+ * session (`POST /datasets/{datasetId}/uploads`) for anything new.
2473
+ *
2474
+ */
2475
+ 409: ResponseError;
2407
2476
  /**
2408
2477
  * The uploaded file exceeds your tier's size limit for a dataset.
2409
2478
  */