backtest-kit 1.1.9 β 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +396 -34
- package/build/index.cjs +1906 -450
- package/build/index.mjs +1905 -451
- package/package.json +1 -1
- package/types.d.ts +530 -28
package/README.md
CHANGED
|
@@ -10,13 +10,9 @@ Build sophisticated trading systems with confidence. Backtest Kit empowers you t
|
|
|
10
10
|
|
|
11
11
|
π **[API Reference](https://github.com/tripolskypetr/backtest-kit)** | π **[Quick Start](#quick-start)**
|
|
12
12
|
|
|
13
|
-
## π― Supported Order Types
|
|
14
|
-
|
|
15
|
-
Backtest Kit supports multiple execution styles to match real trading behavior:
|
|
16
|
-
|
|
17
13
|
## β¨ Why Choose Backtest Kit?
|
|
18
14
|
|
|
19
|
-
- π **Production-Ready Architecture**: Seamlessly switch between backtest and live modes with robust error recovery and graceful shutdown mechanisms. Your strategy code remains identical across environments.
|
|
15
|
+
- π **Production-Ready Architecture**: Seamlessly switch between backtest and live modes with robust error recovery and graceful shutdown mechanisms. Your strategy code remains identical across environments.
|
|
20
16
|
|
|
21
17
|
- πΎ **Crash-Safe Persistence**: Atomic file writes with automatic state recovery ensure no duplicate signals or lost dataβeven after crashes. Resume execution exactly where you left off. π
|
|
22
18
|
|
|
@@ -26,7 +22,7 @@ Backtest Kit supports multiple execution styles to match real trading behavior:
|
|
|
26
22
|
|
|
27
23
|
- π **VWAP Pricing**: Volume-weighted average price from last 5 1-minute candles ensures realistic backtest results that match live execution. π
|
|
28
24
|
|
|
29
|
-
- π― **Type-Safe Signal Lifecycle**: State machine with compile-time guarantees (idle β opened β active β closed). No runtime state confusion. π
|
|
25
|
+
- π― **Type-Safe Signal Lifecycle**: State machine with compile-time guarantees (idle β scheduled β opened β active β closed/cancelled). No runtime state confusion. π
|
|
30
26
|
|
|
31
27
|
- π **Accurate PNL Calculation**: Realistic profit/loss with configurable fees (0.1%) and slippage (0.1%). Track gross and net returns separately. π°
|
|
32
28
|
|
|
@@ -50,26 +46,28 @@ Backtest Kit supports multiple execution styles to match real trading behavior:
|
|
|
50
46
|
|
|
51
47
|
- π **Safe Math & Robustness**: All metrics protected against NaN/Infinity with unsafe numeric checks. Returns N/A for invalid calculations. β¨
|
|
52
48
|
|
|
53
|
-
- π§ͺ **Comprehensive Test Coverage**:
|
|
49
|
+
- π§ͺ **Comprehensive Test Coverage**: 123 unit and integration tests covering validation, PNL, callbacks, reports, performance tracking, walker, heatmap, position sizing, risk management, scheduled signals, and event system.
|
|
54
50
|
|
|
55
51
|
---
|
|
56
52
|
|
|
57
|
-
###
|
|
53
|
+
### π³ Supported Order Types
|
|
54
|
+
|
|
55
|
+
Backtest Kit supports multiple execution styles to match real trading behavior:
|
|
58
56
|
|
|
59
57
|
- **Market** β instant execution using current VWAP
|
|
60
|
-
|
|
58
|
+
|
|
61
59
|
- **Limit** β entry at a specified `priceOpen`
|
|
62
|
-
|
|
60
|
+
|
|
63
61
|
- **Take Profit (TP)** β automatic exit at the target price
|
|
64
|
-
|
|
62
|
+
|
|
65
63
|
- **Stop Loss (SL)** β protective exit at the stop level
|
|
66
|
-
|
|
64
|
+
|
|
67
65
|
- **OCO (TP + SL)** β linked exits; one cancels the other
|
|
68
|
-
|
|
69
|
-
- **
|
|
66
|
+
|
|
67
|
+
- **Grid** β auto-cancel if price never reaches entry point or hits SL before activation
|
|
70
68
|
|
|
71
69
|
|
|
72
|
-
###
|
|
70
|
+
### π Extendable Order Types
|
|
73
71
|
|
|
74
72
|
Easy to add without modifying the core:
|
|
75
73
|
|
|
@@ -128,23 +126,32 @@ addStrategy({
|
|
|
128
126
|
strategyName: "sma-crossover",
|
|
129
127
|
interval: "5m", // Throttling: signals generated max once per 5 minutes
|
|
130
128
|
getSignal: async (symbol) => {
|
|
131
|
-
|
|
129
|
+
const price = await getAveragePrice(symbol);
|
|
132
130
|
return {
|
|
133
131
|
position: "long",
|
|
134
132
|
note: "BTC breakout",
|
|
135
|
-
priceOpen:
|
|
136
|
-
priceTakeProfit:
|
|
137
|
-
priceStopLoss:
|
|
138
|
-
minuteEstimatedTime: 60,
|
|
133
|
+
priceOpen: price,
|
|
134
|
+
priceTakeProfit: price + 1_000, // Must be > priceOpen for long
|
|
135
|
+
priceStopLoss: price - 1_000, // Must be < priceOpen for long
|
|
136
|
+
minuteEstimatedTime: 60,
|
|
139
137
|
};
|
|
140
138
|
},
|
|
141
139
|
callbacks: {
|
|
140
|
+
onSchedule: (symbol, signal, currentPrice, backtest) => {
|
|
141
|
+
console.log(`[${backtest ? "BT" : "LIVE"}] Scheduled signal created:`, signal.id);
|
|
142
|
+
},
|
|
142
143
|
onOpen: (symbol, signal, currentPrice, backtest) => {
|
|
143
144
|
console.log(`[${backtest ? "BT" : "LIVE"}] Signal opened:`, signal.id);
|
|
144
145
|
},
|
|
146
|
+
onActive: (symbol, signal, currentPrice, backtest) => {
|
|
147
|
+
console.log(`[${backtest ? "BT" : "LIVE"}] Signal active:`, signal.id);
|
|
148
|
+
},
|
|
145
149
|
onClose: (symbol, signal, priceClose, backtest) => {
|
|
146
150
|
console.log(`[${backtest ? "BT" : "LIVE"}] Signal closed:`, priceClose);
|
|
147
151
|
},
|
|
152
|
+
onCancel: (symbol, signal, currentPrice, backtest) => {
|
|
153
|
+
console.log(`[${backtest ? "BT" : "LIVE"}] Scheduled signal cancelled:`, signal.id);
|
|
154
|
+
},
|
|
148
155
|
},
|
|
149
156
|
});
|
|
150
157
|
|
|
@@ -220,6 +227,7 @@ Backtest.background("BTCUSDT", {
|
|
|
220
227
|
- π‘οΈ **Signal Lifecycle**: Type-safe state machine prevents invalid state transitions. π
|
|
221
228
|
- π¦ **Dependency Inversion**: Lazy-load components at runtime for modular, scalable designs. π§©
|
|
222
229
|
- π **Schema Reflection**: Runtime introspection with `listExchanges()`, `listStrategies()`, `listFrames()`. π
|
|
230
|
+
- π¬ **Data Validation**: Automatic detection and rejection of incomplete candles from Binance API with anomaly checks.
|
|
223
231
|
|
|
224
232
|
---
|
|
225
233
|
|
|
@@ -238,6 +246,7 @@ Backtest.background("BTCUSDT", {
|
|
|
238
246
|
- π€ **`addStrategy`**: Create trading strategies with custom signals and callbacks. π‘
|
|
239
247
|
- π **`addFrame`**: Configure timeframes for backtesting. π
|
|
240
248
|
- π **`Backtest` / `Live`**: Run strategies in backtest or live mode (generator or background). β‘
|
|
249
|
+
- π
**`Schedule`**: Track scheduled signals and cancellation rate for limit orders. π
|
|
241
250
|
- π **`Walker`**: Compare multiple strategies in parallel with ranking. π
|
|
242
251
|
- π₯ **`Heat`**: Portfolio-wide performance analysis across multiple symbols. π
|
|
243
252
|
- π° **`PositionSize`**: Calculate position sizes with Fixed %, Kelly Criterion, or ATR-based methods. π΅
|
|
@@ -253,7 +262,7 @@ Check out the sections below for detailed examples! π
|
|
|
253
262
|
|
|
254
263
|
### 1. Register Exchange Data Source
|
|
255
264
|
|
|
256
|
-
You can plug any data source
|
|
265
|
+
You can plug any data source: CCXT for live data or a database for faster backtesting:
|
|
257
266
|
|
|
258
267
|
```typescript
|
|
259
268
|
import { addExchange } from "backtest-kit";
|
|
@@ -303,14 +312,14 @@ addStrategy({
|
|
|
303
312
|
strategyName: "my-strategy",
|
|
304
313
|
interval: "5m", // Throttling: signals generated max once per 5 minutes
|
|
305
314
|
getSignal: async (symbol) => {
|
|
306
|
-
|
|
315
|
+
const price = await getAveragePrice(symbol);
|
|
307
316
|
return {
|
|
308
317
|
position: "long",
|
|
309
318
|
note: "BTC breakout",
|
|
310
|
-
priceOpen:
|
|
311
|
-
priceTakeProfit:
|
|
312
|
-
priceStopLoss:
|
|
313
|
-
minuteEstimatedTime: 60,
|
|
319
|
+
priceOpen: price,
|
|
320
|
+
priceTakeProfit: price + 1_000, // Must be > priceOpen for long
|
|
321
|
+
priceStopLoss: price - 1_000, // Must be < priceOpen for long
|
|
322
|
+
minuteEstimatedTime: 60,
|
|
314
323
|
};
|
|
315
324
|
},
|
|
316
325
|
callbacks: {
|
|
@@ -1062,24 +1071,377 @@ test("Custom Redis adapter works correctly", async ({ pass, fail }) => {
|
|
|
1062
1071
|
|
|
1063
1072
|
---
|
|
1064
1073
|
|
|
1074
|
+
## π Architecture Overview
|
|
1075
|
+
|
|
1076
|
+
The framework follows **clean architecture** with:
|
|
1077
|
+
|
|
1078
|
+
- **Client Layer** - Pure business logic without DI (ClientStrategy, ClientExchange, ClientFrame)
|
|
1079
|
+
- **Service Layer** - DI-based services organized by responsibility
|
|
1080
|
+
- **Schema Services** - Registry pattern for configuration
|
|
1081
|
+
- **Connection Services** - Memoized client instance creators
|
|
1082
|
+
- **Global Services** - Context wrappers for public API
|
|
1083
|
+
- **Logic Services** - Async generator orchestration (backtest/live)
|
|
1084
|
+
- **Persistence Layer** - Crash-safe atomic file writes with `PersistSignalAdapter`
|
|
1085
|
+
|
|
1086
|
+
---
|
|
1087
|
+
|
|
1088
|
+
## β
Signal Validation
|
|
1089
|
+
|
|
1090
|
+
All signals are validated automatically before execution:
|
|
1091
|
+
|
|
1092
|
+
```typescript
|
|
1093
|
+
// β
Valid long signal
|
|
1094
|
+
{
|
|
1095
|
+
position: "long",
|
|
1096
|
+
priceOpen: 50000,
|
|
1097
|
+
priceTakeProfit: 51000, // β
51000 > 50000
|
|
1098
|
+
priceStopLoss: 49000, // β
49000 < 50000
|
|
1099
|
+
minuteEstimatedTime: 60, // β
positive
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// β Invalid long signal - throws error
|
|
1103
|
+
{
|
|
1104
|
+
position: "long",
|
|
1105
|
+
priceOpen: 50000,
|
|
1106
|
+
priceTakeProfit: 49000, // β 49000 < 50000 (must be higher for long)
|
|
1107
|
+
priceStopLoss: 51000, // β 51000 > 50000 (must be lower for long)
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// β
Valid short signal
|
|
1111
|
+
{
|
|
1112
|
+
position: "short",
|
|
1113
|
+
priceOpen: 50000,
|
|
1114
|
+
priceTakeProfit: 49000, // β
49000 < 50000 (profit goes down for short)
|
|
1115
|
+
priceStopLoss: 51000, // β
51000 > 50000 (stop loss goes up for short)
|
|
1116
|
+
}
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
Validation errors include detailed messages for debugging.
|
|
1120
|
+
|
|
1121
|
+
---
|
|
1122
|
+
|
|
1123
|
+
## π§ Interval Throttling
|
|
1124
|
+
|
|
1125
|
+
Prevent signal spam with automatic throttling:
|
|
1126
|
+
|
|
1127
|
+
```typescript
|
|
1128
|
+
addStrategy({
|
|
1129
|
+
strategyName: "my-strategy",
|
|
1130
|
+
interval: "5m", // Signals generated max once per 5 minutes
|
|
1131
|
+
getSignal: async (symbol) => {
|
|
1132
|
+
// This function will be called max once per 5 minutes
|
|
1133
|
+
// Even if tick() is called every second
|
|
1134
|
+
return signal;
|
|
1135
|
+
},
|
|
1136
|
+
});
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
Supported intervals: `"1m"`, `"3m"`, `"5m"`, `"15m"`, `"30m"`, `"1h"`
|
|
1140
|
+
|
|
1141
|
+
---
|
|
1142
|
+
|
|
1143
|
+
## π Markdown Reports
|
|
1144
|
+
|
|
1145
|
+
Generate detailed trading reports with statistics:
|
|
1146
|
+
|
|
1147
|
+
### Backtest Reports
|
|
1148
|
+
|
|
1149
|
+
```typescript
|
|
1150
|
+
import { Backtest } from "backtest-kit";
|
|
1151
|
+
|
|
1152
|
+
// Get raw statistical data (Controller)
|
|
1153
|
+
const stats = await Backtest.getData("my-strategy");
|
|
1154
|
+
console.log(stats);
|
|
1155
|
+
// Returns:
|
|
1156
|
+
// {
|
|
1157
|
+
// signalList: [...], // All closed signals
|
|
1158
|
+
// totalSignals: 10,
|
|
1159
|
+
// winCount: 7,
|
|
1160
|
+
// lossCount: 3,
|
|
1161
|
+
// winRate: 70.0, // Percentage (higher is better)
|
|
1162
|
+
// avgPnl: 1.23, // Average PNL % (higher is better)
|
|
1163
|
+
// totalPnl: 12.30, // Total PNL % (higher is better)
|
|
1164
|
+
// stdDev: 2.45, // Standard deviation (lower is better)
|
|
1165
|
+
// sharpeRatio: 0.50, // Risk-adjusted return (higher is better)
|
|
1166
|
+
// annualizedSharpeRatio: 9.55, // Sharpe Γ β365 (higher is better)
|
|
1167
|
+
// certaintyRatio: 1.75, // avgWin / |avgLoss| (higher is better)
|
|
1168
|
+
// expectedYearlyReturns: 156 // Estimated yearly trades (higher is better)
|
|
1169
|
+
// }
|
|
1170
|
+
|
|
1171
|
+
// Generate markdown report (View)
|
|
1172
|
+
const markdown = await Backtest.getReport("my-strategy");
|
|
1173
|
+
|
|
1174
|
+
// Save to disk (default: ./logs/backtest/my-strategy.md)
|
|
1175
|
+
await Backtest.dump("my-strategy");
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
### Live Trading Reports
|
|
1179
|
+
|
|
1180
|
+
```typescript
|
|
1181
|
+
import { Live } from "backtest-kit";
|
|
1182
|
+
|
|
1183
|
+
// Get raw statistical data (Controller)
|
|
1184
|
+
const stats = await Live.getData("my-strategy");
|
|
1185
|
+
console.log(stats);
|
|
1186
|
+
// Returns:
|
|
1187
|
+
// {
|
|
1188
|
+
// eventList: [...], // All events (idle, scheduled, opened, active, closed, cancelled)
|
|
1189
|
+
// totalEvents: 15,
|
|
1190
|
+
// totalClosed: 5,
|
|
1191
|
+
// winCount: 3,
|
|
1192
|
+
// lossCount: 2,
|
|
1193
|
+
// winRate: 60.0, // Percentage (higher is better)
|
|
1194
|
+
// avgPnl: 1.23, // Average PNL % (higher is better)
|
|
1195
|
+
// totalPnl: 6.15, // Total PNL % (higher is better)
|
|
1196
|
+
// stdDev: 1.85, // Standard deviation (lower is better)
|
|
1197
|
+
// sharpeRatio: 0.66, // Risk-adjusted return (higher is better)
|
|
1198
|
+
// annualizedSharpeRatio: 12.61,// Sharpe Γ β365 (higher is better)
|
|
1199
|
+
// certaintyRatio: 2.10, // avgWin / |avgLoss| (higher is better)
|
|
1200
|
+
// expectedYearlyReturns: 365 // Estimated yearly trades (higher is better)
|
|
1201
|
+
// }
|
|
1202
|
+
|
|
1203
|
+
// Generate markdown report (View)
|
|
1204
|
+
const markdown = await Live.getReport("my-strategy");
|
|
1205
|
+
|
|
1206
|
+
// Save to disk (default: ./logs/live/my-strategy.md)
|
|
1207
|
+
await Live.dump("my-strategy");
|
|
1208
|
+
```
|
|
1209
|
+
|
|
1210
|
+
### Scheduled Signals Reports
|
|
1211
|
+
|
|
1212
|
+
```typescript
|
|
1213
|
+
import { Schedule } from "backtest-kit";
|
|
1214
|
+
|
|
1215
|
+
// Get raw scheduled signals data (Controller)
|
|
1216
|
+
const stats = await Schedule.getData("my-strategy");
|
|
1217
|
+
console.log(stats);
|
|
1218
|
+
// Returns:
|
|
1219
|
+
// {
|
|
1220
|
+
// eventList: [...], // All scheduled/cancelled events
|
|
1221
|
+
// totalEvents: 8,
|
|
1222
|
+
// totalScheduled: 6, // Number of scheduled signals
|
|
1223
|
+
// totalCancelled: 2, // Number of cancelled signals
|
|
1224
|
+
// cancellationRate: 33.33, // Percentage (lower is better)
|
|
1225
|
+
// avgWaitTime: 45.5, // Average wait time for cancelled signals in minutes
|
|
1226
|
+
// }
|
|
1227
|
+
|
|
1228
|
+
// Generate markdown report (View)
|
|
1229
|
+
const markdown = await Schedule.getReport("my-strategy");
|
|
1230
|
+
|
|
1231
|
+
// Save to disk (default: ./logs/schedule/my-strategy.md)
|
|
1232
|
+
await Schedule.dump("my-strategy");
|
|
1233
|
+
|
|
1234
|
+
// Clear accumulated data
|
|
1235
|
+
await Schedule.clear("my-strategy");
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
**Scheduled Signals Report Example:**
|
|
1239
|
+
```markdown
|
|
1240
|
+
# Scheduled Signals Report: my-strategy
|
|
1241
|
+
|
|
1242
|
+
| Timestamp | Action | Symbol | Signal ID | Position | Note | Current Price | Entry Price | Take Profit | Stop Loss | Wait Time (min) |
|
|
1243
|
+
|-----------|--------|--------|-----------|----------|------|---------------|-------------|-------------|-----------|-----------------|
|
|
1244
|
+
| 2024-01-15T10:30:00Z | SCHEDULED | BTCUSDT | sig-001 | LONG | BTC breakout | 42150.50 USD | 42000.00 USD | 43000.00 USD | 41000.00 USD | N/A |
|
|
1245
|
+
| 2024-01-15T10:35:00Z | CANCELLED | BTCUSDT | sig-002 | LONG | BTC breakout | 42350.80 USD | 10000.00 USD | 11000.00 USD | 9000.00 USD | 60 |
|
|
1246
|
+
|
|
1247
|
+
**Total events:** 8
|
|
1248
|
+
**Scheduled signals:** 6
|
|
1249
|
+
**Cancelled signals:** 2
|
|
1250
|
+
**Cancellation rate:** 33.33% (lower is better)
|
|
1251
|
+
**Average wait time (cancelled):** 45.50 minutes
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
---
|
|
1255
|
+
|
|
1256
|
+
## π§ Event Listeners
|
|
1257
|
+
|
|
1258
|
+
### Listen to All Signals (Backtest + Live)
|
|
1259
|
+
|
|
1260
|
+
```typescript
|
|
1261
|
+
import { listenSignal } from "backtest-kit";
|
|
1262
|
+
|
|
1263
|
+
// Listen to both backtest and live signals
|
|
1264
|
+
listenSignal((event) => {
|
|
1265
|
+
console.log(`[${event.backtest ? "BT" : "LIVE"}] ${event.action}:`, event.signal.id);
|
|
1266
|
+
|
|
1267
|
+
if (event.action === "closed") {
|
|
1268
|
+
console.log("PNL:", event.pnl.pnlPercentage);
|
|
1269
|
+
console.log("Close reason:", event.closeReason);
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
### Listen Once with Filter
|
|
1275
|
+
|
|
1276
|
+
```typescript
|
|
1277
|
+
import { listenSignalOnce, listenSignalLiveOnce } from "backtest-kit";
|
|
1278
|
+
|
|
1279
|
+
// Listen once with filter
|
|
1280
|
+
listenSignalOnce(
|
|
1281
|
+
(event) => event.action === "closed" && event.pnl.pnlPercentage > 5,
|
|
1282
|
+
(event) => {
|
|
1283
|
+
console.log("Big win detected:", event.pnl.pnlPercentage);
|
|
1284
|
+
}
|
|
1285
|
+
);
|
|
1286
|
+
|
|
1287
|
+
// Listen once for specific symbol in live mode
|
|
1288
|
+
listenSignalLiveOnce(
|
|
1289
|
+
(event) => event.signal.symbol === "BTCUSDT" && event.action === "opened",
|
|
1290
|
+
(event) => {
|
|
1291
|
+
console.log("BTC signal opened:", event.signal.id);
|
|
1292
|
+
}
|
|
1293
|
+
);
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
### Listen to Background Completion
|
|
1297
|
+
|
|
1298
|
+
```typescript
|
|
1299
|
+
import { listenDoneBacktest, listenDoneLive, listenDoneWalker } from "backtest-kit";
|
|
1300
|
+
|
|
1301
|
+
// Backtest completion
|
|
1302
|
+
listenDoneBacktest((event) => {
|
|
1303
|
+
console.log("Backtest completed:", event.strategyName);
|
|
1304
|
+
console.log("Symbol:", event.symbol);
|
|
1305
|
+
console.log("Exchange:", event.exchangeName);
|
|
1306
|
+
});
|
|
1307
|
+
|
|
1308
|
+
// Live trading completion
|
|
1309
|
+
listenDoneLive((event) => {
|
|
1310
|
+
console.log("Live trading stopped:", event.strategyName);
|
|
1311
|
+
});
|
|
1312
|
+
|
|
1313
|
+
// Walker completion
|
|
1314
|
+
listenDoneWalker((event) => {
|
|
1315
|
+
console.log("Walker completed:", event.strategyName);
|
|
1316
|
+
console.log("Best strategy:", event.bestStrategy);
|
|
1317
|
+
});
|
|
1318
|
+
```
|
|
1319
|
+
|
|
1320
|
+
---
|
|
1321
|
+
|
|
1322
|
+
## βοΈ Global Configuration
|
|
1323
|
+
|
|
1324
|
+
You can customize framework behavior using the `setConfig()` function. This allows you to adjust global parameters without modifying the source code.
|
|
1325
|
+
|
|
1326
|
+
### Available Configuration Options
|
|
1327
|
+
|
|
1328
|
+
```typescript
|
|
1329
|
+
import { setConfig } from "backtest-kit";
|
|
1330
|
+
|
|
1331
|
+
// Configure global parameters
|
|
1332
|
+
await setConfig({
|
|
1333
|
+
// Time to wait for scheduled signal activation (in minutes)
|
|
1334
|
+
// If a scheduled signal doesn't activate within this time, it will be cancelled
|
|
1335
|
+
// Default: 120 minutes
|
|
1336
|
+
CC_SCHEDULE_AWAIT_MINUTES: 90,
|
|
1337
|
+
|
|
1338
|
+
// Number of candles to use for average price calculation (VWAP)
|
|
1339
|
+
// Used in both backtest and live modes for price calculations
|
|
1340
|
+
// Default: 5 candles (last 5 minutes when using 1m interval)
|
|
1341
|
+
CC_AVG_PRICE_CANDLES_COUNT: 10,
|
|
1342
|
+
});
|
|
1343
|
+
```
|
|
1344
|
+
|
|
1345
|
+
### Configuration Parameters
|
|
1346
|
+
|
|
1347
|
+
#### `CC_SCHEDULE_AWAIT_MINUTES`
|
|
1348
|
+
|
|
1349
|
+
Controls how long scheduled signals wait for activation before being cancelled.
|
|
1350
|
+
|
|
1351
|
+
- **Default:** `120` minutes (2 hours)
|
|
1352
|
+
- **Use case:** Adjust based on market volatility and strategy timeframe
|
|
1353
|
+
- **Example:** Lower for scalping strategies (30-60 min), higher for swing trading (180-360 min)
|
|
1354
|
+
|
|
1355
|
+
```typescript
|
|
1356
|
+
// For scalping strategies with tight entry windows
|
|
1357
|
+
await setConfig({
|
|
1358
|
+
CC_SCHEDULE_AWAIT_MINUTES: 30,
|
|
1359
|
+
});
|
|
1360
|
+
|
|
1361
|
+
// For swing trading with wider entry windows
|
|
1362
|
+
await setConfig({
|
|
1363
|
+
CC_SCHEDULE_AWAIT_MINUTES: 240,
|
|
1364
|
+
});
|
|
1365
|
+
```
|
|
1366
|
+
|
|
1367
|
+
#### `CC_AVG_PRICE_CANDLES_COUNT`
|
|
1368
|
+
|
|
1369
|
+
Controls the number of 1-minute candles used for VWAP (Volume Weighted Average Price) calculations.
|
|
1370
|
+
|
|
1371
|
+
- **Default:** `5` candles (5 minutes of data)
|
|
1372
|
+
- **Use case:** Adjust for more stable (higher) or responsive (lower) price calculations
|
|
1373
|
+
- **Impact:** Affects entry/exit prices in both backtest and live modes
|
|
1374
|
+
|
|
1375
|
+
```typescript
|
|
1376
|
+
// More responsive to recent price changes (3 minutes)
|
|
1377
|
+
await setConfig({
|
|
1378
|
+
CC_AVG_PRICE_CANDLES_COUNT: 3,
|
|
1379
|
+
});
|
|
1380
|
+
|
|
1381
|
+
// More stable, less sensitive to spikes (10 minutes)
|
|
1382
|
+
await setConfig({
|
|
1383
|
+
CC_AVG_PRICE_CANDLES_COUNT: 10,
|
|
1384
|
+
});
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
### When to Call `setConfig()`
|
|
1388
|
+
|
|
1389
|
+
Always call `setConfig()` **before** running any strategies to ensure configuration is applied:
|
|
1390
|
+
|
|
1391
|
+
```typescript
|
|
1392
|
+
import { setConfig, Backtest, Live } from "backtest-kit";
|
|
1393
|
+
|
|
1394
|
+
// 1. Configure framework first
|
|
1395
|
+
await setConfig({
|
|
1396
|
+
CC_SCHEDULE_AWAIT_MINUTES: 90,
|
|
1397
|
+
CC_AVG_PRICE_CANDLES_COUNT: 7,
|
|
1398
|
+
});
|
|
1399
|
+
|
|
1400
|
+
// 2. Then run strategies
|
|
1401
|
+
Backtest.background("BTCUSDT", {
|
|
1402
|
+
strategyName: "my-strategy",
|
|
1403
|
+
exchangeName: "binance",
|
|
1404
|
+
frameName: "1d-backtest"
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
Live.background("ETHUSDT", {
|
|
1408
|
+
strategyName: "my-strategy",
|
|
1409
|
+
exchangeName: "binance"
|
|
1410
|
+
});
|
|
1411
|
+
```
|
|
1412
|
+
|
|
1413
|
+
### Partial Configuration
|
|
1414
|
+
|
|
1415
|
+
You can update individual parameters without specifying all of them:
|
|
1416
|
+
|
|
1417
|
+
```typescript
|
|
1418
|
+
// Only change candle count, keep other defaults
|
|
1419
|
+
await setConfig({
|
|
1420
|
+
CC_AVG_PRICE_CANDLES_COUNT: 8,
|
|
1421
|
+
});
|
|
1422
|
+
|
|
1423
|
+
// Later, only change timeout
|
|
1424
|
+
await setConfig({
|
|
1425
|
+
CC_SCHEDULE_AWAIT_MINUTES: 60,
|
|
1426
|
+
});
|
|
1427
|
+
```
|
|
1428
|
+
|
|
1429
|
+
---
|
|
1430
|
+
|
|
1065
1431
|
## β
Tested & Reliable
|
|
1066
1432
|
|
|
1067
|
-
`backtest-kit` comes with
|
|
1068
|
-
- π‘οΈ **Validation**: Ensures all components (exchanges, strategies, frames, risk profiles) are properly configured. β
|
|
1069
|
-
- π **Recovery**: Handles edge cases like invalid signals or empty outputs. π οΈ
|
|
1070
|
-
- π **Navigation**: Smoothly switches between backtest and live modes without errors. π
|
|
1071
|
-
- β‘ **Performance**: Efficient memory usage and history management. π
|
|
1433
|
+
`backtest-kit` comes with **123 unit and integration tests** covering:
|
|
1072
1434
|
|
|
1073
|
-
**109 unit and integration tests** covering:
|
|
1074
1435
|
- Signal validation and throttling
|
|
1075
1436
|
- PNL calculation with fees and slippage
|
|
1076
1437
|
- Crash recovery and state persistence
|
|
1077
|
-
- Callback execution order
|
|
1078
|
-
- Markdown report generation
|
|
1438
|
+
- Callback execution order (onSchedule, onOpen, onActive, onClose, onCancel)
|
|
1439
|
+
- Markdown report generation (backtest, live, scheduled signals)
|
|
1079
1440
|
- Walker strategy comparison
|
|
1080
1441
|
- Heatmap portfolio analysis
|
|
1081
1442
|
- Position sizing calculations
|
|
1082
1443
|
- Risk management validation
|
|
1444
|
+
- Scheduled signals lifecycle and cancellation tracking
|
|
1083
1445
|
- Event system
|
|
1084
1446
|
|
|
1085
1447
|
---
|