@qtsurfer/api-client 0.17.0 → 0.19.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.
@@ -859,6 +859,8 @@ export const SweepBaseConfigSchema = {
859
859
  format: "double",
860
860
  exclusiveMinimum: 0,
861
861
  maximum: 100,
862
+ description:
863
+ "Share of the free balance each entry locks, in percent (0-100]. Omitted, a backtest sizes every entry with everything available.",
862
864
  },
863
865
  },
864
866
  } as const;
@@ -2860,6 +2862,73 @@ export const StartLiveRequestSchema = {
2860
2862
  description: {
2861
2863
  type: "string",
2862
2864
  },
2865
+ paper: {
2866
+ $ref: "#/components/schemas/LivePaperConfig",
2867
+ },
2868
+ },
2869
+ } as const;
2870
+
2871
+ export const LivePaperConfigSchema = {
2872
+ type: "object",
2873
+ additionalProperties: false,
2874
+ description: `Paper trading for this run: the same economics as a backtest's \`baseConfig\` (same fields,
2875
+ defaults and limits), plus \`output\`. An empty object takes every default. Each quote
2876
+ currency the run trades gets its own simulated account, opened with \`initialFunding\` in
2877
+ that currency; accounts are never added together. As returned on a run, the block is
2878
+ normalised: \`feeRate\` is resolved into \`buyFeeRate\`/\`sellFeeRate\` and defaults are filled
2879
+ in.
2880
+ `,
2881
+ properties: {
2882
+ initialFunding: {
2883
+ type: "number",
2884
+ format: "double",
2885
+ exclusiveMinimum: 0,
2886
+ maximum: 1000000000,
2887
+ default: 100,
2888
+ description:
2889
+ "Starting capital of each account, in that account's own quote currency.",
2890
+ },
2891
+ feeRate: {
2892
+ type: "number",
2893
+ format: "double",
2894
+ minimum: 0,
2895
+ default: 0.001,
2896
+ description:
2897
+ "Fee rate for both sides (0.001 = 0.1%). Accepted on start; returned resolved into the two fields below.",
2898
+ },
2899
+ buyFeeRate: {
2900
+ type: "number",
2901
+ format: "double",
2902
+ minimum: 0,
2903
+ description: "Buy-side fee rate; overrides `feeRate`.",
2904
+ },
2905
+ sellFeeRate: {
2906
+ type: "number",
2907
+ format: "double",
2908
+ minimum: 0,
2909
+ description: "Sell-side fee rate; overrides `feeRate`.",
2910
+ },
2911
+ feeLeg: {
2912
+ type: "string",
2913
+ enum: ["RECEIVED", "QUOTE", "BASE"],
2914
+ default: "RECEIVED",
2915
+ description:
2916
+ "Which asset fees are charged in. Case-insensitive on start.",
2917
+ },
2918
+ percentAmountToLock: {
2919
+ type: "number",
2920
+ format: "double",
2921
+ exclusiveMinimum: 0,
2922
+ maximum: 100,
2923
+ description:
2924
+ "Share of the account's free balance each entry locks, in percent. Omitted, the strategy's own setting applies, and without one 10%.",
2925
+ },
2926
+ output: {
2927
+ type: "string",
2928
+ enum: ["separate", "mix"],
2929
+ default: "separate",
2930
+ description: `\`separate\` keeps paper output out of the run's signals (read it with \`GET /live/{runId}/paper\`); \`mix\` also interleaves it into the run's signals as \`type: paper\`, right after the signal that caused it.`,
2931
+ },
2863
2932
  },
2864
2933
  } as const;
2865
2934
 
@@ -2979,6 +3048,15 @@ export const LiveRunSchema = {
2979
3048
  description:
2980
3049
  "The sandbox trial's promotion verdict, once one exists. Shape is not yet stabilized as public API — treat as opaque diagnostics.",
2981
3050
  },
3051
+ paper: {
3052
+ allOf: [
3053
+ {
3054
+ $ref: "#/components/schemas/LivePaperConfig",
3055
+ },
3056
+ ],
3057
+ description:
3058
+ "The run's paper trading configuration as accepted at start, normalised. Absent when the run has no paper trading.",
3059
+ },
2982
3060
  },
2983
3061
  } as const;
2984
3062
 
@@ -3017,6 +3095,91 @@ export const LiveRunCompactSchema = {
3017
3095
  },
3018
3096
  } as const;
3019
3097
 
3098
+ export const LiveRunSummarySchema = {
3099
+ type: "object",
3100
+ required: [
3101
+ "strategyId",
3102
+ "runId",
3103
+ "visibility",
3104
+ "stage",
3105
+ "state",
3106
+ "desired",
3107
+ "sources",
3108
+ "createdAtMs",
3109
+ "startedAtMs",
3110
+ ],
3111
+ description:
3112
+ "A run as it appears in `GET /live` — one of your own, narrower than `LiveRun` (no `params`, `paramsVersion`, `relay`, or `gate`), since listing stays cheap regardless of how many runs you have. Check a specific run's full state with `GET /strategy/{strategyId}/live`.",
3113
+ properties: {
3114
+ strategyId: {
3115
+ $ref: "#/components/schemas/strategyId",
3116
+ },
3117
+ runId: {
3118
+ type: "string",
3119
+ description:
3120
+ "This run's own id — its canonical identity for `PATCH`/`PUT .../params` and for `GET /live/public`.",
3121
+ },
3122
+ name: {
3123
+ type: "string",
3124
+ },
3125
+ description: {
3126
+ type: "string",
3127
+ },
3128
+ visibility: {
3129
+ type: "string",
3130
+ enum: ["private", "public"],
3131
+ },
3132
+ stage: {
3133
+ type: "string",
3134
+ enum: ["SANDBOX", "LIVE"],
3135
+ description:
3136
+ "A new run always starts `SANDBOX` — a trial run compared against a second execution for agreement — and moves to `LIVE` once it passes.",
3137
+ },
3138
+ state: {
3139
+ type: "string",
3140
+ description: `\`STARTING\` until first observed running; otherwise the runner's own reported state (e.g. \`RUNNING\`).`,
3141
+ },
3142
+ desired: {
3143
+ type: "string",
3144
+ enum: ["RUNNING", "STOPPED"],
3145
+ description:
3146
+ "What you last asked for. `state` can lag this briefly after `DELETE`.",
3147
+ },
3148
+ sources: {
3149
+ type: "array",
3150
+ items: {
3151
+ $ref: "#/components/schemas/LiveSource",
3152
+ },
3153
+ },
3154
+ createdAtMs: {
3155
+ type: "integer",
3156
+ format: "int64",
3157
+ description: "Epoch milliseconds this run was started.",
3158
+ },
3159
+ startedAtMs: {
3160
+ type: "integer",
3161
+ format: "int64",
3162
+ description: "Epoch milliseconds.",
3163
+ },
3164
+ },
3165
+ } as const;
3166
+
3167
+ export const LiveListResponseSchema = {
3168
+ type: "object",
3169
+ required: ["runs"],
3170
+ properties: {
3171
+ runs: {
3172
+ type: "array",
3173
+ items: {
3174
+ $ref: "#/components/schemas/LiveRunSummary",
3175
+ },
3176
+ },
3177
+ _links: {
3178
+ $ref: "#/components/schemas/PublicLiveListLinks",
3179
+ },
3180
+ },
3181
+ } as const;
3182
+
3020
3183
  export const PublicLiveRunSchema = {
3021
3184
  type: "object",
3022
3185
  required: ["runId", "sources", "state", "createdAtMs"],
@@ -3106,6 +3269,217 @@ export const LiveSignalPageSchema = {
3106
3269
  },
3107
3270
  } as const;
3108
3271
 
3272
+ export const LivePaperSchema = {
3273
+ type: "object",
3274
+ required: ["runId", "stage", "accounts"],
3275
+ properties: {
3276
+ runId: {
3277
+ type: "string",
3278
+ },
3279
+ stage: {
3280
+ type: "string",
3281
+ enum: ["SANDBOX", "LIVE"],
3282
+ },
3283
+ accounts: {
3284
+ type: "array",
3285
+ items: {
3286
+ $ref: "#/components/schemas/LivePaperAccount",
3287
+ },
3288
+ },
3289
+ },
3290
+ } as const;
3291
+
3292
+ export const LivePaperAccountSchema = {
3293
+ type: "object",
3294
+ required: [
3295
+ "currency",
3296
+ "initialFunding",
3297
+ "equity",
3298
+ "realisedPnl",
3299
+ "trades",
3300
+ "gaps",
3301
+ "openPositions",
3302
+ ],
3303
+ description: "One simulated account — one per quote currency the run trades.",
3304
+ properties: {
3305
+ currency: {
3306
+ type: "string",
3307
+ description: "The account's quote currency; every amount below is in it.",
3308
+ },
3309
+ initialFunding: {
3310
+ type: "number",
3311
+ format: "double",
3312
+ },
3313
+ equity: {
3314
+ type: "number",
3315
+ format: "double",
3316
+ description: "Latest recorded equity — see `equityKind`.",
3317
+ },
3318
+ equityAtMs: {
3319
+ type: "integer",
3320
+ format: "int64",
3321
+ description:
3322
+ "Market time of that value. Absent while the account holds its starting capital.",
3323
+ },
3324
+ equityKind: {
3325
+ type: "string",
3326
+ enum: ["equity", "mark"],
3327
+ description: `\`equity\` at a closed trade, \`mark\` at a periodic mark-to-market (includes open positions at market price).`,
3328
+ },
3329
+ realisedPnl: {
3330
+ type: "number",
3331
+ format: "double",
3332
+ description: "Sum of the PnL of the closed trades.",
3333
+ },
3334
+ trades: {
3335
+ type: "integer",
3336
+ format: "int64",
3337
+ description: "Closed trades.",
3338
+ },
3339
+ gaps: {
3340
+ type: "integer",
3341
+ description:
3342
+ "Times open positions were lost because the run was restarted with them open.",
3343
+ },
3344
+ openPositions: {
3345
+ type: "array",
3346
+ items: {
3347
+ $ref: "#/components/schemas/LivePaperPosition",
3348
+ },
3349
+ },
3350
+ kpi: {
3351
+ $ref: "#/components/schemas/LivePaperKpi",
3352
+ },
3353
+ },
3354
+ } as const;
3355
+
3356
+ export const LivePaperPositionSchema = {
3357
+ type: "object",
3358
+ required: ["instrument", "base", "cost"],
3359
+ properties: {
3360
+ instrument: {
3361
+ type: "string",
3362
+ example: "BTC/USDT",
3363
+ },
3364
+ base: {
3365
+ type: "number",
3366
+ format: "double",
3367
+ description: "Amount held, in the base asset.",
3368
+ },
3369
+ cost: {
3370
+ type: "number",
3371
+ format: "double",
3372
+ description: "What it cost, in the account's currency.",
3373
+ },
3374
+ },
3375
+ } as const;
3376
+
3377
+ export const LivePaperKpiSchema = {
3378
+ type: "object",
3379
+ description:
3380
+ "The same KPIs a backtest reports, over the trades closed so far. Absent until the first closed trade is recorded.",
3381
+ properties: {
3382
+ totalTrades: {
3383
+ type: "integer",
3384
+ format: "int64",
3385
+ },
3386
+ winCount: {
3387
+ type: "integer",
3388
+ format: "int64",
3389
+ },
3390
+ lossCount: {
3391
+ type: "integer",
3392
+ format: "int64",
3393
+ },
3394
+ winRate: {
3395
+ type: "number",
3396
+ format: "double",
3397
+ description: "Ratio (0.5 = half the trades won).",
3398
+ },
3399
+ pnlTotal: {
3400
+ type: "number",
3401
+ format: "double",
3402
+ },
3403
+ pnlTotalPercent: {
3404
+ type: "number",
3405
+ format: "double",
3406
+ description: "Percent of `initialFunding` (0-100 scale).",
3407
+ },
3408
+ sharpeRatio: {
3409
+ type: ["number", "null"],
3410
+ format: "double",
3411
+ },
3412
+ sortinoRatio: {
3413
+ type: ["number", "null"],
3414
+ format: "double",
3415
+ },
3416
+ cagr: {
3417
+ type: ["number", "null"],
3418
+ format: "double",
3419
+ description: "Ratio (0.15 for 15%).",
3420
+ },
3421
+ maxDrawdown: {
3422
+ type: "number",
3423
+ format: "double",
3424
+ },
3425
+ maxDrawdownPercent: {
3426
+ type: "number",
3427
+ format: "double",
3428
+ description: "Percent (0-100 scale).",
3429
+ },
3430
+ },
3431
+ } as const;
3432
+
3433
+ export const LivePaperEquityPageSchema = {
3434
+ type: "object",
3435
+ required: ["points"],
3436
+ properties: {
3437
+ points: {
3438
+ type: "array",
3439
+ items: {
3440
+ $ref: "#/components/schemas/LivePaperEquityPoint",
3441
+ },
3442
+ },
3443
+ _links: {
3444
+ type: "object",
3445
+ properties: {
3446
+ next: {
3447
+ type: "object",
3448
+ properties: {
3449
+ href: {
3450
+ type: "string",
3451
+ },
3452
+ },
3453
+ },
3454
+ },
3455
+ },
3456
+ },
3457
+ } as const;
3458
+
3459
+ export const LivePaperEquityPointSchema = {
3460
+ type: "object",
3461
+ required: ["currency", "kind", "eventTsMs"],
3462
+ properties: {
3463
+ currency: {
3464
+ type: "string",
3465
+ },
3466
+ kind: {
3467
+ type: "string",
3468
+ enum: ["equity", "mark", "gap"],
3469
+ },
3470
+ eventTsMs: {
3471
+ type: "integer",
3472
+ format: "int64",
3473
+ description: "Market time of the point.",
3474
+ },
3475
+ equity: {
3476
+ type: "number",
3477
+ format: "double",
3478
+ description: "Absent on a `gap`.",
3479
+ },
3480
+ },
3481
+ } as const;
3482
+
3109
3483
  export const LiveSignalSchema = {
3110
3484
  type: "object",
3111
3485
  required: [
@@ -3145,11 +3519,12 @@ export const LiveSignalSchema = {
3145
3519
  },
3146
3520
  type: {
3147
3521
  type: "string",
3148
- enum: ["hint", "info", "marker", "command"],
3522
+ enum: ["hint", "info", "marker", "command", "paper"],
3523
+ description: `\`paper\` items appear only for a run whose \`paper.output\` is \`mix\`; they are not relayed over the WebSocket channel.`,
3149
3524
  },
3150
3525
  kind: {
3151
3526
  type: ["string", "null"],
3152
- description: `\`BUY\`/\`SELL\` for a \`hint\`, the command name for a \`command\`, absent otherwise.`,
3527
+ description: `\`BUY\`/\`SELL\` for a \`hint\`, the command name for a \`command\`; for \`paper\`, what the item is: \`fill\`, \`trade\`, \`equity\`, \`mark\`, \`kpi\` or \`gap\`. Absent otherwise.`,
3153
3528
  },
3154
3529
  eventTsMs: {
3155
3530
  type: "integer",
@@ -3162,7 +3537,16 @@ export const LiveSignalSchema = {
3162
3537
  description: "Time it was published — always at or after `eventTsMs`.",
3163
3538
  },
3164
3539
  instrument: {
3165
- $ref: "#/components/schemas/LiveSignalInstrument",
3540
+ anyOf: [
3541
+ {
3542
+ $ref: "#/components/schemas/LiveSignalInstrument",
3543
+ },
3544
+ {
3545
+ type: "null",
3546
+ },
3547
+ ],
3548
+ description:
3549
+ "The instrument the signal is about. `null` only for a `paper` item about a whole account (`equity`, `mark`, `kpi`), whose `data.currency` names the account.",
3166
3550
  },
3167
3551
  order: {
3168
3552
  $ref: "#/components/schemas/LiveSignalOrder",
@@ -109,6 +109,9 @@ import type {
109
109
  StartLiveData,
110
110
  StartLiveResponse,
111
111
  StartLiveError,
112
+ ListLiveData,
113
+ ListLiveResponse,
114
+ ListLiveError,
112
115
  ListPublicLiveData,
113
116
  ListPublicLiveResponse,
114
117
  ListPublicLiveError,
@@ -121,6 +124,12 @@ import type {
121
124
  GetLiveRunSignalsData,
122
125
  GetLiveRunSignalsResponse,
123
126
  GetLiveRunSignalsError,
127
+ GetLiveRunPaperData,
128
+ GetLiveRunPaperResponse,
129
+ GetLiveRunPaperError,
130
+ GetLiveRunPaperEquityData,
131
+ GetLiveRunPaperEquityResponse,
132
+ GetLiveRunPaperEquityError,
124
133
  MintLiveConnectionTokenData,
125
134
  MintLiveConnectionTokenResponse,
126
135
  } from "./types.gen";
@@ -1339,6 +1348,14 @@ export const getLive = <ThrowOnError extends boolean = false>(
1339
1348
  * the "Live execution" guide linked from this tag's description for the full flow (minting a
1340
1349
  * connection token, the channel and RPC method).
1341
1350
  *
1351
+ * **Paper trading.** Pass a `paper` block to have the run's hints executed in simulation from
1352
+ * its first tick, as a backtest would execute them: fills, closed trades, equity and KPIs,
1353
+ * with one simulated account per quote currency. Omitted, the run has no paper trading. It
1354
+ * takes the same economics as a backtest's `baseConfig` plus where its output goes; read it
1355
+ * back with `GET /live/{runId}/paper`. A strategy that listens to its own execution events
1356
+ * (it overrides `getExecutionCallback()`) has no other execution venue, so it cannot start
1357
+ * without a `paper` block.
1358
+ *
1342
1359
  */
1343
1360
  export const startLive = <ThrowOnError extends boolean = false>(
1344
1361
  options: Options<StartLiveData, ThrowOnError>
@@ -1363,6 +1380,32 @@ export const startLive = <ThrowOnError extends boolean = false>(
1363
1380
  });
1364
1381
  };
1365
1382
 
1383
+ /**
1384
+ * List your own live runs
1385
+ * Every run you have started, in any `stage`, `desired` state, or `visibility` — newest
1386
+ * first. Unlike `GET /live/public`, this is not filtered to `RUNNING` public runs: it is
1387
+ * the complete list of runs you own, including `sandbox` trials and stopped ones.
1388
+ *
1389
+ */
1390
+ export const listLive = <ThrowOnError extends boolean = false>(
1391
+ options?: Options<ListLiveData, ThrowOnError>
1392
+ ) => {
1393
+ return (options?.client ?? _heyApiClient).get<
1394
+ ListLiveResponse,
1395
+ ListLiveError,
1396
+ ThrowOnError
1397
+ >({
1398
+ security: [
1399
+ {
1400
+ scheme: "bearer",
1401
+ type: "http",
1402
+ },
1403
+ ],
1404
+ url: "/live",
1405
+ ...options,
1406
+ });
1407
+ };
1408
+
1366
1409
  /**
1367
1410
  * Browse public live runs
1368
1411
  * Every run whose owner marked it `public` and is currently live and running — anyone's,
@@ -1501,6 +1544,74 @@ export const getLiveRunSignals = <ThrowOnError extends boolean = false>(
1501
1544
  });
1502
1545
  };
1503
1546
 
1547
+ /**
1548
+ * Read a run's paper trading
1549
+ * The run's paper trading as last recorded: one entry per simulated account (one per quote
1550
+ * currency the run trades — never added together), with its starting capital, current
1551
+ * equity, realised PnL, open positions and KPIs. The KPIs are the same a backtest reports,
1552
+ * computed over the trades closed so far.
1553
+ *
1554
+ * `equity` is the account's latest recorded value: at the last closed trade (`equityKind:
1555
+ * equity`), or the last periodic mark-to-market while positions are open (`equityKind:
1556
+ * mark`, taken every minute of market time). Until either exists the account holds its
1557
+ * starting capital.
1558
+ *
1559
+ * Readable by the run's owner, and by anyone if the run is `public`. A run started without
1560
+ * a `paper` block answers `404`.
1561
+ *
1562
+ */
1563
+ export const getLiveRunPaper = <ThrowOnError extends boolean = false>(
1564
+ options: Options<GetLiveRunPaperData, ThrowOnError>
1565
+ ) => {
1566
+ return (options.client ?? _heyApiClient).get<
1567
+ GetLiveRunPaperResponse,
1568
+ GetLiveRunPaperError,
1569
+ ThrowOnError
1570
+ >({
1571
+ security: [
1572
+ {
1573
+ scheme: "bearer",
1574
+ type: "http",
1575
+ },
1576
+ ],
1577
+ url: "/live/{runId}/paper",
1578
+ ...options,
1579
+ });
1580
+ };
1581
+
1582
+ /**
1583
+ * Read a run's paper equity curve
1584
+ * The run's paper equity curve, oldest first, page by page. It is kept for the life of the
1585
+ * run, so unlike signals it has no moving window. Points are `equity` at every closed trade,
1586
+ * `mark` every minute of market time while positions are open, and `gap` where the run was
1587
+ * restarted with positions open: those positions are not carried over, so the curve has no
1588
+ * value there.
1589
+ *
1590
+ * `currency` narrows to one account; without it, every account's points come interleaved by
1591
+ * time, each carrying its currency.
1592
+ *
1593
+ * Readable by the run's owner, and by anyone if the run is `public`.
1594
+ *
1595
+ */
1596
+ export const getLiveRunPaperEquity = <ThrowOnError extends boolean = false>(
1597
+ options: Options<GetLiveRunPaperEquityData, ThrowOnError>
1598
+ ) => {
1599
+ return (options.client ?? _heyApiClient).get<
1600
+ GetLiveRunPaperEquityResponse,
1601
+ GetLiveRunPaperEquityError,
1602
+ ThrowOnError
1603
+ >({
1604
+ security: [
1605
+ {
1606
+ scheme: "bearer",
1607
+ type: "http",
1608
+ },
1609
+ ],
1610
+ url: "/live/{runId}/paper/equity",
1611
+ ...options,
1612
+ });
1613
+ };
1614
+
1504
1615
  /**
1505
1616
  * Mint a WebSocket connection token
1506
1617
  * Mints a short-lived token for the WebSocket connection used to receive a run's signals in