tradeblocks-mcp 3.0.2 → 3.0.3

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 (214) hide show
  1. package/README.md +82 -68
  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-BKQ4PM4Y.js → chunk-6S37CXUA.js} +11 -13
  7. package/dist/chunk-6S37CXUA.js.map +1 -0
  8. package/dist/{chunk-PRAYH3RT.js → chunk-AP7IHUUR.js} +29 -12
  9. package/dist/chunk-AP7IHUUR.js.map +1 -0
  10. package/dist/{chunk-QTTR7AAW.js → chunk-C6LL746C.js} +67 -84
  11. package/dist/{chunk-QTTR7AAW.js.map → chunk-C6LL746C.js.map} +1 -1
  12. package/dist/{chunk-W2PP3LEH.js → chunk-SEUZYQGQ.js} +17 -8
  13. package/dist/chunk-SEUZYQGQ.js.map +1 -0
  14. package/dist/{chunk-4BLCXNQ6.js → chunk-UBUC5A66.js} +105 -114
  15. package/dist/chunk-UBUC5A66.js.map +1 -0
  16. package/dist/{chunk-XXYOUIZY.js → chunk-VDU25Z6X.js} +63 -80
  17. package/dist/chunk-VDU25Z6X.js.map +1 -0
  18. package/dist/daily-log-processor-BY3ISY6K.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-H3ARIVZ4.js +16 -0
  22. package/dist/{proto-3HZTCWK4.js → proto-V23GIZG2.js} +2 -2
  23. package/dist/{sync-PO4IPCYV.js → sync-EVLKB3ZJ.js} +7 -7
  24. package/dist/test-exports.js +358 -254
  25. package/dist/test-exports.js.map +1 -1
  26. package/dist/trade-processor-EYA3I3XB.js +9 -0
  27. package/dist/{trades-store-LOL3FQSF.js → trades-store-R3NL25T2.js} +2 -2
  28. package/manifest.json +3 -11
  29. package/package.json +1 -1
  30. package/server/{chunk-NZO6PT64.js → chunk-4P7D7YZP.js} +102 -113
  31. package/server/chunk-4P7D7YZP.js.map +1 -0
  32. package/server/{chunk-72GKJE2U.js → chunk-BOPHW5M6.js} +521 -235
  33. package/server/chunk-BOPHW5M6.js.map +1 -0
  34. package/server/{chunk-WA5AAPCH.js → chunk-GH2552SE.js} +17 -8
  35. package/server/chunk-GH2552SE.js.map +1 -0
  36. package/server/{chunk-5EBXHT6C.js → chunk-OBYKFW2B.js} +11 -13
  37. package/server/chunk-OBYKFW2B.js.map +1 -0
  38. package/server/{chunk-FBNDMCT5.js → chunk-T66KH2XH.js} +13 -11
  39. package/server/chunk-T66KH2XH.js.map +1 -0
  40. package/server/{chunk-NRFXAJF7.js → chunk-W5E7FHC4.js} +24 -52
  41. package/server/chunk-W5E7FHC4.js.map +1 -0
  42. package/server/{chunk-CSDVJPBB.js → chunk-YUCOAJ4Z.js} +29 -12
  43. package/server/chunk-YUCOAJ4Z.js.map +1 -0
  44. package/server/{chunk-PNKG7RY7.js → chunk-ZBJCF4ZG.js} +63 -80
  45. package/server/chunk-ZBJCF4ZG.js.map +1 -0
  46. package/server/{config-6IZXEFEX.js → config-DK7KOMNL.js} +1 -1
  47. package/server/config-DK7KOMNL.js.map +1 -0
  48. package/server/daily-log-processor-ENEUT22A.js +10 -0
  49. package/server/{daily-logs-store-NU7M4L5C.js → daily-logs-store-YFNXTB7J.js} +2 -2
  50. package/server/http-server.js +2 -5
  51. package/server/index.js +1771 -1538
  52. package/server/index.js.map +1 -1
  53. package/server/iv-solver-worker.js +9 -1
  54. package/server/market-provider-B437HKLW.js +17 -0
  55. package/server/{proto-DWRZJO4E.js → proto-YZ4TLX2N.js} +2 -2
  56. package/server/{sync-QFI5L7S7.js → sync-V25UQJA3.js} +7 -7
  57. package/server/trade-processor-L3PIQ5TG.js +10 -0
  58. package/server/{trades-store-VY26MWER.js → trades-store-RTTEYMXH.js} +2 -2
  59. package/src/auth/clients-store.ts +4 -4
  60. package/src/auth/code-store.ts +1 -1
  61. package/src/auth/config.ts +11 -12
  62. package/src/auth/login-page.ts +8 -10
  63. package/src/auth/provider.ts +35 -30
  64. package/src/auth/token.ts +17 -15
  65. package/src/db/backtest-schemas.ts +12 -4
  66. package/src/db/connection.ts +107 -40
  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 +127 -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/similarity.ts +316 -283
  114. package/src/tools/edge-decay.ts +124 -197
  115. package/src/tools/exit-analysis.ts +130 -77
  116. package/src/tools/greeks-attribution.ts +84 -35
  117. package/src/tools/guides.ts +4 -6
  118. package/src/tools/imports.ts +9 -12
  119. package/src/tools/market-data.ts +1067 -757
  120. package/src/tools/market-enrichment.ts +3 -3
  121. package/src/tools/market-fetch.ts +148 -67
  122. package/src/tools/market-imports.ts +12 -12
  123. package/src/tools/middleware/sync-middleware.ts +5 -6
  124. package/src/tools/performance.ts +185 -302
  125. package/src/tools/profile-analysis.ts +52 -66
  126. package/src/tools/profiles.ts +106 -69
  127. package/src/tools/regime-advisor.ts +20 -45
  128. package/src/tools/replay.ts +81 -77
  129. package/src/tools/reports/discrepancies.ts +298 -328
  130. package/src/tools/reports/fields.ts +7 -25
  131. package/src/tools/reports/helpers.ts +18 -49
  132. package/src/tools/reports/predictive.ts +27 -70
  133. package/src/tools/reports/slippage-trends.ts +315 -345
  134. package/src/tools/reports/slippage.ts +1 -4
  135. package/src/tools/reports/strategy-matches.ts +399 -441
  136. package/src/tools/schema.ts +43 -40
  137. package/src/tools/shared/filters.ts +3 -9
  138. package/src/tools/snapshot.ts +9 -30
  139. package/src/tools/sql.ts +15 -14
  140. package/src/tools/tickers.ts +1 -4
  141. package/src/utils/batch-exit-analysis.ts +31 -42
  142. package/src/utils/black-scholes.ts +39 -29
  143. package/src/utils/block-loader.ts +68 -82
  144. package/src/utils/calibration-probe.ts +1 -2
  145. package/src/utils/chain-loader.ts +3 -3
  146. package/src/utils/csv-discovery.ts +16 -22
  147. package/src/utils/data-quality.ts +24 -36
  148. package/src/utils/exit-triggers.ts +91 -96
  149. package/src/utils/field-timing.ts +94 -79
  150. package/src/utils/filter-predicates.ts +13 -9
  151. package/src/utils/flatfile-importer.ts +94 -64
  152. package/src/utils/greeks-decomposition.ts +152 -100
  153. package/src/utils/iv-solver-pool.ts +55 -25
  154. package/src/utils/iv-solver-worker.ts +5 -5
  155. package/src/utils/market-enricher.ts +528 -497
  156. package/src/utils/market-importer.ts +31 -12
  157. package/src/utils/market-provider.ts +21 -23
  158. package/src/utils/massive-tier.ts +5 -7
  159. package/src/utils/migrate-option-data-helpers.ts +2 -8
  160. package/src/utils/option-quote-greeks.ts +25 -31
  161. package/src/utils/option-time.ts +4 -8
  162. package/src/utils/output-formatter.ts +1 -4
  163. package/src/utils/provider-capabilities.ts +1 -4
  164. package/src/utils/providers/massive.ts +59 -93
  165. package/src/utils/providers/thetadata/backfill.ts +14 -23
  166. package/src/utils/providers/thetadata/client.ts +12 -8
  167. package/src/utils/providers/thetadata/decode.ts +2 -20
  168. package/src/utils/providers/thetadata/endpoints.ts +32 -40
  169. package/src/utils/providers/thetadata/join.ts +11 -10
  170. package/src/utils/providers/thetadata/proto.ts +12 -10
  171. package/src/utils/providers/thetadata/quote-mid-greeks.ts +5 -5
  172. package/src/utils/providers/thetadata.ts +11 -10
  173. package/src/utils/quote-enricher.ts +4 -4
  174. package/src/utils/quote-parquet-projection.ts +3 -11
  175. package/src/utils/sample-date-selector.ts +3 -5
  176. package/src/utils/schema-metadata.ts +102 -70
  177. package/src/utils/ticker.ts +5 -9
  178. package/src/utils/trade-replay.ts +77 -68
  179. package/dist/chunk-4BLCXNQ6.js.map +0 -1
  180. package/dist/chunk-BKQ4PM4Y.js.map +0 -1
  181. package/dist/chunk-FGZH632F.js.map +0 -1
  182. package/dist/chunk-LDKTV7GW.js.map +0 -1
  183. package/dist/chunk-PRAYH3RT.js.map +0 -1
  184. package/dist/chunk-W2PP3LEH.js.map +0 -1
  185. package/dist/chunk-XXYOUIZY.js.map +0 -1
  186. package/dist/daily-log-processor-6MWJ23JK.js +0 -9
  187. package/dist/market-provider-VDRJUEF2.js +0 -16
  188. package/dist/trade-processor-NHU4VWRX.js +0 -9
  189. package/server/chunk-5EBXHT6C.js.map +0 -1
  190. package/server/chunk-72GKJE2U.js.map +0 -1
  191. package/server/chunk-CSDVJPBB.js.map +0 -1
  192. package/server/chunk-FBNDMCT5.js.map +0 -1
  193. package/server/chunk-NRFXAJF7.js.map +0 -1
  194. package/server/chunk-NZO6PT64.js.map +0 -1
  195. package/server/chunk-PNKG7RY7.js.map +0 -1
  196. package/server/chunk-WA5AAPCH.js.map +0 -1
  197. package/server/config-6IZXEFEX.js.map +0 -1
  198. package/server/daily-log-processor-Y3PVSVBM.js +0 -10
  199. package/server/market-provider-VOYYVYWT.js +0 -17
  200. package/server/trade-processor-JWVS37KM.js +0 -10
  201. /package/dist/{daily-log-processor-6MWJ23JK.js.map → daily-log-processor-BY3ISY6K.js.map} +0 -0
  202. /package/dist/{daily-logs-store-D3QC2XPV.js.map → daily-logs-store-3C3OTGPK.js.map} +0 -0
  203. /package/dist/{market-provider-VDRJUEF2.js.map → market-provider-H3ARIVZ4.js.map} +0 -0
  204. /package/dist/{proto-3HZTCWK4.js.map → proto-V23GIZG2.js.map} +0 -0
  205. /package/dist/{sync-PO4IPCYV.js.map → sync-EVLKB3ZJ.js.map} +0 -0
  206. /package/dist/{trade-processor-NHU4VWRX.js.map → trade-processor-EYA3I3XB.js.map} +0 -0
  207. /package/dist/{trades-store-LOL3FQSF.js.map → trades-store-R3NL25T2.js.map} +0 -0
  208. /package/server/{daily-log-processor-Y3PVSVBM.js.map → daily-log-processor-ENEUT22A.js.map} +0 -0
  209. /package/server/{daily-logs-store-NU7M4L5C.js.map → daily-logs-store-YFNXTB7J.js.map} +0 -0
  210. /package/server/{market-provider-VOYYVYWT.js.map → market-provider-B437HKLW.js.map} +0 -0
  211. /package/server/{proto-DWRZJO4E.js.map → proto-YZ4TLX2N.js.map} +0 -0
  212. /package/server/{sync-QFI5L7S7.js.map → sync-V25UQJA3.js.map} +0 -0
  213. /package/server/{trade-processor-JWVS37KM.js.map → trade-processor-L3PIQ5TG.js.map} +0 -0
  214. /package/server/{trades-store-VY26MWER.js.map → trades-store-RTTEYMXH.js.map} +0 -0
@@ -15420,12 +15420,7 @@ function normalQuantile(p) {
15420
15420
  4.374664141464968,
15421
15421
  2.938163982698783
15422
15422
  ];
15423
- const d = [
15424
- 0.007784695709041462,
15425
- 0.3224671290700398,
15426
- 2.445134137142996,
15427
- 3.754408661907416
15428
- ];
15423
+ const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
15429
15424
  const pLow = 0.02425;
15430
15425
  const pHigh = 1 - pLow;
15431
15426
  let q;
@@ -15589,10 +15584,7 @@ function calculateCorrelationMatrix(trades, options = {}) {
15589
15584
  }
15590
15585
  const strategyReturns = {};
15591
15586
  for (const strategy of Object.keys(strategyDailyReturns)) {
15592
- strategyReturns[strategy] = aggregateByPeriod(
15593
- strategyDailyReturns[strategy],
15594
- timePeriod
15595
- );
15587
+ strategyReturns[strategy] = aggregateByPeriod(strategyDailyReturns[strategy], timePeriod);
15596
15588
  }
15597
15589
  const allDates = /* @__PURE__ */ new Set();
15598
15590
  for (const returns of Object.values(strategyReturns)) {
@@ -15727,9 +15719,7 @@ function normalizeReturn(trade, mode) {
15727
15719
  return trade.pl / trade.marginReq;
15728
15720
  }
15729
15721
  case "notional": {
15730
- const notional = Math.abs(
15731
- (trade.openingPrice || 0) * (trade.numContracts || 0)
15732
- );
15722
+ const notional = Math.abs((trade.openingPrice || 0) * (trade.numContracts || 0));
15733
15723
  if (!notional) {
15734
15724
  return null;
15735
15725
  }
@@ -15742,9 +15732,7 @@ function normalizeReturn(trade, mode) {
15742
15732
  function getTradeDateKey(trade, basis) {
15743
15733
  const date = basis === "closed" ? trade.dateClosed : trade.dateOpened;
15744
15734
  if (!date) {
15745
- throw new Error(
15746
- "Trade is missing required date information for correlation calculation"
15747
- );
15735
+ throw new Error("Trade is missing required date information for correlation calculation");
15748
15736
  }
15749
15737
  const year = date.getFullYear();
15750
15738
  const month = String(date.getMonth() + 1).padStart(2, "0");
@@ -15761,9 +15749,7 @@ function getIsoWeekKey(dateStr) {
15761
15749
  const dayOfWeek = thursday.getUTCDay() || 7;
15762
15750
  thursday.setUTCDate(thursday.getUTCDate() + (4 - dayOfWeek));
15763
15751
  const yearStart = new Date(Date.UTC(thursday.getUTCFullYear(), 0, 1));
15764
- const weekNum = Math.ceil(
15765
- ((thursday.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
15766
- );
15752
+ const weekNum = Math.ceil(((thursday.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
15767
15753
  return `${thursday.getUTCFullYear()}-W${String(weekNum).padStart(2, "0")}`;
15768
15754
  }
15769
15755
  function getMonthKey(dateStr) {
@@ -15850,9 +15836,7 @@ function performTailRiskAnalysis(trades, options = {}) {
15850
15836
  }
15851
15837
  if (strategyFilter && strategyFilter.length > 0) {
15852
15838
  const filterSet = new Set(strategyFilter);
15853
- filteredTrades = filteredTrades.filter(
15854
- (t) => t.strategy && filterSet.has(t.strategy)
15855
- );
15839
+ filteredTrades = filteredTrades.filter((t) => t.strategy && filterSet.has(t.strategy));
15856
15840
  }
15857
15841
  if (dateRange?.from || dateRange?.to) {
15858
15842
  filteredTrades = filteredTrades.filter((t) => {
@@ -15867,41 +15851,27 @@ function performTailRiskAnalysis(trades, options = {}) {
15867
15851
  return true;
15868
15852
  });
15869
15853
  }
15870
- const aligned = aggregateAndAlignReturns(
15871
- filteredTrades,
15872
- normalization,
15873
- dateBasis
15874
- );
15854
+ const aligned = aggregateAndAlignReturns(filteredTrades, normalization, dateBasis);
15875
15855
  if (aligned.strategies.length < 2) {
15876
- return createEmptyResult(
15877
- aligned,
15878
- tailThreshold,
15879
- varianceThreshold,
15880
- startTime
15881
- );
15856
+ return createEmptyResult(aligned, tailThreshold, varianceThreshold, startTime);
15882
15857
  }
15883
15858
  if (aligned.dates.length < minTradingDays) {
15884
- return createEmptyResult(
15885
- aligned,
15886
- tailThreshold,
15887
- varianceThreshold,
15888
- startTime
15889
- );
15859
+ return createEmptyResult(aligned, tailThreshold, varianceThreshold, startTime);
15890
15860
  }
15891
15861
  const transformedReturns = aligned.returns.map(
15892
15862
  (strategyReturns) => probabilityIntegralTransform(strategyReturns)
15893
15863
  );
15894
15864
  const copulaCorrelationMatrix = computeCorrelationMatrix(transformedReturns);
15895
- const { eigenvalues, eigenvectors, explainedVariance, effectiveFactors } = performEigenAnalysis(copulaCorrelationMatrix, varianceThreshold);
15865
+ const { eigenvalues, eigenvectors, explainedVariance, effectiveFactors } = performEigenAnalysis(
15866
+ copulaCorrelationMatrix,
15867
+ varianceThreshold
15868
+ );
15896
15869
  const jointTailRiskResult = estimateJointTailRisk(
15897
15870
  transformedReturns,
15898
15871
  aligned.tradedMask,
15899
15872
  tailThreshold
15900
15873
  );
15901
- const analytics = calculateTailRiskAnalytics(
15902
- jointTailRiskResult.matrix,
15903
- aligned.strategies
15904
- );
15874
+ const analytics = calculateTailRiskAnalytics(jointTailRiskResult.matrix, aligned.strategies);
15905
15875
  const marginalContributions = calculateMarginalContributions(
15906
15876
  copulaCorrelationMatrix,
15907
15877
  jointTailRiskResult.matrix,
@@ -15998,9 +15968,7 @@ function normalizeReturn2(trade, mode) {
15998
15968
  break;
15999
15969
  }
16000
15970
  case "notional": {
16001
- const notional = Math.abs(
16002
- (trade.openingPrice || 0) * (trade.numContracts || 0)
16003
- );
15971
+ const notional = Math.abs((trade.openingPrice || 0) * (trade.numContracts || 0));
16004
15972
  if (!notional || notional === 0) {
16005
15973
  return null;
16006
15974
  }
@@ -16084,10 +16052,7 @@ function performEigenAnalysis(correlationMatrix, varianceThreshold = 0.8) {
16084
16052
  effectiveFactors
16085
16053
  };
16086
16054
  } catch (error) {
16087
- console.warn(
16088
- "Eigenvalue decomposition failed, using identity fallback:",
16089
- error
16090
- );
16055
+ console.warn("Eigenvalue decomposition failed, using identity fallback:", error);
16091
16056
  return {
16092
16057
  eigenvalues: new Array(n).fill(1),
16093
16058
  eigenvectors: correlationMatrix.map(
@@ -16146,10 +16111,7 @@ function estimateJointTailRisk(transformedReturns, tradedMask, tailThreshold) {
16146
16111
  }
16147
16112
  }
16148
16113
  }
16149
- const minTailObs = getMinTailObservations(
16150
- tailThreshold,
16151
- sharedTradingDays
16152
- );
16114
+ const minTailObs = getMinTailObservations(tailThreshold, sharedTradingDays);
16153
16115
  if (iInTailAndBothTraded < minTailObs) {
16154
16116
  row.push(NaN);
16155
16117
  insufficientPairs++;
@@ -16220,10 +16182,7 @@ function calculateMarginalContributions(_copulaCorrelationMatrix, jointTailRiskM
16220
16182
  }
16221
16183
  const contributions = [];
16222
16184
  const firstEigenvector = eigenvectors[0] || new Array(n).fill(0);
16223
- const sumAbsLoadings = firstEigenvector.reduce(
16224
- (sum2, val) => sum2 + Math.abs(val),
16225
- 0
16226
- );
16185
+ const sumAbsLoadings = firstEigenvector.reduce((sum2, val) => sum2 + Math.abs(val), 0);
16227
16186
  for (let i = 0; i < n; i++) {
16228
16187
  const concentrationScore = sumAbsLoadings > 0 ? Math.abs(firstEigenvector[i]) / sumAbsLoadings : 1 / n;
16229
16188
  let sumJointRisk = 0;
@@ -20837,8 +20796,10 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20837
20796
  if (!trade.dateOpened) return false;
20838
20797
  const date = new Date(trade.dateOpened);
20839
20798
  if (isNaN(date.getTime())) return false;
20840
- if (typeof trade.openingCommissionsFees !== "number" || isNaN(trade.openingCommissionsFees)) return false;
20841
- if (typeof trade.closingCommissionsFees !== "number" || isNaN(trade.closingCommissionsFees)) return false;
20799
+ if (typeof trade.openingCommissionsFees !== "number" || isNaN(trade.openingCommissionsFees))
20800
+ return false;
20801
+ if (typeof trade.closingCommissionsFees !== "number" || isNaN(trade.closingCommissionsFees))
20802
+ return false;
20842
20803
  return true;
20843
20804
  } catch {
20844
20805
  return false;
@@ -20877,7 +20838,10 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20877
20838
  const streaks = this.calculateStreaks(validTrades);
20878
20839
  const timeInDrawdown = this.calculateTimeInDrawdown(validTrades, adjustedDailyLogs);
20879
20840
  const periodicWinRates = this.calculatePeriodicWinRates(validTrades);
20880
- const initialCapital = _PortfolioStatsCalculator.calculateInitialCapital(validTrades, adjustedDailyLogs);
20841
+ const initialCapital = _PortfolioStatsCalculator.calculateInitialCapital(
20842
+ validTrades,
20843
+ adjustedDailyLogs
20844
+ );
20881
20845
  return {
20882
20846
  totalTrades,
20883
20847
  totalPl,
@@ -20915,14 +20879,17 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20915
20879
  if (trades.length === 0) {
20916
20880
  return {};
20917
20881
  }
20918
- const tradesByStrategy = trades.reduce((acc, trade) => {
20919
- const strategy = trade.strategy || "Unknown";
20920
- if (!acc[strategy]) {
20921
- acc[strategy] = [];
20922
- }
20923
- acc[strategy].push(trade);
20924
- return acc;
20925
- }, {});
20882
+ const tradesByStrategy = trades.reduce(
20883
+ (acc, trade) => {
20884
+ const strategy = trade.strategy || "Unknown";
20885
+ if (!acc[strategy]) {
20886
+ acc[strategy] = [];
20887
+ }
20888
+ acc[strategy].push(trade);
20889
+ return acc;
20890
+ },
20891
+ {}
20892
+ );
20926
20893
  const strategyStats = {};
20927
20894
  Object.entries(tradesByStrategy).forEach(([strategyName, strategyTrades]) => {
20928
20895
  const portfolioStats = this.calculatePortfolioStats(strategyTrades);
@@ -20957,7 +20924,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
20957
20924
  return maxDrawdown2;
20958
20925
  }
20959
20926
  if (trades.length === 0) return 0;
20960
- const closedTrades = trades.filter((trade) => trade.dateClosed && trade.fundsAtClose !== void 0);
20927
+ const closedTrades = trades.filter(
20928
+ (trade) => trade.dateClosed && trade.fundsAtClose !== void 0
20929
+ );
20961
20930
  if (closedTrades.length === 0) return 0;
20962
20931
  const sortedTrades = [...closedTrades].sort((a, b) => {
20963
20932
  try {
@@ -21058,9 +21027,7 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
21058
21027
  * Calculate average days to expiration (DTE)
21059
21028
  */
21060
21029
  calculateAvgDTE(trades) {
21061
- const tradesWithDTE = trades.filter(
21062
- (trade) => trade.dateClosed && trade.dateOpened
21063
- );
21030
+ const tradesWithDTE = trades.filter((trade) => trade.dateClosed && trade.dateOpened);
21064
21031
  if (tradesWithDTE.length === 0) return void 0;
21065
21032
  const totalDTE = tradesWithDTE.reduce((sum2, trade) => {
21066
21033
  const openDate = new Date(trade.dateOpened);
@@ -21081,7 +21048,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
21081
21048
  return a.timeOpened.localeCompare(b.timeOpened);
21082
21049
  });
21083
21050
  const startDate = new Date(sortedTrades[0].dateOpened);
21084
- const endDate = new Date(sortedTrades[sortedTrades.length - 1].dateClosed || sortedTrades[sortedTrades.length - 1].dateOpened);
21051
+ const endDate = new Date(
21052
+ sortedTrades[sortedTrades.length - 1].dateClosed || sortedTrades[sortedTrades.length - 1].dateOpened
21053
+ );
21085
21054
  const totalYears = (endDate.getTime() - startDate.getTime()) / (1e3 * 60 * 60 * 24 * 365.25);
21086
21055
  if (totalYears <= 0) return void 0;
21087
21056
  const initialCapital = _PortfolioStatsCalculator.calculateInitialCapital(trades);
@@ -21148,7 +21117,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
21148
21117
  if (winningTrades.length === 0 || losingTrades.length === 0) return void 0;
21149
21118
  const winRate = winningTrades.length / trades.length;
21150
21119
  const avgWin = winningTrades.reduce((sum2, trade) => sum2 + trade.pl, 0) / winningTrades.length;
21151
- const avgLoss = Math.abs(losingTrades.reduce((sum2, trade) => sum2 + trade.pl, 0) / losingTrades.length);
21120
+ const avgLoss = Math.abs(
21121
+ losingTrades.reduce((sum2, trade) => sum2 + trade.pl, 0) / losingTrades.length
21122
+ );
21152
21123
  if (avgLoss === 0) return void 0;
21153
21124
  const winLossRatio = avgWin / avgLoss;
21154
21125
  const kellyPercentage = (winRate * winLossRatio - (1 - winRate)) / winLossRatio;
@@ -21194,7 +21165,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
21194
21165
  return daysInDrawdown / dailyLogEntries.length * 100;
21195
21166
  }
21196
21167
  if (trades.length === 0) return void 0;
21197
- const closedTrades = trades.filter((trade) => trade.dateClosed && trade.fundsAtClose !== void 0);
21168
+ const closedTrades = trades.filter(
21169
+ (trade) => trade.dateClosed && trade.fundsAtClose !== void 0
21170
+ );
21198
21171
  if (closedTrades.length === 0) return void 0;
21199
21172
  const sortedTrades = [...closedTrades].sort((a, b) => {
21200
21173
  try {
@@ -21243,7 +21216,9 @@ var PortfolioStatsCalculator = class _PortfolioStatsCalculator {
21243
21216
  }
21244
21217
  monthlyTrades.get(monthKey).push(trade);
21245
21218
  const startOfYear = new Date(date.getFullYear(), 0, 1);
21246
- const weekNumber = Math.ceil(((date.getTime() - startOfYear.getTime()) / 864e5 + startOfYear.getDay() + 1) / 7);
21219
+ const weekNumber = Math.ceil(
21220
+ ((date.getTime() - startOfYear.getTime()) / 864e5 + startOfYear.getDay() + 1) / 7
21221
+ );
21247
21222
  const weekKey = `${date.getFullYear()}-${String(weekNumber).padStart(2, "0")}`;
21248
21223
  if (!weeklyTrades.has(weekKey)) {
21249
21224
  weeklyTrades.set(weekKey, []);
@@ -21420,7 +21395,14 @@ var WalkForwardAnalyzer = class {
21420
21395
  const calculator = new PortfolioStatsCalculator();
21421
21396
  const startedAt = /* @__PURE__ */ new Date();
21422
21397
  if (sortedTrades.length === 0) {
21423
- const emptyResults = this.buildResults([], options.config, 0, 0, sortedTrades.length, startedAt);
21398
+ const emptyResults = this.buildResults(
21399
+ [],
21400
+ options.config,
21401
+ 0,
21402
+ 0,
21403
+ sortedTrades.length,
21404
+ startedAt
21405
+ );
21424
21406
  return {
21425
21407
  config: options.config,
21426
21408
  results: emptyResults,
@@ -21441,8 +21423,16 @@ var WalkForwardAnalyzer = class {
21441
21423
  for (let index = 0; index < windows.length; index++) {
21442
21424
  this.throwIfAborted(options.signal);
21443
21425
  const window2 = windows[index];
21444
- const inSampleTrades = this.filterTrades(sortedTrades, window2.inSampleStart, window2.inSampleEnd);
21445
- const outSampleTrades = this.filterTrades(sortedTrades, window2.outOfSampleStart, window2.outOfSampleEnd);
21426
+ const inSampleTrades = this.filterTrades(
21427
+ sortedTrades,
21428
+ window2.inSampleStart,
21429
+ window2.inSampleEnd
21430
+ );
21431
+ const outSampleTrades = this.filterTrades(
21432
+ sortedTrades,
21433
+ window2.outOfSampleStart,
21434
+ window2.outOfSampleEnd
21435
+ );
21446
21436
  const minInSample = options.config.minInSampleTrades ?? DEFAULT_MIN_IN_SAMPLE_TRADES;
21447
21437
  const minOutSample = options.config.minOutOfSampleTrades ?? DEFAULT_MIN_OUT_SAMPLE_TRADES;
21448
21438
  if (inSampleTrades.length < minInSample || outSampleTrades.length < minOutSample) {
@@ -21451,7 +21441,9 @@ var WalkForwardAnalyzer = class {
21451
21441
  skippedWindows.push({ ...window2, reason, detail });
21452
21442
  continue;
21453
21443
  }
21454
- const combinationIterator = this.buildCombinationIterator(options.config.parameterRanges || {});
21444
+ const combinationIterator = this.buildCombinationIterator(
21445
+ options.config.parameterRanges || {}
21446
+ );
21455
21447
  if (combinationIterator.count > MAX_PARAMETER_COMBINATIONS) {
21456
21448
  throw new Error(
21457
21449
  `Walk-forward parameter grid too large (${combinationIterator.count.toLocaleString()} combinations). Reduce ranges or increase step sizes.`
@@ -21482,7 +21474,12 @@ var WalkForwardAnalyzer = class {
21482
21474
  inSampleInitialCapital
21483
21475
  );
21484
21476
  const inSampleStats = calculator.calculatePortfolioStats(scaledInSampleTrades);
21485
- if (!this.isRiskAcceptable(params, inSampleStats, scaledInSampleTrades, options.config.performanceFloor)) {
21477
+ if (!this.isRiskAcceptable(
21478
+ params,
21479
+ inSampleStats,
21480
+ scaledInSampleTrades,
21481
+ options.config.performanceFloor
21482
+ )) {
21486
21483
  continue;
21487
21484
  }
21488
21485
  if (enforceDiversificationConstraints && diversificationConfig) {
@@ -21494,7 +21491,10 @@ var WalkForwardAnalyzer = class {
21494
21491
  continue;
21495
21492
  }
21496
21493
  }
21497
- const targetValue = this.getTargetMetricValue(inSampleStats, options.config.optimizationTarget);
21494
+ const targetValue = this.getTargetMetricValue(
21495
+ inSampleStats,
21496
+ options.config.optimizationTarget
21497
+ );
21498
21498
  if (!Number.isFinite(targetValue)) {
21499
21499
  continue;
21500
21500
  }
@@ -21549,7 +21549,10 @@ var WalkForwardAnalyzer = class {
21549
21549
  inSampleMetrics: bestCombo.inSampleStats,
21550
21550
  outOfSampleMetrics: outSampleStats,
21551
21551
  targetMetricInSample: bestCombo.score,
21552
- targetMetricOutOfSample: this.getTargetMetricValue(outSampleStats, options.config.optimizationTarget),
21552
+ targetMetricOutOfSample: this.getTargetMetricValue(
21553
+ outSampleStats,
21554
+ options.config.optimizationTarget
21555
+ ),
21553
21556
  diversificationMetrics
21554
21557
  };
21555
21558
  periods.push(period);
@@ -21623,7 +21626,9 @@ var WalkForwardAnalyzer = class {
21623
21626
  const inSampleStart = new Date(cursor);
21624
21627
  const inSampleEnd = new Date(cursor + (config4.inSampleDays - 1) * DAY_MS);
21625
21628
  const outOfSampleStart = new Date(inSampleEnd.getTime() + DAY_MS);
21626
- const outOfSampleEnd = new Date(outOfSampleStart.getTime() + (config4.outOfSampleDays - 1) * DAY_MS);
21629
+ const outOfSampleEnd = new Date(
21630
+ outOfSampleStart.getTime() + (config4.outOfSampleDays - 1) * DAY_MS
21631
+ );
21627
21632
  if (outOfSampleStart > lastDate) {
21628
21633
  break;
21629
21634
  }
@@ -21638,7 +21643,9 @@ var WalkForwardAnalyzer = class {
21638
21643
  return windows;
21639
21644
  }
21640
21645
  floorToUTCDate(date) {
21641
- const floored = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
21646
+ const floored = new Date(
21647
+ Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())
21648
+ );
21642
21649
  return floored;
21643
21650
  }
21644
21651
  buildCombinationIterator(parameterRanges) {
@@ -21824,10 +21831,7 @@ var WalkForwardAnalyzer = class {
21824
21831
  maxCorrelationPair,
21825
21832
  avgTailDependence: tailRiskResult?.analytics.averageJointTailRisk ?? 0,
21826
21833
  maxTailDependence: tailRiskResult?.analytics.highestJointTailRisk.value ?? 0,
21827
- maxTailDependencePair: tailRiskResult?.analytics.highestJointTailRisk.pair ?? [
21828
- "",
21829
- ""
21830
- ],
21834
+ maxTailDependencePair: tailRiskResult?.analytics.highestJointTailRisk.pair ?? ["", ""],
21831
21835
  effectiveFactors: tailRiskResult?.effectiveFactors ?? correlationMatrix.strategies.length,
21832
21836
  highRiskPairsPct: tailRiskResult?.analytics.highRiskPairsPct ?? 0,
21833
21837
  // Track insufficient tail data for UI display
@@ -22198,10 +22202,7 @@ function createSyntheticMaxLossTrades(trades, percentage, simulationLength, base
22198
22202
  return [];
22199
22203
  }
22200
22204
  const requestedBudget = Math.ceil(simulationLength * percentage / 100);
22201
- const cappedBudget = Math.min(
22202
- simulationLength,
22203
- Math.max(1, requestedBudget)
22204
- );
22205
+ const cappedBudget = Math.min(simulationLength, Math.max(1, requestedBudget));
22205
22206
  if (cappedBudget <= 0) {
22206
22207
  return [];
22207
22208
  }
@@ -22397,9 +22398,7 @@ function calculatePercentageReturns(trades, normalizeTo1Lot, initialCapital) {
22397
22398
  if (trades.length === 0) {
22398
22399
  return [];
22399
22400
  }
22400
- const sortedTrades = [...trades].sort(
22401
- (a, b) => a.dateOpened.getTime() - b.dateOpened.getTime()
22402
- );
22401
+ const sortedTrades = [...trades].sort((a, b) => a.dateOpened.getTime() - b.dateOpened.getTime());
22403
22402
  const percentageReturns = [];
22404
22403
  let capital;
22405
22404
  if (initialCapital !== void 0 && initialCapital > 0) {
@@ -22424,9 +22423,7 @@ function calculateMarginReturns(trades) {
22424
22423
  if (trades.length === 0) {
22425
22424
  return [];
22426
22425
  }
22427
- const sortedTrades = [...trades].sort(
22428
- (a, b) => a.dateOpened.getTime() - b.dateOpened.getTime()
22429
- );
22426
+ const sortedTrades = [...trades].sort((a, b) => a.dateOpened.getTime() - b.dateOpened.getTime());
22430
22427
  const returns = [];
22431
22428
  for (const trade of sortedTrades) {
22432
22429
  if (trade.marginReq > 0) {
@@ -22520,25 +22517,13 @@ function runMonteCarloSimulation(trades, params) {
22520
22517
  let actualResamplePoolSize;
22521
22518
  const isPercentageMode = params.resampleMethod === "percentage";
22522
22519
  if (params.resampleMethod === "trades") {
22523
- const tradePool = getTradeResamplePool(
22524
- trades,
22525
- params.resampleWindow,
22526
- params.strategy
22527
- );
22520
+ const tradePool = getTradeResamplePool(trades, params.resampleWindow, params.strategy);
22528
22521
  actualResamplePoolSize = tradePool.length;
22529
- resamplePool = tradePool.map(
22530
- (t) => params.normalizeTo1Lot ? scaleTradeToOneLot(t) : t.pl
22531
- );
22522
+ resamplePool = tradePool.map((t) => params.normalizeTo1Lot ? scaleTradeToOneLot(t) : t.pl);
22532
22523
  } else if (params.resampleMethod === "daily") {
22533
22524
  const filteredTrades = params.strategy && params.strategy !== "all" ? trades.filter((t) => t.strategy === params.strategy) : trades;
22534
- const dailyReturns = calculateDailyReturns(
22535
- filteredTrades,
22536
- params.normalizeTo1Lot
22537
- );
22538
- const dailyPLs = getDailyResamplePool(
22539
- dailyReturns,
22540
- params.resampleWindow
22541
- );
22525
+ const dailyReturns = calculateDailyReturns(filteredTrades, params.normalizeTo1Lot);
22526
+ const dailyPLs = getDailyResamplePool(dailyReturns, params.resampleWindow);
22542
22527
  actualResamplePoolSize = dailyPLs.length;
22543
22528
  resamplePool = dailyPLs;
22544
22529
  } else {
@@ -22557,10 +22542,7 @@ function runMonteCarloSimulation(trades, params) {
22557
22542
  params.historicalInitialCapital
22558
22543
  // Use historical capital (if provided) to reconstruct trajectory
22559
22544
  );
22560
- const percentagePool = getPercentageResamplePool(
22561
- percentageReturns,
22562
- params.resampleWindow
22563
- );
22545
+ const percentagePool = getPercentageResamplePool(percentageReturns, params.resampleWindow);
22564
22546
  actualResamplePoolSize = percentagePool.length;
22565
22547
  resamplePool = percentagePool;
22566
22548
  }
@@ -22611,20 +22593,13 @@ function runMonteCarloSimulation(trades, params) {
22611
22593
  resamplePool = [...resamplePool, ...worstCaseTrades];
22612
22594
  }
22613
22595
  }
22614
- const enforcedGuaranteeTrades = params.worstCaseEnabled && params.worstCaseMode === "guarantee" && params.simulationLength > 0 ? worstCaseTrades.slice(
22615
- 0,
22616
- Math.min(worstCaseTrades.length, params.simulationLength)
22617
- ) : [];
22596
+ const enforcedGuaranteeTrades = params.worstCaseEnabled && params.worstCaseMode === "guarantee" && params.simulationLength > 0 ? worstCaseTrades.slice(0, Math.min(worstCaseTrades.length, params.simulationLength)) : [];
22618
22597
  const simulations = [];
22619
22598
  for (let i = 0; i < params.numSimulations; i++) {
22620
22599
  const seed = params.randomSeed !== void 0 ? params.randomSeed + i : void 0;
22621
22600
  const guaranteeActive = enforcedGuaranteeTrades.length > 0;
22622
22601
  const baselineSampleSize = guaranteeActive ? Math.max(0, params.simulationLength - enforcedGuaranteeTrades.length) : params.simulationLength;
22623
- let resampledPLs = resampleWithReplacement(
22624
- resamplePool,
22625
- baselineSampleSize,
22626
- seed
22627
- );
22602
+ let resampledPLs = resampleWithReplacement(resamplePool, baselineSampleSize, seed);
22628
22603
  if (guaranteeActive) {
22629
22604
  const combined = [...resampledPLs];
22630
22605
  const rng = seed !== void 0 ? createSeededRandom(seed + 999999) : Math.random;
@@ -22714,10 +22689,7 @@ function calculateStatistics(simulations) {
22714
22689
  50
22715
22690
  );
22716
22691
  const meanSharpeRatio = sharpeRatios.reduce((sum2, s) => sum2 + s, 0) / sharpeRatios.length;
22717
- const variance2 = finalValues.reduce(
22718
- (sum2, v) => sum2 + Math.pow(v - meanFinalValue, 2),
22719
- 0
22720
- ) / (finalValues.length - 1);
22692
+ const variance2 = finalValues.reduce((sum2, v) => sum2 + Math.pow(v - meanFinalValue, 2), 0) / (finalValues.length - 1);
22721
22693
  const stdFinalValue = Math.sqrt(variance2);
22722
22694
  const profitableSimulations = totalReturns.filter((r) => r > 0).length;
22723
22695
  const probabilityOfProfit = profitableSimulations / totalReturns.length;
@@ -22908,10 +22880,7 @@ function linearRegression(y) {
22908
22880
  const slope = sumX2 > 0 ? sumXY / sumX2 : 0;
22909
22881
  const intercept = meanY - slope * meanX;
22910
22882
  const predicted = x.map((xi) => slope * xi + intercept);
22911
- const ssRes = y.reduce(
22912
- (sum2, yi, i) => sum2 + (yi - predicted[i]) ** 2,
22913
- 0
22914
- );
22883
+ const ssRes = y.reduce((sum2, yi, i) => sum2 + (yi - predicted[i]) ** 2, 0);
22915
22884
  const ssTot = y.reduce((sum2, yi) => sum2 + (yi - meanY) ** 2, 0);
22916
22885
  const rSquared = ssTot > 0 ? 1 - ssRes / ssTot : 0;
22917
22886
  const mse = n > 2 ? ssRes / (n - 2) : 0;
@@ -23152,7 +23121,13 @@ function segmentByPeriod(trades) {
23152
23121
  const monthDate = parseMonthKey(m.periodKey);
23153
23122
  return monthDate !== null && getQuarterKey(monthDate) === qKey;
23154
23123
  }).map((m) => m.avgMonthlyReturnPct);
23155
- return computePeriodMetrics(qKey, quarterTrades, isPartial, partialNote, constituentMonthlyReturns);
23124
+ return computePeriodMetrics(
23125
+ qKey,
23126
+ quarterTrades,
23127
+ isPartial,
23128
+ partialNote,
23129
+ constituentMonthlyReturns
23130
+ );
23156
23131
  });
23157
23132
  const yearlyGroups = groupTradesByKey(sortedTrades, getYearKey);
23158
23133
  const yearKeys = Array.from(yearlyGroups.keys()).sort();
@@ -23165,7 +23140,13 @@ function segmentByPeriod(trades) {
23165
23140
  index === yearKeys.length - 1
23166
23141
  );
23167
23142
  const constituentMonthlyReturns = monthlyMetrics.filter((m) => m.periodKey.startsWith(yKey + "-")).map((m) => m.avgMonthlyReturnPct);
23168
- return computePeriodMetrics(yKey, yearTrades, isPartial, partialNote, constituentMonthlyReturns);
23143
+ return computePeriodMetrics(
23144
+ yKey,
23145
+ yearTrades,
23146
+ isPartial,
23147
+ partialNote,
23148
+ constituentMonthlyReturns
23149
+ );
23169
23150
  });
23170
23151
  const yearlyTrends = computePeriodTrends(yearlyMetrics);
23171
23152
  const quarterlyTrends = computePeriodTrends(quarterlyMetrics);
@@ -23362,7 +23343,14 @@ function computeRollingMetrics(trades, options) {
23362
23343
  };
23363
23344
  }
23364
23345
  function computeSeasonalAverages(series) {
23365
- const metricNames = ["winRate", "profitFactor", "kellyPercent", "sharpeRatio", "avgReturn", "netPl"];
23346
+ const metricNames = [
23347
+ "winRate",
23348
+ "profitFactor",
23349
+ "kellyPercent",
23350
+ "sharpeRatio",
23351
+ "avgReturn",
23352
+ "netPl"
23353
+ ];
23366
23354
  const buckets = {};
23367
23355
  for (const metric of metricNames) {
23368
23356
  buckets[metric] = { Q1: [], Q2: [], Q3: [], Q4: [] };
@@ -23598,9 +23586,17 @@ function runRegimeComparison(trades, options) {
23598
23586
  };
23599
23587
  const recentResult = runMonteCarloSimulation(recentPool, recentParams);
23600
23588
  const metricPairs = [
23601
- ["probabilityOfProfit", fullResult.statistics.probabilityOfProfit, recentResult.statistics.probabilityOfProfit],
23589
+ [
23590
+ "probabilityOfProfit",
23591
+ fullResult.statistics.probabilityOfProfit,
23592
+ recentResult.statistics.probabilityOfProfit
23593
+ ],
23602
23594
  ["sharpeRatio", fullResult.statistics.meanSharpeRatio, recentResult.statistics.meanSharpeRatio],
23603
- ["medianMaxDrawdown", fullResult.statistics.medianMaxDrawdown, recentResult.statistics.medianMaxDrawdown]
23595
+ [
23596
+ "medianMaxDrawdown",
23597
+ fullResult.statistics.medianMaxDrawdown,
23598
+ recentResult.statistics.medianMaxDrawdown
23599
+ ]
23604
23600
  ];
23605
23601
  const comparison = metricPairs.map(([metric, fullValue, recentValue]) => {
23606
23602
  const delta = recentValue - fullValue;
@@ -23773,7 +23769,6 @@ function analyzeWalkForwardDegradation(trades, options) {
23773
23769
  if (options) {
23774
23770
  for (const [key, value] of Object.entries(options)) {
23775
23771
  if (value !== void 0) {
23776
- ;
23777
23772
  definedOptions[key] = value;
23778
23773
  }
23779
23774
  }
@@ -23862,7 +23857,11 @@ function analyzeWalkForwardDegradation(trades, options) {
23862
23857
  const oosMetrics = computeMetrics(oosTrades);
23863
23858
  const sharpeEfficiency = computeEfficiency(oosMetrics.sharpe, isMetrics.sharpe, "sharpe");
23864
23859
  const winRateEfficiency = computeEfficiency(oosMetrics.winRate, isMetrics.winRate, "winRate");
23865
- const pfEfficiency = computeEfficiency(oosMetrics.profitFactor, isMetrics.profitFactor, "profitFactor");
23860
+ const pfEfficiency = computeEfficiency(
23861
+ oosMetrics.profitFactor,
23862
+ isMetrics.profitFactor,
23863
+ "profitFactor"
23864
+ );
23866
23865
  if (isMetrics.sharpe !== null && isMetrics.sharpe < 0) {
23867
23866
  warnings.push(
23868
23867
  `Negative IS Sharpe in period ${window2.periodIndex} -- efficiency ratio may be misleading`
@@ -23871,9 +23870,21 @@ function analyzeWalkForwardDegradation(trades, options) {
23871
23870
  periods.push({
23872
23871
  window: window2,
23873
23872
  metrics: {
23874
- sharpe: { inSample: isMetrics.sharpe, outOfSample: oosMetrics.sharpe, efficiency: sharpeEfficiency },
23875
- winRate: { inSample: isMetrics.winRate, outOfSample: oosMetrics.winRate, efficiency: winRateEfficiency },
23876
- profitFactor: { inSample: isMetrics.profitFactor, outOfSample: oosMetrics.profitFactor, efficiency: pfEfficiency }
23873
+ sharpe: {
23874
+ inSample: isMetrics.sharpe,
23875
+ outOfSample: oosMetrics.sharpe,
23876
+ efficiency: sharpeEfficiency
23877
+ },
23878
+ winRate: {
23879
+ inSample: isMetrics.winRate,
23880
+ outOfSample: oosMetrics.winRate,
23881
+ efficiency: winRateEfficiency
23882
+ },
23883
+ profitFactor: {
23884
+ inSample: isMetrics.profitFactor,
23885
+ outOfSample: oosMetrics.profitFactor,
23886
+ efficiency: pfEfficiency
23887
+ }
23877
23888
  },
23878
23889
  sufficient: true,
23879
23890
  warnings
@@ -23917,7 +23928,10 @@ function analyzeWalkForwardDegradation(trades, options) {
23917
23928
  const qualifyingCount = qualifyingPeriods.length;
23918
23929
  const recentCount = Math.min(config4.recentPeriodCount, qualifyingCount);
23919
23930
  const recentPeriodSlice = qualifyingPeriods.slice(-recentCount);
23920
- const historicalPeriodSlice = qualifyingPeriods.slice(0, Math.max(0, qualifyingCount - recentCount));
23931
+ const historicalPeriodSlice = qualifyingPeriods.slice(
23932
+ 0,
23933
+ Math.max(0, qualifyingCount - recentCount)
23934
+ );
23921
23935
  const recentData = getEfficiencyData(recentPeriodSlice);
23922
23936
  const historicalData = getEfficiencyData(historicalPeriodSlice);
23923
23937
  const recentAvgEfficiency = {
@@ -24004,9 +24018,7 @@ function getIsoWeekKey2(dateStr) {
24004
24018
  const dayOfWeek = thursday.getUTCDay() || 7;
24005
24019
  thursday.setUTCDate(thursday.getUTCDate() + (4 - dayOfWeek));
24006
24020
  const yearStart = new Date(Date.UTC(thursday.getUTCFullYear(), 0, 1));
24007
- const weekNum = Math.ceil(
24008
- ((thursday.getTime() - yearStart.getTime()) / 864e5 + 1) / 7
24009
- );
24021
+ const weekNum = Math.ceil(((thursday.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
24010
24022
  return `${thursday.getUTCFullYear()}-W${String(weekNum).padStart(2, "0")}`;
24011
24023
  }
24012
24024
  function getMonthKey3(dateStr) {
@@ -24025,9 +24037,7 @@ function applyDateRangeFilter(trades, dateRange) {
24025
24037
  }
24026
24038
  function applyStrategyFilter(trades, strategy) {
24027
24039
  if (!strategy) return trades;
24028
- return trades.filter(
24029
- (t) => t.strategy.toLowerCase() === strategy.toLowerCase()
24030
- );
24040
+ return trades.filter((t) => t.strategy.toLowerCase() === strategy.toLowerCase());
24031
24041
  }
24032
24042
  function calculateScaledPl(btPl, actualPl, btContracts, actualContracts, scaling) {
24033
24043
  let scaledBtPl = btPl;
@@ -24206,14 +24216,20 @@ function analyzeLiveAlignment(backtestTrades, actualTrades, options) {
24206
24216
  if (actualTrades.length === 0) {
24207
24217
  warnings.push("No actual trades provided");
24208
24218
  }
24209
- const { pairs, unmatchedBacktestByStrategy, unmatchedActualByStrategy } = matchTradesWithScaledPl(filteredBacktest, filteredActual, scaling);
24219
+ const { pairs, unmatchedBacktestByStrategy, unmatchedActualByStrategy } = matchTradesWithScaledPl(
24220
+ filteredBacktest,
24221
+ filteredActual,
24222
+ scaling
24223
+ );
24210
24224
  if (pairs.length === 0 && (backtestTrades.length > 0 || actualTrades.length > 0)) {
24211
24225
  warnings.push("No matched trade pairs found");
24212
24226
  }
24213
24227
  const minOverlapTrades = Math.min(filteredBacktest.length, filteredActual.length);
24214
24228
  const matchRate = minOverlapTrades > 0 ? pairs.length / minOverlapTrades : 0;
24215
24229
  if (matchRate > 0 && matchRate < 0.5) {
24216
- warnings.push(`Low match rate (${(matchRate * 100).toFixed(1)}%) - trade matching may be unreliable`);
24230
+ warnings.push(
24231
+ `Low match rate (${(matchRate * 100).toFixed(1)}%) - trade matching may be unreliable`
24232
+ );
24217
24233
  }
24218
24234
  const dayStrategyMap = /* @__PURE__ */ new Map();
24219
24235
  for (const pair of pairs) {
@@ -24236,12 +24252,14 @@ function analyzeLiveAlignment(backtestTrades, actualTrades, options) {
24236
24252
  if (agreed) stratData.agreed++;
24237
24253
  strategyDayAgreement.set(strategy, stratData);
24238
24254
  }
24239
- const directionByStrategy = Array.from(strategyDayAgreement.entries()).map(([strategy, data]) => ({
24240
- strategy,
24241
- rate: data.total > 0 ? data.agreed / data.total : 0,
24242
- totalDays: data.total,
24243
- agreementDays: data.agreed
24244
- }));
24255
+ const directionByStrategy = Array.from(strategyDayAgreement.entries()).map(
24256
+ ([strategy, data]) => ({
24257
+ strategy,
24258
+ rate: data.total > 0 ? data.agreed / data.total : 0,
24259
+ totalDays: data.total,
24260
+ agreementDays: data.agreed
24261
+ })
24262
+ );
24245
24263
  const directionAgreement = {
24246
24264
  overallRate: totalDays > 0 ? agreementDays / totalDays : 0,
24247
24265
  totalDays,
@@ -24395,20 +24413,9 @@ function safePercentChange(current, comparison) {
24395
24413
  if (comparison === 0) return null;
24396
24414
  return (current - comparison) / Math.abs(comparison) * 100;
24397
24415
  }
24398
- var DOLLAR_METRICS = /* @__PURE__ */ new Set([
24399
- "avgWin",
24400
- "avgLoss",
24401
- "avgReturn",
24402
- "netPl"
24403
- ]);
24404
- var DOLLAR_TREND_METRICS = /* @__PURE__ */ new Set([
24405
- "netPl",
24406
- "tradeCount"
24407
- ]);
24408
- var HIGHER_IS_WORSE_METRICS = /* @__PURE__ */ new Set([
24409
- "maxDrawdownPercent",
24410
- "medianMaxDrawdown"
24411
- ]);
24416
+ var DOLLAR_METRICS = /* @__PURE__ */ new Set(["avgWin", "avgLoss", "avgReturn", "netPl"]);
24417
+ var DOLLAR_TREND_METRICS = /* @__PURE__ */ new Set(["netPl", "tradeCount"]);
24418
+ var HIGHER_IS_WORSE_METRICS = /* @__PURE__ */ new Set(["maxDrawdownPercent", "medianMaxDrawdown"]);
24412
24419
  function extractObservations(periodResult, rollingResult, regimeResult, wfResult, liveResult) {
24413
24420
  const observations = [];
24414
24421
  for (const m of rollingResult.recentVsHistorical.metrics) {
@@ -24666,14 +24673,18 @@ function synthesizeEdgeDecay(trades, actualTrades, options) {
24666
24673
  const winRateComp = findMetric(rollingResult.recentVsHistorical.metrics, "winRate");
24667
24674
  const pfComp = findMetric(rollingResult.recentVsHistorical.metrics, "profitFactor");
24668
24675
  const sharpeComp = findMetric(rollingResult.recentVsHistorical.metrics, "sharpeRatio");
24669
- const rateObsWithPct = observations.filter((o) => o.percentChange !== null && o.metricType === "rate");
24676
+ const rateObsWithPct = observations.filter(
24677
+ (o) => o.percentChange !== null && o.metricType === "rate"
24678
+ );
24670
24679
  let decayCount = 0;
24671
24680
  for (const o of rateObsWithPct) {
24672
24681
  const isDecay = HIGHER_IS_WORSE_METRICS.has(o.metric) ? o.percentChange > 0 : o.percentChange < 0;
24673
24682
  if (isDecay) decayCount++;
24674
24683
  }
24675
24684
  const decayFraction = rateObsWithPct.length > 0 ? decayCount / rateObsWithPct.length : 0;
24676
- const rateObsWithAbsPct = observations.filter((o) => o.absPercentChange !== null && o.metricType === "rate");
24685
+ const rateObsWithAbsPct = observations.filter(
24686
+ (o) => o.absPercentChange !== null && o.metricType === "rate"
24687
+ );
24677
24688
  const meanAbsPctValue = rateObsWithAbsPct.length > 0 ? rateObsWithAbsPct.reduce((sum2, o) => sum2 + o.absPercentChange, 0) / rateObsWithAbsPct.length : 0;
24678
24689
  const meanAbsPctNormalized = Math.min(meanAbsPctValue / 50, 1) * decayFraction;
24679
24690
  const mcDivergenceValue = regimeResult?.divergence.compositeScore ?? null;
@@ -24708,15 +24719,35 @@ function synthesizeEdgeDecay(trades, actualTrades, options) {
24708
24719
  structuralFlagRatio: BASE_WEIGHTS.structuralFlagRatio / otherSum
24709
24720
  };
24710
24721
  }
24711
- const compositeDecayScore = Math.max(0, Math.min(
24712
- 1,
24713
- meanAbsPctNormalized * weights.meanAbsPercentChange + mcDivergenceNormalized * mcDecayDirection * weights.mcRegimeDivergence + wfEffDeltaNormalized * weights.wfEfficiencyDelta + structuralFlagRatioNormalized * weights.structuralFlagRatio
24714
- ));
24722
+ const compositeDecayScore = Math.max(
24723
+ 0,
24724
+ Math.min(
24725
+ 1,
24726
+ meanAbsPctNormalized * weights.meanAbsPercentChange + mcDivergenceNormalized * mcDecayDirection * weights.mcRegimeDivergence + wfEffDeltaNormalized * weights.wfEfficiencyDelta + structuralFlagRatioNormalized * weights.structuralFlagRatio
24727
+ )
24728
+ );
24715
24729
  const compositeDecayScoreComponents = {
24716
- meanAbsPercentChange: { value: meanAbsPctValue, normalized: meanAbsPctNormalized, weight: weights.meanAbsPercentChange, decayFraction },
24717
- mcRegimeDivergence: { value: mcDivergenceValue, normalized: mcDivergenceNormalized * mcDecayDirection, weight: weights.mcRegimeDivergence },
24718
- wfEfficiencyDelta: { value: wfEffDeltaValue, normalized: wfEffDeltaNormalized, weight: weights.wfEfficiencyDelta },
24719
- structuralFlagRatio: { value: structuralFlagRatioValue, normalized: structuralFlagRatioNormalized, weight: weights.structuralFlagRatio }
24730
+ meanAbsPercentChange: {
24731
+ value: meanAbsPctValue,
24732
+ normalized: meanAbsPctNormalized,
24733
+ weight: weights.meanAbsPercentChange,
24734
+ decayFraction
24735
+ },
24736
+ mcRegimeDivergence: {
24737
+ value: mcDivergenceValue,
24738
+ normalized: mcDivergenceNormalized * mcDecayDirection,
24739
+ weight: weights.mcRegimeDivergence
24740
+ },
24741
+ wfEfficiencyDelta: {
24742
+ value: wfEffDeltaValue,
24743
+ normalized: wfEffDeltaNormalized,
24744
+ weight: weights.wfEfficiencyDelta
24745
+ },
24746
+ structuralFlagRatio: {
24747
+ value: structuralFlagRatioValue,
24748
+ normalized: structuralFlagRatioNormalized,
24749
+ weight: weights.structuralFlagRatio
24750
+ }
24720
24751
  };
24721
24752
  const summary = {
24722
24753
  totalTrades,
@@ -24969,7 +25000,9 @@ var PerformanceCalculator = class {
24969
25000
  static calculateMonthlyReturns(trades, initialCapital) {
24970
25001
  if (trades.length === 0) return {};
24971
25002
  if (!initialCapital) {
24972
- const firstTrade = trades.sort((a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime())[0];
25003
+ const firstTrade = trades.sort(
25004
+ (a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime()
25005
+ )[0];
24973
25006
  initialCapital = firstTrade.fundsAtClose - firstTrade.pl;
24974
25007
  }
24975
25008
  const monthlyPl = this.aggregatePLByPeriod(trades, "monthly");
@@ -25102,53 +25135,300 @@ var PerformanceCalculator = class {
25102
25135
  // ../lib/models/report-config.ts
25103
25136
  var REPORT_FIELDS = [
25104
25137
  // Market conditions
25105
- { field: "openingVix", label: "Opening VIX", category: "market", description: "VIX level when the trade was opened" },
25106
- { field: "closingVix", label: "Closing VIX", category: "market", description: "VIX level when the trade was closed" },
25107
- { field: "vixChange", label: "VIX Change", category: "market", description: "How much VIX moved during the trade", formula: "Closing VIX - Opening VIX" },
25108
- { field: "vixChangePct", label: "VIX Change %", category: "market", unit: "%", description: "Percentage change in VIX during the trade", formula: "((Closing VIX - Opening VIX) / Opening VIX) \xD7 100" },
25109
- { field: "openingShortLongRatio", label: "Opening S/L Ratio", category: "market", description: "Short/Long ratio at trade entry - measures market sentiment" },
25110
- { field: "closingShortLongRatio", label: "Closing S/L Ratio", category: "market", description: "Short/Long ratio at trade exit" },
25111
- { field: "shortLongRatioChange", label: "S/L Ratio Change", category: "market", description: "How S/L ratio changed during the trade", formula: "Closing S/L Ratio / Opening S/L Ratio" },
25112
- { field: "shortLongRatioChangePct", label: "S/L Ratio Change %", category: "market", unit: "%", description: "Percentage change in S/L ratio", formula: "((Closing - Opening) / Opening) \xD7 100" },
25113
- { field: "gap", label: "Gap", category: "market", description: "Opening gap in points from previous close" },
25114
- { field: "movement", label: "Movement", category: "market", description: "Underlying price movement during the trade" },
25138
+ {
25139
+ field: "openingVix",
25140
+ label: "Opening VIX",
25141
+ category: "market",
25142
+ description: "VIX level when the trade was opened"
25143
+ },
25144
+ {
25145
+ field: "closingVix",
25146
+ label: "Closing VIX",
25147
+ category: "market",
25148
+ description: "VIX level when the trade was closed"
25149
+ },
25150
+ {
25151
+ field: "vixChange",
25152
+ label: "VIX Change",
25153
+ category: "market",
25154
+ description: "How much VIX moved during the trade",
25155
+ formula: "Closing VIX - Opening VIX"
25156
+ },
25157
+ {
25158
+ field: "vixChangePct",
25159
+ label: "VIX Change %",
25160
+ category: "market",
25161
+ unit: "%",
25162
+ description: "Percentage change in VIX during the trade",
25163
+ formula: "((Closing VIX - Opening VIX) / Opening VIX) \xD7 100"
25164
+ },
25165
+ {
25166
+ field: "openingShortLongRatio",
25167
+ label: "Opening S/L Ratio",
25168
+ category: "market",
25169
+ description: "Short/Long ratio at trade entry - measures market sentiment"
25170
+ },
25171
+ {
25172
+ field: "closingShortLongRatio",
25173
+ label: "Closing S/L Ratio",
25174
+ category: "market",
25175
+ description: "Short/Long ratio at trade exit"
25176
+ },
25177
+ {
25178
+ field: "shortLongRatioChange",
25179
+ label: "S/L Ratio Change",
25180
+ category: "market",
25181
+ description: "How S/L ratio changed during the trade",
25182
+ formula: "Closing S/L Ratio / Opening S/L Ratio"
25183
+ },
25184
+ {
25185
+ field: "shortLongRatioChangePct",
25186
+ label: "S/L Ratio Change %",
25187
+ category: "market",
25188
+ unit: "%",
25189
+ description: "Percentage change in S/L ratio",
25190
+ formula: "((Closing - Opening) / Opening) \xD7 100"
25191
+ },
25192
+ {
25193
+ field: "gap",
25194
+ label: "Gap",
25195
+ category: "market",
25196
+ description: "Opening gap in points from previous close"
25197
+ },
25198
+ {
25199
+ field: "movement",
25200
+ label: "Movement",
25201
+ category: "market",
25202
+ description: "Underlying price movement during the trade"
25203
+ },
25115
25204
  // Return metrics
25116
- { field: "pl", label: "Profit/Loss", category: "returns", unit: "$", description: "Trade profit or loss in dollars (before fees)" },
25117
- { field: "netPl", label: "Net P/L", category: "returns", unit: "$", description: "Profit/loss after subtracting all fees", formula: "P/L - Total Fees" },
25118
- { field: "plPct", label: "P/L %", category: "returns", unit: "%", description: "Return as a percentage of premium collected", formula: "(P/L / Premium) \xD7 100" },
25119
- { field: "netPlPct", label: "Net P/L %", category: "returns", unit: "%", description: "Net return as a percentage of premium", formula: "(Net P/L / Premium) \xD7 100" },
25120
- { field: "rom", label: "Return on Margin", category: "returns", unit: "%", description: "Return relative to margin required - measures capital efficiency", formula: "(P/L / Margin Required) \xD7 100" },
25121
- { field: "isWinner", label: "Is Winner", category: "returns", description: "Binary flag: 1 if trade was profitable, 0 if it was a loss" },
25205
+ {
25206
+ field: "pl",
25207
+ label: "Profit/Loss",
25208
+ category: "returns",
25209
+ unit: "$",
25210
+ description: "Trade profit or loss in dollars (before fees)"
25211
+ },
25212
+ {
25213
+ field: "netPl",
25214
+ label: "Net P/L",
25215
+ category: "returns",
25216
+ unit: "$",
25217
+ description: "Profit/loss after subtracting all fees",
25218
+ formula: "P/L - Total Fees"
25219
+ },
25220
+ {
25221
+ field: "plPct",
25222
+ label: "P/L %",
25223
+ category: "returns",
25224
+ unit: "%",
25225
+ description: "Return as a percentage of premium collected",
25226
+ formula: "(P/L / Premium) \xD7 100"
25227
+ },
25228
+ {
25229
+ field: "netPlPct",
25230
+ label: "Net P/L %",
25231
+ category: "returns",
25232
+ unit: "%",
25233
+ description: "Net return as a percentage of premium",
25234
+ formula: "(Net P/L / Premium) \xD7 100"
25235
+ },
25236
+ {
25237
+ field: "rom",
25238
+ label: "Return on Margin",
25239
+ category: "returns",
25240
+ unit: "%",
25241
+ description: "Return relative to margin required - measures capital efficiency",
25242
+ formula: "(P/L / Margin Required) \xD7 100"
25243
+ },
25244
+ {
25245
+ field: "isWinner",
25246
+ label: "Is Winner",
25247
+ category: "returns",
25248
+ description: "Binary flag: 1 if trade was profitable, 0 if it was a loss"
25249
+ },
25122
25250
  // Risk metrics (MFE/MAE)
25123
- { field: "mfePercent", label: "MFE %", category: "risk", unit: "%", description: "Maximum Favorable Excursion - the best unrealized profit during the trade as % of premium", formula: "(Max Unrealized Profit / Premium) \xD7 100" },
25124
- { field: "maePercent", label: "MAE %", category: "risk", unit: "%", description: "Maximum Adverse Excursion - the worst unrealized loss during the trade as % of premium", formula: "(Max Unrealized Loss / Premium) \xD7 100" },
25125
- { field: "profitCapturePercent", label: "Profit Capture %", category: "risk", unit: "%", description: "How much of the peak profit was captured at exit", formula: "(P/L / MFE) \xD7 100" },
25126
- { field: "excursionRatio", label: "Excursion Ratio", category: "risk", description: "Reward/risk ratio - how much upside vs downside the trade experienced", formula: "MFE / MAE" },
25127
- { field: "rMultiple", label: "R-Multiple", category: "risk", description: 'Risk-adjusted return - how many "R" (risk units) were won or lost', formula: "P/L / MAE" },
25251
+ {
25252
+ field: "mfePercent",
25253
+ label: "MFE %",
25254
+ category: "risk",
25255
+ unit: "%",
25256
+ description: "Maximum Favorable Excursion - the best unrealized profit during the trade as % of premium",
25257
+ formula: "(Max Unrealized Profit / Premium) \xD7 100"
25258
+ },
25259
+ {
25260
+ field: "maePercent",
25261
+ label: "MAE %",
25262
+ category: "risk",
25263
+ unit: "%",
25264
+ description: "Maximum Adverse Excursion - the worst unrealized loss during the trade as % of premium",
25265
+ formula: "(Max Unrealized Loss / Premium) \xD7 100"
25266
+ },
25267
+ {
25268
+ field: "profitCapturePercent",
25269
+ label: "Profit Capture %",
25270
+ category: "risk",
25271
+ unit: "%",
25272
+ description: "How much of the peak profit was captured at exit",
25273
+ formula: "(P/L / MFE) \xD7 100"
25274
+ },
25275
+ {
25276
+ field: "excursionRatio",
25277
+ label: "Excursion Ratio",
25278
+ category: "risk",
25279
+ description: "Reward/risk ratio - how much upside vs downside the trade experienced",
25280
+ formula: "MFE / MAE"
25281
+ },
25282
+ {
25283
+ field: "rMultiple",
25284
+ label: "R-Multiple",
25285
+ category: "risk",
25286
+ description: 'Risk-adjusted return - how many "R" (risk units) were won or lost',
25287
+ formula: "P/L / MAE"
25288
+ },
25128
25289
  // Trade details
25129
- { field: "premium", label: "Premium", category: "trade", unit: "$", description: "Premium collected per contract when opening the trade" },
25130
- { field: "marginReq", label: "Margin Required", category: "trade", unit: "$", description: "Margin/buying power required to hold the position" },
25131
- { field: "openingPrice", label: "Opening Price", category: "trade", unit: "$", description: "Price of the position when opened" },
25132
- { field: "closingPrice", label: "Closing Price", category: "trade", unit: "$", description: "Price of the position when closed" },
25133
- { field: "numContracts", label: "Contracts", category: "trade", description: "Number of contracts traded" },
25134
- { field: "totalFees", label: "Total Fees", category: "trade", unit: "$", description: "All commissions and fees paid", formula: "Opening Fees + Closing Fees" },
25135
- { field: "openingCommissionsFees", label: "Opening Fees", category: "trade", unit: "$", description: "Commissions and fees paid when opening" },
25136
- { field: "closingCommissionsFees", label: "Closing Fees", category: "trade", unit: "$", description: "Commissions and fees paid when closing" },
25137
- { field: "maxProfit", label: "Max Profit", category: "trade", unit: "%", description: "Maximum unrealized profit as % of premium during the trade" },
25138
- { field: "maxLoss", label: "Max Loss", category: "trade", unit: "%", description: "Maximum unrealized loss as % of premium during the trade" },
25290
+ {
25291
+ field: "premium",
25292
+ label: "Premium",
25293
+ category: "trade",
25294
+ unit: "$",
25295
+ description: "Premium collected per contract when opening the trade"
25296
+ },
25297
+ {
25298
+ field: "marginReq",
25299
+ label: "Margin Required",
25300
+ category: "trade",
25301
+ unit: "$",
25302
+ description: "Margin/buying power required to hold the position"
25303
+ },
25304
+ {
25305
+ field: "openingPrice",
25306
+ label: "Opening Price",
25307
+ category: "trade",
25308
+ unit: "$",
25309
+ description: "Price of the position when opened"
25310
+ },
25311
+ {
25312
+ field: "closingPrice",
25313
+ label: "Closing Price",
25314
+ category: "trade",
25315
+ unit: "$",
25316
+ description: "Price of the position when closed"
25317
+ },
25318
+ {
25319
+ field: "numContracts",
25320
+ label: "Contracts",
25321
+ category: "trade",
25322
+ description: "Number of contracts traded"
25323
+ },
25324
+ {
25325
+ field: "totalFees",
25326
+ label: "Total Fees",
25327
+ category: "trade",
25328
+ unit: "$",
25329
+ description: "All commissions and fees paid",
25330
+ formula: "Opening Fees + Closing Fees"
25331
+ },
25332
+ {
25333
+ field: "openingCommissionsFees",
25334
+ label: "Opening Fees",
25335
+ category: "trade",
25336
+ unit: "$",
25337
+ description: "Commissions and fees paid when opening"
25338
+ },
25339
+ {
25340
+ field: "closingCommissionsFees",
25341
+ label: "Closing Fees",
25342
+ category: "trade",
25343
+ unit: "$",
25344
+ description: "Commissions and fees paid when closing"
25345
+ },
25346
+ {
25347
+ field: "maxProfit",
25348
+ label: "Max Profit",
25349
+ category: "trade",
25350
+ unit: "%",
25351
+ description: "Maximum unrealized profit as % of premium during the trade"
25352
+ },
25353
+ {
25354
+ field: "maxLoss",
25355
+ label: "Max Loss",
25356
+ category: "trade",
25357
+ unit: "%",
25358
+ description: "Maximum unrealized loss as % of premium during the trade"
25359
+ },
25139
25360
  // Timing
25140
- { field: "tradeNumber", label: "Trade #", category: "timing", description: "Sequential trade number (1 = first trade)" },
25141
- { field: "dateOpenedTimestamp", label: "Date Opened", category: "timing", description: "When the trade was opened (useful for time-series charts)" },
25142
- { field: "durationHours", label: "Duration (hrs)", category: "timing", unit: "hrs", description: "How long the position was held", formula: "Close Time - Open Time" },
25143
- { field: "dayOfWeek", label: "Day of Week", category: "timing", description: "Day of week when opened: 0=Sunday through 6=Saturday" },
25144
- { field: "hourOfDay", label: "Hour of Day", category: "timing", description: "Hour of day when opened (0-23 in Eastern Time)" },
25145
- { field: "timeOfDayMinutes", label: "Time of Day", category: "timing", description: "Exact time when opened as minutes since midnight (e.g., 11:45 = 705). Useful for scatter plots to analyze floating-time or multiple-entry trades" },
25146
- { field: "dayOfMonth", label: "Day of Month", category: "timing", description: "Day of month when opened (1-31)" },
25147
- { field: "monthOfYear", label: "Month of Year", category: "timing", description: "Month when opened (1=January through 12=December)" },
25148
- { field: "weekOfYear", label: "Week of Year", category: "timing", description: "ISO week number when opened (1-52)" },
25361
+ {
25362
+ field: "tradeNumber",
25363
+ label: "Trade #",
25364
+ category: "timing",
25365
+ description: "Sequential trade number (1 = first trade)"
25366
+ },
25367
+ {
25368
+ field: "dateOpenedTimestamp",
25369
+ label: "Date Opened",
25370
+ category: "timing",
25371
+ description: "When the trade was opened (useful for time-series charts)"
25372
+ },
25373
+ {
25374
+ field: "durationHours",
25375
+ label: "Duration (hrs)",
25376
+ category: "timing",
25377
+ unit: "hrs",
25378
+ description: "How long the position was held",
25379
+ formula: "Close Time - Open Time"
25380
+ },
25381
+ {
25382
+ field: "dayOfWeek",
25383
+ label: "Day of Week",
25384
+ category: "timing",
25385
+ description: "Day of week when opened: 0=Sunday through 6=Saturday"
25386
+ },
25387
+ {
25388
+ field: "hourOfDay",
25389
+ label: "Hour of Day",
25390
+ category: "timing",
25391
+ description: "Hour of day when opened (0-23 in Eastern Time)"
25392
+ },
25393
+ {
25394
+ field: "timeOfDayMinutes",
25395
+ label: "Time of Day",
25396
+ category: "timing",
25397
+ description: "Exact time when opened as minutes since midnight (e.g., 11:45 = 705). Useful for scatter plots to analyze floating-time or multiple-entry trades"
25398
+ },
25399
+ {
25400
+ field: "dayOfMonth",
25401
+ label: "Day of Month",
25402
+ category: "timing",
25403
+ description: "Day of month when opened (1-31)"
25404
+ },
25405
+ {
25406
+ field: "monthOfYear",
25407
+ label: "Month of Year",
25408
+ category: "timing",
25409
+ description: "Month when opened (1=January through 12=December)"
25410
+ },
25411
+ {
25412
+ field: "weekOfYear",
25413
+ label: "Week of Year",
25414
+ category: "timing",
25415
+ description: "ISO week number when opened (1-52)"
25416
+ },
25149
25417
  // Portfolio context
25150
- { field: "exposureOnOpen", label: "Portfolio Exposure %", category: "risk", unit: "%", description: "Portfolio margin exposure as % of equity at the exact moment this trade opened - shows how much risk was deployed when entering" },
25151
- { field: "exposureOnOpenDollars", label: "Portfolio Exposure $", category: "risk", unit: "$", description: "Portfolio margin exposure in dollars at the exact moment this trade opened - shows total margin at risk when entering" }
25418
+ {
25419
+ field: "exposureOnOpen",
25420
+ label: "Portfolio Exposure %",
25421
+ category: "risk",
25422
+ unit: "%",
25423
+ description: "Portfolio margin exposure as % of equity at the exact moment this trade opened - shows how much risk was deployed when entering"
25424
+ },
25425
+ {
25426
+ field: "exposureOnOpenDollars",
25427
+ label: "Portfolio Exposure $",
25428
+ category: "risk",
25429
+ unit: "$",
25430
+ description: "Portfolio margin exposure in dollars at the exact moment this trade opened - shows total margin at risk when entering"
25431
+ }
25152
25432
  ];
25153
25433
 
25154
25434
  // ../lib/calculations/index.ts
@@ -25179,9 +25459,15 @@ var CalculationOrchestrator = class {
25179
25459
  };
25180
25460
  }
25181
25461
  const calculator = new PortfolioStatsCalculator(config4);
25182
- const portfolioStats = calculator.calculatePortfolioStats(trades, dailyLogs);
25462
+ const portfolioStats = calculator.calculatePortfolioStats(
25463
+ trades,
25464
+ dailyLogs
25465
+ );
25183
25466
  const strategyStats = calculator.calculateStrategyStats(trades);
25184
- const performanceMetrics = PerformanceCalculator.calculatePerformanceMetrics(trades, dailyLogs);
25467
+ const performanceMetrics = PerformanceCalculator.calculatePerformanceMetrics(
25468
+ trades,
25469
+ dailyLogs
25470
+ );
25185
25471
  this.cache.set(blockId, {
25186
25472
  portfolioStats,
25187
25473
  strategyStats,
@@ -25221,9 +25507,9 @@ var calculationOrchestrator = new CalculationOrchestrator();
25221
25507
  var REPORTING_TRADE_COLUMN_ALIASES = {
25222
25508
  "Initial Premium ($)": "Initial Premium",
25223
25509
  "Initial Credit": "Initial Premium",
25224
- "Contracts": "No. of Contracts",
25510
+ Contracts: "No. of Contracts",
25225
25511
  "Contracts Traded": "No. of Contracts",
25226
- "PL": "P/L"
25512
+ PL: "P/L"
25227
25513
  };
25228
25514
 
25229
25515
  // ../lib/processing/tat-adapter.ts
@@ -25409,4 +25695,4 @@ decimal.js/decimal.mjs:
25409
25695
  * MIT Licence
25410
25696
  *)
25411
25697
  */
25412
- //# sourceMappingURL=chunk-72GKJE2U.js.map
25698
+ //# sourceMappingURL=chunk-BOPHW5M6.js.map