backtest-kit 1.1.7 โ 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -1
- package/build/index.cjs +519 -5
- package/build/index.mjs +518 -6
- package/package.json +2 -2
- package/types.d.ts +339 -1
package/README.md
CHANGED
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
- โก **Memory Optimized** - Prototype methods + memoization + streaming
|
|
20
20
|
- ๐ **Flexible Architecture** - Plug your own exchanges and strategies
|
|
21
21
|
- ๐ **Markdown Reports** - Auto-generated trading reports with statistics (win rate, avg PNL, Sharpe Ratio, Standard Deviation, Certainty Ratio, Expected Yearly Returns, Risk-Adjusted Returns)
|
|
22
|
+
- ๐ **Performance Profiling** - Built-in performance tracking with aggregated statistics (avg, min, max, stdDev, P95, P99) for bottleneck analysis
|
|
22
23
|
- ๐ **Graceful Shutdown** - Live.background() waits for open positions to close before stopping
|
|
23
24
|
- ๐ **Strategy Dependency Injection** - addStrategy() enables DI pattern for trading strategies
|
|
24
25
|
- ๐ **Schema Reflection API** - listExchanges(), listStrategies(), listFrames() for runtime introspection
|
|
25
|
-
- ๐งช **Comprehensive Test Coverage** -
|
|
26
|
+
- ๐งช **Comprehensive Test Coverage** - 61 unit tests covering validation, PNL, callbacks, reports, performance tracking, and event system
|
|
26
27
|
- ๐พ **Zero Data Download** - Unlike Freqtrade, no need to download gigabytes of historical data - plug any data source (CCXT, database, API)
|
|
27
28
|
- ๐ **Safe Math & Robustness** - All metrics protected against NaN/Infinity with unsafe numeric checks, returns N/A for invalid calculations
|
|
28
29
|
|
|
@@ -710,6 +711,8 @@ Live.background("BTCUSDT", {
|
|
|
710
711
|
- `listenSignalBacktestOnce(filter, callback)` - Subscribe to backtest signals once
|
|
711
712
|
- `listenSignalLive(callback)` - Subscribe to live signals only
|
|
712
713
|
- `listenSignalLiveOnce(filter, callback)` - Subscribe to live signals once
|
|
714
|
+
- `listenPerformance(callback)` - Subscribe to performance metrics (backtest + live)
|
|
715
|
+
- `listenProgress(callback)` - Subscribe to backtest progress events
|
|
713
716
|
- `listenError(callback)` - Subscribe to background execution errors
|
|
714
717
|
- `listenDone(callback)` - Subscribe to background completion events
|
|
715
718
|
- `listenDoneOnce(filter, callback)` - Subscribe to background completion once
|
|
@@ -873,6 +876,31 @@ Live.getReport(strategyName: string): Promise<string>
|
|
|
873
876
|
Live.dump(strategyName: string, path?: string): Promise<void>
|
|
874
877
|
```
|
|
875
878
|
|
|
879
|
+
#### Performance Profiling API
|
|
880
|
+
|
|
881
|
+
```typescript
|
|
882
|
+
import { Performance, PerformanceStatistics, listenPerformance } from "backtest-kit";
|
|
883
|
+
|
|
884
|
+
// Get raw performance statistics (Controller)
|
|
885
|
+
Performance.getData(strategyName: string): Promise<PerformanceStatistics>
|
|
886
|
+
|
|
887
|
+
// Generate markdown report with bottleneck analysis (View)
|
|
888
|
+
Performance.getReport(strategyName: string): Promise<string>
|
|
889
|
+
|
|
890
|
+
// Save performance report to disk (default: ./logs/performance)
|
|
891
|
+
Performance.dump(strategyName: string, path?: string): Promise<void>
|
|
892
|
+
|
|
893
|
+
// Clear accumulated performance data
|
|
894
|
+
Performance.clear(strategyName?: string): Promise<void>
|
|
895
|
+
|
|
896
|
+
// Listen to real-time performance events
|
|
897
|
+
listenPerformance((event) => {
|
|
898
|
+
console.log(`${event.metricType}: ${event.duration.toFixed(2)}ms`);
|
|
899
|
+
console.log(`Strategy: ${event.strategyName} @ ${event.exchangeName}`);
|
|
900
|
+
console.log(`Symbol: ${event.symbol}, Backtest: ${event.backtest}`);
|
|
901
|
+
});
|
|
902
|
+
```
|
|
903
|
+
|
|
876
904
|
## Type Definitions
|
|
877
905
|
|
|
878
906
|
### Statistics Types
|
|
@@ -910,6 +938,44 @@ interface LiveStatistics {
|
|
|
910
938
|
certaintyRatio: number | null; // avgWin / |avgLoss| (higher is better)
|
|
911
939
|
expectedYearlyReturns: number | null; // Estimated yearly trades (higher is better)
|
|
912
940
|
}
|
|
941
|
+
|
|
942
|
+
// Performance statistics (exported from "backtest-kit")
|
|
943
|
+
interface PerformanceStatistics {
|
|
944
|
+
strategyName: string; // Strategy name
|
|
945
|
+
totalEvents: number; // Total number of performance events
|
|
946
|
+
totalDuration: number; // Total execution time (ms)
|
|
947
|
+
metricStats: Record<string, { // Statistics by metric type
|
|
948
|
+
metricType: PerformanceMetricType; // backtest_total | backtest_timeframe | backtest_signal | live_tick
|
|
949
|
+
count: number; // Number of samples
|
|
950
|
+
totalDuration: number; // Total duration (ms)
|
|
951
|
+
avgDuration: number; // Average duration (ms)
|
|
952
|
+
minDuration: number; // Minimum duration (ms)
|
|
953
|
+
maxDuration: number; // Maximum duration (ms)
|
|
954
|
+
stdDev: number; // Standard deviation (ms)
|
|
955
|
+
median: number; // Median duration (ms)
|
|
956
|
+
p95: number; // 95th percentile (ms)
|
|
957
|
+
p99: number; // 99th percentile (ms)
|
|
958
|
+
}>;
|
|
959
|
+
events: PerformanceContract[]; // All raw performance events
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// Performance event (exported from "backtest-kit")
|
|
963
|
+
interface PerformanceContract {
|
|
964
|
+
timestamp: number; // When metric was recorded (epoch ms)
|
|
965
|
+
metricType: PerformanceMetricType; // Type of operation measured
|
|
966
|
+
duration: number; // Operation duration (ms)
|
|
967
|
+
strategyName: string; // Strategy name
|
|
968
|
+
exchangeName: string; // Exchange name
|
|
969
|
+
symbol: string; // Trading symbol
|
|
970
|
+
backtest: boolean; // true = backtest, false = live
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// Performance metric types (exported from "backtest-kit")
|
|
974
|
+
type PerformanceMetricType =
|
|
975
|
+
| "backtest_total" // Total backtest duration
|
|
976
|
+
| "backtest_timeframe" // Single timeframe processing
|
|
977
|
+
| "backtest_signal" // Signal processing (tick + getNextCandles + backtest)
|
|
978
|
+
| "live_tick"; // Single live tick duration
|
|
913
979
|
```
|
|
914
980
|
|
|
915
981
|
### Signal Data
|
|
@@ -1046,6 +1112,72 @@ Backtest.background("BTCUSDT", {
|
|
|
1046
1112
|
});
|
|
1047
1113
|
```
|
|
1048
1114
|
|
|
1115
|
+
### Performance Profiling
|
|
1116
|
+
|
|
1117
|
+
```typescript
|
|
1118
|
+
import { Performance, listenPerformance, Backtest } from "backtest-kit";
|
|
1119
|
+
|
|
1120
|
+
// Listen to real-time performance metrics
|
|
1121
|
+
listenPerformance((event) => {
|
|
1122
|
+
console.log(`[${event.metricType}] ${event.duration.toFixed(2)}ms`);
|
|
1123
|
+
console.log(` Strategy: ${event.strategyName}`);
|
|
1124
|
+
console.log(` Symbol: ${event.symbol}, Backtest: ${event.backtest}`);
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
// Run backtest
|
|
1128
|
+
await Backtest.background("BTCUSDT", {
|
|
1129
|
+
strategyName: "my-strategy",
|
|
1130
|
+
exchangeName: "binance",
|
|
1131
|
+
frameName: "1d-backtest"
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
// Get aggregated performance statistics
|
|
1135
|
+
const perfStats = await Performance.getData("my-strategy");
|
|
1136
|
+
console.log("Performance Statistics:");
|
|
1137
|
+
console.log(` Total events: ${perfStats.totalEvents}`);
|
|
1138
|
+
console.log(` Total duration: ${perfStats.totalDuration.toFixed(2)}ms`);
|
|
1139
|
+
console.log(` Metrics tracked: ${Object.keys(perfStats.metricStats).join(", ")}`);
|
|
1140
|
+
|
|
1141
|
+
// Analyze bottlenecks
|
|
1142
|
+
for (const [type, stats] of Object.entries(perfStats.metricStats)) {
|
|
1143
|
+
console.log(`\n${type}:`);
|
|
1144
|
+
console.log(` Count: ${stats.count}`);
|
|
1145
|
+
console.log(` Average: ${stats.avgDuration.toFixed(2)}ms`);
|
|
1146
|
+
console.log(` Min/Max: ${stats.minDuration.toFixed(2)}ms / ${stats.maxDuration.toFixed(2)}ms`);
|
|
1147
|
+
console.log(` P95/P99: ${stats.p95.toFixed(2)}ms / ${stats.p99.toFixed(2)}ms`);
|
|
1148
|
+
console.log(` Std Dev: ${stats.stdDev.toFixed(2)}ms`);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// Generate and save performance report
|
|
1152
|
+
const markdown = await Performance.getReport("my-strategy");
|
|
1153
|
+
await Performance.dump("my-strategy"); // Saves to ./logs/performance/my-strategy.md
|
|
1154
|
+
```
|
|
1155
|
+
|
|
1156
|
+
**Performance Report Example:**
|
|
1157
|
+
```markdown
|
|
1158
|
+
# Performance Report: my-strategy
|
|
1159
|
+
|
|
1160
|
+
**Total events:** 1440
|
|
1161
|
+
**Total execution time:** 12345.67ms
|
|
1162
|
+
**Number of metric types:** 3
|
|
1163
|
+
|
|
1164
|
+
## Time Distribution
|
|
1165
|
+
|
|
1166
|
+
- **backtest_timeframe**: 65.4% (8074.32ms total)
|
|
1167
|
+
- **backtest_signal**: 28.3% (3493.85ms total)
|
|
1168
|
+
- **backtest_total**: 6.3% (777.50ms total)
|
|
1169
|
+
|
|
1170
|
+
## Detailed Metrics
|
|
1171
|
+
|
|
1172
|
+
| Metric Type | Count | Total (ms) | Avg (ms) | Min (ms) | Max (ms) | Std Dev (ms) | Median (ms) | P95 (ms) | P99 (ms) |
|
|
1173
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
1174
|
+
| backtest_timeframe | 1440 | 8074.32 | 5.61 | 2.10 | 12.45 | 1.85 | 5.20 | 8.90 | 10.50 |
|
|
1175
|
+
| backtest_signal | 45 | 3493.85 | 77.64 | 45.20 | 125.80 | 18.32 | 75.10 | 110.20 | 120.15 |
|
|
1176
|
+
| backtest_total | 1 | 777.50 | 777.50 | 777.50 | 777.50 | 0.00 | 777.50 | 777.50 | 777.50 |
|
|
1177
|
+
|
|
1178
|
+
**Note:** All durations are in milliseconds. P95/P99 represent 95th and 99th percentile response times.
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1049
1181
|
### Early Termination
|
|
1050
1182
|
|
|
1051
1183
|
**Using async generator with break:**
|