backtest-kit 1.6.9 → 1.7.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.
Files changed (4) hide show
  1. package/build/index.cjs +981 -567
  2. package/build/index.mjs +981 -567
  3. package/package.json +1 -1
  4. package/types.d.ts +1002 -653
package/build/index.cjs CHANGED
@@ -2095,6 +2095,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
2095
2095
  symbol: self.params.execution.context.symbol,
2096
2096
  strategyName: self.params.method.context.strategyName,
2097
2097
  exchangeName: self.params.method.context.exchangeName,
2098
+ frameName: self.params.method.context.frameName,
2098
2099
  currentPrice,
2099
2100
  timestamp: currentTime,
2100
2101
  }))) {
@@ -2121,6 +2122,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
2121
2122
  symbol: self.params.execution.context.symbol,
2122
2123
  exchangeName: self.params.method.context.exchangeName,
2123
2124
  strategyName: self.params.method.context.strategyName,
2125
+ frameName: self.params.method.context.frameName,
2124
2126
  scheduledAt: currentTime,
2125
2127
  pendingAt: currentTime, // Для immediate signal оба времени одинаковые
2126
2128
  _isScheduled: false,
@@ -2141,6 +2143,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
2141
2143
  symbol: self.params.execution.context.symbol,
2142
2144
  exchangeName: self.params.method.context.exchangeName,
2143
2145
  strategyName: self.params.method.context.strategyName,
2146
+ frameName: self.params.method.context.frameName,
2144
2147
  scheduledAt: currentTime,
2145
2148
  pendingAt: currentTime, // Временно, обновится при активации
2146
2149
  _isScheduled: true,
@@ -2157,6 +2160,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
2157
2160
  symbol: self.params.execution.context.symbol,
2158
2161
  exchangeName: self.params.method.context.exchangeName,
2159
2162
  strategyName: self.params.method.context.strategyName,
2163
+ frameName: self.params.method.context.frameName,
2160
2164
  scheduledAt: currentTime,
2161
2165
  pendingAt: currentTime, // Для immediate signal оба времени одинаковые
2162
2166
  _isScheduled: false,
@@ -2250,6 +2254,7 @@ const CHECK_SCHEDULED_SIGNAL_TIMEOUT_FN = async (self, scheduled, currentPrice)
2250
2254
  closeTimestamp: currentTime,
2251
2255
  strategyName: self.params.method.context.strategyName,
2252
2256
  exchangeName: self.params.method.context.exchangeName,
2257
+ frameName: self.params.method.context.frameName,
2253
2258
  symbol: self.params.execution.context.symbol,
2254
2259
  backtest: self.params.execution.context.backtest,
2255
2260
  reason: "timeout",
@@ -2307,6 +2312,7 @@ const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPr
2307
2312
  closeTimestamp: self.params.execution.context.when.getTime(),
2308
2313
  strategyName: self.params.method.context.strategyName,
2309
2314
  exchangeName: self.params.method.context.exchangeName,
2315
+ frameName: self.params.method.context.frameName,
2310
2316
  symbol: self.params.execution.context.symbol,
2311
2317
  backtest: self.params.execution.context.backtest,
2312
2318
  reason: "price_reject",
@@ -2345,6 +2351,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
2345
2351
  pendingSignal: scheduled,
2346
2352
  strategyName: self.params.method.context.strategyName,
2347
2353
  exchangeName: self.params.method.context.exchangeName,
2354
+ frameName: self.params.method.context.frameName,
2348
2355
  currentPrice: scheduled.priceOpen,
2349
2356
  timestamp: activationTime,
2350
2357
  }))) {
@@ -2366,6 +2373,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
2366
2373
  await self.params.risk.addSignal(self.params.execution.context.symbol, {
2367
2374
  strategyName: self.params.method.context.strategyName,
2368
2375
  riskName: self.params.riskName,
2376
+ exchangeName: self.params.method.context.exchangeName,
2377
+ frameName: self.params.method.context.frameName,
2369
2378
  });
2370
2379
  if (self.params.callbacks?.onOpen) {
2371
2380
  self.params.callbacks.onOpen(self.params.execution.context.symbol, self._pendingSignal, self._pendingSignal.priceOpen, self.params.execution.context.backtest);
@@ -2375,6 +2384,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
2375
2384
  signal: self._pendingSignal,
2376
2385
  strategyName: self.params.method.context.strategyName,
2377
2386
  exchangeName: self.params.method.context.exchangeName,
2387
+ frameName: self.params.method.context.frameName,
2378
2388
  symbol: self.params.execution.context.symbol,
2379
2389
  currentPrice: self._pendingSignal.priceOpen,
2380
2390
  backtest: self.params.execution.context.backtest,
@@ -2411,6 +2421,7 @@ const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice)
2411
2421
  currentPrice: currentPrice,
2412
2422
  strategyName: self.params.method.context.strategyName,
2413
2423
  exchangeName: self.params.method.context.exchangeName,
2424
+ frameName: self.params.method.context.frameName,
2414
2425
  symbol: self.params.execution.context.symbol,
2415
2426
  percentTp: 0,
2416
2427
  percentSl: 0,
@@ -2438,6 +2449,7 @@ const OPEN_NEW_SCHEDULED_SIGNAL_FN = async (self, signal) => {
2438
2449
  signal: signal,
2439
2450
  strategyName: self.params.method.context.strategyName,
2440
2451
  exchangeName: self.params.method.context.exchangeName,
2452
+ frameName: self.params.method.context.frameName,
2441
2453
  symbol: self.params.execution.context.symbol,
2442
2454
  currentPrice: currentPrice,
2443
2455
  backtest: self.params.execution.context.backtest,
@@ -2453,6 +2465,7 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
2453
2465
  symbol: self.params.execution.context.symbol,
2454
2466
  strategyName: self.params.method.context.strategyName,
2455
2467
  exchangeName: self.params.method.context.exchangeName,
2468
+ frameName: self.params.method.context.frameName,
2456
2469
  currentPrice: signal.priceOpen,
2457
2470
  timestamp: self.params.execution.context.when.getTime(),
2458
2471
  }))) {
@@ -2461,6 +2474,8 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
2461
2474
  await self.params.risk.addSignal(self.params.execution.context.symbol, {
2462
2475
  strategyName: self.params.method.context.strategyName,
2463
2476
  riskName: self.params.riskName,
2477
+ exchangeName: self.params.method.context.exchangeName,
2478
+ frameName: self.params.method.context.frameName,
2464
2479
  });
2465
2480
  if (self.params.callbacks?.onOpen) {
2466
2481
  self.params.callbacks.onOpen(self.params.execution.context.symbol, signal, signal.priceOpen, self.params.execution.context.backtest);
@@ -2470,6 +2485,7 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
2470
2485
  signal: signal,
2471
2486
  strategyName: self.params.method.context.strategyName,
2472
2487
  exchangeName: self.params.method.context.exchangeName,
2488
+ frameName: self.params.method.context.frameName,
2473
2489
  symbol: self.params.execution.context.symbol,
2474
2490
  currentPrice: signal.priceOpen,
2475
2491
  backtest: self.params.execution.context.backtest,
@@ -2525,6 +2541,8 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
2525
2541
  await self.params.risk.removeSignal(self.params.execution.context.symbol, {
2526
2542
  strategyName: self.params.method.context.strategyName,
2527
2543
  riskName: self.params.riskName,
2544
+ exchangeName: self.params.method.context.exchangeName,
2545
+ frameName: self.params.method.context.frameName,
2528
2546
  });
2529
2547
  await self.setPendingSignal(null);
2530
2548
  const result = {
@@ -2536,6 +2554,7 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
2536
2554
  pnl: pnl,
2537
2555
  strategyName: self.params.method.context.strategyName,
2538
2556
  exchangeName: self.params.method.context.exchangeName,
2557
+ frameName: self.params.method.context.frameName,
2539
2558
  symbol: self.params.execution.context.symbol,
2540
2559
  backtest: self.params.execution.context.backtest,
2541
2560
  };
@@ -2604,6 +2623,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice) => {
2604
2623
  currentPrice: currentPrice,
2605
2624
  strategyName: self.params.method.context.strategyName,
2606
2625
  exchangeName: self.params.method.context.exchangeName,
2626
+ frameName: self.params.method.context.frameName,
2607
2627
  symbol: self.params.execution.context.symbol,
2608
2628
  percentTp,
2609
2629
  percentSl,
@@ -2623,6 +2643,7 @@ const RETURN_IDLE_FN = async (self, currentPrice) => {
2623
2643
  signal: null,
2624
2644
  strategyName: self.params.method.context.strategyName,
2625
2645
  exchangeName: self.params.method.context.exchangeName,
2646
+ frameName: self.params.method.context.frameName,
2626
2647
  symbol: self.params.execution.context.symbol,
2627
2648
  currentPrice: currentPrice,
2628
2649
  backtest: self.params.execution.context.backtest,
@@ -2652,6 +2673,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
2652
2673
  closeTimestamp: closeTimestamp,
2653
2674
  strategyName: self.params.method.context.strategyName,
2654
2675
  exchangeName: self.params.method.context.exchangeName,
2676
+ frameName: self.params.method.context.frameName,
2655
2677
  symbol: self.params.execution.context.symbol,
2656
2678
  backtest: self.params.execution.context.backtest,
2657
2679
  reason,
@@ -2687,6 +2709,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
2687
2709
  symbol: self.params.execution.context.symbol,
2688
2710
  strategyName: self.params.method.context.strategyName,
2689
2711
  exchangeName: self.params.method.context.exchangeName,
2712
+ frameName: self.params.method.context.frameName,
2690
2713
  currentPrice: scheduled.priceOpen,
2691
2714
  timestamp: activationTime,
2692
2715
  }))) {
@@ -2708,6 +2731,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
2708
2731
  await self.params.risk.addSignal(self.params.execution.context.symbol, {
2709
2732
  strategyName: self.params.method.context.strategyName,
2710
2733
  riskName: self.params.riskName,
2734
+ exchangeName: self.params.method.context.exchangeName,
2735
+ frameName: self.params.method.context.frameName,
2711
2736
  });
2712
2737
  if (self.params.callbacks?.onOpen) {
2713
2738
  self.params.callbacks.onOpen(self.params.execution.context.symbol, activatedSignal, activatedSignal.priceOpen, self.params.execution.context.backtest);
@@ -2738,6 +2763,8 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
2738
2763
  await self.params.risk.removeSignal(self.params.execution.context.symbol, {
2739
2764
  strategyName: self.params.method.context.strategyName,
2740
2765
  riskName: self.params.riskName,
2766
+ exchangeName: self.params.method.context.exchangeName,
2767
+ frameName: self.params.method.context.frameName,
2741
2768
  });
2742
2769
  await self.setPendingSignal(null);
2743
2770
  const result = {
@@ -2749,6 +2776,7 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
2749
2776
  pnl: pnl,
2750
2777
  strategyName: self.params.method.context.strategyName,
2751
2778
  exchangeName: self.params.method.context.exchangeName,
2779
+ frameName: self.params.method.context.frameName,
2752
2780
  symbol: self.params.execution.context.symbol,
2753
2781
  backtest: self.params.execution.context.backtest,
2754
2782
  };
@@ -3045,10 +3073,9 @@ class ClientStrategy {
3045
3073
  * If no signal is pending, returns null.
3046
3074
  * @returns Promise resolving to the pending signal or null.
3047
3075
  */
3048
- async getPendingSignal(symbol, strategyName) {
3076
+ async getPendingSignal(symbol) {
3049
3077
  this.params.logger.debug("ClientStrategy getPendingSignal", {
3050
3078
  symbol,
3051
- strategyName,
3052
3079
  });
3053
3080
  return this._pendingSignal;
3054
3081
  }
@@ -3057,10 +3084,9 @@ class ClientStrategy {
3057
3084
  * If no scheduled signal exists, returns null.
3058
3085
  * @returns Promise resolving to the scheduled signal or null.
3059
3086
  */
3060
- async getScheduledSignal(symbol, strategyName) {
3087
+ async getScheduledSignal(symbol) {
3061
3088
  this.params.logger.debug("ClientStrategy getScheduledSignal", {
3062
3089
  symbol,
3063
- strategyName,
3064
3090
  });
3065
3091
  return this._scheduledSignal;
3066
3092
  }
@@ -3071,13 +3097,12 @@ class ClientStrategy {
3071
3097
  * not continue processing new ticks or signals.
3072
3098
  *
3073
3099
  * @param symbol - Trading pair symbol
3074
- * @param strategyName - Name of the strategy
3075
3100
  * @returns Promise resolving to true if strategy is stopped, false otherwise
3076
3101
  */
3077
- async getStopped(symbol, strategyName) {
3102
+ async getStopped(symbol) {
3078
3103
  this.params.logger.debug("ClientStrategy getStopped", {
3079
3104
  symbol,
3080
- strategyName,
3105
+ strategyName: this.params.method.context.strategyName,
3081
3106
  });
3082
3107
  return this._isStopped;
3083
3108
  }
@@ -3143,6 +3168,7 @@ class ClientStrategy {
3143
3168
  closeTimestamp: currentTime,
3144
3169
  strategyName: this.params.method.context.strategyName,
3145
3170
  exchangeName: this.params.method.context.exchangeName,
3171
+ frameName: this.params.method.context.frameName,
3146
3172
  symbol: this.params.execution.context.symbol,
3147
3173
  backtest: this.params.execution.context.backtest,
3148
3174
  reason: "user",
@@ -3256,6 +3282,7 @@ class ClientStrategy {
3256
3282
  closeTimestamp: this.params.execution.context.when.getTime(),
3257
3283
  strategyName: this.params.method.context.strategyName,
3258
3284
  exchangeName: this.params.method.context.exchangeName,
3285
+ frameName: this.params.method.context.frameName,
3259
3286
  symbol: this.params.execution.context.symbol,
3260
3287
  backtest: true,
3261
3288
  reason: "user",
@@ -3318,6 +3345,7 @@ class ClientStrategy {
3318
3345
  percentTp: 0,
3319
3346
  strategyName: this.params.method.context.strategyName,
3320
3347
  exchangeName: this.params.method.context.exchangeName,
3348
+ frameName: this.params.method.context.frameName,
3321
3349
  symbol: this.params.execution.context.symbol,
3322
3350
  backtest: this.params.execution.context.backtest,
3323
3351
  };
@@ -3374,13 +3402,11 @@ class ClientStrategy {
3374
3402
  * // Existing signal will continue until natural close
3375
3403
  * ```
3376
3404
  */
3377
- async stop(symbol, strategyName, backtest) {
3405
+ async stop(symbol) {
3378
3406
  this.params.logger.debug("ClientStrategy stop", {
3379
3407
  symbol,
3380
- strategyName,
3381
3408
  hasPendingSignal: this._pendingSignal !== null,
3382
3409
  hasScheduledSignal: this._scheduledSignal !== null,
3383
- backtest,
3384
3410
  });
3385
3411
  this._isStopped = true;
3386
3412
  // Clear scheduled signal if exists
@@ -3388,10 +3414,10 @@ class ClientStrategy {
3388
3414
  return;
3389
3415
  }
3390
3416
  this._scheduledSignal = null;
3391
- if (backtest) {
3417
+ if (this.params.execution.context.backtest) {
3392
3418
  return;
3393
3419
  }
3394
- await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
3420
+ await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
3395
3421
  }
3396
3422
  /**
3397
3423
  * Cancels the scheduled signal without stopping the strategy.
@@ -3414,12 +3440,12 @@ class ClientStrategy {
3414
3440
  * // Strategy continues, can generate new signals
3415
3441
  * ```
3416
3442
  */
3417
- async cancel(symbol, strategyName, backtest, cancelId) {
3443
+ async cancel(symbol, cancelId) {
3418
3444
  this.params.logger.debug("ClientStrategy cancel", {
3419
3445
  symbol,
3420
- strategyName,
3446
+ strategyName: this.params.method.context.strategyName,
3421
3447
  hasScheduledSignal: this._scheduledSignal !== null,
3422
- backtest,
3448
+ backtest: this.params.execution.context.backtest,
3423
3449
  cancelId,
3424
3450
  });
3425
3451
  // Save cancelled signal for next tick to emit cancelled event
@@ -3429,10 +3455,10 @@ class ClientStrategy {
3429
3455
  });
3430
3456
  this._scheduledSignal = null;
3431
3457
  }
3432
- if (backtest) {
3458
+ if (this.params.execution.context.backtest) {
3433
3459
  return;
3434
3460
  }
3435
- await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
3461
+ await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
3436
3462
  }
3437
3463
  }
3438
3464
 
@@ -3508,7 +3534,7 @@ class MergeRisk {
3508
3534
  * Used to track active positions across all risk management systems.
3509
3535
  *
3510
3536
  * @param symbol - Trading pair symbol
3511
- * @param context - Context with strategyName and riskName
3537
+ * @param context - Context with strategyName, riskName, exchangeName and frameName
3512
3538
  * @returns Promise that resolves when all risks have registered the signal
3513
3539
  */
3514
3540
  async addSignal(symbol, context) {
@@ -3525,7 +3551,7 @@ class MergeRisk {
3525
3551
  * Used to update risk state when a position closes.
3526
3552
  *
3527
3553
  * @param symbol - Trading pair symbol
3528
- * @param context - Context with strategyName and riskName
3554
+ * @param context - Context with strategyName, riskName, exchangeName and frameName
3529
3555
  * @returns Promise that resolves when all risks have removed the signal
3530
3556
  */
3531
3557
  async removeSignal(symbol, context) {
@@ -3597,20 +3623,20 @@ class RiskUtils {
3597
3623
  * }
3598
3624
  * ```
3599
3625
  */
3600
- this.getData = async (symbol, strategyName, backtest = false) => {
3626
+ this.getData = async (symbol, context, backtest = false) => {
3601
3627
  backtest$1.loggerService.info(RISK_METHOD_NAME_GET_DATA, {
3602
3628
  symbol,
3603
- strategyName,
3629
+ strategyName: context.strategyName,
3604
3630
  });
3605
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_DATA);
3631
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_DATA);
3606
3632
  {
3607
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3633
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3608
3634
  riskName &&
3609
3635
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA);
3610
3636
  riskList &&
3611
3637
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
3612
3638
  }
3613
- return await backtest$1.riskMarkdownService.getData(symbol, strategyName, backtest);
3639
+ return await backtest$1.riskMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3614
3640
  };
3615
3641
  /**
3616
3642
  * Generates markdown report with all risk rejection events for a symbol-strategy pair.
@@ -3653,20 +3679,20 @@ class RiskUtils {
3653
3679
  * // - my-strategy: 1
3654
3680
  * ```
3655
3681
  */
3656
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
3682
+ this.getReport = async (symbol, context, backtest = false, columns) => {
3657
3683
  backtest$1.loggerService.info(RISK_METHOD_NAME_GET_REPORT, {
3658
3684
  symbol,
3659
- strategyName,
3685
+ strategyName: context.strategyName,
3660
3686
  });
3661
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_REPORT);
3687
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_REPORT);
3662
3688
  {
3663
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3689
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3664
3690
  riskName &&
3665
3691
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT);
3666
3692
  riskList &&
3667
3693
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
3668
3694
  }
3669
- return await backtest$1.riskMarkdownService.getReport(symbol, strategyName, backtest, columns);
3695
+ return await backtest$1.riskMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
3670
3696
  };
3671
3697
  /**
3672
3698
  * Generates and saves markdown report to file.
@@ -3700,21 +3726,21 @@ class RiskUtils {
3700
3726
  * }
3701
3727
  * ```
3702
3728
  */
3703
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
3729
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
3704
3730
  backtest$1.loggerService.info(RISK_METHOD_NAME_DUMP, {
3705
3731
  symbol,
3706
- strategyName,
3732
+ strategyName: context.strategyName,
3707
3733
  path,
3708
3734
  });
3709
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_DUMP);
3735
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_DUMP);
3710
3736
  {
3711
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3737
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3712
3738
  riskName &&
3713
3739
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP);
3714
3740
  riskList &&
3715
3741
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
3716
3742
  }
3717
- await backtest$1.riskMarkdownService.dump(symbol, strategyName, backtest, path, columns);
3743
+ await backtest$1.riskMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
3718
3744
  };
3719
3745
  }
3720
3746
  }
@@ -3747,10 +3773,12 @@ const NOOP_RISK = {
3747
3773
  * Determines the appropriate IRisk instance based on provided riskName and riskList.
3748
3774
  * @param dto - Object containing riskName and riskList
3749
3775
  * @param backtest - Whether running in backtest mode
3776
+ * @param exchangeName - Exchange name for risk isolation
3777
+ * @param frameName - Frame name for risk isolation
3750
3778
  * @param self - Reference to StrategyConnectionService instance
3751
3779
  * @returns Configured IRisk instance (single or merged)
3752
3780
  */
3753
- const GET_RISK_FN = (dto, backtest, self) => {
3781
+ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
3754
3782
  const hasRiskName = !!dto.riskName;
3755
3783
  const hasRiskList = !!dto.riskList?.length;
3756
3784
  // Нет ни riskName, ни riskList
@@ -3759,27 +3787,35 @@ const GET_RISK_FN = (dto, backtest, self) => {
3759
3787
  }
3760
3788
  // Есть только riskName (без riskList)
3761
3789
  if (hasRiskName && !hasRiskList) {
3762
- return self.riskConnectionService.getRisk(dto.riskName, backtest);
3790
+ return self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest);
3763
3791
  }
3764
3792
  // Есть только riskList (без riskName)
3765
3793
  if (!hasRiskName && hasRiskList) {
3766
- return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)));
3794
+ return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)));
3767
3795
  }
3768
3796
  // Есть и riskName, и riskList - объединяем (riskName в начало)
3769
3797
  return new MergeRisk([
3770
- self.riskConnectionService.getRisk(dto.riskName, backtest),
3771
- ...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
3798
+ self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest),
3799
+ ...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)),
3772
3800
  ]);
3773
3801
  };
3774
3802
  /**
3775
3803
  * Creates a unique key for memoizing ClientStrategy instances.
3776
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
3804
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
3777
3805
  * @param symbol - Trading pair symbol
3778
3806
  * @param strategyName - Name of the strategy
3807
+ * @param exchangeName - Exchange name
3808
+ * @param frameName - Frame name (empty string for live)
3779
3809
  * @param backtest - Whether running in backtest mode
3780
3810
  * @returns Unique string key for memoization
3781
3811
  */
3782
- const CREATE_KEY_FN$b = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
3812
+ const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
3813
+ const parts = [symbol, strategyName, exchangeName];
3814
+ if (frameName)
3815
+ parts.push(frameName);
3816
+ parts.push(backtest ? "backtest" : "live");
3817
+ return parts.join(":");
3818
+ };
3783
3819
  /**
3784
3820
  * Callback function for emitting ping events to pingSubject.
3785
3821
  *
@@ -3828,32 +3864,34 @@ class StrategyConnectionService {
3828
3864
  this.strategySchemaService = inject(TYPES.strategySchemaService);
3829
3865
  this.riskConnectionService = inject(TYPES.riskConnectionService);
3830
3866
  this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
3831
- this.methodContextService = inject(TYPES.methodContextService);
3832
3867
  this.partialConnectionService = inject(TYPES.partialConnectionService);
3833
3868
  /**
3834
- * Retrieves memoized ClientStrategy instance for given symbol-strategy pair.
3869
+ * Retrieves memoized ClientStrategy instance for given symbol-strategy pair with exchange and frame isolation.
3835
3870
  *
3836
3871
  * Creates ClientStrategy on first call, returns cached instance on subsequent calls.
3837
- * Cache key is symbol:strategyName string.
3872
+ * Cache key includes exchangeName and frameName for proper isolation.
3838
3873
  *
3839
3874
  * @param symbol - Trading pair symbol
3840
3875
  * @param strategyName - Name of registered strategy schema
3876
+ * @param exchangeName - Exchange name
3877
+ * @param frameName - Frame name (empty string for live)
3878
+ * @param backtest - Whether running in backtest mode
3841
3879
  * @returns Configured ClientStrategy instance
3842
3880
  */
3843
- this.getStrategy = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, backtest), (symbol, strategyName, backtest) => {
3881
+ this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
3844
3882
  const { riskName = "", riskList = [], getSignal, interval, callbacks, } = this.strategySchemaService.get(strategyName);
3845
3883
  return new ClientStrategy({
3846
3884
  symbol,
3847
3885
  interval,
3848
3886
  execution: this.executionContextService,
3849
- method: this.methodContextService,
3887
+ method: { context: { strategyName, exchangeName, frameName } },
3850
3888
  logger: this.loggerService,
3851
3889
  partial: this.partialConnectionService,
3852
3890
  exchange: this.exchangeConnectionService,
3853
3891
  risk: GET_RISK_FN({
3854
3892
  riskName,
3855
3893
  riskList,
3856
- }, backtest, this),
3894
+ }, backtest, exchangeName, frameName, this),
3857
3895
  riskName,
3858
3896
  strategyName,
3859
3897
  getSignal,
@@ -3866,38 +3904,40 @@ class StrategyConnectionService {
3866
3904
  * If no active signal exists, returns null.
3867
3905
  * Used internally for monitoring TP/SL and time expiration.
3868
3906
  *
3907
+ * @param backtest - Whether running in backtest mode
3869
3908
  * @param symbol - Trading pair symbol
3870
- * @param strategyName - Name of strategy to get pending signal for
3909
+ * @param context - Execution context with strategyName, exchangeName, frameName
3871
3910
  *
3872
3911
  * @returns Promise resolving to pending signal or null
3873
3912
  */
3874
- this.getPendingSignal = async (backtest, symbol, strategyName) => {
3913
+ this.getPendingSignal = async (backtest, symbol, context) => {
3875
3914
  this.loggerService.log("strategyConnectionService getPendingSignal", {
3876
3915
  symbol,
3877
- strategyName,
3916
+ context,
3878
3917
  backtest,
3879
3918
  });
3880
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3881
- return await strategy.getPendingSignal(symbol, strategyName);
3919
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3920
+ return await strategy.getPendingSignal(symbol);
3882
3921
  };
3883
3922
  /**
3884
3923
  * Retrieves the currently active scheduled signal for the strategy.
3885
3924
  * If no scheduled signal exists, returns null.
3886
3925
  * Used internally for monitoring scheduled signal activation.
3887
3926
  *
3927
+ * @param backtest - Whether running in backtest mode
3888
3928
  * @param symbol - Trading pair symbol
3889
- * @param strategyName - Name of strategy to get scheduled signal for
3929
+ * @param context - Execution context with strategyName, exchangeName, frameName
3890
3930
  *
3891
3931
  * @returns Promise resolving to scheduled signal or null
3892
3932
  */
3893
- this.getScheduledSignal = async (backtest, symbol, strategyName) => {
3933
+ this.getScheduledSignal = async (backtest, symbol, context) => {
3894
3934
  this.loggerService.log("strategyConnectionService getScheduledSignal", {
3895
3935
  symbol,
3896
- strategyName,
3936
+ context,
3897
3937
  backtest,
3898
3938
  });
3899
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3900
- return await strategy.getScheduledSignal(symbol, strategyName);
3939
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3940
+ return await strategy.getScheduledSignal(symbol);
3901
3941
  };
3902
3942
  /**
3903
3943
  * Retrieves the stopped state of the strategy.
@@ -3905,18 +3945,19 @@ class StrategyConnectionService {
3905
3945
  * Delegates to the underlying strategy instance to check if it has been
3906
3946
  * marked as stopped and should cease operation.
3907
3947
  *
3948
+ * @param backtest - Whether running in backtest mode
3908
3949
  * @param symbol - Trading pair symbol
3909
- * @param strategyName - Name of the strategy
3950
+ * @param context - Execution context with strategyName, exchangeName, frameName
3910
3951
  * @returns Promise resolving to true if strategy is stopped, false otherwise
3911
3952
  */
3912
- this.getStopped = async (backtest, symbol, strategyName) => {
3953
+ this.getStopped = async (backtest, symbol, context) => {
3913
3954
  this.loggerService.log("strategyConnectionService getStopped", {
3914
3955
  symbol,
3915
- strategyName,
3956
+ context,
3916
3957
  backtest,
3917
3958
  });
3918
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3919
- return await strategy.getStopped(symbol, strategyName);
3959
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3960
+ return await strategy.getStopped(symbol);
3920
3961
  };
3921
3962
  /**
3922
3963
  * Executes live trading tick for current strategy.
@@ -3925,18 +3966,19 @@ class StrategyConnectionService {
3925
3966
  * Evaluates current market conditions and returns signal state.
3926
3967
  *
3927
3968
  * @param symbol - Trading pair symbol
3928
- * @param strategyName - Name of strategy to tick
3969
+ * @param context - Execution context with strategyName, exchangeName, frameName
3929
3970
  * @returns Promise resolving to tick result (idle, opened, active, closed)
3930
3971
  */
3931
- this.tick = async (symbol, strategyName) => {
3972
+ this.tick = async (symbol, context) => {
3973
+ const backtest = this.executionContextService.context.backtest;
3932
3974
  this.loggerService.log("strategyConnectionService tick", {
3933
3975
  symbol,
3934
- strategyName,
3976
+ context,
3977
+ backtest,
3935
3978
  });
3936
- const backtest = this.executionContextService.context.backtest;
3937
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3979
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3938
3980
  await strategy.waitForInit();
3939
- const tick = await strategy.tick(symbol, strategyName);
3981
+ const tick = await strategy.tick(symbol, context.strategyName);
3940
3982
  {
3941
3983
  if (this.executionContextService.context.backtest) {
3942
3984
  await signalBacktestEmitter.next(tick);
@@ -3955,24 +3997,28 @@ class StrategyConnectionService {
3955
3997
  * Evaluates strategy signals against historical data.
3956
3998
  *
3957
3999
  * @param symbol - Trading pair symbol
3958
- * @param strategyName - Name of strategy to backtest
4000
+ * @param context - Execution context with strategyName, exchangeName, frameName
3959
4001
  * @param candles - Array of historical candle data to backtest
3960
4002
  * @returns Promise resolving to backtest result (signal or idle)
3961
4003
  */
3962
- this.backtest = async (symbol, strategyName, candles) => {
4004
+ this.backtest = async (symbol, context, candles) => {
4005
+ const backtest = this.executionContextService.context.backtest;
3963
4006
  this.loggerService.log("strategyConnectionService backtest", {
3964
4007
  symbol,
3965
- strategyName,
4008
+ context,
3966
4009
  candleCount: candles.length,
4010
+ backtest,
3967
4011
  });
3968
- const backtest = this.executionContextService.context.backtest;
3969
- const strategy = this.getStrategy(symbol, strategyName, backtest);
4012
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3970
4013
  await strategy.waitForInit();
3971
- const tick = await strategy.backtest(symbol, strategyName, candles);
4014
+ const tick = await strategy.backtest(symbol, context.strategyName, candles);
3972
4015
  {
3973
4016
  if (this.executionContextService.context.backtest) {
3974
4017
  await signalBacktestEmitter.next(tick);
3975
4018
  }
4019
+ if (!this.executionContextService.context.backtest) {
4020
+ await signalLiveEmitter.next(tick);
4021
+ }
3976
4022
  await signalEmitter.next(tick);
3977
4023
  }
3978
4024
  return tick;
@@ -3983,16 +4029,18 @@ class StrategyConnectionService {
3983
4029
  * Delegates to ClientStrategy.stop() which sets internal flag to prevent
3984
4030
  * getSignal from being called on subsequent ticks.
3985
4031
  *
4032
+ * @param backtest - Whether running in backtest mode
3986
4033
  * @param symbol - Trading pair symbol
3987
- * @param strategyName - Name of strategy to stop
4034
+ * @param ctx - Context with strategyName, exchangeName, frameName
3988
4035
  * @returns Promise that resolves when stop flag is set
3989
4036
  */
3990
- this.stop = async (backtest, ctx) => {
4037
+ this.stop = async (backtest, symbol, context) => {
3991
4038
  this.loggerService.log("strategyConnectionService stop", {
3992
- ctx,
4039
+ symbol,
4040
+ context,
3993
4041
  });
3994
- const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
3995
- await strategy.stop(ctx.symbol, ctx.strategyName, backtest);
4042
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4043
+ await strategy.stop(symbol);
3996
4044
  };
3997
4045
  /**
3998
4046
  * Clears the memoized ClientStrategy instance from cache.
@@ -4000,14 +4048,14 @@ class StrategyConnectionService {
4000
4048
  * Forces re-initialization of strategy on next getStrategy call.
4001
4049
  * Useful for resetting strategy state or releasing resources.
4002
4050
  *
4003
- * @param ctx - Optional context with symbol and strategyName (clears all if not provided)
4051
+ * @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
4004
4052
  */
4005
- this.clear = async (backtest, ctx) => {
4053
+ this.clear = async (payload) => {
4006
4054
  this.loggerService.log("strategyConnectionService clear", {
4007
- ctx,
4055
+ payload,
4008
4056
  });
4009
- if (ctx) {
4010
- const key = CREATE_KEY_FN$b(ctx.symbol, ctx.strategyName, backtest);
4057
+ if (payload) {
4058
+ const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
4011
4059
  this.getStrategy.clear(key);
4012
4060
  }
4013
4061
  else {
@@ -4024,17 +4072,19 @@ class StrategyConnectionService {
4024
4072
  * detects the scheduled signal was cancelled.
4025
4073
  *
4026
4074
  * @param backtest - Whether running in backtest mode
4027
- * @param ctx - Context with symbol and strategyName
4075
+ * @param symbol - Trading pair symbol
4076
+ * @param ctx - Context with strategyName, exchangeName, frameName
4028
4077
  * @param cancelId - Optional cancellation ID for user-initiated cancellations
4029
4078
  * @returns Promise that resolves when scheduled signal is cancelled
4030
4079
  */
4031
- this.cancel = async (backtest, ctx, cancelId) => {
4080
+ this.cancel = async (backtest, symbol, context, cancelId) => {
4032
4081
  this.loggerService.log("strategyConnectionService cancel", {
4033
- ctx,
4082
+ symbol,
4083
+ context,
4034
4084
  cancelId,
4035
4085
  });
4036
- const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
4037
- await strategy.cancel(ctx.symbol, ctx.strategyName, backtest, cancelId);
4086
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4087
+ await strategy.cancel(symbol, cancelId);
4038
4088
  };
4039
4089
  }
4040
4090
  }
@@ -4420,7 +4470,7 @@ const get = (object, path) => {
4420
4470
  /** Symbol indicating that positions need to be fetched from persistence */
4421
4471
  const POSITION_NEED_FETCH = Symbol("risk-need-fetch");
4422
4472
  /** Key generator for active position map */
4423
- const GET_KEY_FN = (strategyName, symbol) => `${strategyName}:${symbol}`;
4473
+ const CREATE_NAME_FN = (strategyName, exchangeName, symbol) => `${strategyName}_${exchangeName}_${symbol}`;
4424
4474
  /** Wrapper to execute risk validation function with error handling */
4425
4475
  const DO_VALIDATION_FN = async (validation, params) => {
4426
4476
  try {
@@ -4580,12 +4630,11 @@ class ClientRisk {
4580
4630
  if (this._activePositions === POSITION_NEED_FETCH) {
4581
4631
  await this.waitForInit();
4582
4632
  }
4583
- const key = GET_KEY_FN(context.strategyName, symbol);
4633
+ const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
4584
4634
  const riskMap = this._activePositions;
4585
4635
  riskMap.set(key, {
4586
- signal: null, // Signal details not needed for position tracking
4587
4636
  strategyName: context.strategyName,
4588
- exchangeName: "",
4637
+ exchangeName: context.exchangeName,
4589
4638
  openTimestamp: Date.now(),
4590
4639
  });
4591
4640
  await this._updatePositions();
@@ -4603,7 +4652,7 @@ class ClientRisk {
4603
4652
  if (this._activePositions === POSITION_NEED_FETCH) {
4604
4653
  await this.waitForInit();
4605
4654
  }
4606
- const key = GET_KEY_FN(context.strategyName, symbol);
4655
+ const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
4607
4656
  const riskMap = this._activePositions;
4608
4657
  riskMap.delete(key);
4609
4658
  await this._updatePositions();
@@ -4612,12 +4661,20 @@ class ClientRisk {
4612
4661
 
4613
4662
  /**
4614
4663
  * Creates a unique key for memoizing ClientRisk instances.
4615
- * Key format: "riskName:backtest" or "riskName:live"
4664
+ * Key format: "riskName:exchangeName:frameName:backtest" or "riskName:exchangeName:live"
4616
4665
  * @param riskName - Name of the risk schema
4666
+ * @param exchangeName - Exchange name
4667
+ * @param frameName - Frame name (empty string for live)
4617
4668
  * @param backtest - Whether running in backtest mode
4618
4669
  * @returns Unique string key for memoization
4619
4670
  */
4620
- const CREATE_KEY_FN$a = (riskName, backtest) => `${riskName}:${backtest ? "backtest" : "live"}`;
4671
+ const CREATE_KEY_FN$a = (riskName, exchangeName, frameName, backtest) => {
4672
+ const parts = [riskName, exchangeName];
4673
+ if (frameName)
4674
+ parts.push(frameName);
4675
+ parts.push(backtest ? "backtest" : "live");
4676
+ return parts.join(":");
4677
+ };
4621
4678
  /**
4622
4679
  * Callback function for emitting risk rejection events to riskSubject.
4623
4680
  *
@@ -4630,16 +4687,19 @@ const CREATE_KEY_FN$a = (riskName, backtest) => `${riskName}:${backtest ? "backt
4630
4687
  * @param rejectionResult - Rejection result with id and note
4631
4688
  * @param timestamp - Event timestamp in milliseconds
4632
4689
  * @param backtest - True if backtest mode, false if live mode
4690
+ * @param exchangeName - Exchange name
4691
+ * @param frameName - Frame name
4633
4692
  */
4634
- const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => await riskSubject.next({
4693
+ const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName) => await riskSubject.next({
4635
4694
  symbol,
4636
4695
  pendingSignal: params.pendingSignal,
4637
4696
  strategyName: params.strategyName,
4638
- exchangeName: params.exchangeName,
4697
+ exchangeName,
4639
4698
  currentPrice: params.currentPrice,
4640
4699
  activePositionCount,
4641
4700
  rejectionId: rejectionResult.id,
4642
4701
  rejectionNote: rejectionResult.note,
4702
+ frameName,
4643
4703
  timestamp,
4644
4704
  backtest,
4645
4705
  });
@@ -4680,22 +4740,24 @@ class RiskConnectionService {
4680
4740
  this.loggerService = inject(TYPES.loggerService);
4681
4741
  this.riskSchemaService = inject(TYPES.riskSchemaService);
4682
4742
  /**
4683
- * Retrieves memoized ClientRisk instance for given risk name and backtest mode.
4743
+ * Retrieves memoized ClientRisk instance for given risk name, exchange, frame and backtest mode.
4684
4744
  *
4685
4745
  * Creates ClientRisk on first call, returns cached instance on subsequent calls.
4686
- * Cache key is "riskName:backtest" string to separate live and backtest instances.
4746
+ * Cache key includes exchangeName and frameName to isolate risk per exchange+frame.
4687
4747
  *
4688
4748
  * @param riskName - Name of registered risk schema
4749
+ * @param exchangeName - Exchange name
4750
+ * @param frameName - Frame name (empty string for live)
4689
4751
  * @param backtest - True if backtest mode, false if live mode
4690
4752
  * @returns Configured ClientRisk instance
4691
4753
  */
4692
- this.getRisk = functoolsKit.memoize(([riskName, backtest]) => CREATE_KEY_FN$a(riskName, backtest), (riskName, backtest) => {
4754
+ this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
4693
4755
  const schema = this.riskSchemaService.get(riskName);
4694
4756
  return new ClientRisk({
4695
4757
  ...schema,
4696
4758
  logger: this.loggerService,
4697
4759
  backtest,
4698
- onRejected: COMMIT_REJECTION_FN,
4760
+ onRejected: (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => COMMIT_REJECTION_FN(symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName),
4699
4761
  });
4700
4762
  });
4701
4763
  /**
@@ -4706,57 +4768,55 @@ class RiskConnectionService {
4706
4768
  * ClientRisk will emit riskSubject event via onRejected callback when signal is rejected.
4707
4769
  *
4708
4770
  * @param params - Risk check arguments (portfolio state, position details)
4709
- * @param context - Execution context with risk name and backtest mode
4771
+ * @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
4710
4772
  * @returns Promise resolving to risk check result
4711
4773
  */
4712
- this.checkSignal = async (params, context) => {
4774
+ this.checkSignal = async (params, payload) => {
4713
4775
  this.loggerService.log("riskConnectionService checkSignal", {
4714
4776
  symbol: params.symbol,
4715
- context,
4777
+ payload,
4716
4778
  });
4717
- return await this.getRisk(context.riskName, context.backtest).checkSignal(params);
4779
+ return await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).checkSignal(params);
4718
4780
  };
4719
4781
  /**
4720
4782
  * Registers an opened signal with the risk management system.
4721
4783
  * Routes to appropriate ClientRisk instance.
4722
4784
  *
4723
4785
  * @param symbol - Trading pair symbol
4724
- * @param context - Context information (strategyName, riskName, backtest)
4786
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
4725
4787
  */
4726
- this.addSignal = async (symbol, context) => {
4788
+ this.addSignal = async (symbol, payload) => {
4727
4789
  this.loggerService.log("riskConnectionService addSignal", {
4728
4790
  symbol,
4729
- context,
4791
+ payload,
4730
4792
  });
4731
- await this.getRisk(context.riskName, context.backtest).addSignal(symbol, context);
4793
+ await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).addSignal(symbol, payload);
4732
4794
  };
4733
4795
  /**
4734
4796
  * Removes a closed signal from the risk management system.
4735
4797
  * Routes to appropriate ClientRisk instance.
4736
4798
  *
4737
4799
  * @param symbol - Trading pair symbol
4738
- * @param context - Context information (strategyName, riskName, backtest)
4800
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
4739
4801
  */
4740
- this.removeSignal = async (symbol, context) => {
4802
+ this.removeSignal = async (symbol, payload) => {
4741
4803
  this.loggerService.log("riskConnectionService removeSignal", {
4742
4804
  symbol,
4743
- context,
4805
+ payload,
4744
4806
  });
4745
- await this.getRisk(context.riskName, context.backtest).removeSignal(symbol, context);
4807
+ await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).removeSignal(symbol, payload);
4746
4808
  };
4747
4809
  /**
4748
4810
  * Clears the cached ClientRisk instance for the given risk name.
4749
4811
  *
4750
- * @param backtest - Whether running in backtest mode
4751
- * @param ctx - Optional context with riskName (clears all if not provided)
4812
+ * @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
4752
4813
  */
4753
- this.clear = async (backtest, ctx) => {
4814
+ this.clear = async (payload) => {
4754
4815
  this.loggerService.log("riskConnectionService clear", {
4755
- ctx,
4756
- backtest,
4816
+ payload,
4757
4817
  });
4758
- if (ctx) {
4759
- const key = CREATE_KEY_FN$a(ctx.riskName, backtest);
4818
+ if (payload) {
4819
+ const key = CREATE_KEY_FN$a(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
4760
4820
  this.getRisk.clear(key);
4761
4821
  }
4762
4822
  else {
@@ -4955,7 +5015,6 @@ class StrategyCoreService {
4955
5015
  this.strategySchemaService = inject(TYPES.strategySchemaService);
4956
5016
  this.riskValidationService = inject(TYPES.riskValidationService);
4957
5017
  this.strategyValidationService = inject(TYPES.strategyValidationService);
4958
- this.methodContextService = inject(TYPES.methodContextService);
4959
5018
  /**
4960
5019
  * Validates strategy and associated risk configuration.
4961
5020
  *
@@ -4980,34 +5039,36 @@ class StrategyCoreService {
4980
5039
  * If no active signal exists, returns null.
4981
5040
  * Used internally for monitoring TP/SL and time expiration.
4982
5041
  *
5042
+ * @param backtest - Whether running in backtest mode
4983
5043
  * @param symbol - Trading pair symbol
4984
- * @param strategyName - Name of the strategy
5044
+ * @param context - Execution context with strategyName, exchangeName, frameName
4985
5045
  * @returns Promise resolving to pending signal or null
4986
5046
  */
4987
- this.getPendingSignal = async (backtest, symbol, strategyName) => {
5047
+ this.getPendingSignal = async (backtest, symbol, context) => {
4988
5048
  this.loggerService.log("strategyCoreService getPendingSignal", {
4989
5049
  symbol,
4990
- strategyName,
5050
+ context,
4991
5051
  });
4992
- await this.validate(symbol, strategyName);
4993
- return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
5052
+ await this.validate(symbol, context.strategyName);
5053
+ return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
4994
5054
  };
4995
5055
  /**
4996
5056
  * Retrieves the currently active scheduled signal for the symbol.
4997
5057
  * If no scheduled signal exists, returns null.
4998
5058
  * Used internally for monitoring scheduled signal activation.
4999
5059
  *
5060
+ * @param backtest - Whether running in backtest mode
5000
5061
  * @param symbol - Trading pair symbol
5001
- * @param strategyName - Name of the strategy
5062
+ * @param context - Execution context with strategyName, exchangeName, frameName
5002
5063
  * @returns Promise resolving to scheduled signal or null
5003
5064
  */
5004
- this.getScheduledSignal = async (backtest, symbol, strategyName) => {
5065
+ this.getScheduledSignal = async (backtest, symbol, context) => {
5005
5066
  this.loggerService.log("strategyCoreService getScheduledSignal", {
5006
5067
  symbol,
5007
- strategyName,
5068
+ context,
5008
5069
  });
5009
- await this.validate(symbol, strategyName);
5010
- return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, strategyName);
5070
+ await this.validate(symbol, context.strategyName);
5071
+ return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
5011
5072
  };
5012
5073
  /**
5013
5074
  * Checks if the strategy has been stopped.
@@ -5015,18 +5076,19 @@ class StrategyCoreService {
5015
5076
  * Validates strategy existence and delegates to connection service
5016
5077
  * to retrieve the stopped state from the strategy instance.
5017
5078
  *
5079
+ * @param backtest - Whether running in backtest mode
5018
5080
  * @param symbol - Trading pair symbol
5019
- * @param strategyName - Name of the strategy
5081
+ * @param context - Execution context with strategyName, exchangeName, frameName
5020
5082
  * @returns Promise resolving to true if strategy is stopped, false otherwise
5021
5083
  */
5022
- this.getStopped = async (backtest, symbol, strategyName) => {
5084
+ this.getStopped = async (backtest, symbol, context) => {
5023
5085
  this.loggerService.log("strategyCoreService getStopped", {
5024
5086
  symbol,
5025
- strategyName,
5087
+ context,
5026
5088
  backtest,
5027
5089
  });
5028
- await this.validate(symbol, strategyName);
5029
- return await this.strategyConnectionService.getStopped(backtest, symbol, strategyName);
5090
+ await this.validate(symbol, context.strategyName);
5091
+ return await this.strategyConnectionService.getStopped(backtest, symbol, context);
5030
5092
  };
5031
5093
  /**
5032
5094
  * Checks signal status at a specific timestamp.
@@ -5037,21 +5099,19 @@ class StrategyCoreService {
5037
5099
  * @param symbol - Trading pair symbol
5038
5100
  * @param when - Timestamp for tick evaluation
5039
5101
  * @param backtest - Whether running in backtest mode
5102
+ * @param context - Execution context with strategyName, exchangeName, frameName
5040
5103
  * @returns Discriminated union of tick result (idle, opened, active, closed)
5041
5104
  */
5042
- this.tick = async (symbol, when, backtest) => {
5105
+ this.tick = async (symbol, when, backtest, context) => {
5043
5106
  this.loggerService.log("strategyCoreService tick", {
5044
5107
  symbol,
5045
5108
  when,
5046
5109
  backtest,
5110
+ context,
5047
5111
  });
5048
- if (!MethodContextService.hasContext()) {
5049
- throw new Error("strategyCoreService tick requires a method context");
5050
- }
5051
- const strategyName = this.methodContextService.context.strategyName;
5052
- await this.validate(symbol, strategyName);
5112
+ await this.validate(symbol, context.strategyName);
5053
5113
  return await ExecutionContextService.runInContext(async () => {
5054
- return await this.strategyConnectionService.tick(symbol, strategyName);
5114
+ return await this.strategyConnectionService.tick(symbol, context);
5055
5115
  }, {
5056
5116
  symbol,
5057
5117
  when,
@@ -5068,22 +5128,20 @@ class StrategyCoreService {
5068
5128
  * @param candles - Array of historical candles to test against
5069
5129
  * @param when - Starting timestamp for backtest
5070
5130
  * @param backtest - Whether running in backtest mode (typically true)
5131
+ * @param context - Execution context with strategyName, exchangeName, frameName
5071
5132
  * @returns Closed signal result with PNL
5072
5133
  */
5073
- this.backtest = async (symbol, candles, when, backtest) => {
5134
+ this.backtest = async (symbol, candles, when, backtest, context) => {
5074
5135
  this.loggerService.log("strategyCoreService backtest", {
5075
5136
  symbol,
5076
5137
  candleCount: candles.length,
5077
5138
  when,
5078
5139
  backtest,
5140
+ context,
5079
5141
  });
5080
- if (!MethodContextService.hasContext()) {
5081
- throw new Error("strategyCoreService backtest requires a method context");
5082
- }
5083
- const strategyName = this.methodContextService.context.strategyName;
5084
- await this.validate(symbol, strategyName);
5142
+ await this.validate(symbol, context.strategyName);
5085
5143
  return await ExecutionContextService.runInContext(async () => {
5086
- return await this.strategyConnectionService.backtest(symbol, strategyName, candles);
5144
+ return await this.strategyConnectionService.backtest(symbol, context, candles);
5087
5145
  }, {
5088
5146
  symbol,
5089
5147
  when,
@@ -5096,17 +5154,19 @@ class StrategyCoreService {
5096
5154
  * Delegates to StrategyConnectionService.stop() to set internal flag.
5097
5155
  * Does not require execution context.
5098
5156
  *
5157
+ * @param backtest - Whether running in backtest mode
5099
5158
  * @param symbol - Trading pair symbol
5100
- * @param strategyName - Name of strategy to stop
5159
+ * @param ctx - Context with strategyName, exchangeName, frameName
5101
5160
  * @returns Promise that resolves when stop flag is set
5102
5161
  */
5103
- this.stop = async (backtest, ctx) => {
5162
+ this.stop = async (backtest, symbol, context) => {
5104
5163
  this.loggerService.log("strategyCoreService stop", {
5105
- ctx,
5164
+ symbol,
5165
+ context,
5106
5166
  backtest,
5107
5167
  });
5108
- await this.validate(ctx.symbol, ctx.strategyName);
5109
- return await this.strategyConnectionService.stop(backtest, ctx);
5168
+ await this.validate(symbol, context.strategyName);
5169
+ return await this.strategyConnectionService.stop(backtest, symbol, context);
5110
5170
  };
5111
5171
  /**
5112
5172
  * Cancels the scheduled signal without stopping the strategy.
@@ -5116,18 +5176,20 @@ class StrategyCoreService {
5116
5176
  * Does not require execution context.
5117
5177
  *
5118
5178
  * @param backtest - Whether running in backtest mode
5119
- * @param ctx - Context with symbol and strategyName
5179
+ * @param symbol - Trading pair symbol
5180
+ * @param ctx - Context with strategyName, exchangeName, frameName
5120
5181
  * @param cancelId - Optional cancellation ID for user-initiated cancellations
5121
5182
  * @returns Promise that resolves when scheduled signal is cancelled
5122
5183
  */
5123
- this.cancel = async (backtest, ctx, cancelId) => {
5184
+ this.cancel = async (backtest, symbol, context, cancelId) => {
5124
5185
  this.loggerService.log("strategyCoreService cancel", {
5125
- ctx,
5186
+ symbol,
5187
+ context,
5126
5188
  backtest,
5127
5189
  cancelId,
5128
5190
  });
5129
- await this.validate(ctx.symbol, ctx.strategyName);
5130
- return await this.strategyConnectionService.cancel(backtest, ctx, cancelId);
5191
+ await this.validate(symbol, context.strategyName);
5192
+ return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
5131
5193
  };
5132
5194
  /**
5133
5195
  * Clears the memoized ClientStrategy instance from cache.
@@ -5135,16 +5197,16 @@ class StrategyCoreService {
5135
5197
  * Delegates to StrategyConnectionService.clear() to remove strategy from cache.
5136
5198
  * Forces re-initialization of strategy on next operation.
5137
5199
  *
5138
- * @param ctx - Optional context with symbol and strategyName (clears all if not provided)
5200
+ * @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
5139
5201
  */
5140
- this.clear = async (backtest, ctx) => {
5202
+ this.clear = async (payload) => {
5141
5203
  this.loggerService.log("strategyCoreService clear", {
5142
- ctx,
5204
+ payload,
5143
5205
  });
5144
- if (ctx) {
5145
- await this.validate(ctx.symbol, ctx.strategyName);
5206
+ if (payload) {
5207
+ await this.validate(payload.symbol, payload.strategyName);
5146
5208
  }
5147
- return await this.strategyConnectionService.clear(backtest, ctx);
5209
+ return await this.strategyConnectionService.clear(payload);
5148
5210
  };
5149
5211
  }
5150
5212
  }
@@ -5240,61 +5302,59 @@ class RiskGlobalService {
5240
5302
  * Checks if a signal should be allowed based on risk limits.
5241
5303
  *
5242
5304
  * @param params - Risk check arguments (portfolio state, position details)
5243
- * @param context - Execution context with risk name
5305
+ * @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
5244
5306
  * @returns Promise resolving to risk check result
5245
5307
  */
5246
- this.checkSignal = async (params, context) => {
5308
+ this.checkSignal = async (params, payload) => {
5247
5309
  this.loggerService.log("riskGlobalService checkSignal", {
5248
5310
  symbol: params.symbol,
5249
- context,
5311
+ payload,
5250
5312
  });
5251
- await this.validate(context.riskName);
5252
- return await this.riskConnectionService.checkSignal(params, context);
5313
+ await this.validate(payload.riskName);
5314
+ return await this.riskConnectionService.checkSignal(params, payload);
5253
5315
  };
5254
5316
  /**
5255
5317
  * Registers an opened signal with the risk management system.
5256
5318
  *
5257
5319
  * @param symbol - Trading pair symbol
5258
- * @param context - Context information (strategyName, riskName)
5320
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
5259
5321
  */
5260
- this.addSignal = async (symbol, context) => {
5322
+ this.addSignal = async (symbol, payload) => {
5261
5323
  this.loggerService.log("riskGlobalService addSignal", {
5262
5324
  symbol,
5263
- context,
5325
+ payload,
5264
5326
  });
5265
- await this.validate(context.riskName);
5266
- await this.riskConnectionService.addSignal(symbol, context);
5327
+ await this.validate(payload.riskName);
5328
+ await this.riskConnectionService.addSignal(symbol, payload);
5267
5329
  };
5268
5330
  /**
5269
5331
  * Removes a closed signal from the risk management system.
5270
5332
  *
5271
5333
  * @param symbol - Trading pair symbol
5272
- * @param context - Context information (strategyName, riskName)
5334
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
5273
5335
  */
5274
- this.removeSignal = async (symbol, context) => {
5336
+ this.removeSignal = async (symbol, payload) => {
5275
5337
  this.loggerService.log("riskGlobalService removeSignal", {
5276
5338
  symbol,
5277
- context,
5339
+ payload,
5278
5340
  });
5279
- await this.validate(context.riskName);
5280
- await this.riskConnectionService.removeSignal(symbol, context);
5341
+ await this.validate(payload.riskName);
5342
+ await this.riskConnectionService.removeSignal(symbol, payload);
5281
5343
  };
5282
5344
  /**
5283
5345
  * Clears risk data.
5284
- * If ctx is provided, clears data for that specific risk instance.
5285
- * If no ctx is provided, clears all risk data.
5286
- * @param backtest - Whether running in backtest mode
5287
- * @param ctx - Optional context with riskName (clears all if not provided)
5346
+ * If payload is provided, clears data for that specific risk instance.
5347
+ * If no payload is provided, clears all risk data.
5348
+ * @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
5288
5349
  */
5289
- this.clear = async (backtest, ctx) => {
5350
+ this.clear = async (payload) => {
5290
5351
  this.loggerService.log("riskGlobalService clear", {
5291
- ctx,
5292
- backtest,
5352
+ payload,
5293
5353
  });
5294
- if (ctx) {
5295
- await this.validate(ctx.riskName);
5354
+ if (payload) {
5355
+ await this.validate(payload.riskName);
5296
5356
  }
5297
- return await this.riskConnectionService.clear(backtest, ctx);
5357
+ return await this.riskConnectionService.clear(payload);
5298
5358
  };
5299
5359
  }
5300
5360
  }
@@ -5845,7 +5905,11 @@ class BacktestLogicPrivateService {
5845
5905
  });
5846
5906
  }
5847
5907
  // Check if strategy should stop before processing next frame
5848
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
5908
+ if (await this.strategyCoreService.getStopped(true, symbol, {
5909
+ strategyName: this.methodContextService.context.strategyName,
5910
+ exchangeName: this.methodContextService.context.exchangeName,
5911
+ frameName: this.methodContextService.context.frameName,
5912
+ })) {
5849
5913
  this.loggerService.info("backtestLogicPrivateService stopped by user request (before tick)", {
5850
5914
  symbol,
5851
5915
  when: when.toISOString(),
@@ -5856,7 +5920,11 @@ class BacktestLogicPrivateService {
5856
5920
  }
5857
5921
  let result;
5858
5922
  try {
5859
- result = await this.strategyCoreService.tick(symbol, when, true);
5923
+ result = await this.strategyCoreService.tick(symbol, when, true, {
5924
+ strategyName: this.methodContextService.context.strategyName,
5925
+ exchangeName: this.methodContextService.context.exchangeName,
5926
+ frameName: this.methodContextService.context.frameName,
5927
+ });
5860
5928
  }
5861
5929
  catch (error) {
5862
5930
  console.warn(`backtestLogicPrivateService tick failed, skipping timeframe when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -5870,7 +5938,11 @@ class BacktestLogicPrivateService {
5870
5938
  continue;
5871
5939
  }
5872
5940
  // Check if strategy should stop when idle (no active signal)
5873
- if (await functoolsKit.and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName))) {
5941
+ if (await functoolsKit.and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, {
5942
+ strategyName: this.methodContextService.context.strategyName,
5943
+ exchangeName: this.methodContextService.context.exchangeName,
5944
+ frameName: this.methodContextService.context.frameName,
5945
+ }))) {
5874
5946
  this.loggerService.info("backtestLogicPrivateService stopped by user request (idle state)", {
5875
5947
  symbol,
5876
5948
  when: when.toISOString(),
@@ -5929,7 +6001,11 @@ class BacktestLogicPrivateService {
5929
6001
  // и если активируется - продолжит с TP/SL мониторингом
5930
6002
  let backtestResult;
5931
6003
  try {
5932
- backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true);
6004
+ backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
6005
+ strategyName: this.methodContextService.context.strategyName,
6006
+ exchangeName: this.methodContextService.context.exchangeName,
6007
+ frameName: this.methodContextService.context.frameName,
6008
+ });
5933
6009
  }
5934
6010
  catch (error) {
5935
6011
  console.warn(`backtestLogicPrivateService backtest failed for scheduled signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -5961,6 +6037,7 @@ class BacktestLogicPrivateService {
5961
6037
  duration: signalEndTime - signalStartTime,
5962
6038
  strategyName: this.methodContextService.context.strategyName,
5963
6039
  exchangeName: this.methodContextService.context.exchangeName,
6040
+ frameName: this.methodContextService.context.frameName,
5964
6041
  symbol,
5965
6042
  backtest: true,
5966
6043
  });
@@ -5972,7 +6049,11 @@ class BacktestLogicPrivateService {
5972
6049
  }
5973
6050
  yield backtestResult;
5974
6051
  // Check if strategy should stop after signal is closed
5975
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
6052
+ if (await this.strategyCoreService.getStopped(true, symbol, {
6053
+ strategyName: this.methodContextService.context.strategyName,
6054
+ exchangeName: this.methodContextService.context.exchangeName,
6055
+ frameName: this.methodContextService.context.frameName,
6056
+ })) {
5976
6057
  this.loggerService.info("backtestLogicPrivateService stopped by user request (after scheduled signal closed)", {
5977
6058
  symbol,
5978
6059
  signalId: backtestResult.signal.id,
@@ -6026,7 +6107,11 @@ class BacktestLogicPrivateService {
6026
6107
  // Вызываем backtest - всегда возвращает closed
6027
6108
  let backtestResult;
6028
6109
  try {
6029
- backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true);
6110
+ backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
6111
+ strategyName: this.methodContextService.context.strategyName,
6112
+ exchangeName: this.methodContextService.context.exchangeName,
6113
+ frameName: this.methodContextService.context.frameName,
6114
+ });
6030
6115
  }
6031
6116
  catch (error) {
6032
6117
  console.warn(`backtestLogicPrivateService backtest failed for opened signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -6054,6 +6139,7 @@ class BacktestLogicPrivateService {
6054
6139
  duration: signalEndTime - signalStartTime,
6055
6140
  strategyName: this.methodContextService.context.strategyName,
6056
6141
  exchangeName: this.methodContextService.context.exchangeName,
6142
+ frameName: this.methodContextService.context.frameName,
6057
6143
  symbol,
6058
6144
  backtest: true,
6059
6145
  });
@@ -6065,7 +6151,11 @@ class BacktestLogicPrivateService {
6065
6151
  }
6066
6152
  yield backtestResult;
6067
6153
  // Check if strategy should stop after signal is closed
6068
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
6154
+ if (await this.strategyCoreService.getStopped(true, symbol, {
6155
+ strategyName: this.methodContextService.context.strategyName,
6156
+ exchangeName: this.methodContextService.context.exchangeName,
6157
+ frameName: this.methodContextService.context.frameName,
6158
+ })) {
6069
6159
  this.loggerService.info("backtestLogicPrivateService stopped by user request (after signal closed)", {
6070
6160
  symbol,
6071
6161
  signalId: backtestResult.signal.id,
@@ -6085,6 +6175,7 @@ class BacktestLogicPrivateService {
6085
6175
  duration: timeframeEndTime - timeframeStartTime,
6086
6176
  strategyName: this.methodContextService.context.strategyName,
6087
6177
  exchangeName: this.methodContextService.context.exchangeName,
6178
+ frameName: this.methodContextService.context.frameName,
6088
6179
  symbol,
6089
6180
  backtest: true,
6090
6181
  });
@@ -6112,6 +6203,7 @@ class BacktestLogicPrivateService {
6112
6203
  duration: backtestEndTime - backtestStartTime,
6113
6204
  strategyName: this.methodContextService.context.strategyName,
6114
6205
  exchangeName: this.methodContextService.context.exchangeName,
6206
+ frameName: this.methodContextService.context.frameName,
6115
6207
  symbol,
6116
6208
  backtest: true,
6117
6209
  });
@@ -6174,7 +6266,11 @@ class LiveLogicPrivateService {
6174
6266
  const when = new Date();
6175
6267
  let result;
6176
6268
  try {
6177
- result = await this.strategyCoreService.tick(symbol, when, false);
6269
+ result = await this.strategyCoreService.tick(symbol, when, false, {
6270
+ strategyName: this.methodContextService.context.strategyName,
6271
+ exchangeName: this.methodContextService.context.exchangeName,
6272
+ frameName: this.methodContextService.context.frameName,
6273
+ });
6178
6274
  }
6179
6275
  catch (error) {
6180
6276
  console.warn(`backtestLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -6202,13 +6298,18 @@ class LiveLogicPrivateService {
6202
6298
  duration: tickEndTime - tickStartTime,
6203
6299
  strategyName: this.methodContextService.context.strategyName,
6204
6300
  exchangeName: this.methodContextService.context.exchangeName,
6301
+ frameName: this.methodContextService.context.frameName,
6205
6302
  symbol,
6206
6303
  backtest: false,
6207
6304
  });
6208
6305
  previousEventTimestamp = currentTimestamp;
6209
6306
  // Check if strategy should stop when idle (no active signal)
6210
6307
  if (result.action === "idle") {
6211
- if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName))) {
6308
+ if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, {
6309
+ strategyName: this.methodContextService.context.strategyName,
6310
+ exchangeName: this.methodContextService.context.exchangeName,
6311
+ frameName: this.methodContextService.context.frameName,
6312
+ }))) {
6212
6313
  this.loggerService.info("liveLogicPrivateService stopped by user request (idle state)", {
6213
6314
  symbol,
6214
6315
  when: when.toISOString(),
@@ -6230,7 +6331,11 @@ class LiveLogicPrivateService {
6230
6331
  yield result;
6231
6332
  // Check if strategy should stop after signal is closed
6232
6333
  if (result.action === "closed") {
6233
- if (await this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName)) {
6334
+ if (await this.strategyCoreService.getStopped(false, symbol, {
6335
+ strategyName: this.methodContextService.context.strategyName,
6336
+ exchangeName: this.methodContextService.context.exchangeName,
6337
+ frameName: this.methodContextService.context.frameName,
6338
+ })) {
6234
6339
  this.loggerService.info("liveLogicPrivateService stopped by user request (after signal closed)", {
6235
6340
  symbol,
6236
6341
  signalId: result.signal.id,
@@ -6362,7 +6467,7 @@ class WalkerLogicPrivateService {
6362
6467
  symbol,
6363
6468
  });
6364
6469
  // Get statistics from BacktestMarkdownService
6365
- const stats = await this.backtestMarkdownService.getData(symbol, strategyName, true);
6470
+ const stats = await this.backtestMarkdownService.getData(symbol, strategyName, context.exchangeName, context.frameName, true);
6366
6471
  // Extract metric value
6367
6472
  const value = stats[metric];
6368
6473
  const metricValue = value !== null &&
@@ -6426,7 +6531,7 @@ class WalkerLogicPrivateService {
6426
6531
  bestStrategy,
6427
6532
  bestMetric,
6428
6533
  bestStats: bestStrategy !== null
6429
- ? await this.backtestMarkdownService.getData(symbol, bestStrategy, true)
6534
+ ? await this.backtestMarkdownService.getData(symbol, bestStrategy, context.exchangeName, context.frameName, true)
6430
6535
  : null,
6431
6536
  };
6432
6537
  // Call onComplete callback if provided with final best results
@@ -7789,13 +7894,21 @@ const DEFAULT_COLUMNS = Object.freeze({ ...COLUMN_CONFIG });
7789
7894
 
7790
7895
  /**
7791
7896
  * Creates a unique key for memoizing ReportStorage instances.
7792
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
7897
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
7793
7898
  * @param symbol - Trading pair symbol
7794
7899
  * @param strategyName - Name of the strategy
7900
+ * @param exchangeName - Exchange name
7901
+ * @param frameName - Frame name
7795
7902
  * @param backtest - Whether running in backtest mode
7796
7903
  * @returns Unique string key for memoization
7797
7904
  */
7798
- const CREATE_KEY_FN$9 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
7905
+ const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
7906
+ const parts = [symbol, strategyName, exchangeName];
7907
+ if (frameName)
7908
+ parts.push(frameName);
7909
+ parts.push(backtest ? "backtest" : "live");
7910
+ return parts.join(":");
7911
+ };
7799
7912
  /**
7800
7913
  * Checks if a value is unsafe for display (not a number, NaN, or Infinity).
7801
7914
  *
@@ -8001,17 +8114,17 @@ class BacktestMarkdownService {
8001
8114
  /** Logger service for debug output */
8002
8115
  this.loggerService = inject(TYPES.loggerService);
8003
8116
  /**
8004
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
8005
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
8117
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
8118
+ * Each combination gets its own isolated storage instance.
8006
8119
  */
8007
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, backtest), () => new ReportStorage$5());
8120
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$5());
8008
8121
  /**
8009
8122
  * Processes tick events and accumulates closed signals.
8010
8123
  * Should be called from IStrategyCallbacks.onTick.
8011
8124
  *
8012
8125
  * Only processes closed signals - opened signals are ignored.
8013
8126
  *
8014
- * @param data - Tick result from strategy execution (opened or closed)
8127
+ * @param data - Tick result from strategy execution (opened or closed) with frameName wrapper
8015
8128
  *
8016
8129
  * @example
8017
8130
  * ```typescript
@@ -8031,7 +8144,7 @@ class BacktestMarkdownService {
8031
8144
  if (data.action !== "closed") {
8032
8145
  return;
8033
8146
  }
8034
- const storage = this.getStorage(data.symbol, data.strategyName, true);
8147
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, true);
8035
8148
  storage.addSignal(data);
8036
8149
  };
8037
8150
  /**
@@ -8040,23 +8153,27 @@ class BacktestMarkdownService {
8040
8153
  *
8041
8154
  * @param symbol - Trading pair symbol
8042
8155
  * @param strategyName - Strategy name to get data for
8156
+ * @param exchangeName - Exchange name
8157
+ * @param frameName - Frame name
8043
8158
  * @param backtest - True if backtest mode, false if live mode
8044
8159
  * @returns Statistical data object with all metrics
8045
8160
  *
8046
8161
  * @example
8047
8162
  * ```typescript
8048
8163
  * const service = new BacktestMarkdownService();
8049
- * const stats = await service.getData("BTCUSDT", "my-strategy", true);
8164
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", true);
8050
8165
  * console.log(stats.sharpeRatio, stats.winRate);
8051
8166
  * ```
8052
8167
  */
8053
- this.getData = async (symbol, strategyName, backtest) => {
8168
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8054
8169
  this.loggerService.log("backtestMarkdownService getData", {
8055
8170
  symbol,
8056
8171
  strategyName,
8172
+ exchangeName,
8173
+ frameName,
8057
8174
  backtest,
8058
8175
  });
8059
- const storage = this.getStorage(symbol, strategyName, backtest);
8176
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8060
8177
  return storage.getData();
8061
8178
  };
8062
8179
  /**
@@ -8065,6 +8182,8 @@ class BacktestMarkdownService {
8065
8182
  *
8066
8183
  * @param symbol - Trading pair symbol
8067
8184
  * @param strategyName - Strategy name to generate report for
8185
+ * @param exchangeName - Exchange name
8186
+ * @param frameName - Frame name
8068
8187
  * @param backtest - True if backtest mode, false if live mode
8069
8188
  * @param columns - Column configuration for formatting the table
8070
8189
  * @returns Markdown formatted report string with table of all closed signals
@@ -8072,17 +8191,19 @@ class BacktestMarkdownService {
8072
8191
  * @example
8073
8192
  * ```typescript
8074
8193
  * const service = new BacktestMarkdownService();
8075
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", true);
8194
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", true);
8076
8195
  * console.log(markdown);
8077
8196
  * ```
8078
8197
  */
8079
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
8198
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
8080
8199
  this.loggerService.log("backtestMarkdownService getReport", {
8081
8200
  symbol,
8082
8201
  strategyName,
8202
+ exchangeName,
8203
+ frameName,
8083
8204
  backtest,
8084
8205
  });
8085
- const storage = this.getStorage(symbol, strategyName, backtest);
8206
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8086
8207
  return storage.getReport(strategyName, columns);
8087
8208
  };
8088
8209
  /**
@@ -8092,6 +8213,8 @@ class BacktestMarkdownService {
8092
8213
  *
8093
8214
  * @param symbol - Trading pair symbol
8094
8215
  * @param strategyName - Strategy name to save report for
8216
+ * @param exchangeName - Exchange name
8217
+ * @param frameName - Frame name
8095
8218
  * @param backtest - True if backtest mode, false if live mode
8096
8219
  * @param path - Directory path to save report (default: "./dump/backtest")
8097
8220
  * @param columns - Column configuration for formatting the table
@@ -8101,48 +8224,48 @@ class BacktestMarkdownService {
8101
8224
  * const service = new BacktestMarkdownService();
8102
8225
  *
8103
8226
  * // Save to default path: ./dump/backtest/my-strategy.md
8104
- * await service.dump("BTCUSDT", "my-strategy", true);
8227
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true);
8105
8228
  *
8106
8229
  * // Save to custom path: ./custom/path/my-strategy.md
8107
- * await service.dump("BTCUSDT", "my-strategy", true, "./custom/path");
8230
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true, "./custom/path");
8108
8231
  * ```
8109
8232
  */
8110
- this.dump = async (symbol, strategyName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
8233
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
8111
8234
  this.loggerService.log("backtestMarkdownService dump", {
8112
8235
  symbol,
8113
8236
  strategyName,
8237
+ exchangeName,
8238
+ frameName,
8114
8239
  backtest,
8115
8240
  path,
8116
8241
  });
8117
- const storage = this.getStorage(symbol, strategyName, backtest);
8242
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8118
8243
  await storage.dump(strategyName, path, columns);
8119
8244
  };
8120
8245
  /**
8121
8246
  * Clears accumulated signal data from storage.
8122
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
8247
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
8123
8248
  * If nothing is provided, clears all data.
8124
8249
  *
8125
- * @param backtest - Backtest mode flag
8126
- * @param ctx - Optional context with symbol and strategyName
8250
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
8127
8251
  *
8128
8252
  * @example
8129
8253
  * ```typescript
8130
8254
  * const service = new BacktestMarkdownService();
8131
8255
  *
8132
- * // Clear specific symbol-strategy-backtest triple
8133
- * await service.clear(true, { symbol: "BTCUSDT", strategyName: "my-strategy" });
8256
+ * // Clear specific combination
8257
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: true });
8134
8258
  *
8135
8259
  * // Clear all data
8136
8260
  * await service.clear();
8137
8261
  * ```
8138
8262
  */
8139
- this.clear = async (backtest, ctx) => {
8263
+ this.clear = async (payload) => {
8140
8264
  this.loggerService.log("backtestMarkdownService clear", {
8141
- backtest,
8142
- ctx,
8265
+ payload,
8143
8266
  });
8144
- if (ctx) {
8145
- const key = CREATE_KEY_FN$9(ctx.symbol, ctx.strategyName, backtest);
8267
+ if (payload) {
8268
+ const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
8146
8269
  this.getStorage.clear(key);
8147
8270
  }
8148
8271
  else {
@@ -8169,13 +8292,21 @@ class BacktestMarkdownService {
8169
8292
 
8170
8293
  /**
8171
8294
  * Creates a unique key for memoizing ReportStorage instances.
8172
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
8295
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
8173
8296
  * @param symbol - Trading pair symbol
8174
8297
  * @param strategyName - Name of the strategy
8298
+ * @param exchangeName - Exchange name
8299
+ * @param frameName - Frame name
8175
8300
  * @param backtest - Whether running in backtest mode
8176
8301
  * @returns Unique string key for memoization
8177
8302
  */
8178
- const CREATE_KEY_FN$8 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
8303
+ const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
8304
+ const parts = [symbol, strategyName, exchangeName];
8305
+ if (frameName)
8306
+ parts.push(frameName);
8307
+ parts.push(backtest ? "backtest" : "live");
8308
+ return parts.join(":");
8309
+ };
8179
8310
  /**
8180
8311
  * Checks if a value is unsafe for display (not a number, NaN, or Infinity).
8181
8312
  *
@@ -8502,17 +8633,17 @@ class LiveMarkdownService {
8502
8633
  /** Logger service for debug output */
8503
8634
  this.loggerService = inject(TYPES.loggerService);
8504
8635
  /**
8505
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
8506
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
8636
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
8637
+ * Each combination gets its own isolated storage instance.
8507
8638
  */
8508
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, backtest), () => new ReportStorage$4());
8639
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$4());
8509
8640
  /**
8510
8641
  * Processes tick events and accumulates all event types.
8511
8642
  * Should be called from IStrategyCallbacks.onTick.
8512
8643
  *
8513
8644
  * Processes all event types: idle, opened, active, closed.
8514
8645
  *
8515
- * @param data - Tick result from strategy execution
8646
+ * @param data - Tick result from strategy execution with frameName wrapper
8516
8647
  *
8517
8648
  * @example
8518
8649
  * ```typescript
@@ -8531,7 +8662,7 @@ class LiveMarkdownService {
8531
8662
  this.loggerService.log("liveMarkdownService tick", {
8532
8663
  data,
8533
8664
  });
8534
- const storage = this.getStorage(data.symbol, data.strategyName, false);
8665
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, false);
8535
8666
  if (data.action === "idle") {
8536
8667
  storage.addIdleEvent(data.currentPrice);
8537
8668
  }
@@ -8551,23 +8682,27 @@ class LiveMarkdownService {
8551
8682
  *
8552
8683
  * @param symbol - Trading pair symbol
8553
8684
  * @param strategyName - Strategy name to get data for
8685
+ * @param exchangeName - Exchange name
8686
+ * @param frameName - Frame name
8554
8687
  * @param backtest - True if backtest mode, false if live mode
8555
8688
  * @returns Statistical data object with all metrics
8556
8689
  *
8557
8690
  * @example
8558
8691
  * ```typescript
8559
8692
  * const service = new LiveMarkdownService();
8560
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
8693
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
8561
8694
  * console.log(stats.sharpeRatio, stats.winRate);
8562
8695
  * ```
8563
8696
  */
8564
- this.getData = async (symbol, strategyName, backtest) => {
8697
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8565
8698
  this.loggerService.log("liveMarkdownService getData", {
8566
8699
  symbol,
8567
8700
  strategyName,
8701
+ exchangeName,
8702
+ frameName,
8568
8703
  backtest,
8569
8704
  });
8570
- const storage = this.getStorage(symbol, strategyName, backtest);
8705
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8571
8706
  return storage.getData();
8572
8707
  };
8573
8708
  /**
@@ -8576,6 +8711,8 @@ class LiveMarkdownService {
8576
8711
  *
8577
8712
  * @param symbol - Trading pair symbol
8578
8713
  * @param strategyName - Strategy name to generate report for
8714
+ * @param exchangeName - Exchange name
8715
+ * @param frameName - Frame name
8579
8716
  * @param backtest - True if backtest mode, false if live mode
8580
8717
  * @param columns - Column configuration for formatting the table
8581
8718
  * @returns Markdown formatted report string with table of all events
@@ -8583,17 +8720,19 @@ class LiveMarkdownService {
8583
8720
  * @example
8584
8721
  * ```typescript
8585
8722
  * const service = new LiveMarkdownService();
8586
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
8723
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
8587
8724
  * console.log(markdown);
8588
8725
  * ```
8589
8726
  */
8590
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.live_columns) => {
8727
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.live_columns) => {
8591
8728
  this.loggerService.log("liveMarkdownService getReport", {
8592
8729
  symbol,
8593
8730
  strategyName,
8731
+ exchangeName,
8732
+ frameName,
8594
8733
  backtest,
8595
8734
  });
8596
- const storage = this.getStorage(symbol, strategyName, backtest);
8735
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8597
8736
  return storage.getReport(strategyName, columns);
8598
8737
  };
8599
8738
  /**
@@ -8603,6 +8742,8 @@ class LiveMarkdownService {
8603
8742
  *
8604
8743
  * @param symbol - Trading pair symbol
8605
8744
  * @param strategyName - Strategy name to save report for
8745
+ * @param exchangeName - Exchange name
8746
+ * @param frameName - Frame name
8606
8747
  * @param backtest - True if backtest mode, false if live mode
8607
8748
  * @param path - Directory path to save report (default: "./dump/live")
8608
8749
  * @param columns - Column configuration for formatting the table
@@ -8612,48 +8753,48 @@ class LiveMarkdownService {
8612
8753
  * const service = new LiveMarkdownService();
8613
8754
  *
8614
8755
  * // Save to default path: ./dump/live/my-strategy.md
8615
- * await service.dump("BTCUSDT", "my-strategy", false);
8756
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
8616
8757
  *
8617
8758
  * // Save to custom path: ./custom/path/my-strategy.md
8618
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
8759
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
8619
8760
  * ```
8620
8761
  */
8621
- this.dump = async (symbol, strategyName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
8762
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
8622
8763
  this.loggerService.log("liveMarkdownService dump", {
8623
8764
  symbol,
8624
8765
  strategyName,
8766
+ exchangeName,
8767
+ frameName,
8625
8768
  backtest,
8626
8769
  path,
8627
8770
  });
8628
- const storage = this.getStorage(symbol, strategyName, backtest);
8771
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8629
8772
  await storage.dump(strategyName, path, columns);
8630
8773
  };
8631
8774
  /**
8632
8775
  * Clears accumulated event data from storage.
8633
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
8776
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
8634
8777
  * If nothing is provided, clears all data.
8635
8778
  *
8636
- * @param backtest - Backtest mode flag
8637
- * @param ctx - Optional context with symbol and strategyName
8779
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
8638
8780
  *
8639
8781
  * @example
8640
8782
  * ```typescript
8641
8783
  * const service = new LiveMarkdownService();
8642
8784
  *
8643
- * // Clear specific symbol-strategy-backtest triple
8644
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
8785
+ * // Clear specific combination
8786
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
8645
8787
  *
8646
8788
  * // Clear all data
8647
8789
  * await service.clear();
8648
8790
  * ```
8649
8791
  */
8650
- this.clear = async (backtest, ctx) => {
8792
+ this.clear = async (payload) => {
8651
8793
  this.loggerService.log("liveMarkdownService clear", {
8652
- backtest,
8653
- ctx,
8794
+ payload,
8654
8795
  });
8655
- if (ctx) {
8656
- const key = CREATE_KEY_FN$8(ctx.symbol, ctx.strategyName, backtest);
8796
+ if (payload) {
8797
+ const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
8657
8798
  this.getStorage.clear(key);
8658
8799
  }
8659
8800
  else {
@@ -8680,13 +8821,21 @@ class LiveMarkdownService {
8680
8821
 
8681
8822
  /**
8682
8823
  * Creates a unique key for memoizing ReportStorage instances.
8683
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
8824
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
8684
8825
  * @param symbol - Trading pair symbol
8685
8826
  * @param strategyName - Name of the strategy
8827
+ * @param exchangeName - Exchange name
8828
+ * @param frameName - Frame name
8686
8829
  * @param backtest - Whether running in backtest mode
8687
8830
  * @returns Unique string key for memoization
8688
8831
  */
8689
- const CREATE_KEY_FN$7 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
8832
+ const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
8833
+ const parts = [symbol, strategyName, exchangeName];
8834
+ if (frameName)
8835
+ parts.push(frameName);
8836
+ parts.push(backtest ? "backtest" : "live");
8837
+ return parts.join(":");
8838
+ };
8690
8839
  /** Maximum number of events to store in schedule reports */
8691
8840
  const MAX_EVENTS$4 = 250;
8692
8841
  /**
@@ -8919,17 +9068,17 @@ class ScheduleMarkdownService {
8919
9068
  /** Logger service for debug output */
8920
9069
  this.loggerService = inject(TYPES.loggerService);
8921
9070
  /**
8922
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
8923
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
9071
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
9072
+ * Each combination gets its own isolated storage instance.
8924
9073
  */
8925
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, backtest), () => new ReportStorage$3());
9074
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$3());
8926
9075
  /**
8927
9076
  * Processes tick events and accumulates scheduled/opened/cancelled events.
8928
9077
  * Should be called from signalEmitter subscription.
8929
9078
  *
8930
9079
  * Processes only scheduled, opened and cancelled event types.
8931
9080
  *
8932
- * @param data - Tick result from strategy execution
9081
+ * @param data - Tick result from strategy execution with frameName wrapper
8933
9082
  *
8934
9083
  * @example
8935
9084
  * ```typescript
@@ -8941,7 +9090,7 @@ class ScheduleMarkdownService {
8941
9090
  this.loggerService.log("scheduleMarkdownService tick", {
8942
9091
  data,
8943
9092
  });
8944
- const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
9093
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
8945
9094
  if (data.action === "scheduled") {
8946
9095
  storage.addScheduledEvent(data);
8947
9096
  }
@@ -8962,23 +9111,27 @@ class ScheduleMarkdownService {
8962
9111
  *
8963
9112
  * @param symbol - Trading pair symbol
8964
9113
  * @param strategyName - Strategy name to get data for
9114
+ * @param exchangeName - Exchange name
9115
+ * @param frameName - Frame name
8965
9116
  * @param backtest - True if backtest mode, false if live mode
8966
9117
  * @returns Statistical data object with all metrics
8967
9118
  *
8968
9119
  * @example
8969
9120
  * ```typescript
8970
9121
  * const service = new ScheduleMarkdownService();
8971
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
9122
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
8972
9123
  * console.log(stats.cancellationRate, stats.avgWaitTime);
8973
9124
  * ```
8974
9125
  */
8975
- this.getData = async (symbol, strategyName, backtest) => {
9126
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8976
9127
  this.loggerService.log("scheduleMarkdownService getData", {
8977
9128
  symbol,
8978
9129
  strategyName,
9130
+ exchangeName,
9131
+ frameName,
8979
9132
  backtest,
8980
9133
  });
8981
- const storage = this.getStorage(symbol, strategyName, backtest);
9134
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8982
9135
  return storage.getData();
8983
9136
  };
8984
9137
  /**
@@ -8987,6 +9140,8 @@ class ScheduleMarkdownService {
8987
9140
  *
8988
9141
  * @param symbol - Trading pair symbol
8989
9142
  * @param strategyName - Strategy name to generate report for
9143
+ * @param exchangeName - Exchange name
9144
+ * @param frameName - Frame name
8990
9145
  * @param backtest - True if backtest mode, false if live mode
8991
9146
  * @param columns - Column configuration for formatting the table
8992
9147
  * @returns Markdown formatted report string with table of all events
@@ -8994,17 +9149,19 @@ class ScheduleMarkdownService {
8994
9149
  * @example
8995
9150
  * ```typescript
8996
9151
  * const service = new ScheduleMarkdownService();
8997
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
9152
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
8998
9153
  * console.log(markdown);
8999
9154
  * ```
9000
9155
  */
9001
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
9156
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
9002
9157
  this.loggerService.log("scheduleMarkdownService getReport", {
9003
9158
  symbol,
9004
9159
  strategyName,
9160
+ exchangeName,
9161
+ frameName,
9005
9162
  backtest,
9006
9163
  });
9007
- const storage = this.getStorage(symbol, strategyName, backtest);
9164
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9008
9165
  return storage.getReport(strategyName, columns);
9009
9166
  };
9010
9167
  /**
@@ -9014,6 +9171,8 @@ class ScheduleMarkdownService {
9014
9171
  *
9015
9172
  * @param symbol - Trading pair symbol
9016
9173
  * @param strategyName - Strategy name to save report for
9174
+ * @param exchangeName - Exchange name
9175
+ * @param frameName - Frame name
9017
9176
  * @param backtest - True if backtest mode, false if live mode
9018
9177
  * @param path - Directory path to save report (default: "./dump/schedule")
9019
9178
  * @param columns - Column configuration for formatting the table
@@ -9023,48 +9182,48 @@ class ScheduleMarkdownService {
9023
9182
  * const service = new ScheduleMarkdownService();
9024
9183
  *
9025
9184
  * // Save to default path: ./dump/schedule/my-strategy.md
9026
- * await service.dump("BTCUSDT", "my-strategy", false);
9185
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
9027
9186
  *
9028
9187
  * // Save to custom path: ./custom/path/my-strategy.md
9029
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
9188
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
9030
9189
  * ```
9031
9190
  */
9032
- this.dump = async (symbol, strategyName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
9191
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
9033
9192
  this.loggerService.log("scheduleMarkdownService dump", {
9034
9193
  symbol,
9035
9194
  strategyName,
9195
+ exchangeName,
9196
+ frameName,
9036
9197
  backtest,
9037
9198
  path,
9038
9199
  });
9039
- const storage = this.getStorage(symbol, strategyName, backtest);
9200
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9040
9201
  await storage.dump(strategyName, path, columns);
9041
9202
  };
9042
9203
  /**
9043
9204
  * Clears accumulated event data from storage.
9044
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
9205
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
9045
9206
  * If nothing is provided, clears all data.
9046
9207
  *
9047
- * @param backtest - Backtest mode flag
9048
- * @param ctx - Optional context with symbol and strategyName
9208
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
9049
9209
  *
9050
9210
  * @example
9051
9211
  * ```typescript
9052
9212
  * const service = new ScheduleMarkdownService();
9053
9213
  *
9054
- * // Clear specific symbol-strategy-backtest triple
9055
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
9214
+ * // Clear specific combination
9215
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
9056
9216
  *
9057
9217
  * // Clear all data
9058
9218
  * await service.clear();
9059
9219
  * ```
9060
9220
  */
9061
- this.clear = async (backtest, ctx) => {
9221
+ this.clear = async (payload) => {
9062
9222
  this.loggerService.log("scheduleMarkdownService clear", {
9063
- backtest,
9064
- ctx,
9223
+ payload,
9065
9224
  });
9066
- if (ctx) {
9067
- const key = CREATE_KEY_FN$7(ctx.symbol, ctx.strategyName, backtest);
9225
+ if (payload) {
9226
+ const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
9068
9227
  this.getStorage.clear(key);
9069
9228
  }
9070
9229
  else {
@@ -9091,13 +9250,21 @@ class ScheduleMarkdownService {
9091
9250
 
9092
9251
  /**
9093
9252
  * Creates a unique key for memoizing PerformanceStorage instances.
9094
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
9253
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
9095
9254
  * @param symbol - Trading pair symbol
9096
9255
  * @param strategyName - Name of the strategy
9256
+ * @param exchangeName - Exchange name
9257
+ * @param frameName - Frame name
9097
9258
  * @param backtest - Whether running in backtest mode
9098
9259
  * @returns Unique string key for memoization
9099
9260
  */
9100
- const CREATE_KEY_FN$6 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
9261
+ const CREATE_KEY_FN$6 = (symbol, strategyName, exchangeName, frameName, backtest) => {
9262
+ const parts = [symbol, strategyName, exchangeName];
9263
+ if (frameName)
9264
+ parts.push(frameName);
9265
+ parts.push(backtest ? "backtest" : "live");
9266
+ return parts.join(":");
9267
+ };
9101
9268
  /**
9102
9269
  * Calculates percentile value from sorted array.
9103
9270
  */
@@ -9312,10 +9479,10 @@ class PerformanceMarkdownService {
9312
9479
  /** Logger service for debug output */
9313
9480
  this.loggerService = inject(TYPES.loggerService);
9314
9481
  /**
9315
- * Memoized function to get or create PerformanceStorage for a symbol-strategy-backtest triple.
9316
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
9482
+ * Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
9483
+ * Each combination gets its own isolated storage instance.
9317
9484
  */
9318
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, backtest), () => new PerformanceStorage());
9485
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, exchangeName, frameName, backtest), () => new PerformanceStorage());
9319
9486
  /**
9320
9487
  * Processes performance events and accumulates metrics.
9321
9488
  * Should be called from performance tracking code.
@@ -9328,7 +9495,8 @@ class PerformanceMarkdownService {
9328
9495
  });
9329
9496
  const symbol = event.symbol || "global";
9330
9497
  const strategyName = event.strategyName || "global";
9331
- const storage = this.getStorage(symbol, strategyName, event.backtest);
9498
+ const exchangeName = event.exchangeName || "global";
9499
+ const storage = this.getStorage(symbol, strategyName, exchangeName, event.frameName, event.backtest);
9332
9500
  storage.addEvent(event);
9333
9501
  };
9334
9502
  /**
@@ -9336,24 +9504,28 @@ class PerformanceMarkdownService {
9336
9504
  *
9337
9505
  * @param symbol - Trading pair symbol
9338
9506
  * @param strategyName - Strategy name to get data for
9507
+ * @param exchangeName - Exchange name
9508
+ * @param frameName - Frame name
9339
9509
  * @param backtest - True if backtest mode, false if live mode
9340
9510
  * @returns Performance statistics with aggregated metrics
9341
9511
  *
9342
9512
  * @example
9343
9513
  * ```typescript
9344
- * const stats = await performanceService.getData("BTCUSDT", "my-strategy", false);
9514
+ * const stats = await performanceService.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
9345
9515
  * console.log("Total time:", stats.totalDuration);
9346
9516
  * console.log("Slowest operation:", Object.values(stats.metricStats)
9347
9517
  * .sort((a, b) => b.avgDuration - a.avgDuration)[0]);
9348
9518
  * ```
9349
9519
  */
9350
- this.getData = async (symbol, strategyName, backtest) => {
9520
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
9351
9521
  this.loggerService.log("performanceMarkdownService getData", {
9352
9522
  symbol,
9353
9523
  strategyName,
9524
+ exchangeName,
9525
+ frameName,
9354
9526
  backtest,
9355
9527
  });
9356
- const storage = this.getStorage(symbol, strategyName, backtest);
9528
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9357
9529
  return storage.getData(strategyName);
9358
9530
  };
9359
9531
  /**
@@ -9361,23 +9533,27 @@ class PerformanceMarkdownService {
9361
9533
  *
9362
9534
  * @param symbol - Trading pair symbol
9363
9535
  * @param strategyName - Strategy name to generate report for
9536
+ * @param exchangeName - Exchange name
9537
+ * @param frameName - Frame name
9364
9538
  * @param backtest - True if backtest mode, false if live mode
9365
9539
  * @param columns - Column configuration for formatting the table
9366
9540
  * @returns Markdown formatted report string
9367
9541
  *
9368
9542
  * @example
9369
9543
  * ```typescript
9370
- * const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", false);
9544
+ * const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
9371
9545
  * console.log(markdown);
9372
9546
  * ```
9373
9547
  */
9374
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
9548
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
9375
9549
  this.loggerService.log("performanceMarkdownService getReport", {
9376
9550
  symbol,
9377
9551
  strategyName,
9552
+ exchangeName,
9553
+ frameName,
9378
9554
  backtest,
9379
9555
  });
9380
- const storage = this.getStorage(symbol, strategyName, backtest);
9556
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9381
9557
  return storage.getReport(strategyName, columns);
9382
9558
  };
9383
9559
  /**
@@ -9385,6 +9561,8 @@ class PerformanceMarkdownService {
9385
9561
  *
9386
9562
  * @param symbol - Trading pair symbol
9387
9563
  * @param strategyName - Strategy name to save report for
9564
+ * @param exchangeName - Exchange name
9565
+ * @param frameName - Frame name
9388
9566
  * @param backtest - True if backtest mode, false if live mode
9389
9567
  * @param path - Directory path to save report
9390
9568
  * @param columns - Column configuration for formatting the table
@@ -9392,35 +9570,35 @@ class PerformanceMarkdownService {
9392
9570
  * @example
9393
9571
  * ```typescript
9394
9572
  * // Save to default path: ./dump/performance/my-strategy.md
9395
- * await performanceService.dump("BTCUSDT", "my-strategy", false);
9573
+ * await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
9396
9574
  *
9397
9575
  * // Save to custom path
9398
- * await performanceService.dump("BTCUSDT", "my-strategy", false, "./custom/path");
9576
+ * await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
9399
9577
  * ```
9400
9578
  */
9401
- this.dump = async (symbol, strategyName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
9579
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
9402
9580
  this.loggerService.log("performanceMarkdownService dump", {
9403
9581
  symbol,
9404
9582
  strategyName,
9583
+ exchangeName,
9584
+ frameName,
9405
9585
  backtest,
9406
9586
  path,
9407
9587
  });
9408
- const storage = this.getStorage(symbol, strategyName, backtest);
9588
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9409
9589
  await storage.dump(strategyName, path, columns);
9410
9590
  };
9411
9591
  /**
9412
9592
  * Clears accumulated performance data from storage.
9413
9593
  *
9414
- * @param backtest - Backtest mode flag
9415
- * @param ctx - Optional context with symbol and strategyName
9594
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
9416
9595
  */
9417
- this.clear = async (backtest, ctx) => {
9596
+ this.clear = async (payload) => {
9418
9597
  this.loggerService.log("performanceMarkdownService clear", {
9419
- backtest,
9420
- ctx,
9598
+ payload,
9421
9599
  });
9422
- if (ctx) {
9423
- const key = CREATE_KEY_FN$6(ctx.symbol, ctx.strategyName, backtest);
9600
+ if (payload) {
9601
+ const key = CREATE_KEY_FN$6(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
9424
9602
  this.getStorage.clear(key);
9425
9603
  }
9426
9604
  else {
@@ -9849,12 +10027,19 @@ class WalkerMarkdownService {
9849
10027
 
9850
10028
  /**
9851
10029
  * Creates a unique key for memoizing HeatmapStorage instances.
9852
- * Key format: "strategyName:backtest" or "strategyName:live"
9853
- * @param strategyName - Name of the strategy
10030
+ * Key format: "exchangeName:frameName:backtest" or "exchangeName:live"
10031
+ * @param exchangeName - Exchange name
10032
+ * @param frameName - Frame name
9854
10033
  * @param backtest - Whether running in backtest mode
9855
10034
  * @returns Unique string key for memoization
9856
10035
  */
9857
- const CREATE_KEY_FN$5 = (strategyName, backtest) => `${strategyName}:${backtest ? "backtest" : "live"}`;
10036
+ const CREATE_KEY_FN$5 = (exchangeName, frameName, backtest) => {
10037
+ const parts = [exchangeName];
10038
+ if (frameName)
10039
+ parts.push(frameName);
10040
+ parts.push(backtest ? "backtest" : "live");
10041
+ return parts.join(":");
10042
+ };
9858
10043
  const HEATMAP_METHOD_NAME_GET_DATA = "HeatMarkdownService.getData";
9859
10044
  const HEATMAP_METHOD_NAME_GET_REPORT = "HeatMarkdownService.getReport";
9860
10045
  const HEATMAP_METHOD_NAME_DUMP = "HeatMarkdownService.dump";
@@ -10195,10 +10380,10 @@ class HeatMarkdownService {
10195
10380
  /** Logger service for debug output */
10196
10381
  this.loggerService = inject(TYPES.loggerService);
10197
10382
  /**
10198
- * Memoized function to get or create HeatmapStorage for a strategy and backtest mode.
10199
- * Each strategy + backtest mode combination gets its own isolated heatmap storage instance.
10383
+ * Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
10384
+ * Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
10200
10385
  */
10201
- this.getStorage = functoolsKit.memoize(([strategyName, backtest]) => CREATE_KEY_FN$5(strategyName, backtest), () => new HeatmapStorage());
10386
+ this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$5(exchangeName, frameName, backtest), () => new HeatmapStorage());
10202
10387
  /**
10203
10388
  * Processes tick events and accumulates closed signals.
10204
10389
  * Should be called from signal emitter subscription.
@@ -10214,20 +10399,21 @@ class HeatMarkdownService {
10214
10399
  if (data.action !== "closed") {
10215
10400
  return;
10216
10401
  }
10217
- const storage = this.getStorage(data.strategyName, data.backtest);
10402
+ const storage = this.getStorage(data.exchangeName, data.frameName, data.backtest);
10218
10403
  storage.addSignal(data);
10219
10404
  };
10220
10405
  /**
10221
- * Gets aggregated portfolio heatmap statistics for a strategy.
10406
+ * Gets aggregated portfolio heatmap statistics.
10222
10407
  *
10223
- * @param strategyName - Strategy name to get heatmap data for
10408
+ * @param exchangeName - Exchange name
10409
+ * @param frameName - Frame name
10224
10410
  * @param backtest - True if backtest mode, false if live mode
10225
10411
  * @returns Promise resolving to heatmap statistics with per-symbol and portfolio-wide metrics
10226
10412
  *
10227
10413
  * @example
10228
10414
  * ```typescript
10229
10415
  * const service = new HeatMarkdownService();
10230
- * const stats = await service.getData("my-strategy", true);
10416
+ * const stats = await service.getData("binance", "frame1", true);
10231
10417
  *
10232
10418
  * console.log(`Total symbols: ${stats.totalSymbols}`);
10233
10419
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
@@ -10237,18 +10423,21 @@ class HeatMarkdownService {
10237
10423
  * });
10238
10424
  * ```
10239
10425
  */
10240
- this.getData = async (strategyName, backtest) => {
10426
+ this.getData = async (exchangeName, frameName, backtest) => {
10241
10427
  this.loggerService.log(HEATMAP_METHOD_NAME_GET_DATA, {
10242
- strategyName,
10428
+ exchangeName,
10429
+ frameName,
10243
10430
  backtest,
10244
10431
  });
10245
- const storage = this.getStorage(strategyName, backtest);
10432
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10246
10433
  return storage.getData();
10247
10434
  };
10248
10435
  /**
10249
- * Generates markdown report with portfolio heatmap table for a strategy.
10436
+ * Generates markdown report with portfolio heatmap table.
10250
10437
  *
10251
- * @param strategyName - Strategy name to generate heatmap report for
10438
+ * @param strategyName - Strategy name for report title
10439
+ * @param exchangeName - Exchange name
10440
+ * @param frameName - Frame name
10252
10441
  * @param backtest - True if backtest mode, false if live mode
10253
10442
  * @param columns - Column configuration for formatting the table
10254
10443
  * @returns Promise resolving to markdown formatted report string
@@ -10256,7 +10445,7 @@ class HeatMarkdownService {
10256
10445
  * @example
10257
10446
  * ```typescript
10258
10447
  * const service = new HeatMarkdownService();
10259
- * const markdown = await service.getReport("my-strategy", true);
10448
+ * const markdown = await service.getReport("my-strategy", "binance", "frame1", true);
10260
10449
  * console.log(markdown);
10261
10450
  * // Output:
10262
10451
  * // # Portfolio Heatmap: my-strategy
@@ -10270,21 +10459,25 @@ class HeatMarkdownService {
10270
10459
  * // ...
10271
10460
  * ```
10272
10461
  */
10273
- this.getReport = async (strategyName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
10462
+ this.getReport = async (strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
10274
10463
  this.loggerService.log(HEATMAP_METHOD_NAME_GET_REPORT, {
10275
10464
  strategyName,
10465
+ exchangeName,
10466
+ frameName,
10276
10467
  backtest,
10277
10468
  });
10278
- const storage = this.getStorage(strategyName, backtest);
10469
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10279
10470
  return storage.getReport(strategyName, columns);
10280
10471
  };
10281
10472
  /**
10282
- * Saves heatmap report to disk for a strategy.
10473
+ * Saves heatmap report to disk.
10283
10474
  *
10284
10475
  * Creates directory if it doesn't exist.
10285
10476
  * Default filename: {strategyName}.md
10286
10477
  *
10287
- * @param strategyName - Strategy name to save heatmap report for
10478
+ * @param strategyName - Strategy name for report filename
10479
+ * @param exchangeName - Exchange name
10480
+ * @param frameName - Frame name
10288
10481
  * @param backtest - True if backtest mode, false if live mode
10289
10482
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
10290
10483
  * @param columns - Column configuration for formatting the table
@@ -10294,47 +10487,47 @@ class HeatMarkdownService {
10294
10487
  * const service = new HeatMarkdownService();
10295
10488
  *
10296
10489
  * // Save to default path: ./dump/heatmap/my-strategy.md
10297
- * await service.dump("my-strategy", true);
10490
+ * await service.dump("my-strategy", "binance", "frame1", true);
10298
10491
  *
10299
10492
  * // Save to custom path: ./reports/my-strategy.md
10300
- * await service.dump("my-strategy", true, "./reports");
10493
+ * await service.dump("my-strategy", "binance", "frame1", true, "./reports");
10301
10494
  * ```
10302
10495
  */
10303
- this.dump = async (strategyName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
10496
+ this.dump = async (strategyName, exchangeName, frameName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
10304
10497
  this.loggerService.log(HEATMAP_METHOD_NAME_DUMP, {
10305
10498
  strategyName,
10499
+ exchangeName,
10500
+ frameName,
10306
10501
  backtest,
10307
10502
  path,
10308
10503
  });
10309
- const storage = this.getStorage(strategyName, backtest);
10504
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10310
10505
  await storage.dump(strategyName, path, columns);
10311
10506
  };
10312
10507
  /**
10313
10508
  * Clears accumulated heatmap data from storage.
10314
- * If ctx is provided, clears only that strategy+backtest combination's data.
10315
- * If ctx is omitted, clears all data.
10509
+ * If payload is provided, clears only that exchangeName+frameName+backtest combination's data.
10510
+ * If payload is omitted, clears all data.
10316
10511
  *
10317
- * @param backtest - Backtest mode flag
10318
- * @param ctx - Optional context with strategyName to clear specific data
10512
+ * @param payload - Optional payload with exchangeName, frameName, backtest to clear specific data
10319
10513
  *
10320
10514
  * @example
10321
10515
  * ```typescript
10322
10516
  * const service = new HeatMarkdownService();
10323
10517
  *
10324
- * // Clear specific strategy+backtest data
10325
- * await service.clear(true, { strategyName: "my-strategy" });
10518
+ * // Clear specific exchange+frame+backtest data
10519
+ * await service.clear({ exchangeName: "binance", frameName: "frame1", backtest: true });
10326
10520
  *
10327
10521
  * // Clear all data
10328
10522
  * await service.clear();
10329
10523
  * ```
10330
10524
  */
10331
- this.clear = async (backtest, ctx) => {
10525
+ this.clear = async (payload) => {
10332
10526
  this.loggerService.log(HEATMAP_METHOD_NAME_CLEAR, {
10333
- backtest,
10334
- ctx,
10527
+ payload,
10335
10528
  });
10336
- if (ctx) {
10337
- const key = CREATE_KEY_FN$5(ctx.strategyName, backtest);
10529
+ if (payload) {
10530
+ const key = CREATE_KEY_FN$5(payload.exchangeName, payload.frameName, payload.backtest);
10338
10531
  this.getStorage.clear(key);
10339
10532
  }
10340
10533
  else {
@@ -12192,7 +12385,7 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
12192
12385
  revenuePercent,
12193
12386
  backtest,
12194
12387
  });
12195
- await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
12388
+ await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
12196
12389
  }
12197
12390
  }
12198
12391
  if (shouldPersist) {
@@ -12242,7 +12435,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
12242
12435
  lossPercent,
12243
12436
  backtest,
12244
12437
  });
12245
- await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
12438
+ await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
12246
12439
  }
12247
12440
  }
12248
12441
  if (shouldPersist) {
@@ -12568,10 +12761,11 @@ const CREATE_KEY_FN$4 = (signalId, backtest) => `${signalId}:${backtest ? "backt
12568
12761
  * @param backtest - True if backtest mode
12569
12762
  * @param timestamp - Event timestamp in milliseconds
12570
12763
  */
12571
- const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
12764
+ const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
12572
12765
  symbol,
12573
12766
  strategyName,
12574
12767
  exchangeName,
12768
+ frameName,
12575
12769
  data,
12576
12770
  currentPrice,
12577
12771
  level,
@@ -12593,10 +12787,11 @@ const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, curren
12593
12787
  * @param backtest - True if backtest mode
12594
12788
  * @param timestamp - Event timestamp in milliseconds
12595
12789
  */
12596
- const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
12790
+ const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
12597
12791
  symbol,
12598
12792
  strategyName,
12599
12793
  exchangeName,
12794
+ frameName,
12600
12795
  data,
12601
12796
  currentPrice,
12602
12797
  level,
@@ -12748,11 +12943,21 @@ class PartialConnectionService {
12748
12943
 
12749
12944
  /**
12750
12945
  * Creates a unique key for memoizing ReportStorage instances.
12751
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
12752
- * @param param0 - Tuple of symbol, strategyName and backtest boolean
12946
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
12947
+ * @param symbol - Trading pair symbol
12948
+ * @param strategyName - Name of the strategy
12949
+ * @param exchangeName - Exchange name
12950
+ * @param frameName - Frame name
12951
+ * @param backtest - Whether running in backtest mode
12753
12952
  * @returns Unique string key for memoization
12754
12953
  */
12755
- const CREATE_KEY_FN$3 = ([symbol, strategyName, backtest]) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
12954
+ const CREATE_KEY_FN$3 = (symbol, strategyName, exchangeName, frameName, backtest) => {
12955
+ const parts = [symbol, strategyName, exchangeName];
12956
+ if (frameName)
12957
+ parts.push(frameName);
12958
+ parts.push(backtest ? "backtest" : "live");
12959
+ return parts.join(":");
12960
+ };
12756
12961
  /** Maximum number of events to store in partial reports */
12757
12962
  const MAX_EVENTS$1 = 250;
12758
12963
  /**
@@ -12924,15 +13129,15 @@ class PartialMarkdownService {
12924
13129
  /** Logger service for debug output */
12925
13130
  this.loggerService = inject(TYPES.loggerService);
12926
13131
  /**
12927
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
12928
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
13132
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
13133
+ * Each combination gets its own isolated storage instance.
12929
13134
  */
12930
- this.getStorage = functoolsKit.memoize(CREATE_KEY_FN$3, () => new ReportStorage$1());
13135
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$3(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$1());
12931
13136
  /**
12932
13137
  * Processes profit events and accumulates them.
12933
13138
  * Should be called from partialProfitSubject subscription.
12934
13139
  *
12935
- * @param data - Profit event data
13140
+ * @param data - Profit event data with frameName wrapper
12936
13141
  *
12937
13142
  * @example
12938
13143
  * ```typescript
@@ -12944,14 +13149,14 @@ class PartialMarkdownService {
12944
13149
  this.loggerService.log("partialMarkdownService tickProfit", {
12945
13150
  data,
12946
13151
  });
12947
- const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
13152
+ const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
12948
13153
  storage.addProfitEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
12949
13154
  };
12950
13155
  /**
12951
13156
  * Processes loss events and accumulates them.
12952
13157
  * Should be called from partialLossSubject subscription.
12953
13158
  *
12954
- * @param data - Loss event data
13159
+ * @param data - Loss event data with frameName wrapper
12955
13160
  *
12956
13161
  * @example
12957
13162
  * ```typescript
@@ -12963,7 +13168,7 @@ class PartialMarkdownService {
12963
13168
  this.loggerService.log("partialMarkdownService tickLoss", {
12964
13169
  data,
12965
13170
  });
12966
- const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
13171
+ const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
12967
13172
  storage.addLossEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
12968
13173
  };
12969
13174
  /**
@@ -12972,23 +13177,27 @@ class PartialMarkdownService {
12972
13177
  *
12973
13178
  * @param symbol - Trading pair symbol to get data for
12974
13179
  * @param strategyName - Strategy name to get data for
13180
+ * @param exchangeName - Exchange name
13181
+ * @param frameName - Frame name
12975
13182
  * @param backtest - True if backtest mode, false if live mode
12976
13183
  * @returns Statistical data object with all metrics
12977
13184
  *
12978
13185
  * @example
12979
13186
  * ```typescript
12980
13187
  * const service = new PartialMarkdownService();
12981
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
13188
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
12982
13189
  * console.log(stats.totalProfit, stats.totalLoss);
12983
13190
  * ```
12984
13191
  */
12985
- this.getData = async (symbol, strategyName, backtest) => {
13192
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
12986
13193
  this.loggerService.log("partialMarkdownService getData", {
12987
13194
  symbol,
12988
13195
  strategyName,
13196
+ exchangeName,
13197
+ frameName,
12989
13198
  backtest,
12990
13199
  });
12991
- const storage = this.getStorage(symbol, strategyName, backtest);
13200
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
12992
13201
  return storage.getData();
12993
13202
  };
12994
13203
  /**
@@ -12997,6 +13206,8 @@ class PartialMarkdownService {
12997
13206
  *
12998
13207
  * @param symbol - Trading pair symbol to generate report for
12999
13208
  * @param strategyName - Strategy name to generate report for
13209
+ * @param exchangeName - Exchange name
13210
+ * @param frameName - Frame name
13000
13211
  * @param backtest - True if backtest mode, false if live mode
13001
13212
  * @param columns - Column configuration for formatting the table
13002
13213
  * @returns Markdown formatted report string with table of all events
@@ -13004,17 +13215,19 @@ class PartialMarkdownService {
13004
13215
  * @example
13005
13216
  * ```typescript
13006
13217
  * const service = new PartialMarkdownService();
13007
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
13218
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
13008
13219
  * console.log(markdown);
13009
13220
  * ```
13010
13221
  */
13011
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
13222
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
13012
13223
  this.loggerService.log("partialMarkdownService getReport", {
13013
13224
  symbol,
13014
13225
  strategyName,
13226
+ exchangeName,
13227
+ frameName,
13015
13228
  backtest,
13016
13229
  });
13017
- const storage = this.getStorage(symbol, strategyName, backtest);
13230
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13018
13231
  return storage.getReport(symbol, strategyName, columns);
13019
13232
  };
13020
13233
  /**
@@ -13024,6 +13237,8 @@ class PartialMarkdownService {
13024
13237
  *
13025
13238
  * @param symbol - Trading pair symbol to save report for
13026
13239
  * @param strategyName - Strategy name to save report for
13240
+ * @param exchangeName - Exchange name
13241
+ * @param frameName - Frame name
13027
13242
  * @param backtest - True if backtest mode, false if live mode
13028
13243
  * @param path - Directory path to save report (default: "./dump/partial")
13029
13244
  * @param columns - Column configuration for formatting the table
@@ -13033,48 +13248,48 @@ class PartialMarkdownService {
13033
13248
  * const service = new PartialMarkdownService();
13034
13249
  *
13035
13250
  * // Save to default path: ./dump/partial/BTCUSDT_my-strategy.md
13036
- * await service.dump("BTCUSDT", "my-strategy", false);
13251
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
13037
13252
  *
13038
13253
  * // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
13039
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
13254
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
13040
13255
  * ```
13041
13256
  */
13042
- this.dump = async (symbol, strategyName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
13257
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
13043
13258
  this.loggerService.log("partialMarkdownService dump", {
13044
13259
  symbol,
13045
13260
  strategyName,
13261
+ exchangeName,
13262
+ frameName,
13046
13263
  backtest,
13047
13264
  path,
13048
13265
  });
13049
- const storage = this.getStorage(symbol, strategyName, backtest);
13266
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13050
13267
  await storage.dump(symbol, strategyName, path, columns);
13051
13268
  };
13052
13269
  /**
13053
13270
  * Clears accumulated event data from storage.
13054
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
13271
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
13055
13272
  * If nothing is provided, clears all data.
13056
13273
  *
13057
- * @param backtest - Backtest mode flag
13058
- * @param ctx - Optional context with symbol and strategyName
13274
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
13059
13275
  *
13060
13276
  * @example
13061
13277
  * ```typescript
13062
13278
  * const service = new PartialMarkdownService();
13063
13279
  *
13064
- * // Clear specific symbol-strategy-backtest triple
13065
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
13280
+ * // Clear specific combination
13281
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
13066
13282
  *
13067
13283
  * // Clear all data
13068
13284
  * await service.clear();
13069
13285
  * ```
13070
13286
  */
13071
- this.clear = async (backtest, ctx) => {
13287
+ this.clear = async (payload) => {
13072
13288
  this.loggerService.log("partialMarkdownService clear", {
13073
- backtest,
13074
- ctx,
13289
+ payload,
13075
13290
  });
13076
- if (ctx) {
13077
- const key = CREATE_KEY_FN$3([ctx.symbol, ctx.strategyName, backtest]);
13291
+ if (payload) {
13292
+ const key = CREATE_KEY_FN$3(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
13078
13293
  this.getStorage.clear(key);
13079
13294
  }
13080
13295
  else {
@@ -13247,7 +13462,7 @@ class PartialGlobalService {
13247
13462
  * Warning threshold for message size in kilobytes.
13248
13463
  * Messages exceeding this size trigger console warnings.
13249
13464
  */
13250
- const WARN_KB = 20;
13465
+ const WARN_KB = 30;
13251
13466
  /**
13252
13467
  * Internal function for dumping signal data to markdown files.
13253
13468
  * Creates a directory structure with system prompts, user messages, and LLM output.
@@ -13511,13 +13726,21 @@ class ConfigValidationService {
13511
13726
 
13512
13727
  /**
13513
13728
  * Creates a unique key for memoizing ReportStorage instances.
13514
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
13729
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
13515
13730
  * @param symbol - Trading pair symbol
13516
13731
  * @param strategyName - Name of the strategy
13732
+ * @param exchangeName - Exchange name
13733
+ * @param frameName - Frame name
13517
13734
  * @param backtest - Whether running in backtest mode
13518
13735
  * @returns Unique string key for memoization
13519
13736
  */
13520
- const CREATE_KEY_FN$2 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
13737
+ const CREATE_KEY_FN$2 = (symbol, strategyName, exchangeName, frameName, backtest) => {
13738
+ const parts = [symbol, strategyName, exchangeName];
13739
+ if (frameName)
13740
+ parts.push(frameName);
13741
+ parts.push(backtest ? "backtest" : "live");
13742
+ return parts.join(":");
13743
+ };
13521
13744
  /** Maximum number of events to store in risk reports */
13522
13745
  const MAX_EVENTS = 250;
13523
13746
  /**
@@ -13659,15 +13882,15 @@ class RiskMarkdownService {
13659
13882
  /** Logger service for debug output */
13660
13883
  this.loggerService = inject(TYPES.loggerService);
13661
13884
  /**
13662
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
13663
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
13885
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
13886
+ * Each combination gets its own isolated storage instance.
13664
13887
  */
13665
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, backtest), () => new ReportStorage());
13888
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage());
13666
13889
  /**
13667
13890
  * Processes risk rejection events and accumulates them.
13668
13891
  * Should be called from riskSubject subscription.
13669
13892
  *
13670
- * @param data - Risk rejection event data
13893
+ * @param data - Risk rejection event data with frameName wrapper
13671
13894
  *
13672
13895
  * @example
13673
13896
  * ```typescript
@@ -13679,7 +13902,7 @@ class RiskMarkdownService {
13679
13902
  this.loggerService.log("riskMarkdownService tickRejection", {
13680
13903
  data,
13681
13904
  });
13682
- const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
13905
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
13683
13906
  storage.addRejectionEvent(data);
13684
13907
  };
13685
13908
  /**
@@ -13688,23 +13911,27 @@ class RiskMarkdownService {
13688
13911
  *
13689
13912
  * @param symbol - Trading pair symbol to get data for
13690
13913
  * @param strategyName - Strategy name to get data for
13914
+ * @param exchangeName - Exchange name
13915
+ * @param frameName - Frame name
13691
13916
  * @param backtest - True if backtest mode, false if live mode
13692
13917
  * @returns Statistical data object with all metrics
13693
13918
  *
13694
13919
  * @example
13695
13920
  * ```typescript
13696
13921
  * const service = new RiskMarkdownService();
13697
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
13922
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
13698
13923
  * console.log(stats.totalRejections, stats.bySymbol);
13699
13924
  * ```
13700
13925
  */
13701
- this.getData = async (symbol, strategyName, backtest) => {
13926
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
13702
13927
  this.loggerService.log("riskMarkdownService getData", {
13703
13928
  symbol,
13704
13929
  strategyName,
13930
+ exchangeName,
13931
+ frameName,
13705
13932
  backtest,
13706
13933
  });
13707
- const storage = this.getStorage(symbol, strategyName, backtest);
13934
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13708
13935
  return storage.getData();
13709
13936
  };
13710
13937
  /**
@@ -13713,6 +13940,8 @@ class RiskMarkdownService {
13713
13940
  *
13714
13941
  * @param symbol - Trading pair symbol to generate report for
13715
13942
  * @param strategyName - Strategy name to generate report for
13943
+ * @param exchangeName - Exchange name
13944
+ * @param frameName - Frame name
13716
13945
  * @param backtest - True if backtest mode, false if live mode
13717
13946
  * @param columns - Column configuration for formatting the table
13718
13947
  * @returns Markdown formatted report string with table of all events
@@ -13720,17 +13949,19 @@ class RiskMarkdownService {
13720
13949
  * @example
13721
13950
  * ```typescript
13722
13951
  * const service = new RiskMarkdownService();
13723
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
13952
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
13724
13953
  * console.log(markdown);
13725
13954
  * ```
13726
13955
  */
13727
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
13956
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
13728
13957
  this.loggerService.log("riskMarkdownService getReport", {
13729
13958
  symbol,
13730
13959
  strategyName,
13960
+ exchangeName,
13961
+ frameName,
13731
13962
  backtest,
13732
13963
  });
13733
- const storage = this.getStorage(symbol, strategyName, backtest);
13964
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13734
13965
  return storage.getReport(symbol, strategyName, columns);
13735
13966
  };
13736
13967
  /**
@@ -13740,6 +13971,8 @@ class RiskMarkdownService {
13740
13971
  *
13741
13972
  * @param symbol - Trading pair symbol to save report for
13742
13973
  * @param strategyName - Strategy name to save report for
13974
+ * @param exchangeName - Exchange name
13975
+ * @param frameName - Frame name
13743
13976
  * @param backtest - True if backtest mode, false if live mode
13744
13977
  * @param path - Directory path to save report (default: "./dump/risk")
13745
13978
  * @param columns - Column configuration for formatting the table
@@ -13749,48 +13982,48 @@ class RiskMarkdownService {
13749
13982
  * const service = new RiskMarkdownService();
13750
13983
  *
13751
13984
  * // Save to default path: ./dump/risk/BTCUSDT_my-strategy.md
13752
- * await service.dump("BTCUSDT", "my-strategy", false);
13985
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
13753
13986
  *
13754
13987
  * // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
13755
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
13988
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
13756
13989
  * ```
13757
13990
  */
13758
- this.dump = async (symbol, strategyName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
13991
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
13759
13992
  this.loggerService.log("riskMarkdownService dump", {
13760
13993
  symbol,
13761
13994
  strategyName,
13995
+ exchangeName,
13996
+ frameName,
13762
13997
  backtest,
13763
13998
  path,
13764
13999
  });
13765
- const storage = this.getStorage(symbol, strategyName, backtest);
14000
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13766
14001
  await storage.dump(symbol, strategyName, path, columns);
13767
14002
  };
13768
14003
  /**
13769
14004
  * Clears accumulated event data from storage.
13770
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
14005
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
13771
14006
  * If nothing is provided, clears all data.
13772
14007
  *
13773
- * @param backtest - Backtest mode flag
13774
- * @param ctx - Optional context with symbol and strategyName
14008
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
13775
14009
  *
13776
14010
  * @example
13777
14011
  * ```typescript
13778
14012
  * const service = new RiskMarkdownService();
13779
14013
  *
13780
- * // Clear specific symbol-strategy-backtest triple
13781
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
14014
+ * // Clear specific combination
14015
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
13782
14016
  *
13783
14017
  * // Clear all data
13784
14018
  * await service.clear();
13785
14019
  * ```
13786
14020
  */
13787
- this.clear = async (backtest, ctx) => {
14021
+ this.clear = async (payload) => {
13788
14022
  this.loggerService.log("riskMarkdownService clear", {
13789
- backtest,
13790
- ctx,
14023
+ payload,
13791
14024
  });
13792
- if (ctx) {
13793
- const key = CREATE_KEY_FN$2(ctx.symbol, ctx.strategyName, backtest);
14025
+ if (payload) {
14026
+ const key = CREATE_KEY_FN$2(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
13794
14027
  this.getStorage.clear(key);
13795
14028
  }
13796
14029
  else {
@@ -14300,10 +14533,9 @@ const CANCEL_METHOD_NAME = "strategy.cancel";
14300
14533
  * await stop("BTCUSDT", "my-strategy");
14301
14534
  * ```
14302
14535
  */
14303
- async function stop(symbol, strategyName) {
14536
+ async function stop(symbol) {
14304
14537
  backtest$1.loggerService.info(STOP_METHOD_NAME, {
14305
14538
  symbol,
14306
- strategyName,
14307
14539
  });
14308
14540
  if (!ExecutionContextService.hasContext()) {
14309
14541
  throw new Error("stop requires an execution context");
@@ -14312,7 +14544,12 @@ async function stop(symbol, strategyName) {
14312
14544
  throw new Error("stop requires a method context");
14313
14545
  }
14314
14546
  const { backtest: isBacktest } = backtest$1.executionContextService.context;
14315
- await backtest$1.strategyCoreService.stop(isBacktest, { symbol, strategyName });
14547
+ const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
14548
+ await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
14549
+ exchangeName,
14550
+ frameName,
14551
+ strategyName,
14552
+ });
14316
14553
  }
14317
14554
  /**
14318
14555
  * Cancels the scheduled signal without stopping the strategy.
@@ -14336,10 +14573,9 @@ async function stop(symbol, strategyName) {
14336
14573
  * await cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
14337
14574
  * ```
14338
14575
  */
14339
- async function cancel(symbol, strategyName, cancelId) {
14576
+ async function cancel(symbol, cancelId) {
14340
14577
  backtest$1.loggerService.info(CANCEL_METHOD_NAME, {
14341
14578
  symbol,
14342
- strategyName,
14343
14579
  cancelId,
14344
14580
  });
14345
14581
  if (!ExecutionContextService.hasContext()) {
@@ -14349,7 +14585,8 @@ async function cancel(symbol, strategyName, cancelId) {
14349
14585
  throw new Error("cancel requires a method context");
14350
14586
  }
14351
14587
  const { backtest: isBacktest } = backtest$1.executionContextService.context;
14352
- await backtest$1.strategyCoreService.cancel(isBacktest, { symbol, strategyName }, cancelId);
14588
+ const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
14589
+ await backtest$1.strategyCoreService.cancel(isBacktest, symbol, { exchangeName, frameName, strategyName }, cancelId);
14353
14590
  }
14354
14591
 
14355
14592
  /**
@@ -16496,42 +16733,73 @@ class BacktestInstance {
16496
16733
  context,
16497
16734
  });
16498
16735
  {
16499
- backtest$1.backtestMarkdownService.clear(true, {
16736
+ backtest$1.backtestMarkdownService.clear({
16500
16737
  symbol,
16501
16738
  strategyName: context.strategyName,
16739
+ exchangeName: context.exchangeName,
16740
+ frameName: context.frameName,
16741
+ backtest: true,
16502
16742
  });
16503
- backtest$1.liveMarkdownService.clear(true, {
16743
+ backtest$1.liveMarkdownService.clear({
16504
16744
  symbol,
16505
16745
  strategyName: context.strategyName,
16746
+ exchangeName: context.exchangeName,
16747
+ frameName: context.frameName,
16748
+ backtest: true,
16506
16749
  });
16507
- backtest$1.scheduleMarkdownService.clear(true, {
16750
+ backtest$1.scheduleMarkdownService.clear({
16508
16751
  symbol,
16509
16752
  strategyName: context.strategyName,
16753
+ exchangeName: context.exchangeName,
16754
+ frameName: context.frameName,
16755
+ backtest: true,
16510
16756
  });
16511
- backtest$1.performanceMarkdownService.clear(true, {
16757
+ backtest$1.performanceMarkdownService.clear({
16512
16758
  symbol,
16513
16759
  strategyName: context.strategyName,
16760
+ exchangeName: context.exchangeName,
16761
+ frameName: context.frameName,
16762
+ backtest: true,
16514
16763
  });
16515
- backtest$1.partialMarkdownService.clear(true, {
16764
+ backtest$1.partialMarkdownService.clear({
16516
16765
  symbol,
16517
16766
  strategyName: context.strategyName,
16767
+ exchangeName: context.exchangeName,
16768
+ frameName: context.frameName,
16769
+ backtest: true,
16518
16770
  });
16519
- backtest$1.riskMarkdownService.clear(true, {
16771
+ backtest$1.riskMarkdownService.clear({
16520
16772
  symbol,
16521
16773
  strategyName: context.strategyName,
16774
+ exchangeName: context.exchangeName,
16775
+ frameName: context.frameName,
16776
+ backtest: true,
16522
16777
  });
16523
16778
  }
16524
16779
  {
16525
- backtest$1.strategyCoreService.clear(true, {
16780
+ backtest$1.strategyCoreService.clear({
16526
16781
  symbol,
16527
16782
  strategyName: context.strategyName,
16783
+ exchangeName: context.exchangeName,
16784
+ frameName: context.frameName,
16785
+ backtest: true,
16528
16786
  });
16529
16787
  }
16530
16788
  {
16531
16789
  const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16532
- riskName && backtest$1.riskGlobalService.clear(true, { riskName });
16790
+ riskName && backtest$1.riskGlobalService.clear({
16791
+ riskName,
16792
+ exchangeName: context.exchangeName,
16793
+ frameName: context.frameName,
16794
+ backtest: true,
16795
+ });
16533
16796
  riskList &&
16534
- riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, { riskName }));
16797
+ riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
16798
+ riskName,
16799
+ exchangeName: context.exchangeName,
16800
+ frameName: context.frameName,
16801
+ backtest: true,
16802
+ }));
16535
16803
  }
16536
16804
  return backtest$1.backtestCommandService.run(symbol, context);
16537
16805
  };
@@ -16571,12 +16839,17 @@ class BacktestInstance {
16571
16839
  }
16572
16840
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
16573
16841
  return () => {
16574
- backtest$1.strategyCoreService.stop(true, {
16575
- symbol,
16842
+ backtest$1.strategyCoreService.stop(true, symbol, {
16576
16843
  strategyName: context.strategyName,
16844
+ exchangeName: context.exchangeName,
16845
+ frameName: context.frameName,
16577
16846
  });
16578
16847
  backtest$1.strategyCoreService
16579
- .getPendingSignal(true, symbol, context.strategyName)
16848
+ .getPendingSignal(true, symbol, {
16849
+ strategyName: context.strategyName,
16850
+ exchangeName: context.exchangeName,
16851
+ frameName: context.frameName,
16852
+ })
16580
16853
  .then(async (pendingSignal) => {
16581
16854
  if (pendingSignal) {
16582
16855
  return;
@@ -16696,16 +16969,16 @@ class BacktestUtils {
16696
16969
  * }
16697
16970
  * ```
16698
16971
  */
16699
- this.getPendingSignal = async (symbol, strategyName) => {
16700
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16972
+ this.getPendingSignal = async (symbol, context) => {
16973
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16701
16974
  {
16702
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
16975
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16703
16976
  riskName &&
16704
16977
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16705
16978
  riskList &&
16706
16979
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL));
16707
16980
  }
16708
- return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, strategyName);
16981
+ return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, context);
16709
16982
  };
16710
16983
  /**
16711
16984
  * Retrieves the currently active scheduled signal for the strategy.
@@ -16723,16 +16996,16 @@ class BacktestUtils {
16723
16996
  * }
16724
16997
  * ```
16725
16998
  */
16726
- this.getScheduledSignal = async (symbol, strategyName) => {
16727
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16999
+ this.getScheduledSignal = async (symbol, context) => {
17000
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16728
17001
  {
16729
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17002
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16730
17003
  riskName &&
16731
17004
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16732
17005
  riskList &&
16733
17006
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL));
16734
17007
  }
16735
- return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, strategyName);
17008
+ return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, context);
16736
17009
  };
16737
17010
  /**
16738
17011
  * Stops the strategy from generating new signals.
@@ -16743,24 +17016,29 @@ class BacktestUtils {
16743
17016
  *
16744
17017
  * @param symbol - Trading pair symbol
16745
17018
  * @param strategyName - Strategy name to stop
17019
+ * @param context - Execution context with exchangeName and frameName
16746
17020
  * @returns Promise that resolves when stop flag is set
16747
17021
  *
16748
17022
  * @example
16749
17023
  * ```typescript
16750
17024
  * // Stop strategy after some condition
16751
- * await Backtest.stop("BTCUSDT", "my-strategy");
17025
+ * await Backtest.stop("BTCUSDT", "my-strategy", {
17026
+ * exchangeName: "binance",
17027
+ * frameName: "frame1",
17028
+ * strategyName: "my-strategy"
17029
+ * });
16752
17030
  * ```
16753
17031
  */
16754
- this.stop = async (symbol, strategyName) => {
16755
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_STOP);
17032
+ this.stop = async (symbol, context) => {
17033
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_STOP);
16756
17034
  {
16757
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17035
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16758
17036
  riskName &&
16759
17037
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP);
16760
17038
  riskList &&
16761
17039
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP));
16762
17040
  }
16763
- await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
17041
+ await backtest$1.strategyCoreService.stop(true, symbol, context);
16764
17042
  };
16765
17043
  /**
16766
17044
  * Cancels the scheduled signal without stopping the strategy.
@@ -16771,102 +17049,126 @@ class BacktestUtils {
16771
17049
  *
16772
17050
  * @param symbol - Trading pair symbol
16773
17051
  * @param strategyName - Strategy name
17052
+ * @param context - Execution context with exchangeName and frameName
16774
17053
  * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
16775
17054
  * @returns Promise that resolves when scheduled signal is cancelled
16776
17055
  *
16777
17056
  * @example
16778
17057
  * ```typescript
16779
17058
  * // Cancel scheduled signal with custom ID
16780
- * await Backtest.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17059
+ * await Backtest.cancel("BTCUSDT", "my-strategy", {
17060
+ * exchangeName: "binance",
17061
+ * frameName: "frame1",
17062
+ * strategyName: "my-strategy"
17063
+ * }, "manual-cancel-001");
16781
17064
  * ```
16782
17065
  */
16783
- this.cancel = async (symbol, strategyName, cancelId) => {
16784
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_CANCEL);
17066
+ this.cancel = async (symbol, context, cancelId) => {
17067
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_CANCEL);
16785
17068
  {
16786
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17069
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16787
17070
  riskName &&
16788
17071
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL);
16789
17072
  riskList &&
16790
17073
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL));
16791
17074
  }
16792
- await backtest$1.strategyCoreService.cancel(true, { symbol, strategyName }, cancelId);
17075
+ await backtest$1.strategyCoreService.cancel(true, symbol, context, cancelId);
16793
17076
  };
16794
17077
  /**
16795
17078
  * Gets statistical data from all closed signals for a symbol-strategy pair.
16796
17079
  *
16797
17080
  * @param symbol - Trading pair symbol
16798
17081
  * @param strategyName - Strategy name to get data for
17082
+ * @param context - Execution context with exchangeName and frameName
16799
17083
  * @returns Promise resolving to statistical data object
16800
17084
  *
16801
17085
  * @example
16802
17086
  * ```typescript
16803
- * const stats = await Backtest.getData("BTCUSDT", "my-strategy");
17087
+ * const stats = await Backtest.getData("BTCUSDT", "my-strategy", {
17088
+ * exchangeName: "binance",
17089
+ * frameName: "frame1",
17090
+ * strategyName: "my-strategy"
17091
+ * });
16804
17092
  * console.log(stats.sharpeRatio, stats.winRate);
16805
17093
  * ```
16806
17094
  */
16807
- this.getData = async (symbol, strategyName) => {
16808
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_DATA);
17095
+ this.getData = async (symbol, context) => {
17096
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_DATA);
16809
17097
  {
16810
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17098
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16811
17099
  riskName &&
16812
17100
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA);
16813
17101
  riskList &&
16814
17102
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA));
16815
17103
  }
16816
- return await backtest$1.backtestMarkdownService.getData(symbol, strategyName, true);
17104
+ return await backtest$1.backtestMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, true);
16817
17105
  };
16818
17106
  /**
16819
17107
  * Generates markdown report with all closed signals for a symbol-strategy pair.
16820
17108
  *
16821
17109
  * @param symbol - Trading pair symbol
16822
17110
  * @param strategyName - Strategy name to generate report for
17111
+ * @param context - Execution context with exchangeName and frameName
16823
17112
  * @param columns - Optional columns configuration for the report
16824
17113
  * @returns Promise resolving to markdown formatted report string
16825
17114
  *
16826
17115
  * @example
16827
17116
  * ```typescript
16828
- * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy");
17117
+ * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy", {
17118
+ * exchangeName: "binance",
17119
+ * frameName: "frame1",
17120
+ * strategyName: "my-strategy"
17121
+ * });
16829
17122
  * console.log(markdown);
16830
17123
  * ```
16831
17124
  */
16832
- this.getReport = async (symbol, strategyName, columns) => {
16833
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
17125
+ this.getReport = async (symbol, context, columns) => {
17126
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
16834
17127
  {
16835
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17128
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16836
17129
  riskName &&
16837
17130
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT);
16838
17131
  riskList &&
16839
17132
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT));
16840
17133
  }
16841
- return await backtest$1.backtestMarkdownService.getReport(symbol, strategyName, true, columns);
17134
+ return await backtest$1.backtestMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, true, columns);
16842
17135
  };
16843
17136
  /**
16844
17137
  * Saves strategy report to disk.
16845
17138
  *
16846
17139
  * @param symbol - Trading pair symbol
16847
17140
  * @param strategyName - Strategy name to save report for
17141
+ * @param context - Execution context with exchangeName and frameName
16848
17142
  * @param path - Optional directory path to save report (default: "./dump/backtest")
16849
17143
  * @param columns - Optional columns configuration for the report
16850
17144
  *
16851
17145
  * @example
16852
17146
  * ```typescript
16853
17147
  * // Save to default path: ./dump/backtest/my-strategy.md
16854
- * await Backtest.dump("BTCUSDT", "my-strategy");
17148
+ * await Backtest.dump("BTCUSDT", "my-strategy", {
17149
+ * exchangeName: "binance",
17150
+ * frameName: "frame1",
17151
+ * strategyName: "my-strategy"
17152
+ * });
16855
17153
  *
16856
17154
  * // Save to custom path: ./custom/path/my-strategy.md
16857
- * await Backtest.dump("BTCUSDT", "my-strategy", "./custom/path");
17155
+ * await Backtest.dump("BTCUSDT", "my-strategy", {
17156
+ * exchangeName: "binance",
17157
+ * frameName: "frame1",
17158
+ * strategyName: "my-strategy"
17159
+ * }, "./custom/path");
16858
17160
  * ```
16859
17161
  */
16860
- this.dump = async (symbol, strategyName, path, columns) => {
16861
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_DUMP);
17162
+ this.dump = async (symbol, context, path, columns) => {
17163
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_DUMP);
16862
17164
  {
16863
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17165
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16864
17166
  riskName &&
16865
17167
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP);
16866
17168
  riskList &&
16867
17169
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP));
16868
17170
  }
16869
- await backtest$1.backtestMarkdownService.dump(symbol, strategyName, true, path, columns);
17171
+ await backtest$1.backtestMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, true, path, columns);
16870
17172
  };
16871
17173
  /**
16872
17174
  * Lists all active backtest instances with their current status.
@@ -17041,20 +17343,36 @@ class LiveInstance {
17041
17343
  context,
17042
17344
  });
17043
17345
  {
17044
- backtest$1.backtestMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17045
- backtest$1.liveMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17046
- backtest$1.scheduleMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17047
- backtest$1.performanceMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17048
- backtest$1.partialMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17049
- backtest$1.riskMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17346
+ backtest$1.backtestMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17347
+ backtest$1.liveMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17348
+ backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17349
+ backtest$1.performanceMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17350
+ backtest$1.partialMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17351
+ backtest$1.riskMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17050
17352
  }
17051
17353
  {
17052
- backtest$1.strategyCoreService.clear(false, { symbol, strategyName: context.strategyName });
17354
+ backtest$1.strategyCoreService.clear({
17355
+ symbol,
17356
+ strategyName: context.strategyName,
17357
+ exchangeName: context.exchangeName,
17358
+ frameName: "",
17359
+ backtest: false,
17360
+ });
17053
17361
  }
17054
17362
  {
17055
17363
  const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17056
- riskName && backtest$1.riskGlobalService.clear(false, { riskName });
17057
- riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(false, { riskName }));
17364
+ riskName && backtest$1.riskGlobalService.clear({
17365
+ riskName,
17366
+ exchangeName: context.exchangeName,
17367
+ frameName: "",
17368
+ backtest: false
17369
+ });
17370
+ riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
17371
+ riskName,
17372
+ exchangeName: context.exchangeName,
17373
+ frameName: "",
17374
+ backtest: false
17375
+ }));
17058
17376
  }
17059
17377
  return backtest$1.liveCommandService.run(symbol, context);
17060
17378
  };
@@ -17094,9 +17412,17 @@ class LiveInstance {
17094
17412
  }
17095
17413
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
17096
17414
  return () => {
17097
- backtest$1.strategyCoreService.stop(false, { symbol, strategyName: context.strategyName });
17415
+ backtest$1.strategyCoreService.stop(false, symbol, {
17416
+ strategyName: context.strategyName,
17417
+ exchangeName: context.exchangeName,
17418
+ frameName: ""
17419
+ });
17098
17420
  backtest$1.strategyCoreService
17099
- .getPendingSignal(false, symbol, context.strategyName)
17421
+ .getPendingSignal(false, symbol, {
17422
+ strategyName: context.strategyName,
17423
+ exchangeName: context.exchangeName,
17424
+ frameName: "",
17425
+ })
17100
17426
  .then(async (pendingSignal) => {
17101
17427
  if (pendingSignal) {
17102
17428
  return;
@@ -17223,14 +17549,18 @@ class LiveUtils {
17223
17549
  * }
17224
17550
  * ```
17225
17551
  */
17226
- this.getPendingSignal = async (symbol, strategyName) => {
17227
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17552
+ this.getPendingSignal = async (symbol, context) => {
17553
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17228
17554
  {
17229
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17555
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17230
17556
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17231
17557
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL));
17232
17558
  }
17233
- return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, strategyName);
17559
+ return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, {
17560
+ strategyName: context.strategyName,
17561
+ exchangeName: context.exchangeName,
17562
+ frameName: "",
17563
+ });
17234
17564
  };
17235
17565
  /**
17236
17566
  * Retrieves the currently active scheduled signal for the strategy.
@@ -17248,14 +17578,18 @@ class LiveUtils {
17248
17578
  * }
17249
17579
  * ```
17250
17580
  */
17251
- this.getScheduledSignal = async (symbol, strategyName) => {
17252
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17581
+ this.getScheduledSignal = async (symbol, context) => {
17582
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17253
17583
  {
17254
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17584
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17255
17585
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17256
17586
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL));
17257
17587
  }
17258
- return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, strategyName);
17588
+ return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, {
17589
+ strategyName: context.strategyName,
17590
+ exchangeName: context.exchangeName,
17591
+ frameName: "",
17592
+ });
17259
17593
  };
17260
17594
  /**
17261
17595
  * Stops the strategy from generating new signals.
@@ -17274,14 +17608,18 @@ class LiveUtils {
17274
17608
  * await Live.stop("BTCUSDT", "my-strategy");
17275
17609
  * ```
17276
17610
  */
17277
- this.stop = async (symbol, strategyName) => {
17278
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_STOP);
17611
+ this.stop = async (symbol, context) => {
17612
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_STOP);
17279
17613
  {
17280
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17614
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17281
17615
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP);
17282
17616
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP));
17283
17617
  }
17284
- await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
17618
+ await backtest$1.strategyCoreService.stop(false, symbol, {
17619
+ strategyName: context.strategyName,
17620
+ exchangeName: context.exchangeName,
17621
+ frameName: "",
17622
+ });
17285
17623
  };
17286
17624
  /**
17287
17625
  * Cancels the scheduled signal without stopping the strategy.
@@ -17292,94 +17630,122 @@ class LiveUtils {
17292
17630
  *
17293
17631
  * @param symbol - Trading pair symbol
17294
17632
  * @param strategyName - Strategy name
17633
+ * @param context - Execution context with exchangeName and frameName
17295
17634
  * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
17296
17635
  * @returns Promise that resolves when scheduled signal is cancelled
17297
17636
  *
17298
17637
  * @example
17299
17638
  * ```typescript
17300
17639
  * // Cancel scheduled signal in live trading with custom ID
17301
- * await Live.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17640
+ * await Live.cancel("BTCUSDT", "my-strategy", {
17641
+ * exchangeName: "binance",
17642
+ * frameName: "",
17643
+ * strategyName: "my-strategy"
17644
+ * }, "manual-cancel-001");
17302
17645
  * ```
17303
17646
  */
17304
- this.cancel = async (symbol, strategyName, cancelId) => {
17305
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_CANCEL);
17647
+ this.cancel = async (symbol, context, cancelId) => {
17648
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_CANCEL);
17306
17649
  {
17307
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17650
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17308
17651
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL);
17309
17652
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL));
17310
17653
  }
17311
- await backtest$1.strategyCoreService.cancel(false, { symbol, strategyName }, cancelId);
17654
+ await backtest$1.strategyCoreService.cancel(false, symbol, {
17655
+ strategyName: context.strategyName,
17656
+ exchangeName: context.exchangeName,
17657
+ frameName: "",
17658
+ }, cancelId);
17312
17659
  };
17313
17660
  /**
17314
17661
  * Gets statistical data from all live trading events for a symbol-strategy pair.
17315
17662
  *
17316
17663
  * @param symbol - Trading pair symbol
17317
17664
  * @param strategyName - Strategy name to get data for
17665
+ * @param context - Execution context with exchangeName and frameName
17318
17666
  * @returns Promise resolving to statistical data object
17319
17667
  *
17320
17668
  * @example
17321
17669
  * ```typescript
17322
- * const stats = await Live.getData("BTCUSDT", "my-strategy");
17670
+ * const stats = await Live.getData("BTCUSDT", "my-strategy", {
17671
+ * exchangeName: "binance",
17672
+ * frameName: "",
17673
+ * strategyName: "my-strategy"
17674
+ * });
17323
17675
  * console.log(stats.sharpeRatio, stats.winRate);
17324
17676
  * ```
17325
17677
  */
17326
- this.getData = async (symbol, strategyName) => {
17327
- backtest$1.strategyValidationService.validate(strategyName, "LiveUtils.getData");
17678
+ this.getData = async (symbol, context) => {
17679
+ backtest$1.strategyValidationService.validate(context.strategyName, "LiveUtils.getData");
17328
17680
  {
17329
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17681
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17330
17682
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA);
17331
17683
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA));
17332
17684
  }
17333
- return await backtest$1.liveMarkdownService.getData(symbol, strategyName, false);
17685
+ return await backtest$1.liveMarkdownService.getData(symbol, context.strategyName, context.exchangeName, "", false);
17334
17686
  };
17335
17687
  /**
17336
17688
  * Generates markdown report with all events for a symbol-strategy pair.
17337
17689
  *
17338
17690
  * @param symbol - Trading pair symbol
17339
17691
  * @param strategyName - Strategy name to generate report for
17692
+ * @param context - Execution context with exchangeName and frameName
17340
17693
  * @param columns - Optional columns configuration for the report
17341
17694
  * @returns Promise resolving to markdown formatted report string
17342
17695
  *
17343
17696
  * @example
17344
17697
  * ```typescript
17345
- * const markdown = await Live.getReport("BTCUSDT", "my-strategy");
17698
+ * const markdown = await Live.getReport("BTCUSDT", "my-strategy", {
17699
+ * exchangeName: "binance",
17700
+ * frameName: "",
17701
+ * strategyName: "my-strategy"
17702
+ * });
17346
17703
  * console.log(markdown);
17347
17704
  * ```
17348
17705
  */
17349
- this.getReport = async (symbol, strategyName, columns) => {
17350
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_REPORT);
17706
+ this.getReport = async (symbol, context, columns) => {
17707
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_REPORT);
17351
17708
  {
17352
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17709
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17353
17710
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT);
17354
17711
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT));
17355
17712
  }
17356
- return await backtest$1.liveMarkdownService.getReport(symbol, strategyName, false, columns);
17713
+ return await backtest$1.liveMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, "", false, columns);
17357
17714
  };
17358
17715
  /**
17359
17716
  * Saves strategy report to disk.
17360
17717
  *
17361
17718
  * @param symbol - Trading pair symbol
17362
17719
  * @param strategyName - Strategy name to save report for
17720
+ * @param context - Execution context with exchangeName and frameName
17363
17721
  * @param path - Optional directory path to save report (default: "./dump/live")
17364
17722
  * @param columns - Optional columns configuration for the report
17365
17723
  *
17366
17724
  * @example
17367
17725
  * ```typescript
17368
17726
  * // Save to default path: ./dump/live/my-strategy.md
17369
- * await Live.dump("BTCUSDT", "my-strategy");
17727
+ * await Live.dump("BTCUSDT", "my-strategy", {
17728
+ * exchangeName: "binance",
17729
+ * frameName: "",
17730
+ * strategyName: "my-strategy"
17731
+ * });
17370
17732
  *
17371
17733
  * // Save to custom path: ./custom/path/my-strategy.md
17372
- * await Live.dump("BTCUSDT", "my-strategy", "./custom/path");
17734
+ * await Live.dump("BTCUSDT", "my-strategy", {
17735
+ * exchangeName: "binance",
17736
+ * frameName: "",
17737
+ * strategyName: "my-strategy"
17738
+ * }, "./custom/path");
17373
17739
  * ```
17374
17740
  */
17375
- this.dump = async (symbol, strategyName, path, columns) => {
17376
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_DUMP);
17741
+ this.dump = async (symbol, context, path, columns) => {
17742
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_DUMP);
17377
17743
  {
17378
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17744
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17379
17745
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP);
17380
17746
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP));
17381
17747
  }
17382
- await backtest$1.liveMarkdownService.dump(symbol, strategyName, false, path, columns);
17748
+ await backtest$1.liveMarkdownService.dump(symbol, context.strategyName, context.exchangeName, "", false, path, columns);
17383
17749
  };
17384
17750
  /**
17385
17751
  * Lists all active live trading instances with their current status.
@@ -17460,19 +17826,19 @@ class ScheduleUtils {
17460
17826
  * console.log(stats.cancellationRate, stats.avgWaitTime);
17461
17827
  * ```
17462
17828
  */
17463
- this.getData = async (symbol, strategyName, backtest = false) => {
17829
+ this.getData = async (symbol, context, backtest = false) => {
17464
17830
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_DATA, {
17465
17831
  symbol,
17466
- strategyName,
17832
+ strategyName: context.strategyName,
17467
17833
  backtest,
17468
17834
  });
17469
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
17835
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
17470
17836
  {
17471
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17837
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17472
17838
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA);
17473
17839
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA));
17474
17840
  }
17475
- return await backtest$1.scheduleMarkdownService.getData(symbol, strategyName, backtest);
17841
+ return await backtest$1.scheduleMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
17476
17842
  };
17477
17843
  /**
17478
17844
  * Generates markdown report with all scheduled events for a symbol-strategy pair.
@@ -17488,19 +17854,19 @@ class ScheduleUtils {
17488
17854
  * console.log(markdown);
17489
17855
  * ```
17490
17856
  */
17491
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
17857
+ this.getReport = async (symbol, context, backtest = false, columns) => {
17492
17858
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_REPORT, {
17493
17859
  symbol,
17494
- strategyName,
17860
+ strategyName: context.strategyName,
17495
17861
  backtest,
17496
17862
  });
17497
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
17863
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
17498
17864
  {
17499
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17865
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17500
17866
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT);
17501
17867
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT));
17502
17868
  }
17503
- return await backtest$1.scheduleMarkdownService.getReport(symbol, strategyName, backtest, columns);
17869
+ return await backtest$1.scheduleMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
17504
17870
  };
17505
17871
  /**
17506
17872
  * Saves strategy report to disk.
@@ -17519,20 +17885,20 @@ class ScheduleUtils {
17519
17885
  * await Schedule.dump("BTCUSDT", "my-strategy", "./custom/path");
17520
17886
  * ```
17521
17887
  */
17522
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
17888
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
17523
17889
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_DUMP, {
17524
17890
  symbol,
17525
- strategyName,
17891
+ strategyName: context.strategyName,
17526
17892
  backtest,
17527
17893
  path,
17528
17894
  });
17529
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_DUMP);
17895
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_DUMP);
17530
17896
  {
17531
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17897
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17532
17898
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP);
17533
17899
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP));
17534
17900
  }
17535
- await backtest$1.scheduleMarkdownService.dump(symbol, strategyName, backtest, path, columns);
17901
+ await backtest$1.scheduleMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
17536
17902
  };
17537
17903
  }
17538
17904
  }
@@ -17613,14 +17979,14 @@ class Performance {
17613
17979
  * }
17614
17980
  * ```
17615
17981
  */
17616
- static async getData(symbol, strategyName, backtest = false) {
17617
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
17982
+ static async getData(symbol, context, backtest = false) {
17983
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
17618
17984
  {
17619
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17985
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17620
17986
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA);
17621
17987
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA));
17622
17988
  }
17623
- return backtest$1.performanceMarkdownService.getData(symbol, strategyName, backtest);
17989
+ return backtest$1.performanceMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
17624
17990
  }
17625
17991
  /**
17626
17992
  * Generates markdown report with performance analysis.
@@ -17645,14 +18011,14 @@ class Performance {
17645
18011
  * await fs.writeFile("performance-report.md", markdown);
17646
18012
  * ```
17647
18013
  */
17648
- static async getReport(symbol, strategyName, backtest = false, columns) {
17649
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
18014
+ static async getReport(symbol, context, backtest = false, columns) {
18015
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
17650
18016
  {
17651
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18017
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17652
18018
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT);
17653
18019
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT));
17654
18020
  }
17655
- return backtest$1.performanceMarkdownService.getReport(symbol, strategyName, backtest, columns);
18021
+ return backtest$1.performanceMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
17656
18022
  }
17657
18023
  /**
17658
18024
  * Saves performance report to disk.
@@ -17674,14 +18040,14 @@ class Performance {
17674
18040
  * await Performance.dump("BTCUSDT", "my-strategy", "./reports/perf");
17675
18041
  * ```
17676
18042
  */
17677
- static async dump(symbol, strategyName, backtest = false, path = "./dump/performance", columns) {
17678
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_DUMP);
18043
+ static async dump(symbol, context, backtest = false, path = "./dump/performance", columns) {
18044
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_DUMP);
17679
18045
  {
17680
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18046
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17681
18047
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP);
17682
18048
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP));
17683
18049
  }
17684
- return backtest$1.performanceMarkdownService.dump(symbol, strategyName, backtest, path, columns);
18050
+ return backtest$1.performanceMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
17685
18051
  }
17686
18052
  }
17687
18053
 
@@ -17819,21 +18185,37 @@ class WalkerInstance {
17819
18185
  // Clear backtest data for all strategies
17820
18186
  for (const strategyName of walkerSchema.strategies) {
17821
18187
  {
17822
- backtest$1.backtestMarkdownService.clear(true, { symbol, strategyName });
17823
- backtest$1.liveMarkdownService.clear(true, { symbol, strategyName });
17824
- backtest$1.scheduleMarkdownService.clear(true, { symbol, strategyName });
17825
- backtest$1.performanceMarkdownService.clear(true, { symbol, strategyName });
17826
- backtest$1.partialMarkdownService.clear(true, { symbol, strategyName });
17827
- backtest$1.riskMarkdownService.clear(true, { symbol, strategyName });
18188
+ backtest$1.backtestMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18189
+ backtest$1.liveMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18190
+ backtest$1.scheduleMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18191
+ backtest$1.performanceMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18192
+ backtest$1.partialMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18193
+ backtest$1.riskMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
17828
18194
  }
17829
18195
  {
17830
- backtest$1.strategyCoreService.clear(true, { symbol, strategyName });
18196
+ backtest$1.strategyCoreService.clear({
18197
+ symbol,
18198
+ strategyName,
18199
+ exchangeName: walkerSchema.exchangeName,
18200
+ frameName: walkerSchema.frameName,
18201
+ backtest: true,
18202
+ });
17831
18203
  }
17832
18204
  {
17833
18205
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17834
- riskName && backtest$1.riskGlobalService.clear(true, { riskName });
18206
+ riskName && backtest$1.riskGlobalService.clear({
18207
+ riskName,
18208
+ exchangeName: walkerSchema.exchangeName,
18209
+ frameName: walkerSchema.frameName,
18210
+ backtest: true
18211
+ });
17835
18212
  riskList &&
17836
- riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, { riskName }));
18213
+ riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
18214
+ riskName,
18215
+ exchangeName: walkerSchema.exchangeName,
18216
+ frameName: walkerSchema.frameName,
18217
+ backtest: true
18218
+ }));
17837
18219
  }
17838
18220
  }
17839
18221
  return backtest$1.walkerCommandService.run(symbol, {
@@ -17878,7 +18260,11 @@ class WalkerInstance {
17878
18260
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
17879
18261
  return () => {
17880
18262
  for (const strategyName of walkerSchema.strategies) {
17881
- backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
18263
+ backtest$1.strategyCoreService.stop(true, symbol, {
18264
+ strategyName,
18265
+ exchangeName: walkerSchema.exchangeName,
18266
+ frameName: walkerSchema.frameName
18267
+ });
17882
18268
  walkerStopSubject.next({
17883
18269
  symbol,
17884
18270
  strategyName,
@@ -18019,7 +18405,11 @@ class WalkerUtils {
18019
18405
  }
18020
18406
  for (const strategyName of walkerSchema.strategies) {
18021
18407
  await walkerStopSubject.next({ symbol, strategyName, walkerName });
18022
- await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
18408
+ await backtest$1.strategyCoreService.stop(true, symbol, {
18409
+ strategyName,
18410
+ exchangeName: walkerSchema.exchangeName,
18411
+ frameName: walkerSchema.frameName
18412
+ });
18023
18413
  }
18024
18414
  };
18025
18415
  /**
@@ -18187,11 +18577,16 @@ class HeatUtils {
18187
18577
  * Data is automatically collected from all closed signals for the strategy.
18188
18578
  *
18189
18579
  * @param strategyName - Strategy name to get heatmap data for
18580
+ * @param context - Execution context with exchangeName and frameName
18581
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18190
18582
  * @returns Promise resolving to heatmap statistics object
18191
18583
  *
18192
18584
  * @example
18193
18585
  * ```typescript
18194
- * const stats = await Heat.getData("my-strategy");
18586
+ * const stats = await Heat.getData("my-strategy", {
18587
+ * exchangeName: "binance",
18588
+ * frameName: "frame1"
18589
+ * });
18195
18590
  *
18196
18591
  * console.log(`Total symbols: ${stats.totalSymbols}`);
18197
18592
  * console.log(`Portfolio Total PNL: ${stats.portfolioTotalPnl}%`);
@@ -18203,7 +18598,7 @@ class HeatUtils {
18203
18598
  * });
18204
18599
  * ```
18205
18600
  */
18206
- this.getData = async (strategyName, backtest = false) => {
18601
+ this.getData = async (strategyName, context, backtest = false) => {
18207
18602
  backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
18208
18603
  backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_DATA);
18209
18604
  {
@@ -18211,7 +18606,7 @@ class HeatUtils {
18211
18606
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
18212
18607
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
18213
18608
  }
18214
- return await backtest$1.heatMarkdownService.getData(strategyName, backtest);
18609
+ return await backtest$1.heatMarkdownService.getData(context.exchangeName, context.frameName, backtest);
18215
18610
  };
18216
18611
  /**
18217
18612
  * Generates markdown report with portfolio heatmap table for a strategy.
@@ -18220,12 +18615,17 @@ class HeatUtils {
18220
18615
  * Symbols are sorted by Total PNL descending.
18221
18616
  *
18222
18617
  * @param strategyName - Strategy name to generate heatmap report for
18618
+ * @param context - Execution context with exchangeName and frameName
18619
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18223
18620
  * @param columns - Optional columns configuration for the report
18224
18621
  * @returns Promise resolving to markdown formatted report string
18225
18622
  *
18226
18623
  * @example
18227
18624
  * ```typescript
18228
- * const markdown = await Heat.getReport("my-strategy");
18625
+ * const markdown = await Heat.getReport("my-strategy", {
18626
+ * exchangeName: "binance",
18627
+ * frameName: "frame1"
18628
+ * });
18229
18629
  * console.log(markdown);
18230
18630
  * // Output:
18231
18631
  * // # Portfolio Heatmap: my-strategy
@@ -18239,7 +18639,7 @@ class HeatUtils {
18239
18639
  * // ...
18240
18640
  * ```
18241
18641
  */
18242
- this.getReport = async (strategyName, backtest = false, columns) => {
18642
+ this.getReport = async (strategyName, context, backtest = false, columns) => {
18243
18643
  backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
18244
18644
  backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_REPORT);
18245
18645
  {
@@ -18247,7 +18647,7 @@ class HeatUtils {
18247
18647
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
18248
18648
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
18249
18649
  }
18250
- return await backtest$1.heatMarkdownService.getReport(strategyName, backtest, columns);
18650
+ return await backtest$1.heatMarkdownService.getReport(strategyName, context.exchangeName, context.frameName, backtest, columns);
18251
18651
  };
18252
18652
  /**
18253
18653
  * Saves heatmap report to disk for a strategy.
@@ -18256,19 +18656,27 @@ class HeatUtils {
18256
18656
  * Default filename: {strategyName}.md
18257
18657
  *
18258
18658
  * @param strategyName - Strategy name to save heatmap report for
18659
+ * @param context - Execution context with exchangeName and frameName
18660
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18259
18661
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
18260
18662
  * @param columns - Optional columns configuration for the report
18261
18663
  *
18262
18664
  * @example
18263
18665
  * ```typescript
18264
18666
  * // Save to default path: ./dump/heatmap/my-strategy.md
18265
- * await Heat.dump("my-strategy");
18667
+ * await Heat.dump("my-strategy", {
18668
+ * exchangeName: "binance",
18669
+ * frameName: "frame1"
18670
+ * });
18266
18671
  *
18267
18672
  * // Save to custom path: ./reports/my-strategy.md
18268
- * await Heat.dump("my-strategy", "./reports");
18673
+ * await Heat.dump("my-strategy", {
18674
+ * exchangeName: "binance",
18675
+ * frameName: "frame1"
18676
+ * }, false, "./reports");
18269
18677
  * ```
18270
18678
  */
18271
- this.dump = async (strategyName, backtest = false, path, columns) => {
18679
+ this.dump = async (strategyName, context, backtest = false, path, columns) => {
18272
18680
  backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
18273
18681
  backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_DUMP);
18274
18682
  {
@@ -18276,7 +18684,7 @@ class HeatUtils {
18276
18684
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
18277
18685
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
18278
18686
  }
18279
- await backtest$1.heatMarkdownService.dump(strategyName, backtest, path, columns);
18687
+ await backtest$1.heatMarkdownService.dump(strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18280
18688
  };
18281
18689
  }
18282
18690
  }
@@ -18592,15 +19000,15 @@ class PartialUtils {
18592
19000
  * }
18593
19001
  * ```
18594
19002
  */
18595
- this.getData = async (symbol, strategyName, backtest = false) => {
18596
- backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_DATA, { symbol, strategyName });
18597
- backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_GET_DATA);
19003
+ this.getData = async (symbol, context, backtest = false) => {
19004
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_DATA, { symbol, strategyName: context.strategyName });
19005
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_DATA);
18598
19006
  {
18599
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19007
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18600
19008
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA);
18601
19009
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA));
18602
19010
  }
18603
- return await backtest$1.partialMarkdownService.getData(symbol, strategyName, backtest);
19011
+ return await backtest$1.partialMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
18604
19012
  };
18605
19013
  /**
18606
19014
  * Generates markdown report with all partial profit/loss events for a symbol-strategy pair.
@@ -18641,15 +19049,15 @@ class PartialUtils {
18641
19049
  * // **Loss events:** 1
18642
19050
  * ```
18643
19051
  */
18644
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
18645
- backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_REPORT, { symbol, strategyName });
18646
- backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_GET_REPORT);
19052
+ this.getReport = async (symbol, context, backtest = false, columns) => {
19053
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_REPORT, { symbol, strategyName: context.strategyName });
19054
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_REPORT);
18647
19055
  {
18648
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19056
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18649
19057
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT);
18650
19058
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT));
18651
19059
  }
18652
- return await backtest$1.partialMarkdownService.getReport(symbol, strategyName, backtest, columns);
19060
+ return await backtest$1.partialMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
18653
19061
  };
18654
19062
  /**
18655
19063
  * Generates and saves markdown report to file.
@@ -18683,15 +19091,15 @@ class PartialUtils {
18683
19091
  * }
18684
19092
  * ```
18685
19093
  */
18686
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
18687
- backtest$1.loggerService.info(PARTIAL_METHOD_NAME_DUMP, { symbol, strategyName, path });
18688
- backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_DUMP);
19094
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
19095
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_DUMP, { symbol, strategyName: context.strategyName, path });
19096
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_DUMP);
18689
19097
  {
18690
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19098
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18691
19099
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP);
18692
19100
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP));
18693
19101
  }
18694
- await backtest$1.partialMarkdownService.dump(symbol, strategyName, backtest, path, columns);
19102
+ await backtest$1.partialMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18695
19103
  };
18696
19104
  }
18697
19105
  }
@@ -19104,7 +19512,13 @@ const INTERVAL_MINUTES = {
19104
19512
  * @param backtest - Whether running in backtest mode
19105
19513
  * @returns Cache key string
19106
19514
  */
19107
- const CREATE_KEY_FN$1 = (strategyName, exchangeName, backtest) => `${strategyName}:${exchangeName}:${backtest ? "backtest" : "live"}`;
19515
+ const CREATE_KEY_FN$1 = (strategyName, exchangeName, frameName, backtest) => {
19516
+ const parts = [strategyName, exchangeName];
19517
+ if (frameName)
19518
+ parts.push(frameName);
19519
+ parts.push(backtest ? "backtest" : "live");
19520
+ return parts.join(":");
19521
+ };
19108
19522
  /**
19109
19523
  * Instance class for caching function results with timeframe-based invalidation.
19110
19524
  *
@@ -19180,7 +19594,7 @@ class CacheInstance {
19180
19594
  throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
19181
19595
  }
19182
19596
  }
19183
- const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
19597
+ const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.methodContextService.context.frameName, backtest$1.executionContextService.context.backtest);
19184
19598
  const currentWhen = backtest$1.executionContextService.context.when;
19185
19599
  const cached = this._cacheMap.get(key);
19186
19600
  if (cached) {
@@ -19218,7 +19632,7 @@ class CacheInstance {
19218
19632
  * ```
19219
19633
  */
19220
19634
  this.clear = () => {
19221
- const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
19635
+ const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.methodContextService.context.frameName, backtest$1.executionContextService.context.backtest);
19222
19636
  this._cacheMap.delete(key);
19223
19637
  };
19224
19638
  }