backtest-kit 8.1.0 → 8.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.cjs CHANGED
@@ -21926,10 +21926,10 @@ let ReportStorage$a = class ReportStorage {
21926
21926
  const fallVariance = fallReturns.reduce((sum, r) => sum + Math.pow(r, 2), 0) / totalSignals;
21927
21927
  const fallDeviation = Math.sqrt(fallVariance);
21928
21928
  const sortinoRatio = fallDeviation > 0 ? avgPnl / fallDeviation : 0;
21929
- // Avg absolute peak drawdown per signal — used as denominator for Calmar and Recovery
21930
- const avgAbsFall = fallReturns.reduce((sum, r) => sum + Math.abs(r), 0) / totalSignals;
21931
- const calmarRatio = avgAbsFall > 0 ? expectedYearlyReturns / avgAbsFall : 0;
21932
- const recoveryFactor = avgAbsFall > 0 ? totalPnl / avgAbsFall : 0;
21929
+ // Max absolute drawdown across all signals — used as denominator for Calmar and Recovery
21930
+ const maxAbsFall = fallReturns.reduce((max, r) => Math.max(max, Math.abs(r)), 0);
21931
+ const calmarRatio = maxAbsFall > 0 ? expectedYearlyReturns / maxAbsFall : 0;
21932
+ const recoveryFactor = maxAbsFall > 0 ? totalPnl / maxAbsFall : 0;
21933
21933
  return {
21934
21934
  signalList: this._signalList,
21935
21935
  totalSignals,
@@ -22658,12 +22658,10 @@ let ReportStorage$9 = class ReportStorage {
22658
22658
  const fallDeviation = Math.sqrt(fallVariance);
22659
22659
  sortinoRatio = fallDeviation > 0 ? avgPnl / fallDeviation : 0;
22660
22660
  }
22661
- // Avg absolute peak drawdown per signal — denominator for Calmar and Recovery
22662
- const avgAbsFall = totalClosed > 0
22663
- ? fallReturns.reduce((sum, r) => sum + Math.abs(r), 0) / totalClosed
22664
- : 0;
22665
- const calmarRatio = avgAbsFall > 0 ? expectedYearlyReturns / avgAbsFall : 0;
22666
- const recoveryFactor = avgAbsFall > 0 ? totalPnl / avgAbsFall : 0;
22661
+ // Max absolute drawdown across all signals — denominator for Calmar and Recovery
22662
+ const maxAbsFall = fallReturns.reduce((max, r) => Math.max(max, Math.abs(r)), 0);
22663
+ const calmarRatio = maxAbsFall > 0 ? expectedYearlyReturns / maxAbsFall : 0;
22664
+ const recoveryFactor = maxAbsFall > 0 ? totalPnl / maxAbsFall : 0;
22667
22665
  return {
22668
22666
  eventList: this._eventList,
22669
22667
  totalEvents: this._eventList.length,
@@ -24657,15 +24655,21 @@ class HeatmapStorage {
24657
24655
  sortinoRatio = avgPnl / fallDeviation;
24658
24656
  }
24659
24657
  }
24660
- // Avg absolute peak drawdown per signal — denominator for Calmar and Recovery
24661
- const avgAbsFall = signals.length > 0
24662
- ? fallReturns.reduce((acc, r) => acc + Math.abs(r), 0) / signals.length
24663
- : 0;
24658
+ // Max absolute drawdown across all signals — denominator for Calmar and Recovery
24659
+ const maxAbsFall = fallReturns.reduce((max, r) => Math.max(max, Math.abs(r)), 0);
24660
+ // Expected yearly returns needed for Calmar
24661
+ let expectedYearlyReturns = 0;
24662
+ if (signals.length > 0 && avgPnl !== null) {
24663
+ const avgDurationMs = signals.reduce((sum, s) => sum + (s.closeTimestamp - s.signal.pendingAt), 0) / signals.length;
24664
+ const avgDurationDays = avgDurationMs / (1000 * 60 * 60 * 24);
24665
+ const tradesPerYear = avgDurationDays > 0 ? 365 / avgDurationDays : 0;
24666
+ expectedYearlyReturns = avgPnl * tradesPerYear;
24667
+ }
24664
24668
  let calmarRatio = null;
24665
24669
  let recoveryFactor = null;
24666
- if (avgAbsFall > 0 && totalPnl !== null) {
24667
- calmarRatio = totalPnl / avgAbsFall;
24668
- recoveryFactor = totalPnl / avgAbsFall;
24670
+ if (maxAbsFall > 0 && totalPnl !== null) {
24671
+ calmarRatio = expectedYearlyReturns / maxAbsFall;
24672
+ recoveryFactor = totalPnl / maxAbsFall;
24669
24673
  }
24670
24674
  // Apply safe math checks
24671
24675
  if (isUnsafe(winRate))
package/build/index.mjs CHANGED
@@ -21906,10 +21906,10 @@ let ReportStorage$a = class ReportStorage {
21906
21906
  const fallVariance = fallReturns.reduce((sum, r) => sum + Math.pow(r, 2), 0) / totalSignals;
21907
21907
  const fallDeviation = Math.sqrt(fallVariance);
21908
21908
  const sortinoRatio = fallDeviation > 0 ? avgPnl / fallDeviation : 0;
21909
- // Avg absolute peak drawdown per signal — used as denominator for Calmar and Recovery
21910
- const avgAbsFall = fallReturns.reduce((sum, r) => sum + Math.abs(r), 0) / totalSignals;
21911
- const calmarRatio = avgAbsFall > 0 ? expectedYearlyReturns / avgAbsFall : 0;
21912
- const recoveryFactor = avgAbsFall > 0 ? totalPnl / avgAbsFall : 0;
21909
+ // Max absolute drawdown across all signals — used as denominator for Calmar and Recovery
21910
+ const maxAbsFall = fallReturns.reduce((max, r) => Math.max(max, Math.abs(r)), 0);
21911
+ const calmarRatio = maxAbsFall > 0 ? expectedYearlyReturns / maxAbsFall : 0;
21912
+ const recoveryFactor = maxAbsFall > 0 ? totalPnl / maxAbsFall : 0;
21913
21913
  return {
21914
21914
  signalList: this._signalList,
21915
21915
  totalSignals,
@@ -22638,12 +22638,10 @@ let ReportStorage$9 = class ReportStorage {
22638
22638
  const fallDeviation = Math.sqrt(fallVariance);
22639
22639
  sortinoRatio = fallDeviation > 0 ? avgPnl / fallDeviation : 0;
22640
22640
  }
22641
- // Avg absolute peak drawdown per signal — denominator for Calmar and Recovery
22642
- const avgAbsFall = totalClosed > 0
22643
- ? fallReturns.reduce((sum, r) => sum + Math.abs(r), 0) / totalClosed
22644
- : 0;
22645
- const calmarRatio = avgAbsFall > 0 ? expectedYearlyReturns / avgAbsFall : 0;
22646
- const recoveryFactor = avgAbsFall > 0 ? totalPnl / avgAbsFall : 0;
22641
+ // Max absolute drawdown across all signals — denominator for Calmar and Recovery
22642
+ const maxAbsFall = fallReturns.reduce((max, r) => Math.max(max, Math.abs(r)), 0);
22643
+ const calmarRatio = maxAbsFall > 0 ? expectedYearlyReturns / maxAbsFall : 0;
22644
+ const recoveryFactor = maxAbsFall > 0 ? totalPnl / maxAbsFall : 0;
22647
22645
  return {
22648
22646
  eventList: this._eventList,
22649
22647
  totalEvents: this._eventList.length,
@@ -24637,15 +24635,21 @@ class HeatmapStorage {
24637
24635
  sortinoRatio = avgPnl / fallDeviation;
24638
24636
  }
24639
24637
  }
24640
- // Avg absolute peak drawdown per signal — denominator for Calmar and Recovery
24641
- const avgAbsFall = signals.length > 0
24642
- ? fallReturns.reduce((acc, r) => acc + Math.abs(r), 0) / signals.length
24643
- : 0;
24638
+ // Max absolute drawdown across all signals — denominator for Calmar and Recovery
24639
+ const maxAbsFall = fallReturns.reduce((max, r) => Math.max(max, Math.abs(r)), 0);
24640
+ // Expected yearly returns needed for Calmar
24641
+ let expectedYearlyReturns = 0;
24642
+ if (signals.length > 0 && avgPnl !== null) {
24643
+ const avgDurationMs = signals.reduce((sum, s) => sum + (s.closeTimestamp - s.signal.pendingAt), 0) / signals.length;
24644
+ const avgDurationDays = avgDurationMs / (1000 * 60 * 60 * 24);
24645
+ const tradesPerYear = avgDurationDays > 0 ? 365 / avgDurationDays : 0;
24646
+ expectedYearlyReturns = avgPnl * tradesPerYear;
24647
+ }
24644
24648
  let calmarRatio = null;
24645
24649
  let recoveryFactor = null;
24646
- if (avgAbsFall > 0 && totalPnl !== null) {
24647
- calmarRatio = totalPnl / avgAbsFall;
24648
- recoveryFactor = totalPnl / avgAbsFall;
24650
+ if (maxAbsFall > 0 && totalPnl !== null) {
24651
+ calmarRatio = expectedYearlyReturns / maxAbsFall;
24652
+ recoveryFactor = totalPnl / maxAbsFall;
24649
24653
  }
24650
24654
  // Apply safe math checks
24651
24655
  if (isUnsafe(winRate))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "8.1.0",
3
+ "version": "8.1.2",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",