backtest-kit 1.5.3 → 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/build/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createActivator } from 'di-kit';
2
2
  import { scoped } from 'di-scoped';
3
- import { errorData, getErrorMessage, sleep, memoize, makeExtendable, singleshot, not, trycatch, retry, Subject, randomString, ToolRegistry, isObject, and, resolveDocuments, str, iterateDocuments, distinctDocuments, queued } from 'functools-kit';
3
+ import { errorData, getErrorMessage, sleep, memoize, makeExtendable, singleshot, not, trycatch, retry, Subject, randomString, ToolRegistry, isObject, and, resolveDocuments, str, iterateDocuments, distinctDocuments, queued, singlerun } from 'functools-kit';
4
4
  import fs, { mkdir, writeFile } from 'fs/promises';
5
5
  import path, { join } from 'path';
6
6
  import crypto from 'crypto';
@@ -13400,17 +13400,50 @@ const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
13400
13400
  const BACKTEST_METHOD_NAME_STOP = "BacktestUtils.stop";
13401
13401
  const BACKTEST_METHOD_NAME_GET_REPORT = "BacktestUtils.getReport";
13402
13402
  const BACKTEST_METHOD_NAME_DUMP = "BacktestUtils.dump";
13403
+ const BACKTEST_METHOD_NAME_TASK = "BacktestUtils.task";
13404
+ const BACKTEST_METHOD_NAME_GET_STATUS = "BacktestUtils.getStatus";
13403
13405
  /**
13404
- * Utility class for backtest operations.
13406
+ * Internal task function that runs backtest and handles completion.
13407
+ * Consumes backtest results and updates instance state flags.
13405
13408
  *
13406
- * Provides simplified access to backtestCommandService.run() with logging.
13407
- * Exported as singleton instance for convenient usage.
13409
+ * @param symbol - Trading pair symbol
13410
+ * @param context - Execution context with strategy, exchange, and frame names
13411
+ * @param self - BacktestInstance reference for state management
13412
+ * @returns Promise that resolves when backtest completes
13413
+ *
13414
+ * @internal
13415
+ */
13416
+ const INSTANCE_TASK_FN$2 = async (symbol, context, self) => {
13417
+ {
13418
+ self._isStopped = false;
13419
+ self._isDone = false;
13420
+ }
13421
+ for await (const _ of self.run(symbol, context)) {
13422
+ if (self._isStopped) {
13423
+ break;
13424
+ }
13425
+ }
13426
+ if (!self._isDone) {
13427
+ await doneBacktestSubject.next({
13428
+ exchangeName: context.exchangeName,
13429
+ strategyName: context.strategyName,
13430
+ backtest: true,
13431
+ symbol,
13432
+ });
13433
+ }
13434
+ self._isDone = true;
13435
+ };
13436
+ /**
13437
+ * Instance class for backtest operations on a specific symbol-strategy pair.
13438
+ *
13439
+ * Provides isolated backtest execution and reporting for a single symbol-strategy combination.
13440
+ * Each instance maintains its own state and context.
13408
13441
  *
13409
13442
  * @example
13410
13443
  * ```typescript
13411
- * import { Backtest } from "./classes/Backtest";
13444
+ * const instance = new BacktestInstance("BTCUSDT", "my-strategy");
13412
13445
  *
13413
- * for await (const result of Backtest.run("BTCUSDT", {
13446
+ * for await (const result of instance.run("BTCUSDT", {
13414
13447
  * strategyName: "my-strategy",
13415
13448
  * exchangeName: "my-exchange",
13416
13449
  * frameName: "1d-backtest"
@@ -13419,8 +13452,57 @@ const BACKTEST_METHOD_NAME_DUMP = "BacktestUtils.dump";
13419
13452
  * }
13420
13453
  * ```
13421
13454
  */
13422
- class BacktestUtils {
13423
- constructor() {
13455
+ class BacktestInstance {
13456
+ /**
13457
+ * Creates a new BacktestInstance for a specific symbol-strategy pair.
13458
+ *
13459
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
13460
+ * @param strategyName - Strategy name for this backtest instance
13461
+ */
13462
+ constructor(symbol, strategyName) {
13463
+ this.symbol = symbol;
13464
+ this.strategyName = strategyName;
13465
+ /** Internal flag indicating if backtest was stopped manually */
13466
+ this._isStopped = false;
13467
+ /** Internal flag indicating if backtest task completed */
13468
+ this._isDone = false;
13469
+ /**
13470
+ * Internal singlerun task that executes the backtest.
13471
+ * Ensures only one backtest run per instance using singlerun wrapper.
13472
+ *
13473
+ * @param symbol - Trading pair symbol
13474
+ * @param context - Execution context with strategy, exchange, and frame names
13475
+ * @returns Promise that resolves when backtest completes
13476
+ *
13477
+ * @internal
13478
+ */
13479
+ this.task = singlerun(async (symbol, context) => {
13480
+ backtest$1.loggerService.info(BACKTEST_METHOD_NAME_TASK, {
13481
+ symbol,
13482
+ context,
13483
+ });
13484
+ return await INSTANCE_TASK_FN$2(symbol, context, this);
13485
+ });
13486
+ /**
13487
+ * Gets the current status of this backtest instance.
13488
+ *
13489
+ * @returns Promise resolving to status object with symbol, strategyName, and task status
13490
+ *
13491
+ * @example
13492
+ * ```typescript
13493
+ * const instance = new BacktestInstance("BTCUSDT", "my-strategy");
13494
+ * const status = await instance.getStatus();
13495
+ * console.log(status.status); // "idle", "running", or "done"
13496
+ * ```
13497
+ */
13498
+ this.getStatus = async () => {
13499
+ backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_STATUS);
13500
+ return {
13501
+ symbol: this.symbol,
13502
+ strategyName: this.strategyName,
13503
+ status: this.task.getStatus(),
13504
+ };
13505
+ };
13424
13506
  /**
13425
13507
  * Runs backtest for a symbol with context propagation.
13426
13508
  *
@@ -13458,13 +13540,12 @@ class BacktestUtils {
13458
13540
  *
13459
13541
  * @example
13460
13542
  * ```typescript
13461
- * // Run backtest silently, only callbacks will fire
13462
- * await Backtest.background("BTCUSDT", {
13543
+ * const instance = new BacktestInstance();
13544
+ * const cancel = instance.background("BTCUSDT", {
13463
13545
  * strategyName: "my-strategy",
13464
13546
  * exchangeName: "my-exchange",
13465
13547
  * frameName: "1d-backtest"
13466
13548
  * });
13467
- * console.log("Backtest completed");
13468
13549
  * ```
13469
13550
  */
13470
13551
  this.background = (symbol, context) => {
@@ -13472,25 +13553,7 @@ class BacktestUtils {
13472
13553
  symbol,
13473
13554
  context,
13474
13555
  });
13475
- let isStopped = false;
13476
- let isDone = false;
13477
- const task = async () => {
13478
- for await (const _ of this.run(symbol, context)) {
13479
- if (isStopped) {
13480
- break;
13481
- }
13482
- }
13483
- if (!isDone) {
13484
- await doneBacktestSubject.next({
13485
- exchangeName: context.exchangeName,
13486
- strategyName: context.strategyName,
13487
- backtest: true,
13488
- symbol,
13489
- });
13490
- }
13491
- isDone = true;
13492
- };
13493
- task().catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
13556
+ this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
13494
13557
  return () => {
13495
13558
  backtest$1.strategyGlobalService.stop({ symbol, strategyName: context.strategyName }, true);
13496
13559
  backtest$1.strategyGlobalService
@@ -13499,7 +13562,7 @@ class BacktestUtils {
13499
13562
  if (pendingSignal) {
13500
13563
  return;
13501
13564
  }
13502
- if (!isDone) {
13565
+ if (!this._isDone) {
13503
13566
  await doneBacktestSubject.next({
13504
13567
  exchangeName: context.exchangeName,
13505
13568
  strategyName: context.strategyName,
@@ -13507,9 +13570,9 @@ class BacktestUtils {
13507
13570
  symbol,
13508
13571
  });
13509
13572
  }
13510
- isDone = true;
13573
+ this._isDone = true;
13511
13574
  });
13512
- isStopped = true;
13575
+ this._isStopped = true;
13513
13576
  };
13514
13577
  };
13515
13578
  /**
@@ -13525,8 +13588,8 @@ class BacktestUtils {
13525
13588
  *
13526
13589
  * @example
13527
13590
  * ```typescript
13528
- * // Stop strategy after some condition
13529
- * await Backtest.stop("BTCUSDT", "my-strategy");
13591
+ * const instance = new BacktestInstance();
13592
+ * await instance.stop("BTCUSDT", "my-strategy");
13530
13593
  * ```
13531
13594
  */
13532
13595
  this.stop = async (symbol, strategyName) => {
@@ -13545,7 +13608,8 @@ class BacktestUtils {
13545
13608
  *
13546
13609
  * @example
13547
13610
  * ```typescript
13548
- * const stats = await Backtest.getData("BTCUSDT", "my-strategy");
13611
+ * const instance = new BacktestInstance();
13612
+ * const stats = await instance.getData("BTCUSDT", "my-strategy");
13549
13613
  * console.log(stats.sharpeRatio, stats.winRate);
13550
13614
  * ```
13551
13615
  */
@@ -13565,7 +13629,8 @@ class BacktestUtils {
13565
13629
  *
13566
13630
  * @example
13567
13631
  * ```typescript
13568
- * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy");
13632
+ * const instance = new BacktestInstance();
13633
+ * const markdown = await instance.getReport("BTCUSDT", "my-strategy");
13569
13634
  * console.log(markdown);
13570
13635
  * ```
13571
13636
  */
@@ -13585,11 +13650,12 @@ class BacktestUtils {
13585
13650
  *
13586
13651
  * @example
13587
13652
  * ```typescript
13653
+ * const instance = new BacktestInstance();
13588
13654
  * // Save to default path: ./dump/backtest/my-strategy.md
13589
- * await Backtest.dump("BTCUSDT", "my-strategy");
13655
+ * await instance.dump("BTCUSDT", "my-strategy");
13590
13656
  *
13591
13657
  * // Save to custom path: ./custom/path/my-strategy.md
13592
- * await Backtest.dump("BTCUSDT", "my-strategy", "./custom/path");
13658
+ * await instance.dump("BTCUSDT", "my-strategy", "./custom/path");
13593
13659
  * ```
13594
13660
  */
13595
13661
  this.dump = async (symbol, strategyName, path) => {
@@ -13602,6 +13668,162 @@ class BacktestUtils {
13602
13668
  };
13603
13669
  }
13604
13670
  }
13671
+ /**
13672
+ * Utility class for backtest operations.
13673
+ *
13674
+ * Provides simplified access to backtestCommandService.run() with logging.
13675
+ * Exported as singleton instance for convenient usage.
13676
+ *
13677
+ * @example
13678
+ * ```typescript
13679
+ * import { Backtest } from "./classes/Backtest";
13680
+ *
13681
+ * for await (const result of Backtest.run("BTCUSDT", {
13682
+ * strategyName: "my-strategy",
13683
+ * exchangeName: "my-exchange",
13684
+ * frameName: "1d-backtest"
13685
+ * })) {
13686
+ * console.log("Closed signal PNL:", result.pnl.pnlPercentage);
13687
+ * }
13688
+ * ```
13689
+ */
13690
+ class BacktestUtils {
13691
+ constructor() {
13692
+ /**
13693
+ * Memoized function to get or create BacktestInstance for a symbol-strategy pair.
13694
+ * Each symbol-strategy combination gets its own isolated instance.
13695
+ */
13696
+ this._getInstance = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => new BacktestInstance(symbol, strategyName));
13697
+ /**
13698
+ * Runs backtest for a symbol with context propagation.
13699
+ *
13700
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
13701
+ * @param context - Execution context with strategy, exchange, and frame names
13702
+ * @returns Async generator yielding closed signals with PNL
13703
+ */
13704
+ this.run = (symbol, context) => {
13705
+ const instance = this._getInstance(symbol, context.strategyName);
13706
+ return instance.run(symbol, context);
13707
+ };
13708
+ /**
13709
+ * Runs backtest in background without yielding results.
13710
+ *
13711
+ * Consumes all backtest results internally without exposing them.
13712
+ * Useful for running backtests for side effects only (callbacks, logging).
13713
+ *
13714
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
13715
+ * @param context - Execution context with strategy, exchange, and frame names
13716
+ * @returns Cancellation closure
13717
+ *
13718
+ * @example
13719
+ * ```typescript
13720
+ * // Run backtest silently, only callbacks will fire
13721
+ * await Backtest.background("BTCUSDT", {
13722
+ * strategyName: "my-strategy",
13723
+ * exchangeName: "my-exchange",
13724
+ * frameName: "1d-backtest"
13725
+ * });
13726
+ * console.log("Backtest completed");
13727
+ * ```
13728
+ */
13729
+ this.background = (symbol, context) => {
13730
+ const instance = this._getInstance(symbol, context.strategyName);
13731
+ return instance.background(symbol, context);
13732
+ };
13733
+ /**
13734
+ * Stops the strategy from generating new signals.
13735
+ *
13736
+ * Sets internal flag to prevent strategy from opening new signals.
13737
+ * Current active signal (if any) will complete normally.
13738
+ * Backtest will stop at the next safe point (idle state or after signal closes).
13739
+ *
13740
+ * @param symbol - Trading pair symbol
13741
+ * @param strategyName - Strategy name to stop
13742
+ * @returns Promise that resolves when stop flag is set
13743
+ *
13744
+ * @example
13745
+ * ```typescript
13746
+ * // Stop strategy after some condition
13747
+ * await Backtest.stop("BTCUSDT", "my-strategy");
13748
+ * ```
13749
+ */
13750
+ this.stop = async (symbol, strategyName) => {
13751
+ const instance = this._getInstance(symbol, strategyName);
13752
+ return await instance.stop(symbol, strategyName);
13753
+ };
13754
+ /**
13755
+ * Gets statistical data from all closed signals for a symbol-strategy pair.
13756
+ *
13757
+ * @param symbol - Trading pair symbol
13758
+ * @param strategyName - Strategy name to get data for
13759
+ * @returns Promise resolving to statistical data object
13760
+ *
13761
+ * @example
13762
+ * ```typescript
13763
+ * const stats = await Backtest.getData("BTCUSDT", "my-strategy");
13764
+ * console.log(stats.sharpeRatio, stats.winRate);
13765
+ * ```
13766
+ */
13767
+ this.getData = async (symbol, strategyName) => {
13768
+ const instance = this._getInstance(symbol, strategyName);
13769
+ return await instance.getData(symbol, strategyName);
13770
+ };
13771
+ /**
13772
+ * Generates markdown report with all closed signals for a symbol-strategy pair.
13773
+ *
13774
+ * @param symbol - Trading pair symbol
13775
+ * @param strategyName - Strategy name to generate report for
13776
+ * @returns Promise resolving to markdown formatted report string
13777
+ *
13778
+ * @example
13779
+ * ```typescript
13780
+ * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy");
13781
+ * console.log(markdown);
13782
+ * ```
13783
+ */
13784
+ this.getReport = async (symbol, strategyName) => {
13785
+ const instance = this._getInstance(symbol, strategyName);
13786
+ return await instance.getReport(symbol, strategyName);
13787
+ };
13788
+ /**
13789
+ * Saves strategy report to disk.
13790
+ *
13791
+ * @param symbol - Trading pair symbol
13792
+ * @param strategyName - Strategy name to save report for
13793
+ * @param path - Optional directory path to save report (default: "./dump/backtest")
13794
+ *
13795
+ * @example
13796
+ * ```typescript
13797
+ * // Save to default path: ./dump/backtest/my-strategy.md
13798
+ * await Backtest.dump("BTCUSDT", "my-strategy");
13799
+ *
13800
+ * // Save to custom path: ./custom/path/my-strategy.md
13801
+ * await Backtest.dump("BTCUSDT", "my-strategy", "./custom/path");
13802
+ * ```
13803
+ */
13804
+ this.dump = async (symbol, strategyName, path) => {
13805
+ const instance = this._getInstance(symbol, strategyName);
13806
+ return await instance.dump(symbol, strategyName, path);
13807
+ };
13808
+ /**
13809
+ * Lists all active backtest instances with their current status.
13810
+ *
13811
+ * @returns Promise resolving to array of status objects for all instances
13812
+ *
13813
+ * @example
13814
+ * ```typescript
13815
+ * const statusList = await Backtest.list();
13816
+ * statusList.forEach(status => {
13817
+ * console.log(`${status.symbol} - ${status.strategyName}: ${status.status}`);
13818
+ * });
13819
+ * ```
13820
+ */
13821
+ this.list = async () => {
13822
+ const instanceList = this._getInstance.values();
13823
+ return await Promise.all(instanceList.map((instance) => instance.getStatus()));
13824
+ };
13825
+ }
13826
+ }
13605
13827
  /**
13606
13828
  * Singleton instance of BacktestUtils for convenient backtest operations.
13607
13829
  *
@@ -13627,37 +13849,110 @@ const LIVE_METHOD_NAME_BACKGROUND = "LiveUtils.background";
13627
13849
  const LIVE_METHOD_NAME_STOP = "LiveUtils.stop";
13628
13850
  const LIVE_METHOD_NAME_GET_REPORT = "LiveUtils.getReport";
13629
13851
  const LIVE_METHOD_NAME_DUMP = "LiveUtils.dump";
13852
+ const LIVE_METHOD_NAME_TASK = "LiveUtils.task";
13853
+ const LIVE_METHOD_NAME_GET_STATUS = "LiveUtils.getStatus";
13630
13854
  /**
13631
- * Utility class for live trading operations.
13855
+ * Internal task function that runs live trading and handles completion.
13856
+ * Consumes live trading results and updates instance state flags.
13632
13857
  *
13633
- * Provides simplified access to liveCommandService.run() with logging.
13634
- * Exported as singleton instance for convenient usage.
13858
+ * @param symbol - Trading pair symbol
13859
+ * @param context - Execution context with strategy and exchange names
13860
+ * @param self - LiveInstance reference for state management
13861
+ * @returns Promise that resolves when live trading completes
13635
13862
  *
13636
- * Features:
13637
- * - Infinite async generator (never completes)
13638
- * - Crash recovery via persisted state
13639
- * - Real-time progression with Date.now()
13863
+ * @internal
13864
+ */
13865
+ const INSTANCE_TASK_FN$1 = async (symbol, context, self) => {
13866
+ {
13867
+ self._isStopped = false;
13868
+ self._isDone = false;
13869
+ }
13870
+ for await (const signal of self.run(symbol, context)) {
13871
+ if (signal?.action === "closed" && self._isStopped) {
13872
+ break;
13873
+ }
13874
+ }
13875
+ if (!self._isDone) {
13876
+ await doneLiveSubject.next({
13877
+ exchangeName: context.exchangeName,
13878
+ strategyName: context.strategyName,
13879
+ backtest: false,
13880
+ symbol,
13881
+ });
13882
+ }
13883
+ self._isDone = true;
13884
+ };
13885
+ /**
13886
+ * Instance class for live trading operations on a specific symbol-strategy pair.
13887
+ *
13888
+ * Provides isolated live trading execution and reporting for a single symbol-strategy combination.
13889
+ * Each instance maintains its own state and context.
13640
13890
  *
13641
13891
  * @example
13642
13892
  * ```typescript
13643
- * import { Live } from "./classes/Live";
13893
+ * const instance = new LiveInstance("BTCUSDT", "my-strategy");
13644
13894
  *
13645
- * // Infinite loop - use Ctrl+C to stop
13646
- * for await (const result of Live.run("BTCUSDT", {
13895
+ * for await (const result of instance.run("BTCUSDT", {
13647
13896
  * strategyName: "my-strategy",
13648
- * exchangeName: "my-exchange",
13649
- * frameName: ""
13897
+ * exchangeName: "my-exchange"
13650
13898
  * })) {
13651
- * if (result.action === "opened") {
13652
- * console.log("Signal opened:", result.signal);
13653
- * } else if (result.action === "closed") {
13654
- * console.log("PNL:", result.pnl.pnlPercentage);
13899
+ * if (result.action === "closed") {
13900
+ * console.log("Signal closed, PNL:", result.pnl.pnlPercentage);
13655
13901
  * }
13656
13902
  * }
13657
13903
  * ```
13658
13904
  */
13659
- class LiveUtils {
13660
- constructor() {
13905
+ class LiveInstance {
13906
+ /**
13907
+ * Creates a new LiveInstance for a specific symbol-strategy pair.
13908
+ *
13909
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
13910
+ * @param strategyName - Strategy name for this live trading instance
13911
+ */
13912
+ constructor(symbol, strategyName) {
13913
+ this.symbol = symbol;
13914
+ this.strategyName = strategyName;
13915
+ /** Internal flag indicating if live trading was stopped manually */
13916
+ this._isStopped = false;
13917
+ /** Internal flag indicating if live trading task completed */
13918
+ this._isDone = false;
13919
+ /**
13920
+ * Internal singlerun task that executes the live trading.
13921
+ * Ensures only one live trading run per instance using singlerun wrapper.
13922
+ *
13923
+ * @param symbol - Trading pair symbol
13924
+ * @param context - Execution context with strategy and exchange names
13925
+ * @returns Promise that resolves when live trading completes
13926
+ *
13927
+ * @internal
13928
+ */
13929
+ this.task = singlerun(async (symbol, context) => {
13930
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_TASK, {
13931
+ symbol,
13932
+ context,
13933
+ });
13934
+ return await INSTANCE_TASK_FN$1(symbol, context, this);
13935
+ });
13936
+ /**
13937
+ * Gets the current status of this live trading instance.
13938
+ *
13939
+ * @returns Promise resolving to status object with symbol, strategyName, and task status
13940
+ *
13941
+ * @example
13942
+ * ```typescript
13943
+ * const instance = new LiveInstance("BTCUSDT", "my-strategy");
13944
+ * const status = await instance.getStatus();
13945
+ * console.log(status.status); // "idle", "running", or "done"
13946
+ * ```
13947
+ */
13948
+ this.getStatus = async () => {
13949
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_STATUS);
13950
+ return {
13951
+ symbol: this.symbol,
13952
+ strategyName: this.strategyName,
13953
+ status: this.task.getStatus(),
13954
+ };
13955
+ };
13661
13956
  /**
13662
13957
  * Runs live trading for a symbol with context propagation.
13663
13958
  *
@@ -13699,9 +13994,8 @@ class LiveUtils {
13699
13994
  *
13700
13995
  * @example
13701
13996
  * ```typescript
13702
- * // Run live trading silently in background, only callbacks will fire
13703
- * // This will run forever until Ctrl+C
13704
- * await Live.background("BTCUSDT", {
13997
+ * const instance = new LiveInstance();
13998
+ * const cancel = instance.background("BTCUSDT", {
13705
13999
  * strategyName: "my-strategy",
13706
14000
  * exchangeName: "my-exchange"
13707
14001
  * });
@@ -13712,25 +14006,7 @@ class LiveUtils {
13712
14006
  symbol,
13713
14007
  context,
13714
14008
  });
13715
- let isStopped = false;
13716
- let isDone = false;
13717
- const task = async () => {
13718
- for await (const signal of this.run(symbol, context)) {
13719
- if (signal?.action === "closed" && isStopped) {
13720
- break;
13721
- }
13722
- }
13723
- if (!isDone) {
13724
- await doneLiveSubject.next({
13725
- exchangeName: context.exchangeName,
13726
- strategyName: context.strategyName,
13727
- backtest: false,
13728
- symbol,
13729
- });
13730
- }
13731
- isDone = true;
13732
- };
13733
- task().catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
14009
+ this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
13734
14010
  return () => {
13735
14011
  backtest$1.strategyGlobalService.stop({ symbol, strategyName: context.strategyName }, false);
13736
14012
  backtest$1.strategyGlobalService
@@ -13739,7 +14015,7 @@ class LiveUtils {
13739
14015
  if (pendingSignal) {
13740
14016
  return;
13741
14017
  }
13742
- if (!isDone) {
14018
+ if (!this._isDone) {
13743
14019
  await doneLiveSubject.next({
13744
14020
  exchangeName: context.exchangeName,
13745
14021
  strategyName: context.strategyName,
@@ -13747,11 +14023,179 @@ class LiveUtils {
13747
14023
  symbol,
13748
14024
  });
13749
14025
  }
13750
- isDone = true;
14026
+ this._isDone = true;
13751
14027
  });
13752
- isStopped = true;
14028
+ this._isStopped = true;
13753
14029
  };
13754
14030
  };
14031
+ /**
14032
+ * Stops the strategy from generating new signals.
14033
+ *
14034
+ * Sets internal flag to prevent strategy from opening new signals.
14035
+ * Current active signal (if any) will complete normally.
14036
+ * Live trading will stop at the next safe point (idle/closed state).
14037
+ *
14038
+ * @param symbol - Trading pair symbol
14039
+ * @param strategyName - Strategy name to stop
14040
+ * @returns Promise that resolves when stop flag is set
14041
+ *
14042
+ * @example
14043
+ * ```typescript
14044
+ * const instance = new LiveInstance();
14045
+ * await instance.stop("BTCUSDT", "my-strategy");
14046
+ * ```
14047
+ */
14048
+ this.stop = async (symbol, strategyName) => {
14049
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_STOP, {
14050
+ symbol,
14051
+ strategyName,
14052
+ });
14053
+ await backtest$1.strategyGlobalService.stop({ symbol, strategyName }, false);
14054
+ };
14055
+ /**
14056
+ * Gets statistical data from all live trading events for a symbol-strategy pair.
14057
+ *
14058
+ * @param symbol - Trading pair symbol
14059
+ * @param strategyName - Strategy name to get data for
14060
+ * @returns Promise resolving to statistical data object
14061
+ *
14062
+ * @example
14063
+ * ```typescript
14064
+ * const instance = new LiveInstance();
14065
+ * const stats = await instance.getData("BTCUSDT", "my-strategy");
14066
+ * console.log(stats.sharpeRatio, stats.winRate);
14067
+ * ```
14068
+ */
14069
+ this.getData = async (symbol, strategyName) => {
14070
+ backtest$1.loggerService.info("LiveUtils.getData", {
14071
+ symbol,
14072
+ strategyName,
14073
+ });
14074
+ return await backtest$1.liveMarkdownService.getData(symbol, strategyName);
14075
+ };
14076
+ /**
14077
+ * Generates markdown report with all events for a symbol-strategy pair.
14078
+ *
14079
+ * @param symbol - Trading pair symbol
14080
+ * @param strategyName - Strategy name to generate report for
14081
+ * @returns Promise resolving to markdown formatted report string
14082
+ *
14083
+ * @example
14084
+ * ```typescript
14085
+ * const instance = new LiveInstance();
14086
+ * const markdown = await instance.getReport("BTCUSDT", "my-strategy");
14087
+ * console.log(markdown);
14088
+ * ```
14089
+ */
14090
+ this.getReport = async (symbol, strategyName) => {
14091
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_REPORT, {
14092
+ symbol,
14093
+ strategyName,
14094
+ });
14095
+ return await backtest$1.liveMarkdownService.getReport(symbol, strategyName);
14096
+ };
14097
+ /**
14098
+ * Saves strategy report to disk.
14099
+ *
14100
+ * @param symbol - Trading pair symbol
14101
+ * @param strategyName - Strategy name to save report for
14102
+ * @param path - Optional directory path to save report (default: "./dump/live")
14103
+ *
14104
+ * @example
14105
+ * ```typescript
14106
+ * const instance = new LiveInstance();
14107
+ * // Save to default path: ./dump/live/my-strategy.md
14108
+ * await instance.dump("BTCUSDT", "my-strategy");
14109
+ *
14110
+ * // Save to custom path: ./custom/path/my-strategy.md
14111
+ * await instance.dump("BTCUSDT", "my-strategy", "./custom/path");
14112
+ * ```
14113
+ */
14114
+ this.dump = async (symbol, strategyName, path) => {
14115
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_DUMP, {
14116
+ symbol,
14117
+ strategyName,
14118
+ path,
14119
+ });
14120
+ await backtest$1.liveMarkdownService.dump(symbol, strategyName, path);
14121
+ };
14122
+ }
14123
+ }
14124
+ /**
14125
+ * Utility class for live trading operations.
14126
+ *
14127
+ * Provides simplified access to liveCommandService.run() with logging.
14128
+ * Exported as singleton instance for convenient usage.
14129
+ *
14130
+ * Features:
14131
+ * - Infinite async generator (never completes)
14132
+ * - Crash recovery via persisted state
14133
+ * - Real-time progression with Date.now()
14134
+ *
14135
+ * @example
14136
+ * ```typescript
14137
+ * import { Live } from "./classes/Live";
14138
+ *
14139
+ * // Infinite loop - use Ctrl+C to stop
14140
+ * for await (const result of Live.run("BTCUSDT", {
14141
+ * strategyName: "my-strategy",
14142
+ * exchangeName: "my-exchange",
14143
+ * frameName: ""
14144
+ * })) {
14145
+ * if (result.action === "opened") {
14146
+ * console.log("Signal opened:", result.signal);
14147
+ * } else if (result.action === "closed") {
14148
+ * console.log("PNL:", result.pnl.pnlPercentage);
14149
+ * }
14150
+ * }
14151
+ * ```
14152
+ */
14153
+ class LiveUtils {
14154
+ constructor() {
14155
+ /**
14156
+ * Memoized function to get or create LiveInstance for a symbol-strategy pair.
14157
+ * Each symbol-strategy combination gets its own isolated instance.
14158
+ */
14159
+ this._getInstance = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => new LiveInstance(symbol, strategyName));
14160
+ /**
14161
+ * Runs live trading for a symbol with context propagation.
14162
+ *
14163
+ * Infinite async generator with crash recovery support.
14164
+ * Process can crash and restart - state will be recovered from disk.
14165
+ *
14166
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
14167
+ * @param context - Execution context with strategy and exchange names
14168
+ * @returns Infinite async generator yielding opened and closed signals
14169
+ */
14170
+ this.run = (symbol, context) => {
14171
+ const instance = this._getInstance(symbol, context.strategyName);
14172
+ return instance.run(symbol, context);
14173
+ };
14174
+ /**
14175
+ * Runs live trading in background without yielding results.
14176
+ *
14177
+ * Consumes all live trading results internally without exposing them.
14178
+ * Infinite loop - will run until process is stopped or crashes.
14179
+ * Useful for running live trading for side effects only (callbacks, persistence).
14180
+ *
14181
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
14182
+ * @param context - Execution context with strategy and exchange names
14183
+ * @returns Cancellation closure
14184
+ *
14185
+ * @example
14186
+ * ```typescript
14187
+ * // Run live trading silently in background, only callbacks will fire
14188
+ * // This will run forever until Ctrl+C
14189
+ * await Live.background("BTCUSDT", {
14190
+ * strategyName: "my-strategy",
14191
+ * exchangeName: "my-exchange"
14192
+ * });
14193
+ * ```
14194
+ */
14195
+ this.background = (symbol, context) => {
14196
+ const instance = this._getInstance(symbol, context.strategyName);
14197
+ return instance.background(symbol, context);
14198
+ };
13755
14199
  /**
13756
14200
  * Stops the strategy from generating new signals.
13757
14201
  *
@@ -13770,11 +14214,8 @@ class LiveUtils {
13770
14214
  * ```
13771
14215
  */
13772
14216
  this.stop = async (symbol, strategyName) => {
13773
- backtest$1.loggerService.info(LIVE_METHOD_NAME_STOP, {
13774
- symbol,
13775
- strategyName,
13776
- });
13777
- await backtest$1.strategyGlobalService.stop({ symbol, strategyName }, false);
14217
+ const instance = this._getInstance(symbol, strategyName);
14218
+ return await instance.stop(symbol, strategyName);
13778
14219
  };
13779
14220
  /**
13780
14221
  * Gets statistical data from all live trading events for a symbol-strategy pair.
@@ -13790,11 +14231,8 @@ class LiveUtils {
13790
14231
  * ```
13791
14232
  */
13792
14233
  this.getData = async (symbol, strategyName) => {
13793
- backtest$1.loggerService.info("LiveUtils.getData", {
13794
- symbol,
13795
- strategyName,
13796
- });
13797
- return await backtest$1.liveMarkdownService.getData(symbol, strategyName);
14234
+ const instance = this._getInstance(symbol, strategyName);
14235
+ return await instance.getData(symbol, strategyName);
13798
14236
  };
13799
14237
  /**
13800
14238
  * Generates markdown report with all events for a symbol-strategy pair.
@@ -13810,11 +14248,8 @@ class LiveUtils {
13810
14248
  * ```
13811
14249
  */
13812
14250
  this.getReport = async (symbol, strategyName) => {
13813
- backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_REPORT, {
13814
- symbol,
13815
- strategyName,
13816
- });
13817
- return await backtest$1.liveMarkdownService.getReport(symbol, strategyName);
14251
+ const instance = this._getInstance(symbol, strategyName);
14252
+ return await instance.getReport(symbol, strategyName);
13818
14253
  };
13819
14254
  /**
13820
14255
  * Saves strategy report to disk.
@@ -13833,12 +14268,25 @@ class LiveUtils {
13833
14268
  * ```
13834
14269
  */
13835
14270
  this.dump = async (symbol, strategyName, path) => {
13836
- backtest$1.loggerService.info(LIVE_METHOD_NAME_DUMP, {
13837
- symbol,
13838
- strategyName,
13839
- path,
13840
- });
13841
- await backtest$1.liveMarkdownService.dump(symbol, strategyName, path);
14271
+ const instance = this._getInstance(symbol, strategyName);
14272
+ return await instance.dump(symbol, strategyName, path);
14273
+ };
14274
+ /**
14275
+ * Lists all active live trading instances with their current status.
14276
+ *
14277
+ * @returns Promise resolving to array of status objects for all instances
14278
+ *
14279
+ * @example
14280
+ * ```typescript
14281
+ * const statusList = await Live.list();
14282
+ * statusList.forEach(status => {
14283
+ * console.log(`${status.symbol} - ${status.strategyName}: ${status.status}`);
14284
+ * });
14285
+ * ```
14286
+ */
14287
+ this.list = async () => {
14288
+ const instanceList = this._getInstance.values();
14289
+ return await Promise.all(instanceList.map((instance) => instance.getStatus()));
13842
14290
  };
13843
14291
  }
13844
14292
  }
@@ -14087,27 +14535,108 @@ const WALKER_METHOD_NAME_STOP = "WalkerUtils.stop";
14087
14535
  const WALKER_METHOD_NAME_GET_DATA = "WalkerUtils.getData";
14088
14536
  const WALKER_METHOD_NAME_GET_REPORT = "WalkerUtils.getReport";
14089
14537
  const WALKER_METHOD_NAME_DUMP = "WalkerUtils.dump";
14538
+ const WALKER_METHOD_NAME_TASK = "WalkerUtils.task";
14539
+ const WALKER_METHOD_NAME_GET_STATUS = "WalkerUtils.getStatus";
14090
14540
  /**
14091
- * Utility class for walker operations.
14541
+ * Internal task function that runs walker and handles completion.
14542
+ * Consumes walker results and updates instance state flags.
14092
14543
  *
14093
- * Provides simplified access to walkerCommandService.run() with logging.
14094
- * Automatically pulls exchangeName and frameName from walker schema.
14095
- * Exported as singleton instance for convenient usage.
14544
+ * @param symbol - Trading pair symbol
14545
+ * @param context - Execution context with walker name
14546
+ * @param self - WalkerInstance reference for state management
14547
+ * @returns Promise that resolves when walker completes
14548
+ *
14549
+ * @internal
14550
+ */
14551
+ const INSTANCE_TASK_FN = async (symbol, context, self) => {
14552
+ {
14553
+ self._isStopped = false;
14554
+ self._isDone = false;
14555
+ }
14556
+ for await (const _ of self.run(symbol, context)) {
14557
+ if (self._isStopped) {
14558
+ break;
14559
+ }
14560
+ }
14561
+ if (!self._isDone) {
14562
+ const walkerSchema = backtest$1.walkerSchemaService.get(context.walkerName);
14563
+ await doneWalkerSubject.next({
14564
+ exchangeName: walkerSchema.exchangeName,
14565
+ strategyName: context.walkerName,
14566
+ backtest: true,
14567
+ symbol,
14568
+ });
14569
+ }
14570
+ self._isDone = true;
14571
+ };
14572
+ /**
14573
+ * Instance class for walker operations on a specific symbol-walker pair.
14574
+ *
14575
+ * Provides isolated walker execution and reporting for a single symbol-walker combination.
14576
+ * Each instance maintains its own state and context.
14096
14577
  *
14097
14578
  * @example
14098
14579
  * ```typescript
14099
- * import { Walker } from "./classes/Walker";
14580
+ * const instance = new WalkerInstance("BTCUSDT", "my-walker");
14100
14581
  *
14101
- * for await (const result of Walker.run("BTCUSDT", {
14582
+ * for await (const result of instance.run("BTCUSDT", {
14102
14583
  * walkerName: "my-walker"
14103
14584
  * })) {
14104
14585
  * console.log("Progress:", result.strategiesTested, "/", result.totalStrategies);
14105
- * console.log("Best strategy:", result.bestStrategy, result.bestMetric);
14106
14586
  * }
14107
14587
  * ```
14108
14588
  */
14109
- class WalkerUtils {
14110
- constructor() {
14589
+ class WalkerInstance {
14590
+ /**
14591
+ * Creates a new WalkerInstance for a specific symbol-walker pair.
14592
+ *
14593
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
14594
+ * @param walkerName - Walker name for this walker instance
14595
+ */
14596
+ constructor(symbol, walkerName) {
14597
+ this.symbol = symbol;
14598
+ this.walkerName = walkerName;
14599
+ /** Internal flag indicating if walker was stopped manually */
14600
+ this._isStopped = false;
14601
+ /** Internal flag indicating if walker task completed */
14602
+ this._isDone = false;
14603
+ /**
14604
+ * Internal singlerun task that executes the walker.
14605
+ * Ensures only one walker run per instance using singlerun wrapper.
14606
+ *
14607
+ * @param symbol - Trading pair symbol
14608
+ * @param context - Execution context with walker name
14609
+ * @returns Promise that resolves when walker completes
14610
+ *
14611
+ * @internal
14612
+ */
14613
+ this.task = singlerun(async (symbol, context) => {
14614
+ backtest$1.loggerService.info(WALKER_METHOD_NAME_TASK, {
14615
+ symbol,
14616
+ context,
14617
+ });
14618
+ return await INSTANCE_TASK_FN(symbol, context, this);
14619
+ });
14620
+ /**
14621
+ * Gets the current status of this walker instance.
14622
+ *
14623
+ * @returns Promise resolving to status object with symbol, walkerName, and task status
14624
+ *
14625
+ * @example
14626
+ * ```typescript
14627
+ * const instance = new WalkerInstance("BTCUSDT", "my-walker");
14628
+ * const status = await instance.getStatus();
14629
+ * console.log(status.status); // "idle", "running", or "done"
14630
+ * ```
14631
+ */
14632
+ this.getStatus = async () => {
14633
+ backtest$1.loggerService.info(WALKER_METHOD_NAME_GET_STATUS);
14634
+ return {
14635
+ symbol: this.symbol,
14636
+ walkerName: this.walkerName,
14637
+ status: this.task.getStatus(),
14638
+ };
14639
+ };
14111
14640
  /**
14112
14641
  * Runs walker comparison for a symbol with context propagation.
14113
14642
  *
@@ -14160,11 +14689,10 @@ class WalkerUtils {
14160
14689
  *
14161
14690
  * @example
14162
14691
  * ```typescript
14163
- * // Run walker silently, only callbacks will fire
14164
- * await Walker.background("BTCUSDT", {
14692
+ * const instance = new WalkerInstance();
14693
+ * const cancel = instance.background("BTCUSDT", {
14165
14694
  * walkerName: "my-walker"
14166
14695
  * });
14167
- * console.log("Walker comparison completed");
14168
14696
  * ```
14169
14697
  */
14170
14698
  this.background = (symbol, context) => {
@@ -14173,31 +14701,13 @@ class WalkerUtils {
14173
14701
  context,
14174
14702
  });
14175
14703
  const walkerSchema = backtest$1.walkerSchemaService.get(context.walkerName);
14176
- let isStopped = false;
14177
- let isDone = false;
14178
- const task = async () => {
14179
- for await (const _ of this.run(symbol, context)) {
14180
- if (isStopped) {
14181
- break;
14182
- }
14183
- }
14184
- if (!isDone) {
14185
- await doneWalkerSubject.next({
14186
- exchangeName: walkerSchema.exchangeName,
14187
- strategyName: context.walkerName,
14188
- backtest: true,
14189
- symbol,
14190
- });
14191
- }
14192
- isDone = true;
14193
- };
14194
- task().catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
14704
+ this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
14195
14705
  return () => {
14196
14706
  for (const strategyName of walkerSchema.strategies) {
14197
14707
  backtest$1.strategyGlobalService.stop({ symbol, strategyName }, true);
14198
14708
  walkerStopSubject.next({ symbol, strategyName, walkerName: context.walkerName });
14199
14709
  }
14200
- if (!isDone) {
14710
+ if (!this._isDone) {
14201
14711
  doneWalkerSubject.next({
14202
14712
  exchangeName: walkerSchema.exchangeName,
14203
14713
  strategyName: context.walkerName,
@@ -14205,8 +14715,8 @@ class WalkerUtils {
14205
14715
  symbol,
14206
14716
  });
14207
14717
  }
14208
- isDone = true;
14209
- isStopped = true;
14718
+ this._isDone = true;
14719
+ this._isStopped = true;
14210
14720
  };
14211
14721
  };
14212
14722
  /**
@@ -14228,8 +14738,8 @@ class WalkerUtils {
14228
14738
  *
14229
14739
  * @example
14230
14740
  * ```typescript
14231
- * // Stop walker and all its strategies
14232
- * await Walker.stop("BTCUSDT", "my-walker");
14741
+ * const instance = new WalkerInstance();
14742
+ * await instance.stop("BTCUSDT", "my-walker");
14233
14743
  * ```
14234
14744
  */
14235
14745
  this.stop = async (symbol, walkerName) => {
@@ -14252,7 +14762,8 @@ class WalkerUtils {
14252
14762
  *
14253
14763
  * @example
14254
14764
  * ```typescript
14255
- * const results = await Walker.getData("BTCUSDT", "my-walker");
14765
+ * const instance = new WalkerInstance();
14766
+ * const results = await instance.getData("BTCUSDT", "my-walker");
14256
14767
  * console.log(results.bestStrategy, results.bestMetric);
14257
14768
  * ```
14258
14769
  */
@@ -14276,7 +14787,8 @@ class WalkerUtils {
14276
14787
  *
14277
14788
  * @example
14278
14789
  * ```typescript
14279
- * const markdown = await Walker.getReport("BTCUSDT", "my-walker");
14790
+ * const instance = new WalkerInstance();
14791
+ * const markdown = await instance.getReport("BTCUSDT", "my-walker");
14280
14792
  * console.log(markdown);
14281
14793
  * ```
14282
14794
  */
@@ -14300,11 +14812,12 @@ class WalkerUtils {
14300
14812
  *
14301
14813
  * @example
14302
14814
  * ```typescript
14815
+ * const instance = new WalkerInstance();
14303
14816
  * // Save to default path: ./dump/walker/my-walker.md
14304
- * await Walker.dump("BTCUSDT", "my-walker");
14817
+ * await instance.dump("BTCUSDT", "my-walker");
14305
14818
  *
14306
14819
  * // Save to custom path: ./custom/path/my-walker.md
14307
- * await Walker.dump("BTCUSDT", "my-walker", "./custom/path");
14820
+ * await instance.dump("BTCUSDT", "my-walker", "./custom/path");
14308
14821
  * ```
14309
14822
  */
14310
14823
  this.dump = async (symbol, walkerName, path) => {
@@ -14321,6 +14834,166 @@ class WalkerUtils {
14321
14834
  };
14322
14835
  }
14323
14836
  }
14837
+ /**
14838
+ * Utility class for walker operations.
14839
+ *
14840
+ * Provides simplified access to walkerCommandService.run() with logging.
14841
+ * Automatically pulls exchangeName and frameName from walker schema.
14842
+ * Exported as singleton instance for convenient usage.
14843
+ *
14844
+ * @example
14845
+ * ```typescript
14846
+ * import { Walker } from "./classes/Walker";
14847
+ *
14848
+ * for await (const result of Walker.run("BTCUSDT", {
14849
+ * walkerName: "my-walker"
14850
+ * })) {
14851
+ * console.log("Progress:", result.strategiesTested, "/", result.totalStrategies);
14852
+ * console.log("Best strategy:", result.bestStrategy, result.bestMetric);
14853
+ * }
14854
+ * ```
14855
+ */
14856
+ class WalkerUtils {
14857
+ constructor() {
14858
+ /**
14859
+ * Memoized function to get or create WalkerInstance for a symbol-walker pair.
14860
+ * Each symbol-walker combination gets its own isolated instance.
14861
+ */
14862
+ this._getInstance = memoize(([symbol, walkerName]) => `${symbol}:${walkerName}`, (symbol, walkerName) => new WalkerInstance(symbol, walkerName));
14863
+ /**
14864
+ * Runs walker comparison for a symbol with context propagation.
14865
+ *
14866
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
14867
+ * @param context - Execution context with walker name
14868
+ * @returns Async generator yielding progress updates after each strategy
14869
+ */
14870
+ this.run = (symbol, context) => {
14871
+ const instance = this._getInstance(symbol, context.walkerName);
14872
+ return instance.run(symbol, context);
14873
+ };
14874
+ /**
14875
+ * Runs walker comparison in background without yielding results.
14876
+ *
14877
+ * Consumes all walker progress updates internally without exposing them.
14878
+ * Useful for running walker comparison for side effects only (callbacks, logging).
14879
+ *
14880
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
14881
+ * @param context - Execution context with walker name
14882
+ * @returns Cancellation closure
14883
+ *
14884
+ * @example
14885
+ * ```typescript
14886
+ * // Run walker silently, only callbacks will fire
14887
+ * await Walker.background("BTCUSDT", {
14888
+ * walkerName: "my-walker"
14889
+ * });
14890
+ * console.log("Walker comparison completed");
14891
+ * ```
14892
+ */
14893
+ this.background = (symbol, context) => {
14894
+ const instance = this._getInstance(symbol, context.walkerName);
14895
+ return instance.background(symbol, context);
14896
+ };
14897
+ /**
14898
+ * Stops all strategies in the walker from generating new signals.
14899
+ *
14900
+ * Iterates through all strategies defined in walker schema and:
14901
+ * 1. Sends stop signal via walkerStopSubject (interrupts current running strategy)
14902
+ * 2. Sets internal stop flag for each strategy (prevents new signals)
14903
+ *
14904
+ * Current active signals (if any) will complete normally.
14905
+ * Walker will stop at the next safe point.
14906
+ *
14907
+ * Supports multiple walkers running on the same symbol simultaneously.
14908
+ * Stop signal is filtered by walkerName to prevent interference.
14909
+ *
14910
+ * @param symbol - Trading pair symbol
14911
+ * @param walkerName - Walker name to stop
14912
+ * @returns Promise that resolves when all stop flags are set
14913
+ *
14914
+ * @example
14915
+ * ```typescript
14916
+ * // Stop walker and all its strategies
14917
+ * await Walker.stop("BTCUSDT", "my-walker");
14918
+ * ```
14919
+ */
14920
+ this.stop = async (symbol, walkerName) => {
14921
+ const instance = this._getInstance(symbol, walkerName);
14922
+ return await instance.stop(symbol, walkerName);
14923
+ };
14924
+ /**
14925
+ * Gets walker results data from all strategy comparisons.
14926
+ *
14927
+ * @param symbol - Trading symbol
14928
+ * @param walkerName - Walker name to get data for
14929
+ * @returns Promise resolving to walker results data object
14930
+ *
14931
+ * @example
14932
+ * ```typescript
14933
+ * const results = await Walker.getData("BTCUSDT", "my-walker");
14934
+ * console.log(results.bestStrategy, results.bestMetric);
14935
+ * ```
14936
+ */
14937
+ this.getData = async (symbol, walkerName) => {
14938
+ const instance = this._getInstance(symbol, walkerName);
14939
+ return await instance.getData(symbol, walkerName);
14940
+ };
14941
+ /**
14942
+ * Generates markdown report with all strategy comparisons for a walker.
14943
+ *
14944
+ * @param symbol - Trading symbol
14945
+ * @param walkerName - Walker name to generate report for
14946
+ * @returns Promise resolving to markdown formatted report string
14947
+ *
14948
+ * @example
14949
+ * ```typescript
14950
+ * const markdown = await Walker.getReport("BTCUSDT", "my-walker");
14951
+ * console.log(markdown);
14952
+ * ```
14953
+ */
14954
+ this.getReport = async (symbol, walkerName) => {
14955
+ const instance = this._getInstance(symbol, walkerName);
14956
+ return await instance.getReport(symbol, walkerName);
14957
+ };
14958
+ /**
14959
+ * Saves walker report to disk.
14960
+ *
14961
+ * @param symbol - Trading symbol
14962
+ * @param walkerName - Walker name to save report for
14963
+ * @param path - Optional directory path to save report (default: "./dump/walker")
14964
+ *
14965
+ * @example
14966
+ * ```typescript
14967
+ * // Save to default path: ./dump/walker/my-walker.md
14968
+ * await Walker.dump("BTCUSDT", "my-walker");
14969
+ *
14970
+ * // Save to custom path: ./custom/path/my-walker.md
14971
+ * await Walker.dump("BTCUSDT", "my-walker", "./custom/path");
14972
+ * ```
14973
+ */
14974
+ this.dump = async (symbol, walkerName, path) => {
14975
+ const instance = this._getInstance(symbol, walkerName);
14976
+ return await instance.dump(symbol, walkerName, path);
14977
+ };
14978
+ /**
14979
+ * Lists all active walker instances with their current status.
14980
+ *
14981
+ * @returns Promise resolving to array of status objects for all instances
14982
+ *
14983
+ * @example
14984
+ * ```typescript
14985
+ * const statusList = await Walker.list();
14986
+ * statusList.forEach(status => {
14987
+ * console.log(`${status.symbol} - ${status.walkerName}: ${status.status}`);
14988
+ * });
14989
+ * ```
14990
+ */
14991
+ this.list = async () => {
14992
+ const instanceList = this._getInstance.values();
14993
+ return await Promise.all(instanceList.map((instance) => instance.getStatus()));
14994
+ };
14995
+ }
14996
+ }
14324
14997
  /**
14325
14998
  * Singleton instance of WalkerUtils for convenient walker operations.
14326
14999
  *