@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/dist/index.d.ts CHANGED
@@ -44,7 +44,7 @@ type InstrumentListMeta = {
44
44
  /**
45
45
  * The market segment served in `data`
46
46
  */
47
- segment: 'spot' | 'futures';
47
+ segment: "spot" | "futures";
48
48
  };
49
49
  /**
50
50
  * HAL `_links` — segment discovery for the instruments listing
@@ -152,7 +152,7 @@ type Exchange = {
152
152
  /**
153
153
  * Managed exchange data sources available for backtesting.
154
154
  */
155
- type DataSourceType = 'ticker';
155
+ type DataSourceType = "ticker";
156
156
  type PrepareRequest = {
157
157
  instrument: Instrument;
158
158
  /**
@@ -179,7 +179,7 @@ type PrepareRequest = {
179
179
  * labels return `400`.
180
180
  *
181
181
  */
182
- cadence?: '1s' | '5s' | '1m' | '5m' | '15m' | '1h' | '4h' | '1d';
182
+ cadence?: "1s" | "5s" | "1m" | "5m" | "15m" | "1h" | "4h" | "1d";
183
183
  };
184
184
  /**
185
185
  * Information about a single job
@@ -196,7 +196,7 @@ type JobState = {
196
196
  * `PrepareJobState.coverageRatio`, not by polling.
197
197
  *
198
198
  */
199
- status: 'New' | 'Started' | 'Completed' | 'Aborted' | 'Failed';
199
+ status: "New" | "Started" | "Completed" | "Aborted" | "Failed";
200
200
  /**
201
201
  * Detailed status information, if available
202
202
  */
@@ -270,7 +270,7 @@ type PrepareJobState = JobState & {
270
270
  * instrument did not trade that hour. `unknown`: no data to classify by.
271
271
  *
272
272
  */
273
- rationale?: 'pending_conversion' | 'low_activity' | 'unknown';
273
+ rationale?: "pending_conversion" | "low_activity" | "unknown";
274
274
  }>;
275
275
  };
276
276
  /**
@@ -284,7 +284,7 @@ type SweepAxis = {
284
284
  values: Array<number | boolean>;
285
285
  };
286
286
  type SweepSpecRequest = {
287
- sampler?: 'grid' | 'random' | 'lhs';
287
+ sampler?: "grid" | "random" | "lhs";
288
288
  /**
289
289
  * Reproducibility seed. If omitted, the server generates one with Java's
290
290
  * `L64X128MixRandom` generator and returns the effective value. The range
@@ -296,7 +296,7 @@ type SweepSpecRequest = {
296
296
  * Number of samples for `random` and `lhs`; ignored by `grid`.
297
297
  */
298
298
  samples?: number;
299
- objective?: 'sharpe' | 'sortino' | 'pnl' | 'maxdd';
299
+ objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
300
300
  params: {
301
301
  [key: string]: SweepAxis;
302
302
  };
@@ -306,7 +306,7 @@ type SweepBaseConfig = {
306
306
  feeRate?: number;
307
307
  buyFeeRate?: number;
308
308
  sellFeeRate?: number;
309
- feeLeg?: 'RECEIVED' | 'QUOTE' | 'BASE';
309
+ feeLeg?: "RECEIVED" | "QUOTE" | "BASE";
310
310
  percentAmountToLock?: number;
311
311
  };
312
312
  type ExecuteSweepRequest = {
@@ -325,6 +325,21 @@ type ExecuteSweepRequest = {
325
325
  * Trials below this trade count are flagged but remain in the results.
326
326
  */
327
327
  minTradeFloor?: number;
328
+ walkForward?: WalkForwardRequest;
329
+ };
330
+ /**
331
+ * 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.
332
+ */
333
+ type WalkForwardRequest = {
334
+ /**
335
+ * 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.
336
+ * 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.
337
+ */
338
+ folds: number;
339
+ /**
340
+ * 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.
341
+ */
342
+ inSamplePct?: number;
328
343
  };
329
344
  type ExecuteSweepAccepted = {
330
345
  sweepId: string;
@@ -339,13 +354,51 @@ type ExecuteSweepAccepted = {
339
354
  * False when an identical sweep already exists and was not enqueued again.
340
355
  */
341
356
  queued: boolean;
357
+ walkForward?: WalkForwardAccepted;
342
358
  };
359
+ /**
360
+ * 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.
361
+ */
362
+ type WalkForwardAccepted = {
363
+ folds: number;
364
+ inSamplePct: number;
365
+ /**
366
+ * 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.
367
+ */
368
+ totalRuns: number;
369
+ };
370
+ /**
371
+ * 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.
372
+ */
343
373
  type SweepProgress = {
344
374
  done: number;
345
375
  total: number;
376
+ /**
377
+ * 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.
378
+ */
346
379
  aborted: number;
347
380
  shardCount: number;
348
381
  pendingShards: number;
382
+ /**
383
+ * 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.
384
+ */
385
+ failedShards: number;
386
+ /**
387
+ * 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.
388
+ */
389
+ retrying: number;
390
+ /**
391
+ * 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.
392
+ */
393
+ notStarted: number;
394
+ /**
395
+ * 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.
396
+ */
397
+ stalledSeconds?: number;
398
+ /**
399
+ * 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.
400
+ */
401
+ etaSeconds?: number;
349
402
  };
350
403
  type SweepRunRow = {
351
404
  /**
@@ -356,6 +409,18 @@ type SweepRunRow = {
356
409
  * Present only in the `ranked` view.
357
410
  */
358
411
  rank?: number;
412
+ /**
413
+ * 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`.
414
+ */
415
+ plateauScore?: number;
416
+ /**
417
+ * 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.
418
+ */
419
+ neighbourCount?: number;
420
+ /**
421
+ * 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.
422
+ */
423
+ deflatedSharpe?: number;
359
424
  params: {
360
425
  [key: string]: unknown;
361
426
  };
@@ -374,11 +439,84 @@ type SweepRunRow = {
374
439
  aborted: boolean;
375
440
  runtimeMs: number;
376
441
  };
442
+ /**
443
+ * Sensitivity aggregates over a sweep's stored rows. Marginals are always complete; heatmaps may be capped, in which case `heatmapsTruncated` is true.
444
+ */
445
+ type SweepSensitivity = {
446
+ sweepId?: string;
447
+ status?: "RUNNING" | "COMPLETED" | "PARTIAL" | "CANCELLED";
448
+ objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
449
+ /**
450
+ * Rows available when this was computed. Grows while a sweep is still running.
451
+ */
452
+ rowsAnalysed?: number;
453
+ marginals?: Array<SweepMarginal>;
454
+ heatmaps?: Array<SweepHeatmap>;
455
+ /**
456
+ * 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.
457
+ */
458
+ heatmapsTruncated?: boolean;
459
+ };
460
+ /**
461
+ * One axis, with every other axis collapsed away.
462
+ */
463
+ type SweepMarginal = {
464
+ param?: string;
465
+ points?: Array<SweepMarginalPoint>;
466
+ };
467
+ /**
468
+ * 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.
469
+ */
470
+ type SweepMarginalPoint = {
471
+ /**
472
+ * The axis value, as it appears in a run's parameters.
473
+ */
474
+ value?: unknown;
475
+ /**
476
+ * Non-aborted runs that used this value.
477
+ */
478
+ count?: number;
479
+ best?: number;
480
+ mean?: number;
481
+ worst?: number;
482
+ };
483
+ /**
484
+ * The surface for one pair of axes, with all others collapsed away.
485
+ */
486
+ type SweepHeatmap = {
487
+ paramA?: string;
488
+ paramB?: string;
489
+ cells?: Array<SweepHeatmapCell>;
490
+ };
491
+ type SweepHeatmapCell = {
492
+ valueA?: unknown;
493
+ valueB?: unknown;
494
+ count?: number;
495
+ best?: number;
496
+ mean?: number;
497
+ };
377
498
  type ExecuteSweepResult = {
378
499
  sweepId: string;
379
- status: 'RUNNING' | 'COMPLETED' | 'PARTIAL' | 'CANCELLED';
380
- objective: 'sharpe' | 'sortino' | 'pnl' | 'maxdd';
381
- order: 'ranked' | 'natural';
500
+ status: "RUNNING" | "COMPLETED" | "PARTIAL" | "CANCELLED";
501
+ objective: "sharpe" | "sortino" | "pnl" | "maxdd";
502
+ order: "ranked" | "natural";
503
+ /**
504
+ * 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`.
505
+ */
506
+ ranking?: "plateau" | "raw";
507
+ /**
508
+ * 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.
509
+ */
510
+ pbo?: number;
511
+ /**
512
+ * How many train/test splits the `pbo` figure was averaged over.
513
+ */
514
+ pboSplits?: number;
515
+ /**
516
+ * 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.
517
+ * 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.
518
+ */
519
+ failReason?: string;
382
520
  progress: SweepProgress;
383
521
  /**
384
522
  * Total result rows currently available.
@@ -389,6 +527,68 @@ type ExecuteSweepResult = {
389
527
  */
390
528
  truncated: boolean;
391
529
  leaderboard: Array<SweepRunRow>;
530
+ walkForward?: WalkForwardResult;
531
+ };
532
+ /**
533
+ * 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.
534
+ */
535
+ type WalkForwardResult = {
536
+ /**
537
+ * Folds requested at submit.
538
+ */
539
+ folds: number;
540
+ /**
541
+ * Resolved in-sample share each fold optimized on.
542
+ */
543
+ inSamplePct?: number;
544
+ /**
545
+ * Folds that have finished and reported a winner.
546
+ */
547
+ completedFolds: number;
548
+ /**
549
+ * 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.
550
+ */
551
+ paramDrift?: number;
552
+ /**
553
+ * One entry per completed fold, oldest first.
554
+ */
555
+ results: Array<WalkForwardFold>;
556
+ };
557
+ /**
558
+ * 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.
559
+ */
560
+ type WalkForwardFold = {
561
+ /**
562
+ * Position in the walk-forward sequence, oldest first.
563
+ */
564
+ foldIx: number;
565
+ /**
566
+ * First index of the optimization window, into the prepared session.
567
+ */
568
+ inSampleFrom: number;
569
+ /**
570
+ * End of the optimization window, exclusive — and where scoring begins.
571
+ */
572
+ inSampleTo: number;
573
+ /**
574
+ * End of the scoring window, exclusive.
575
+ */
576
+ outOfSampleTo: number;
577
+ /**
578
+ * The parameter vector that won this fold's optimization window.
579
+ */
580
+ params: {
581
+ [key: string]: unknown;
582
+ };
583
+ /**
584
+ * How that winner scored on the window it was chosen on.
585
+ */
586
+ inSampleSharpe: number;
587
+ outOfSample: SweepRunRow;
588
+ /**
589
+ * Vectors this fold evaluated in-sample before picking its winner.
590
+ */
591
+ vectorsRun: number;
392
592
  };
393
593
  /**
394
594
  * Response returned by async endpoints (`202 Accepted`). The `jobId` is deterministic for the
@@ -506,7 +706,7 @@ type ResultMap = {
506
706
  /**
507
707
  * Upload status. Done = signal file is available at signalsUrl. Failed = upload error (see signalsUploadReason). Skipped = no signals emitted.
508
708
  */
509
- signalsUpload?: 'Done' | 'Failed' | 'Skipped';
709
+ signalsUpload?: "Done" | "Failed" | "Skipped";
510
710
  /**
511
711
  * ISO 8601 timestamp of when the upload completed. Only present when signalsUpload is Done.
512
712
  */
@@ -560,7 +760,7 @@ type Notice = {
560
760
  * `compile-dry-run` is only a lower bound over a bounded synthetic series.
561
761
  *
562
762
  */
563
- provenance?: 'execute' | 'compile-dry-run';
763
+ provenance?: "execute" | "compile-dry-run";
564
764
  };
565
765
  /**
566
766
  * What is known about a registered strategy: that it compiled, and what validating it found.
@@ -580,7 +780,7 @@ type StrategyState = {
580
780
  * * `failed` — it did not; `detail` says how.
581
781
  *
582
782
  */
583
- validation: 'not_validated' | 'pending' | 'passed' | 'failed';
783
+ validation: "not_validated" | "pending" | "passed" | "failed";
584
784
  /**
585
785
  * When the live compilation was produced.
586
786
  */
@@ -598,7 +798,7 @@ type StrategyState = {
598
798
  * re-registering the source fills it in.
599
799
  *
600
800
  */
601
- requiredSources?: Array<'Ticker' | 'KLine' | 'FundingRate'>;
801
+ requiredSources?: Array<"Ticker" | "KLine" | "FundingRate">;
602
802
  /**
603
803
  * When the verdict was recorded. Absent until there is one.
604
804
  */
@@ -642,7 +842,7 @@ type AuthTokenResponse = {
642
842
  /**
643
843
  * Always `Bearer`.
644
844
  */
645
- token_type: 'Bearer';
845
+ token_type: "Bearer";
646
846
  /**
647
847
  * Seconds until the JWT expires (typically 3600).
648
848
  */
@@ -654,7 +854,7 @@ type AuthTokenResponse = {
654
854
  /**
655
855
  * Subscription tier this token was issued for. Drives rate limits and feature flags on downstream endpoints.
656
856
  */
657
- tier: 'free' | 'basic' | 'pro' | 'elite';
857
+ tier: "free" | "basic" | "pro" | "elite";
658
858
  };
659
859
  /**
660
860
  * Error envelope returned by `POST /auth/token` when the API key is rejected.
@@ -663,7 +863,7 @@ type AuthTokenError = {
663
863
  /**
664
864
  * Machine-readable error reason.
665
865
  */
666
- code: 'invalid_apikey' | 'apikey_revoked' | 'apikey_expired';
866
+ code: "invalid_apikey" | "apikey_revoked" | "apikey_expired";
667
867
  /**
668
868
  * Human-readable description of the failure.
669
869
  */
@@ -673,7 +873,7 @@ type AuthenticateData = {
673
873
  body?: never;
674
874
  path?: never;
675
875
  query?: never;
676
- url: '/auth/token';
876
+ url: "/auth/token";
677
877
  };
678
878
  type AuthenticateErrors = {
679
879
  /**
@@ -697,7 +897,7 @@ type ListExchangesData = {
697
897
  body?: never;
698
898
  path?: never;
699
899
  query?: never;
700
- url: '/exchanges';
900
+ url: "/exchanges";
701
901
  };
702
902
  type ListExchangesResponses = {
703
903
  /**
@@ -715,7 +915,7 @@ type ListInstrumentsData = {
715
915
  exchangeId: string;
716
916
  };
717
917
  query?: never;
718
- url: '/exchange/{exchangeId}/instruments';
918
+ url: "/exchange/{exchangeId}/instruments";
719
919
  };
720
920
  type ListInstrumentsErrors = {
721
921
  /**
@@ -741,10 +941,10 @@ type ListSegmentInstrumentsData = {
741
941
  /**
742
942
  * Market segment to list instruments for
743
943
  */
744
- segment: 'spot' | 'futures';
944
+ segment: "spot" | "futures";
745
945
  };
746
946
  query?: never;
747
- url: '/exchange/{exchangeId}/{segment}/instruments';
947
+ url: "/exchange/{exchangeId}/{segment}/instruments";
748
948
  };
749
949
  type ListSegmentInstrumentsErrors = {
750
950
  /**
@@ -789,9 +989,9 @@ type DownloadTickersData = {
789
989
  * [lastra-convert](https://github.com/QTSurfer/lastra-convert).
790
990
  *
791
991
  */
792
- format?: 'lastra' | 'parquet';
992
+ format?: "lastra" | "parquet";
793
993
  };
794
- url: '/exchange/{exchangeId}/tickers/{base}/{quote}';
994
+ url: "/exchange/{exchangeId}/tickers/{base}/{quote}";
795
995
  };
796
996
  type DownloadTickersErrors = {
797
997
  /**
@@ -847,9 +1047,9 @@ type DownloadKlinesData = {
847
1047
  * `parquet` returns Parquet via on-the-fly conversion.
848
1048
  *
849
1049
  */
850
- format?: 'lastra' | 'parquet';
1050
+ format?: "lastra" | "parquet";
851
1051
  };
852
- url: '/exchange/{exchangeId}/klines/{base}/{quote}';
1052
+ url: "/exchange/{exchangeId}/klines/{base}/{quote}";
853
1053
  };
854
1054
  type DownloadKlinesErrors = {
855
1055
  /**
@@ -883,7 +1083,7 @@ type CompileStrategyData = {
883
1083
  body: string;
884
1084
  path?: never;
885
1085
  query?: never;
886
- url: '/strategy';
1086
+ url: "/strategy";
887
1087
  };
888
1088
  type CompileStrategyErrors = {
889
1089
  /**
@@ -916,7 +1116,7 @@ type ValidateStrategyData = {
916
1116
  strategyId: StrategyId;
917
1117
  };
918
1118
  query?: never;
919
- url: '/strategy/{strategyId}/validate';
1119
+ url: "/strategy/{strategyId}/validate";
920
1120
  };
921
1121
  type ValidateStrategyErrors = {
922
1122
  /**
@@ -934,11 +1134,14 @@ type ValidateStrategyResponses = {
934
1134
  * Validation queued. Not a terminal outcome — poll `GET /strategy/{strategyId}` until
935
1135
  * `validation` leaves `pending`.
936
1136
  *
1137
+ * The body is a `StrategyState` carrying only what is known at this point: the id and
1138
+ * `validation: pending`. **The status code, not the body, is what tells the two responses
1139
+ * apart** — a `200` can also carry `validation: pending`, left by a check an earlier call
1140
+ * queued. So `202` means *this call started a check*, while `pending` means only *a check
1141
+ * is outstanding*.
1142
+ *
937
1143
  */
938
- 202: {
939
- strategyId: StrategyId;
940
- validation: 'pending';
941
- };
1144
+ 202: StrategyState;
942
1145
  };
943
1146
  type ValidateStrategyResponse = ValidateStrategyResponses[keyof ValidateStrategyResponses];
944
1147
  type GetStrategyData = {
@@ -950,7 +1153,7 @@ type GetStrategyData = {
950
1153
  strategyId: StrategyId;
951
1154
  };
952
1155
  query?: never;
953
- url: '/strategy/{strategyId}';
1156
+ url: "/strategy/{strategyId}";
954
1157
  };
955
1158
  type GetStrategyErrors = {
956
1159
  /**
@@ -982,7 +1185,7 @@ type PrepareBacktestData = {
982
1185
  type: DataSourceType;
983
1186
  };
984
1187
  query?: never;
985
- url: '/backtest/{exchangeId}/{type}/prepare';
1188
+ url: "/backtest/{exchangeId}/{type}/prepare";
986
1189
  };
987
1190
  type PrepareBacktestErrors = {
988
1191
  /**
@@ -1027,7 +1230,7 @@ type GetPrepareStatusData = {
1027
1230
  jobId: string;
1028
1231
  };
1029
1232
  query?: never;
1030
- url: '/backtest/{exchangeId}/{type}/prepare/{jobId}';
1233
+ url: "/backtest/{exchangeId}/{type}/prepare/{jobId}";
1031
1234
  };
1032
1235
  type GetPrepareStatusErrors = {
1033
1236
  /**
@@ -1058,7 +1261,7 @@ type ExecuteSweepData = {
1058
1261
  requestId: string;
1059
1262
  };
1060
1263
  query?: never;
1061
- url: '/backtest/{exchangeId}/{type}/executeSweep/{requestId}';
1264
+ url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}";
1062
1265
  };
1063
1266
  type ExecuteSweepErrors = {
1064
1267
  /**
@@ -1091,7 +1294,7 @@ type CancelSweepData = {
1091
1294
  sweepId: string;
1092
1295
  };
1093
1296
  query?: never;
1094
- url: '/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}';
1297
+ url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}";
1095
1298
  };
1096
1299
  type CancelSweepErrors = {
1097
1300
  /**
@@ -1105,7 +1308,7 @@ type CancelSweepResponses = {
1105
1308
  * Cancellation requested.
1106
1309
  */
1107
1310
  200: {
1108
- status: 'cancelling';
1311
+ status: "cancelling";
1109
1312
  sweepId: string;
1110
1313
  };
1111
1314
  };
@@ -1119,13 +1322,17 @@ type GetSweepResultData = {
1119
1322
  sweepId: string;
1120
1323
  };
1121
1324
  query?: {
1122
- objective?: 'sharpe' | 'sortino' | 'pnl' | 'maxdd';
1325
+ objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
1123
1326
  /**
1124
1327
  * `natural` is stable materialisation order; `ranked` is the display view.
1125
1328
  */
1126
- order?: 'ranked' | 'natural';
1329
+ order?: "ranked" | "natural";
1330
+ /**
1331
+ * 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`.
1332
+ */
1333
+ ranking?: "plateau" | "raw";
1127
1334
  };
1128
- url: '/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}';
1335
+ url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}";
1129
1336
  };
1130
1337
  type GetSweepResultErrors = {
1131
1338
  /**
@@ -1141,6 +1348,36 @@ type GetSweepResultResponses = {
1141
1348
  200: ExecuteSweepResult;
1142
1349
  };
1143
1350
  type GetSweepResultResponse = GetSweepResultResponses[keyof GetSweepResultResponses];
1351
+ type GetSweepSensitivityData = {
1352
+ body?: never;
1353
+ path: {
1354
+ exchangeId: string;
1355
+ type: DataSourceType;
1356
+ requestId: string;
1357
+ sweepId: string;
1358
+ };
1359
+ query?: {
1360
+ /**
1361
+ * Which metric to aggregate. Defaults to the objective the sweep was submitted with.
1362
+ */
1363
+ objective?: "sharpe" | "sortino" | "pnl" | "maxdd";
1364
+ };
1365
+ url: "/backtest/{exchangeId}/{type}/executeSweep/{requestId}/{sweepId}/sensitivity";
1366
+ };
1367
+ type GetSweepSensitivityErrors = {
1368
+ /**
1369
+ * Sweep not found or expired.
1370
+ */
1371
+ 404: ResponseError;
1372
+ };
1373
+ type GetSweepSensitivityError = GetSweepSensitivityErrors[keyof GetSweepSensitivityErrors];
1374
+ type GetSweepSensitivityResponses = {
1375
+ /**
1376
+ * Sensitivity aggregates over the rows available so far.
1377
+ */
1378
+ 200: SweepSensitivity;
1379
+ };
1380
+ type GetSweepSensitivityResponse = GetSweepSensitivityResponses[keyof GetSweepSensitivityResponses];
1144
1381
  type ExecuteBacktestData = {
1145
1382
  /**
1146
1383
  * Execute task parameters
@@ -1169,7 +1406,7 @@ type ExecuteBacktestData = {
1169
1406
  type: DataSourceType;
1170
1407
  };
1171
1408
  query?: never;
1172
- url: '/backtest/{exchangeId}/{type}/execute';
1409
+ url: "/backtest/{exchangeId}/{type}/execute";
1173
1410
  };
1174
1411
  type ExecuteBacktestErrors = {
1175
1412
  /**
@@ -1204,7 +1441,7 @@ type CancelBacktestData = {
1204
1441
  jobId: string;
1205
1442
  };
1206
1443
  query?: never;
1207
- url: '/backtest/{exchangeId}/{type}/execute/{jobId}';
1444
+ url: "/backtest/{exchangeId}/{type}/execute/{jobId}";
1208
1445
  };
1209
1446
  type CancelBacktestErrors = {
1210
1447
  /**
@@ -1218,7 +1455,7 @@ type CancelBacktestResponses = {
1218
1455
  * Cancellation request accepted
1219
1456
  */
1220
1457
  200: {
1221
- status?: 'cancelling';
1458
+ status?: "cancelling";
1222
1459
  jobId?: string;
1223
1460
  };
1224
1461
  };
@@ -1240,7 +1477,7 @@ type GetBacktestResultData = {
1240
1477
  jobId: string;
1241
1478
  };
1242
1479
  query?: never;
1243
- url: '/backtest/{exchangeId}/{type}/execute/{jobId}';
1480
+ url: "/backtest/{exchangeId}/{type}/execute/{jobId}";
1244
1481
  };
1245
1482
  type GetBacktestResultErrors = {
1246
1483
  /**
@@ -1276,7 +1513,7 @@ type GetBacktestResultResponses = {
1276
1513
  };
1277
1514
  type GetBacktestResultResponse = GetBacktestResultResponses[keyof GetBacktestResultResponses];
1278
1515
  type ClientOptions = {
1279
- baseUrl: 'https://api.staging.qtsurfer.com/v1' | 'https://api.qtsurfer.com/v1' | (string & {});
1516
+ baseUrl: "https://api.staging.qtsurfer.com/v1" | "https://api.qtsurfer.com/v1" | (string & {});
1280
1517
  };
1281
1518
 
1282
1519
  type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = Options$1<TData, ThrowOnError> & {
@@ -1415,7 +1652,7 @@ declare const compileStrategy: <ThrowOnError extends boolean = false>(options: O
1415
1652
  * bytecode that is no longer what would run.
1416
1653
  *
1417
1654
  */
1418
- declare const validateStrategy: <ThrowOnError extends boolean = false>(options: Options<ValidateStrategyData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<ValidateStrategyResponse, ResponseError, ThrowOnError>;
1655
+ declare const validateStrategy: <ThrowOnError extends boolean = false>(options: Options<ValidateStrategyData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<StrategyState, ResponseError, ThrowOnError>;
1419
1656
  /**
1420
1657
  * Get a strategy by id, including its validation state
1421
1658
  * Reports that the strategy is registered — implied by a `200` at all — and what validating it
@@ -1449,6 +1686,17 @@ declare const getPrepareStatus: <ThrowOnError extends boolean = false>(options:
1449
1686
  * The backend expands and executes the matrix internally; clients poll the returned
1450
1687
  * `sweepId` for incremental results.
1451
1688
  *
1689
+ * Supplying `walkForward` runs the sweep in a different mode entirely. Instead of scoring
1690
+ * every parameter vector once over the whole range, the data is split into F sequential
1691
+ * folds; each fold optimizes the full grid on its own window and then scores only its winner
1692
+ * on the window immediately after — data that winner was not chosen on. It answers a harder
1693
+ * question than a leaderboard: not "which parameters won", but "does re-optimizing this
1694
+ * periodically actually work". Omit the block and nothing changes, including the response.
1695
+ *
1696
+ * The cost is the reason it is opt-in rather than always on: F folds × N vectors, so a
1697
+ * 4-fold run over a 500-point grid is 2004 backtests where the plain sweep is 500. The
1698
+ * request is rejected when `folds × totalRuns` exceeds the server's sweep budget.
1699
+ *
1452
1700
  */
1453
1701
  declare const executeSweep: <ThrowOnError extends boolean = false>(options: Options<ExecuteSweepData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<ExecuteSweepAccepted, ResponseError, ThrowOnError>;
1454
1702
  /**
@@ -1465,8 +1713,59 @@ declare const cancelSweep: <ThrowOnError extends boolean = false>(options: Optio
1465
1713
  * display leaderboard. `order=natural` returns every available row, untruncated, ordered by
1466
1714
  * deterministic `runIx`; use that view when materialising durable trial rows.
1467
1715
  *
1716
+ * The `ranked` view is ordered by **plateau score** by default, not by the raw objective. A
1717
+ * plateau score is the objective of the worst run in a parameter point's immediate
1718
+ * neighbourhood, so a point scores well only if the region around it also does — the highest
1719
+ * raw score is frequently a spike that does not survive the parameters moving slightly. Pass
1720
+ * `ranking=raw` for the unadjusted objective order.
1721
+ *
1722
+ * Rows in the `ranked` view carry `plateauScore` and `neighbourCount` when plateau ranking
1723
+ * applied. Read them together: `neighbourCount: 0` means the point had no neighbours to
1724
+ * compare against, so its plateau score is unevidenced rather than confirmed. Sweeps
1725
+ * submitted before plateau ranking existed have no stored parameter grid to rebuild a
1726
+ * neighbourhood from and are always ranked raw; the response's `ranking` field says which
1727
+ * ordering was actually used.
1728
+ *
1729
+ * A sweep submitted with `walkForward` answers in a different shape, and the `walkForward`
1730
+ * field on the response is what tells the two apart — it appears as soon as the sweep is
1731
+ * accepted, before any fold has finished, so it is safe to branch on while polling. There
1732
+ * the leaderboard is one row per completed fold: that fold's winner as it scored
1733
+ * **out-of-sample**, with `runIx` carrying the fold index rather than a grid position. The
1734
+ * in-sample runs behind those winners are not retained — they are an optimization's working
1735
+ * set, and only the winner survives its fold. `ranking` is always `raw` and no plateau, DSR
1736
+ * or PBO figure is reported: the out-of-sample scores are already the honest number, and
1737
+ * layering a certification computed over F observations on top of them would overstate what
1738
+ * was measured.
1739
+ *
1468
1740
  */
1469
1741
  declare const getSweepResult: <ThrowOnError extends boolean = false>(options: Options<GetSweepResultData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<ExecuteSweepResult, ResponseError, ThrowOnError>;
1742
+ /**
1743
+ * Get sweep sensitivity surfaces
1744
+ * How the objective moves as each parameter moves — the question a leaderboard cannot answer.
1745
+ * A leaderboard says which point won; a sweep can spend its entire budget on an axis that
1746
+ * never moved the objective at all, and showing only the top rows hides that completely.
1747
+ *
1748
+ * A **marginal** takes one axis and collapses every other one: for each value of that axis,
1749
+ * it aggregates every run that used it, whatever the rest of the parameters were. A flat
1750
+ * marginal means the axis is irrelevant over the range swept. `best`, `mean` and `worst` are
1751
+ * all reported because them disagreeing is itself the signal — a value with a high `best` and
1752
+ * a poor `mean` works only in specific company, which is an interaction between parameters
1753
+ * and would be invisible behind a single number.
1754
+ *
1755
+ * A **heatmap** does the same over a pair of axes, where that interaction becomes visible
1756
+ * directly.
1757
+ *
1758
+ * Served from the sweep's stored rows: no re-run, no engine call, and it works on a sweep
1759
+ * still in flight — the aggregates then describe the runs finished so far. Aborted runs are
1760
+ * excluded throughout, since a run that threw measured nothing and counting it as a bad
1761
+ * outcome would invent evidence against a parameter value that was never really tested.
1762
+ *
1763
+ * This is a separate endpoint rather than extra fields on the result view because the
1764
+ * two-dimensional half is quadratic in the axis count (N axes give N(N-1)/2 surfaces, each
1765
+ * the product of two axes' value counts) and is not wanted on the poll that drives progress.
1766
+ *
1767
+ */
1768
+ declare const getSweepSensitivity: <ThrowOnError extends boolean = false>(options: Options<GetSweepSensitivityData, ThrowOnError>) => _hey_api_client_fetch.RequestResult<SweepSensitivity, ResponseError, ThrowOnError>;
1470
1769
  /**
1471
1770
  * Execute a compiled strategy against a prepared dataset
1472
1771
  * Enqueues an execute task that runs the strategy identified by `strategyId` over the data
@@ -1507,4 +1806,4 @@ declare const getBacktestResult: <ThrowOnError extends boolean = false>(options:
1507
1806
 
1508
1807
  declare const client: _hey_api_client_fetch.Client;
1509
1808
 
1510
- export { type AcceptedJob, type AuthTokenError, type AuthTokenResponse, type AuthenticateData, type AuthenticateError, type AuthenticateErrors, type AuthenticateResponse, type AuthenticateResponses, type BacktestJobResult, type CancelBacktestData, type CancelBacktestError, type CancelBacktestErrors, type CancelBacktestResponse, type CancelBacktestResponses, type CancelSweepData, type CancelSweepError, type CancelSweepErrors, type CancelSweepResponse, type CancelSweepResponses, type ClientOptions, type CompileStrategyData, type CompileStrategyError, type CompileStrategyErrors, type CompileStrategyResponse, type CompileStrategyResponses, type CoverageWindow, type DataSourceType, type DownloadKlinesData, type DownloadKlinesError, type DownloadKlinesErrors, type DownloadKlinesResponse, type DownloadKlinesResponses, type DownloadTickersData, type DownloadTickersError, type DownloadTickersErrors, type DownloadTickersResponse, type DownloadTickersResponses, type EquityPoint, type Exchange, type ExecuteBacktestData, type ExecuteBacktestError, type ExecuteBacktestErrors, type ExecuteBacktestResponse, type ExecuteBacktestResponses, type ExecuteSweepAccepted, type ExecuteSweepData, type ExecuteSweepError, type ExecuteSweepErrors, type ExecuteSweepRequest, type ExecuteSweepResponse, type ExecuteSweepResponses, type ExecuteSweepResult, type GetBacktestResultData, type GetBacktestResultError, type GetBacktestResultErrors, type GetBacktestResultResponse, type GetBacktestResultResponses, type GetPrepareStatusData, type GetPrepareStatusError, type GetPrepareStatusErrors, type GetPrepareStatusResponse, type GetPrepareStatusResponses, type GetStrategyData, type GetStrategyError, type GetStrategyErrors, type GetStrategyResponse, type GetStrategyResponses, type GetSweepResultData, type GetSweepResultError, type GetSweepResultErrors, type GetSweepResultResponse, type GetSweepResultResponses, type HalLink, type Instrument, type InstrumentCoverage, type InstrumentDetail, type InstrumentLinks, type InstrumentListMeta, type InstrumentListResponse, type JobState, type ListExchangesData, type ListExchangesResponse, type ListExchangesResponses, type ListInstrumentsData, type ListInstrumentsError, type ListInstrumentsErrors, type ListInstrumentsResponse, type ListInstrumentsResponses, type ListSegmentInstrumentsData, type ListSegmentInstrumentsError, type ListSegmentInstrumentsErrors, type ListSegmentInstrumentsResponse, type ListSegmentInstrumentsResponses, type Notice, type Options, type PrepareBacktestData, type PrepareBacktestError, type PrepareBacktestErrors, type PrepareBacktestResponse, type PrepareBacktestResponses, type PrepareJobState, type PrepareRequest, type ResponseError, type ResultMap, type StrategyId, type StrategyState, type SweepAxis, type SweepBaseConfig, type SweepProgress, type SweepRunRow, type SweepSpecRequest, type ValidateStrategyData, type ValidateStrategyError, type ValidateStrategyErrors, type ValidateStrategyResponse, type ValidateStrategyResponses, authenticate, cancelBacktest, cancelSweep, client, compileStrategy, downloadKlines, downloadTickers, executeBacktest, executeSweep, getBacktestResult, getPrepareStatus, getStrategy, getSweepResult, listExchanges, listInstruments, listSegmentInstruments, prepareBacktest, validateStrategy };
1809
+ export { type AcceptedJob, type AuthTokenError, type AuthTokenResponse, type AuthenticateData, type AuthenticateError, type AuthenticateErrors, type AuthenticateResponse, type AuthenticateResponses, type BacktestJobResult, type CancelBacktestData, type CancelBacktestError, type CancelBacktestErrors, type CancelBacktestResponse, type CancelBacktestResponses, type CancelSweepData, type CancelSweepError, type CancelSweepErrors, type CancelSweepResponse, type CancelSweepResponses, type ClientOptions, type CompileStrategyData, type CompileStrategyError, type CompileStrategyErrors, type CompileStrategyResponse, type CompileStrategyResponses, type CoverageWindow, type DataSourceType, type DownloadKlinesData, type DownloadKlinesError, type DownloadKlinesErrors, type DownloadKlinesResponse, type DownloadKlinesResponses, type DownloadTickersData, type DownloadTickersError, type DownloadTickersErrors, type DownloadTickersResponse, type DownloadTickersResponses, type EquityPoint, type Exchange, type ExecuteBacktestData, type ExecuteBacktestError, type ExecuteBacktestErrors, type ExecuteBacktestResponse, type ExecuteBacktestResponses, type ExecuteSweepAccepted, type ExecuteSweepData, type ExecuteSweepError, type ExecuteSweepErrors, type ExecuteSweepRequest, type ExecuteSweepResponse, type ExecuteSweepResponses, type ExecuteSweepResult, type GetBacktestResultData, type GetBacktestResultError, type GetBacktestResultErrors, type GetBacktestResultResponse, type GetBacktestResultResponses, type GetPrepareStatusData, type GetPrepareStatusError, type GetPrepareStatusErrors, type GetPrepareStatusResponse, type GetPrepareStatusResponses, type GetStrategyData, type GetStrategyError, type GetStrategyErrors, type GetStrategyResponse, type GetStrategyResponses, type GetSweepResultData, type GetSweepResultError, type GetSweepResultErrors, type GetSweepResultResponse, type GetSweepResultResponses, type GetSweepSensitivityData, type GetSweepSensitivityError, type GetSweepSensitivityErrors, type GetSweepSensitivityResponse, type GetSweepSensitivityResponses, type HalLink, type Instrument, type InstrumentCoverage, type InstrumentDetail, type InstrumentLinks, type InstrumentListMeta, type InstrumentListResponse, type JobState, type ListExchangesData, type ListExchangesResponse, type ListExchangesResponses, type ListInstrumentsData, type ListInstrumentsError, type ListInstrumentsErrors, type ListInstrumentsResponse, type ListInstrumentsResponses, type ListSegmentInstrumentsData, type ListSegmentInstrumentsError, type ListSegmentInstrumentsErrors, type ListSegmentInstrumentsResponse, type ListSegmentInstrumentsResponses, type Notice, type Options, type PrepareBacktestData, type PrepareBacktestError, type PrepareBacktestErrors, type PrepareBacktestResponse, type PrepareBacktestResponses, type PrepareJobState, type PrepareRequest, type ResponseError, type ResultMap, type StrategyId, type StrategyState, type SweepAxis, type SweepBaseConfig, type SweepHeatmap, type SweepHeatmapCell, type SweepMarginal, type SweepMarginalPoint, type SweepProgress, type SweepRunRow, type SweepSensitivity, type SweepSpecRequest, type ValidateStrategyData, type ValidateStrategyError, type ValidateStrategyErrors, type ValidateStrategyResponse, type ValidateStrategyResponses, type WalkForwardAccepted, type WalkForwardFold, type WalkForwardRequest, type WalkForwardResult, authenticate, cancelBacktest, cancelSweep, client, compileStrategy, downloadKlines, downloadTickers, executeBacktest, executeSweep, getBacktestResult, getPrepareStatus, getStrategy, getSweepResult, getSweepSensitivity, listExchanges, listInstruments, listSegmentInstruments, prepareBacktest, validateStrategy };