@qtsurfer/api-client 0.10.0 → 0.12.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 +9 -2
- package/dist/index.d.ts +713 -24
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/generated/schemas.gen.ts +608 -32
- package/src/generated/sdk.gen.ts +242 -2
- package/src/generated/types.gen.ts +680 -21
|
@@ -180,8 +180,32 @@ export type Exchange = {
|
|
|
180
180
|
*/
|
|
181
181
|
export type DataSourceType = "ticker";
|
|
182
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Two shapes, chosen by the `exchangeId` path segment. Against a managed exchange,
|
|
185
|
+
* `instrument` is required and `datasetId`/`datasetVersionId` are ignored. Against the
|
|
186
|
+
* reserved `exchangeId: user`, send `datasetId` instead of `instrument` — `instrument` is
|
|
187
|
+
* ignored there, since it comes from the dataset itself.
|
|
188
|
+
*
|
|
189
|
+
*/
|
|
183
190
|
export type PrepareRequest = {
|
|
184
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Required unless `exchangeId` is the reserved value `user`, in which case send
|
|
193
|
+
* `datasetId` instead.
|
|
194
|
+
*
|
|
195
|
+
*/
|
|
196
|
+
instrument?: Instrument;
|
|
197
|
+
/**
|
|
198
|
+
* Only for `exchangeId: user`: the id of a dataset created via `POST /datasets`, in place
|
|
199
|
+
* of `instrument`. Ignored against a managed exchange.
|
|
200
|
+
*
|
|
201
|
+
*/
|
|
202
|
+
datasetId?: string;
|
|
203
|
+
/**
|
|
204
|
+
* Only for `exchangeId: user`, and optional even then: pins a specific past version of
|
|
205
|
+
* the dataset instead of its current one. Defaults to the dataset's current version.
|
|
206
|
+
*
|
|
207
|
+
*/
|
|
208
|
+
datasetVersionId?: string;
|
|
185
209
|
/**
|
|
186
210
|
* Start date for the preparation process. Supports the following formats:
|
|
187
211
|
* - ISO-8601 (e.g. 2024-12-14T23:59:59Z)
|
|
@@ -206,7 +230,22 @@ export type PrepareRequest = {
|
|
|
206
230
|
* labels return `400`.
|
|
207
231
|
*
|
|
208
232
|
*/
|
|
209
|
-
cadence?:
|
|
233
|
+
cadence?:
|
|
234
|
+
| "1s"
|
|
235
|
+
| "5s"
|
|
236
|
+
| "1m"
|
|
237
|
+
| "3m"
|
|
238
|
+
| "5m"
|
|
239
|
+
| "15m"
|
|
240
|
+
| "30m"
|
|
241
|
+
| "1h"
|
|
242
|
+
| "2h"
|
|
243
|
+
| "4h"
|
|
244
|
+
| "8h"
|
|
245
|
+
| "12h"
|
|
246
|
+
| "1d"
|
|
247
|
+
| "1w"
|
|
248
|
+
| "1q";
|
|
210
249
|
};
|
|
211
250
|
|
|
212
251
|
/**
|
|
@@ -248,12 +287,19 @@ export type JobState = {
|
|
|
248
287
|
};
|
|
249
288
|
|
|
250
289
|
/**
|
|
251
|
-
* State of a single-instrument prepare job — the `JobState` shape plus a
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
290
|
+
* State of a single-instrument prepare job — the `JobState` shape plus a coverage summary.
|
|
291
|
+
* A single-instrument prepare is always terminal (`status: Completed`): the client decides
|
|
292
|
+
* what to do from `coverageRatio` (e.g. execute if it is at or above a chosen threshold)
|
|
293
|
+
* rather than polling for missing hours that may never arrive — a missing hour for one
|
|
294
|
+
* instrument usually means low activity, not missing data.
|
|
295
|
+
*
|
|
296
|
+
* **Two coverage shapes, by exchange vs. dataset.** Against a managed exchange, coverage is
|
|
297
|
+
* walked hour by hour: `totalHours`/`hoursWithData`/`hoursWithoutData`. Against a
|
|
298
|
+
* dataset-backed prepare (`exchangeId: user`), coverage is reported on the dataset's own
|
|
299
|
+
* cadence grid instead — hour-walking a daily dataset would report `1/24` and read as
|
|
300
|
+
* broken — via `cadence`/`gaps`/`largestGapSteps`; `totalHours`/`hoursWithData`/
|
|
301
|
+
* `hoursWithoutData` are absent in that case. `dataFrom`/`dataTo`/`coverageRatio` are present
|
|
302
|
+
* either way, computed accordingly.
|
|
257
303
|
*
|
|
258
304
|
*/
|
|
259
305
|
export type PrepareJobState = JobState & {
|
|
@@ -266,21 +312,48 @@ export type PrepareJobState = JobState & {
|
|
|
266
312
|
*/
|
|
267
313
|
dataTo?: string | null;
|
|
268
314
|
/**
|
|
269
|
-
* `hoursWithData / totalHours` in `[0,1]` (`1.0` when
|
|
270
|
-
* fraction of hours in the requested range that have served
|
|
315
|
+
* Against a managed exchange: `hoursWithData / totalHours` in `[0,1]` (`1.0` when
|
|
316
|
+
* `totalHours` is 0), the fraction of hours in the requested range that have served
|
|
317
|
+
* data. Against a dataset (`exchangeId: user`): `rows / expectedStepsAtCadence`
|
|
318
|
+
* over the dataset version's own range — echoing what ingest computed once, not
|
|
319
|
+
* recomputed against a narrower prepare request.
|
|
271
320
|
*
|
|
272
321
|
*/
|
|
273
322
|
coverageRatio?: number;
|
|
274
323
|
/**
|
|
275
|
-
* Number of whole hours in the requested prepare range.
|
|
324
|
+
* Number of whole hours in the requested prepare range. Managed exchanges only —
|
|
325
|
+
* absent for a dataset-backed prepare.
|
|
326
|
+
*
|
|
276
327
|
*/
|
|
277
328
|
totalHours?: number;
|
|
278
329
|
/**
|
|
279
|
-
* Number of hours in the range that have data.
|
|
330
|
+
* Number of hours in the range that have data. Managed exchanges only — absent for
|
|
331
|
+
* a dataset-backed prepare.
|
|
332
|
+
*
|
|
280
333
|
*/
|
|
281
334
|
hoursWithData?: number;
|
|
282
335
|
/**
|
|
283
|
-
*
|
|
336
|
+
* The dataset version's own discovered cadence (e.g. `1m`, `1h`). Only present for a
|
|
337
|
+
* dataset-backed prepare (`exchangeId: user`).
|
|
338
|
+
*
|
|
339
|
+
*/
|
|
340
|
+
cadence?: string;
|
|
341
|
+
/**
|
|
342
|
+
* Number of gaps in the dataset version at its own cadence, as discovered at ingest
|
|
343
|
+
* time. Only present for a dataset-backed prepare.
|
|
344
|
+
*
|
|
345
|
+
*/
|
|
346
|
+
gaps?: number;
|
|
347
|
+
/**
|
|
348
|
+
* The largest gap in the dataset version, in units of its own cadence step. Only
|
|
349
|
+
* present for a dataset-backed prepare.
|
|
350
|
+
*
|
|
351
|
+
*/
|
|
352
|
+
largestGapSteps?: number;
|
|
353
|
+
/**
|
|
354
|
+
* One entry per hour in the range that has no data, with a rationale. Managed
|
|
355
|
+
* exchanges only — absent for a dataset-backed prepare.
|
|
356
|
+
*
|
|
284
357
|
*/
|
|
285
358
|
hoursWithoutData?: Array<{
|
|
286
359
|
/**
|
|
@@ -361,6 +434,43 @@ export type ExecuteSweepRequest = {
|
|
|
361
434
|
*/
|
|
362
435
|
minTradeFloor?: number;
|
|
363
436
|
walkForward?: WalkForwardRequest;
|
|
437
|
+
equityCurve?: EquityCurveRequest;
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Requested equity-curve transform, applied server-side in a fixed pipeline order: `resample` (point count) then `differential` (encoding) then `outMode` (JSON shape) — each stage assumes the previous one already ran. A server-side size guard can still force a smaller/deflated shape above its thresholds regardless of what is requested here — see `EquityCurveMeta` for what actually happened.
|
|
442
|
+
*/
|
|
443
|
+
export type EquityCurveOptions = {
|
|
444
|
+
/**
|
|
445
|
+
* Downsample to at most this many points (extrema-preserving — the global max/min and the exact first/last point are always kept). Omit for no downsampling.
|
|
446
|
+
*/
|
|
447
|
+
resample?: number;
|
|
448
|
+
/**
|
|
449
|
+
* Delta-encode both fields from the second (post-resample) point onward.
|
|
450
|
+
*/
|
|
451
|
+
differential?: boolean;
|
|
452
|
+
/**
|
|
453
|
+
* Requested JSON shape.
|
|
454
|
+
*/
|
|
455
|
+
outMode?: EquityCurveOutMode;
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Selection (`mode`/`n`/`maxPct`) plus the transform preference (`resample`/`differential`/`outMode`) applied by `GET .../equityCurve` whenever ITS OWN query params are absent, for a curve this sweep retained. The transform half never affects retention or `sweepId` — a caller can always override it per-request at read time regardless of what was submitted here.
|
|
460
|
+
*/
|
|
461
|
+
export type EquityCurveRequest = EquityCurveOptions & {
|
|
462
|
+
/**
|
|
463
|
+
* Which trials keep their per-point equity curve. `auto` retains curves only while the accumulated size stays within server limits; `topN`/`topPct` retain curves for the best-ranked trials explicitly; `none` retains no curves.
|
|
464
|
+
*/
|
|
465
|
+
mode?: "auto" | "topN" | "topPct" | "none";
|
|
466
|
+
/**
|
|
467
|
+
* Trial count to retain when mode is topN.
|
|
468
|
+
*/
|
|
469
|
+
n?: number;
|
|
470
|
+
/**
|
|
471
|
+
* Top percentage of trials to retain when mode is topPct.
|
|
472
|
+
*/
|
|
473
|
+
maxPct?: number;
|
|
364
474
|
};
|
|
365
475
|
|
|
366
476
|
/**
|
|
@@ -478,6 +588,10 @@ export type SweepRunRow = {
|
|
|
478
588
|
belowTradeFloor: boolean;
|
|
479
589
|
aborted: boolean;
|
|
480
590
|
runtimeMs: number;
|
|
591
|
+
/**
|
|
592
|
+
* Present only when this trial's curve was selected (`equityCurve.mode` was `topN`/`topPct` on the request, and this row ranked among the winners) — absent, not null, otherwise; a run that was never spilled and one that was spilled but not selected look identical here. Always a pointer today (`url` present, no inline points): a sweep's curves live in a spill store, not the response, until fetched separately. `GET` the `url` to fetch the curve itself; its own `meta` there is the real, possibly size-guarded outcome, while this outer `meta` is a raw, untransformed preview from selection time and can differ.
|
|
593
|
+
*/
|
|
594
|
+
equityCurve?: EquityCurveResult;
|
|
481
595
|
};
|
|
482
596
|
|
|
483
597
|
/**
|
|
@@ -543,6 +657,9 @@ export type SweepHeatmapCell = {
|
|
|
543
657
|
|
|
544
658
|
export type ExecuteSweepResult = {
|
|
545
659
|
sweepId: string;
|
|
660
|
+
/**
|
|
661
|
+
* The sweep's own status vocabulary — not the same set `state.status` below uses. See `state` for why.
|
|
662
|
+
*/
|
|
546
663
|
status: "RUNNING" | "COMPLETED" | "PARTIAL" | "CANCELLED";
|
|
547
664
|
objective: "sharpe" | "sortino" | "pnl" | "maxdd";
|
|
548
665
|
order: "ranked" | "natural";
|
|
@@ -574,6 +691,13 @@ export type ExecuteSweepResult = {
|
|
|
574
691
|
truncated: boolean;
|
|
575
692
|
leaderboard: Array<SweepRunRow>;
|
|
576
693
|
walkForward?: WalkForwardResult;
|
|
694
|
+
/**
|
|
695
|
+
* The same `JobState` shape a single-execute `BacktestJobResult` carries — not a sweep-specific lookalike, the actual type, so field names and timestamp formatting match exactly.
|
|
696
|
+
* `state.status` uses `JobState`'s own vocabulary (`New`/`Started`/`Completed`/ `Aborted`/`Failed`), mapped from the sweep's `status` field above rather than copying it: `PARTIAL` and `CANCELLED` both map to `Aborted`, because a sweep's `PARTIAL` is already terminal (some shards finished, some failed, nothing more is coming) unlike a single job's non-terminal `Partial`, which has no equivalent here at all.
|
|
697
|
+
* `state.completed` is real ticks processed on a plain sweep. On a `walkForward` sweep it is currently always `0` — the walk-forward fold runner was not wired to count ticks when this shipped, unlike the plain shard path.
|
|
698
|
+
* `state.size` is always `0` on every path (single execute, plain sweep, walk-forward alike) — nothing populates it anywhere yet. That is a known gap across the whole API, not a sweep-specific omission.
|
|
699
|
+
*/
|
|
700
|
+
state: JobState;
|
|
577
701
|
};
|
|
578
702
|
|
|
579
703
|
/**
|
|
@@ -739,9 +863,9 @@ export type ResultMap = {
|
|
|
739
863
|
*/
|
|
740
864
|
maxDrawdownPercent?: number;
|
|
741
865
|
/**
|
|
742
|
-
* Equity curve over the backtest.
|
|
866
|
+
* Equity curve over the backtest. `points[0]` (or `timestamps[0]`/`equities[0]` in `SHORT` mode) is an anchor at the backtest `from` with `initialCapital`; the remaining points are one sample per emitted yield, in order. Use it to plot the strategy's running equity without re-deriving it from the yield history. Always inline for a plain backtest today — never a pointer (`url`); that shape exists only for a sweep row's top-N winners.
|
|
743
867
|
*/
|
|
744
|
-
equityCurve?:
|
|
868
|
+
equityCurve?: EquityCurveResult;
|
|
745
869
|
/**
|
|
746
870
|
* Number of signals emitted during strategy execution
|
|
747
871
|
*/
|
|
@@ -782,6 +906,60 @@ export type EquityPoint = {
|
|
|
782
906
|
equity: number;
|
|
783
907
|
};
|
|
784
908
|
|
|
909
|
+
/**
|
|
910
|
+
* JSON shape for an equity curve's points. `ARRAY` is `[{timestamp, equity}, ...]`; `SHORT` is `{timestamps: [...], equities: [...]}` (parallel arrays, no repeated key text). The one schema shared by every place `outMode` appears, request or response, so the two cannot drift to different value sets.
|
|
911
|
+
*/
|
|
912
|
+
export type EquityCurveOutMode = "ARRAY" | "SHORT";
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* What the transform pipeline actually did, computed from the observed outcome — never a copy of what was requested. Lets a caller detect a forced or no-op transform (e.g. a `resample` ceiling already above the curve's size is a legal no-op, reported honestly as `resampled: false`).
|
|
916
|
+
*/
|
|
917
|
+
export type EquityCurveMeta = {
|
|
918
|
+
/**
|
|
919
|
+
* Size of the curve the transform pipeline received.
|
|
920
|
+
*/
|
|
921
|
+
inputPointCount: number;
|
|
922
|
+
/**
|
|
923
|
+
* Size after the full pipeline (resample, then differential, then outMode).
|
|
924
|
+
*/
|
|
925
|
+
outputPointCount: number;
|
|
926
|
+
/**
|
|
927
|
+
* True only if the resample stage actually changed the point count.
|
|
928
|
+
*/
|
|
929
|
+
resampled: boolean;
|
|
930
|
+
/**
|
|
931
|
+
* True only if delta-encoding actually ran. Requesting it on a curve of 0 or 1 points has nothing to encode, so it does not run even if asked.
|
|
932
|
+
*/
|
|
933
|
+
differential: boolean;
|
|
934
|
+
/**
|
|
935
|
+
* The actual JSON shape served. Present even when the points themselves are not (a pointer curve, `EquityCurveResult.url`) — a caller resolving that URL separately still needs to know how to parse what it gets back before fetching it. May override an explicit request above a server-side size threshold; this field, not the request, is the source of truth for what shape actually came back.
|
|
936
|
+
*/
|
|
937
|
+
outMode: EquityCurveOutMode;
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* An equity curve, shaped per `meta.outMode`: `points` when `ARRAY`, `timestamps` + `equities` (parallel arrays) when `SHORT`. Used identically wherever a curve is returned — a plain backtest's inline `equityCurve` and a sweep row's `equityCurve` are the same type. `url` is present *instead of* any points when the curve is served by pointer rather than inline (a sweep row's top-N winners only): `GET` it separately to fetch this exact same shape with the points populated.
|
|
942
|
+
*/
|
|
943
|
+
export type EquityCurveResult = {
|
|
944
|
+
meta: EquityCurveMeta;
|
|
945
|
+
/**
|
|
946
|
+
* Present when `meta.outMode` is `ARRAY` and the curve is inline (not a pointer).
|
|
947
|
+
*/
|
|
948
|
+
points?: Array<EquityPoint>;
|
|
949
|
+
/**
|
|
950
|
+
* Present when `meta.outMode` is `SHORT` and the curve is inline (not a pointer).
|
|
951
|
+
*/
|
|
952
|
+
timestamps?: Array<number>;
|
|
953
|
+
/**
|
|
954
|
+
* Present when `meta.outMode` is `SHORT` and the curve is inline (not a pointer), parallel to `timestamps` (same index, same point).
|
|
955
|
+
*/
|
|
956
|
+
equities?: Array<number>;
|
|
957
|
+
/**
|
|
958
|
+
* Present only for a sweep row's pointer curve. `GET` this to fetch the curve itself, in this exact `{points|timestamps+equities, meta}` shape — `meta` there is the real, possibly size-guarded outcome; this outer `meta` is a raw, untransformed preview from the moment the sweep selected this trial's curve, and the two can legitimately differ.
|
|
959
|
+
*/
|
|
960
|
+
url?: string;
|
|
961
|
+
};
|
|
962
|
+
|
|
785
963
|
/**
|
|
786
964
|
* Unique identifier for a compiled strategy, derived from the source itself: the same code
|
|
787
965
|
* always yields the same id, for every caller, whatever its formatting. See
|
|
@@ -790,6 +968,52 @@ export type EquityPoint = {
|
|
|
790
968
|
*/
|
|
791
969
|
export type StrategyId = string;
|
|
792
970
|
|
|
971
|
+
/**
|
|
972
|
+
* One property name `POST /strategy` could establish without constructing the strategy —
|
|
973
|
+
* either declared with `@StrategyProperty` on the compiled source, or one of the small set of
|
|
974
|
+
* base properties every strategy carries (`amnt`, `enabled`, `multiEntry`, ...).
|
|
975
|
+
*
|
|
976
|
+
* **Best-effort, not exhaustive.** A property registered through an attached risk/backtest
|
|
977
|
+
* config needs a live instance to discover and is not listed here. Use this to catch a typo'd
|
|
978
|
+
* sweep key before submitting, not as the definitive list of what a sweep will accept — a
|
|
979
|
+
* name absent from this list may still be valid.
|
|
980
|
+
*
|
|
981
|
+
*/
|
|
982
|
+
export type DeclaredProperty = {
|
|
983
|
+
/**
|
|
984
|
+
* The key a sweep or execute param map uses for this property.
|
|
985
|
+
*/
|
|
986
|
+
name: string;
|
|
987
|
+
/**
|
|
988
|
+
* Human-readable label, as declared.
|
|
989
|
+
*/
|
|
990
|
+
description?: string;
|
|
991
|
+
/**
|
|
992
|
+
* The declared default, as a string, if one was given. Absent, not null, when none was
|
|
993
|
+
* declared.
|
|
994
|
+
*
|
|
995
|
+
*/
|
|
996
|
+
defaultValue?: string;
|
|
997
|
+
/**
|
|
998
|
+
* Whether a value for this key is injected into the strategy's field (`true`) or only
|
|
999
|
+
* available through the property map (`false`).
|
|
1000
|
+
*
|
|
1001
|
+
*/
|
|
1002
|
+
reflected?: boolean;
|
|
1003
|
+
/**
|
|
1004
|
+
* Suggested sweep/range minimum, if declared. Advisory only, never validated.
|
|
1005
|
+
*/
|
|
1006
|
+
min?: number;
|
|
1007
|
+
/**
|
|
1008
|
+
* Suggested sweep/range maximum, if declared. Advisory only, never validated.
|
|
1009
|
+
*/
|
|
1010
|
+
max?: number;
|
|
1011
|
+
/**
|
|
1012
|
+
* Suggested sweep/range step, if declared. Advisory only, never validated.
|
|
1013
|
+
*/
|
|
1014
|
+
step?: number;
|
|
1015
|
+
};
|
|
1016
|
+
|
|
793
1017
|
/**
|
|
794
1018
|
* A diagnostic the engine raised while the strategy ran. Advisory: it describes something worth
|
|
795
1019
|
* knowing about how the strategy is wired, not necessarily an error.
|
|
@@ -912,6 +1136,165 @@ export type StrategyState = {
|
|
|
912
1136
|
_links?: StrategyLinks;
|
|
913
1137
|
};
|
|
914
1138
|
|
|
1139
|
+
/**
|
|
1140
|
+
* A dataset's own metadata — not its data. `currentVersionId` is what a prepare against
|
|
1141
|
+
* `exchangeId: user` reads by default; see `DatasetVersion` for what a version carries.
|
|
1142
|
+
*
|
|
1143
|
+
* `from`/`to`/`cadence` mirror that current version's own discovered range and cadence, so
|
|
1144
|
+
* you don't need a second call to `GET /datasets/{datasetId}/uploads/{uploadId}` just to see
|
|
1145
|
+
* what a dataset covers. Absent until a version exists.
|
|
1146
|
+
*
|
|
1147
|
+
*/
|
|
1148
|
+
export type Dataset = {
|
|
1149
|
+
/**
|
|
1150
|
+
* Opaque id, returned by `POST /datasets`.
|
|
1151
|
+
*/
|
|
1152
|
+
datasetId: string;
|
|
1153
|
+
/**
|
|
1154
|
+
* Unique among your datasets.
|
|
1155
|
+
*/
|
|
1156
|
+
name: string;
|
|
1157
|
+
/**
|
|
1158
|
+
* Always `ticker` in v1.
|
|
1159
|
+
*/
|
|
1160
|
+
type: "ticker";
|
|
1161
|
+
instrument: Instrument;
|
|
1162
|
+
/**
|
|
1163
|
+
* When the dataset was created.
|
|
1164
|
+
*/
|
|
1165
|
+
createdAt: string;
|
|
1166
|
+
/**
|
|
1167
|
+
* The id of the most recently finalized, successfully ingested version. Absent until at
|
|
1168
|
+
* least one upload has finished ingesting.
|
|
1169
|
+
*
|
|
1170
|
+
*/
|
|
1171
|
+
currentVersionId?: string;
|
|
1172
|
+
/**
|
|
1173
|
+
* When `currentVersionId` last changed. Absent until it has a value.
|
|
1174
|
+
*/
|
|
1175
|
+
updatedAt?: string;
|
|
1176
|
+
/**
|
|
1177
|
+
* Start of `currentVersionId`'s own data range, as discovered at ingest time. Absent
|
|
1178
|
+
* until a version exists.
|
|
1179
|
+
*
|
|
1180
|
+
*/
|
|
1181
|
+
from?: string;
|
|
1182
|
+
/**
|
|
1183
|
+
* End of `currentVersionId`'s own data range, as discovered at ingest time. Absent until
|
|
1184
|
+
* a version exists.
|
|
1185
|
+
*
|
|
1186
|
+
*/
|
|
1187
|
+
to?: string;
|
|
1188
|
+
/**
|
|
1189
|
+
* `currentVersionId`'s own discovered bar cadence (e.g. `1s`, `1m`, `1h`). Absent until a
|
|
1190
|
+
* version exists.
|
|
1191
|
+
*
|
|
1192
|
+
*/
|
|
1193
|
+
cadence?: string;
|
|
1194
|
+
};
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* A `Dataset` plus a self link. Returned by `GET /datasets/{datasetId}`.
|
|
1198
|
+
*/
|
|
1199
|
+
export type DatasetWithLinks = Dataset & {
|
|
1200
|
+
_links?: {
|
|
1201
|
+
self?: {
|
|
1202
|
+
href?: string;
|
|
1203
|
+
};
|
|
1204
|
+
};
|
|
1205
|
+
};
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* A `Dataset` plus the first upload session — the presigned URL to PUT the file to.
|
|
1209
|
+
*
|
|
1210
|
+
*/
|
|
1211
|
+
export type DatasetCreated = Dataset & {
|
|
1212
|
+
/**
|
|
1213
|
+
* Identifies this upload session. Pass to
|
|
1214
|
+
* `POST /datasets/{datasetId}/uploads/{uploadId}/finalize` once the PUT completes.
|
|
1215
|
+
*
|
|
1216
|
+
*/
|
|
1217
|
+
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
|
+
};
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* One successfully ingested upload. Cadence and timestamp unit are discovered from the file,
|
|
1234
|
+
* not declared by the caller.
|
|
1235
|
+
*
|
|
1236
|
+
*/
|
|
1237
|
+
export type DatasetVersion = {
|
|
1238
|
+
datasetId: string;
|
|
1239
|
+
/**
|
|
1240
|
+
* The version id. Pass as `datasetVersionId` on `POST .../prepare` to pin it.
|
|
1241
|
+
*/
|
|
1242
|
+
id?: string;
|
|
1243
|
+
/**
|
|
1244
|
+
* Size of the uploaded file.
|
|
1245
|
+
*/
|
|
1246
|
+
bytes?: number;
|
|
1247
|
+
/**
|
|
1248
|
+
* Number of data rows.
|
|
1249
|
+
*/
|
|
1250
|
+
rows?: number;
|
|
1251
|
+
/**
|
|
1252
|
+
* The discovered bar cadence (e.g. `1s`, `1m`, `1h`).
|
|
1253
|
+
*/
|
|
1254
|
+
cadence?: string;
|
|
1255
|
+
/**
|
|
1256
|
+
* The unit the `timestamp` column was uploaded in — ISO-8601, or the epoch band its
|
|
1257
|
+
* numeric values fell in (seconds, millis, or micros).
|
|
1258
|
+
*
|
|
1259
|
+
*/
|
|
1260
|
+
timestampUnit?: "iso" | "s" | "ms" | "us";
|
|
1261
|
+
/**
|
|
1262
|
+
* Number of gaps at the discovered cadence.
|
|
1263
|
+
*/
|
|
1264
|
+
gaps?: number;
|
|
1265
|
+
/**
|
|
1266
|
+
* The largest gap, in units of the discovered cadence step.
|
|
1267
|
+
*/
|
|
1268
|
+
largestGapSteps?: number;
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Progress of one upload, from staged through ingest. Postgres-backed once a version exists,
|
|
1273
|
+
* so `ready`/`failed` are permanent answers; `uploading`/`ingesting` reflect in-flight state
|
|
1274
|
+
* that can itself age out — see the `404` case on `GET .../uploads/{uploadId}`.
|
|
1275
|
+
*
|
|
1276
|
+
*/
|
|
1277
|
+
export type DatasetUploadState = {
|
|
1278
|
+
uploadId: string;
|
|
1279
|
+
/**
|
|
1280
|
+
* * `uploading` — the file was PUT to the presigned URL, but `finalize` has not been
|
|
1281
|
+
* called yet.
|
|
1282
|
+
* * `ingesting` — `finalize` was called; the worker is parsing and validating the file.
|
|
1283
|
+
* * `ready` — ingested successfully. `version` carries the result.
|
|
1284
|
+
* * `failed` — ingest rejected the file (e.g. bad CSV contract, mixed timestamp units).
|
|
1285
|
+
*
|
|
1286
|
+
*/
|
|
1287
|
+
status: "uploading" | "ingesting" | "ready" | "failed";
|
|
1288
|
+
/**
|
|
1289
|
+
* The ingest job id, while `status` is `ingesting`.
|
|
1290
|
+
*/
|
|
1291
|
+
jobId?: string;
|
|
1292
|
+
/**
|
|
1293
|
+
* Present when `status` is `ready` or `failed`.
|
|
1294
|
+
*/
|
|
1295
|
+
version?: DatasetVersion;
|
|
1296
|
+
};
|
|
1297
|
+
|
|
915
1298
|
export type AuthTokenResponse = {
|
|
916
1299
|
/**
|
|
917
1300
|
* Short-lived HS256 JWT. Send as `Authorization: Bearer <token>` on all other endpoints.
|
|
@@ -1246,6 +1629,12 @@ export type CompileStrategyResponses = {
|
|
|
1246
1629
|
*/
|
|
1247
1630
|
200: {
|
|
1248
1631
|
strategyId: StrategyId;
|
|
1632
|
+
/**
|
|
1633
|
+
* What could be established about this strategy's sweep-key vocabulary without
|
|
1634
|
+
* constructing it. See `DeclaredProperty` — best-effort, not exhaustive.
|
|
1635
|
+
*
|
|
1636
|
+
*/
|
|
1637
|
+
declaredProperties?: Array<DeclaredProperty>;
|
|
1249
1638
|
};
|
|
1250
1639
|
};
|
|
1251
1640
|
|
|
@@ -1407,7 +1796,9 @@ export type PrepareBacktestData = {
|
|
|
1407
1796
|
body: PrepareRequest;
|
|
1408
1797
|
path: {
|
|
1409
1798
|
/**
|
|
1410
|
-
* ID of the exchange to prepare the backtesting for
|
|
1799
|
+
* ID of the exchange to prepare the backtesting for (e.g. `binance`), or the reserved
|
|
1800
|
+
* value `user` to prepare from a dataset you uploaded instead of a managed exchange.
|
|
1801
|
+
*
|
|
1411
1802
|
*/
|
|
1412
1803
|
exchangeId: string;
|
|
1413
1804
|
/**
|
|
@@ -1422,17 +1813,23 @@ export type PrepareBacktestData = {
|
|
|
1422
1813
|
export type PrepareBacktestErrors = {
|
|
1423
1814
|
/**
|
|
1424
1815
|
* Invalid request or parameters. Also returned when `from` is older than the configured
|
|
1425
|
-
* lookback window or `to` is in the future.
|
|
1816
|
+
* lookback window or `to` is in the future. For `exchangeId: user`, also returned when
|
|
1817
|
+
* the dataset's current upload has not finished ingesting, or `cadence` asks for a finer
|
|
1818
|
+
* granularity than the dataset's own discovered cadence, or the requested range exceeds
|
|
1819
|
+
* your tier's range limit.
|
|
1426
1820
|
*
|
|
1427
1821
|
*/
|
|
1428
1822
|
400: ResponseError;
|
|
1429
1823
|
/**
|
|
1430
|
-
* Exchange or data source type not found
|
|
1824
|
+
* Exchange or data source type not found. For `exchangeId: user`, also returned when
|
|
1825
|
+
* `datasetId` (or a pinned `datasetVersionId`) doesn't exist or isn't yours.
|
|
1826
|
+
*
|
|
1431
1827
|
*/
|
|
1432
1828
|
404: ResponseError;
|
|
1433
1829
|
/**
|
|
1434
1830
|
* Rate limited. Returned when the global queue exceeds capacity or the user has too many
|
|
1435
|
-
* active backtests.
|
|
1831
|
+
* active backtests. Does not apply to `exchangeId: user` — a dataset prepare reads an
|
|
1832
|
+
* already-ingested file rather than enqueueing worker capacity.
|
|
1436
1833
|
*
|
|
1437
1834
|
*/
|
|
1438
1835
|
429: ResponseError;
|
|
@@ -1455,7 +1852,9 @@ export type GetPrepareStatusData = {
|
|
|
1455
1852
|
body?: never;
|
|
1456
1853
|
path: {
|
|
1457
1854
|
/**
|
|
1458
|
-
* ID of the exchange for the backtesting process
|
|
1855
|
+
* ID of the exchange for the backtesting process, or the reserved value `user` for a
|
|
1856
|
+
* dataset-backed prepare.
|
|
1857
|
+
*
|
|
1459
1858
|
*/
|
|
1460
1859
|
exchangeId: string;
|
|
1461
1860
|
/**
|
|
@@ -1649,6 +2048,55 @@ export type GetSweepSensitivityResponses = {
|
|
|
1649
2048
|
export type GetSweepSensitivityResponse =
|
|
1650
2049
|
GetSweepSensitivityResponses[keyof GetSweepSensitivityResponses];
|
|
1651
2050
|
|
|
2051
|
+
export type GetSweepRunEquityCurveData = {
|
|
2052
|
+
body?: never;
|
|
2053
|
+
path: {
|
|
2054
|
+
exchangeId: string;
|
|
2055
|
+
type: DataSourceType;
|
|
2056
|
+
requestId: string;
|
|
2057
|
+
sweepId: string;
|
|
2058
|
+
/**
|
|
2059
|
+
* The trial's `runIx`, as it appears on its leaderboard row.
|
|
2060
|
+
*/
|
|
2061
|
+
runIx: number;
|
|
2062
|
+
};
|
|
2063
|
+
query?: {
|
|
2064
|
+
/**
|
|
2065
|
+
* Requested JSON shape. Omit to use the sweep's submitted default; may be overridden either way by the server's size guard.
|
|
2066
|
+
*/
|
|
2067
|
+
outMode?: EquityCurveOutMode;
|
|
2068
|
+
/**
|
|
2069
|
+
* Downsample to at most this many points (extrema-preserving — the global max/min and the exact first/last point are always kept). Omit to use the sweep's submitted default (itself omittable, for no downsampling).
|
|
2070
|
+
*/
|
|
2071
|
+
resample?: number;
|
|
2072
|
+
/**
|
|
2073
|
+
* Delta-encode both fields from the second point onward. Omit to use the sweep's submitted default.
|
|
2074
|
+
*/
|
|
2075
|
+
differential?: boolean;
|
|
2076
|
+
};
|
|
2077
|
+
url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}/runs/{runIx}/equityCurve";
|
|
2078
|
+
};
|
|
2079
|
+
|
|
2080
|
+
export type GetSweepRunEquityCurveErrors = {
|
|
2081
|
+
/**
|
|
2082
|
+
* Sweep or `runIx` not found, or that trial's curve was never selected — indistinguishable from a caller's perspective.
|
|
2083
|
+
*/
|
|
2084
|
+
404: ResponseError;
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
export type GetSweepRunEquityCurveError =
|
|
2088
|
+
GetSweepRunEquityCurveErrors[keyof GetSweepRunEquityCurveErrors];
|
|
2089
|
+
|
|
2090
|
+
export type GetSweepRunEquityCurveResponses = {
|
|
2091
|
+
/**
|
|
2092
|
+
* The trial's equity curve, shaped per the resolved options.
|
|
2093
|
+
*/
|
|
2094
|
+
200: EquityCurveResult;
|
|
2095
|
+
};
|
|
2096
|
+
|
|
2097
|
+
export type GetSweepRunEquityCurveResponse =
|
|
2098
|
+
GetSweepRunEquityCurveResponses[keyof GetSweepRunEquityCurveResponses];
|
|
2099
|
+
|
|
1652
2100
|
export type ExecuteBacktestData = {
|
|
1653
2101
|
/**
|
|
1654
2102
|
* Execute task parameters
|
|
@@ -1665,10 +2113,13 @@ export type ExecuteBacktestData = {
|
|
|
1665
2113
|
*
|
|
1666
2114
|
*/
|
|
1667
2115
|
storeSignals?: boolean;
|
|
2116
|
+
equityCurve?: EquityCurveOptions;
|
|
1668
2117
|
};
|
|
1669
2118
|
path: {
|
|
1670
2119
|
/**
|
|
1671
|
-
* ID of the exchange for the backtesting process
|
|
2120
|
+
* ID of the exchange for the backtesting process, or the reserved value `user` if
|
|
2121
|
+
* `prepareJobId` came from a dataset-backed prepare.
|
|
2122
|
+
*
|
|
1672
2123
|
*/
|
|
1673
2124
|
exchangeId: string;
|
|
1674
2125
|
/**
|
|
@@ -1804,6 +2255,214 @@ export type GetBacktestResultResponses = {
|
|
|
1804
2255
|
export type GetBacktestResultResponse =
|
|
1805
2256
|
GetBacktestResultResponses[keyof GetBacktestResultResponses];
|
|
1806
2257
|
|
|
2258
|
+
export type ListDatasetsData = {
|
|
2259
|
+
body?: never;
|
|
2260
|
+
path?: never;
|
|
2261
|
+
query?: never;
|
|
2262
|
+
url: "/datasets";
|
|
2263
|
+
};
|
|
2264
|
+
|
|
2265
|
+
export type ListDatasetsResponses = {
|
|
2266
|
+
/**
|
|
2267
|
+
* Your datasets
|
|
2268
|
+
*/
|
|
2269
|
+
200: {
|
|
2270
|
+
datasets: Array<Dataset>;
|
|
2271
|
+
};
|
|
2272
|
+
};
|
|
2273
|
+
|
|
2274
|
+
export type ListDatasetsResponse =
|
|
2275
|
+
ListDatasetsResponses[keyof ListDatasetsResponses];
|
|
2276
|
+
|
|
2277
|
+
export type CreateDatasetData = {
|
|
2278
|
+
/**
|
|
2279
|
+
* The dataset to create
|
|
2280
|
+
*/
|
|
2281
|
+
body: {
|
|
2282
|
+
/**
|
|
2283
|
+
* A name unique among your datasets. `409` if already taken.
|
|
2284
|
+
*/
|
|
2285
|
+
name: string;
|
|
2286
|
+
instrument: Instrument;
|
|
2287
|
+
};
|
|
2288
|
+
path?: never;
|
|
2289
|
+
query?: never;
|
|
2290
|
+
url: "/datasets";
|
|
2291
|
+
};
|
|
2292
|
+
|
|
2293
|
+
export type CreateDatasetErrors = {
|
|
2294
|
+
/**
|
|
2295
|
+
* Invalid request, or `instrument` is not a plain spot pair
|
|
2296
|
+
*/
|
|
2297
|
+
400: ResponseError;
|
|
2298
|
+
/**
|
|
2299
|
+
* You already have a dataset with this `name`
|
|
2300
|
+
*/
|
|
2301
|
+
409: ResponseError;
|
|
2302
|
+
/**
|
|
2303
|
+
* Your tier's dataset count limit is reached. Delete one, or upgrade.
|
|
2304
|
+
*/
|
|
2305
|
+
429: ResponseError;
|
|
2306
|
+
};
|
|
2307
|
+
|
|
2308
|
+
export type CreateDatasetError = CreateDatasetErrors[keyof CreateDatasetErrors];
|
|
2309
|
+
|
|
2310
|
+
export type CreateDatasetResponses = {
|
|
2311
|
+
/**
|
|
2312
|
+
* Dataset created, with an upload session ready for its first version
|
|
2313
|
+
*/
|
|
2314
|
+
201: DatasetCreated;
|
|
2315
|
+
};
|
|
2316
|
+
|
|
2317
|
+
export type CreateDatasetResponse =
|
|
2318
|
+
CreateDatasetResponses[keyof CreateDatasetResponses];
|
|
2319
|
+
|
|
2320
|
+
export type DeleteDatasetData = {
|
|
2321
|
+
body?: never;
|
|
2322
|
+
path: {
|
|
2323
|
+
/**
|
|
2324
|
+
* The id returned by `POST /datasets`
|
|
2325
|
+
*/
|
|
2326
|
+
datasetId: string;
|
|
2327
|
+
};
|
|
2328
|
+
query?: never;
|
|
2329
|
+
url: "/datasets/{datasetId}";
|
|
2330
|
+
};
|
|
2331
|
+
|
|
2332
|
+
export type DeleteDatasetErrors = {
|
|
2333
|
+
/**
|
|
2334
|
+
* No such dataset for this user, or already deleted
|
|
2335
|
+
*/
|
|
2336
|
+
404: ResponseError;
|
|
2337
|
+
};
|
|
2338
|
+
|
|
2339
|
+
export type DeleteDatasetError = DeleteDatasetErrors[keyof DeleteDatasetErrors];
|
|
2340
|
+
|
|
2341
|
+
export type DeleteDatasetResponses = {
|
|
2342
|
+
/**
|
|
2343
|
+
* Deleted
|
|
2344
|
+
*/
|
|
2345
|
+
200: {
|
|
2346
|
+
datasetId: string;
|
|
2347
|
+
deleted: true;
|
|
2348
|
+
};
|
|
2349
|
+
};
|
|
2350
|
+
|
|
2351
|
+
export type DeleteDatasetResponse =
|
|
2352
|
+
DeleteDatasetResponses[keyof DeleteDatasetResponses];
|
|
2353
|
+
|
|
2354
|
+
export type GetDatasetData = {
|
|
2355
|
+
body?: never;
|
|
2356
|
+
path: {
|
|
2357
|
+
/**
|
|
2358
|
+
* The id returned by `POST /datasets`
|
|
2359
|
+
*/
|
|
2360
|
+
datasetId: string;
|
|
2361
|
+
};
|
|
2362
|
+
query?: never;
|
|
2363
|
+
url: "/datasets/{datasetId}";
|
|
2364
|
+
};
|
|
2365
|
+
|
|
2366
|
+
export type GetDatasetErrors = {
|
|
2367
|
+
/**
|
|
2368
|
+
* No such dataset for this user
|
|
2369
|
+
*/
|
|
2370
|
+
404: ResponseError;
|
|
2371
|
+
};
|
|
2372
|
+
|
|
2373
|
+
export type GetDatasetError = GetDatasetErrors[keyof GetDatasetErrors];
|
|
2374
|
+
|
|
2375
|
+
export type GetDatasetResponses = {
|
|
2376
|
+
/**
|
|
2377
|
+
* Dataset detail
|
|
2378
|
+
*/
|
|
2379
|
+
200: DatasetWithLinks;
|
|
2380
|
+
};
|
|
2381
|
+
|
|
2382
|
+
export type GetDatasetResponse = GetDatasetResponses[keyof GetDatasetResponses];
|
|
2383
|
+
|
|
2384
|
+
export type FinalizeDatasetUploadData = {
|
|
2385
|
+
body?: never;
|
|
2386
|
+
path: {
|
|
2387
|
+
/**
|
|
2388
|
+
* The id returned by `POST /datasets`
|
|
2389
|
+
*/
|
|
2390
|
+
datasetId: string;
|
|
2391
|
+
/**
|
|
2392
|
+
* The `uploadId` returned by `POST /datasets`
|
|
2393
|
+
*/
|
|
2394
|
+
uploadId: string;
|
|
2395
|
+
};
|
|
2396
|
+
query?: never;
|
|
2397
|
+
url: "/datasets/{datasetId}/uploads/{uploadId}/finalize";
|
|
2398
|
+
};
|
|
2399
|
+
|
|
2400
|
+
export type FinalizeDatasetUploadErrors = {
|
|
2401
|
+
/**
|
|
2402
|
+
* No such dataset for this user, or nothing was PUT to `upload.url` yet — a finalize with
|
|
2403
|
+
* nothing to finalize.
|
|
2404
|
+
*
|
|
2405
|
+
*/
|
|
2406
|
+
404: ResponseError;
|
|
2407
|
+
/**
|
|
2408
|
+
* The uploaded file exceeds your tier's size limit for a dataset.
|
|
2409
|
+
*/
|
|
2410
|
+
413: ResponseError;
|
|
2411
|
+
};
|
|
2412
|
+
|
|
2413
|
+
export type FinalizeDatasetUploadError =
|
|
2414
|
+
FinalizeDatasetUploadErrors[keyof FinalizeDatasetUploadErrors];
|
|
2415
|
+
|
|
2416
|
+
export type FinalizeDatasetUploadResponses = {
|
|
2417
|
+
/**
|
|
2418
|
+
* Ingest queued
|
|
2419
|
+
*/
|
|
2420
|
+
202: {
|
|
2421
|
+
jobId: string;
|
|
2422
|
+
};
|
|
2423
|
+
};
|
|
2424
|
+
|
|
2425
|
+
export type FinalizeDatasetUploadResponse =
|
|
2426
|
+
FinalizeDatasetUploadResponses[keyof FinalizeDatasetUploadResponses];
|
|
2427
|
+
|
|
2428
|
+
export type GetDatasetUploadData = {
|
|
2429
|
+
body?: never;
|
|
2430
|
+
path: {
|
|
2431
|
+
/**
|
|
2432
|
+
* The id returned by `POST /datasets`
|
|
2433
|
+
*/
|
|
2434
|
+
datasetId: string;
|
|
2435
|
+
/**
|
|
2436
|
+
* The `uploadId` returned by `POST /datasets`
|
|
2437
|
+
*/
|
|
2438
|
+
uploadId: string;
|
|
2439
|
+
};
|
|
2440
|
+
query?: never;
|
|
2441
|
+
url: "/datasets/{datasetId}/uploads/{uploadId}";
|
|
2442
|
+
};
|
|
2443
|
+
|
|
2444
|
+
export type GetDatasetUploadErrors = {
|
|
2445
|
+
/**
|
|
2446
|
+
* No such dataset for this user, or genuinely nothing is known about this `uploadId` — no
|
|
2447
|
+
* version, no in-flight job, and nothing was ever PUT to its upload URL.
|
|
2448
|
+
*
|
|
2449
|
+
*/
|
|
2450
|
+
404: ResponseError;
|
|
2451
|
+
};
|
|
2452
|
+
|
|
2453
|
+
export type GetDatasetUploadError =
|
|
2454
|
+
GetDatasetUploadErrors[keyof GetDatasetUploadErrors];
|
|
2455
|
+
|
|
2456
|
+
export type GetDatasetUploadResponses = {
|
|
2457
|
+
/**
|
|
2458
|
+
* Current upload/ingest state
|
|
2459
|
+
*/
|
|
2460
|
+
200: DatasetUploadState;
|
|
2461
|
+
};
|
|
2462
|
+
|
|
2463
|
+
export type GetDatasetUploadResponse =
|
|
2464
|
+
GetDatasetUploadResponses[keyof GetDatasetUploadResponses];
|
|
2465
|
+
|
|
1807
2466
|
export type ClientOptions = {
|
|
1808
2467
|
baseUrl:
|
|
1809
2468
|
| "https://api.qtsurfer.net/v1"
|