@qtsurfer/api-client 0.7.0 → 0.9.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 +22 -11
- package/dist/index.d.ts +348 -49
- package/dist/index.js +22 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/generated/client.gen.ts +16 -6
- package/src/generated/index.ts +2 -2
- package/src/generated/schemas.gen.ts +1396 -982
- package/src/generated/sdk.gen.ts +433 -190
- package/src/generated/types.gen.ts +1303 -1016
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
* General response error
|
|
5
5
|
*/
|
|
6
6
|
export type ResponseError = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Status code
|
|
9
|
+
*/
|
|
10
|
+
code: number;
|
|
11
|
+
/**
|
|
12
|
+
* Error description
|
|
13
|
+
*/
|
|
14
|
+
message: string;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -23,211 +23,211 @@ export type Instrument = string;
|
|
|
23
23
|
* HAL-style response envelope for the instruments listing
|
|
24
24
|
*/
|
|
25
25
|
export type InstrumentListResponse = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The list of instruments for the segment
|
|
28
|
+
*/
|
|
29
|
+
data: Array<InstrumentDetail>;
|
|
30
|
+
meta: InstrumentListMeta;
|
|
31
|
+
_links: InstrumentLinks;
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Metadata describing the instruments listing
|
|
36
36
|
*/
|
|
37
37
|
export type InstrumentListMeta = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
/**
|
|
39
|
+
* When this listing was last refreshed
|
|
40
|
+
*/
|
|
41
|
+
updatedAt: string;
|
|
42
|
+
/**
|
|
43
|
+
* The exchange the instruments belong to
|
|
44
|
+
*/
|
|
45
|
+
exchange: string;
|
|
46
|
+
/**
|
|
47
|
+
* The market segment served in `data`
|
|
48
|
+
*/
|
|
49
|
+
segment: "spot" | "futures";
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* HAL `_links` — segment discovery for the instruments listing
|
|
54
54
|
*/
|
|
55
55
|
export type InstrumentLinks = {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Link to this listing
|
|
58
|
+
*/
|
|
59
|
+
self: HalLink;
|
|
60
|
+
/**
|
|
61
|
+
* Link to the spot instruments listing. Present when the exchange has a spot segment.
|
|
62
|
+
*/
|
|
63
|
+
spot?: HalLink;
|
|
64
|
+
/**
|
|
65
|
+
* Link to the futures instruments listing. Present only when the exchange has a futures segment.
|
|
66
|
+
*/
|
|
67
|
+
futures?: HalLink;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* A HAL link object (Hypertext Application Language)
|
|
72
72
|
*/
|
|
73
73
|
export type HalLink = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
/**
|
|
75
|
+
* The link target as an absolute-path URI reference (resolve against the API base). A URI Template (RFC 6570) when `templated` is true.
|
|
76
|
+
*/
|
|
77
|
+
href: string;
|
|
78
|
+
/**
|
|
79
|
+
* True when `href` is an RFC 6570 URI Template.
|
|
80
|
+
*/
|
|
81
|
+
templated?: boolean;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Exchange instrument with per-data-type coverage and market info
|
|
86
86
|
*/
|
|
87
87
|
export type InstrumentDetail = {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Instrument identifier (e.g. currency pair)
|
|
90
|
+
*/
|
|
91
|
+
id: string;
|
|
92
|
+
/**
|
|
93
|
+
* Base currency
|
|
94
|
+
*/
|
|
95
|
+
base: string;
|
|
96
|
+
/**
|
|
97
|
+
* Quote currency
|
|
98
|
+
*/
|
|
99
|
+
quote: string;
|
|
100
|
+
coverage?: InstrumentCoverage;
|
|
101
|
+
/**
|
|
102
|
+
* Last traded price
|
|
103
|
+
*/
|
|
104
|
+
lastPrice?: number;
|
|
105
|
+
/**
|
|
106
|
+
* Trading volume in the last 24 hours (in quote currency)
|
|
107
|
+
*/
|
|
108
|
+
volume24h?: number;
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
112
|
* Time coverage of available data for this instrument, per data type
|
|
113
113
|
*/
|
|
114
114
|
export type InstrumentCoverage = {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Coverage of ticker data
|
|
117
|
+
*/
|
|
118
|
+
tickers?: CoverageWindow;
|
|
119
|
+
/**
|
|
120
|
+
* Coverage of kline (candlestick) data
|
|
121
|
+
*/
|
|
122
|
+
klines?: CoverageWindow;
|
|
123
123
|
};
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
126
|
* The time range of available data for a single data type
|
|
127
127
|
*/
|
|
128
128
|
export type CoverageWindow = {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Earliest timestamp with data available
|
|
131
|
+
*/
|
|
132
|
+
from?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Latest timestamp with data available
|
|
135
|
+
*/
|
|
136
|
+
to?: string;
|
|
137
|
+
/**
|
|
138
|
+
* If the instrument stopped producing this data type (delisted/inactive), the timestamp it went inactive. Optional — omitted while the instrument is active.
|
|
139
|
+
*/
|
|
140
|
+
inactiveSince?: string;
|
|
141
141
|
};
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
144
|
* Exchange service provider
|
|
145
145
|
*/
|
|
146
146
|
export type Exchange = {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Unique identifier for the exchange
|
|
149
|
+
*/
|
|
150
|
+
id: string;
|
|
151
|
+
/**
|
|
152
|
+
* Name of the exchange
|
|
153
|
+
*/
|
|
154
|
+
name: string;
|
|
155
|
+
/**
|
|
156
|
+
* Description of the exchange
|
|
157
|
+
*/
|
|
158
|
+
description?: string;
|
|
159
159
|
};
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
162
|
* Managed exchange data sources available for backtesting.
|
|
163
163
|
*/
|
|
164
|
-
export type DataSourceType =
|
|
164
|
+
export type DataSourceType = "ticker";
|
|
165
165
|
|
|
166
166
|
export type PrepareRequest = {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
167
|
+
instrument: Instrument;
|
|
168
|
+
/**
|
|
169
|
+
* Start date for the preparation process. Supports the following formats:
|
|
170
|
+
* - ISO-8601 (e.g. 2024-12-14T23:59:59Z)
|
|
171
|
+
* - ISO DATE (e.g. 2024-12-14)
|
|
172
|
+
* - BASIC ISO DATE (e.g., 20241214)
|
|
173
|
+
*
|
|
174
|
+
*/
|
|
175
|
+
from: string;
|
|
176
|
+
/**
|
|
177
|
+
* End date for the preparation process. Supports the following formats:
|
|
178
|
+
* - ISO-8601 (e.g. 2024-12-14T23:59:59Z)
|
|
179
|
+
* - ISO DATE (e.g. 2024-12-14)
|
|
180
|
+
* - BASIC ISO DATE (e.g., 20241214)
|
|
181
|
+
*
|
|
182
|
+
*/
|
|
183
|
+
to: string;
|
|
184
|
+
/**
|
|
185
|
+
* Output bar cadence for the prepared range. Defaults to the publisher's
|
|
186
|
+
* native cadence (`1s`); coarser cadences are produced on demand via
|
|
187
|
+
* resampling and stored alongside the native blob in cache. Coarser-than-
|
|
188
|
+
* source values must be exact multiples of the source cadence — invalid
|
|
189
|
+
* labels return `400`.
|
|
190
|
+
*
|
|
191
|
+
*/
|
|
192
|
+
cadence?: "1s" | "5s" | "1m" | "5m" | "15m" | "1h" | "4h" | "1d";
|
|
193
193
|
};
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* Information about a single job
|
|
197
197
|
*/
|
|
198
198
|
export type JobState = {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Opaque context identifier for the job
|
|
201
|
+
*/
|
|
202
|
+
contextId: string;
|
|
203
|
+
/**
|
|
204
|
+
* Current status of the job. Treat `Completed | Aborted | Failed` as
|
|
205
|
+
* terminal; `New | Started` mean keep polling. A single-instrument prepare
|
|
206
|
+
* is always terminal (`Completed`) — decide from
|
|
207
|
+
* `PrepareJobState.coverageRatio`, not by polling.
|
|
208
|
+
*
|
|
209
|
+
*/
|
|
210
|
+
status: "New" | "Started" | "Completed" | "Aborted" | "Failed";
|
|
211
|
+
/**
|
|
212
|
+
* Detailed status information, if available
|
|
213
|
+
*/
|
|
214
|
+
statusDetail?: string | null;
|
|
215
|
+
/**
|
|
216
|
+
* Total size of the data being prepared
|
|
217
|
+
*/
|
|
218
|
+
size: number;
|
|
219
|
+
/**
|
|
220
|
+
* The amount of data processed so far
|
|
221
|
+
*/
|
|
222
|
+
completed: number;
|
|
223
|
+
/**
|
|
224
|
+
* Timestamp for when the preparation started
|
|
225
|
+
*/
|
|
226
|
+
startTime?: string | null;
|
|
227
|
+
/**
|
|
228
|
+
* Timestamp for when the preparation finished
|
|
229
|
+
*/
|
|
230
|
+
endTime?: string | null;
|
|
231
231
|
};
|
|
232
232
|
|
|
233
233
|
/**
|
|
@@ -240,175 +240,386 @@ export type JobState = {
|
|
|
240
240
|
*
|
|
241
241
|
*/
|
|
242
242
|
export type PrepareJobState = JobState & {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
243
|
+
/**
|
|
244
|
+
* Start of the available data range for the prepared instrument.
|
|
245
|
+
*/
|
|
246
|
+
dataFrom?: string | null;
|
|
247
|
+
/**
|
|
248
|
+
* End of the available data range for the prepared instrument.
|
|
249
|
+
*/
|
|
250
|
+
dataTo?: string | null;
|
|
251
|
+
/**
|
|
252
|
+
* `hoursWithData / totalHours` in `[0,1]` (`1.0` when `totalHours` is 0) — the
|
|
253
|
+
* fraction of hours in the requested range that have served data.
|
|
254
|
+
*
|
|
255
|
+
*/
|
|
256
|
+
coverageRatio?: number;
|
|
257
|
+
/**
|
|
258
|
+
* Number of whole hours in the requested prepare range.
|
|
259
|
+
*/
|
|
260
|
+
totalHours?: number;
|
|
261
|
+
/**
|
|
262
|
+
* Number of hours in the range that have data.
|
|
263
|
+
*/
|
|
264
|
+
hoursWithData?: number;
|
|
265
|
+
/**
|
|
266
|
+
* One entry per hour in the range that has no data, with a rationale.
|
|
267
|
+
*/
|
|
268
|
+
hoursWithoutData?: Array<{
|
|
269
|
+
/**
|
|
270
|
+
* The hour (UTC, hour-aligned) that has no data.
|
|
271
|
+
*/
|
|
272
|
+
hour?: string;
|
|
273
|
+
/**
|
|
274
|
+
* Expected row count for the hour (currently always 0; reserved for
|
|
275
|
+
* future use). The rationale never depends on it.
|
|
254
276
|
*
|
|
255
277
|
*/
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Number of whole hours in the requested prepare range.
|
|
259
|
-
*/
|
|
260
|
-
totalHours?: number;
|
|
261
|
-
/**
|
|
262
|
-
* Number of hours in the range that have data.
|
|
263
|
-
*/
|
|
264
|
-
hoursWithData?: number;
|
|
278
|
+
expected?: number;
|
|
265
279
|
/**
|
|
266
|
-
*
|
|
280
|
+
* Why the hour has no data. `pending_conversion`: data for this hour is
|
|
281
|
+
* still being produced — a re-poll may fill it. `low_activity`: the
|
|
282
|
+
* instrument did not trade that hour. `unknown`: no data to classify by.
|
|
283
|
+
*
|
|
267
284
|
*/
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
* The hour (UTC, hour-aligned) that has no data.
|
|
271
|
-
*/
|
|
272
|
-
hour?: string;
|
|
273
|
-
/**
|
|
274
|
-
* Expected row count for the hour (currently always 0; reserved for
|
|
275
|
-
* future use). The rationale never depends on it.
|
|
276
|
-
*
|
|
277
|
-
*/
|
|
278
|
-
expected?: number;
|
|
279
|
-
/**
|
|
280
|
-
* Why the hour has no data. `pending_conversion`: data for this hour is
|
|
281
|
-
* still being produced — a re-poll may fill it. `low_activity`: the
|
|
282
|
-
* instrument did not trade that hour. `unknown`: no data to classify by.
|
|
283
|
-
*
|
|
284
|
-
*/
|
|
285
|
-
rationale?: 'pending_conversion' | 'low_activity' | 'unknown';
|
|
286
|
-
}>;
|
|
285
|
+
rationale?: "pending_conversion" | "low_activity" | "unknown";
|
|
286
|
+
}>;
|
|
287
287
|
};
|
|
288
288
|
|
|
289
289
|
/**
|
|
290
290
|
* A numeric range or an explicit list of values for one strategy property.
|
|
291
291
|
*/
|
|
292
|
-
export type SweepAxis =
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
292
|
+
export type SweepAxis =
|
|
293
|
+
| {
|
|
294
|
+
from: number;
|
|
295
|
+
to: number;
|
|
296
|
+
step: number;
|
|
297
|
+
}
|
|
298
|
+
| {
|
|
299
|
+
values: Array<number | boolean>;
|
|
300
|
+
};
|
|
299
301
|
|
|
300
302
|
export type SweepSpecRequest = {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
303
|
+
sampler?: "grid" | "random" | "lhs";
|
|
304
|
+
/**
|
|
305
|
+
* Reproducibility seed. If omitted, the server generates one with Java's
|
|
306
|
+
* `L64X128MixRandom` generator and returns the effective value. The range
|
|
307
|
+
* is limited to JavaScript-safe integers so generated clients can replay it exactly.
|
|
308
|
+
*
|
|
309
|
+
*/
|
|
310
|
+
seed?: number;
|
|
311
|
+
/**
|
|
312
|
+
* Number of samples for `random` and `lhs`; ignored by `grid`.
|
|
313
|
+
*/
|
|
314
|
+
samples?: number;
|
|
315
|
+
objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
|
|
316
|
+
params: {
|
|
317
|
+
[key: string]: SweepAxis;
|
|
318
|
+
};
|
|
317
319
|
};
|
|
318
320
|
|
|
319
321
|
export type SweepBaseConfig = {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
322
|
+
initialFunding?: number;
|
|
323
|
+
feeRate?: number;
|
|
324
|
+
buyFeeRate?: number;
|
|
325
|
+
sellFeeRate?: number;
|
|
326
|
+
feeLeg?: "RECEIVED" | "QUOTE" | "BASE";
|
|
327
|
+
percentAmountToLock?: number;
|
|
326
328
|
};
|
|
327
329
|
|
|
328
330
|
export type ExecuteSweepRequest = {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
331
|
+
strategyId: StrategyId;
|
|
332
|
+
sweep: SweepSpecRequest;
|
|
333
|
+
baseConfig?: SweepBaseConfig;
|
|
334
|
+
/**
|
|
335
|
+
* Store signals for every trial. Keep false for normal sweeps.
|
|
336
|
+
*/
|
|
337
|
+
storeSignals?: boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Requested horizontal shard count; 0 or omitted selects automatically.
|
|
340
|
+
*/
|
|
341
|
+
shards?: number;
|
|
342
|
+
/**
|
|
343
|
+
* Trials below this trade count are flagged but remain in the results.
|
|
344
|
+
*/
|
|
345
|
+
minTradeFloor?: number;
|
|
346
|
+
walkForward?: WalkForwardRequest;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Opt in to walk-forward validation. Present, the sweep runs as F sequential folds and the result gains a `walkForward` section; absent, nothing about the sweep changes. Two requests that differ only in this block are two different sweeps and do not deduplicate against each other.
|
|
351
|
+
*/
|
|
352
|
+
export type WalkForwardRequest = {
|
|
353
|
+
/**
|
|
354
|
+
* How many sequential optimize-then-score windows to run. Two is the minimum for a reason, and it is structural rather than a tuning choice: parameter drift is measured between consecutive fold winners, and a single fold — one train/test split with no sequence — has no consecutive pair to compare, so it would report the strongest possible stability having measured nothing.
|
|
355
|
+
* The upper bound is a server setting (12 by default) and is deliberately not pinned here, since a spec that hardcodes a tunable limit lies the day it is raised. Exceeding it, or exceeding the sweep budget once multiplied by the grid size, is a 400.
|
|
356
|
+
*/
|
|
357
|
+
folds: number;
|
|
358
|
+
/**
|
|
359
|
+
* Share of the session each fold spends optimizing; the remainder is where its winner is scored. Lower values leave more data to be scored on and, on short sessions, are also what lets the requested fold count tile the data at all.
|
|
360
|
+
*/
|
|
361
|
+
inSamplePct?: number;
|
|
344
362
|
};
|
|
345
363
|
|
|
346
364
|
export type ExecuteSweepAccepted = {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
365
|
+
sweepId: string;
|
|
366
|
+
requestId: string;
|
|
367
|
+
totalRuns: number;
|
|
368
|
+
shards: number;
|
|
369
|
+
/**
|
|
370
|
+
* Effective seed used to expand the sweep.
|
|
371
|
+
*/
|
|
372
|
+
seed: number;
|
|
373
|
+
/**
|
|
374
|
+
* False when an identical sweep already exists and was not enqueued again.
|
|
375
|
+
*/
|
|
376
|
+
queued: boolean;
|
|
377
|
+
walkForward?: WalkForwardAccepted;
|
|
359
378
|
};
|
|
360
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Echo of the accepted walk-forward configuration, present only when the submit carried one. `inSamplePct` is the resolved value, so a request that omitted it can see what it got.
|
|
382
|
+
*/
|
|
383
|
+
export type WalkForwardAccepted = {
|
|
384
|
+
folds: number;
|
|
385
|
+
inSamplePct: number;
|
|
386
|
+
/**
|
|
387
|
+
* What this sweep actually costs, `folds × (grid size + 1)` — the in-sample runs for every fold plus each fold's one out-of-sample run. Deliberately distinct from the top-level `totalRuns`, which stays the size of the grid that was submitted.
|
|
388
|
+
*/
|
|
389
|
+
totalRuns: number;
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* How far along a sweep is, and — when the sweep is still running — enough to tell a healthy one from a stuck one. The counts partition the shards (or, for a walk-forward sweep, the folds): every unit is either finished, failed, waiting to be retried, or not yet started.
|
|
394
|
+
*/
|
|
361
395
|
export type SweepProgress = {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
396
|
+
done: number;
|
|
397
|
+
total: number;
|
|
398
|
+
/**
|
|
399
|
+
* Individual runs that executed and aborted. A row-level count: a shard that fails before producing any rows leaves this at 0, which is why `failedShards` exists alongside it.
|
|
400
|
+
*/
|
|
401
|
+
aborted: number;
|
|
402
|
+
shardCount: number;
|
|
403
|
+
pendingShards: number;
|
|
404
|
+
/**
|
|
405
|
+
* Shards (or folds) that failed and will not be retried. Distinct from `aborted`: this counts whole units that never reported, not runs that ran badly.
|
|
406
|
+
*/
|
|
407
|
+
failedShards: number;
|
|
408
|
+
/**
|
|
409
|
+
* Units whose last attempt failed on something transient — an I/O error, a worker that died mid-read — and which are queued to be attempted again. Not counted as failures, because they have not failed yet; a sweep with a non-zero value here is still expected to complete.
|
|
410
|
+
*/
|
|
411
|
+
retrying: number;
|
|
412
|
+
/**
|
|
413
|
+
* Units that have not reported anything yet. Covers both work still queued behind other work and work claimed by a worker that stopped before it began, which is why a sweep with a persistent value here and a rising `stalledSeconds` is worth looking at.
|
|
414
|
+
*/
|
|
415
|
+
notStarted: number;
|
|
416
|
+
/**
|
|
417
|
+
* Seconds since anything last advanced. Omitted on a finished sweep, where it would only measure how long ago it finished, and on sweeps submitted before this field existed.
|
|
418
|
+
*/
|
|
419
|
+
stalledSeconds?: number;
|
|
420
|
+
/**
|
|
421
|
+
* Rough seconds remaining, extrapolated from the rate observed so far and assuming nothing else competes for workers. Runs conservative in practice — it has measured 2–5× long when a sweep spent part of its life waiting to be retried, since that wait dilutes the observed rate. **Omitted, never zero, when it cannot be computed**: a sweep with nothing finished yet has no rate to extrapolate from, and a zero would read as "about to finish". Excludes queue wait entirely; `retrying` and `stalledSeconds` are where that shows up.
|
|
422
|
+
*/
|
|
423
|
+
etaSeconds?: number;
|
|
367
424
|
};
|
|
368
425
|
|
|
369
426
|
export type SweepRunRow = {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
427
|
+
/**
|
|
428
|
+
* Deterministic zero-based expansion index, stable across shards and ranking.
|
|
429
|
+
*/
|
|
430
|
+
runIx: number;
|
|
431
|
+
/**
|
|
432
|
+
* Present only in the `ranked` view.
|
|
433
|
+
*/
|
|
434
|
+
rank?: number;
|
|
435
|
+
/**
|
|
436
|
+
* The objective of the worst run in this point's immediate neighbourhood — how well the region around it holds up, not how well it scored itself. Present only in the `ranked` view when plateau ranking applied. Always read together with `neighbourCount`.
|
|
437
|
+
*/
|
|
438
|
+
plateauScore?: number;
|
|
439
|
+
/**
|
|
440
|
+
* How many neighbouring parameter points backed the `plateauScore`. Zero means the point had no neighbours in the grid, so its score is unevidenced rather than confirmed — the value alone cannot be distinguished from a genuinely robust one.
|
|
441
|
+
*/
|
|
442
|
+
neighbourCount?: number;
|
|
443
|
+
/**
|
|
444
|
+
* Probability that this run's Sharpe reflects real edge rather than the best draw from however many parameter vectors were tried. Above ~0.95 the result survives the multiple-testing correction; near 0.5 or below it is indistinguishable from the best of a pile of coin flips. Absent on aborted runs, and on sweeps with too few trials to establish any dispersion to deflate against.
|
|
445
|
+
*/
|
|
446
|
+
deflatedSharpe?: number;
|
|
447
|
+
params: {
|
|
448
|
+
[key: string]: unknown;
|
|
449
|
+
};
|
|
450
|
+
sharpe: number;
|
|
451
|
+
sortino: number;
|
|
452
|
+
/**
|
|
453
|
+
* Absolute net PnL in the output currency.
|
|
454
|
+
*/
|
|
455
|
+
pnl: number;
|
|
456
|
+
pnlPct: number;
|
|
457
|
+
cagr: number;
|
|
458
|
+
maxDdPct: number;
|
|
459
|
+
trades: number;
|
|
460
|
+
winRate: number;
|
|
461
|
+
belowTradeFloor: boolean;
|
|
462
|
+
aborted: boolean;
|
|
463
|
+
runtimeMs: number;
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Sensitivity aggregates over a sweep's stored rows. Marginals are always complete; heatmaps may be capped, in which case `heatmapsTruncated` is true.
|
|
468
|
+
*/
|
|
469
|
+
export type SweepSensitivity = {
|
|
470
|
+
sweepId?: string;
|
|
471
|
+
status?: "RUNNING" | "COMPLETED" | "PARTIAL" | "CANCELLED";
|
|
472
|
+
objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
|
|
473
|
+
/**
|
|
474
|
+
* Rows available when this was computed. Grows while a sweep is still running.
|
|
475
|
+
*/
|
|
476
|
+
rowsAnalysed?: number;
|
|
477
|
+
marginals?: Array<SweepMarginal>;
|
|
478
|
+
heatmaps?: Array<SweepHeatmap>;
|
|
479
|
+
/**
|
|
480
|
+
* True when at least one two-parameter surface was left out to stay inside the response budget. Told explicitly because a silently short list would read as "these are all the interactions", which is the wrong thing to conclude from a sensitivity view.
|
|
481
|
+
*/
|
|
482
|
+
heatmapsTruncated?: boolean;
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* One axis, with every other axis collapsed away.
|
|
487
|
+
*/
|
|
488
|
+
export type SweepMarginal = {
|
|
489
|
+
param?: string;
|
|
490
|
+
points?: Array<SweepMarginalPoint>;
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* How the objective behaved at one value of one axis. `best` and `mean` disagreeing is informative rather than noise: a high `best` with a poor `mean` marks a value that only works alongside particular settings of the other axes.
|
|
495
|
+
*/
|
|
496
|
+
export type SweepMarginalPoint = {
|
|
497
|
+
/**
|
|
498
|
+
* The axis value, as it appears in a run's parameters.
|
|
499
|
+
*/
|
|
500
|
+
value?: unknown;
|
|
501
|
+
/**
|
|
502
|
+
* Non-aborted runs that used this value.
|
|
503
|
+
*/
|
|
504
|
+
count?: number;
|
|
505
|
+
best?: number;
|
|
506
|
+
mean?: number;
|
|
507
|
+
worst?: number;
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* The surface for one pair of axes, with all others collapsed away.
|
|
512
|
+
*/
|
|
513
|
+
export type SweepHeatmap = {
|
|
514
|
+
paramA?: string;
|
|
515
|
+
paramB?: string;
|
|
516
|
+
cells?: Array<SweepHeatmapCell>;
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
export type SweepHeatmapCell = {
|
|
520
|
+
valueA?: unknown;
|
|
521
|
+
valueB?: unknown;
|
|
522
|
+
count?: number;
|
|
523
|
+
best?: number;
|
|
524
|
+
mean?: number;
|
|
395
525
|
};
|
|
396
526
|
|
|
397
527
|
export type ExecuteSweepResult = {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
528
|
+
sweepId: string;
|
|
529
|
+
status: "RUNNING" | "COMPLETED" | "PARTIAL" | "CANCELLED";
|
|
530
|
+
objective: "sharpe" | "sortino" | "pnl" | "maxdd";
|
|
531
|
+
order: "ranked" | "natural";
|
|
532
|
+
/**
|
|
533
|
+
* Which ordering was actually applied, which is not always the one requested: a sweep with no stored parameter grid cannot be plateau-ranked and falls back to `raw`. Always `raw` when `order=natural`.
|
|
534
|
+
*/
|
|
535
|
+
ranking?: "plateau" | "raw";
|
|
536
|
+
/**
|
|
537
|
+
* Probability of backtest overfitting for the sweep as a whole, by combinatorially symmetric cross-validation: how often the configuration that won in-sample lands below median out-of-sample. Above ~0.5 the sweep is selecting noise, whatever its top row says. Computed once when the last shard finishes, so it is absent while the sweep is still running and on sweeps too small for the statistic to mean anything.
|
|
538
|
+
*/
|
|
539
|
+
pbo?: number;
|
|
540
|
+
/**
|
|
541
|
+
* How many train/test splits the `pbo` figure was averaged over.
|
|
542
|
+
*/
|
|
543
|
+
pboSplits?: number;
|
|
544
|
+
/**
|
|
545
|
+
* Why the sweep produced less than it should have — the cause reported by the **first** shard to fail, not a list. It is what turns an inscrutable empty leaderboard into an answer: a sweep can come back `PARTIAL` with `done: 0` because the strategy could not be loaded at all, and without this the response says only that nothing finished.
|
|
546
|
+
* First failure wins and later ones are not recorded, so on a sweep where several shards failed for different reasons this names one of them rather than all. Absent when no shard reported a cause, which is the normal case for a healthy sweep — read it together with `progress.failedShards` rather than as a count of anything.
|
|
547
|
+
*/
|
|
548
|
+
failReason?: string;
|
|
549
|
+
progress: SweepProgress;
|
|
550
|
+
/**
|
|
551
|
+
* Total result rows currently available.
|
|
552
|
+
*/
|
|
553
|
+
leaderboardSize: number;
|
|
554
|
+
/**
|
|
555
|
+
* True only when the ranked view exceeds its display limit.
|
|
556
|
+
*/
|
|
557
|
+
truncated: boolean;
|
|
558
|
+
leaderboard: Array<SweepRunRow>;
|
|
559
|
+
walkForward?: WalkForwardResult;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Present only on a sweep submitted with `walkForward`, and present from acceptance onward — its presence, not its contents, is what identifies a walk-forward sweep. `completedFolds` is 0 while the first fold is still running.
|
|
564
|
+
*/
|
|
565
|
+
export type WalkForwardResult = {
|
|
566
|
+
/**
|
|
567
|
+
* Folds requested at submit.
|
|
568
|
+
*/
|
|
569
|
+
folds: number;
|
|
570
|
+
/**
|
|
571
|
+
* Resolved in-sample share each fold optimized on.
|
|
572
|
+
*/
|
|
573
|
+
inSamplePct?: number;
|
|
574
|
+
/**
|
|
575
|
+
* Folds that have finished and reported a winner.
|
|
576
|
+
*/
|
|
577
|
+
completedFolds: number;
|
|
578
|
+
/**
|
|
579
|
+
* Mean normalized lattice distance between consecutive fold winners. Low is good: winners that stay in a tight band fold after fold are evidence the parameter means something, while winners that jump across the grid every time are the sweep re-fitting noise, and that backtest will not survive contact with live data. **Absent is not zero** — the field is omitted whenever the figure could not be computed (fewer than two folds finished, no stored grid to place winners on), because zero is itself a meaningful reading here and a placeholder would be indistinguishable from perfect stability.
|
|
580
|
+
*/
|
|
581
|
+
paramDrift?: number;
|
|
582
|
+
/**
|
|
583
|
+
* One entry per completed fold, oldest first.
|
|
584
|
+
*/
|
|
585
|
+
results: Array<WalkForwardFold>;
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* What one fold concluded. The out-of-sample row is the answer; the in-sample figure is only there to be compared against it, since any grid produces a flattering in-sample winner — that is what optimizing does. The gap between them is the whole reading.
|
|
590
|
+
*/
|
|
591
|
+
export type WalkForwardFold = {
|
|
592
|
+
/**
|
|
593
|
+
* Position in the walk-forward sequence, oldest first.
|
|
594
|
+
*/
|
|
595
|
+
foldIx: number;
|
|
596
|
+
/**
|
|
597
|
+
* First index of the optimization window, into the prepared session.
|
|
598
|
+
*/
|
|
599
|
+
inSampleFrom: number;
|
|
600
|
+
/**
|
|
601
|
+
* End of the optimization window, exclusive — and where scoring begins.
|
|
602
|
+
*/
|
|
603
|
+
inSampleTo: number;
|
|
604
|
+
/**
|
|
605
|
+
* End of the scoring window, exclusive.
|
|
606
|
+
*/
|
|
607
|
+
outOfSampleTo: number;
|
|
608
|
+
/**
|
|
609
|
+
* The parameter vector that won this fold's optimization window.
|
|
610
|
+
*/
|
|
611
|
+
params: {
|
|
612
|
+
[key: string]: unknown;
|
|
613
|
+
};
|
|
614
|
+
/**
|
|
615
|
+
* How that winner scored on the window it was chosen on.
|
|
616
|
+
*/
|
|
617
|
+
inSampleSharpe: number;
|
|
618
|
+
outOfSample: SweepRunRow;
|
|
619
|
+
/**
|
|
620
|
+
* Vectors this fold evaluated in-sample before picking its winner.
|
|
621
|
+
*/
|
|
622
|
+
vectorsRun: number;
|
|
412
623
|
};
|
|
413
624
|
|
|
414
625
|
/**
|
|
@@ -417,141 +628,141 @@ export type ExecuteSweepResult = {
|
|
|
417
628
|
*
|
|
418
629
|
*/
|
|
419
630
|
export type AcceptedJob = {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
631
|
+
/**
|
|
632
|
+
* Unique job identifier; use this to poll for completion.
|
|
633
|
+
*/
|
|
634
|
+
jobId: string;
|
|
424
635
|
};
|
|
425
636
|
|
|
426
637
|
/**
|
|
427
638
|
* Backtest job result.
|
|
428
639
|
*/
|
|
429
640
|
export type BacktestJobResult = {
|
|
430
|
-
|
|
431
|
-
|
|
641
|
+
results: ResultMap;
|
|
642
|
+
state: JobState;
|
|
432
643
|
};
|
|
433
644
|
|
|
434
645
|
/**
|
|
435
646
|
* Execution result map. Always includes core fields (hostName, iops, strategyId, instrument). Yield metrics (pnlTotal, pnlTotalPercent, totalTrades, winRate, equityCurve, etc.) are present when the strategy emitted at least one trade. When signal storage is enabled, includes signal fields described below. `notices` carries what the run had to say about itself, and is absent when it had nothing.
|
|
436
647
|
*/
|
|
437
648
|
export type ResultMap = {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
649
|
+
/**
|
|
650
|
+
* Identifier of the worker that executed the strategy. Useful when reporting issues so support can correlate with logs.
|
|
651
|
+
*/
|
|
652
|
+
hostName?: string;
|
|
653
|
+
/**
|
|
654
|
+
* Instrument operations per second throughput during execution
|
|
655
|
+
*/
|
|
656
|
+
iops?: number;
|
|
657
|
+
/**
|
|
658
|
+
* **Not the `strategyId` you compiled with** — this is the execution context id,
|
|
659
|
+
* `strategy:<user>:<strategyId>`. The compiled strategy's id is the last `:`-separated
|
|
660
|
+
* segment; that, not this whole string, is what `GET /strategy/{strategyId}` takes.
|
|
661
|
+
*
|
|
662
|
+
* Take the segment after the last `:` rather than counting from the front: the shape has
|
|
663
|
+
* changed once already and callers that indexed a fixed position broke on it.
|
|
664
|
+
*
|
|
665
|
+
*/
|
|
666
|
+
strategyId: string;
|
|
667
|
+
/**
|
|
668
|
+
* The instrument (currency pair) that was backtested
|
|
669
|
+
*/
|
|
670
|
+
instrument: string;
|
|
671
|
+
/**
|
|
672
|
+
* Diagnostics the engine raised over this run, each with `provenance: execute`.
|
|
673
|
+
*
|
|
674
|
+
* **Absent means nothing was raised.** This is the one surface where silence is a real
|
|
675
|
+
* answer: the run happened, over your data, start to finish, and the engine found nothing
|
|
676
|
+
* worth saying. That is not true of the compile path, where an empty list only means a
|
|
677
|
+
* short synthetic series reached nothing — see `GET /strategy/{strategyId}`.
|
|
678
|
+
*
|
|
679
|
+
* Notices are raised on failed and aborted runs too, and those are the ones most worth
|
|
680
|
+
* reading: a run that produced no trades often did so for a reason stated here.
|
|
681
|
+
*
|
|
682
|
+
*/
|
|
683
|
+
notices?: Array<Notice>;
|
|
684
|
+
/**
|
|
685
|
+
* How many notices were dropped past the cap of 50. Absent when none were. A large value usually means one fault repeating per instrument or per parameter vector rather than 50 distinct problems.
|
|
686
|
+
*/
|
|
687
|
+
noticesTruncated?: number;
|
|
688
|
+
/**
|
|
689
|
+
* Total profit and loss in the output currency
|
|
690
|
+
*/
|
|
691
|
+
pnlTotal?: number;
|
|
692
|
+
/**
|
|
693
|
+
* Total PnL as a percentage of the initial capital (`backtestFunding`). Zero when `backtestFunding` is 0.
|
|
694
|
+
*/
|
|
695
|
+
pnlTotalPercent?: number;
|
|
696
|
+
/**
|
|
697
|
+
* Total number of trades executed by the strategy
|
|
698
|
+
*/
|
|
699
|
+
totalTrades?: number;
|
|
700
|
+
/**
|
|
701
|
+
* Percentage of profitable trades (0-100)
|
|
702
|
+
*/
|
|
703
|
+
winRate?: number;
|
|
704
|
+
/**
|
|
705
|
+
* Risk-adjusted return ratio (mean return / standard deviation of returns)
|
|
706
|
+
*/
|
|
707
|
+
sharpeRatio?: number;
|
|
708
|
+
/**
|
|
709
|
+
* Downside risk-adjusted return ratio (mean return / downside deviation)
|
|
710
|
+
*/
|
|
711
|
+
sortinoRatio?: number;
|
|
712
|
+
/**
|
|
713
|
+
* Compound Annual Growth Rate
|
|
714
|
+
*/
|
|
715
|
+
cagr?: number;
|
|
716
|
+
/**
|
|
717
|
+
* Maximum absolute drawdown in the output currency
|
|
718
|
+
*/
|
|
719
|
+
maxDrawdown?: number;
|
|
720
|
+
/**
|
|
721
|
+
* Maximum percentage drawdown from peak equity
|
|
722
|
+
*/
|
|
723
|
+
maxDrawdownPercent?: number;
|
|
724
|
+
/**
|
|
725
|
+
* Equity curve over the backtest. Element 0 is an anchor at the backtest `from` with `initialCapital`; the remaining points are one sample per emitted yield, in order. Use it to plot the strategy's running equity without re-deriving it from the yield history.
|
|
726
|
+
*/
|
|
727
|
+
equityCurve?: Array<EquityPoint>;
|
|
728
|
+
/**
|
|
729
|
+
* Number of signals emitted during strategy execution
|
|
730
|
+
*/
|
|
731
|
+
signalCount?: number;
|
|
732
|
+
/**
|
|
733
|
+
* Storage key for the signals file. Treat as opaque; use signalsUrl to download.
|
|
734
|
+
*/
|
|
735
|
+
signalsId?: string;
|
|
736
|
+
/**
|
|
737
|
+
* HTTPS URL to download the signals Parquet file. Use signalsUpload to know when it's ready.
|
|
738
|
+
*/
|
|
739
|
+
signalsUrl?: string;
|
|
740
|
+
/**
|
|
741
|
+
* Upload status. Done = signal file is available at signalsUrl. Failed = upload error (see signalsUploadReason). Skipped = no signals emitted.
|
|
742
|
+
*/
|
|
743
|
+
signalsUpload?: "Done" | "Failed" | "Skipped";
|
|
744
|
+
/**
|
|
745
|
+
* ISO 8601 timestamp of when the upload completed. Only present when signalsUpload is Done.
|
|
746
|
+
*/
|
|
747
|
+
signalsUploadedAt?: string;
|
|
748
|
+
/**
|
|
749
|
+
* Human-readable reason when signalsUpload is Failed or Skipped.
|
|
750
|
+
*/
|
|
751
|
+
signalsUploadReason?: string;
|
|
541
752
|
};
|
|
542
753
|
|
|
543
754
|
/**
|
|
544
755
|
* Single sample of the running equity at a yield event.
|
|
545
756
|
*/
|
|
546
757
|
export type EquityPoint = {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
758
|
+
/**
|
|
759
|
+
* Epoch milliseconds. The first point in an equity curve is anchored at the backtest `from`; subsequent points carry the timestamp of each emitted yield.
|
|
760
|
+
*/
|
|
761
|
+
timestamp: number;
|
|
762
|
+
/**
|
|
763
|
+
* Running equity at this point (`initialCapital + cumulativePnl`).
|
|
764
|
+
*/
|
|
765
|
+
equity: number;
|
|
555
766
|
};
|
|
556
767
|
|
|
557
768
|
/**
|
|
@@ -568,25 +779,25 @@ export type StrategyId = string;
|
|
|
568
779
|
*
|
|
569
780
|
*/
|
|
570
781
|
export type Notice = {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
782
|
+
/**
|
|
783
|
+
* Severity as the engine classified it.
|
|
784
|
+
*/
|
|
785
|
+
level: string;
|
|
786
|
+
/**
|
|
787
|
+
* Stable identifier for the kind of finding; safe to match on.
|
|
788
|
+
*/
|
|
789
|
+
code: string;
|
|
790
|
+
/**
|
|
791
|
+
* Human-readable explanation.
|
|
792
|
+
*/
|
|
793
|
+
message: string;
|
|
794
|
+
/**
|
|
795
|
+
* Where it came from, which matters because the two silences differ: an empty list from a
|
|
796
|
+
* real run (`execute`) is a clean bill of health, while an empty list from
|
|
797
|
+
* `compile-dry-run` is only a lower bound over a bounded synthetic series.
|
|
798
|
+
*
|
|
799
|
+
*/
|
|
800
|
+
provenance?: "execute" | "compile-dry-run";
|
|
590
801
|
};
|
|
591
802
|
|
|
592
803
|
/**
|
|
@@ -598,796 +809,872 @@ export type Notice = {
|
|
|
598
809
|
*
|
|
599
810
|
*/
|
|
600
811
|
export type StrategyState = {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
812
|
+
strategyId: StrategyId;
|
|
813
|
+
/**
|
|
814
|
+
* * `not_validated` — registered, never checked. `POST /strategy/{strategyId}/validate`
|
|
815
|
+
* checks it.
|
|
816
|
+
* * `pending` — a check was asked for and has not answered yet.
|
|
817
|
+
* * `passed` — the class loaded and survived its first event.
|
|
818
|
+
* * `failed` — it did not; `detail` says how.
|
|
819
|
+
*
|
|
820
|
+
*/
|
|
821
|
+
validation: "not_validated" | "pending" | "passed" | "failed";
|
|
822
|
+
/**
|
|
823
|
+
* When the live compilation was produced.
|
|
824
|
+
*/
|
|
825
|
+
compiledAt?: string;
|
|
826
|
+
/**
|
|
827
|
+
* The market data a strategy needs, read off the compiled class rather than off anything
|
|
828
|
+
* you sent — `TickerStrategy`, `KlineStrategy` and `FundingRateStrategy` each declare one,
|
|
829
|
+
* and a `MultiSourceStrategy` declares a set.
|
|
830
|
+
*
|
|
831
|
+
* **Absent is not "needs nothing".** A strategy always needs market data, so an absent
|
|
832
|
+
* field never means an empty requirement — it means the platform could not establish the
|
|
833
|
+
* answer without constructing your strategy, which it will not do to fill in a field.
|
|
834
|
+
* That happens for a `MultiSourceStrategy`, for a class that overrides
|
|
835
|
+
* `getMarketDataSource()`, and for anything registered before this field existed;
|
|
836
|
+
* re-registering the source fills it in.
|
|
837
|
+
*
|
|
838
|
+
*/
|
|
839
|
+
requiredSources?: Array<"Ticker" | "KLine" | "FundingRate">;
|
|
840
|
+
/**
|
|
841
|
+
* When the verdict was recorded. Absent until there is one.
|
|
842
|
+
*/
|
|
843
|
+
validatedAt?: string;
|
|
844
|
+
/**
|
|
845
|
+
* Why validation failed, or why a queued check has not reported. Present on `failed`, and
|
|
846
|
+
* alongside `validationStalled`.
|
|
847
|
+
*
|
|
848
|
+
*/
|
|
849
|
+
detail?: string;
|
|
850
|
+
/**
|
|
851
|
+
* What the run surfaced. An empty or absent list is not a clean bill of health when
|
|
852
|
+
* `dryRunIncomplete` is true — see that field.
|
|
853
|
+
*
|
|
854
|
+
*/
|
|
855
|
+
notices?: Array<Notice>;
|
|
856
|
+
/**
|
|
857
|
+
* How many notices were dropped past the cap. Absent when none were.
|
|
858
|
+
*/
|
|
859
|
+
noticesTruncated?: number;
|
|
860
|
+
/**
|
|
861
|
+
* The check did not finish its budget — it ran out of time, was refused because the
|
|
862
|
+
* platform was already holding too many unfinishable runs, or hit a failure attributable to
|
|
863
|
+
* the synthetic instrument rather than to your strategy. The verdict stands as far as it
|
|
864
|
+
* went; it simply reached less than a full run would.
|
|
865
|
+
*
|
|
866
|
+
*/
|
|
867
|
+
dryRunIncomplete?: boolean;
|
|
868
|
+
/**
|
|
869
|
+
* A queued check has not reported for far longer than one takes. Nothing is disproved about
|
|
870
|
+
* the strategy — the check has not run. Stop waiting and re-request it later.
|
|
871
|
+
*
|
|
872
|
+
*/
|
|
873
|
+
validationStalled?: boolean;
|
|
663
874
|
};
|
|
664
875
|
|
|
665
876
|
export type AuthTokenResponse = {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
877
|
+
/**
|
|
878
|
+
* Short-lived HS256 JWT. Send as `Authorization: Bearer <token>` on all other endpoints.
|
|
879
|
+
*/
|
|
880
|
+
access_token: string;
|
|
881
|
+
/**
|
|
882
|
+
* Always `Bearer`.
|
|
883
|
+
*/
|
|
884
|
+
token_type: "Bearer";
|
|
885
|
+
/**
|
|
886
|
+
* Seconds until the JWT expires (typically 3600).
|
|
887
|
+
*/
|
|
888
|
+
expires_in: number;
|
|
889
|
+
/**
|
|
890
|
+
* Scopes granted to this token. Reserved for future use; currently always empty.
|
|
891
|
+
*/
|
|
892
|
+
scopes?: Array<string>;
|
|
893
|
+
/**
|
|
894
|
+
* Subscription tier this token was issued for. Drives rate limits and feature flags on downstream endpoints.
|
|
895
|
+
*/
|
|
896
|
+
tier: "free" | "basic" | "pro" | "elite";
|
|
686
897
|
};
|
|
687
898
|
|
|
688
899
|
/**
|
|
689
900
|
* Error envelope returned by `POST /auth/token` when the API key is rejected.
|
|
690
901
|
*/
|
|
691
902
|
export type AuthTokenError = {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
903
|
+
/**
|
|
904
|
+
* Machine-readable error reason.
|
|
905
|
+
*/
|
|
906
|
+
code: "invalid_apikey" | "apikey_revoked" | "apikey_expired";
|
|
907
|
+
/**
|
|
908
|
+
* Human-readable description of the failure.
|
|
909
|
+
*/
|
|
910
|
+
message: string;
|
|
700
911
|
};
|
|
701
912
|
|
|
702
913
|
export type AuthenticateData = {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
914
|
+
body?: never;
|
|
915
|
+
path?: never;
|
|
916
|
+
query?: never;
|
|
917
|
+
url: "/auth/token";
|
|
707
918
|
};
|
|
708
919
|
|
|
709
920
|
export type AuthenticateErrors = {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
921
|
+
/**
|
|
922
|
+
* API key is invalid, revoked, or expired.
|
|
923
|
+
*/
|
|
924
|
+
401: AuthTokenError;
|
|
925
|
+
/**
|
|
926
|
+
* Rate limit exceeded for this API key.
|
|
927
|
+
*/
|
|
928
|
+
429: unknown;
|
|
718
929
|
};
|
|
719
930
|
|
|
720
931
|
export type AuthenticateError = AuthenticateErrors[keyof AuthenticateErrors];
|
|
721
932
|
|
|
722
933
|
export type AuthenticateResponses = {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
934
|
+
/**
|
|
935
|
+
* API key accepted; JWT returned.
|
|
936
|
+
*/
|
|
937
|
+
200: AuthTokenResponse;
|
|
727
938
|
};
|
|
728
939
|
|
|
729
|
-
export type AuthenticateResponse =
|
|
940
|
+
export type AuthenticateResponse =
|
|
941
|
+
AuthenticateResponses[keyof AuthenticateResponses];
|
|
730
942
|
|
|
731
943
|
export type ListExchangesData = {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
944
|
+
body?: never;
|
|
945
|
+
path?: never;
|
|
946
|
+
query?: never;
|
|
947
|
+
url: "/exchanges";
|
|
736
948
|
};
|
|
737
949
|
|
|
738
950
|
export type ListExchangesResponses = {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
951
|
+
/**
|
|
952
|
+
* A JSON array of Exchanges
|
|
953
|
+
*/
|
|
954
|
+
200: Array<Exchange>;
|
|
743
955
|
};
|
|
744
956
|
|
|
745
|
-
export type ListExchangesResponse =
|
|
957
|
+
export type ListExchangesResponse =
|
|
958
|
+
ListExchangesResponses[keyof ListExchangesResponses];
|
|
746
959
|
|
|
747
960
|
export type ListInstrumentsData = {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
961
|
+
body?: never;
|
|
962
|
+
path: {
|
|
963
|
+
/**
|
|
964
|
+
* ID of the exchange to retrieve instruments for
|
|
965
|
+
*/
|
|
966
|
+
exchangeId: string;
|
|
967
|
+
};
|
|
968
|
+
query?: never;
|
|
969
|
+
url: "/exchange/{exchangeId}/instruments";
|
|
757
970
|
};
|
|
758
971
|
|
|
759
972
|
export type ListInstrumentsErrors = {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
973
|
+
/**
|
|
974
|
+
* Exchange not found or instrument catalog not available
|
|
975
|
+
*/
|
|
976
|
+
404: ResponseError;
|
|
764
977
|
};
|
|
765
978
|
|
|
766
|
-
export type ListInstrumentsError =
|
|
979
|
+
export type ListInstrumentsError =
|
|
980
|
+
ListInstrumentsErrors[keyof ListInstrumentsErrors];
|
|
767
981
|
|
|
768
982
|
export type ListInstrumentsResponses = {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
983
|
+
/**
|
|
984
|
+
* The default (spot) segment's instruments in `data`, `meta`, and HAL `_links` (self + spot/futures segment discovery)
|
|
985
|
+
*/
|
|
986
|
+
200: InstrumentListResponse;
|
|
773
987
|
};
|
|
774
988
|
|
|
775
|
-
export type ListInstrumentsResponse =
|
|
989
|
+
export type ListInstrumentsResponse =
|
|
990
|
+
ListInstrumentsResponses[keyof ListInstrumentsResponses];
|
|
776
991
|
|
|
777
992
|
export type ListSegmentInstrumentsData = {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
993
|
+
body?: never;
|
|
994
|
+
path: {
|
|
995
|
+
/**
|
|
996
|
+
* ID of the exchange to retrieve instruments for
|
|
997
|
+
*/
|
|
998
|
+
exchangeId: string;
|
|
999
|
+
/**
|
|
1000
|
+
* Market segment to list instruments for
|
|
1001
|
+
*/
|
|
1002
|
+
segment: "spot" | "futures";
|
|
1003
|
+
};
|
|
1004
|
+
query?: never;
|
|
1005
|
+
url: "/exchange/{exchangeId}/{segment}/instruments";
|
|
791
1006
|
};
|
|
792
1007
|
|
|
793
1008
|
export type ListSegmentInstrumentsErrors = {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1009
|
+
/**
|
|
1010
|
+
* Exchange, segment, or instrument catalog not found
|
|
1011
|
+
*/
|
|
1012
|
+
404: ResponseError;
|
|
798
1013
|
};
|
|
799
1014
|
|
|
800
|
-
export type ListSegmentInstrumentsError =
|
|
1015
|
+
export type ListSegmentInstrumentsError =
|
|
1016
|
+
ListSegmentInstrumentsErrors[keyof ListSegmentInstrumentsErrors];
|
|
801
1017
|
|
|
802
1018
|
export type ListSegmentInstrumentsResponses = {
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1019
|
+
/**
|
|
1020
|
+
* An object with a `data` array of instrument details (each with per-data-type coverage) and a `meta` block
|
|
1021
|
+
*/
|
|
1022
|
+
200: InstrumentListResponse;
|
|
807
1023
|
};
|
|
808
1024
|
|
|
809
|
-
export type ListSegmentInstrumentsResponse =
|
|
1025
|
+
export type ListSegmentInstrumentsResponse =
|
|
1026
|
+
ListSegmentInstrumentsResponses[keyof ListSegmentInstrumentsResponses];
|
|
810
1027
|
|
|
811
1028
|
export type DownloadTickersData = {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
/**
|
|
815
|
-
* ID of the exchange (e.g. `binance`).
|
|
816
|
-
*/
|
|
817
|
-
exchangeId: string;
|
|
818
|
-
/**
|
|
819
|
-
* Base asset symbol (first leg of the pair).
|
|
820
|
-
*/
|
|
821
|
-
base: string;
|
|
822
|
-
/**
|
|
823
|
-
* Quote asset symbol (second leg of the pair).
|
|
824
|
-
*/
|
|
825
|
-
quote: string;
|
|
826
|
-
};
|
|
827
|
-
query: {
|
|
828
|
-
/**
|
|
829
|
-
* Hour selector in `YYYY-MM-DDTHH` (UTC). The returned segment covers
|
|
830
|
-
* `[HH:00:00Z, HH+1:00:00Z)`.
|
|
831
|
-
*
|
|
832
|
-
*/
|
|
833
|
-
hour: string;
|
|
834
|
-
/**
|
|
835
|
-
* Response wire format. `lastra` (default) returns raw Lastra bytes.
|
|
836
|
-
* `parquet` returns Parquet via on-the-fly conversion using
|
|
837
|
-
* [lastra-convert](https://github.com/QTSurfer/lastra-convert).
|
|
838
|
-
*
|
|
839
|
-
*/
|
|
840
|
-
format?: 'lastra' | 'parquet';
|
|
841
|
-
};
|
|
842
|
-
url: '/exchange/{exchangeId}/tickers/{base}/{quote}';
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
export type DownloadTickersErrors = {
|
|
1029
|
+
body?: never;
|
|
1030
|
+
path: {
|
|
846
1031
|
/**
|
|
847
|
-
*
|
|
1032
|
+
* ID of the exchange (e.g. `binance`).
|
|
848
1033
|
*/
|
|
849
|
-
|
|
1034
|
+
exchangeId: string;
|
|
850
1035
|
/**
|
|
851
|
-
*
|
|
1036
|
+
* Base asset symbol (first leg of the pair).
|
|
852
1037
|
*/
|
|
853
|
-
|
|
1038
|
+
base: string;
|
|
854
1039
|
/**
|
|
855
|
-
*
|
|
1040
|
+
* Quote asset symbol (second leg of the pair).
|
|
856
1041
|
*/
|
|
857
|
-
|
|
858
|
-
};
|
|
859
|
-
|
|
860
|
-
export type DownloadTickersError = DownloadTickersErrors[keyof DownloadTickersErrors];
|
|
861
|
-
|
|
862
|
-
export type DownloadTickersResponses = {
|
|
1042
|
+
quote: string;
|
|
1043
|
+
};
|
|
1044
|
+
query: {
|
|
863
1045
|
/**
|
|
864
|
-
*
|
|
865
|
-
* `
|
|
866
|
-
* `application/vnd.apache.parquet` when `format=parquet` was
|
|
867
|
-
* requested.
|
|
1046
|
+
* Hour selector in `YYYY-MM-DDTHH` (UTC). The returned segment covers
|
|
1047
|
+
* `[HH:00:00Z, HH+1:00:00Z)`.
|
|
868
1048
|
*
|
|
869
1049
|
*/
|
|
870
|
-
|
|
1050
|
+
hour: string;
|
|
1051
|
+
/**
|
|
1052
|
+
* Response wire format. `lastra` (default) returns raw Lastra bytes.
|
|
1053
|
+
* `parquet` returns Parquet via on-the-fly conversion using
|
|
1054
|
+
* [lastra-convert](https://github.com/QTSurfer/lastra-convert).
|
|
1055
|
+
*
|
|
1056
|
+
*/
|
|
1057
|
+
format?: "lastra" | "parquet";
|
|
1058
|
+
};
|
|
1059
|
+
url: "/exchange/{exchangeId}/tickers/{base}/{quote}";
|
|
871
1060
|
};
|
|
872
1061
|
|
|
873
|
-
export type
|
|
1062
|
+
export type DownloadTickersErrors = {
|
|
1063
|
+
/**
|
|
1064
|
+
* Missing or malformed parameters (e.g. `hour` not `YYYY-MM-DDTHH`).
|
|
1065
|
+
*/
|
|
1066
|
+
400: ResponseError;
|
|
1067
|
+
/**
|
|
1068
|
+
* No Lastra segment exists for the requested instrument/hour.
|
|
1069
|
+
*/
|
|
1070
|
+
404: ResponseError;
|
|
1071
|
+
/**
|
|
1072
|
+
* Unexpected I/O error serving the file.
|
|
1073
|
+
*/
|
|
1074
|
+
500: ResponseError;
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
export type DownloadTickersError =
|
|
1078
|
+
DownloadTickersErrors[keyof DownloadTickersErrors];
|
|
874
1079
|
|
|
875
|
-
export type
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
*/
|
|
885
|
-
base: string;
|
|
886
|
-
/**
|
|
887
|
-
* Quote asset symbol.
|
|
888
|
-
*/
|
|
889
|
-
quote: string;
|
|
890
|
-
};
|
|
891
|
-
query: {
|
|
892
|
-
/**
|
|
893
|
-
* Hour selector in `YYYY-MM-DDTHH` (UTC). The returned segment covers
|
|
894
|
-
* `[HH:00:00Z, HH+1:00:00Z)`.
|
|
895
|
-
*
|
|
896
|
-
*/
|
|
897
|
-
hour: string;
|
|
898
|
-
/**
|
|
899
|
-
* Response wire format. `lastra` (default) returns raw Lastra bytes.
|
|
900
|
-
* `parquet` returns Parquet via on-the-fly conversion.
|
|
901
|
-
*
|
|
902
|
-
*/
|
|
903
|
-
format?: 'lastra' | 'parquet';
|
|
904
|
-
};
|
|
905
|
-
url: '/exchange/{exchangeId}/klines/{base}/{quote}';
|
|
1080
|
+
export type DownloadTickersResponses = {
|
|
1081
|
+
/**
|
|
1082
|
+
* One hour of tickers for the instrument. `Content-Type` is
|
|
1083
|
+
* `application/vnd.lastra` by default or
|
|
1084
|
+
* `application/vnd.apache.parquet` when `format=parquet` was
|
|
1085
|
+
* requested.
|
|
1086
|
+
*
|
|
1087
|
+
*/
|
|
1088
|
+
200: Blob | File;
|
|
906
1089
|
};
|
|
907
1090
|
|
|
908
|
-
export type
|
|
1091
|
+
export type DownloadTickersResponse =
|
|
1092
|
+
DownloadTickersResponses[keyof DownloadTickersResponses];
|
|
1093
|
+
|
|
1094
|
+
export type DownloadKlinesData = {
|
|
1095
|
+
body?: never;
|
|
1096
|
+
path: {
|
|
1097
|
+
/**
|
|
1098
|
+
* ID of the exchange (e.g. `binance`).
|
|
1099
|
+
*/
|
|
1100
|
+
exchangeId: string;
|
|
1101
|
+
/**
|
|
1102
|
+
* Base asset symbol.
|
|
1103
|
+
*/
|
|
1104
|
+
base: string;
|
|
909
1105
|
/**
|
|
910
|
-
*
|
|
1106
|
+
* Quote asset symbol.
|
|
911
1107
|
*/
|
|
912
|
-
|
|
1108
|
+
quote: string;
|
|
1109
|
+
};
|
|
1110
|
+
query: {
|
|
913
1111
|
/**
|
|
914
|
-
*
|
|
1112
|
+
* Hour selector in `YYYY-MM-DDTHH` (UTC). The returned segment covers
|
|
1113
|
+
* `[HH:00:00Z, HH+1:00:00Z)`.
|
|
1114
|
+
*
|
|
915
1115
|
*/
|
|
916
|
-
|
|
1116
|
+
hour: string;
|
|
917
1117
|
/**
|
|
918
|
-
*
|
|
1118
|
+
* Response wire format. `lastra` (default) returns raw Lastra bytes.
|
|
1119
|
+
* `parquet` returns Parquet via on-the-fly conversion.
|
|
1120
|
+
*
|
|
919
1121
|
*/
|
|
920
|
-
|
|
1122
|
+
format?: "lastra" | "parquet";
|
|
1123
|
+
};
|
|
1124
|
+
url: "/exchange/{exchangeId}/klines/{base}/{quote}";
|
|
921
1125
|
};
|
|
922
1126
|
|
|
923
|
-
export type
|
|
1127
|
+
export type DownloadKlinesErrors = {
|
|
1128
|
+
/**
|
|
1129
|
+
* Missing or malformed parameters (e.g. `hour` not `YYYY-MM-DDTHH`).
|
|
1130
|
+
*/
|
|
1131
|
+
400: ResponseError;
|
|
1132
|
+
/**
|
|
1133
|
+
* No Lastra segment exists for the requested instrument/hour.
|
|
1134
|
+
*/
|
|
1135
|
+
404: ResponseError;
|
|
1136
|
+
/**
|
|
1137
|
+
* Unexpected I/O error serving the file.
|
|
1138
|
+
*/
|
|
1139
|
+
500: ResponseError;
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
export type DownloadKlinesError =
|
|
1143
|
+
DownloadKlinesErrors[keyof DownloadKlinesErrors];
|
|
924
1144
|
|
|
925
1145
|
export type DownloadKlinesResponses = {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1146
|
+
/**
|
|
1147
|
+
* One hour of klines for the instrument. `Content-Type` is
|
|
1148
|
+
* `application/vnd.lastra` by default or
|
|
1149
|
+
* `application/vnd.apache.parquet` when `format=parquet`.
|
|
1150
|
+
*
|
|
1151
|
+
*/
|
|
1152
|
+
200: Blob | File;
|
|
933
1153
|
};
|
|
934
1154
|
|
|
935
|
-
export type DownloadKlinesResponse =
|
|
1155
|
+
export type DownloadKlinesResponse =
|
|
1156
|
+
DownloadKlinesResponses[keyof DownloadKlinesResponses];
|
|
936
1157
|
|
|
937
1158
|
export type CompileStrategyData = {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1159
|
+
/**
|
|
1160
|
+
* Raw strategy Java source code
|
|
1161
|
+
*/
|
|
1162
|
+
body: string;
|
|
1163
|
+
path?: never;
|
|
1164
|
+
query?: never;
|
|
1165
|
+
url: "/strategy";
|
|
945
1166
|
};
|
|
946
1167
|
|
|
947
1168
|
export type CompileStrategyErrors = {
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1169
|
+
/**
|
|
1170
|
+
* The source is not valid Java; the message carries the compiler diagnostics. Nothing is
|
|
1171
|
+
* registered, so there is no id to look up afterwards.
|
|
1172
|
+
*
|
|
1173
|
+
*/
|
|
1174
|
+
400: ResponseError;
|
|
1175
|
+
/**
|
|
1176
|
+
* Too many compilations in flight. Retry later.
|
|
1177
|
+
*/
|
|
1178
|
+
429: ResponseError;
|
|
958
1179
|
};
|
|
959
1180
|
|
|
960
|
-
export type CompileStrategyError =
|
|
1181
|
+
export type CompileStrategyError =
|
|
1182
|
+
CompileStrategyErrors[keyof CompileStrategyErrors];
|
|
961
1183
|
|
|
962
1184
|
export type CompileStrategyResponses = {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1185
|
+
/**
|
|
1186
|
+
* Compiled and registered
|
|
1187
|
+
*/
|
|
1188
|
+
200: {
|
|
1189
|
+
strategyId: StrategyId;
|
|
1190
|
+
};
|
|
969
1191
|
};
|
|
970
1192
|
|
|
971
|
-
export type CompileStrategyResponse =
|
|
1193
|
+
export type CompileStrategyResponse =
|
|
1194
|
+
CompileStrategyResponses[keyof CompileStrategyResponses];
|
|
972
1195
|
|
|
973
1196
|
export type ValidateStrategyData = {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1197
|
+
body?: never;
|
|
1198
|
+
path: {
|
|
1199
|
+
/**
|
|
1200
|
+
* The id returned by `POST /strategy`
|
|
1201
|
+
*/
|
|
1202
|
+
strategyId: StrategyId;
|
|
1203
|
+
};
|
|
1204
|
+
query?: never;
|
|
1205
|
+
url: "/strategy/{strategyId}/validate";
|
|
983
1206
|
};
|
|
984
1207
|
|
|
985
1208
|
export type ValidateStrategyErrors = {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1209
|
+
/**
|
|
1210
|
+
* No such registered strategy for this user
|
|
1211
|
+
*/
|
|
1212
|
+
404: ResponseError;
|
|
990
1213
|
};
|
|
991
1214
|
|
|
992
|
-
export type ValidateStrategyError =
|
|
1215
|
+
export type ValidateStrategyError =
|
|
1216
|
+
ValidateStrategyErrors[keyof ValidateStrategyErrors];
|
|
993
1217
|
|
|
994
1218
|
export type ValidateStrategyResponses = {
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1219
|
+
/**
|
|
1220
|
+
* Already validated; the recorded verdict, unchanged
|
|
1221
|
+
*/
|
|
1222
|
+
200: StrategyState;
|
|
1223
|
+
/**
|
|
1224
|
+
* Validation queued. Not a terminal outcome — poll `GET /strategy/{strategyId}` until
|
|
1225
|
+
* `validation` leaves `pending`.
|
|
1226
|
+
*
|
|
1227
|
+
* The body is a `StrategyState` carrying only what is known at this point: the id and
|
|
1228
|
+
* `validation: pending`. **The status code, not the body, is what tells the two responses
|
|
1229
|
+
* apart** — a `200` can also carry `validation: pending`, left by a check an earlier call
|
|
1230
|
+
* queued. So `202` means *this call started a check*, while `pending` means only *a check
|
|
1231
|
+
* is outstanding*.
|
|
1232
|
+
*
|
|
1233
|
+
*/
|
|
1234
|
+
202: StrategyState;
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
export type ValidateStrategyResponse =
|
|
1238
|
+
ValidateStrategyResponses[keyof ValidateStrategyResponses];
|
|
1011
1239
|
|
|
1012
1240
|
export type GetStrategyData = {
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1241
|
+
body?: never;
|
|
1242
|
+
path: {
|
|
1243
|
+
/**
|
|
1244
|
+
* The id returned by `POST /strategy`
|
|
1245
|
+
*/
|
|
1246
|
+
strategyId: StrategyId;
|
|
1247
|
+
};
|
|
1248
|
+
query?: never;
|
|
1249
|
+
url: "/strategy/{strategyId}";
|
|
1022
1250
|
};
|
|
1023
1251
|
|
|
1024
1252
|
export type GetStrategyErrors = {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1253
|
+
/**
|
|
1254
|
+
* No such registered strategy for this user
|
|
1255
|
+
*/
|
|
1256
|
+
404: ResponseError;
|
|
1029
1257
|
};
|
|
1030
1258
|
|
|
1031
1259
|
export type GetStrategyError = GetStrategyErrors[keyof GetStrategyErrors];
|
|
1032
1260
|
|
|
1033
1261
|
export type GetStrategyResponses = {
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1262
|
+
/**
|
|
1263
|
+
* Strategy state
|
|
1264
|
+
*/
|
|
1265
|
+
200: StrategyState;
|
|
1038
1266
|
};
|
|
1039
1267
|
|
|
1040
|
-
export type GetStrategyResponse =
|
|
1268
|
+
export type GetStrategyResponse =
|
|
1269
|
+
GetStrategyResponses[keyof GetStrategyResponses];
|
|
1041
1270
|
|
|
1042
1271
|
export type PrepareBacktestData = {
|
|
1272
|
+
/**
|
|
1273
|
+
* The required data to prepare a backtesting
|
|
1274
|
+
*/
|
|
1275
|
+
body: PrepareRequest;
|
|
1276
|
+
path: {
|
|
1043
1277
|
/**
|
|
1044
|
-
*
|
|
1278
|
+
* ID of the exchange to prepare the backtesting for
|
|
1045
1279
|
*/
|
|
1046
|
-
|
|
1047
|
-
path: {
|
|
1048
|
-
/**
|
|
1049
|
-
* ID of the exchange to prepare the backtesting for
|
|
1050
|
-
*/
|
|
1051
|
-
exchangeId: string;
|
|
1052
|
-
/**
|
|
1053
|
-
* The type of data source to prepare from
|
|
1054
|
-
*/
|
|
1055
|
-
type: DataSourceType;
|
|
1056
|
-
};
|
|
1057
|
-
query?: never;
|
|
1058
|
-
url: '/backtest/{exchangeId}/{type}/prepare';
|
|
1059
|
-
};
|
|
1060
|
-
|
|
1061
|
-
export type PrepareBacktestErrors = {
|
|
1280
|
+
exchangeId: string;
|
|
1062
1281
|
/**
|
|
1063
|
-
*
|
|
1064
|
-
* lookback window or `to` is in the future.
|
|
1065
|
-
*
|
|
1282
|
+
* The type of data source to prepare from
|
|
1066
1283
|
*/
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
404: ResponseError;
|
|
1072
|
-
/**
|
|
1073
|
-
* Rate limited. Returned when the global queue exceeds capacity or the user has too many
|
|
1074
|
-
* active backtests.
|
|
1075
|
-
*
|
|
1076
|
-
*/
|
|
1077
|
-
429: ResponseError;
|
|
1284
|
+
type: DataSourceType;
|
|
1285
|
+
};
|
|
1286
|
+
query?: never;
|
|
1287
|
+
url: "/backtest/{exchangeId}/{type}/prepare";
|
|
1078
1288
|
};
|
|
1079
1289
|
|
|
1080
|
-
export type
|
|
1290
|
+
export type PrepareBacktestErrors = {
|
|
1291
|
+
/**
|
|
1292
|
+
* Invalid request or parameters. Also returned when `from` is older than the configured
|
|
1293
|
+
* lookback window or `to` is in the future.
|
|
1294
|
+
*
|
|
1295
|
+
*/
|
|
1296
|
+
400: ResponseError;
|
|
1297
|
+
/**
|
|
1298
|
+
* Exchange or data source type not found
|
|
1299
|
+
*/
|
|
1300
|
+
404: ResponseError;
|
|
1301
|
+
/**
|
|
1302
|
+
* Rate limited. Returned when the global queue exceeds capacity or the user has too many
|
|
1303
|
+
* active backtests.
|
|
1304
|
+
*
|
|
1305
|
+
*/
|
|
1306
|
+
429: ResponseError;
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
export type PrepareBacktestError =
|
|
1310
|
+
PrepareBacktestErrors[keyof PrepareBacktestErrors];
|
|
1081
1311
|
|
|
1082
1312
|
export type PrepareBacktestResponses = {
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1313
|
+
/**
|
|
1314
|
+
* Prepare task accepted (queued for processing)
|
|
1315
|
+
*/
|
|
1316
|
+
202: AcceptedJob;
|
|
1087
1317
|
};
|
|
1088
1318
|
|
|
1089
|
-
export type PrepareBacktestResponse =
|
|
1319
|
+
export type PrepareBacktestResponse =
|
|
1320
|
+
PrepareBacktestResponses[keyof PrepareBacktestResponses];
|
|
1090
1321
|
|
|
1091
1322
|
export type GetPrepareStatusData = {
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
/**
|
|
1099
|
-
* The type of data source to prepare from
|
|
1100
|
-
*/
|
|
1101
|
-
type: DataSourceType;
|
|
1102
|
-
/**
|
|
1103
|
-
* Job ID returned by `POST /prepare`
|
|
1104
|
-
*/
|
|
1105
|
-
jobId: string;
|
|
1106
|
-
};
|
|
1107
|
-
query?: never;
|
|
1108
|
-
url: '/backtest/{exchangeId}/{type}/prepare/{jobId}';
|
|
1109
|
-
};
|
|
1110
|
-
|
|
1111
|
-
export type GetPrepareStatusErrors = {
|
|
1323
|
+
body?: never;
|
|
1324
|
+
path: {
|
|
1325
|
+
/**
|
|
1326
|
+
* ID of the exchange for the backtesting process
|
|
1327
|
+
*/
|
|
1328
|
+
exchangeId: string;
|
|
1112
1329
|
/**
|
|
1113
|
-
*
|
|
1330
|
+
* The type of data source to prepare from
|
|
1114
1331
|
*/
|
|
1115
|
-
|
|
1332
|
+
type: DataSourceType;
|
|
1116
1333
|
/**
|
|
1117
|
-
*
|
|
1334
|
+
* Job ID returned by `POST /prepare`
|
|
1118
1335
|
*/
|
|
1119
|
-
|
|
1336
|
+
jobId: string;
|
|
1337
|
+
};
|
|
1338
|
+
query?: never;
|
|
1339
|
+
url: "/backtest/{exchangeId}/{type}/prepare/{jobId}";
|
|
1120
1340
|
};
|
|
1121
1341
|
|
|
1122
|
-
export type
|
|
1342
|
+
export type GetPrepareStatusErrors = {
|
|
1343
|
+
/**
|
|
1344
|
+
* Invalid request or parameters
|
|
1345
|
+
*/
|
|
1346
|
+
400: ResponseError;
|
|
1347
|
+
/**
|
|
1348
|
+
* Prepare job not found or expired
|
|
1349
|
+
*/
|
|
1350
|
+
404: ResponseError;
|
|
1351
|
+
};
|
|
1352
|
+
|
|
1353
|
+
export type GetPrepareStatusError =
|
|
1354
|
+
GetPrepareStatusErrors[keyof GetPrepareStatusErrors];
|
|
1123
1355
|
|
|
1124
1356
|
export type GetPrepareStatusResponses = {
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1357
|
+
/**
|
|
1358
|
+
* Current prepare job state
|
|
1359
|
+
*/
|
|
1360
|
+
200: PrepareJobState;
|
|
1129
1361
|
};
|
|
1130
1362
|
|
|
1131
|
-
export type GetPrepareStatusResponse =
|
|
1363
|
+
export type GetPrepareStatusResponse =
|
|
1364
|
+
GetPrepareStatusResponses[keyof GetPrepareStatusResponses];
|
|
1132
1365
|
|
|
1133
1366
|
export type ExecuteSweepData = {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1367
|
+
body: ExecuteSweepRequest;
|
|
1368
|
+
path: {
|
|
1369
|
+
exchangeId: string;
|
|
1370
|
+
type: DataSourceType;
|
|
1371
|
+
/**
|
|
1372
|
+
* Job ID returned by `POST /backtest/{exchangeId}/{type}/prepare`.
|
|
1373
|
+
*/
|
|
1374
|
+
requestId: string;
|
|
1375
|
+
};
|
|
1376
|
+
query?: never;
|
|
1377
|
+
url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}";
|
|
1145
1378
|
};
|
|
1146
1379
|
|
|
1147
1380
|
export type ExecuteSweepErrors = {
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1381
|
+
/**
|
|
1382
|
+
* Invalid sweep specification or the expanded grid exceeds the server limit.
|
|
1383
|
+
*/
|
|
1384
|
+
400: ResponseError;
|
|
1385
|
+
/**
|
|
1386
|
+
* Prepared request not found or expired.
|
|
1387
|
+
*/
|
|
1388
|
+
404: ResponseError;
|
|
1389
|
+
/**
|
|
1390
|
+
* Sweep queue or user concurrency limit reached.
|
|
1391
|
+
*/
|
|
1392
|
+
429: ResponseError;
|
|
1160
1393
|
};
|
|
1161
1394
|
|
|
1162
1395
|
export type ExecuteSweepError = ExecuteSweepErrors[keyof ExecuteSweepErrors];
|
|
1163
1396
|
|
|
1164
1397
|
export type ExecuteSweepResponses = {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1398
|
+
/**
|
|
1399
|
+
* Sweep accepted. The effective seed is returned for reproducibility.
|
|
1400
|
+
*/
|
|
1401
|
+
202: ExecuteSweepAccepted;
|
|
1169
1402
|
};
|
|
1170
1403
|
|
|
1171
|
-
export type ExecuteSweepResponse =
|
|
1404
|
+
export type ExecuteSweepResponse =
|
|
1405
|
+
ExecuteSweepResponses[keyof ExecuteSweepResponses];
|
|
1172
1406
|
|
|
1173
1407
|
export type CancelSweepData = {
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1408
|
+
body?: never;
|
|
1409
|
+
path: {
|
|
1410
|
+
exchangeId: string;
|
|
1411
|
+
type: DataSourceType;
|
|
1412
|
+
requestId: string;
|
|
1413
|
+
sweepId: string;
|
|
1414
|
+
};
|
|
1415
|
+
query?: never;
|
|
1416
|
+
url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}";
|
|
1183
1417
|
};
|
|
1184
1418
|
|
|
1185
1419
|
export type CancelSweepErrors = {
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1420
|
+
/**
|
|
1421
|
+
* Sweep not found.
|
|
1422
|
+
*/
|
|
1423
|
+
404: ResponseError;
|
|
1190
1424
|
};
|
|
1191
1425
|
|
|
1192
1426
|
export type CancelSweepError = CancelSweepErrors[keyof CancelSweepErrors];
|
|
1193
1427
|
|
|
1194
1428
|
export type CancelSweepResponses = {
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1429
|
+
/**
|
|
1430
|
+
* Cancellation requested.
|
|
1431
|
+
*/
|
|
1432
|
+
200: {
|
|
1433
|
+
status: "cancelling";
|
|
1434
|
+
sweepId: string;
|
|
1435
|
+
};
|
|
1202
1436
|
};
|
|
1203
1437
|
|
|
1204
|
-
export type CancelSweepResponse =
|
|
1438
|
+
export type CancelSweepResponse =
|
|
1439
|
+
CancelSweepResponses[keyof CancelSweepResponses];
|
|
1205
1440
|
|
|
1206
1441
|
export type GetSweepResultData = {
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1442
|
+
body?: never;
|
|
1443
|
+
path: {
|
|
1444
|
+
exchangeId: string;
|
|
1445
|
+
type: DataSourceType;
|
|
1446
|
+
requestId: string;
|
|
1447
|
+
sweepId: string;
|
|
1448
|
+
};
|
|
1449
|
+
query?: {
|
|
1450
|
+
objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
|
|
1451
|
+
/**
|
|
1452
|
+
* `natural` is stable materialisation order; `ranked` is the display view.
|
|
1453
|
+
*/
|
|
1454
|
+
order?: "ranked" | "natural";
|
|
1455
|
+
/**
|
|
1456
|
+
* How the `ranked` view is ordered. `plateau` prefers points whose neighbourhood also scores well; `raw` uses the objective alone. Ignored when `order=natural`, which is always ordered by `runIx`.
|
|
1457
|
+
*/
|
|
1458
|
+
ranking?: "plateau" | "raw";
|
|
1459
|
+
};
|
|
1460
|
+
url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}";
|
|
1222
1461
|
};
|
|
1223
1462
|
|
|
1224
1463
|
export type GetSweepResultErrors = {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1464
|
+
/**
|
|
1465
|
+
* Sweep not found or expired.
|
|
1466
|
+
*/
|
|
1467
|
+
404: ResponseError;
|
|
1229
1468
|
};
|
|
1230
1469
|
|
|
1231
|
-
export type GetSweepResultError =
|
|
1470
|
+
export type GetSweepResultError =
|
|
1471
|
+
GetSweepResultErrors[keyof GetSweepResultErrors];
|
|
1232
1472
|
|
|
1233
1473
|
export type GetSweepResultResponses = {
|
|
1474
|
+
/**
|
|
1475
|
+
* Current sweep snapshot and all currently available result rows for the selected view.
|
|
1476
|
+
*/
|
|
1477
|
+
200: ExecuteSweepResult;
|
|
1478
|
+
};
|
|
1479
|
+
|
|
1480
|
+
export type GetSweepResultResponse =
|
|
1481
|
+
GetSweepResultResponses[keyof GetSweepResultResponses];
|
|
1482
|
+
|
|
1483
|
+
export type GetSweepSensitivityData = {
|
|
1484
|
+
body?: never;
|
|
1485
|
+
path: {
|
|
1486
|
+
exchangeId: string;
|
|
1487
|
+
type: DataSourceType;
|
|
1488
|
+
requestId: string;
|
|
1489
|
+
sweepId: string;
|
|
1490
|
+
};
|
|
1491
|
+
query?: {
|
|
1234
1492
|
/**
|
|
1235
|
-
*
|
|
1493
|
+
* Which metric to aggregate. Defaults to the objective the sweep was submitted with.
|
|
1236
1494
|
*/
|
|
1237
|
-
|
|
1495
|
+
objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
|
|
1496
|
+
};
|
|
1497
|
+
url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}/sensitivity";
|
|
1238
1498
|
};
|
|
1239
1499
|
|
|
1240
|
-
export type
|
|
1500
|
+
export type GetSweepSensitivityErrors = {
|
|
1501
|
+
/**
|
|
1502
|
+
* Sweep not found or expired.
|
|
1503
|
+
*/
|
|
1504
|
+
404: ResponseError;
|
|
1505
|
+
};
|
|
1506
|
+
|
|
1507
|
+
export type GetSweepSensitivityError =
|
|
1508
|
+
GetSweepSensitivityErrors[keyof GetSweepSensitivityErrors];
|
|
1509
|
+
|
|
1510
|
+
export type GetSweepSensitivityResponses = {
|
|
1511
|
+
/**
|
|
1512
|
+
* Sensitivity aggregates over the rows available so far.
|
|
1513
|
+
*/
|
|
1514
|
+
200: SweepSensitivity;
|
|
1515
|
+
};
|
|
1516
|
+
|
|
1517
|
+
export type GetSweepSensitivityResponse =
|
|
1518
|
+
GetSweepSensitivityResponses[keyof GetSweepSensitivityResponses];
|
|
1241
1519
|
|
|
1242
1520
|
export type ExecuteBacktestData = {
|
|
1521
|
+
/**
|
|
1522
|
+
* Execute task parameters
|
|
1523
|
+
*/
|
|
1524
|
+
body: {
|
|
1243
1525
|
/**
|
|
1244
|
-
*
|
|
1526
|
+
* Job ID returned by `POST /prepare` (must be in `Completed` state)
|
|
1245
1527
|
*/
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
* Job ID returned by `POST /prepare` (must be in `Completed` state)
|
|
1249
|
-
*/
|
|
1250
|
-
prepareJobId: string;
|
|
1251
|
-
strategyId: StrategyId;
|
|
1252
|
-
/**
|
|
1253
|
-
* When true, the worker uploads emitted signals to object storage and the
|
|
1254
|
-
* response includes `signalsUrl` / `signalsId` fields. Defaults to false.
|
|
1255
|
-
*
|
|
1256
|
-
*/
|
|
1257
|
-
storeSignals?: boolean;
|
|
1258
|
-
};
|
|
1259
|
-
path: {
|
|
1260
|
-
/**
|
|
1261
|
-
* ID of the exchange for the backtesting process
|
|
1262
|
-
*/
|
|
1263
|
-
exchangeId: string;
|
|
1264
|
-
/**
|
|
1265
|
-
* The type of data source to execute from
|
|
1266
|
-
*/
|
|
1267
|
-
type: DataSourceType;
|
|
1268
|
-
};
|
|
1269
|
-
query?: never;
|
|
1270
|
-
url: '/backtest/{exchangeId}/{type}/execute';
|
|
1271
|
-
};
|
|
1272
|
-
|
|
1273
|
-
export type ExecuteBacktestErrors = {
|
|
1528
|
+
prepareJobId: string;
|
|
1529
|
+
strategyId: StrategyId;
|
|
1274
1530
|
/**
|
|
1275
|
-
*
|
|
1531
|
+
* When true, the worker uploads emitted signals to object storage and the
|
|
1532
|
+
* response includes `signalsUrl` / `signalsId` fields. Defaults to false.
|
|
1533
|
+
*
|
|
1276
1534
|
*/
|
|
1277
|
-
|
|
1535
|
+
storeSignals?: boolean;
|
|
1536
|
+
};
|
|
1537
|
+
path: {
|
|
1278
1538
|
/**
|
|
1279
|
-
*
|
|
1539
|
+
* ID of the exchange for the backtesting process
|
|
1280
1540
|
*/
|
|
1281
|
-
|
|
1541
|
+
exchangeId: string;
|
|
1282
1542
|
/**
|
|
1283
|
-
*
|
|
1543
|
+
* The type of data source to execute from
|
|
1284
1544
|
*/
|
|
1285
|
-
|
|
1545
|
+
type: DataSourceType;
|
|
1546
|
+
};
|
|
1547
|
+
query?: never;
|
|
1548
|
+
url: "/backtest/{exchangeId}/{type}/execute";
|
|
1286
1549
|
};
|
|
1287
1550
|
|
|
1288
|
-
export type
|
|
1551
|
+
export type ExecuteBacktestErrors = {
|
|
1552
|
+
/**
|
|
1553
|
+
* Invalid request or parameters
|
|
1554
|
+
*/
|
|
1555
|
+
400: ResponseError;
|
|
1556
|
+
/**
|
|
1557
|
+
* Prepare job not found or expired
|
|
1558
|
+
*/
|
|
1559
|
+
404: ResponseError;
|
|
1560
|
+
/**
|
|
1561
|
+
* Rate limited (global queue at capacity or per-user limit reached)
|
|
1562
|
+
*/
|
|
1563
|
+
429: ResponseError;
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
export type ExecuteBacktestError =
|
|
1567
|
+
ExecuteBacktestErrors[keyof ExecuteBacktestErrors];
|
|
1289
1568
|
|
|
1290
1569
|
export type ExecuteBacktestResponses = {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1570
|
+
/**
|
|
1571
|
+
* Execute task accepted (queued for processing)
|
|
1572
|
+
*/
|
|
1573
|
+
202: AcceptedJob;
|
|
1295
1574
|
};
|
|
1296
1575
|
|
|
1297
|
-
export type ExecuteBacktestResponse =
|
|
1576
|
+
export type ExecuteBacktestResponse =
|
|
1577
|
+
ExecuteBacktestResponses[keyof ExecuteBacktestResponses];
|
|
1298
1578
|
|
|
1299
1579
|
export type CancelBacktestData = {
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1580
|
+
body?: never;
|
|
1581
|
+
path: {
|
|
1582
|
+
exchangeId: string;
|
|
1583
|
+
type: DataSourceType;
|
|
1584
|
+
/**
|
|
1585
|
+
* Job ID returned by `POST /execute`
|
|
1586
|
+
*/
|
|
1587
|
+
jobId: string;
|
|
1588
|
+
};
|
|
1589
|
+
query?: never;
|
|
1590
|
+
url: "/backtest/{exchangeId}/{type}/execute/{jobId}";
|
|
1311
1591
|
};
|
|
1312
1592
|
|
|
1313
1593
|
export type CancelBacktestErrors = {
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1594
|
+
/**
|
|
1595
|
+
* Execution not found
|
|
1596
|
+
*/
|
|
1597
|
+
404: ResponseError;
|
|
1318
1598
|
};
|
|
1319
1599
|
|
|
1320
|
-
export type CancelBacktestError =
|
|
1600
|
+
export type CancelBacktestError =
|
|
1601
|
+
CancelBacktestErrors[keyof CancelBacktestErrors];
|
|
1321
1602
|
|
|
1322
1603
|
export type CancelBacktestResponses = {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1604
|
+
/**
|
|
1605
|
+
* Cancellation request accepted
|
|
1606
|
+
*/
|
|
1607
|
+
200: {
|
|
1608
|
+
status?: "cancelling";
|
|
1609
|
+
jobId?: string;
|
|
1610
|
+
};
|
|
1330
1611
|
};
|
|
1331
1612
|
|
|
1332
|
-
export type CancelBacktestResponse =
|
|
1613
|
+
export type CancelBacktestResponse =
|
|
1614
|
+
CancelBacktestResponses[keyof CancelBacktestResponses];
|
|
1333
1615
|
|
|
1334
1616
|
export type GetBacktestResultData = {
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
/**
|
|
1338
|
-
* ID of the exchange for the backtesting process
|
|
1339
|
-
*/
|
|
1340
|
-
exchangeId: string;
|
|
1341
|
-
/**
|
|
1342
|
-
* The type of data source to execute from
|
|
1343
|
-
*/
|
|
1344
|
-
type: DataSourceType;
|
|
1345
|
-
/**
|
|
1346
|
-
* Job ID returned by `POST /execute`
|
|
1347
|
-
*/
|
|
1348
|
-
jobId: string;
|
|
1349
|
-
};
|
|
1350
|
-
query?: never;
|
|
1351
|
-
url: '/backtest/{exchangeId}/{type}/execute/{jobId}';
|
|
1352
|
-
};
|
|
1353
|
-
|
|
1354
|
-
export type GetBacktestResultErrors = {
|
|
1617
|
+
body?: never;
|
|
1618
|
+
path: {
|
|
1355
1619
|
/**
|
|
1356
|
-
*
|
|
1620
|
+
* ID of the exchange for the backtesting process
|
|
1357
1621
|
*/
|
|
1358
|
-
|
|
1359
|
-
/**
|
|
1360
|
-
* Execution job not found
|
|
1361
|
-
*/
|
|
1362
|
-
404: ResponseError;
|
|
1363
|
-
};
|
|
1364
|
-
|
|
1365
|
-
export type GetBacktestResultError = GetBacktestResultErrors[keyof GetBacktestResultErrors];
|
|
1366
|
-
|
|
1367
|
-
export type GetBacktestResultResponses = {
|
|
1622
|
+
exchangeId: string;
|
|
1368
1623
|
/**
|
|
1369
|
-
*
|
|
1624
|
+
* The type of data source to execute from
|
|
1370
1625
|
*/
|
|
1371
|
-
|
|
1626
|
+
type: DataSourceType;
|
|
1372
1627
|
/**
|
|
1373
|
-
*
|
|
1374
|
-
*
|
|
1375
|
-
* Returned in two situations, both of which mean "ask again", never "you are done":
|
|
1376
|
-
* the job has not produced its result yet, or the job reached a terminal status while
|
|
1377
|
-
* its stored result could not be read back. The response body is an empty object: it
|
|
1378
|
-
* deliberately carries no `state`, so a client cannot mistake it for a finished result.
|
|
1379
|
-
*
|
|
1380
|
-
* Treat any `202` as a signal to continue the poll loop under your existing timeout.
|
|
1381
|
-
* Never treat it as a terminal outcome.
|
|
1382
|
-
*
|
|
1628
|
+
* Job ID returned by `POST /execute`
|
|
1383
1629
|
*/
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1630
|
+
jobId: string;
|
|
1631
|
+
};
|
|
1632
|
+
query?: never;
|
|
1633
|
+
url: "/backtest/{exchangeId}/{type}/execute/{jobId}";
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
export type GetBacktestResultErrors = {
|
|
1637
|
+
/**
|
|
1638
|
+
* Invalid request or parameters
|
|
1639
|
+
*/
|
|
1640
|
+
400: ResponseError;
|
|
1641
|
+
/**
|
|
1642
|
+
* Execution job not found
|
|
1643
|
+
*/
|
|
1644
|
+
404: ResponseError;
|
|
1387
1645
|
};
|
|
1388
1646
|
|
|
1389
|
-
export type
|
|
1647
|
+
export type GetBacktestResultError =
|
|
1648
|
+
GetBacktestResultErrors[keyof GetBacktestResultErrors];
|
|
1649
|
+
|
|
1650
|
+
export type GetBacktestResultResponses = {
|
|
1651
|
+
/**
|
|
1652
|
+
* Backtesting execution result
|
|
1653
|
+
*/
|
|
1654
|
+
200: BacktestJobResult;
|
|
1655
|
+
/**
|
|
1656
|
+
* The job is known but its result is not readable yet — keep polling.
|
|
1657
|
+
*
|
|
1658
|
+
* Returned in two situations, both of which mean "ask again", never "you are done":
|
|
1659
|
+
* the job has not produced its result yet, or the job reached a terminal status while
|
|
1660
|
+
* its stored result could not be read back. The response body is an empty object: it
|
|
1661
|
+
* deliberately carries no `state`, so a client cannot mistake it for a finished result.
|
|
1662
|
+
*
|
|
1663
|
+
* Treat any `202` as a signal to continue the poll loop under your existing timeout.
|
|
1664
|
+
* Never treat it as a terminal outcome.
|
|
1665
|
+
*
|
|
1666
|
+
*/
|
|
1667
|
+
202: {
|
|
1668
|
+
[key: string]: never;
|
|
1669
|
+
};
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
export type GetBacktestResultResponse =
|
|
1673
|
+
GetBacktestResultResponses[keyof GetBacktestResultResponses];
|
|
1390
1674
|
|
|
1391
1675
|
export type ClientOptions = {
|
|
1392
|
-
|
|
1393
|
-
|
|
1676
|
+
baseUrl:
|
|
1677
|
+
| "https://api.staging.qtsurfer.com/v1"
|
|
1678
|
+
| "https://api.qtsurfer.com/v1"
|
|
1679
|
+
| (string & {});
|
|
1680
|
+
};
|