backtest-kit 1.5.2 โ†’ 1.5.4

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 CHANGED
@@ -227,6 +227,7 @@ Backtest.background("BTCUSDT", {
227
227
 
228
228
  - ๐Ÿค **Mode Switching**: Seamlessly switch between backtest and live modes with identical strategy code. ๐Ÿ”„
229
229
  - ๐Ÿ“œ **Crash Recovery**: Atomic persistence ensures state recovery after crashesโ€”no duplicate signals. ๐Ÿ—‚๏ธ
230
+ - ๐Ÿ›‘ **Graceful Shutdown**: Stop backtests, live trading, and walkers programmatically with `Backtest.stop()`, `Live.stop()`, and `Walker.stop()`. Current signals complete normally, no forced closures. โน๏ธ
230
231
  - ๐Ÿ› ๏ธ **Custom Validators**: Define validation rules with strategy-level throttling and price logic checks. ๐Ÿ”ง
231
232
  - ๐Ÿ›ก๏ธ **Signal Lifecycle**: Type-safe state machine prevents invalid state transitions. ๐Ÿš‘
232
233
  - ๐Ÿ“ฆ **Dependency Inversion**: Lazy-load components at runtime for modular, scalable designs. ๐Ÿงฉ
@@ -250,6 +251,7 @@ Backtest.background("BTCUSDT", {
250
251
  - ๐Ÿค– **`addStrategy`**: Create trading strategies with custom signals and callbacks. ๐Ÿ’ก
251
252
  - ๐ŸŒ **`addFrame`**: Configure timeframes for backtesting. ๐Ÿ“…
252
253
  - ๐Ÿ”„ **`Backtest` / `Live`**: Run strategies in backtest or live mode (generator or background). โšก
254
+ - ๐Ÿ›‘ **`Backtest.stop()` / `Live.stop()` / `Walker.stop()`**: Gracefully stop running strategiesโ€”current signals complete, no forced exits. โน๏ธ
253
255
  - ๐Ÿ“… **`Schedule`**: Track scheduled signals and cancellation rate for limit orders. ๐Ÿ“Š
254
256
  - ๐Ÿ“Š **`Partial`**: Access partial profit/loss statistics and reports for risk management. Track signals reaching milestone levels (10%, 20%, 30%, etc.). ๐Ÿ’น
255
257
  - ๐ŸŽฏ **`Constant`**: Kelly Criterion-based constants for optimal take profit (TP_LEVEL1-3) and stop loss (SL_LEVEL1-2) levels. ๐Ÿ“
@@ -365,6 +367,12 @@ listenDoneBacktest((event) => {
365
367
  Backtest.dump(event.strategyName); // ./logs/backtest/my-strategy.md
366
368
  });
367
369
 
370
+ // Graceful shutdown - stop backtest programmatically
371
+ await Backtest.stop("BTCUSDT", "my-strategy");
372
+ // - Current signal completes execution (onClose callback fires)
373
+ // - No new signals are generated after stop
374
+ // - listenDoneBacktest event fires when complete
375
+
368
376
  // Option 2: Manual iteration (for custom control)
369
377
  for await (const result of Backtest.run("BTCUSDT", {
370
378
  strategyName: "my-strategy",
@@ -384,7 +392,7 @@ Live mode automatically persists state to disk with atomic writes:
384
392
  import { Live, listenSignalLive } from "backtest-kit";
385
393
 
386
394
  // Run live trading in background (infinite loop, crash-safe)
387
- const stop = Live.background("BTCUSDT", {
395
+ const cancelFn = Live.background("BTCUSDT", {
388
396
  strategyName: "my-strategy",
389
397
  exchangeName: "binance"
390
398
  });
@@ -403,7 +411,14 @@ listenSignalLive((event) => {
403
411
  }
404
412
  });
405
413
 
406
- // Stop when needed: stop();
414
+ // Graceful shutdown - stop live trading programmatically
415
+ await Live.stop("BTCUSDT", "my-strategy");
416
+ // - Active signal completes normally (no forced close)
417
+ // - No new signals are generated after stop
418
+ // - State remains persisted for resume on restart
419
+
420
+ // Or use cancelFn() for immediate cancellation
421
+ cancelFn();
407
422
  ```
408
423
 
409
424
  **Crash Recovery:** If process crashes, restart with same codeโ€”state automatically recovered from disk (no duplicate signals).
@@ -426,8 +441,11 @@ addWalker({
426
441
  onStrategyStart: (strategyName, symbol) => {
427
442
  console.log(`Starting strategy: ${strategyName}`);
428
443
  },
429
- onStrategyComplete: (strategyName, symbol, stats) => {
444
+ onStrategyComplete: async (strategyName, symbol, stats) => {
430
445
  console.log(`${strategyName} completed:`, stats.sharpeRatio);
446
+
447
+ // Optional: Stop walker early after first strategy completes
448
+ // await Walker.stop("BTCUSDT", "btc-walker");
431
449
  },
432
450
  onComplete: (results) => {
433
451
  console.log("Best strategy:", results.bestStrategy);
@@ -437,7 +455,7 @@ addWalker({
437
455
  });
438
456
 
439
457
  // Run walker in background
440
- Walker.background("BTCUSDT", {
458
+ const cancelFn = Walker.background("BTCUSDT", {
441
459
  walkerName: "btc-walker"
442
460
  });
443
461
 
@@ -447,6 +465,16 @@ listenWalkerComplete((results) => {
447
465
  Walker.dump("BTCUSDT", results.walkerName); // Save report
448
466
  });
449
467
 
468
+ // Graceful shutdown - stop walker programmatically
469
+ await Walker.stop("BTCUSDT", "btc-walker");
470
+ // - Current strategy completes execution
471
+ // - Remaining strategies in queue won't run
472
+ // - listenWalkerComplete event fires with partial results
473
+ // - Use case: Early termination when first strategy is good enough
474
+
475
+ // Or use cancelFn() for immediate cancellation
476
+ cancelFn();
477
+
450
478
  // Get raw comparison data
451
479
  const results = await Walker.getData("BTCUSDT", "btc-walker");
452
480
  console.log(results);
@@ -1328,7 +1356,148 @@ listenPartialProfit(({ symbol, signal, price, level, backtest }) => {
1328
1356
 
1329
1357
  ---
1330
1358
 
1331
- ### 11. Scheduled Signal Persistence
1359
+ ### 11. Graceful Shutdown
1360
+
1361
+ The framework provides graceful shutdown mechanisms for all execution modes: backtests, live trading, and walkers. This ensures clean termination without forced signal closures.
1362
+
1363
+ #### How Graceful Shutdown Works
1364
+
1365
+ When you call `Backtest.stop()`, `Live.stop()`, or `Walker.stop()`:
1366
+
1367
+ 1. **Current Signal Completes** - Active signals finish normally (reach TP/SL or expire)
1368
+ 2. **No New Signals** - Strategy stops generating new signals after stop is called
1369
+ 3. **Callbacks Fire** - All lifecycle callbacks (`onClose`, etc.) execute as expected
1370
+ 4. **Events Emitted** - Completion events (`listenDoneBacktest`, `listenDoneLive`, `listenWalkerComplete`) fire
1371
+ 5. **State Persisted** - In live mode, final state is saved to disk
1372
+
1373
+ #### Backtest Shutdown
1374
+
1375
+ ```typescript
1376
+ import { Backtest, listenDoneBacktest } from "backtest-kit";
1377
+
1378
+ Backtest.background("BTCUSDT", {
1379
+ strategyName: "my-strategy",
1380
+ exchangeName: "binance",
1381
+ frameName: "1d-backtest"
1382
+ });
1383
+
1384
+ // Stop backtest gracefully
1385
+ await Backtest.stop("BTCUSDT", "my-strategy");
1386
+ // - Current active signal completes (TP/SL reached)
1387
+ // - No new signals generated after stop
1388
+ // - listenDoneBacktest event fires
1389
+
1390
+ listenDoneBacktest((event) => {
1391
+ console.log("Backtest stopped:", event.strategyName);
1392
+ });
1393
+ ```
1394
+
1395
+ #### Live Trading Shutdown
1396
+
1397
+ ```typescript
1398
+ import { Live, listenDoneLive } from "backtest-kit";
1399
+
1400
+ Live.background("BTCUSDT", {
1401
+ strategyName: "my-strategy",
1402
+ exchangeName: "binance"
1403
+ });
1404
+
1405
+ // Stop live trading gracefully
1406
+ await Live.stop("BTCUSDT", "my-strategy");
1407
+ // - Active signal completes normally (no forced close)
1408
+ // - No new signals generated after stop
1409
+ // - State persisted to disk for resume on restart
1410
+
1411
+ listenDoneLive((event) => {
1412
+ console.log("Live trading stopped:", event.strategyName);
1413
+ });
1414
+ ```
1415
+
1416
+ #### Walker Shutdown (Early Termination)
1417
+
1418
+ Walker shutdown is particularly useful for early termination when comparing strategies:
1419
+
1420
+ ```typescript
1421
+ import { addWalker, Walker, listenWalkerComplete } from "backtest-kit";
1422
+
1423
+ addWalker({
1424
+ walkerName: "btc-walker",
1425
+ exchangeName: "binance",
1426
+ frameName: "1d-backtest",
1427
+ strategies: ["strategy-a", "strategy-b", "strategy-c"],
1428
+ callbacks: {
1429
+ onStrategyComplete: async (strategyName, symbol, stats) => {
1430
+ console.log(`${strategyName} completed with Sharpe: ${stats.sharpeRatio}`);
1431
+
1432
+ // Early termination: Stop walker if first strategy is good enough
1433
+ if (stats.sharpeRatio > 2.0) {
1434
+ console.log("Found excellent strategy, stopping walker early");
1435
+ await Walker.stop("BTCUSDT", "btc-walker");
1436
+ }
1437
+ },
1438
+ },
1439
+ });
1440
+
1441
+ Walker.background("BTCUSDT", {
1442
+ walkerName: "btc-walker"
1443
+ });
1444
+
1445
+ // Or stop walker manually after some condition
1446
+ await Walker.stop("BTCUSDT", "btc-walker");
1447
+ // - Current strategy completes execution
1448
+ // - Remaining strategies (not yet started) won't run
1449
+ // - listenWalkerComplete fires with partial results
1450
+
1451
+ listenWalkerComplete((results) => {
1452
+ console.log("Walker stopped early:", results.bestStrategy);
1453
+ console.log(`Tested ${results.strategies.length}/3 strategies`);
1454
+ });
1455
+ ```
1456
+
1457
+ #### Multiple Walkers on Same Symbol
1458
+
1459
+ Walker shutdown only affects the specified walker, not others running on the same symbol:
1460
+
1461
+ ```typescript
1462
+ // Start two independent walkers on same symbol
1463
+ Walker.background("BTCUSDT", { walkerName: "walker-A" });
1464
+ Walker.background("BTCUSDT", { walkerName: "walker-B" });
1465
+
1466
+ // Stop walker-A only
1467
+ await Walker.stop("BTCUSDT", "walker-A");
1468
+ // - walker-A stops gracefully
1469
+ // - walker-B continues unaffected
1470
+ ```
1471
+
1472
+ #### Use Cases
1473
+
1474
+ 1. **Backtest Early Exit** - Stop backtest when strategy performs poorly (e.g., drawdown > 10%)
1475
+ 2. **Live Trading Maintenance** - Gracefully stop live trading for system updates
1476
+ 3. **Walker Optimization** - Skip remaining strategies when first one is excellent
1477
+ 4. **Resource Management** - Stop long-running backtests to free up resources
1478
+ 5. **Conditional Termination** - Stop based on external events (API limits, market conditions)
1479
+
1480
+ #### Best Practices
1481
+
1482
+ 1. **Always await stop()** - Ensure graceful shutdown completes before exiting process
1483
+ 2. **Use listenDone events** - Track completion with `listenDoneBacktest`, `listenDoneLive`, `listenWalkerComplete`
1484
+ 3. **Don't force-kill** - Let signals complete naturally instead of process.exit()
1485
+ 4. **Save reports** - Call `dump()` methods before stopping to preserve results
1486
+ 5. **Test shutdown paths** - Write tests that verify graceful shutdown behavior
1487
+
1488
+ ```typescript
1489
+ // GOOD - Graceful shutdown with cleanup
1490
+ await Backtest.stop("BTCUSDT", "my-strategy");
1491
+ await Backtest.dump("my-strategy"); // Save report
1492
+ console.log("Shutdown complete");
1493
+
1494
+ // BAD - Forced exit without cleanup
1495
+ process.exit(0); // Signals may not complete, callbacks may not fire
1496
+ ```
1497
+
1498
+ ---
1499
+
1500
+ ### 12. Scheduled Signal Persistence
1332
1501
 
1333
1502
  The framework includes a separate persistence system for scheduled signals (`PersistScheduleAdapter`) that works independently from pending/active signal persistence (`PersistSignalAdapter`). This separation ensures crash-safe recovery of both signal types.
1334
1503
 
@@ -2265,16 +2434,17 @@ await setConfig({
2265
2434
 
2266
2435
  ## โœ… Tested & Reliable
2267
2436
 
2268
- `backtest-kit` comes with **217 unit and integration tests** covering:
2437
+ `backtest-kit` comes with **244 unit and integration tests** covering:
2269
2438
 
2270
2439
  - Signal validation and throttling
2271
2440
  - PNL calculation with fees and slippage
2272
2441
  - Crash recovery and state persistence
2273
2442
  - Dual-layer persistence (pending signals and scheduled signals)
2274
2443
  - Crash recovery validation (exchange/strategy name mismatch protection)
2444
+ - Graceful shutdown (Backtest.stop, Live.stop, Walker.stop) with signal completion
2275
2445
  - Callback execution order (onSchedule, onOpen, onActive, onClose, onCancel)
2276
2446
  - Markdown report generation (backtest, live, scheduled signals)
2277
- - Walker strategy comparison
2447
+ - Walker strategy comparison and early termination
2278
2448
  - Heatmap portfolio analysis
2279
2449
  - Position sizing calculations
2280
2450
  - Risk management validation