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.
Files changed (67) hide show
  1. package/README.md +3 -12
  2. package/dist/{chunk-C6LL746C.js → chunk-2I3S2ZLT.js} +259 -1
  3. package/dist/chunk-2I3S2ZLT.js.map +1 -0
  4. package/dist/{chunk-UBUC5A66.js → chunk-4HZLVUOZ.js} +81 -76
  5. package/dist/chunk-4HZLVUOZ.js.map +1 -0
  6. package/dist/{chunk-VDU25Z6X.js → chunk-NWNSKALN.js} +2 -2
  7. package/dist/{chunk-AP7IHUUR.js → chunk-WNTYA7ER.js} +2 -2
  8. package/dist/{chunk-6S37CXUA.js → chunk-YZA4RS76.js} +14 -6
  9. package/dist/chunk-YZA4RS76.js.map +1 -0
  10. package/dist/{chunk-SEUZYQGQ.js → chunk-ZTJXC3LS.js} +2 -2
  11. package/dist/daily-log-processor-MZW2XBZY.js +9 -0
  12. package/dist/market-provider-6U33TQUT.js +16 -0
  13. package/dist/{sync-EVLKB3ZJ.js → sync-3UBC37VW.js} +6 -6
  14. package/dist/test-exports.js +560 -271
  15. package/dist/test-exports.js.map +1 -1
  16. package/dist/trade-processor-DKDCWGKD.js +9 -0
  17. package/package.json +2 -6
  18. package/server/{chunk-YUCOAJ4Z.js → chunk-536NSFED.js} +2 -2
  19. package/server/{chunk-GH2552SE.js → chunk-A3UKD64A.js} +2 -2
  20. package/server/{chunk-ZBJCF4ZG.js → chunk-OMUDNJBJ.js} +2 -2
  21. package/server/{chunk-BOPHW5M6.js → chunk-RJDJHZ5Y.js} +414 -101
  22. package/server/chunk-RJDJHZ5Y.js.map +1 -0
  23. package/server/{chunk-4P7D7YZP.js → chunk-RM4B2VKS.js} +72 -71
  24. package/server/chunk-RM4B2VKS.js.map +1 -0
  25. package/server/{chunk-OBYKFW2B.js → chunk-SY6GDNVI.js} +14 -6
  26. package/server/chunk-SY6GDNVI.js.map +1 -0
  27. package/server/daily-log-processor-B2VPU2FQ.js +10 -0
  28. package/server/index.js +787 -552
  29. package/server/index.js.map +1 -1
  30. package/server/market-provider-L56RFHAC.js +17 -0
  31. package/server/{sync-V25UQJA3.js → sync-CENKDN53.js} +6 -6
  32. package/server/trade-processor-3PI4LHZI.js +10 -0
  33. package/src/db/backtest-schemas.ts +26 -4
  34. package/src/db/data-root.ts +22 -0
  35. package/src/test-exports.ts +12 -0
  36. package/src/tools/blocks/index.ts +2 -0
  37. package/src/tools/blocks/paired-comparison.ts +425 -0
  38. package/src/tools/imports.ts +2 -2
  39. package/src/utils/block-loader.ts +1 -1
  40. package/src/utils/calibration-probe.ts +2 -2
  41. package/dist/chunk-6S37CXUA.js.map +0 -1
  42. package/dist/chunk-C6LL746C.js.map +0 -1
  43. package/dist/chunk-UBUC5A66.js.map +0 -1
  44. package/dist/daily-log-processor-BY3ISY6K.js +0 -9
  45. package/dist/market-provider-H3ARIVZ4.js +0 -16
  46. package/dist/trade-processor-EYA3I3XB.js +0 -9
  47. package/manifest.json +0 -133
  48. package/server/chunk-4P7D7YZP.js.map +0 -1
  49. package/server/chunk-BOPHW5M6.js.map +0 -1
  50. package/server/chunk-OBYKFW2B.js.map +0 -1
  51. package/server/daily-log-processor-ENEUT22A.js +0 -10
  52. package/server/market-provider-B437HKLW.js +0 -17
  53. package/server/trade-processor-L3PIQ5TG.js +0 -10
  54. /package/dist/{chunk-VDU25Z6X.js.map → chunk-NWNSKALN.js.map} +0 -0
  55. /package/dist/{chunk-AP7IHUUR.js.map → chunk-WNTYA7ER.js.map} +0 -0
  56. /package/dist/{chunk-SEUZYQGQ.js.map → chunk-ZTJXC3LS.js.map} +0 -0
  57. /package/dist/{daily-log-processor-BY3ISY6K.js.map → daily-log-processor-MZW2XBZY.js.map} +0 -0
  58. /package/dist/{market-provider-H3ARIVZ4.js.map → market-provider-6U33TQUT.js.map} +0 -0
  59. /package/dist/{sync-EVLKB3ZJ.js.map → sync-3UBC37VW.js.map} +0 -0
  60. /package/dist/{trade-processor-EYA3I3XB.js.map → trade-processor-DKDCWGKD.js.map} +0 -0
  61. /package/server/{chunk-YUCOAJ4Z.js.map → chunk-536NSFED.js.map} +0 -0
  62. /package/server/{chunk-GH2552SE.js.map → chunk-A3UKD64A.js.map} +0 -0
  63. /package/server/{chunk-ZBJCF4ZG.js.map → chunk-OMUDNJBJ.js.map} +0 -0
  64. /package/server/{daily-log-processor-ENEUT22A.js.map → daily-log-processor-B2VPU2FQ.js.map} +0 -0
  65. /package/server/{market-provider-B437HKLW.js.map → market-provider-L56RFHAC.js.map} +0 -0
  66. /package/server/{sync-V25UQJA3.js.map → sync-CENKDN53.js.map} +0 -0
  67. /package/server/{trade-processor-L3PIQ5TG.js.map → trade-processor-3PI4LHZI.js.map} +0 -0
package/README.md CHANGED
@@ -14,13 +14,7 @@ Model Context Protocol (MCP) server for options trading analysis. Works with Cla
14
14
 
15
15
  ## Installation
16
16
 
17
- ### Option 1: MCPB Bundle (Claude Desktop - One Click)
18
-
19
- Download the latest `.mcpb` file from [Releases](https://github.com/tradeblocks-org/tradeblocks/releases) and double-click to install.
20
-
21
- The installer will prompt you to select your Trading Data Directory.
22
-
23
- ### Option 2: npx (All Platforms)
17
+ ### Option 1: npx (All Platforms)
24
18
 
25
19
  Run directly without installation:
26
20
 
@@ -32,9 +26,9 @@ npx tradeblocks-mcp ~/Trading/backtests
32
26
  npx tradeblocks-mcp --http ~/Trading/backtests
33
27
  ```
34
28
 
35
- See [Configuration by Platform](#configuration-by-platform) below for platform-specific setup.
29
+ For Claude Desktop, add the server to `claude_desktop_config.json` — see [Configuration by Platform](#configuration-by-platform) below for platform-specific setup.
36
30
 
37
- ### Option 3: From Source
31
+ ### Option 2: From Source
38
32
 
39
33
  ```bash
40
34
  git clone https://github.com/tradeblocks-org/tradeblocks
@@ -399,9 +393,6 @@ npm run build
399
393
 
400
394
  # Run tests
401
395
  npm test
402
-
403
- # Pack MCPB bundle
404
- npm run mcpb:pack
405
396
  ```
406
397
 
407
398
  ## Market Data (Optional)
@@ -21416,6 +21416,262 @@ var DAY_MS = 24 * 60 * 60 * 1e3;
21416
21416
  // ../lib/calculations/walk-forward-degradation.ts
21417
21417
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
21418
21418
 
21419
+ // ../lib/calculations/paired-block-bootstrap.ts
21420
+ function mulberry32(seed) {
21421
+ let state = seed >>> 0;
21422
+ return function() {
21423
+ state = state + 1831565813 >>> 0;
21424
+ let t = state;
21425
+ t = Math.imul(t ^ t >>> 15, t | 1);
21426
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
21427
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
21428
+ };
21429
+ }
21430
+ function deriveSeed(seed, blockDays) {
21431
+ return seed + Math.imul(blockDays, 2654435761) >>> 0;
21432
+ }
21433
+ function percentileOf(sorted, p) {
21434
+ const n = sorted.length;
21435
+ if (n === 1) return sorted[0];
21436
+ const rank = p * (n - 1);
21437
+ const lo = Math.floor(rank);
21438
+ const hi = Math.ceil(rank);
21439
+ if (lo === hi) return sorted[lo];
21440
+ const weight = rank - lo;
21441
+ return sorted[lo] * (1 - weight) + sorted[hi] * weight;
21442
+ }
21443
+ function observedValueMap(arm) {
21444
+ const map2 = /* @__PURE__ */ new Map();
21445
+ for (let i = 0; i < arm.index.length; i++) {
21446
+ if (arm.observedMask[i]) {
21447
+ map2.set(arm.index[i], arm.values[i]);
21448
+ }
21449
+ }
21450
+ return map2;
21451
+ }
21452
+ function isConstantArm(arm) {
21453
+ return arm !== void 0 && "constant" in arm;
21454
+ }
21455
+ function unionDays(a, b) {
21456
+ const seen = /* @__PURE__ */ new Set();
21457
+ for (const d of a) seen.add(d);
21458
+ for (const d of b) seen.add(d);
21459
+ return Array.from(seen).sort();
21460
+ }
21461
+ function buildOverlap(ambient, isObserved, deltaOf) {
21462
+ const days = [];
21463
+ const delta = [];
21464
+ const runs = [];
21465
+ let runStart = -1;
21466
+ for (const day of ambient) {
21467
+ if (isObserved(day)) {
21468
+ if (runStart === -1) runStart = days.length;
21469
+ days.push(day);
21470
+ delta.push(deltaOf(day));
21471
+ } else if (runStart !== -1) {
21472
+ runs.push({ start: runStart, length: days.length - runStart });
21473
+ runStart = -1;
21474
+ }
21475
+ }
21476
+ if (runStart !== -1) {
21477
+ runs.push({ start: runStart, length: days.length - runStart });
21478
+ }
21479
+ return { days, delta, runs };
21480
+ }
21481
+ function buildComparisonOverlap(armA, armB) {
21482
+ const mapA = observedValueMap(armA);
21483
+ if (armB === void 0 || isConstantArm(armB)) {
21484
+ const c = armB === void 0 ? 0 : armB.constant;
21485
+ return buildOverlap(
21486
+ armA.index,
21487
+ (day) => mapA.has(day),
21488
+ (day) => mapA.get(day) - c
21489
+ );
21490
+ }
21491
+ const mapB = observedValueMap(armB);
21492
+ const ambient = unionDays(armA.index, armB.index);
21493
+ return buildOverlap(
21494
+ ambient,
21495
+ (day) => mapA.has(day) && mapB.has(day),
21496
+ (day) => mapA.get(day) - mapB.get(day)
21497
+ );
21498
+ }
21499
+ function enumerateBlockStarts(runs, blockDays) {
21500
+ const starts = [];
21501
+ for (const run of runs) {
21502
+ const lastStart = run.length - blockDays;
21503
+ for (let offset = 0; offset <= lastStart; offset++) {
21504
+ starts.push(run.start + offset);
21505
+ }
21506
+ }
21507
+ return starts;
21508
+ }
21509
+ function drawResampleIndices(rng, blockStarts, blockDays, n) {
21510
+ const indices = [];
21511
+ while (indices.length < n) {
21512
+ const start = blockStarts[Math.floor(rng() * blockStarts.length)];
21513
+ for (let k = 0; k < blockDays && indices.length < n; k++) {
21514
+ indices.push(start + k);
21515
+ }
21516
+ }
21517
+ return indices;
21518
+ }
21519
+ function computeCore(params) {
21520
+ const {
21521
+ overlapDays,
21522
+ runs,
21523
+ deltaSeries,
21524
+ memberDeltas,
21525
+ extremum,
21526
+ blockDays,
21527
+ resamples,
21528
+ seed,
21529
+ ciLevel,
21530
+ statistic,
21531
+ effectiveNFloorBlocks
21532
+ } = params;
21533
+ const n = overlapDays.length;
21534
+ const effectiveN = n / blockDays;
21535
+ const takeExtremum = (values) => extremum === "min" ? Math.min(...values) : Math.max(...values);
21536
+ let point;
21537
+ if (n === 0) {
21538
+ point = null;
21539
+ } else if (memberDeltas) {
21540
+ point = takeExtremum(memberDeltas.map((d) => statistic(d)));
21541
+ } else {
21542
+ point = statistic(deltaSeries);
21543
+ }
21544
+ const blockStarts = enumerateBlockStarts(runs, blockDays);
21545
+ if (effectiveNFloorBlocks !== void 0 && effectiveN < effectiveNFloorBlocks) {
21546
+ return { point, low: null, high: null, effectiveN, status: "notComparable" };
21547
+ }
21548
+ if (blockStarts.length < 2) {
21549
+ return { point, low: null, high: null, effectiveN, status: "underpowered" };
21550
+ }
21551
+ const rng = mulberry32(deriveSeed(seed, blockDays));
21552
+ const distribution = new Array(resamples);
21553
+ for (let r = 0; r < resamples; r++) {
21554
+ const idx = drawResampleIndices(rng, blockStarts, blockDays, n);
21555
+ if (memberDeltas) {
21556
+ const stats = memberDeltas.map((d) => statistic(idx.map((i) => d[i])));
21557
+ distribution[r] = takeExtremum(stats);
21558
+ } else {
21559
+ distribution[r] = statistic(idx.map((i) => deltaSeries[i]));
21560
+ }
21561
+ }
21562
+ distribution.sort((a, b) => a - b);
21563
+ const alpha = 1 - ciLevel;
21564
+ const low = percentileOf(distribution, alpha / 2);
21565
+ const high = percentileOf(distribution, 1 - alpha / 2);
21566
+ return { point, low, high, effectiveN, status: "resolved" };
21567
+ }
21568
+ function buildSelectionOverlap(members) {
21569
+ const memberMaps = members.map((m) => {
21570
+ const overlap2 = buildComparisonOverlap(m.armA, m.armB);
21571
+ const map2 = /* @__PURE__ */ new Map();
21572
+ for (let i = 0; i < overlap2.days.length; i++) {
21573
+ map2.set(overlap2.days[i], overlap2.delta[i]);
21574
+ }
21575
+ return map2;
21576
+ });
21577
+ let ambient = [];
21578
+ for (const m of members) {
21579
+ const armBDays = isConstantArm(m.armB) || m.armB === void 0 ? [] : m.armB.index;
21580
+ ambient = unionDays(ambient, unionDays(m.armA.index, armBDays));
21581
+ }
21582
+ const overlap = buildOverlap(
21583
+ ambient,
21584
+ (day) => memberMaps.every((map2) => map2.has(day)),
21585
+ () => 0
21586
+ );
21587
+ const memberDeltas = memberMaps.map((map2) => overlap.days.map((day) => map2.get(day)));
21588
+ return { days: overlap.days, runs: overlap.runs, memberDeltas };
21589
+ }
21590
+ function holdingPeriodBlockDays(holdingPeriodsTradingDays, percentile = 0.95) {
21591
+ if (holdingPeriodsTradingDays.length === 0) return 1;
21592
+ const sorted = [...holdingPeriodsTradingDays].sort((a, b) => a - b);
21593
+ return Math.max(1, Math.round(percentileOf(sorted, percentile)));
21594
+ }
21595
+ function pairedBlockBootstrap(input) {
21596
+ const blockDays = Math.max(1, Math.round(input.holdingRule.blockDays));
21597
+ const { ciLevel, resamples, seed, statistic, effectiveNFloorBlocks } = input;
21598
+ let overlapDays;
21599
+ let runs;
21600
+ let deltaSeries;
21601
+ let memberDeltas;
21602
+ let extremum;
21603
+ let selection = null;
21604
+ if (input.selectionSet) {
21605
+ const sel = buildSelectionOverlap(input.selectionSet.members);
21606
+ overlapDays = sel.days;
21607
+ runs = sel.runs;
21608
+ memberDeltas = sel.memberDeltas;
21609
+ extremum = input.selectionSet.extremum;
21610
+ deltaSeries = [];
21611
+ const memberPoints = sel.memberDeltas.map((d) => statistic(d));
21612
+ const kConsidered = memberPoints.length;
21613
+ const centroid = kConsidered > 0 ? memberPoints.reduce((s, v) => s + v, 0) / kConsidered : 0;
21614
+ let maxGap = 0;
21615
+ if (kConsidered >= 2) {
21616
+ const ordered = [...memberPoints].sort((a, b) => a - b);
21617
+ maxGap = extremum === "min" ? ordered[1] - ordered[0] : ordered[kConsidered - 1] - ordered[kConsidered - 2];
21618
+ }
21619
+ selection = { centroid, maxGap, kConsidered };
21620
+ } else {
21621
+ const overlap = buildComparisonOverlap(input.armA, input.armB);
21622
+ overlapDays = overlap.days;
21623
+ runs = overlap.runs;
21624
+ deltaSeries = overlap.delta;
21625
+ }
21626
+ const overlapWindow = overlapDays.length > 0 ? { start: overlapDays[0], end: overlapDays[overlapDays.length - 1] } : null;
21627
+ const primary = computeCore({
21628
+ overlapDays,
21629
+ runs,
21630
+ deltaSeries,
21631
+ memberDeltas,
21632
+ extremum,
21633
+ blockDays,
21634
+ resamples,
21635
+ seed,
21636
+ ciLevel,
21637
+ statistic,
21638
+ effectiveNFloorBlocks
21639
+ });
21640
+ const sensitivity = [];
21641
+ for (const multiplier of input.holdingRule.sensitivity ?? []) {
21642
+ const sensBlockDays = Math.max(1, Math.round(multiplier * blockDays));
21643
+ const sens = computeCore({
21644
+ overlapDays,
21645
+ runs,
21646
+ deltaSeries,
21647
+ memberDeltas,
21648
+ extremum,
21649
+ blockDays: sensBlockDays,
21650
+ resamples,
21651
+ seed,
21652
+ ciLevel,
21653
+ statistic,
21654
+ effectiveNFloorBlocks
21655
+ });
21656
+ sensitivity.push({
21657
+ blockDays: sensBlockDays,
21658
+ ci: { low: sens.low, high: sens.high },
21659
+ status: sens.status
21660
+ });
21661
+ }
21662
+ return {
21663
+ point: primary.point,
21664
+ ci: { level: ciLevel, low: primary.low, high: primary.high, method: "paired-day-block" },
21665
+ effectiveN: primary.effectiveN,
21666
+ overlapWindow,
21667
+ blockDays,
21668
+ sensitivity,
21669
+ selection,
21670
+ status: primary.status,
21671
+ seed
21672
+ };
21673
+ }
21674
+
21419
21675
  // ../lib/calculations/index.ts
21420
21676
  function generateDataHash(trades, dailyLogs) {
21421
21677
  const data = {
@@ -21637,6 +21893,8 @@ export {
21637
21893
  PortfolioStatsCalculator,
21638
21894
  calculateCorrelationMatrix,
21639
21895
  performTailRiskAnalysis,
21896
+ holdingPeriodBlockDays,
21897
+ pairedBlockBootstrap,
21640
21898
  REPORTING_TRADE_COLUMN_ALIASES,
21641
21899
  isTatFormat,
21642
21900
  convertTatRowToReportingTrade
@@ -21652,4 +21910,4 @@ decimal.js/decimal.mjs:
21652
21910
  * MIT Licence
21653
21911
  *)
21654
21912
  */
21655
- //# sourceMappingURL=chunk-C6LL746C.js.map
21913
+ //# sourceMappingURL=chunk-2I3S2ZLT.js.map