tradeblocks-mcp 3.0.3 → 3.3.1
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 +3 -12
- package/dist/{chunk-C6LL746C.js → chunk-2I3S2ZLT.js} +259 -1
- package/dist/chunk-2I3S2ZLT.js.map +1 -0
- package/dist/{chunk-UBUC5A66.js → chunk-4HZLVUOZ.js} +81 -76
- package/dist/chunk-4HZLVUOZ.js.map +1 -0
- package/dist/{chunk-VDU25Z6X.js → chunk-NWNSKALN.js} +2 -2
- package/dist/{chunk-AP7IHUUR.js → chunk-WNTYA7ER.js} +2 -2
- package/dist/{chunk-6S37CXUA.js → chunk-YZA4RS76.js} +14 -6
- package/dist/chunk-YZA4RS76.js.map +1 -0
- package/dist/{chunk-SEUZYQGQ.js → chunk-ZTJXC3LS.js} +2 -2
- package/dist/daily-log-processor-MZW2XBZY.js +9 -0
- package/dist/market-provider-6U33TQUT.js +16 -0
- package/dist/{sync-EVLKB3ZJ.js → sync-3UBC37VW.js} +6 -6
- package/dist/test-exports.js +560 -271
- package/dist/test-exports.js.map +1 -1
- package/dist/trade-processor-DKDCWGKD.js +9 -0
- package/package.json +2 -6
- package/server/{chunk-YUCOAJ4Z.js → chunk-536NSFED.js} +2 -2
- package/server/{chunk-GH2552SE.js → chunk-A3UKD64A.js} +2 -2
- package/server/{chunk-ZBJCF4ZG.js → chunk-OMUDNJBJ.js} +2 -2
- package/server/{chunk-BOPHW5M6.js → chunk-RJDJHZ5Y.js} +414 -101
- package/server/chunk-RJDJHZ5Y.js.map +1 -0
- package/server/{chunk-4P7D7YZP.js → chunk-RM4B2VKS.js} +72 -71
- package/server/chunk-RM4B2VKS.js.map +1 -0
- package/server/{chunk-OBYKFW2B.js → chunk-SY6GDNVI.js} +14 -6
- package/server/chunk-SY6GDNVI.js.map +1 -0
- package/server/daily-log-processor-B2VPU2FQ.js +10 -0
- package/server/index.js +787 -552
- package/server/index.js.map +1 -1
- package/server/market-provider-L56RFHAC.js +17 -0
- package/server/{sync-V25UQJA3.js → sync-CENKDN53.js} +6 -6
- package/server/trade-processor-3PI4LHZI.js +10 -0
- package/src/db/backtest-schemas.ts +26 -4
- package/src/db/data-root.ts +22 -0
- package/src/test-exports.ts +12 -0
- package/src/tools/blocks/index.ts +2 -0
- package/src/tools/blocks/paired-comparison.ts +425 -0
- package/src/tools/imports.ts +2 -2
- package/src/utils/block-loader.ts +1 -1
- package/src/utils/calibration-probe.ts +2 -2
- package/dist/chunk-6S37CXUA.js.map +0 -1
- package/dist/chunk-C6LL746C.js.map +0 -1
- package/dist/chunk-UBUC5A66.js.map +0 -1
- package/dist/daily-log-processor-BY3ISY6K.js +0 -9
- package/dist/market-provider-H3ARIVZ4.js +0 -16
- package/dist/trade-processor-EYA3I3XB.js +0 -9
- package/manifest.json +0 -133
- package/server/chunk-4P7D7YZP.js.map +0 -1
- package/server/chunk-BOPHW5M6.js.map +0 -1
- package/server/chunk-OBYKFW2B.js.map +0 -1
- package/server/daily-log-processor-ENEUT22A.js +0 -10
- package/server/market-provider-B437HKLW.js +0 -17
- package/server/trade-processor-L3PIQ5TG.js +0 -10
- /package/dist/{chunk-VDU25Z6X.js.map → chunk-NWNSKALN.js.map} +0 -0
- /package/dist/{chunk-AP7IHUUR.js.map → chunk-WNTYA7ER.js.map} +0 -0
- /package/dist/{chunk-SEUZYQGQ.js.map → chunk-ZTJXC3LS.js.map} +0 -0
- /package/dist/{daily-log-processor-BY3ISY6K.js.map → daily-log-processor-MZW2XBZY.js.map} +0 -0
- /package/dist/{market-provider-H3ARIVZ4.js.map → market-provider-6U33TQUT.js.map} +0 -0
- /package/dist/{sync-EVLKB3ZJ.js.map → sync-3UBC37VW.js.map} +0 -0
- /package/dist/{trade-processor-EYA3I3XB.js.map → trade-processor-DKDCWGKD.js.map} +0 -0
- /package/server/{chunk-YUCOAJ4Z.js.map → chunk-536NSFED.js.map} +0 -0
- /package/server/{chunk-GH2552SE.js.map → chunk-A3UKD64A.js.map} +0 -0
- /package/server/{chunk-ZBJCF4ZG.js.map → chunk-OMUDNJBJ.js.map} +0 -0
- /package/server/{daily-log-processor-ENEUT22A.js.map → daily-log-processor-B2VPU2FQ.js.map} +0 -0
- /package/server/{market-provider-B437HKLW.js.map → market-provider-L56RFHAC.js.map} +0 -0
- /package/server/{sync-V25UQJA3.js.map → sync-CENKDN53.js.map} +0 -0
- /package/server/{trade-processor-L3PIQ5TG.js.map → trade-processor-3PI4LHZI.js.map} +0 -0
package/dist/test-exports.js
CHANGED
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
resolveCanonicalMarketPartitionDir,
|
|
58
58
|
resolveCanonicalMarketPartitionFile,
|
|
59
59
|
resolveCanonicalMarketPartitionPath,
|
|
60
|
+
resolveDbPath,
|
|
60
61
|
resolveMarketDir,
|
|
61
62
|
resolveTradeTicker,
|
|
62
63
|
setDataRoot,
|
|
@@ -80,7 +81,7 @@ import {
|
|
|
80
81
|
writeParquetPartition,
|
|
81
82
|
writeQuoteMinutesPartition,
|
|
82
83
|
writeSpotPartition
|
|
83
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-4HZLVUOZ.js";
|
|
84
85
|
import {
|
|
85
86
|
BACHELIER_DTE_THRESHOLD,
|
|
86
87
|
IvSolverPool,
|
|
@@ -156,34 +157,48 @@ import {
|
|
|
156
157
|
stockHistoryOhlc,
|
|
157
158
|
thetaTimestampToEtMinute,
|
|
158
159
|
toMassiveTicker
|
|
159
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-NWNSKALN.js";
|
|
160
161
|
import {
|
|
161
162
|
PortfolioStatsCalculator,
|
|
162
163
|
calculateCorrelationMatrix,
|
|
164
|
+
holdingPeriodBlockDays,
|
|
165
|
+
pairedBlockBootstrap,
|
|
163
166
|
performTailRiskAnalysis
|
|
164
|
-
} from "./chunk-
|
|
165
|
-
import "./chunk-
|
|
166
|
-
import "./chunk-
|
|
167
|
-
import "./chunk-
|
|
167
|
+
} from "./chunk-2I3S2ZLT.js";
|
|
168
|
+
import "./chunk-WNTYA7ER.js";
|
|
169
|
+
import "./chunk-ZTJXC3LS.js";
|
|
170
|
+
import "./chunk-YZA4RS76.js";
|
|
168
171
|
import "./chunk-27S67XW3.js";
|
|
169
172
|
import "./chunk-2E63THNI.js";
|
|
170
173
|
import "./chunk-5WRI5ZAA.js";
|
|
171
174
|
|
|
172
|
-
// src/
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
175
|
+
// src/tools/blocks/paired-comparison.ts
|
|
176
|
+
import { z } from "zod";
|
|
177
|
+
|
|
178
|
+
// src/utils/output-formatter.ts
|
|
179
|
+
function createToolOutput(summary, data) {
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{ type: "text", text: summary },
|
|
183
|
+
{
|
|
184
|
+
type: "resource",
|
|
185
|
+
resource: {
|
|
186
|
+
uri: "data:application/json",
|
|
187
|
+
mimeType: "application/json",
|
|
188
|
+
text: JSON.stringify(data)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function formatCurrency(value) {
|
|
195
|
+
const isNegative = value < 0;
|
|
196
|
+
const absValue = Math.abs(value);
|
|
197
|
+
const formatted = absValue.toLocaleString("en-US", {
|
|
198
|
+
minimumFractionDigits: 2,
|
|
199
|
+
maximumFractionDigits: 2
|
|
200
|
+
});
|
|
201
|
+
return isNegative ? `-$${formatted}` : `$${formatted}`;
|
|
187
202
|
}
|
|
188
203
|
|
|
189
204
|
// src/tools/shared/filters.ts
|
|
@@ -232,6 +247,294 @@ function filterDailyLogsByDateRange(dailyLogs, startDate, endDate) {
|
|
|
232
247
|
return filtered;
|
|
233
248
|
}
|
|
234
249
|
|
|
250
|
+
// src/tools/middleware/sync-middleware.ts
|
|
251
|
+
function withSyncedBlock(baseDir, handler) {
|
|
252
|
+
return async (input) => {
|
|
253
|
+
await upgradeToReadWrite(baseDir, { fallbackToReadOnly: true });
|
|
254
|
+
let syncResult;
|
|
255
|
+
if (getConnectionMode() === "read_write") {
|
|
256
|
+
try {
|
|
257
|
+
syncResult = await syncBlock(input.blockId, baseDir);
|
|
258
|
+
} finally {
|
|
259
|
+
await downgradeToReadOnly(baseDir);
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
syncResult = { blockId: input.blockId, status: "unchanged" };
|
|
263
|
+
}
|
|
264
|
+
if (syncResult.status === "deleted") {
|
|
265
|
+
return {
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: "text",
|
|
269
|
+
text: `Block '${input.blockId}' no longer exists (folder was deleted). Call list_blocks to see available blocks.`
|
|
270
|
+
}
|
|
271
|
+
],
|
|
272
|
+
isError: true
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
if (syncResult.status === "error" && syncResult.error) {
|
|
276
|
+
return {
|
|
277
|
+
content: [
|
|
278
|
+
{
|
|
279
|
+
type: "text",
|
|
280
|
+
text: `Sync error for block '${input.blockId}': ${syncResult.error}. Call list_blocks to see available blocks.`
|
|
281
|
+
}
|
|
282
|
+
],
|
|
283
|
+
isError: true
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return handler(input, { syncResult, baseDir });
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/tools/blocks/paired-comparison.ts
|
|
291
|
+
var ATTRIBUTION_NOTE = "A trade's P&L is attributed evenly across the trading days it was open (dateOpened through dateClosed). Trading days are derived from the block's own trade data (the union of every trade's open and close dates) -- no market calendar is assumed, so weekends or holidays appear only if a trade spans them.";
|
|
292
|
+
var DEFAULT_CI_LEVEL = 0.95;
|
|
293
|
+
var DEFAULT_RESAMPLES = 2e3;
|
|
294
|
+
var DEFAULT_SEED = 42;
|
|
295
|
+
var SENSITIVITY_MULTIPLIERS = [0.5, 2];
|
|
296
|
+
var pairedComparisonInputSchema = z.object({
|
|
297
|
+
blockId: z.string().describe("Block folder name to analyze"),
|
|
298
|
+
strategyA: z.string().describe("Strategy name for arm A (case-insensitive)"),
|
|
299
|
+
strategyB: z.string().optional().describe(
|
|
300
|
+
"Strategy name for arm B (case-insensitive). If omitted, arm A is compared against a constant 0 -- i.e. is the edge distinguishable from nothing."
|
|
301
|
+
),
|
|
302
|
+
statistic: z.enum(["mean_daily_pnl", "median_daily_pnl"]).default("mean_daily_pnl").describe("Which daily-P&L functional to compare. Default mean_daily_pnl."),
|
|
303
|
+
dateRange: z.object({
|
|
304
|
+
start: z.string().describe("Start date (YYYY-MM-DD)"),
|
|
305
|
+
end: z.string().describe("End date (YYYY-MM-DD)")
|
|
306
|
+
}).optional().describe("Optional date range filter applied to both arms (by trade open date)."),
|
|
307
|
+
ciLevel: z.number().default(DEFAULT_CI_LEVEL).describe("Confidence level in (0, 1). Default 0.95 (deterministic)."),
|
|
308
|
+
resamples: z.number().int().default(DEFAULT_RESAMPLES).describe("Number of bootstrap resamples. Default 2000 (deterministic)."),
|
|
309
|
+
seed: z.number().int().default(DEFAULT_SEED).describe("PRNG seed. Same inputs + seed -> identical result. Default 42 (deterministic)."),
|
|
310
|
+
blockDays: z.number().int().min(1).optional().describe(
|
|
311
|
+
"Override the block length. By default it is derived from this block's own holding-period distribution (95th percentile of days-open)."
|
|
312
|
+
),
|
|
313
|
+
effectiveNFloorBlocks: z.number().min(0).optional().describe(
|
|
314
|
+
"Optional: refuse with notComparable when the shared overlap yields fewer distinct blocks than this floor. When omitted, only structural degeneracy refuses (underpowered)."
|
|
315
|
+
)
|
|
316
|
+
});
|
|
317
|
+
function toCalendarDateStr2(date) {
|
|
318
|
+
const y = date.getUTCFullYear();
|
|
319
|
+
const m = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
320
|
+
const d = String(date.getUTCDate()).padStart(2, "0");
|
|
321
|
+
return `${y}-${m}-${d}`;
|
|
322
|
+
}
|
|
323
|
+
function buildBlockTradingDayIndex(trades) {
|
|
324
|
+
const days = /* @__PURE__ */ new Set();
|
|
325
|
+
for (const t of trades) {
|
|
326
|
+
days.add(toCalendarDateStr2(t.dateOpened));
|
|
327
|
+
days.add(toCalendarDateStr2(t.dateClosed ?? t.dateOpened));
|
|
328
|
+
}
|
|
329
|
+
return Array.from(days).sort();
|
|
330
|
+
}
|
|
331
|
+
function gridSpan(grid, openStr, closeStr) {
|
|
332
|
+
let lo = grid.findIndex((d) => d >= openStr);
|
|
333
|
+
if (lo === -1) lo = grid.length;
|
|
334
|
+
let hi = -1;
|
|
335
|
+
for (let i = grid.length - 1; i >= 0; i--) {
|
|
336
|
+
if (grid[i] <= closeStr) {
|
|
337
|
+
hi = i;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return [lo, hi];
|
|
342
|
+
}
|
|
343
|
+
function armHoldingPeriods(armTrades, grid) {
|
|
344
|
+
return armTrades.map((t) => {
|
|
345
|
+
const openStr = toCalendarDateStr2(t.dateOpened);
|
|
346
|
+
const closeStr = toCalendarDateStr2(t.dateClosed ?? t.dateOpened);
|
|
347
|
+
const [lo, hi] = gridSpan(grid, openStr, closeStr);
|
|
348
|
+
return Math.max(1, hi - lo + 1);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function buildArmDaySeries(armTrades, grid) {
|
|
352
|
+
const values = new Array(grid.length).fill(0);
|
|
353
|
+
const observedMask = new Array(grid.length).fill(false);
|
|
354
|
+
for (const t of armTrades) {
|
|
355
|
+
const openStr = toCalendarDateStr2(t.dateOpened);
|
|
356
|
+
const closeStr = toCalendarDateStr2(t.dateClosed ?? t.dateOpened);
|
|
357
|
+
const [lo, hi] = gridSpan(grid, openStr, closeStr);
|
|
358
|
+
if (hi < lo) continue;
|
|
359
|
+
const span = hi - lo + 1;
|
|
360
|
+
const perDay = t.pl / span;
|
|
361
|
+
for (let i = lo; i <= hi; i++) {
|
|
362
|
+
values[i] += perDay;
|
|
363
|
+
observedMask[i] = true;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return { index: grid, values, observedMask };
|
|
367
|
+
}
|
|
368
|
+
function countObserved(series) {
|
|
369
|
+
return series.observedMask.reduce((n, o) => n + (o ? 1 : 0), 0);
|
|
370
|
+
}
|
|
371
|
+
function meanOf(values) {
|
|
372
|
+
return values.reduce((s, v) => s + v, 0) / values.length;
|
|
373
|
+
}
|
|
374
|
+
function medianOf(values) {
|
|
375
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
376
|
+
const mid = Math.floor(sorted.length / 2);
|
|
377
|
+
return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
378
|
+
}
|
|
379
|
+
var STATISTIC_FNS = {
|
|
380
|
+
mean_daily_pnl: meanOf,
|
|
381
|
+
median_daily_pnl: medianOf
|
|
382
|
+
};
|
|
383
|
+
var STATISTIC_LABELS = {
|
|
384
|
+
mean_daily_pnl: "mean daily P&L",
|
|
385
|
+
median_daily_pnl: "median daily P&L"
|
|
386
|
+
};
|
|
387
|
+
function runPairedBootstrapComparison(params) {
|
|
388
|
+
const {
|
|
389
|
+
armATrades,
|
|
390
|
+
armBTrades,
|
|
391
|
+
blockTrades,
|
|
392
|
+
statistic,
|
|
393
|
+
ciLevel,
|
|
394
|
+
resamples,
|
|
395
|
+
seed,
|
|
396
|
+
blockDays: blockDaysOverride,
|
|
397
|
+
effectiveNFloorBlocks,
|
|
398
|
+
strategyA,
|
|
399
|
+
strategyB
|
|
400
|
+
} = params;
|
|
401
|
+
if (armATrades.length === 0) {
|
|
402
|
+
throw new Error(`No trades found for strategy "${strategyA}".`);
|
|
403
|
+
}
|
|
404
|
+
if (armBTrades !== null && armBTrades.length === 0) {
|
|
405
|
+
throw new Error(`No trades found for strategy "${strategyB}".`);
|
|
406
|
+
}
|
|
407
|
+
const grid = buildBlockTradingDayIndex(blockTrades);
|
|
408
|
+
const armA = buildArmDaySeries(armATrades, grid);
|
|
409
|
+
const armB = armBTrades !== null ? buildArmDaySeries(armBTrades, grid) : null;
|
|
410
|
+
const hpA = holdingPeriodBlockDays(armHoldingPeriods(armATrades, grid));
|
|
411
|
+
const hpB = armBTrades !== null ? holdingPeriodBlockDays(armHoldingPeriods(armBTrades, grid)) : hpA;
|
|
412
|
+
const derivedBlockDays = Math.max(hpA, hpB);
|
|
413
|
+
const derivedFromArm = hpB > hpA ? "B" : "A";
|
|
414
|
+
const blockDays = blockDaysOverride ?? derivedBlockDays;
|
|
415
|
+
const blockDaysNote = blockDaysOverride !== void 0 ? `block length = ${blockDays} trading day(s), caller-supplied override` : armB !== null ? `block length = ${blockDays} trading day(s), derived from the 95th-percentile holding period of arm ${derivedFromArm} (the longer-held arm -- the conservative choice)` : `block length = ${blockDays} trading day(s), derived from the 95th-percentile holding period of arm A`;
|
|
416
|
+
const result = pairedBlockBootstrap({
|
|
417
|
+
armA,
|
|
418
|
+
armB: armB ?? { constant: 0 },
|
|
419
|
+
statistic: STATISTIC_FNS[statistic],
|
|
420
|
+
holdingRule: { blockDays, sensitivity: SENSITIVITY_MULTIPLIERS },
|
|
421
|
+
ciLevel,
|
|
422
|
+
resamples,
|
|
423
|
+
seed,
|
|
424
|
+
effectiveNFloorBlocks
|
|
425
|
+
});
|
|
426
|
+
const statLabel = STATISTIC_LABELS[statistic];
|
|
427
|
+
const comparisonLabel = armB !== null ? `${strategyA} minus ${strategyB}` : `${strategyA} vs 0`;
|
|
428
|
+
let summary;
|
|
429
|
+
let refusalMessage = null;
|
|
430
|
+
if (result.status === "notComparable") {
|
|
431
|
+
refusalMessage = `Not comparable: effective sample (${result.effectiveN.toFixed(2)} blocks) is below the required power floor. A confidence interval is withheld.`;
|
|
432
|
+
summary = `Paired comparison (${comparisonLabel}): ${refusalMessage}`;
|
|
433
|
+
} else if (result.status === "underpowered") {
|
|
434
|
+
refusalMessage = `Underpowered: the shared overlap is too short to resample at a block length of ${blockDays} trading day(s) (fewer than two drawable blocks). A confidence interval is withheld.`;
|
|
435
|
+
summary = `Paired comparison (${comparisonLabel}): ${refusalMessage}`;
|
|
436
|
+
} else {
|
|
437
|
+
const point = result.point ?? 0;
|
|
438
|
+
const low = result.ci.low ?? 0;
|
|
439
|
+
const high = result.ci.high ?? 0;
|
|
440
|
+
const includesZero = low <= 0 && high >= 0;
|
|
441
|
+
const zeroClause = includesZero ? "includes zero (not distinguishable)" : "excludes zero (distinguishable)";
|
|
442
|
+
const subject = armB !== null ? `the difference in ${statLabel} (${comparisonLabel})` : `${statLabel}`;
|
|
443
|
+
summary = `Paired comparison: ${subject} is ${formatCurrency(point)}, ${(ciLevel * 100).toFixed(0)}% CI [${formatCurrency(low)}, ${formatCurrency(high)}] -- ${zeroClause}.`;
|
|
444
|
+
}
|
|
445
|
+
const data = {
|
|
446
|
+
comparison: {
|
|
447
|
+
strategyA,
|
|
448
|
+
strategyB: strategyB ?? null,
|
|
449
|
+
mode: armB !== null ? "two-arm" : "single-arm-vs-zero",
|
|
450
|
+
description: comparisonLabel
|
|
451
|
+
},
|
|
452
|
+
statistic,
|
|
453
|
+
point: result.point,
|
|
454
|
+
ci: result.ci,
|
|
455
|
+
status: result.status,
|
|
456
|
+
refusal: refusalMessage,
|
|
457
|
+
effectiveN: result.effectiveN,
|
|
458
|
+
blockDays: result.blockDays,
|
|
459
|
+
blockDaysDerivation: blockDaysNote,
|
|
460
|
+
overlapWindow: result.overlapWindow,
|
|
461
|
+
observedDays: {
|
|
462
|
+
armA: countObserved(armA),
|
|
463
|
+
armB: armB !== null ? countObserved(armB) : null
|
|
464
|
+
},
|
|
465
|
+
tradeCounts: {
|
|
466
|
+
armA: armATrades.length,
|
|
467
|
+
armB: armBTrades !== null ? armBTrades.length : null
|
|
468
|
+
},
|
|
469
|
+
sensitivity: result.sensitivity,
|
|
470
|
+
resamples,
|
|
471
|
+
seed: result.seed,
|
|
472
|
+
ciLevel,
|
|
473
|
+
attributionMethodology: ATTRIBUTION_NOTE
|
|
474
|
+
};
|
|
475
|
+
return { summary, data, result };
|
|
476
|
+
}
|
|
477
|
+
function registerPairedComparisonTool(server, baseDir) {
|
|
478
|
+
server.registerTool(
|
|
479
|
+
"paired_bootstrap_comparison",
|
|
480
|
+
{
|
|
481
|
+
description: "Honest confidence intervals for 'is strategy A actually different from strategy B (or from zero)' -- day-block resampling that accounts for multi-day positions, dormant periods, and paired comparison on shared days. " + ATTRIBUTION_NOTE,
|
|
482
|
+
inputSchema: pairedComparisonInputSchema
|
|
483
|
+
},
|
|
484
|
+
withSyncedBlock(baseDir, async (input) => {
|
|
485
|
+
try {
|
|
486
|
+
const { blockId, strategyA, strategyB, statistic, dateRange } = input;
|
|
487
|
+
const block = await loadBlock(baseDir, blockId);
|
|
488
|
+
const inRange = (trades) => dateRange ? filterByDateRange(trades, dateRange.start, dateRange.end) : trades;
|
|
489
|
+
const blockTrades = inRange(block.trades);
|
|
490
|
+
const armATrades = inRange(filterByStrategy(block.trades, strategyA));
|
|
491
|
+
const armBTrades = strategyB !== void 0 ? inRange(filterByStrategy(block.trades, strategyB)) : null;
|
|
492
|
+
const { summary, data } = runPairedBootstrapComparison({
|
|
493
|
+
armATrades,
|
|
494
|
+
armBTrades,
|
|
495
|
+
blockTrades,
|
|
496
|
+
statistic,
|
|
497
|
+
ciLevel: input.ciLevel,
|
|
498
|
+
resamples: input.resamples,
|
|
499
|
+
seed: input.seed,
|
|
500
|
+
blockDays: input.blockDays,
|
|
501
|
+
effectiveNFloorBlocks: input.effectiveNFloorBlocks,
|
|
502
|
+
strategyA,
|
|
503
|
+
strategyB
|
|
504
|
+
});
|
|
505
|
+
return createToolOutput(summary, { blockId, ...data });
|
|
506
|
+
} catch (error) {
|
|
507
|
+
return {
|
|
508
|
+
content: [
|
|
509
|
+
{
|
|
510
|
+
type: "text",
|
|
511
|
+
text: `Error running paired bootstrap comparison: ${error.message}`
|
|
512
|
+
}
|
|
513
|
+
],
|
|
514
|
+
isError: true
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
})
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// src/utils/trading-dates.ts
|
|
522
|
+
function yesterdayET(now = /* @__PURE__ */ new Date()) {
|
|
523
|
+
const todayET = new Intl.DateTimeFormat("en-CA", {
|
|
524
|
+
timeZone: "America/New_York",
|
|
525
|
+
year: "numeric",
|
|
526
|
+
month: "2-digit",
|
|
527
|
+
day: "2-digit"
|
|
528
|
+
}).format(now);
|
|
529
|
+
const [y, m, d] = todayET.split("-").map(Number);
|
|
530
|
+
const prior = new Date(Date.UTC(y, m - 1, d));
|
|
531
|
+
prior.setUTCDate(prior.getUTCDate() - 1);
|
|
532
|
+
const py = prior.getUTCFullYear();
|
|
533
|
+
const pm = String(prior.getUTCMonth() + 1).padStart(2, "0");
|
|
534
|
+
const pd = String(prior.getUTCDate()).padStart(2, "0");
|
|
535
|
+
return `${py}-${pm}-${pd}`;
|
|
536
|
+
}
|
|
537
|
+
|
|
235
538
|
// src/utils/schema-metadata.ts
|
|
236
539
|
var SCHEMA_DESCRIPTIONS = {
|
|
237
540
|
trades: {
|
|
@@ -2589,113 +2892,94 @@ function buildFilterPredicate(filter) {
|
|
|
2589
2892
|
}
|
|
2590
2893
|
|
|
2591
2894
|
// src/tools/profiles.ts
|
|
2592
|
-
import { z } from "zod";
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
content: [
|
|
2598
|
-
{ type: "text", text: summary },
|
|
2599
|
-
{
|
|
2600
|
-
type: "resource",
|
|
2601
|
-
resource: {
|
|
2602
|
-
uri: "data:application/json",
|
|
2603
|
-
mimeType: "application/json",
|
|
2604
|
-
text: JSON.stringify(data)
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
]
|
|
2608
|
-
};
|
|
2609
|
-
}
|
|
2610
|
-
|
|
2611
|
-
// src/tools/profiles.ts
|
|
2612
|
-
var profileStrategySchema = z.object({
|
|
2613
|
-
blockId: z.string().describe("Block ID (block_id) to associate the profile with"),
|
|
2614
|
-
strategyName: z.string().describe("Human-readable strategy name (e.g., 'Pickle RIC v2')"),
|
|
2615
|
-
structureType: z.string().describe(
|
|
2895
|
+
import { z as z2 } from "zod";
|
|
2896
|
+
var profileStrategySchema = z2.object({
|
|
2897
|
+
blockId: z2.string().describe("Block ID (block_id) to associate the profile with"),
|
|
2898
|
+
strategyName: z2.string().describe("Human-readable strategy name (e.g., 'Pickle RIC v2')"),
|
|
2899
|
+
structureType: z2.string().describe(
|
|
2616
2900
|
"Option structure type: iron_condor, calendar_spread, double_calendar, vertical_spread, butterfly, reverse_iron_condor, short_put_spread, short_call_spread, straddle, strangle, etc."
|
|
2617
2901
|
),
|
|
2618
|
-
greeksBias:
|
|
2902
|
+
greeksBias: z2.string().describe(
|
|
2619
2903
|
"Primary greeks exposure: theta_positive, vega_negative, delta_neutral, delta_positive, delta_negative, gamma_scalp, etc."
|
|
2620
2904
|
),
|
|
2621
|
-
thesis:
|
|
2622
|
-
legs:
|
|
2623
|
-
|
|
2624
|
-
type:
|
|
2625
|
-
strike:
|
|
2626
|
-
expiry:
|
|
2627
|
-
quantity:
|
|
2628
|
-
strikeMethod:
|
|
2629
|
-
strikeValue:
|
|
2905
|
+
thesis: z2.string().default("").describe("Free-text description of the strategy thesis"),
|
|
2906
|
+
legs: z2.array(
|
|
2907
|
+
z2.object({
|
|
2908
|
+
type: z2.string().describe("Leg type: long_put, short_call, long_call, short_put, etc."),
|
|
2909
|
+
strike: z2.string().describe("Strike selection: ATM, 5-delta, 30-delta, etc."),
|
|
2910
|
+
expiry: z2.string().describe("Expiry selection: same-day, weekly, 45-DTE, etc."),
|
|
2911
|
+
quantity: z2.number().describe("Quantity (positive=long, negative=short)"),
|
|
2912
|
+
strikeMethod: z2.enum(["delta", "dollar_price", "offset", "percentage"]).optional().describe("How strike is selected"),
|
|
2913
|
+
strikeValue: z2.number().optional().describe("Numeric strike value (e.g., 25 for 25-delta)")
|
|
2630
2914
|
})
|
|
2631
2915
|
).default([]).describe("Structured leg descriptions"),
|
|
2632
|
-
entryFilters:
|
|
2633
|
-
|
|
2634
|
-
field:
|
|
2635
|
-
operator:
|
|
2636
|
-
value:
|
|
2637
|
-
description:
|
|
2638
|
-
source:
|
|
2916
|
+
entryFilters: z2.array(
|
|
2917
|
+
z2.object({
|
|
2918
|
+
field: z2.string().describe("Market data field: VIX_Close, RSI_14, Vol_Regime, etc."),
|
|
2919
|
+
operator: z2.string().describe("Comparison operator: >, <, >=, <=, ==, between, in"),
|
|
2920
|
+
value: z2.union([z2.string(), z2.number(), z2.array(z2.union([z2.string(), z2.number()]))]).describe("Filter value or array for between/in operators"),
|
|
2921
|
+
description: z2.string().optional().describe("Human-readable description of this filter"),
|
|
2922
|
+
source: z2.enum(["market", "execution"]).optional().describe(
|
|
2639
2923
|
"Filter source: 'market' = testable against market data columns, 'execution' = platform-level (time windows, leg ratios). Defaults to 'market'. Execution filters are documented but skipped during validate_entry_filters analysis."
|
|
2640
2924
|
)
|
|
2641
2925
|
})
|
|
2642
2926
|
).default([]).describe(
|
|
2643
2927
|
"Entry condition filters. Tag each with source: 'market' (testable in analysis) or 'execution' (OO/platform-level, skipped in analysis)."
|
|
2644
2928
|
),
|
|
2645
|
-
exitRules:
|
|
2646
|
-
|
|
2647
|
-
type:
|
|
2648
|
-
trigger:
|
|
2649
|
-
description:
|
|
2650
|
-
stopLossType:
|
|
2651
|
-
stopLossValue:
|
|
2652
|
-
monitoring:
|
|
2653
|
-
granularity:
|
|
2654
|
-
priceSource:
|
|
2929
|
+
exitRules: z2.array(
|
|
2930
|
+
z2.object({
|
|
2931
|
+
type: z2.string().describe("Rule type: stop_loss, profit_target, time_exit, conditional"),
|
|
2932
|
+
trigger: z2.string().describe("Trigger condition: '200% of credit', '50% of max profit', '15:00 ET'"),
|
|
2933
|
+
description: z2.string().optional().describe("Human-readable description"),
|
|
2934
|
+
stopLossType: z2.enum(["percentage", "dollar", "sl_ratio", "debit_percentage"]).optional().describe("Stop loss calculation method"),
|
|
2935
|
+
stopLossValue: z2.number().optional().describe("Stop loss numeric value"),
|
|
2936
|
+
monitoring: z2.object({
|
|
2937
|
+
granularity: z2.enum(["intra_minute", "candle_close", "end_of_bar"]).optional().describe("Price check frequency"),
|
|
2938
|
+
priceSource: z2.enum(["nbbo", "mid", "last"]).optional().describe("Which price to use")
|
|
2655
2939
|
}).optional().describe("Monitoring configuration for this rule"),
|
|
2656
|
-
slippage:
|
|
2940
|
+
slippage: z2.number().optional().describe("Per-rule slippage override")
|
|
2657
2941
|
})
|
|
2658
2942
|
).default([]).describe("Exit rules and triggers"),
|
|
2659
|
-
expectedRegimes:
|
|
2943
|
+
expectedRegimes: z2.array(z2.enum(["very_low", "low", "below_avg", "above_avg", "high", "extreme"])).default([]).describe(
|
|
2660
2944
|
"VIX-based vol regimes this strategy targets. very_low=VIX<13, low=13-16, below_avg=16-20, above_avg=20-25, high=25-30, extreme=30+"
|
|
2661
2945
|
),
|
|
2662
|
-
keyMetrics:
|
|
2663
|
-
expectedWinRate:
|
|
2664
|
-
targetPremium:
|
|
2665
|
-
maxLoss:
|
|
2666
|
-
profitTarget:
|
|
2946
|
+
keyMetrics: z2.object({
|
|
2947
|
+
expectedWinRate: z2.number().optional().describe("Expected win rate (0-1)"),
|
|
2948
|
+
targetPremium: z2.number().optional().describe("Target premium collected ($)"),
|
|
2949
|
+
maxLoss: z2.number().optional().describe("Maximum loss per contract ($)"),
|
|
2950
|
+
profitTarget: z2.number().optional().describe("Profit target ($ or %)")
|
|
2667
2951
|
}).passthrough().default({}).describe("Performance benchmarks and strategy-specific metrics"),
|
|
2668
|
-
positionSizing:
|
|
2669
|
-
method:
|
|
2670
|
-
allocationPct:
|
|
2671
|
-
maxContracts:
|
|
2672
|
-
maxAllocationDollar:
|
|
2673
|
-
maxOpenPositions:
|
|
2674
|
-
description:
|
|
2675
|
-
backtestAllocationPct:
|
|
2676
|
-
liveAllocationPct:
|
|
2677
|
-
maxContractsPerTrade:
|
|
2952
|
+
positionSizing: z2.object({
|
|
2953
|
+
method: z2.string().describe("Sizing method: pct_of_portfolio, fixed_contracts, fixed_dollar, discretionary"),
|
|
2954
|
+
allocationPct: z2.number().optional().describe("Portfolio allocation percentage (e.g., 2 for 2%)"),
|
|
2955
|
+
maxContracts: z2.number().optional().describe("Maximum contracts per trade"),
|
|
2956
|
+
maxAllocationDollar: z2.number().optional().describe("Maximum dollar allocation per trade"),
|
|
2957
|
+
maxOpenPositions: z2.number().optional().describe("Maximum concurrent open positions"),
|
|
2958
|
+
description: z2.string().optional().describe("Free-text sizing notes"),
|
|
2959
|
+
backtestAllocationPct: z2.number().optional().describe("Allocation % used in backtest"),
|
|
2960
|
+
liveAllocationPct: z2.number().optional().describe("Allocation % used in live portfolio"),
|
|
2961
|
+
maxContractsPerTrade: z2.number().optional().describe("Per-entry contract cap (distinct from maxContracts hard cap)")
|
|
2678
2962
|
}).optional().describe(
|
|
2679
2963
|
"Position sizing rules. Per-block \u2014 same strategy in backtest vs portfolio may have different sizing."
|
|
2680
2964
|
),
|
|
2681
|
-
underlying:
|
|
2682
|
-
reEntry:
|
|
2683
|
-
capProfits:
|
|
2684
|
-
capLosses:
|
|
2685
|
-
requireTwoPricesPT:
|
|
2686
|
-
closeOnCompletion:
|
|
2687
|
-
ignoreMarginReq:
|
|
2965
|
+
underlying: z2.string().optional().describe("Underlying symbol: SPX, QQQ, etc."),
|
|
2966
|
+
reEntry: z2.boolean().optional().describe("Strategy supports re-entry on same day"),
|
|
2967
|
+
capProfits: z2.boolean().optional().describe("Profits are capped by structure"),
|
|
2968
|
+
capLosses: z2.boolean().optional().describe("Losses are capped by structure"),
|
|
2969
|
+
requireTwoPricesPT: z2.boolean().optional().describe("Profit target requires two prices"),
|
|
2970
|
+
closeOnCompletion: z2.boolean().optional().describe("Close entire position when any leg hits target"),
|
|
2971
|
+
ignoreMarginReq: z2.boolean().optional().describe("Strategy ignores standard margin requirements")
|
|
2688
2972
|
});
|
|
2689
|
-
var getStrategyProfileSchema =
|
|
2690
|
-
blockId:
|
|
2691
|
-
strategyName:
|
|
2973
|
+
var getStrategyProfileSchema = z2.object({
|
|
2974
|
+
blockId: z2.string().describe("Block ID to look up"),
|
|
2975
|
+
strategyName: z2.string().describe("Strategy name to look up")
|
|
2692
2976
|
});
|
|
2693
|
-
var listProfilesSchema =
|
|
2694
|
-
blockId:
|
|
2977
|
+
var listProfilesSchema = z2.object({
|
|
2978
|
+
blockId: z2.string().optional().describe("Optional block ID filter. Omit to list all profiles across all blocks.")
|
|
2695
2979
|
});
|
|
2696
|
-
var deleteProfileSchema =
|
|
2697
|
-
blockId:
|
|
2698
|
-
strategyName:
|
|
2980
|
+
var deleteProfileSchema = z2.object({
|
|
2981
|
+
blockId: z2.string().describe("Block ID of the profile to delete"),
|
|
2982
|
+
strategyName: z2.string().describe("Strategy name of the profile to delete")
|
|
2699
2983
|
});
|
|
2700
2984
|
async function handleProfileStrategy(input, baseDir) {
|
|
2701
2985
|
await upgradeToReadWrite(baseDir);
|
|
@@ -2781,7 +3065,7 @@ async function handleDeleteProfile(input, baseDir) {
|
|
|
2781
3065
|
}
|
|
2782
3066
|
|
|
2783
3067
|
// src/tools/profile-analysis.ts
|
|
2784
|
-
import { z as
|
|
3068
|
+
import { z as z3 } from "zod";
|
|
2785
3069
|
function formatTradeDate(date) {
|
|
2786
3070
|
if (typeof date === "string") {
|
|
2787
3071
|
const match = date.match(/^(\d{4})-(\d{2})-(\d{2})/);
|
|
@@ -2937,10 +3221,10 @@ function findBucket(value, buckets) {
|
|
|
2937
3221
|
}
|
|
2938
3222
|
return null;
|
|
2939
3223
|
}
|
|
2940
|
-
var analyzeStructureFitSchema =
|
|
2941
|
-
blockId:
|
|
2942
|
-
strategyName:
|
|
2943
|
-
minTrades:
|
|
3224
|
+
var analyzeStructureFitSchema = z3.object({
|
|
3225
|
+
blockId: z3.string().describe("Block ID to analyze"),
|
|
3226
|
+
strategyName: z3.string().describe("Strategy name matching a stored profile"),
|
|
3227
|
+
minTrades: z3.number().optional().default(10).describe("Minimum trades per bucket for reliable stats (thin-data warning threshold)")
|
|
2944
3228
|
});
|
|
2945
3229
|
async function handleAnalyzeStructureFit(input, baseDir) {
|
|
2946
3230
|
const { blockId, strategyName } = input;
|
|
@@ -3113,11 +3397,11 @@ async function handleAnalyzeStructureFit(input, baseDir) {
|
|
|
3113
3397
|
}
|
|
3114
3398
|
});
|
|
3115
3399
|
}
|
|
3116
|
-
var validateEntryFiltersSchema =
|
|
3117
|
-
blockId:
|
|
3118
|
-
strategyName:
|
|
3119
|
-
minTrades:
|
|
3120
|
-
maxAblationFilters:
|
|
3400
|
+
var validateEntryFiltersSchema = z3.object({
|
|
3401
|
+
blockId: z3.string().describe("Block ID to analyze"),
|
|
3402
|
+
strategyName: z3.string().describe("Strategy name matching a stored profile"),
|
|
3403
|
+
minTrades: z3.number().optional().default(10).describe("Minimum trades per group for reliable stats"),
|
|
3404
|
+
maxAblationFilters: z3.number().optional().default(8).describe("Maximum number of filters for pairwise ablation (cap for combinatorial explosion)")
|
|
3121
3405
|
});
|
|
3122
3406
|
async function handleValidateEntryFilters(input, baseDir) {
|
|
3123
3407
|
const { blockId, strategyName } = input;
|
|
@@ -3337,9 +3621,9 @@ async function handleValidateEntryFilters(input, baseDir) {
|
|
|
3337
3621
|
warnings
|
|
3338
3622
|
});
|
|
3339
3623
|
}
|
|
3340
|
-
var portfolioStructureMapSchema =
|
|
3341
|
-
blockId:
|
|
3342
|
-
minTrades:
|
|
3624
|
+
var portfolioStructureMapSchema = z3.object({
|
|
3625
|
+
blockId: z3.string().optional().describe("Block ID to analyze. When omitted, aggregate across all blocks."),
|
|
3626
|
+
minTrades: z3.number().optional().default(10).describe("Thin-data warning threshold (default: 10)")
|
|
3343
3627
|
});
|
|
3344
3628
|
async function handlePortfolioStructureMap(input, baseDir) {
|
|
3345
3629
|
try {
|
|
@@ -3531,7 +3815,7 @@ async function handlePortfolioStructureMap(input, baseDir) {
|
|
|
3531
3815
|
}
|
|
3532
3816
|
|
|
3533
3817
|
// src/tools/regime-advisor.ts
|
|
3534
|
-
import { z as
|
|
3818
|
+
import { z as z4 } from "zod";
|
|
3535
3819
|
function formatTradeDate2(date) {
|
|
3536
3820
|
if (typeof date === "string") {
|
|
3537
3821
|
const match = date.match(/^(\d{4})-(\d{2})-(\d{2})/);
|
|
@@ -3597,9 +3881,9 @@ var VOL_REGIME_LABELS2 = {
|
|
|
3597
3881
|
5: "high",
|
|
3598
3882
|
6: "extreme"
|
|
3599
3883
|
};
|
|
3600
|
-
var regimeAllocationAdvisorSchema =
|
|
3601
|
-
blockId:
|
|
3602
|
-
minTrades:
|
|
3884
|
+
var regimeAllocationAdvisorSchema = z4.object({
|
|
3885
|
+
blockId: z4.string().optional().describe("Block ID to analyze. When omitted, aggregate across all profiled strategies."),
|
|
3886
|
+
minTrades: z4.number().optional().default(5).describe("Minimum trades per regime cell for reliable stats (default: 5)")
|
|
3603
3887
|
});
|
|
3604
3888
|
async function handleRegimeAllocationAdvisor(input, baseDir) {
|
|
3605
3889
|
const minTrades = input.minTrades ?? 5;
|
|
@@ -3795,7 +4079,7 @@ function getResolvedProviderCapabilities(env = process.env) {
|
|
|
3795
4079
|
}
|
|
3796
4080
|
|
|
3797
4081
|
// src/tools/replay.ts
|
|
3798
|
-
import { z as
|
|
4082
|
+
import { z as z5 } from "zod";
|
|
3799
4083
|
|
|
3800
4084
|
// src/market/tickers/resolver.ts
|
|
3801
4085
|
var OCC_RE = /^([A-Z]+)\d{6}[CP]\d{6,11}$/;
|
|
@@ -3814,36 +4098,36 @@ function rootToUnderlying(input, registry) {
|
|
|
3814
4098
|
}
|
|
3815
4099
|
|
|
3816
4100
|
// src/tools/replay.ts
|
|
3817
|
-
var replayTradeSchema =
|
|
4101
|
+
var replayTradeSchema = z5.object({
|
|
3818
4102
|
// Mode A: Hypothetical / explicit legs
|
|
3819
|
-
legs:
|
|
3820
|
-
|
|
3821
|
-
ticker:
|
|
3822
|
-
strike:
|
|
3823
|
-
type:
|
|
3824
|
-
expiry:
|
|
3825
|
-
quantity:
|
|
3826
|
-
entry_price:
|
|
4103
|
+
legs: z5.array(
|
|
4104
|
+
z5.object({
|
|
4105
|
+
ticker: z5.string().describe("Underlying ticker, e.g., 'SPY', 'SPX'"),
|
|
4106
|
+
strike: z5.number().describe("Strike price"),
|
|
4107
|
+
type: z5.enum(["C", "P"]).describe("Call or Put"),
|
|
4108
|
+
expiry: z5.string().describe("Expiration date YYYY-MM-DD"),
|
|
4109
|
+
quantity: z5.number().describe("Positive = long, negative = short"),
|
|
4110
|
+
entry_price: z5.number().describe("Per-contract entry price (premium paid/received)")
|
|
3827
4111
|
})
|
|
3828
4112
|
).optional().describe("Explicit leg definitions for hypothetical replay"),
|
|
3829
4113
|
// Mode B: Tradelog replay
|
|
3830
|
-
block_id:
|
|
3831
|
-
trade_index:
|
|
4114
|
+
block_id: z5.string().optional().describe("Block ID to load trade from"),
|
|
4115
|
+
trade_index: z5.number().optional().describe("0-based index of trade in block's tradelog (ordered by date_opened)"),
|
|
3832
4116
|
// Common fields
|
|
3833
|
-
open_date:
|
|
4117
|
+
open_date: z5.string().optional().describe(
|
|
3834
4118
|
"Trade open date YYYY-MM-DD (required for hypothetical mode, auto-resolved for tradelog mode)"
|
|
3835
4119
|
),
|
|
3836
|
-
close_date:
|
|
4120
|
+
close_date: z5.string().optional().describe(
|
|
3837
4121
|
"Trade close date YYYY-MM-DD (required for hypothetical, auto-resolved for tradelog)"
|
|
3838
4122
|
),
|
|
3839
|
-
multiplier:
|
|
3840
|
-
format:
|
|
4123
|
+
multiplier: z5.number().default(100).describe("Contract multiplier (default 100 for standard options)"),
|
|
4124
|
+
format: z5.enum(["full", "summary", "sampled"]).default("sampled").describe(
|
|
3841
4125
|
"Output format: 'sampled' returns path sampled at ~15min intervals (default), 'full' returns complete minute-by-minute P&L path, 'summary' returns MFE/MAE/P&L without minute-level path"
|
|
3842
4126
|
),
|
|
3843
|
-
close_at:
|
|
4127
|
+
close_at: z5.enum(["trade", "expiry"]).default("trade").describe(
|
|
3844
4128
|
"When to end the P&L path: 'trade' (default) truncates at the trade's actual close time, 'expiry' shows full path through option expiry. Only applies to tradelog mode."
|
|
3845
4129
|
),
|
|
3846
|
-
skip_quotes:
|
|
4130
|
+
skip_quotes: z5.boolean().default(false).describe(
|
|
3847
4131
|
"Skip NBBO quote enrichment for option bars. Faster, but uses cached trade bars / HL2 marks."
|
|
3848
4132
|
)
|
|
3849
4133
|
});
|
|
@@ -4128,15 +4412,15 @@ async function handleReplayTrade(params, baseDir, stores, injectedConn) {
|
|
|
4128
4412
|
}
|
|
4129
4413
|
|
|
4130
4414
|
// src/tools/snapshot.ts
|
|
4131
|
-
import { z as
|
|
4132
|
-
var getOptionSnapshotSchema =
|
|
4133
|
-
underlying:
|
|
4134
|
-
strike_price_gte:
|
|
4135
|
-
strike_price_lte:
|
|
4136
|
-
expiration_date_gte:
|
|
4137
|
-
expiration_date_lte:
|
|
4138
|
-
contract_type:
|
|
4139
|
-
limit:
|
|
4415
|
+
import { z as z6 } from "zod";
|
|
4416
|
+
var getOptionSnapshotSchema = z6.object({
|
|
4417
|
+
underlying: z6.string().describe("Underlying ticker symbol (e.g., 'SPX', 'SPY', 'AAPL')"),
|
|
4418
|
+
strike_price_gte: z6.number().optional().describe("Minimum strike price filter"),
|
|
4419
|
+
strike_price_lte: z6.number().optional().describe("Maximum strike price filter"),
|
|
4420
|
+
expiration_date_gte: z6.string().optional().describe("Earliest expiration date (YYYY-MM-DD)"),
|
|
4421
|
+
expiration_date_lte: z6.string().optional().describe("Latest expiration date (YYYY-MM-DD)"),
|
|
4422
|
+
contract_type: z6.enum(["call", "put"]).optional().describe("Filter by call or put"),
|
|
4423
|
+
limit: z6.number().optional().default(50).describe("Max contracts to return (default 50, use higher for full chain)")
|
|
4140
4424
|
});
|
|
4141
4425
|
async function handleGetOptionSnapshot(params) {
|
|
4142
4426
|
try {
|
|
@@ -4948,8 +5232,8 @@ function analyzeExitTriggers(config) {
|
|
|
4948
5232
|
}
|
|
4949
5233
|
|
|
4950
5234
|
// src/tools/exit-analysis.ts
|
|
4951
|
-
import { z as
|
|
4952
|
-
var triggerTypeEnum =
|
|
5235
|
+
import { z as z7 } from "zod";
|
|
5236
|
+
var triggerTypeEnum = z7.enum([
|
|
4953
5237
|
"profitTarget",
|
|
4954
5238
|
"stopLoss",
|
|
4955
5239
|
"trailingStop",
|
|
@@ -4966,70 +5250,70 @@ var triggerTypeEnum = z6.enum([
|
|
|
4966
5250
|
"slRatioThreshold",
|
|
4967
5251
|
"slRatioMove"
|
|
4968
5252
|
]);
|
|
4969
|
-
var triggerConfigSchema =
|
|
5253
|
+
var triggerConfigSchema = z7.object({
|
|
4970
5254
|
type: triggerTypeEnum,
|
|
4971
|
-
threshold:
|
|
4972
|
-
unit:
|
|
4973
|
-
expiry:
|
|
4974
|
-
openDate:
|
|
4975
|
-
clockTime:
|
|
4976
|
-
trailAmount:
|
|
4977
|
-
steps:
|
|
4978
|
-
|
|
4979
|
-
armAt:
|
|
4980
|
-
stopAt:
|
|
4981
|
-
closeAllocationPct:
|
|
5255
|
+
threshold: z7.number(),
|
|
5256
|
+
unit: z7.enum(["percent", "dollar"]).default("dollar").optional(),
|
|
5257
|
+
expiry: z7.string().optional(),
|
|
5258
|
+
openDate: z7.string().optional(),
|
|
5259
|
+
clockTime: z7.string().optional(),
|
|
5260
|
+
trailAmount: z7.number().optional(),
|
|
5261
|
+
steps: z7.array(
|
|
5262
|
+
z7.object({
|
|
5263
|
+
armAt: z7.number(),
|
|
5264
|
+
stopAt: z7.number(),
|
|
5265
|
+
closeAllocationPct: z7.number().min(0).max(1).optional().describe("Fraction of REMAINING position to close at this milestone (0-1)")
|
|
4982
5266
|
})
|
|
4983
5267
|
).optional(),
|
|
4984
|
-
spreadWidth:
|
|
4985
|
-
contracts:
|
|
4986
|
-
legIndex:
|
|
4987
|
-
exitAbove:
|
|
4988
|
-
exitBelow:
|
|
5268
|
+
spreadWidth: z7.number().optional(),
|
|
5269
|
+
contracts: z7.number().optional(),
|
|
5270
|
+
legIndex: z7.number().optional().describe("0-based leg index for perLegDelta \u2014 targets specific leg"),
|
|
5271
|
+
exitAbove: z7.number().optional().describe("Fire when value exceeds this (directional, no abs)"),
|
|
5272
|
+
exitBelow: z7.number().optional().describe("Fire when value drops below this (directional, no abs)")
|
|
4989
5273
|
});
|
|
4990
|
-
var legSchema =
|
|
4991
|
-
ticker:
|
|
4992
|
-
strike:
|
|
4993
|
-
type:
|
|
4994
|
-
expiry:
|
|
4995
|
-
quantity:
|
|
4996
|
-
entry_price:
|
|
5274
|
+
var legSchema = z7.object({
|
|
5275
|
+
ticker: z7.string(),
|
|
5276
|
+
strike: z7.number(),
|
|
5277
|
+
type: z7.enum(["C", "P"]),
|
|
5278
|
+
expiry: z7.string(),
|
|
5279
|
+
quantity: z7.number(),
|
|
5280
|
+
entry_price: z7.number()
|
|
4997
5281
|
});
|
|
4998
|
-
var analyzeExitTriggersSchema =
|
|
5282
|
+
var analyzeExitTriggersSchema = z7.object({
|
|
4999
5283
|
// Replay inputs (same shape as replay_trade)
|
|
5000
|
-
legs:
|
|
5001
|
-
block_id:
|
|
5002
|
-
trade_index:
|
|
5003
|
-
open_date:
|
|
5004
|
-
close_date:
|
|
5005
|
-
multiplier:
|
|
5006
|
-
triggers:
|
|
5007
|
-
actual_exit_timestamp:
|
|
5008
|
-
leg_groups:
|
|
5009
|
-
|
|
5010
|
-
label:
|
|
5011
|
-
leg_indices:
|
|
5012
|
-
triggers:
|
|
5284
|
+
legs: z7.array(legSchema).optional(),
|
|
5285
|
+
block_id: z7.string().optional(),
|
|
5286
|
+
trade_index: z7.number().optional(),
|
|
5287
|
+
open_date: z7.string().optional(),
|
|
5288
|
+
close_date: z7.string().optional(),
|
|
5289
|
+
multiplier: z7.number().default(100),
|
|
5290
|
+
triggers: z7.array(triggerConfigSchema).describe("Exit triggers to evaluate against the P&L path"),
|
|
5291
|
+
actual_exit_timestamp: z7.string().optional().describe("Actual exit time for comparison (format: YYYY-MM-DD HH:MM)"),
|
|
5292
|
+
leg_groups: z7.array(
|
|
5293
|
+
z7.object({
|
|
5294
|
+
label: z7.string(),
|
|
5295
|
+
leg_indices: z7.array(z7.number()),
|
|
5296
|
+
triggers: z7.array(triggerConfigSchema)
|
|
5013
5297
|
})
|
|
5014
5298
|
).optional().describe("Per-leg-group exit triggers for multi-structure strategies"),
|
|
5015
|
-
format:
|
|
5299
|
+
format: z7.enum(["summary", "full"]).default("summary").describe("'summary' omits per-step trigger states, 'full' includes all fire events")
|
|
5016
5300
|
});
|
|
5017
|
-
var decomposeGreeksSchema =
|
|
5301
|
+
var decomposeGreeksSchema = z7.object({
|
|
5018
5302
|
// Same replay inputs
|
|
5019
|
-
legs:
|
|
5020
|
-
block_id:
|
|
5021
|
-
trade_index:
|
|
5022
|
-
open_date:
|
|
5023
|
-
close_date:
|
|
5024
|
-
multiplier:
|
|
5025
|
-
leg_groups:
|
|
5026
|
-
|
|
5027
|
-
label:
|
|
5028
|
-
leg_indices:
|
|
5303
|
+
legs: z7.array(legSchema).optional(),
|
|
5304
|
+
block_id: z7.string().optional(),
|
|
5305
|
+
trade_index: z7.number().optional(),
|
|
5306
|
+
open_date: z7.string().optional(),
|
|
5307
|
+
close_date: z7.string().optional(),
|
|
5308
|
+
multiplier: z7.number().default(100),
|
|
5309
|
+
leg_groups: z7.array(
|
|
5310
|
+
z7.object({
|
|
5311
|
+
label: z7.string(),
|
|
5312
|
+
leg_indices: z7.array(z7.number())
|
|
5029
5313
|
})
|
|
5030
5314
|
).optional().describe("Leg grouping for per-group vega attribution (e.g., front_month vs back_month)"),
|
|
5031
|
-
format:
|
|
5032
|
-
skip_quotes:
|
|
5315
|
+
format: z7.enum(["summary", "full"]).default("summary").describe("'summary' shows ranked factors, 'full' includes per-step contributions"),
|
|
5316
|
+
skip_quotes: z7.boolean().default(false).describe("Skip NBBO quote enrichment for option bars. Faster, but lower precision.")
|
|
5033
5317
|
});
|
|
5034
5318
|
var REVERSE_ROOT_MAP = {
|
|
5035
5319
|
SPXW: "SPX",
|
|
@@ -5455,7 +5739,7 @@ function analyzeBatch(trades, config) {
|
|
|
5455
5739
|
}
|
|
5456
5740
|
|
|
5457
5741
|
// src/tools/batch-exit-analysis.ts
|
|
5458
|
-
import { z as
|
|
5742
|
+
import { z as z8 } from "zod";
|
|
5459
5743
|
async function mapWithLimit(items, limit, fn) {
|
|
5460
5744
|
const results = new Array(items.length);
|
|
5461
5745
|
let idx = 0;
|
|
@@ -5469,7 +5753,7 @@ async function mapWithLimit(items, limit, fn) {
|
|
|
5469
5753
|
await Promise.all(workers);
|
|
5470
5754
|
return results;
|
|
5471
5755
|
}
|
|
5472
|
-
var triggerTypeEnum2 =
|
|
5756
|
+
var triggerTypeEnum2 = z8.enum([
|
|
5473
5757
|
"profitTarget",
|
|
5474
5758
|
"stopLoss",
|
|
5475
5759
|
"trailingStop",
|
|
@@ -5486,50 +5770,50 @@ var triggerTypeEnum2 = z7.enum([
|
|
|
5486
5770
|
"slRatioThreshold",
|
|
5487
5771
|
"slRatioMove"
|
|
5488
5772
|
]);
|
|
5489
|
-
var triggerConfigSchema2 =
|
|
5773
|
+
var triggerConfigSchema2 = z8.object({
|
|
5490
5774
|
type: triggerTypeEnum2,
|
|
5491
|
-
threshold:
|
|
5492
|
-
unit:
|
|
5493
|
-
expiry:
|
|
5494
|
-
openDate:
|
|
5495
|
-
clockTime:
|
|
5496
|
-
trailAmount:
|
|
5497
|
-
steps:
|
|
5498
|
-
|
|
5499
|
-
armAt:
|
|
5500
|
-
stopAt:
|
|
5501
|
-
closeAllocationPct:
|
|
5775
|
+
threshold: z8.number(),
|
|
5776
|
+
unit: z8.enum(["percent", "dollar"]).default("dollar").optional(),
|
|
5777
|
+
expiry: z8.string().optional(),
|
|
5778
|
+
openDate: z8.string().optional(),
|
|
5779
|
+
clockTime: z8.string().optional(),
|
|
5780
|
+
trailAmount: z8.number().optional(),
|
|
5781
|
+
steps: z8.array(
|
|
5782
|
+
z8.object({
|
|
5783
|
+
armAt: z8.number(),
|
|
5784
|
+
stopAt: z8.number(),
|
|
5785
|
+
closeAllocationPct: z8.number().min(0).max(1).optional().describe("Fraction of REMAINING position to close at this milestone (0-1)")
|
|
5502
5786
|
})
|
|
5503
5787
|
).optional(),
|
|
5504
|
-
spreadWidth:
|
|
5505
|
-
contracts:
|
|
5506
|
-
legIndex:
|
|
5507
|
-
exitAbove:
|
|
5508
|
-
exitBelow:
|
|
5788
|
+
spreadWidth: z8.number().optional(),
|
|
5789
|
+
contracts: z8.number().optional(),
|
|
5790
|
+
legIndex: z8.number().optional().describe("0-based leg index for perLegDelta \u2014 targets specific leg"),
|
|
5791
|
+
exitAbove: z8.number().optional().describe("Fire when value exceeds this (directional, no abs)"),
|
|
5792
|
+
exitBelow: z8.number().optional().describe("Fire when value drops below this (directional, no abs)")
|
|
5509
5793
|
});
|
|
5510
|
-
var batchExitAnalysisSchema =
|
|
5511
|
-
block_id:
|
|
5512
|
-
strategy:
|
|
5513
|
-
date_range:
|
|
5514
|
-
from:
|
|
5515
|
-
to:
|
|
5794
|
+
var batchExitAnalysisSchema = z8.object({
|
|
5795
|
+
block_id: z8.string().describe("Block ID to analyze trades from"),
|
|
5796
|
+
strategy: z8.string().optional().describe("Filter trades by strategy name (case-insensitive ILIKE)"),
|
|
5797
|
+
date_range: z8.object({
|
|
5798
|
+
from: z8.string().optional().describe("Start date YYYY-MM-DD"),
|
|
5799
|
+
to: z8.string().optional().describe("End date YYYY-MM-DD")
|
|
5516
5800
|
}).optional().describe("Filter trades by date range"),
|
|
5517
|
-
candidate_policy:
|
|
5518
|
-
leg_groups:
|
|
5519
|
-
|
|
5520
|
-
label:
|
|
5521
|
-
leg_indices:
|
|
5522
|
-
triggers:
|
|
5801
|
+
candidate_policy: z8.array(triggerConfigSchema2).describe("Candidate exit policy triggers to evaluate -- same schema as analyze_exit_triggers"),
|
|
5802
|
+
leg_groups: z8.array(
|
|
5803
|
+
z8.object({
|
|
5804
|
+
label: z8.string(),
|
|
5805
|
+
leg_indices: z8.array(z8.number()),
|
|
5806
|
+
triggers: z8.array(triggerConfigSchema2)
|
|
5523
5807
|
})
|
|
5524
5808
|
).optional().describe("Per-leg-group exit triggers for multi-structure strategies"),
|
|
5525
|
-
baseline_mode:
|
|
5809
|
+
baseline_mode: z8.enum(["actual", "holdToEnd"]).default("actual").describe(
|
|
5526
5810
|
"'actual' compares candidate vs trade's actual P&L; 'holdToEnd' compares vs last replay timestamp"
|
|
5527
5811
|
),
|
|
5528
|
-
limit:
|
|
5529
|
-
min_pl:
|
|
5530
|
-
max_pl:
|
|
5531
|
-
multiplier:
|
|
5532
|
-
format:
|
|
5812
|
+
limit: z8.number().min(1).max(200).default(50).describe("Max trades to analyze. Most recent trades selected"),
|
|
5813
|
+
min_pl: z8.number().optional().describe("Only include trades with actual P&L >= this value"),
|
|
5814
|
+
max_pl: z8.number().optional().describe("Only include trades with actual P&L <= this value"),
|
|
5815
|
+
multiplier: z8.number().default(100).describe("Contract multiplier (default 100)"),
|
|
5816
|
+
format: z8.enum(["summary", "full"]).default("summary").describe(
|
|
5533
5817
|
"'summary' returns aggregate stats + trigger attribution; 'full' adds per-trade breakdown"
|
|
5534
5818
|
)
|
|
5535
5819
|
});
|
|
@@ -5741,7 +6025,7 @@ function expandDateRange(fromDate, toDate) {
|
|
|
5741
6025
|
|
|
5742
6026
|
// src/tools/sql.ts
|
|
5743
6027
|
import * as path2 from "path";
|
|
5744
|
-
import { z as
|
|
6028
|
+
import { z as z9 } from "zod";
|
|
5745
6029
|
var BLOCKED_PATTERNS = [
|
|
5746
6030
|
// External access
|
|
5747
6031
|
{ pattern: /\bCOPY\b/i, operation: "COPY" },
|
|
@@ -6005,15 +6289,15 @@ function collectBackfillConcreteFallbacks(input) {
|
|
|
6005
6289
|
return fallbacks;
|
|
6006
6290
|
}
|
|
6007
6291
|
async function appendBackfillManifestLineDurable(manifestPath, line) {
|
|
6008
|
-
const
|
|
6292
|
+
const path11 = requireNonEmpty("manifestPath", manifestPath);
|
|
6009
6293
|
const text = String(line);
|
|
6010
6294
|
if (!text.endsWith("\n")) {
|
|
6011
6295
|
throw new Error("manifest line must end with a newline");
|
|
6012
6296
|
}
|
|
6013
|
-
const parentDir = dirname(
|
|
6297
|
+
const parentDir = dirname(path11);
|
|
6014
6298
|
await mkdir(parentDir, { recursive: true });
|
|
6015
|
-
const existedBeforeOpen = await pathExists(
|
|
6016
|
-
const handle = await open(
|
|
6299
|
+
const existedBeforeOpen = await pathExists(path11);
|
|
6300
|
+
const handle = await open(path11, "a");
|
|
6017
6301
|
try {
|
|
6018
6302
|
await handle.writeFile(text);
|
|
6019
6303
|
await handle.sync();
|
|
@@ -6079,9 +6363,9 @@ function validateManifestStatus(value) {
|
|
|
6079
6363
|
}
|
|
6080
6364
|
throw new Error("status must be prepared, committed, failed, or committed_manifest_failed");
|
|
6081
6365
|
}
|
|
6082
|
-
async function pathExists(
|
|
6366
|
+
async function pathExists(path11) {
|
|
6083
6367
|
try {
|
|
6084
|
-
const handle = await open(
|
|
6368
|
+
const handle = await open(path11, "r");
|
|
6085
6369
|
await handle.close();
|
|
6086
6370
|
return true;
|
|
6087
6371
|
} catch {
|
|
@@ -6144,7 +6428,7 @@ function formatIsoDate(date) {
|
|
|
6144
6428
|
}
|
|
6145
6429
|
|
|
6146
6430
|
// src/tools/greeks-attribution.ts
|
|
6147
|
-
import { z as
|
|
6431
|
+
import { z as z10 } from "zod";
|
|
6148
6432
|
|
|
6149
6433
|
// src/utils/flatfile-importer.ts
|
|
6150
6434
|
function tradingDays(from, to) {
|
|
@@ -6162,17 +6446,17 @@ function tradingDays(from, to) {
|
|
|
6162
6446
|
}
|
|
6163
6447
|
|
|
6164
6448
|
// src/tools/greeks-attribution.ts
|
|
6165
|
-
var getGreeksAttributionSchema =
|
|
6166
|
-
block_id:
|
|
6167
|
-
mode:
|
|
6168
|
-
trade_index:
|
|
6449
|
+
var getGreeksAttributionSchema = z10.object({
|
|
6450
|
+
block_id: z10.string().describe("Block ID to analyze"),
|
|
6451
|
+
mode: z10.enum(["summary", "instance"]).default("summary").describe("summary: block-level attribution. instance: single trade time-series."),
|
|
6452
|
+
trade_index: z10.number().int().min(0).optional().describe(
|
|
6169
6453
|
"Trade index (required for instance mode). Use get_block_info to find trade indices."
|
|
6170
6454
|
),
|
|
6171
|
-
skip_quotes:
|
|
6455
|
+
skip_quotes: z10.boolean().default(true).describe(
|
|
6172
6456
|
"Use cached bar data only (fast). Set false to fetch NBBO quotes for higher precision."
|
|
6173
6457
|
),
|
|
6174
|
-
detailed:
|
|
6175
|
-
strategy:
|
|
6458
|
+
detailed: z10.boolean().default(false).describe("false: 5 factors (delta, gamma, theta, vega, residual). true: adds charm, vanna."),
|
|
6459
|
+
strategy: z10.string().optional().describe("Filter to trades matching this strategy name (case-insensitive).")
|
|
6176
6460
|
});
|
|
6177
6461
|
var COLLAPSE_MAP = {
|
|
6178
6462
|
charm: "delta",
|
|
@@ -8137,27 +8421,27 @@ function createMarketStores(ctx) {
|
|
|
8137
8421
|
}
|
|
8138
8422
|
|
|
8139
8423
|
// src/market/tickers/schemas.ts
|
|
8140
|
-
import { z as
|
|
8424
|
+
import { z as z11 } from "zod";
|
|
8141
8425
|
var TICKER_RE = /^[A-Z][A-Z0-9^_-]*$/;
|
|
8142
|
-
var UnderlyingsFileSchema =
|
|
8143
|
-
version:
|
|
8144
|
-
underlyings:
|
|
8145
|
-
|
|
8146
|
-
underlying:
|
|
8147
|
-
roots:
|
|
8426
|
+
var UnderlyingsFileSchema = z11.object({
|
|
8427
|
+
version: z11.literal(1),
|
|
8428
|
+
underlyings: z11.array(
|
|
8429
|
+
z11.object({
|
|
8430
|
+
underlying: z11.string().min(1).max(16).regex(TICKER_RE),
|
|
8431
|
+
roots: z11.array(z11.string().min(1).max(16).regex(TICKER_RE)).min(1).max(32)
|
|
8148
8432
|
})
|
|
8149
8433
|
)
|
|
8150
8434
|
});
|
|
8151
|
-
var registerUnderlyingSchema =
|
|
8152
|
-
underlying:
|
|
8153
|
-
roots:
|
|
8435
|
+
var registerUnderlyingSchema = z11.object({
|
|
8436
|
+
underlying: z11.string().min(1).max(16).regex(TICKER_RE).describe("Canonical underlying symbol, e.g. SPX"),
|
|
8437
|
+
roots: z11.array(z11.string().min(1).max(16).regex(TICKER_RE)).min(1).max(32).describe("OCC roots that resolve to this underlying, e.g. ['SPX','SPXW','SPXQ']")
|
|
8154
8438
|
});
|
|
8155
|
-
var unregisterUnderlyingSchema =
|
|
8156
|
-
underlying:
|
|
8439
|
+
var unregisterUnderlyingSchema = z11.object({
|
|
8440
|
+
underlying: z11.string().min(1).max(16).regex(TICKER_RE).describe("Underlying to remove. Bundled defaults cannot be removed.")
|
|
8157
8441
|
});
|
|
8158
|
-
var listUnderlyingsSchema =
|
|
8159
|
-
var resolveRootSchema =
|
|
8160
|
-
input:
|
|
8442
|
+
var listUnderlyingsSchema = z11.object({});
|
|
8443
|
+
var resolveRootSchema = z11.object({
|
|
8444
|
+
input: z11.string().min(1).max(32).describe("Bare root ('SPXW') or full OCC ticker ('SPXW251219C05000000')")
|
|
8161
8445
|
});
|
|
8162
8446
|
|
|
8163
8447
|
// src/market/tickers/registry.ts
|
|
@@ -9686,11 +9970,10 @@ function compareRow(oldRow, newRow, kind, ticker, date) {
|
|
|
9686
9970
|
}
|
|
9687
9971
|
|
|
9688
9972
|
// src/utils/calibration-probe.ts
|
|
9689
|
-
import * as path11 from "path";
|
|
9690
9973
|
import { DuckDBInstance } from "@duckdb/node-api";
|
|
9691
9974
|
async function calibrateProviderFetch(ticker, probeDates, dataRoot) {
|
|
9692
9975
|
const provider = getProvider();
|
|
9693
|
-
const dbPath =
|
|
9976
|
+
const dbPath = resolveDbPath(dataRoot, "market");
|
|
9694
9977
|
const instance = await DuckDBInstance.create(dbPath);
|
|
9695
9978
|
const conn = await instance.connect();
|
|
9696
9979
|
const deltas = [];
|
|
@@ -9805,6 +10088,7 @@ export {
|
|
|
9805
10088
|
appendBackfillManifestLineDurable,
|
|
9806
10089
|
applyQuoteGreeks,
|
|
9807
10090
|
applyQuoteGreeksParallel,
|
|
10091
|
+
armHoldingPeriods,
|
|
9808
10092
|
assessPrecision,
|
|
9809
10093
|
bachelierDelta,
|
|
9810
10094
|
bachelierGamma,
|
|
@@ -9821,6 +10105,8 @@ export {
|
|
|
9821
10105
|
bsPrice,
|
|
9822
10106
|
bsTheta,
|
|
9823
10107
|
bsVega,
|
|
10108
|
+
buildArmDaySeries,
|
|
10109
|
+
buildBlockTradingDayIndex,
|
|
9824
10110
|
buildEnrichmentPlan,
|
|
9825
10111
|
buildFilterPredicate,
|
|
9826
10112
|
buildLookaheadFreeQuery,
|
|
@@ -9988,6 +10274,7 @@ export {
|
|
|
9988
10274
|
optionHistoryQuote,
|
|
9989
10275
|
optionHistoryQuoteBand,
|
|
9990
10276
|
optionListContracts,
|
|
10277
|
+
pairedComparisonInputSchema,
|
|
9991
10278
|
parseBackfillOccTicker,
|
|
9992
10279
|
parseCsvToBars,
|
|
9993
10280
|
parseDatabaseRowsToBars,
|
|
@@ -10002,6 +10289,7 @@ export {
|
|
|
10002
10289
|
readJsonFile,
|
|
10003
10290
|
readParquetFilesSql,
|
|
10004
10291
|
regimeAllocationAdvisorSchema,
|
|
10292
|
+
registerPairedComparisonTool,
|
|
10005
10293
|
registerTickerTools,
|
|
10006
10294
|
registerUnderlyingSchema,
|
|
10007
10295
|
replayTradeSchema,
|
|
@@ -10019,6 +10307,7 @@ export {
|
|
|
10019
10307
|
rthDailyAggregateSubquery,
|
|
10020
10308
|
runContextEnrichment,
|
|
10021
10309
|
runEnrichment,
|
|
10310
|
+
runPairedBootstrapComparison,
|
|
10022
10311
|
saveUserOverride,
|
|
10023
10312
|
scoreDataQuality,
|
|
10024
10313
|
selectVerificationSampleDates,
|