tradeblocks-mcp 3.0.2 → 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 (218) hide show
  1. package/README.md +85 -80
  2. package/dist/{chunk-LDKTV7GW.js → chunk-27S67XW3.js} +24 -52
  3. package/dist/chunk-27S67XW3.js.map +1 -0
  4. package/dist/{chunk-FGZH632F.js → chunk-2E63THNI.js} +13 -11
  5. package/dist/chunk-2E63THNI.js.map +1 -0
  6. package/dist/{chunk-QTTR7AAW.js → chunk-2I3S2ZLT.js} +325 -84
  7. package/dist/chunk-2I3S2ZLT.js.map +1 -0
  8. package/dist/{chunk-4BLCXNQ6.js → chunk-4HZLVUOZ.js} +179 -183
  9. package/dist/chunk-4HZLVUOZ.js.map +1 -0
  10. package/dist/{chunk-XXYOUIZY.js → chunk-NWNSKALN.js} +63 -80
  11. package/dist/chunk-NWNSKALN.js.map +1 -0
  12. package/dist/{chunk-PRAYH3RT.js → chunk-WNTYA7ER.js} +29 -12
  13. package/dist/chunk-WNTYA7ER.js.map +1 -0
  14. package/dist/{chunk-BKQ4PM4Y.js → chunk-YZA4RS76.js} +24 -18
  15. package/dist/chunk-YZA4RS76.js.map +1 -0
  16. package/dist/{chunk-W2PP3LEH.js → chunk-ZTJXC3LS.js} +17 -8
  17. package/dist/chunk-ZTJXC3LS.js.map +1 -0
  18. package/dist/daily-log-processor-MZW2XBZY.js +9 -0
  19. package/dist/{daily-logs-store-D3QC2XPV.js → daily-logs-store-3C3OTGPK.js} +2 -2
  20. package/dist/iv-solver-worker.js +9 -1
  21. package/dist/market-provider-6U33TQUT.js +16 -0
  22. package/dist/{proto-3HZTCWK4.js → proto-V23GIZG2.js} +2 -2
  23. package/dist/{sync-PO4IPCYV.js → sync-3UBC37VW.js} +7 -7
  24. package/dist/test-exports.js +876 -483
  25. package/dist/test-exports.js.map +1 -1
  26. package/dist/trade-processor-DKDCWGKD.js +9 -0
  27. package/dist/{trades-store-LOL3FQSF.js → trades-store-R3NL25T2.js} +2 -2
  28. package/package.json +2 -6
  29. package/server/{chunk-CSDVJPBB.js → chunk-536NSFED.js} +29 -12
  30. package/server/chunk-536NSFED.js.map +1 -0
  31. package/server/{chunk-WA5AAPCH.js → chunk-A3UKD64A.js} +17 -8
  32. package/server/chunk-A3UKD64A.js.map +1 -0
  33. package/server/{chunk-PNKG7RY7.js → chunk-OMUDNJBJ.js} +63 -80
  34. package/server/chunk-OMUDNJBJ.js.map +1 -0
  35. package/server/{chunk-72GKJE2U.js → chunk-RJDJHZ5Y.js} +934 -335
  36. package/server/chunk-RJDJHZ5Y.js.map +1 -0
  37. package/server/{chunk-NZO6PT64.js → chunk-RM4B2VKS.js} +167 -177
  38. package/server/chunk-RM4B2VKS.js.map +1 -0
  39. package/server/{chunk-5EBXHT6C.js → chunk-SY6GDNVI.js} +24 -18
  40. package/server/chunk-SY6GDNVI.js.map +1 -0
  41. package/server/{chunk-FBNDMCT5.js → chunk-T66KH2XH.js} +13 -11
  42. package/server/chunk-T66KH2XH.js.map +1 -0
  43. package/server/{chunk-NRFXAJF7.js → chunk-W5E7FHC4.js} +24 -52
  44. package/server/chunk-W5E7FHC4.js.map +1 -0
  45. package/server/{config-6IZXEFEX.js → config-DK7KOMNL.js} +1 -1
  46. package/server/config-DK7KOMNL.js.map +1 -0
  47. package/server/daily-log-processor-B2VPU2FQ.js +10 -0
  48. package/server/{daily-logs-store-NU7M4L5C.js → daily-logs-store-YFNXTB7J.js} +2 -2
  49. package/server/http-server.js +2 -5
  50. package/server/index.js +2497 -2029
  51. package/server/index.js.map +1 -1
  52. package/server/iv-solver-worker.js +9 -1
  53. package/server/market-provider-L56RFHAC.js +17 -0
  54. package/server/{proto-DWRZJO4E.js → proto-YZ4TLX2N.js} +2 -2
  55. package/server/{sync-QFI5L7S7.js → sync-CENKDN53.js} +7 -7
  56. package/server/trade-processor-3PI4LHZI.js +10 -0
  57. package/server/{trades-store-VY26MWER.js → trades-store-RTTEYMXH.js} +2 -2
  58. package/src/auth/clients-store.ts +4 -4
  59. package/src/auth/code-store.ts +1 -1
  60. package/src/auth/config.ts +11 -12
  61. package/src/auth/login-page.ts +8 -10
  62. package/src/auth/provider.ts +35 -30
  63. package/src/auth/token.ts +17 -15
  64. package/src/db/backtest-schemas.ts +38 -8
  65. package/src/db/connection.ts +107 -40
  66. package/src/db/data-root.ts +22 -0
  67. package/src/db/index.ts +37 -5
  68. package/src/db/json-adapters.ts +22 -31
  69. package/src/db/json-migration.ts +11 -15
  70. package/src/db/json-store.ts +5 -3
  71. package/src/db/market-datasets.ts +48 -15
  72. package/src/db/market-schemas.ts +11 -5
  73. package/src/db/market-views.ts +119 -32
  74. package/src/db/parquet-writer.ts +7 -7
  75. package/src/db/profile-schemas.ts +39 -22
  76. package/src/db/schemas.ts +2 -2
  77. package/src/http-server.ts +7 -12
  78. package/src/index.ts +8 -9
  79. package/src/market/ingestor/index.ts +1 -4
  80. package/src/market/ingestor/market-ingestor.ts +140 -67
  81. package/src/market/ingestor/types.ts +1 -3
  82. package/src/market/stores/chain-sql.ts +2 -8
  83. package/src/market/stores/chain-store.ts +1 -4
  84. package/src/market/stores/duckdb-chain-store.ts +3 -14
  85. package/src/market/stores/duckdb-enriched-store.ts +3 -13
  86. package/src/market/stores/duckdb-quote-store.ts +10 -27
  87. package/src/market/stores/duckdb-spot-store.ts +4 -20
  88. package/src/market/stores/enriched-sql.ts +3 -9
  89. package/src/market/stores/enriched-store.ts +2 -2
  90. package/src/market/stores/parquet-chain-store.ts +5 -22
  91. package/src/market/stores/parquet-enriched-store.ts +4 -16
  92. package/src/market/stores/parquet-oi-daily-store.ts +3 -14
  93. package/src/market/stores/parquet-quote-store.ts +9 -29
  94. package/src/market/stores/parquet-spot-store.ts +14 -33
  95. package/src/market/stores/quote-store.ts +2 -10
  96. package/src/market/stores/spot-sql.ts +3 -15
  97. package/src/market/stores/spot-store.ts +1 -1
  98. package/src/market/tickers/defaults.json +6 -6
  99. package/src/market/tickers/loader.ts +2 -7
  100. package/src/market/tickers/registry.ts +5 -15
  101. package/src/market/tickers/schemas.ts +2 -6
  102. package/src/models/strategy-profile.ts +39 -39
  103. package/src/sync/block-sync.ts +44 -65
  104. package/src/sync/index.ts +1 -4
  105. package/src/sync/metadata.ts +14 -20
  106. package/src/test-exports.ts +139 -123
  107. package/src/tools/analysis.ts +180 -159
  108. package/src/tools/batch-exit-analysis.ts +100 -59
  109. package/src/tools/blocks/analysis.ts +116 -101
  110. package/src/tools/blocks/comparison.ts +281 -364
  111. package/src/tools/blocks/core.ts +208 -253
  112. package/src/tools/blocks/health.ts +571 -563
  113. package/src/tools/blocks/index.ts +2 -0
  114. package/src/tools/blocks/paired-comparison.ts +425 -0
  115. package/src/tools/blocks/similarity.ts +316 -283
  116. package/src/tools/edge-decay.ts +124 -197
  117. package/src/tools/exit-analysis.ts +130 -77
  118. package/src/tools/greeks-attribution.ts +84 -35
  119. package/src/tools/guides.ts +4 -6
  120. package/src/tools/imports.ts +11 -14
  121. package/src/tools/market-data.ts +1067 -757
  122. package/src/tools/market-enrichment.ts +3 -3
  123. package/src/tools/market-fetch.ts +148 -67
  124. package/src/tools/market-imports.ts +12 -12
  125. package/src/tools/middleware/sync-middleware.ts +5 -6
  126. package/src/tools/performance.ts +185 -302
  127. package/src/tools/profile-analysis.ts +52 -66
  128. package/src/tools/profiles.ts +106 -69
  129. package/src/tools/regime-advisor.ts +20 -45
  130. package/src/tools/replay.ts +81 -77
  131. package/src/tools/reports/discrepancies.ts +298 -328
  132. package/src/tools/reports/fields.ts +7 -25
  133. package/src/tools/reports/helpers.ts +18 -49
  134. package/src/tools/reports/predictive.ts +27 -70
  135. package/src/tools/reports/slippage-trends.ts +315 -345
  136. package/src/tools/reports/slippage.ts +1 -4
  137. package/src/tools/reports/strategy-matches.ts +399 -441
  138. package/src/tools/schema.ts +43 -40
  139. package/src/tools/shared/filters.ts +3 -9
  140. package/src/tools/snapshot.ts +9 -30
  141. package/src/tools/sql.ts +15 -14
  142. package/src/tools/tickers.ts +1 -4
  143. package/src/utils/batch-exit-analysis.ts +31 -42
  144. package/src/utils/black-scholes.ts +39 -29
  145. package/src/utils/block-loader.ts +69 -83
  146. package/src/utils/calibration-probe.ts +3 -4
  147. package/src/utils/chain-loader.ts +3 -3
  148. package/src/utils/csv-discovery.ts +16 -22
  149. package/src/utils/data-quality.ts +24 -36
  150. package/src/utils/exit-triggers.ts +91 -96
  151. package/src/utils/field-timing.ts +94 -79
  152. package/src/utils/filter-predicates.ts +13 -9
  153. package/src/utils/flatfile-importer.ts +94 -64
  154. package/src/utils/greeks-decomposition.ts +152 -100
  155. package/src/utils/iv-solver-pool.ts +55 -25
  156. package/src/utils/iv-solver-worker.ts +5 -5
  157. package/src/utils/market-enricher.ts +528 -497
  158. package/src/utils/market-importer.ts +31 -12
  159. package/src/utils/market-provider.ts +21 -23
  160. package/src/utils/massive-tier.ts +5 -7
  161. package/src/utils/migrate-option-data-helpers.ts +2 -8
  162. package/src/utils/option-quote-greeks.ts +25 -31
  163. package/src/utils/option-time.ts +4 -8
  164. package/src/utils/output-formatter.ts +1 -4
  165. package/src/utils/provider-capabilities.ts +1 -4
  166. package/src/utils/providers/massive.ts +59 -93
  167. package/src/utils/providers/thetadata/backfill.ts +14 -23
  168. package/src/utils/providers/thetadata/client.ts +12 -8
  169. package/src/utils/providers/thetadata/decode.ts +2 -20
  170. package/src/utils/providers/thetadata/endpoints.ts +32 -40
  171. package/src/utils/providers/thetadata/join.ts +11 -10
  172. package/src/utils/providers/thetadata/proto.ts +12 -10
  173. package/src/utils/providers/thetadata/quote-mid-greeks.ts +5 -5
  174. package/src/utils/providers/thetadata.ts +11 -10
  175. package/src/utils/quote-enricher.ts +4 -4
  176. package/src/utils/quote-parquet-projection.ts +3 -11
  177. package/src/utils/sample-date-selector.ts +3 -5
  178. package/src/utils/schema-metadata.ts +102 -70
  179. package/src/utils/ticker.ts +5 -9
  180. package/src/utils/trade-replay.ts +77 -68
  181. package/dist/chunk-4BLCXNQ6.js.map +0 -1
  182. package/dist/chunk-BKQ4PM4Y.js.map +0 -1
  183. package/dist/chunk-FGZH632F.js.map +0 -1
  184. package/dist/chunk-LDKTV7GW.js.map +0 -1
  185. package/dist/chunk-PRAYH3RT.js.map +0 -1
  186. package/dist/chunk-QTTR7AAW.js.map +0 -1
  187. package/dist/chunk-W2PP3LEH.js.map +0 -1
  188. package/dist/chunk-XXYOUIZY.js.map +0 -1
  189. package/dist/daily-log-processor-6MWJ23JK.js +0 -9
  190. package/dist/market-provider-VDRJUEF2.js +0 -16
  191. package/dist/trade-processor-NHU4VWRX.js +0 -9
  192. package/manifest.json +0 -141
  193. package/server/chunk-5EBXHT6C.js.map +0 -1
  194. package/server/chunk-72GKJE2U.js.map +0 -1
  195. package/server/chunk-CSDVJPBB.js.map +0 -1
  196. package/server/chunk-FBNDMCT5.js.map +0 -1
  197. package/server/chunk-NRFXAJF7.js.map +0 -1
  198. package/server/chunk-NZO6PT64.js.map +0 -1
  199. package/server/chunk-PNKG7RY7.js.map +0 -1
  200. package/server/chunk-WA5AAPCH.js.map +0 -1
  201. package/server/config-6IZXEFEX.js.map +0 -1
  202. package/server/daily-log-processor-Y3PVSVBM.js +0 -10
  203. package/server/market-provider-VOYYVYWT.js +0 -17
  204. package/server/trade-processor-JWVS37KM.js +0 -10
  205. /package/dist/{daily-log-processor-6MWJ23JK.js.map → daily-log-processor-MZW2XBZY.js.map} +0 -0
  206. /package/dist/{daily-logs-store-D3QC2XPV.js.map → daily-logs-store-3C3OTGPK.js.map} +0 -0
  207. /package/dist/{market-provider-VDRJUEF2.js.map → market-provider-6U33TQUT.js.map} +0 -0
  208. /package/dist/{proto-3HZTCWK4.js.map → proto-V23GIZG2.js.map} +0 -0
  209. /package/dist/{sync-PO4IPCYV.js.map → sync-3UBC37VW.js.map} +0 -0
  210. /package/dist/{trade-processor-NHU4VWRX.js.map → trade-processor-DKDCWGKD.js.map} +0 -0
  211. /package/dist/{trades-store-LOL3FQSF.js.map → trades-store-R3NL25T2.js.map} +0 -0
  212. /package/server/{daily-log-processor-Y3PVSVBM.js.map → daily-log-processor-B2VPU2FQ.js.map} +0 -0
  213. /package/server/{daily-logs-store-NU7M4L5C.js.map → daily-logs-store-YFNXTB7J.js.map} +0 -0
  214. /package/server/{market-provider-VOYYVYWT.js.map → market-provider-L56RFHAC.js.map} +0 -0
  215. /package/server/{proto-DWRZJO4E.js.map → proto-YZ4TLX2N.js.map} +0 -0
  216. /package/server/{sync-QFI5L7S7.js.map → sync-CENKDN53.js.map} +0 -0
  217. /package/server/{trade-processor-JWVS37KM.js.map → trade-processor-3PI4LHZI.js.map} +0 -0
  218. /package/server/{trades-store-VY26MWER.js.map → trades-store-RTTEYMXH.js.map} +0 -0
@@ -19791,8 +19791,10 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
19791
19791
  if (!trade.dateOpened) return false;
19792
19792
  const date = new Date(trade.dateOpened);
19793
19793
  if (isNaN(date.getTime())) return false;
19794
- if (typeof trade.openingCommissionsFees !== "number" || isNaN(trade.openingCommissionsFees)) return false;
19795
- if (typeof trade.closingCommissionsFees !== "number" || isNaN(trade.closingCommissionsFees)) return false;
19794
+ if (typeof trade.openingCommissionsFees !== "number" || isNaN(trade.openingCommissionsFees))
19795
+ return false;
19796
+ if (typeof trade.closingCommissionsFees !== "number" || isNaN(trade.closingCommissionsFees))
19797
+ return false;
19796
19798
  return true;
19797
19799
  } catch {
19798
19800
  return false;
@@ -19831,7 +19833,10 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
19831
19833
  const streaks = this.calculateStreaks(validTrades);
19832
19834
  const timeInDrawdown = this.calculateTimeInDrawdown(validTrades, adjustedDailyLogs);
19833
19835
  const periodicWinRates = this.calculatePeriodicWinRates(validTrades);
19834
- const initialCapital = _PortfolioStatsCalculator.calculateInitialCapital(validTrades, adjustedDailyLogs);
19836
+ const initialCapital = _PortfolioStatsCalculator.calculateInitialCapital(
19837
+ validTrades,
19838
+ adjustedDailyLogs
19839
+ );
19835
19840
  return {
19836
19841
  totalTrades,
19837
19842
  totalPl,
@@ -19869,14 +19874,17 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
19869
19874
  if (trades.length === 0) {
19870
19875
  return {};
19871
19876
  }
19872
- const tradesByStrategy = trades.reduce((acc, trade) => {
19873
- const strategy = trade.strategy || "Unknown";
19874
- if (!acc[strategy]) {
19875
- acc[strategy] = [];
19876
- }
19877
- acc[strategy].push(trade);
19878
- return acc;
19879
- }, {});
19877
+ const tradesByStrategy = trades.reduce(
19878
+ (acc, trade) => {
19879
+ const strategy = trade.strategy || "Unknown";
19880
+ if (!acc[strategy]) {
19881
+ acc[strategy] = [];
19882
+ }
19883
+ acc[strategy].push(trade);
19884
+ return acc;
19885
+ },
19886
+ {}
19887
+ );
19880
19888
  const strategyStats = {};
19881
19889
  Object.entries(tradesByStrategy).forEach(([strategyName, strategyTrades]) => {
19882
19890
  const portfolioStats = this.calculatePortfolioStats(strategyTrades);
@@ -19911,7 +19919,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
19911
19919
  return maxDrawdown2;
19912
19920
  }
19913
19921
  if (trades.length === 0) return 0;
19914
- const closedTrades = trades.filter((trade) => trade.dateClosed && trade.fundsAtClose !== void 0);
19922
+ const closedTrades = trades.filter(
19923
+ (trade) => trade.dateClosed && trade.fundsAtClose !== void 0
19924
+ );
19915
19925
  if (closedTrades.length === 0) return 0;
19916
19926
  const sortedTrades = [...closedTrades].sort((a, b) => {
19917
19927
  try {
@@ -20012,9 +20022,7 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20012
20022
  * Calculate average days to expiration (DTE)
20013
20023
  */
20014
20024
  calculateAvgDTE(trades) {
20015
- const tradesWithDTE = trades.filter(
20016
- (trade) => trade.dateClosed && trade.dateOpened
20017
- );
20025
+ const tradesWithDTE = trades.filter((trade) => trade.dateClosed && trade.dateOpened);
20018
20026
  if (tradesWithDTE.length === 0) return void 0;
20019
20027
  const totalDTE = tradesWithDTE.reduce((sum2, trade) => {
20020
20028
  const openDate = new Date(trade.dateOpened);
@@ -20035,7 +20043,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20035
20043
  return a.timeOpened.localeCompare(b.timeOpened);
20036
20044
  });
20037
20045
  const startDate = new Date(sortedTrades[0].dateOpened);
20038
- const endDate = new Date(sortedTrades[sortedTrades.length - 1].dateClosed || sortedTrades[sortedTrades.length - 1].dateOpened);
20046
+ const endDate = new Date(
20047
+ sortedTrades[sortedTrades.length - 1].dateClosed || sortedTrades[sortedTrades.length - 1].dateOpened
20048
+ );
20039
20049
  const totalYears = (endDate.getTime() - startDate.getTime()) / (1e3 * 60 * 60 * 24 * 365.25);
20040
20050
  if (totalYears <= 0) return void 0;
20041
20051
  const initialCapital = _PortfolioStatsCalculator.calculateInitialCapital(trades);
@@ -20102,7 +20112,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20102
20112
  if (winningTrades.length === 0 || losingTrades.length === 0) return void 0;
20103
20113
  const winRate = winningTrades.length / trades.length;
20104
20114
  const avgWin = winningTrades.reduce((sum2, trade) => sum2 + trade.pl, 0) / winningTrades.length;
20105
- const avgLoss = Math.abs(losingTrades.reduce((sum2, trade) => sum2 + trade.pl, 0) / losingTrades.length);
20115
+ const avgLoss = Math.abs(
20116
+ losingTrades.reduce((sum2, trade) => sum2 + trade.pl, 0) / losingTrades.length
20117
+ );
20106
20118
  if (avgLoss === 0) return void 0;
20107
20119
  const winLossRatio = avgWin / avgLoss;
20108
20120
  const kellyPercentage = (winRate * winLossRatio - (1 - winRate)) / winLossRatio;
@@ -20148,7 +20160,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20148
20160
  return daysInDrawdown / dailyLogEntries.length * 100;
20149
20161
  }
20150
20162
  if (trades.length === 0) return void 0;
20151
- const closedTrades = trades.filter((trade) => trade.dateClosed && trade.fundsAtClose !== void 0);
20163
+ const closedTrades = trades.filter(
20164
+ (trade) => trade.dateClosed && trade.fundsAtClose !== void 0
20165
+ );
20152
20166
  if (closedTrades.length === 0) return void 0;
20153
20167
  const sortedTrades = [...closedTrades].sort((a, b) => {
20154
20168
  try {
@@ -20197,7 +20211,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20197
20211
  }
20198
20212
  monthlyTrades.get(monthKey).push(trade);
20199
20213
  const startOfYear = new Date(date.getFullYear(), 0, 1);
20200
- const weekNumber = Math.ceil(((date.getTime() - startOfYear.getTime()) / 864e5 + startOfYear.getDay() + 1) / 7);
20214
+ const weekNumber = Math.ceil(
20215
+ ((date.getTime() - startOfYear.getTime()) / 864e5 + startOfYear.getDay() + 1) / 7
20216
+ );
20201
20217
  const weekKey = `${date.getFullYear()}-${String(weekNumber).padStart(2, "0")}`;
20202
20218
  if (!weeklyTrades.has(weekKey)) {
20203
20219
  weeklyTrades.set(weekKey, []);
@@ -20377,12 +20393,7 @@ function normalQuantile(p) {
20377
20393
  4.374664141464968,
20378
20394
  2.938163982698783
20379
20395
  ];
20380
- const d = [
20381
- 0.007784695709041462,
20382
- 0.3224671290700398,
20383
- 2.445134137142996,
20384
- 3.754408661907416
20385
- ];
20396
+ const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
20386
20397
  const pLow = 0.02425;
20387
20398
  const pHigh = 1 - pLow;
20388
20399
  let q;
@@ -20510,10 +20521,7 @@ function calculateCorrelationMatrix(trades, options = {}) {
20510
20521
  }
20511
20522
  const strategyReturns = {};
20512
20523
  for (const strategy of Object.keys(strategyDailyReturns)) {
20513
- strategyReturns[strategy] = aggregateByPeriod(
20514
- strategyDailyReturns[strategy],
20515
- timePeriod
20516
- );
20524
+ strategyReturns[strategy] = aggregateByPeriod(strategyDailyReturns[strategy], timePeriod);
20517
20525
  }
20518
20526
  const allDates = /* @__PURE__ */ new Set();
20519
20527
  for (const returns of Object.values(strategyReturns)) {
@@ -20648,9 +20656,7 @@ function normalizeReturn(trade, mode) {
20648
20656
  return trade.pl / trade.marginReq;
20649
20657
  }
20650
20658
  case "notional": {
20651
- const notional = Math.abs(
20652
- (trade.openingPrice || 0) * (trade.numContracts || 0)
20653
- );
20659
+ const notional = Math.abs((trade.openingPrice || 0) * (trade.numContracts || 0));
20654
20660
  if (!notional) {
20655
20661
  return null;
20656
20662
  }
@@ -20663,9 +20669,7 @@ function normalizeReturn(trade, mode) {
20663
20669
  function getTradeDateKey(trade, basis) {
20664
20670
  const date = basis === "closed" ? trade.dateClosed : trade.dateOpened;
20665
20671
  if (!date) {
20666
- throw new Error(
20667
- "Trade is missing required date information for correlation calculation"
20668
- );
20672
+ throw new Error("Trade is missing required date information for correlation calculation");
20669
20673
  }
20670
20674
  const year = date.getFullYear();
20671
20675
  const month = String(date.getMonth() + 1).padStart(2, "0");
@@ -20682,9 +20686,7 @@ function getIsoWeekKey(dateStr) {
20682
20686
  const dayOfWeek = thursday.getUTCDay() || 7;
20683
20687
  thursday.setUTCDate(thursday.getUTCDate() + (4 - dayOfWeek));
20684
20688
  const yearStart = new Date(Date.UTC(thursday.getUTCFullYear(), 0, 1));
20685
- const weekNum = Math.ceil(
20686
- ((thursday.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
20687
- );
20689
+ const weekNum = Math.ceil(((thursday.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
20688
20690
  return `${thursday.getUTCFullYear()}-W${String(weekNum).padStart(2, "0")}`;
20689
20691
  }
20690
20692
  function getMonthKey(dateStr) {
@@ -20734,9 +20736,7 @@ function performTailRiskAnalysis(trades, options = {}) {
20734
20736
  }
20735
20737
  if (strategyFilter && strategyFilter.length > 0) {
20736
20738
  const filterSet = new Set(strategyFilter);
20737
- filteredTrades = filteredTrades.filter(
20738
- (t) => t.strategy && filterSet.has(t.strategy)
20739
- );
20739
+ filteredTrades = filteredTrades.filter((t) => t.strategy && filterSet.has(t.strategy));
20740
20740
  }
20741
20741
  if (dateRange?.from || dateRange?.to) {
20742
20742
  filteredTrades = filteredTrades.filter((t) => {
@@ -20751,41 +20751,27 @@ function performTailRiskAnalysis(trades, options = {}) {
20751
20751
  return true;
20752
20752
  });
20753
20753
  }
20754
- const aligned = aggregateAndAlignReturns(
20755
- filteredTrades,
20756
- normalization,
20757
- dateBasis
20758
- );
20754
+ const aligned = aggregateAndAlignReturns(filteredTrades, normalization, dateBasis);
20759
20755
  if (aligned.strategies.length < 2) {
20760
- return createEmptyResult(
20761
- aligned,
20762
- tailThreshold,
20763
- varianceThreshold,
20764
- startTime
20765
- );
20756
+ return createEmptyResult(aligned, tailThreshold, varianceThreshold, startTime);
20766
20757
  }
20767
20758
  if (aligned.dates.length < minTradingDays) {
20768
- return createEmptyResult(
20769
- aligned,
20770
- tailThreshold,
20771
- varianceThreshold,
20772
- startTime
20773
- );
20759
+ return createEmptyResult(aligned, tailThreshold, varianceThreshold, startTime);
20774
20760
  }
20775
20761
  const transformedReturns = aligned.returns.map(
20776
20762
  (strategyReturns) => probabilityIntegralTransform(strategyReturns)
20777
20763
  );
20778
20764
  const copulaCorrelationMatrix = computeCorrelationMatrix(transformedReturns);
20779
- const { eigenvalues, eigenvectors, explainedVariance, effectiveFactors } = performEigenAnalysis(copulaCorrelationMatrix, varianceThreshold);
20765
+ const { eigenvalues, eigenvectors, explainedVariance, effectiveFactors } = performEigenAnalysis(
20766
+ copulaCorrelationMatrix,
20767
+ varianceThreshold
20768
+ );
20780
20769
  const jointTailRiskResult = estimateJointTailRisk(
20781
20770
  transformedReturns,
20782
20771
  aligned.tradedMask,
20783
20772
  tailThreshold
20784
20773
  );
20785
- const analytics = calculateTailRiskAnalytics(
20786
- jointTailRiskResult.matrix,
20787
- aligned.strategies
20788
- );
20774
+ const analytics = calculateTailRiskAnalytics(jointTailRiskResult.matrix, aligned.strategies);
20789
20775
  const marginalContributions = calculateMarginalContributions(
20790
20776
  copulaCorrelationMatrix,
20791
20777
  jointTailRiskResult.matrix,
@@ -20882,9 +20868,7 @@ function normalizeReturn2(trade, mode) {
20882
20868
  break;
20883
20869
  }
20884
20870
  case "notional": {
20885
- const notional = Math.abs(
20886
- (trade.openingPrice || 0) * (trade.numContracts || 0)
20887
- );
20871
+ const notional = Math.abs((trade.openingPrice || 0) * (trade.numContracts || 0));
20888
20872
  if (!notional || notional === 0) {
20889
20873
  return null;
20890
20874
  }
@@ -20968,10 +20952,7 @@ function performEigenAnalysis(correlationMatrix, varianceThreshold = 0.8) {
20968
20952
  effectiveFactors
20969
20953
  };
20970
20954
  } catch (error) {
20971
- console.warn(
20972
- "Eigenvalue decomposition failed, using identity fallback:",
20973
- error
20974
- );
20955
+ console.warn("Eigenvalue decomposition failed, using identity fallback:", error);
20975
20956
  return {
20976
20957
  eigenvalues: new Array(n).fill(1),
20977
20958
  eigenvectors: correlationMatrix.map(
@@ -21030,10 +21011,7 @@ function estimateJointTailRisk(transformedReturns, tradedMask, tailThreshold) {
21030
21011
  }
21031
21012
  }
21032
21013
  }
21033
- const minTailObs = getMinTailObservations(
21034
- tailThreshold,
21035
- sharedTradingDays
21036
- );
21014
+ const minTailObs = getMinTailObservations(tailThreshold, sharedTradingDays);
21037
21015
  if (iInTailAndBothTraded < minTailObs) {
21038
21016
  row.push(NaN);
21039
21017
  insufficientPairs++;
@@ -21104,10 +21082,7 @@ function calculateMarginalContributions(_copulaCorrelationMatrix, jointTailRiskM
21104
21082
  }
21105
21083
  const contributions = [];
21106
21084
  const firstEigenvector = eigenvectors[0] || new Array(n).fill(0);
21107
- const sumAbsLoadings = firstEigenvector.reduce(
21108
- (sum2, val) => sum2 + Math.abs(val),
21109
- 0
21110
- );
21085
+ const sumAbsLoadings = firstEigenvector.reduce((sum2, val) => sum2 + Math.abs(val), 0);
21111
21086
  for (let i = 0; i < n; i++) {
21112
21087
  const concentrationScore = sumAbsLoadings > 0 ? Math.abs(firstEigenvector[i]) / sumAbsLoadings : 1 / n;
21113
21088
  let sumJointRisk = 0;
@@ -21303,7 +21278,9 @@ var PerformanceCalculator = class {
21303
21278
  static calculateMonthlyReturns(trades, initialCapital) {
21304
21279
  if (trades.length === 0) return {};
21305
21280
  if (!initialCapital) {
21306
- const firstTrade = trades.sort((a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime())[0];
21281
+ const firstTrade = trades.sort(
21282
+ (a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime()
21283
+ )[0];
21307
21284
  initialCapital = firstTrade.fundsAtClose - firstTrade.pl;
21308
21285
  }
21309
21286
  const monthlyPl = this.aggregatePLByPeriod(trades, "monthly");
@@ -21439,6 +21416,262 @@ var DAY_MS = 24 * 60 * 60 * 1e3;
21439
21416
  // ../lib/calculations/walk-forward-degradation.ts
21440
21417
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
21441
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
+
21442
21675
  // ../lib/calculations/index.ts
21443
21676
  function generateDataHash(trades, dailyLogs) {
21444
21677
  const data = {
@@ -21467,9 +21700,15 @@ var CalculationOrchestrator = class {
21467
21700
  };
21468
21701
  }
21469
21702
  const calculator = new PortfolioStatsCalculator(config4);
21470
- const portfolioStats = calculator.calculatePortfolioStats(trades, dailyLogs);
21703
+ const portfolioStats = calculator.calculatePortfolioStats(
21704
+ trades,
21705
+ dailyLogs
21706
+ );
21471
21707
  const strategyStats = calculator.calculateStrategyStats(trades);
21472
- const performanceMetrics = PerformanceCalculator.calculatePerformanceMetrics(trades, dailyLogs);
21708
+ const performanceMetrics = PerformanceCalculator.calculatePerformanceMetrics(
21709
+ trades,
21710
+ dailyLogs
21711
+ );
21473
21712
  this.cache.set(blockId, {
21474
21713
  portfolioStats,
21475
21714
  strategyStats,
@@ -21509,9 +21748,9 @@ var calculationOrchestrator = new CalculationOrchestrator();
21509
21748
  var REPORTING_TRADE_COLUMN_ALIASES = {
21510
21749
  "Initial Premium ($)": "Initial Premium",
21511
21750
  "Initial Credit": "Initial Premium",
21512
- "Contracts": "No. of Contracts",
21751
+ Contracts: "No. of Contracts",
21513
21752
  "Contracts Traded": "No. of Contracts",
21514
- "PL": "P/L"
21753
+ PL: "P/L"
21515
21754
  };
21516
21755
 
21517
21756
  // ../lib/processing/tat-adapter.ts
@@ -21654,6 +21893,8 @@ export {
21654
21893
  PortfolioStatsCalculator,
21655
21894
  calculateCorrelationMatrix,
21656
21895
  performTailRiskAnalysis,
21896
+ holdingPeriodBlockDays,
21897
+ pairedBlockBootstrap,
21657
21898
  REPORTING_TRADE_COLUMN_ALIASES,
21658
21899
  isTatFormat,
21659
21900
  convertTatRowToReportingTrade
@@ -21669,4 +21910,4 @@ decimal.js/decimal.mjs:
21669
21910
  * MIT Licence
21670
21911
  *)
21671
21912
  */
21672
- //# sourceMappingURL=chunk-QTTR7AAW.js.map
21913
+ //# sourceMappingURL=chunk-2I3S2ZLT.js.map