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/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:
|
|
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
|
-
|
|
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
|
|
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-
|
|
21913
|
+
//# sourceMappingURL=chunk-2I3S2ZLT.js.map
|