backtest-kit 12.1.0 → 12.2.0
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 +12 -5
- package/build/index.mjs +12 -5
- package/package.json +1 -1
package/build/index.cjs
CHANGED
|
@@ -27679,9 +27679,12 @@ class HeatmapStorage {
|
|
|
27679
27679
|
}
|
|
27680
27680
|
// Per-trade Sharpe Ratio
|
|
27681
27681
|
let sharpeRatio = null;
|
|
27682
|
+
// canComputeRatios gate is explicit here (matching the standalone Backtest/Live
|
|
27683
|
+
// paths) even though stdDev is already null below MIN_SIGNALS_FOR_RATIOS — relying
|
|
27684
|
+
// on the stdDev===null implication would couple the gate to an unrelated branch.
|
|
27682
27685
|
// STDDEV_EPSILON guard — protects against float-artifact stdDev producing
|
|
27683
27686
|
// spuriously astronomical sharpe on identical-returns symbols.
|
|
27684
|
-
if (avgPnl !== null && stdDev !== null && stdDev > STDDEV_EPSILON) {
|
|
27687
|
+
if (canComputeRatios && avgPnl !== null && stdDev !== null && stdDev > STDDEV_EPSILON) {
|
|
27685
27688
|
sharpeRatio = avgPnl / stdDev;
|
|
27686
27689
|
}
|
|
27687
27690
|
// Equity-curve max drawdown via compounded equity ("as-if 100% allocation per trade").
|
|
@@ -27874,17 +27877,21 @@ class HeatmapStorage {
|
|
|
27874
27877
|
: sorted[mid];
|
|
27875
27878
|
}
|
|
27876
27879
|
// Expectancy — probabilities from observed win/loss counts (break-evens contribute 0).
|
|
27880
|
+
// Gated by MIN_SIGNALS_FOR_RATIOS (via canComputeRatios), same as the standalone
|
|
27881
|
+
// Backtest/Live paths and the portfolio-level pooled Expectancy below — on a tiny
|
|
27882
|
+
// sample the per-trade EV is too noisy to publish, and an ungated per-symbol value
|
|
27883
|
+
// would disagree with the symbol's own standalone report (which IS gated).
|
|
27877
27884
|
let expectancy = null;
|
|
27878
|
-
if (totalTrades > 0 && avgWin !== null && avgLoss !== null) {
|
|
27885
|
+
if (canComputeRatios && totalTrades > 0 && avgWin !== null && avgLoss !== null) {
|
|
27879
27886
|
const winProb = winCount / totalTrades;
|
|
27880
27887
|
const lossProb = lossCount / totalTrades;
|
|
27881
27888
|
expectancy = winProb * avgWin + lossProb * avgLoss;
|
|
27882
27889
|
}
|
|
27883
|
-
else if (totalTrades > 0 && avgWin !== null && avgLoss === null) {
|
|
27890
|
+
else if (canComputeRatios && totalTrades > 0 && avgWin !== null && avgLoss === null) {
|
|
27884
27891
|
// No losing trades — expectancy is just average win frequency × avgWin
|
|
27885
27892
|
expectancy = (winCount / totalTrades) * avgWin;
|
|
27886
27893
|
}
|
|
27887
|
-
else if (totalTrades > 0 && avgWin === null && avgLoss !== null) {
|
|
27894
|
+
else if (canComputeRatios && totalTrades > 0 && avgWin === null && avgLoss !== null) {
|
|
27888
27895
|
expectancy = (lossCount / totalTrades) * avgLoss;
|
|
27889
27896
|
}
|
|
27890
27897
|
// Average only over signals that have the value — do not dilute the mean with zeros.
|
|
@@ -28594,7 +28601,7 @@ class HeatmapStorage {
|
|
|
28594
28601
|
`*Sortino Ratio (column): per-symbol Avg PNL / downside deviation, where downside deviation = √( Σ min(0, per-trade PNL)² / total trade count ) (canonical Sortino: MAR = 0, divide by N_total). UNITS: dimensionless. Null when that symbol's trade count < ${MIN_SIGNALS_FOR_RATIOS}, OR no losing trades, OR downside deviation ≤ 1e-9 (float-artifact guard).*`,
|
|
28595
28602
|
`*Calmar Ratio (column): per-symbol Expected Yearly Returns / Max Drawdown, clamped to ±${MAX_CALMAR_RATIO}. Denominator is the mark-to-market max drawdown of that symbol's compounded equity curve. Null when Expected Yearly Returns is null (requires ≥ ${MIN_SIGNALS_FOR_ANNUALIZATION} signals and a calendar span ≥ ${MIN_CALENDAR_SPAN_DAYS} days for that symbol) OR Max Drawdown ≤ 0.*`,
|
|
28596
28603
|
`*Recovery Factor (column): per-symbol (final equity − 1) × 100 / Max Drawdown, clamped to ±${MAX_CALMAR_RATIO}. The numerator is the compounded total return of that symbol's equity curve. Null when that symbol's trade count < ${MIN_SIGNALS_FOR_RATIOS}, the equity curve blew up (reached ≤ 0), or Max Drawdown ≤ 0.*`,
|
|
28597
|
-
`*Expectancy (column): per-symbol expected value per trade. Three cases depending on what kinds of trades exist for that symbol: (a) BOTH winning and losing trades present → (winning-trade count / Total Trades) × Avg Win + (losing-trade count / Total Trades) × Avg Loss; (b) only winning trades present → (winning-trade count / Total Trades) × Avg Win (zero contribution from non-existent losses); (c) only losing trades present → (losing-trade count / Total Trades) × Avg Loss. Break-even trades contribute 0 (excluded from both probabilities). UNITS: percent per trade.
|
|
28604
|
+
`*Expectancy (column): per-symbol expected value per trade. Three cases depending on what kinds of trades exist for that symbol: (a) BOTH winning and losing trades present → (winning-trade count / Total Trades) × Avg Win + (losing-trade count / Total Trades) × Avg Loss; (b) only winning trades present → (winning-trade count / Total Trades) × Avg Win (zero contribution from non-existent losses); (c) only losing trades present → (losing-trade count / Total Trades) × Avg Loss. Break-even trades contribute 0 (excluded from both probabilities). UNITS: percent per trade. Null when that symbol's trade count < ${MIN_SIGNALS_FOR_RATIOS} — the same sample-size gate as the standalone Backtest/Live report and the portfolio-level pooled Expectancy further up, so the per-symbol value never disagrees with the symbol's own standalone report.*`,
|
|
28598
28605
|
`*Max Drawdown (column): per-symbol mark-to-market max drawdown — the symbol's compounded equity curve applies each closed signal's worst intra-trade excursion (its trough-PNL snapshot, ≤ 0) before booking the realised close, so deep round-trip dips count rather than only realised close-to-close drops. UNITS: percent. NOT realised-only.*`,
|
|
28599
28606
|
`*Avg Peak PNL / Avg Max Drawdown PNL (columns): per-symbol arithmetic means of each closed signal's peak-PNL / trough-PNL snapshot — the best / worst mark-to-market PNL recorded while the position was open. Signals that never recorded the snapshot are excluded — no zero dilution. UNITS: percent. NOT gated by MIN_SIGNALS — each is null only if no signal for that symbol carries the corresponding snapshot.*`,
|
|
28600
28607
|
`*Peak Profit PNL / Max Drawdown PNL (columns): per-symbol MAX of the peak-PNL snapshot / MIN of the trough-PNL snapshot across the symbol's stored closed signals. UNITS: percent. The single best best-case and worst worst-case excursions for that symbol — tail behaviour the averages hide. NOT gated by MIN_SIGNALS — each is null only if no signal for that symbol carries the corresponding snapshot.*`,
|
package/build/index.mjs
CHANGED
|
@@ -27659,9 +27659,12 @@ class HeatmapStorage {
|
|
|
27659
27659
|
}
|
|
27660
27660
|
// Per-trade Sharpe Ratio
|
|
27661
27661
|
let sharpeRatio = null;
|
|
27662
|
+
// canComputeRatios gate is explicit here (matching the standalone Backtest/Live
|
|
27663
|
+
// paths) even though stdDev is already null below MIN_SIGNALS_FOR_RATIOS — relying
|
|
27664
|
+
// on the stdDev===null implication would couple the gate to an unrelated branch.
|
|
27662
27665
|
// STDDEV_EPSILON guard — protects against float-artifact stdDev producing
|
|
27663
27666
|
// spuriously astronomical sharpe on identical-returns symbols.
|
|
27664
|
-
if (avgPnl !== null && stdDev !== null && stdDev > STDDEV_EPSILON) {
|
|
27667
|
+
if (canComputeRatios && avgPnl !== null && stdDev !== null && stdDev > STDDEV_EPSILON) {
|
|
27665
27668
|
sharpeRatio = avgPnl / stdDev;
|
|
27666
27669
|
}
|
|
27667
27670
|
// Equity-curve max drawdown via compounded equity ("as-if 100% allocation per trade").
|
|
@@ -27854,17 +27857,21 @@ class HeatmapStorage {
|
|
|
27854
27857
|
: sorted[mid];
|
|
27855
27858
|
}
|
|
27856
27859
|
// Expectancy — probabilities from observed win/loss counts (break-evens contribute 0).
|
|
27860
|
+
// Gated by MIN_SIGNALS_FOR_RATIOS (via canComputeRatios), same as the standalone
|
|
27861
|
+
// Backtest/Live paths and the portfolio-level pooled Expectancy below — on a tiny
|
|
27862
|
+
// sample the per-trade EV is too noisy to publish, and an ungated per-symbol value
|
|
27863
|
+
// would disagree with the symbol's own standalone report (which IS gated).
|
|
27857
27864
|
let expectancy = null;
|
|
27858
|
-
if (totalTrades > 0 && avgWin !== null && avgLoss !== null) {
|
|
27865
|
+
if (canComputeRatios && totalTrades > 0 && avgWin !== null && avgLoss !== null) {
|
|
27859
27866
|
const winProb = winCount / totalTrades;
|
|
27860
27867
|
const lossProb = lossCount / totalTrades;
|
|
27861
27868
|
expectancy = winProb * avgWin + lossProb * avgLoss;
|
|
27862
27869
|
}
|
|
27863
|
-
else if (totalTrades > 0 && avgWin !== null && avgLoss === null) {
|
|
27870
|
+
else if (canComputeRatios && totalTrades > 0 && avgWin !== null && avgLoss === null) {
|
|
27864
27871
|
// No losing trades — expectancy is just average win frequency × avgWin
|
|
27865
27872
|
expectancy = (winCount / totalTrades) * avgWin;
|
|
27866
27873
|
}
|
|
27867
|
-
else if (totalTrades > 0 && avgWin === null && avgLoss !== null) {
|
|
27874
|
+
else if (canComputeRatios && totalTrades > 0 && avgWin === null && avgLoss !== null) {
|
|
27868
27875
|
expectancy = (lossCount / totalTrades) * avgLoss;
|
|
27869
27876
|
}
|
|
27870
27877
|
// Average only over signals that have the value — do not dilute the mean with zeros.
|
|
@@ -28574,7 +28581,7 @@ class HeatmapStorage {
|
|
|
28574
28581
|
`*Sortino Ratio (column): per-symbol Avg PNL / downside deviation, where downside deviation = √( Σ min(0, per-trade PNL)² / total trade count ) (canonical Sortino: MAR = 0, divide by N_total). UNITS: dimensionless. Null when that symbol's trade count < ${MIN_SIGNALS_FOR_RATIOS}, OR no losing trades, OR downside deviation ≤ 1e-9 (float-artifact guard).*`,
|
|
28575
28582
|
`*Calmar Ratio (column): per-symbol Expected Yearly Returns / Max Drawdown, clamped to ±${MAX_CALMAR_RATIO}. Denominator is the mark-to-market max drawdown of that symbol's compounded equity curve. Null when Expected Yearly Returns is null (requires ≥ ${MIN_SIGNALS_FOR_ANNUALIZATION} signals and a calendar span ≥ ${MIN_CALENDAR_SPAN_DAYS} days for that symbol) OR Max Drawdown ≤ 0.*`,
|
|
28576
28583
|
`*Recovery Factor (column): per-symbol (final equity − 1) × 100 / Max Drawdown, clamped to ±${MAX_CALMAR_RATIO}. The numerator is the compounded total return of that symbol's equity curve. Null when that symbol's trade count < ${MIN_SIGNALS_FOR_RATIOS}, the equity curve blew up (reached ≤ 0), or Max Drawdown ≤ 0.*`,
|
|
28577
|
-
`*Expectancy (column): per-symbol expected value per trade. Three cases depending on what kinds of trades exist for that symbol: (a) BOTH winning and losing trades present → (winning-trade count / Total Trades) × Avg Win + (losing-trade count / Total Trades) × Avg Loss; (b) only winning trades present → (winning-trade count / Total Trades) × Avg Win (zero contribution from non-existent losses); (c) only losing trades present → (losing-trade count / Total Trades) × Avg Loss. Break-even trades contribute 0 (excluded from both probabilities). UNITS: percent per trade.
|
|
28584
|
+
`*Expectancy (column): per-symbol expected value per trade. Three cases depending on what kinds of trades exist for that symbol: (a) BOTH winning and losing trades present → (winning-trade count / Total Trades) × Avg Win + (losing-trade count / Total Trades) × Avg Loss; (b) only winning trades present → (winning-trade count / Total Trades) × Avg Win (zero contribution from non-existent losses); (c) only losing trades present → (losing-trade count / Total Trades) × Avg Loss. Break-even trades contribute 0 (excluded from both probabilities). UNITS: percent per trade. Null when that symbol's trade count < ${MIN_SIGNALS_FOR_RATIOS} — the same sample-size gate as the standalone Backtest/Live report and the portfolio-level pooled Expectancy further up, so the per-symbol value never disagrees with the symbol's own standalone report.*`,
|
|
28578
28585
|
`*Max Drawdown (column): per-symbol mark-to-market max drawdown — the symbol's compounded equity curve applies each closed signal's worst intra-trade excursion (its trough-PNL snapshot, ≤ 0) before booking the realised close, so deep round-trip dips count rather than only realised close-to-close drops. UNITS: percent. NOT realised-only.*`,
|
|
28579
28586
|
`*Avg Peak PNL / Avg Max Drawdown PNL (columns): per-symbol arithmetic means of each closed signal's peak-PNL / trough-PNL snapshot — the best / worst mark-to-market PNL recorded while the position was open. Signals that never recorded the snapshot are excluded — no zero dilution. UNITS: percent. NOT gated by MIN_SIGNALS — each is null only if no signal for that symbol carries the corresponding snapshot.*`,
|
|
28580
28587
|
`*Peak Profit PNL / Max Drawdown PNL (columns): per-symbol MAX of the peak-PNL snapshot / MIN of the trough-PNL snapshot across the symbol's stored closed signals. UNITS: percent. The single best best-case and worst worst-case excursions for that symbol — tail behaviour the averages hide. NOT gated by MIN_SIGNALS — each is null only if no signal for that symbol carries the corresponding snapshot.*`,
|