backtest-kit 1.6.9 → 1.7.2

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 +1051 -602
  2. package/build/index.mjs +1051 -602
  3. package/package.json +1 -1
  4. package/types.d.ts +1034 -661
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, backtest) {
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
@@ -3391,7 +3417,7 @@ class ClientStrategy {
3391
3417
  if (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,10 @@ 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, backtest, cancelId) {
3418
3444
  this.params.logger.debug("ClientStrategy cancel", {
3419
3445
  symbol,
3420
- strategyName,
3421
3446
  hasScheduledSignal: this._scheduledSignal !== null,
3422
- backtest,
3423
3447
  cancelId,
3424
3448
  });
3425
3449
  // Save cancelled signal for next tick to emit cancelled event
@@ -3432,7 +3456,7 @@ class ClientStrategy {
3432
3456
  if (backtest) {
3433
3457
  return;
3434
3458
  }
3435
- await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
3459
+ await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
3436
3460
  }
3437
3461
  }
3438
3462
 
@@ -3508,7 +3532,7 @@ class MergeRisk {
3508
3532
  * Used to track active positions across all risk management systems.
3509
3533
  *
3510
3534
  * @param symbol - Trading pair symbol
3511
- * @param context - Context with strategyName and riskName
3535
+ * @param context - Context with strategyName, riskName, exchangeName and frameName
3512
3536
  * @returns Promise that resolves when all risks have registered the signal
3513
3537
  */
3514
3538
  async addSignal(symbol, context) {
@@ -3525,7 +3549,7 @@ class MergeRisk {
3525
3549
  * Used to update risk state when a position closes.
3526
3550
  *
3527
3551
  * @param symbol - Trading pair symbol
3528
- * @param context - Context with strategyName and riskName
3552
+ * @param context - Context with strategyName, riskName, exchangeName and frameName
3529
3553
  * @returns Promise that resolves when all risks have removed the signal
3530
3554
  */
3531
3555
  async removeSignal(symbol, context) {
@@ -3597,20 +3621,20 @@ class RiskUtils {
3597
3621
  * }
3598
3622
  * ```
3599
3623
  */
3600
- this.getData = async (symbol, strategyName, backtest = false) => {
3624
+ this.getData = async (symbol, context, backtest = false) => {
3601
3625
  backtest$1.loggerService.info(RISK_METHOD_NAME_GET_DATA, {
3602
3626
  symbol,
3603
- strategyName,
3627
+ strategyName: context.strategyName,
3604
3628
  });
3605
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_DATA);
3629
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_DATA);
3606
3630
  {
3607
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3631
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3608
3632
  riskName &&
3609
3633
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA);
3610
3634
  riskList &&
3611
3635
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
3612
3636
  }
3613
- return await backtest$1.riskMarkdownService.getData(symbol, strategyName, backtest);
3637
+ return await backtest$1.riskMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3614
3638
  };
3615
3639
  /**
3616
3640
  * Generates markdown report with all risk rejection events for a symbol-strategy pair.
@@ -3653,20 +3677,20 @@ class RiskUtils {
3653
3677
  * // - my-strategy: 1
3654
3678
  * ```
3655
3679
  */
3656
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
3680
+ this.getReport = async (symbol, context, backtest = false, columns) => {
3657
3681
  backtest$1.loggerService.info(RISK_METHOD_NAME_GET_REPORT, {
3658
3682
  symbol,
3659
- strategyName,
3683
+ strategyName: context.strategyName,
3660
3684
  });
3661
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_REPORT);
3685
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_REPORT);
3662
3686
  {
3663
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3687
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3664
3688
  riskName &&
3665
3689
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT);
3666
3690
  riskList &&
3667
3691
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
3668
3692
  }
3669
- return await backtest$1.riskMarkdownService.getReport(symbol, strategyName, backtest, columns);
3693
+ return await backtest$1.riskMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
3670
3694
  };
3671
3695
  /**
3672
3696
  * Generates and saves markdown report to file.
@@ -3700,21 +3724,21 @@ class RiskUtils {
3700
3724
  * }
3701
3725
  * ```
3702
3726
  */
3703
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
3727
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
3704
3728
  backtest$1.loggerService.info(RISK_METHOD_NAME_DUMP, {
3705
3729
  symbol,
3706
- strategyName,
3730
+ strategyName: context.strategyName,
3707
3731
  path,
3708
3732
  });
3709
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_DUMP);
3733
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_DUMP);
3710
3734
  {
3711
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3735
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3712
3736
  riskName &&
3713
3737
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP);
3714
3738
  riskList &&
3715
3739
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
3716
3740
  }
3717
- await backtest$1.riskMarkdownService.dump(symbol, strategyName, backtest, path, columns);
3741
+ await backtest$1.riskMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
3718
3742
  };
3719
3743
  }
3720
3744
  }
@@ -3747,10 +3771,12 @@ const NOOP_RISK = {
3747
3771
  * Determines the appropriate IRisk instance based on provided riskName and riskList.
3748
3772
  * @param dto - Object containing riskName and riskList
3749
3773
  * @param backtest - Whether running in backtest mode
3774
+ * @param exchangeName - Exchange name for risk isolation
3775
+ * @param frameName - Frame name for risk isolation
3750
3776
  * @param self - Reference to StrategyConnectionService instance
3751
3777
  * @returns Configured IRisk instance (single or merged)
3752
3778
  */
3753
- const GET_RISK_FN = (dto, backtest, self) => {
3779
+ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
3754
3780
  const hasRiskName = !!dto.riskName;
3755
3781
  const hasRiskList = !!dto.riskList?.length;
3756
3782
  // Нет ни riskName, ни riskList
@@ -3759,27 +3785,35 @@ const GET_RISK_FN = (dto, backtest, self) => {
3759
3785
  }
3760
3786
  // Есть только riskName (без riskList)
3761
3787
  if (hasRiskName && !hasRiskList) {
3762
- return self.riskConnectionService.getRisk(dto.riskName, backtest);
3788
+ return self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest);
3763
3789
  }
3764
3790
  // Есть только riskList (без riskName)
3765
3791
  if (!hasRiskName && hasRiskList) {
3766
- return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)));
3792
+ return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)));
3767
3793
  }
3768
3794
  // Есть и riskName, и riskList - объединяем (riskName в начало)
3769
3795
  return new MergeRisk([
3770
- self.riskConnectionService.getRisk(dto.riskName, backtest),
3771
- ...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
3796
+ self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest),
3797
+ ...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)),
3772
3798
  ]);
3773
3799
  };
3774
3800
  /**
3775
3801
  * Creates a unique key for memoizing ClientStrategy instances.
3776
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
3802
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
3777
3803
  * @param symbol - Trading pair symbol
3778
3804
  * @param strategyName - Name of the strategy
3805
+ * @param exchangeName - Exchange name
3806
+ * @param frameName - Frame name (empty string for live)
3779
3807
  * @param backtest - Whether running in backtest mode
3780
3808
  * @returns Unique string key for memoization
3781
3809
  */
3782
- const CREATE_KEY_FN$b = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
3810
+ const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
3811
+ const parts = [symbol, strategyName, exchangeName];
3812
+ if (frameName)
3813
+ parts.push(frameName);
3814
+ parts.push(backtest ? "backtest" : "live");
3815
+ return parts.join(":");
3816
+ };
3783
3817
  /**
3784
3818
  * Callback function for emitting ping events to pingSubject.
3785
3819
  *
@@ -3828,32 +3862,34 @@ class StrategyConnectionService {
3828
3862
  this.strategySchemaService = inject(TYPES.strategySchemaService);
3829
3863
  this.riskConnectionService = inject(TYPES.riskConnectionService);
3830
3864
  this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
3831
- this.methodContextService = inject(TYPES.methodContextService);
3832
3865
  this.partialConnectionService = inject(TYPES.partialConnectionService);
3833
3866
  /**
3834
- * Retrieves memoized ClientStrategy instance for given symbol-strategy pair.
3867
+ * Retrieves memoized ClientStrategy instance for given symbol-strategy pair with exchange and frame isolation.
3835
3868
  *
3836
3869
  * Creates ClientStrategy on first call, returns cached instance on subsequent calls.
3837
- * Cache key is symbol:strategyName string.
3870
+ * Cache key includes exchangeName and frameName for proper isolation.
3838
3871
  *
3839
3872
  * @param symbol - Trading pair symbol
3840
3873
  * @param strategyName - Name of registered strategy schema
3874
+ * @param exchangeName - Exchange name
3875
+ * @param frameName - Frame name (empty string for live)
3876
+ * @param backtest - Whether running in backtest mode
3841
3877
  * @returns Configured ClientStrategy instance
3842
3878
  */
3843
- this.getStrategy = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, backtest), (symbol, strategyName, backtest) => {
3879
+ this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
3844
3880
  const { riskName = "", riskList = [], getSignal, interval, callbacks, } = this.strategySchemaService.get(strategyName);
3845
3881
  return new ClientStrategy({
3846
3882
  symbol,
3847
3883
  interval,
3848
3884
  execution: this.executionContextService,
3849
- method: this.methodContextService,
3885
+ method: { context: { strategyName, exchangeName, frameName } },
3850
3886
  logger: this.loggerService,
3851
3887
  partial: this.partialConnectionService,
3852
3888
  exchange: this.exchangeConnectionService,
3853
3889
  risk: GET_RISK_FN({
3854
3890
  riskName,
3855
3891
  riskList,
3856
- }, backtest, this),
3892
+ }, backtest, exchangeName, frameName, this),
3857
3893
  riskName,
3858
3894
  strategyName,
3859
3895
  getSignal,
@@ -3866,38 +3902,40 @@ class StrategyConnectionService {
3866
3902
  * If no active signal exists, returns null.
3867
3903
  * Used internally for monitoring TP/SL and time expiration.
3868
3904
  *
3905
+ * @param backtest - Whether running in backtest mode
3869
3906
  * @param symbol - Trading pair symbol
3870
- * @param strategyName - Name of strategy to get pending signal for
3907
+ * @param context - Execution context with strategyName, exchangeName, frameName
3871
3908
  *
3872
3909
  * @returns Promise resolving to pending signal or null
3873
3910
  */
3874
- this.getPendingSignal = async (backtest, symbol, strategyName) => {
3911
+ this.getPendingSignal = async (backtest, symbol, context) => {
3875
3912
  this.loggerService.log("strategyConnectionService getPendingSignal", {
3876
3913
  symbol,
3877
- strategyName,
3914
+ context,
3878
3915
  backtest,
3879
3916
  });
3880
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3881
- return await strategy.getPendingSignal(symbol, strategyName);
3917
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3918
+ return await strategy.getPendingSignal(symbol);
3882
3919
  };
3883
3920
  /**
3884
3921
  * Retrieves the currently active scheduled signal for the strategy.
3885
3922
  * If no scheduled signal exists, returns null.
3886
3923
  * Used internally for monitoring scheduled signal activation.
3887
3924
  *
3925
+ * @param backtest - Whether running in backtest mode
3888
3926
  * @param symbol - Trading pair symbol
3889
- * @param strategyName - Name of strategy to get scheduled signal for
3927
+ * @param context - Execution context with strategyName, exchangeName, frameName
3890
3928
  *
3891
3929
  * @returns Promise resolving to scheduled signal or null
3892
3930
  */
3893
- this.getScheduledSignal = async (backtest, symbol, strategyName) => {
3931
+ this.getScheduledSignal = async (backtest, symbol, context) => {
3894
3932
  this.loggerService.log("strategyConnectionService getScheduledSignal", {
3895
3933
  symbol,
3896
- strategyName,
3934
+ context,
3897
3935
  backtest,
3898
3936
  });
3899
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3900
- return await strategy.getScheduledSignal(symbol, strategyName);
3937
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3938
+ return await strategy.getScheduledSignal(symbol);
3901
3939
  };
3902
3940
  /**
3903
3941
  * Retrieves the stopped state of the strategy.
@@ -3905,18 +3943,19 @@ class StrategyConnectionService {
3905
3943
  * Delegates to the underlying strategy instance to check if it has been
3906
3944
  * marked as stopped and should cease operation.
3907
3945
  *
3946
+ * @param backtest - Whether running in backtest mode
3908
3947
  * @param symbol - Trading pair symbol
3909
- * @param strategyName - Name of the strategy
3948
+ * @param context - Execution context with strategyName, exchangeName, frameName
3910
3949
  * @returns Promise resolving to true if strategy is stopped, false otherwise
3911
3950
  */
3912
- this.getStopped = async (backtest, symbol, strategyName) => {
3951
+ this.getStopped = async (backtest, symbol, context) => {
3913
3952
  this.loggerService.log("strategyConnectionService getStopped", {
3914
3953
  symbol,
3915
- strategyName,
3954
+ context,
3916
3955
  backtest,
3917
3956
  });
3918
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3919
- return await strategy.getStopped(symbol, strategyName);
3957
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3958
+ return await strategy.getStopped(symbol);
3920
3959
  };
3921
3960
  /**
3922
3961
  * Executes live trading tick for current strategy.
@@ -3925,18 +3964,19 @@ class StrategyConnectionService {
3925
3964
  * Evaluates current market conditions and returns signal state.
3926
3965
  *
3927
3966
  * @param symbol - Trading pair symbol
3928
- * @param strategyName - Name of strategy to tick
3967
+ * @param context - Execution context with strategyName, exchangeName, frameName
3929
3968
  * @returns Promise resolving to tick result (idle, opened, active, closed)
3930
3969
  */
3931
- this.tick = async (symbol, strategyName) => {
3970
+ this.tick = async (symbol, context) => {
3971
+ const backtest = this.executionContextService.context.backtest;
3932
3972
  this.loggerService.log("strategyConnectionService tick", {
3933
3973
  symbol,
3934
- strategyName,
3974
+ context,
3975
+ backtest,
3935
3976
  });
3936
- const backtest = this.executionContextService.context.backtest;
3937
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3977
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3938
3978
  await strategy.waitForInit();
3939
- const tick = await strategy.tick(symbol, strategyName);
3979
+ const tick = await strategy.tick(symbol, context.strategyName);
3940
3980
  {
3941
3981
  if (this.executionContextService.context.backtest) {
3942
3982
  await signalBacktestEmitter.next(tick);
@@ -3955,24 +3995,28 @@ class StrategyConnectionService {
3955
3995
  * Evaluates strategy signals against historical data.
3956
3996
  *
3957
3997
  * @param symbol - Trading pair symbol
3958
- * @param strategyName - Name of strategy to backtest
3998
+ * @param context - Execution context with strategyName, exchangeName, frameName
3959
3999
  * @param candles - Array of historical candle data to backtest
3960
4000
  * @returns Promise resolving to backtest result (signal or idle)
3961
4001
  */
3962
- this.backtest = async (symbol, strategyName, candles) => {
4002
+ this.backtest = async (symbol, context, candles) => {
4003
+ const backtest = this.executionContextService.context.backtest;
3963
4004
  this.loggerService.log("strategyConnectionService backtest", {
3964
4005
  symbol,
3965
- strategyName,
4006
+ context,
3966
4007
  candleCount: candles.length,
4008
+ backtest,
3967
4009
  });
3968
- const backtest = this.executionContextService.context.backtest;
3969
- const strategy = this.getStrategy(symbol, strategyName, backtest);
4010
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3970
4011
  await strategy.waitForInit();
3971
- const tick = await strategy.backtest(symbol, strategyName, candles);
4012
+ const tick = await strategy.backtest(symbol, context.strategyName, candles);
3972
4013
  {
3973
4014
  if (this.executionContextService.context.backtest) {
3974
4015
  await signalBacktestEmitter.next(tick);
3975
4016
  }
4017
+ if (!this.executionContextService.context.backtest) {
4018
+ await signalLiveEmitter.next(tick);
4019
+ }
3976
4020
  await signalEmitter.next(tick);
3977
4021
  }
3978
4022
  return tick;
@@ -3983,16 +4027,18 @@ class StrategyConnectionService {
3983
4027
  * Delegates to ClientStrategy.stop() which sets internal flag to prevent
3984
4028
  * getSignal from being called on subsequent ticks.
3985
4029
  *
4030
+ * @param backtest - Whether running in backtest mode
3986
4031
  * @param symbol - Trading pair symbol
3987
- * @param strategyName - Name of strategy to stop
4032
+ * @param ctx - Context with strategyName, exchangeName, frameName
3988
4033
  * @returns Promise that resolves when stop flag is set
3989
4034
  */
3990
- this.stop = async (backtest, ctx) => {
4035
+ this.stop = async (backtest, symbol, context) => {
3991
4036
  this.loggerService.log("strategyConnectionService stop", {
3992
- ctx,
4037
+ symbol,
4038
+ context,
3993
4039
  });
3994
- const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
3995
- await strategy.stop(ctx.symbol, ctx.strategyName, backtest);
4040
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4041
+ await strategy.stop(symbol, backtest);
3996
4042
  };
3997
4043
  /**
3998
4044
  * Clears the memoized ClientStrategy instance from cache.
@@ -4000,14 +4046,14 @@ class StrategyConnectionService {
4000
4046
  * Forces re-initialization of strategy on next getStrategy call.
4001
4047
  * Useful for resetting strategy state or releasing resources.
4002
4048
  *
4003
- * @param ctx - Optional context with symbol and strategyName (clears all if not provided)
4049
+ * @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
4004
4050
  */
4005
- this.clear = async (backtest, ctx) => {
4051
+ this.clear = async (payload) => {
4006
4052
  this.loggerService.log("strategyConnectionService clear", {
4007
- ctx,
4053
+ payload,
4008
4054
  });
4009
- if (ctx) {
4010
- const key = CREATE_KEY_FN$b(ctx.symbol, ctx.strategyName, backtest);
4055
+ if (payload) {
4056
+ const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
4011
4057
  this.getStrategy.clear(key);
4012
4058
  }
4013
4059
  else {
@@ -4024,17 +4070,19 @@ class StrategyConnectionService {
4024
4070
  * detects the scheduled signal was cancelled.
4025
4071
  *
4026
4072
  * @param backtest - Whether running in backtest mode
4027
- * @param ctx - Context with symbol and strategyName
4073
+ * @param symbol - Trading pair symbol
4074
+ * @param ctx - Context with strategyName, exchangeName, frameName
4028
4075
  * @param cancelId - Optional cancellation ID for user-initiated cancellations
4029
4076
  * @returns Promise that resolves when scheduled signal is cancelled
4030
4077
  */
4031
- this.cancel = async (backtest, ctx, cancelId) => {
4078
+ this.cancel = async (backtest, symbol, context, cancelId) => {
4032
4079
  this.loggerService.log("strategyConnectionService cancel", {
4033
- ctx,
4080
+ symbol,
4081
+ context,
4034
4082
  cancelId,
4035
4083
  });
4036
- const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
4037
- await strategy.cancel(ctx.symbol, ctx.strategyName, backtest, cancelId);
4084
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4085
+ await strategy.cancel(symbol, backtest, cancelId);
4038
4086
  };
4039
4087
  }
4040
4088
  }
@@ -4420,7 +4468,7 @@ const get = (object, path) => {
4420
4468
  /** Symbol indicating that positions need to be fetched from persistence */
4421
4469
  const POSITION_NEED_FETCH = Symbol("risk-need-fetch");
4422
4470
  /** Key generator for active position map */
4423
- const GET_KEY_FN = (strategyName, symbol) => `${strategyName}:${symbol}`;
4471
+ const CREATE_NAME_FN = (strategyName, exchangeName, symbol) => `${strategyName}_${exchangeName}_${symbol}`;
4424
4472
  /** Wrapper to execute risk validation function with error handling */
4425
4473
  const DO_VALIDATION_FN = async (validation, params) => {
4426
4474
  try {
@@ -4580,12 +4628,11 @@ class ClientRisk {
4580
4628
  if (this._activePositions === POSITION_NEED_FETCH) {
4581
4629
  await this.waitForInit();
4582
4630
  }
4583
- const key = GET_KEY_FN(context.strategyName, symbol);
4631
+ const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
4584
4632
  const riskMap = this._activePositions;
4585
4633
  riskMap.set(key, {
4586
- signal: null, // Signal details not needed for position tracking
4587
4634
  strategyName: context.strategyName,
4588
- exchangeName: "",
4635
+ exchangeName: context.exchangeName,
4589
4636
  openTimestamp: Date.now(),
4590
4637
  });
4591
4638
  await this._updatePositions();
@@ -4603,7 +4650,7 @@ class ClientRisk {
4603
4650
  if (this._activePositions === POSITION_NEED_FETCH) {
4604
4651
  await this.waitForInit();
4605
4652
  }
4606
- const key = GET_KEY_FN(context.strategyName, symbol);
4653
+ const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
4607
4654
  const riskMap = this._activePositions;
4608
4655
  riskMap.delete(key);
4609
4656
  await this._updatePositions();
@@ -4612,12 +4659,20 @@ class ClientRisk {
4612
4659
 
4613
4660
  /**
4614
4661
  * Creates a unique key for memoizing ClientRisk instances.
4615
- * Key format: "riskName:backtest" or "riskName:live"
4662
+ * Key format: "riskName:exchangeName:frameName:backtest" or "riskName:exchangeName:live"
4616
4663
  * @param riskName - Name of the risk schema
4664
+ * @param exchangeName - Exchange name
4665
+ * @param frameName - Frame name (empty string for live)
4617
4666
  * @param backtest - Whether running in backtest mode
4618
4667
  * @returns Unique string key for memoization
4619
4668
  */
4620
- const CREATE_KEY_FN$a = (riskName, backtest) => `${riskName}:${backtest ? "backtest" : "live"}`;
4669
+ const CREATE_KEY_FN$a = (riskName, exchangeName, frameName, backtest) => {
4670
+ const parts = [riskName, exchangeName];
4671
+ if (frameName)
4672
+ parts.push(frameName);
4673
+ parts.push(backtest ? "backtest" : "live");
4674
+ return parts.join(":");
4675
+ };
4621
4676
  /**
4622
4677
  * Callback function for emitting risk rejection events to riskSubject.
4623
4678
  *
@@ -4630,16 +4685,19 @@ const CREATE_KEY_FN$a = (riskName, backtest) => `${riskName}:${backtest ? "backt
4630
4685
  * @param rejectionResult - Rejection result with id and note
4631
4686
  * @param timestamp - Event timestamp in milliseconds
4632
4687
  * @param backtest - True if backtest mode, false if live mode
4688
+ * @param exchangeName - Exchange name
4689
+ * @param frameName - Frame name
4633
4690
  */
4634
- const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => await riskSubject.next({
4691
+ const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName) => await riskSubject.next({
4635
4692
  symbol,
4636
4693
  pendingSignal: params.pendingSignal,
4637
4694
  strategyName: params.strategyName,
4638
- exchangeName: params.exchangeName,
4695
+ exchangeName,
4639
4696
  currentPrice: params.currentPrice,
4640
4697
  activePositionCount,
4641
4698
  rejectionId: rejectionResult.id,
4642
4699
  rejectionNote: rejectionResult.note,
4700
+ frameName,
4643
4701
  timestamp,
4644
4702
  backtest,
4645
4703
  });
@@ -4680,22 +4738,24 @@ class RiskConnectionService {
4680
4738
  this.loggerService = inject(TYPES.loggerService);
4681
4739
  this.riskSchemaService = inject(TYPES.riskSchemaService);
4682
4740
  /**
4683
- * Retrieves memoized ClientRisk instance for given risk name and backtest mode.
4741
+ * Retrieves memoized ClientRisk instance for given risk name, exchange, frame and backtest mode.
4684
4742
  *
4685
4743
  * Creates ClientRisk on first call, returns cached instance on subsequent calls.
4686
- * Cache key is "riskName:backtest" string to separate live and backtest instances.
4744
+ * Cache key includes exchangeName and frameName to isolate risk per exchange+frame.
4687
4745
  *
4688
4746
  * @param riskName - Name of registered risk schema
4747
+ * @param exchangeName - Exchange name
4748
+ * @param frameName - Frame name (empty string for live)
4689
4749
  * @param backtest - True if backtest mode, false if live mode
4690
4750
  * @returns Configured ClientRisk instance
4691
4751
  */
4692
- this.getRisk = functoolsKit.memoize(([riskName, backtest]) => CREATE_KEY_FN$a(riskName, backtest), (riskName, backtest) => {
4752
+ this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
4693
4753
  const schema = this.riskSchemaService.get(riskName);
4694
4754
  return new ClientRisk({
4695
4755
  ...schema,
4696
4756
  logger: this.loggerService,
4697
4757
  backtest,
4698
- onRejected: COMMIT_REJECTION_FN,
4758
+ onRejected: (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => COMMIT_REJECTION_FN(symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName),
4699
4759
  });
4700
4760
  });
4701
4761
  /**
@@ -4706,57 +4766,55 @@ class RiskConnectionService {
4706
4766
  * ClientRisk will emit riskSubject event via onRejected callback when signal is rejected.
4707
4767
  *
4708
4768
  * @param params - Risk check arguments (portfolio state, position details)
4709
- * @param context - Execution context with risk name and backtest mode
4769
+ * @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
4710
4770
  * @returns Promise resolving to risk check result
4711
4771
  */
4712
- this.checkSignal = async (params, context) => {
4772
+ this.checkSignal = async (params, payload) => {
4713
4773
  this.loggerService.log("riskConnectionService checkSignal", {
4714
4774
  symbol: params.symbol,
4715
- context,
4775
+ payload,
4716
4776
  });
4717
- return await this.getRisk(context.riskName, context.backtest).checkSignal(params);
4777
+ return await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).checkSignal(params);
4718
4778
  };
4719
4779
  /**
4720
4780
  * Registers an opened signal with the risk management system.
4721
4781
  * Routes to appropriate ClientRisk instance.
4722
4782
  *
4723
4783
  * @param symbol - Trading pair symbol
4724
- * @param context - Context information (strategyName, riskName, backtest)
4784
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
4725
4785
  */
4726
- this.addSignal = async (symbol, context) => {
4786
+ this.addSignal = async (symbol, payload) => {
4727
4787
  this.loggerService.log("riskConnectionService addSignal", {
4728
4788
  symbol,
4729
- context,
4789
+ payload,
4730
4790
  });
4731
- await this.getRisk(context.riskName, context.backtest).addSignal(symbol, context);
4791
+ await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).addSignal(symbol, payload);
4732
4792
  };
4733
4793
  /**
4734
4794
  * Removes a closed signal from the risk management system.
4735
4795
  * Routes to appropriate ClientRisk instance.
4736
4796
  *
4737
4797
  * @param symbol - Trading pair symbol
4738
- * @param context - Context information (strategyName, riskName, backtest)
4798
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
4739
4799
  */
4740
- this.removeSignal = async (symbol, context) => {
4800
+ this.removeSignal = async (symbol, payload) => {
4741
4801
  this.loggerService.log("riskConnectionService removeSignal", {
4742
4802
  symbol,
4743
- context,
4803
+ payload,
4744
4804
  });
4745
- await this.getRisk(context.riskName, context.backtest).removeSignal(symbol, context);
4805
+ await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).removeSignal(symbol, payload);
4746
4806
  };
4747
4807
  /**
4748
4808
  * Clears the cached ClientRisk instance for the given risk name.
4749
4809
  *
4750
- * @param backtest - Whether running in backtest mode
4751
- * @param ctx - Optional context with riskName (clears all if not provided)
4810
+ * @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
4752
4811
  */
4753
- this.clear = async (backtest, ctx) => {
4812
+ this.clear = async (payload) => {
4754
4813
  this.loggerService.log("riskConnectionService clear", {
4755
- ctx,
4756
- backtest,
4814
+ payload,
4757
4815
  });
4758
- if (ctx) {
4759
- const key = CREATE_KEY_FN$a(ctx.riskName, backtest);
4816
+ if (payload) {
4817
+ const key = CREATE_KEY_FN$a(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
4760
4818
  this.getRisk.clear(key);
4761
4819
  }
4762
4820
  else {
@@ -4955,23 +5013,22 @@ class StrategyCoreService {
4955
5013
  this.strategySchemaService = inject(TYPES.strategySchemaService);
4956
5014
  this.riskValidationService = inject(TYPES.riskValidationService);
4957
5015
  this.strategyValidationService = inject(TYPES.strategyValidationService);
4958
- this.methodContextService = inject(TYPES.methodContextService);
4959
5016
  /**
4960
5017
  * Validates strategy and associated risk configuration.
4961
5018
  *
4962
- * Memoized to avoid redundant validations for the same symbol-strategy pair.
5019
+ * Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
4963
5020
  * Logs validation activity.
4964
5021
  * @param symbol - Trading pair symbol
4965
- * @param strategyName - Name of the strategy to validate
5022
+ * @param context - Execution context with strategyName, exchangeName, frameName
4966
5023
  * @returns Promise that resolves when validation is complete
4967
5024
  */
4968
- this.validate = functoolsKit.memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, async (symbol, strategyName) => {
5025
+ this.validate = functoolsKit.memoize(([symbol, context]) => `${symbol}:${context.strategyName}:${context.exchangeName}:${context.frameName}`, async (symbol, context) => {
4969
5026
  this.loggerService.log(METHOD_NAME_VALIDATE, {
4970
5027
  symbol,
4971
- strategyName,
5028
+ context,
4972
5029
  });
4973
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
4974
- this.strategyValidationService.validate(strategyName, METHOD_NAME_VALIDATE);
5030
+ const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
5031
+ this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
4975
5032
  riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
4976
5033
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
4977
5034
  });
@@ -4980,34 +5037,36 @@ class StrategyCoreService {
4980
5037
  * If no active signal exists, returns null.
4981
5038
  * Used internally for monitoring TP/SL and time expiration.
4982
5039
  *
5040
+ * @param backtest - Whether running in backtest mode
4983
5041
  * @param symbol - Trading pair symbol
4984
- * @param strategyName - Name of the strategy
5042
+ * @param context - Execution context with strategyName, exchangeName, frameName
4985
5043
  * @returns Promise resolving to pending signal or null
4986
5044
  */
4987
- this.getPendingSignal = async (backtest, symbol, strategyName) => {
5045
+ this.getPendingSignal = async (backtest, symbol, context) => {
4988
5046
  this.loggerService.log("strategyCoreService getPendingSignal", {
4989
5047
  symbol,
4990
- strategyName,
5048
+ context,
4991
5049
  });
4992
- await this.validate(symbol, strategyName);
4993
- return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
5050
+ await this.validate(symbol, context);
5051
+ return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
4994
5052
  };
4995
5053
  /**
4996
5054
  * Retrieves the currently active scheduled signal for the symbol.
4997
5055
  * If no scheduled signal exists, returns null.
4998
5056
  * Used internally for monitoring scheduled signal activation.
4999
5057
  *
5058
+ * @param backtest - Whether running in backtest mode
5000
5059
  * @param symbol - Trading pair symbol
5001
- * @param strategyName - Name of the strategy
5060
+ * @param context - Execution context with strategyName, exchangeName, frameName
5002
5061
  * @returns Promise resolving to scheduled signal or null
5003
5062
  */
5004
- this.getScheduledSignal = async (backtest, symbol, strategyName) => {
5063
+ this.getScheduledSignal = async (backtest, symbol, context) => {
5005
5064
  this.loggerService.log("strategyCoreService getScheduledSignal", {
5006
5065
  symbol,
5007
- strategyName,
5066
+ context,
5008
5067
  });
5009
- await this.validate(symbol, strategyName);
5010
- return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, strategyName);
5068
+ await this.validate(symbol, context);
5069
+ return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
5011
5070
  };
5012
5071
  /**
5013
5072
  * Checks if the strategy has been stopped.
@@ -5015,18 +5074,19 @@ class StrategyCoreService {
5015
5074
  * Validates strategy existence and delegates to connection service
5016
5075
  * to retrieve the stopped state from the strategy instance.
5017
5076
  *
5077
+ * @param backtest - Whether running in backtest mode
5018
5078
  * @param symbol - Trading pair symbol
5019
- * @param strategyName - Name of the strategy
5079
+ * @param context - Execution context with strategyName, exchangeName, frameName
5020
5080
  * @returns Promise resolving to true if strategy is stopped, false otherwise
5021
5081
  */
5022
- this.getStopped = async (backtest, symbol, strategyName) => {
5082
+ this.getStopped = async (backtest, symbol, context) => {
5023
5083
  this.loggerService.log("strategyCoreService getStopped", {
5024
5084
  symbol,
5025
- strategyName,
5085
+ context,
5026
5086
  backtest,
5027
5087
  });
5028
- await this.validate(symbol, strategyName);
5029
- return await this.strategyConnectionService.getStopped(backtest, symbol, strategyName);
5088
+ await this.validate(symbol, context);
5089
+ return await this.strategyConnectionService.getStopped(backtest, symbol, context);
5030
5090
  };
5031
5091
  /**
5032
5092
  * Checks signal status at a specific timestamp.
@@ -5037,21 +5097,19 @@ class StrategyCoreService {
5037
5097
  * @param symbol - Trading pair symbol
5038
5098
  * @param when - Timestamp for tick evaluation
5039
5099
  * @param backtest - Whether running in backtest mode
5100
+ * @param context - Execution context with strategyName, exchangeName, frameName
5040
5101
  * @returns Discriminated union of tick result (idle, opened, active, closed)
5041
5102
  */
5042
- this.tick = async (symbol, when, backtest) => {
5103
+ this.tick = async (symbol, when, backtest, context) => {
5043
5104
  this.loggerService.log("strategyCoreService tick", {
5044
5105
  symbol,
5045
5106
  when,
5046
5107
  backtest,
5108
+ context,
5047
5109
  });
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);
5110
+ await this.validate(symbol, context);
5053
5111
  return await ExecutionContextService.runInContext(async () => {
5054
- return await this.strategyConnectionService.tick(symbol, strategyName);
5112
+ return await this.strategyConnectionService.tick(symbol, context);
5055
5113
  }, {
5056
5114
  symbol,
5057
5115
  when,
@@ -5068,22 +5126,20 @@ class StrategyCoreService {
5068
5126
  * @param candles - Array of historical candles to test against
5069
5127
  * @param when - Starting timestamp for backtest
5070
5128
  * @param backtest - Whether running in backtest mode (typically true)
5129
+ * @param context - Execution context with strategyName, exchangeName, frameName
5071
5130
  * @returns Closed signal result with PNL
5072
5131
  */
5073
- this.backtest = async (symbol, candles, when, backtest) => {
5132
+ this.backtest = async (symbol, candles, when, backtest, context) => {
5074
5133
  this.loggerService.log("strategyCoreService backtest", {
5075
5134
  symbol,
5076
5135
  candleCount: candles.length,
5077
5136
  when,
5078
5137
  backtest,
5138
+ context,
5079
5139
  });
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);
5140
+ await this.validate(symbol, context);
5085
5141
  return await ExecutionContextService.runInContext(async () => {
5086
- return await this.strategyConnectionService.backtest(symbol, strategyName, candles);
5142
+ return await this.strategyConnectionService.backtest(symbol, context, candles);
5087
5143
  }, {
5088
5144
  symbol,
5089
5145
  when,
@@ -5096,17 +5152,19 @@ class StrategyCoreService {
5096
5152
  * Delegates to StrategyConnectionService.stop() to set internal flag.
5097
5153
  * Does not require execution context.
5098
5154
  *
5155
+ * @param backtest - Whether running in backtest mode
5099
5156
  * @param symbol - Trading pair symbol
5100
- * @param strategyName - Name of strategy to stop
5157
+ * @param ctx - Context with strategyName, exchangeName, frameName
5101
5158
  * @returns Promise that resolves when stop flag is set
5102
5159
  */
5103
- this.stop = async (backtest, ctx) => {
5160
+ this.stop = async (backtest, symbol, context) => {
5104
5161
  this.loggerService.log("strategyCoreService stop", {
5105
- ctx,
5162
+ symbol,
5163
+ context,
5106
5164
  backtest,
5107
5165
  });
5108
- await this.validate(ctx.symbol, ctx.strategyName);
5109
- return await this.strategyConnectionService.stop(backtest, ctx);
5166
+ await this.validate(symbol, context);
5167
+ return await this.strategyConnectionService.stop(backtest, symbol, context);
5110
5168
  };
5111
5169
  /**
5112
5170
  * Cancels the scheduled signal without stopping the strategy.
@@ -5116,18 +5174,20 @@ class StrategyCoreService {
5116
5174
  * Does not require execution context.
5117
5175
  *
5118
5176
  * @param backtest - Whether running in backtest mode
5119
- * @param ctx - Context with symbol and strategyName
5177
+ * @param symbol - Trading pair symbol
5178
+ * @param ctx - Context with strategyName, exchangeName, frameName
5120
5179
  * @param cancelId - Optional cancellation ID for user-initiated cancellations
5121
5180
  * @returns Promise that resolves when scheduled signal is cancelled
5122
5181
  */
5123
- this.cancel = async (backtest, ctx, cancelId) => {
5182
+ this.cancel = async (backtest, symbol, context, cancelId) => {
5124
5183
  this.loggerService.log("strategyCoreService cancel", {
5125
- ctx,
5184
+ symbol,
5185
+ context,
5126
5186
  backtest,
5127
5187
  cancelId,
5128
5188
  });
5129
- await this.validate(ctx.symbol, ctx.strategyName);
5130
- return await this.strategyConnectionService.cancel(backtest, ctx, cancelId);
5189
+ await this.validate(symbol, context);
5190
+ return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
5131
5191
  };
5132
5192
  /**
5133
5193
  * Clears the memoized ClientStrategy instance from cache.
@@ -5135,16 +5195,20 @@ class StrategyCoreService {
5135
5195
  * Delegates to StrategyConnectionService.clear() to remove strategy from cache.
5136
5196
  * Forces re-initialization of strategy on next operation.
5137
5197
  *
5138
- * @param ctx - Optional context with symbol and strategyName (clears all if not provided)
5198
+ * @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
5139
5199
  */
5140
- this.clear = async (backtest, ctx) => {
5200
+ this.clear = async (payload) => {
5141
5201
  this.loggerService.log("strategyCoreService clear", {
5142
- ctx,
5202
+ payload,
5143
5203
  });
5144
- if (ctx) {
5145
- await this.validate(ctx.symbol, ctx.strategyName);
5204
+ if (payload) {
5205
+ await this.validate(payload.symbol, {
5206
+ strategyName: payload.strategyName,
5207
+ exchangeName: payload.exchangeName,
5208
+ frameName: payload.frameName
5209
+ });
5146
5210
  }
5147
- return await this.strategyConnectionService.clear(backtest, ctx);
5211
+ return await this.strategyConnectionService.clear(payload);
5148
5212
  };
5149
5213
  }
5150
5214
  }
@@ -5225,76 +5289,74 @@ class RiskGlobalService {
5225
5289
  this.riskValidationService = inject(TYPES.riskValidationService);
5226
5290
  /**
5227
5291
  * Validates risk configuration.
5228
- * Memoized to avoid redundant validations for the same risk instance.
5292
+ * Memoized to avoid redundant validations for the same risk-exchange-frame combination.
5229
5293
  * Logs validation activity.
5230
- * @param riskName - Name of the risk instance to validate
5294
+ * @param payload - Payload with riskName, exchangeName and frameName
5231
5295
  * @returns Promise that resolves when validation is complete
5232
5296
  */
5233
- this.validate = functoolsKit.memoize(([riskName]) => `${riskName}`, async (riskName) => {
5297
+ this.validate = functoolsKit.memoize(([payload]) => `${payload.riskName}:${payload.exchangeName}:${payload.frameName}`, async (payload) => {
5234
5298
  this.loggerService.log("riskGlobalService validate", {
5235
- riskName,
5299
+ payload,
5236
5300
  });
5237
- this.riskValidationService.validate(riskName, "riskGlobalService validate");
5301
+ this.riskValidationService.validate(payload.riskName, "riskGlobalService validate");
5238
5302
  });
5239
5303
  /**
5240
5304
  * Checks if a signal should be allowed based on risk limits.
5241
5305
  *
5242
5306
  * @param params - Risk check arguments (portfolio state, position details)
5243
- * @param context - Execution context with risk name
5307
+ * @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
5244
5308
  * @returns Promise resolving to risk check result
5245
5309
  */
5246
- this.checkSignal = async (params, context) => {
5310
+ this.checkSignal = async (params, payload) => {
5247
5311
  this.loggerService.log("riskGlobalService checkSignal", {
5248
5312
  symbol: params.symbol,
5249
- context,
5313
+ payload,
5250
5314
  });
5251
- await this.validate(context.riskName);
5252
- return await this.riskConnectionService.checkSignal(params, context);
5315
+ await this.validate(payload);
5316
+ return await this.riskConnectionService.checkSignal(params, payload);
5253
5317
  };
5254
5318
  /**
5255
5319
  * Registers an opened signal with the risk management system.
5256
5320
  *
5257
5321
  * @param symbol - Trading pair symbol
5258
- * @param context - Context information (strategyName, riskName)
5322
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
5259
5323
  */
5260
- this.addSignal = async (symbol, context) => {
5324
+ this.addSignal = async (symbol, payload) => {
5261
5325
  this.loggerService.log("riskGlobalService addSignal", {
5262
5326
  symbol,
5263
- context,
5327
+ payload,
5264
5328
  });
5265
- await this.validate(context.riskName);
5266
- await this.riskConnectionService.addSignal(symbol, context);
5329
+ await this.validate(payload);
5330
+ await this.riskConnectionService.addSignal(symbol, payload);
5267
5331
  };
5268
5332
  /**
5269
5333
  * Removes a closed signal from the risk management system.
5270
5334
  *
5271
5335
  * @param symbol - Trading pair symbol
5272
- * @param context - Context information (strategyName, riskName)
5336
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
5273
5337
  */
5274
- this.removeSignal = async (symbol, context) => {
5338
+ this.removeSignal = async (symbol, payload) => {
5275
5339
  this.loggerService.log("riskGlobalService removeSignal", {
5276
5340
  symbol,
5277
- context,
5341
+ payload,
5278
5342
  });
5279
- await this.validate(context.riskName);
5280
- await this.riskConnectionService.removeSignal(symbol, context);
5343
+ await this.validate(payload);
5344
+ await this.riskConnectionService.removeSignal(symbol, payload);
5281
5345
  };
5282
5346
  /**
5283
5347
  * 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)
5348
+ * If payload is provided, clears data for that specific risk instance.
5349
+ * If no payload is provided, clears all risk data.
5350
+ * @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
5288
5351
  */
5289
- this.clear = async (backtest, ctx) => {
5352
+ this.clear = async (payload) => {
5290
5353
  this.loggerService.log("riskGlobalService clear", {
5291
- ctx,
5292
- backtest,
5354
+ payload,
5293
5355
  });
5294
- if (ctx) {
5295
- await this.validate(ctx.riskName);
5356
+ if (payload) {
5357
+ await this.validate(payload);
5296
5358
  }
5297
- return await this.riskConnectionService.clear(backtest, ctx);
5359
+ return await this.riskConnectionService.clear(payload);
5298
5360
  };
5299
5361
  }
5300
5362
  }
@@ -5845,7 +5907,11 @@ class BacktestLogicPrivateService {
5845
5907
  });
5846
5908
  }
5847
5909
  // Check if strategy should stop before processing next frame
5848
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
5910
+ if (await this.strategyCoreService.getStopped(true, symbol, {
5911
+ strategyName: this.methodContextService.context.strategyName,
5912
+ exchangeName: this.methodContextService.context.exchangeName,
5913
+ frameName: this.methodContextService.context.frameName,
5914
+ })) {
5849
5915
  this.loggerService.info("backtestLogicPrivateService stopped by user request (before tick)", {
5850
5916
  symbol,
5851
5917
  when: when.toISOString(),
@@ -5856,7 +5922,11 @@ class BacktestLogicPrivateService {
5856
5922
  }
5857
5923
  let result;
5858
5924
  try {
5859
- result = await this.strategyCoreService.tick(symbol, when, true);
5925
+ result = await this.strategyCoreService.tick(symbol, when, true, {
5926
+ strategyName: this.methodContextService.context.strategyName,
5927
+ exchangeName: this.methodContextService.context.exchangeName,
5928
+ frameName: this.methodContextService.context.frameName,
5929
+ });
5860
5930
  }
5861
5931
  catch (error) {
5862
5932
  console.warn(`backtestLogicPrivateService tick failed, skipping timeframe when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -5870,7 +5940,11 @@ class BacktestLogicPrivateService {
5870
5940
  continue;
5871
5941
  }
5872
5942
  // 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))) {
5943
+ if (await functoolsKit.and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, {
5944
+ strategyName: this.methodContextService.context.strategyName,
5945
+ exchangeName: this.methodContextService.context.exchangeName,
5946
+ frameName: this.methodContextService.context.frameName,
5947
+ }))) {
5874
5948
  this.loggerService.info("backtestLogicPrivateService stopped by user request (idle state)", {
5875
5949
  symbol,
5876
5950
  when: when.toISOString(),
@@ -5929,7 +6003,11 @@ class BacktestLogicPrivateService {
5929
6003
  // и если активируется - продолжит с TP/SL мониторингом
5930
6004
  let backtestResult;
5931
6005
  try {
5932
- backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true);
6006
+ backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
6007
+ strategyName: this.methodContextService.context.strategyName,
6008
+ exchangeName: this.methodContextService.context.exchangeName,
6009
+ frameName: this.methodContextService.context.frameName,
6010
+ });
5933
6011
  }
5934
6012
  catch (error) {
5935
6013
  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 +6039,7 @@ class BacktestLogicPrivateService {
5961
6039
  duration: signalEndTime - signalStartTime,
5962
6040
  strategyName: this.methodContextService.context.strategyName,
5963
6041
  exchangeName: this.methodContextService.context.exchangeName,
6042
+ frameName: this.methodContextService.context.frameName,
5964
6043
  symbol,
5965
6044
  backtest: true,
5966
6045
  });
@@ -5972,7 +6051,11 @@ class BacktestLogicPrivateService {
5972
6051
  }
5973
6052
  yield backtestResult;
5974
6053
  // Check if strategy should stop after signal is closed
5975
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
6054
+ if (await this.strategyCoreService.getStopped(true, symbol, {
6055
+ strategyName: this.methodContextService.context.strategyName,
6056
+ exchangeName: this.methodContextService.context.exchangeName,
6057
+ frameName: this.methodContextService.context.frameName,
6058
+ })) {
5976
6059
  this.loggerService.info("backtestLogicPrivateService stopped by user request (after scheduled signal closed)", {
5977
6060
  symbol,
5978
6061
  signalId: backtestResult.signal.id,
@@ -6026,7 +6109,11 @@ class BacktestLogicPrivateService {
6026
6109
  // Вызываем backtest - всегда возвращает closed
6027
6110
  let backtestResult;
6028
6111
  try {
6029
- backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true);
6112
+ backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
6113
+ strategyName: this.methodContextService.context.strategyName,
6114
+ exchangeName: this.methodContextService.context.exchangeName,
6115
+ frameName: this.methodContextService.context.frameName,
6116
+ });
6030
6117
  }
6031
6118
  catch (error) {
6032
6119
  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 +6141,7 @@ class BacktestLogicPrivateService {
6054
6141
  duration: signalEndTime - signalStartTime,
6055
6142
  strategyName: this.methodContextService.context.strategyName,
6056
6143
  exchangeName: this.methodContextService.context.exchangeName,
6144
+ frameName: this.methodContextService.context.frameName,
6057
6145
  symbol,
6058
6146
  backtest: true,
6059
6147
  });
@@ -6065,7 +6153,11 @@ class BacktestLogicPrivateService {
6065
6153
  }
6066
6154
  yield backtestResult;
6067
6155
  // Check if strategy should stop after signal is closed
6068
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
6156
+ if (await this.strategyCoreService.getStopped(true, symbol, {
6157
+ strategyName: this.methodContextService.context.strategyName,
6158
+ exchangeName: this.methodContextService.context.exchangeName,
6159
+ frameName: this.methodContextService.context.frameName,
6160
+ })) {
6069
6161
  this.loggerService.info("backtestLogicPrivateService stopped by user request (after signal closed)", {
6070
6162
  symbol,
6071
6163
  signalId: backtestResult.signal.id,
@@ -6085,6 +6177,7 @@ class BacktestLogicPrivateService {
6085
6177
  duration: timeframeEndTime - timeframeStartTime,
6086
6178
  strategyName: this.methodContextService.context.strategyName,
6087
6179
  exchangeName: this.methodContextService.context.exchangeName,
6180
+ frameName: this.methodContextService.context.frameName,
6088
6181
  symbol,
6089
6182
  backtest: true,
6090
6183
  });
@@ -6112,6 +6205,7 @@ class BacktestLogicPrivateService {
6112
6205
  duration: backtestEndTime - backtestStartTime,
6113
6206
  strategyName: this.methodContextService.context.strategyName,
6114
6207
  exchangeName: this.methodContextService.context.exchangeName,
6208
+ frameName: this.methodContextService.context.frameName,
6115
6209
  symbol,
6116
6210
  backtest: true,
6117
6211
  });
@@ -6174,7 +6268,11 @@ class LiveLogicPrivateService {
6174
6268
  const when = new Date();
6175
6269
  let result;
6176
6270
  try {
6177
- result = await this.strategyCoreService.tick(symbol, when, false);
6271
+ result = await this.strategyCoreService.tick(symbol, when, false, {
6272
+ strategyName: this.methodContextService.context.strategyName,
6273
+ exchangeName: this.methodContextService.context.exchangeName,
6274
+ frameName: this.methodContextService.context.frameName,
6275
+ });
6178
6276
  }
6179
6277
  catch (error) {
6180
6278
  console.warn(`backtestLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -6202,13 +6300,18 @@ class LiveLogicPrivateService {
6202
6300
  duration: tickEndTime - tickStartTime,
6203
6301
  strategyName: this.methodContextService.context.strategyName,
6204
6302
  exchangeName: this.methodContextService.context.exchangeName,
6303
+ frameName: this.methodContextService.context.frameName,
6205
6304
  symbol,
6206
6305
  backtest: false,
6207
6306
  });
6208
6307
  previousEventTimestamp = currentTimestamp;
6209
6308
  // Check if strategy should stop when idle (no active signal)
6210
6309
  if (result.action === "idle") {
6211
- if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName))) {
6310
+ if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, {
6311
+ strategyName: this.methodContextService.context.strategyName,
6312
+ exchangeName: this.methodContextService.context.exchangeName,
6313
+ frameName: this.methodContextService.context.frameName,
6314
+ }))) {
6212
6315
  this.loggerService.info("liveLogicPrivateService stopped by user request (idle state)", {
6213
6316
  symbol,
6214
6317
  when: when.toISOString(),
@@ -6230,7 +6333,11 @@ class LiveLogicPrivateService {
6230
6333
  yield result;
6231
6334
  // Check if strategy should stop after signal is closed
6232
6335
  if (result.action === "closed") {
6233
- if (await this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName)) {
6336
+ if (await this.strategyCoreService.getStopped(false, symbol, {
6337
+ strategyName: this.methodContextService.context.strategyName,
6338
+ exchangeName: this.methodContextService.context.exchangeName,
6339
+ frameName: this.methodContextService.context.frameName,
6340
+ })) {
6234
6341
  this.loggerService.info("liveLogicPrivateService stopped by user request (after signal closed)", {
6235
6342
  symbol,
6236
6343
  signalId: result.signal.id,
@@ -6362,7 +6469,7 @@ class WalkerLogicPrivateService {
6362
6469
  symbol,
6363
6470
  });
6364
6471
  // Get statistics from BacktestMarkdownService
6365
- const stats = await this.backtestMarkdownService.getData(symbol, strategyName, true);
6472
+ const stats = await this.backtestMarkdownService.getData(symbol, strategyName, context.exchangeName, context.frameName, true);
6366
6473
  // Extract metric value
6367
6474
  const value = stats[metric];
6368
6475
  const metricValue = value !== null &&
@@ -6426,7 +6533,7 @@ class WalkerLogicPrivateService {
6426
6533
  bestStrategy,
6427
6534
  bestMetric,
6428
6535
  bestStats: bestStrategy !== null
6429
- ? await this.backtestMarkdownService.getData(symbol, bestStrategy, true)
6536
+ ? await this.backtestMarkdownService.getData(symbol, bestStrategy, context.exchangeName, context.frameName, true)
6430
6537
  : null,
6431
6538
  };
6432
6539
  // Call onComplete callback if provided with final best results
@@ -7789,13 +7896,21 @@ const DEFAULT_COLUMNS = Object.freeze({ ...COLUMN_CONFIG });
7789
7896
 
7790
7897
  /**
7791
7898
  * Creates a unique key for memoizing ReportStorage instances.
7792
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
7899
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
7793
7900
  * @param symbol - Trading pair symbol
7794
7901
  * @param strategyName - Name of the strategy
7902
+ * @param exchangeName - Exchange name
7903
+ * @param frameName - Frame name
7795
7904
  * @param backtest - Whether running in backtest mode
7796
7905
  * @returns Unique string key for memoization
7797
7906
  */
7798
- const CREATE_KEY_FN$9 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
7907
+ const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
7908
+ const parts = [symbol, strategyName, exchangeName];
7909
+ if (frameName)
7910
+ parts.push(frameName);
7911
+ parts.push(backtest ? "backtest" : "live");
7912
+ return parts.join(":");
7913
+ };
7799
7914
  /**
7800
7915
  * Checks if a value is unsafe for display (not a number, NaN, or Infinity).
7801
7916
  *
@@ -8001,17 +8116,17 @@ class BacktestMarkdownService {
8001
8116
  /** Logger service for debug output */
8002
8117
  this.loggerService = inject(TYPES.loggerService);
8003
8118
  /**
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.
8119
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
8120
+ * Each combination gets its own isolated storage instance.
8006
8121
  */
8007
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, backtest), () => new ReportStorage$5());
8122
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$5());
8008
8123
  /**
8009
8124
  * Processes tick events and accumulates closed signals.
8010
8125
  * Should be called from IStrategyCallbacks.onTick.
8011
8126
  *
8012
8127
  * Only processes closed signals - opened signals are ignored.
8013
8128
  *
8014
- * @param data - Tick result from strategy execution (opened or closed)
8129
+ * @param data - Tick result from strategy execution (opened or closed) with frameName wrapper
8015
8130
  *
8016
8131
  * @example
8017
8132
  * ```typescript
@@ -8031,7 +8146,7 @@ class BacktestMarkdownService {
8031
8146
  if (data.action !== "closed") {
8032
8147
  return;
8033
8148
  }
8034
- const storage = this.getStorage(data.symbol, data.strategyName, true);
8149
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, true);
8035
8150
  storage.addSignal(data);
8036
8151
  };
8037
8152
  /**
@@ -8040,23 +8155,27 @@ class BacktestMarkdownService {
8040
8155
  *
8041
8156
  * @param symbol - Trading pair symbol
8042
8157
  * @param strategyName - Strategy name to get data for
8158
+ * @param exchangeName - Exchange name
8159
+ * @param frameName - Frame name
8043
8160
  * @param backtest - True if backtest mode, false if live mode
8044
8161
  * @returns Statistical data object with all metrics
8045
8162
  *
8046
8163
  * @example
8047
8164
  * ```typescript
8048
8165
  * const service = new BacktestMarkdownService();
8049
- * const stats = await service.getData("BTCUSDT", "my-strategy", true);
8166
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", true);
8050
8167
  * console.log(stats.sharpeRatio, stats.winRate);
8051
8168
  * ```
8052
8169
  */
8053
- this.getData = async (symbol, strategyName, backtest) => {
8170
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8054
8171
  this.loggerService.log("backtestMarkdownService getData", {
8055
8172
  symbol,
8056
8173
  strategyName,
8174
+ exchangeName,
8175
+ frameName,
8057
8176
  backtest,
8058
8177
  });
8059
- const storage = this.getStorage(symbol, strategyName, backtest);
8178
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8060
8179
  return storage.getData();
8061
8180
  };
8062
8181
  /**
@@ -8065,6 +8184,8 @@ class BacktestMarkdownService {
8065
8184
  *
8066
8185
  * @param symbol - Trading pair symbol
8067
8186
  * @param strategyName - Strategy name to generate report for
8187
+ * @param exchangeName - Exchange name
8188
+ * @param frameName - Frame name
8068
8189
  * @param backtest - True if backtest mode, false if live mode
8069
8190
  * @param columns - Column configuration for formatting the table
8070
8191
  * @returns Markdown formatted report string with table of all closed signals
@@ -8072,17 +8193,19 @@ class BacktestMarkdownService {
8072
8193
  * @example
8073
8194
  * ```typescript
8074
8195
  * const service = new BacktestMarkdownService();
8075
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", true);
8196
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", true);
8076
8197
  * console.log(markdown);
8077
8198
  * ```
8078
8199
  */
8079
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
8200
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
8080
8201
  this.loggerService.log("backtestMarkdownService getReport", {
8081
8202
  symbol,
8082
8203
  strategyName,
8204
+ exchangeName,
8205
+ frameName,
8083
8206
  backtest,
8084
8207
  });
8085
- const storage = this.getStorage(symbol, strategyName, backtest);
8208
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8086
8209
  return storage.getReport(strategyName, columns);
8087
8210
  };
8088
8211
  /**
@@ -8092,6 +8215,8 @@ class BacktestMarkdownService {
8092
8215
  *
8093
8216
  * @param symbol - Trading pair symbol
8094
8217
  * @param strategyName - Strategy name to save report for
8218
+ * @param exchangeName - Exchange name
8219
+ * @param frameName - Frame name
8095
8220
  * @param backtest - True if backtest mode, false if live mode
8096
8221
  * @param path - Directory path to save report (default: "./dump/backtest")
8097
8222
  * @param columns - Column configuration for formatting the table
@@ -8101,48 +8226,48 @@ class BacktestMarkdownService {
8101
8226
  * const service = new BacktestMarkdownService();
8102
8227
  *
8103
8228
  * // Save to default path: ./dump/backtest/my-strategy.md
8104
- * await service.dump("BTCUSDT", "my-strategy", true);
8229
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true);
8105
8230
  *
8106
8231
  * // Save to custom path: ./custom/path/my-strategy.md
8107
- * await service.dump("BTCUSDT", "my-strategy", true, "./custom/path");
8232
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true, "./custom/path");
8108
8233
  * ```
8109
8234
  */
8110
- this.dump = async (symbol, strategyName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
8235
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
8111
8236
  this.loggerService.log("backtestMarkdownService dump", {
8112
8237
  symbol,
8113
8238
  strategyName,
8239
+ exchangeName,
8240
+ frameName,
8114
8241
  backtest,
8115
8242
  path,
8116
8243
  });
8117
- const storage = this.getStorage(symbol, strategyName, backtest);
8244
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8118
8245
  await storage.dump(strategyName, path, columns);
8119
8246
  };
8120
8247
  /**
8121
8248
  * Clears accumulated signal data from storage.
8122
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
8249
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
8123
8250
  * If nothing is provided, clears all data.
8124
8251
  *
8125
- * @param backtest - Backtest mode flag
8126
- * @param ctx - Optional context with symbol and strategyName
8252
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
8127
8253
  *
8128
8254
  * @example
8129
8255
  * ```typescript
8130
8256
  * const service = new BacktestMarkdownService();
8131
8257
  *
8132
- * // Clear specific symbol-strategy-backtest triple
8133
- * await service.clear(true, { symbol: "BTCUSDT", strategyName: "my-strategy" });
8258
+ * // Clear specific combination
8259
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: true });
8134
8260
  *
8135
8261
  * // Clear all data
8136
8262
  * await service.clear();
8137
8263
  * ```
8138
8264
  */
8139
- this.clear = async (backtest, ctx) => {
8265
+ this.clear = async (payload) => {
8140
8266
  this.loggerService.log("backtestMarkdownService clear", {
8141
- backtest,
8142
- ctx,
8267
+ payload,
8143
8268
  });
8144
- if (ctx) {
8145
- const key = CREATE_KEY_FN$9(ctx.symbol, ctx.strategyName, backtest);
8269
+ if (payload) {
8270
+ const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
8146
8271
  this.getStorage.clear(key);
8147
8272
  }
8148
8273
  else {
@@ -8169,13 +8294,21 @@ class BacktestMarkdownService {
8169
8294
 
8170
8295
  /**
8171
8296
  * Creates a unique key for memoizing ReportStorage instances.
8172
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
8297
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
8173
8298
  * @param symbol - Trading pair symbol
8174
8299
  * @param strategyName - Name of the strategy
8300
+ * @param exchangeName - Exchange name
8301
+ * @param frameName - Frame name
8175
8302
  * @param backtest - Whether running in backtest mode
8176
8303
  * @returns Unique string key for memoization
8177
8304
  */
8178
- const CREATE_KEY_FN$8 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
8305
+ const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
8306
+ const parts = [symbol, strategyName, exchangeName];
8307
+ if (frameName)
8308
+ parts.push(frameName);
8309
+ parts.push(backtest ? "backtest" : "live");
8310
+ return parts.join(":");
8311
+ };
8179
8312
  /**
8180
8313
  * Checks if a value is unsafe for display (not a number, NaN, or Infinity).
8181
8314
  *
@@ -8502,17 +8635,17 @@ class LiveMarkdownService {
8502
8635
  /** Logger service for debug output */
8503
8636
  this.loggerService = inject(TYPES.loggerService);
8504
8637
  /**
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.
8638
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
8639
+ * Each combination gets its own isolated storage instance.
8507
8640
  */
8508
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, backtest), () => new ReportStorage$4());
8641
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$4());
8509
8642
  /**
8510
8643
  * Processes tick events and accumulates all event types.
8511
8644
  * Should be called from IStrategyCallbacks.onTick.
8512
8645
  *
8513
8646
  * Processes all event types: idle, opened, active, closed.
8514
8647
  *
8515
- * @param data - Tick result from strategy execution
8648
+ * @param data - Tick result from strategy execution with frameName wrapper
8516
8649
  *
8517
8650
  * @example
8518
8651
  * ```typescript
@@ -8531,7 +8664,7 @@ class LiveMarkdownService {
8531
8664
  this.loggerService.log("liveMarkdownService tick", {
8532
8665
  data,
8533
8666
  });
8534
- const storage = this.getStorage(data.symbol, data.strategyName, false);
8667
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, false);
8535
8668
  if (data.action === "idle") {
8536
8669
  storage.addIdleEvent(data.currentPrice);
8537
8670
  }
@@ -8551,23 +8684,27 @@ class LiveMarkdownService {
8551
8684
  *
8552
8685
  * @param symbol - Trading pair symbol
8553
8686
  * @param strategyName - Strategy name to get data for
8687
+ * @param exchangeName - Exchange name
8688
+ * @param frameName - Frame name
8554
8689
  * @param backtest - True if backtest mode, false if live mode
8555
8690
  * @returns Statistical data object with all metrics
8556
8691
  *
8557
8692
  * @example
8558
8693
  * ```typescript
8559
8694
  * const service = new LiveMarkdownService();
8560
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
8695
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
8561
8696
  * console.log(stats.sharpeRatio, stats.winRate);
8562
8697
  * ```
8563
8698
  */
8564
- this.getData = async (symbol, strategyName, backtest) => {
8699
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8565
8700
  this.loggerService.log("liveMarkdownService getData", {
8566
8701
  symbol,
8567
8702
  strategyName,
8703
+ exchangeName,
8704
+ frameName,
8568
8705
  backtest,
8569
8706
  });
8570
- const storage = this.getStorage(symbol, strategyName, backtest);
8707
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8571
8708
  return storage.getData();
8572
8709
  };
8573
8710
  /**
@@ -8576,6 +8713,8 @@ class LiveMarkdownService {
8576
8713
  *
8577
8714
  * @param symbol - Trading pair symbol
8578
8715
  * @param strategyName - Strategy name to generate report for
8716
+ * @param exchangeName - Exchange name
8717
+ * @param frameName - Frame name
8579
8718
  * @param backtest - True if backtest mode, false if live mode
8580
8719
  * @param columns - Column configuration for formatting the table
8581
8720
  * @returns Markdown formatted report string with table of all events
@@ -8583,17 +8722,19 @@ class LiveMarkdownService {
8583
8722
  * @example
8584
8723
  * ```typescript
8585
8724
  * const service = new LiveMarkdownService();
8586
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
8725
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
8587
8726
  * console.log(markdown);
8588
8727
  * ```
8589
8728
  */
8590
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.live_columns) => {
8729
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.live_columns) => {
8591
8730
  this.loggerService.log("liveMarkdownService getReport", {
8592
8731
  symbol,
8593
8732
  strategyName,
8733
+ exchangeName,
8734
+ frameName,
8594
8735
  backtest,
8595
8736
  });
8596
- const storage = this.getStorage(symbol, strategyName, backtest);
8737
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8597
8738
  return storage.getReport(strategyName, columns);
8598
8739
  };
8599
8740
  /**
@@ -8603,6 +8744,8 @@ class LiveMarkdownService {
8603
8744
  *
8604
8745
  * @param symbol - Trading pair symbol
8605
8746
  * @param strategyName - Strategy name to save report for
8747
+ * @param exchangeName - Exchange name
8748
+ * @param frameName - Frame name
8606
8749
  * @param backtest - True if backtest mode, false if live mode
8607
8750
  * @param path - Directory path to save report (default: "./dump/live")
8608
8751
  * @param columns - Column configuration for formatting the table
@@ -8612,48 +8755,48 @@ class LiveMarkdownService {
8612
8755
  * const service = new LiveMarkdownService();
8613
8756
  *
8614
8757
  * // Save to default path: ./dump/live/my-strategy.md
8615
- * await service.dump("BTCUSDT", "my-strategy", false);
8758
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
8616
8759
  *
8617
8760
  * // Save to custom path: ./custom/path/my-strategy.md
8618
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
8761
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
8619
8762
  * ```
8620
8763
  */
8621
- this.dump = async (symbol, strategyName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
8764
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
8622
8765
  this.loggerService.log("liveMarkdownService dump", {
8623
8766
  symbol,
8624
8767
  strategyName,
8768
+ exchangeName,
8769
+ frameName,
8625
8770
  backtest,
8626
8771
  path,
8627
8772
  });
8628
- const storage = this.getStorage(symbol, strategyName, backtest);
8773
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8629
8774
  await storage.dump(strategyName, path, columns);
8630
8775
  };
8631
8776
  /**
8632
8777
  * Clears accumulated event data from storage.
8633
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
8778
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
8634
8779
  * If nothing is provided, clears all data.
8635
8780
  *
8636
- * @param backtest - Backtest mode flag
8637
- * @param ctx - Optional context with symbol and strategyName
8781
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
8638
8782
  *
8639
8783
  * @example
8640
8784
  * ```typescript
8641
8785
  * const service = new LiveMarkdownService();
8642
8786
  *
8643
- * // Clear specific symbol-strategy-backtest triple
8644
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
8787
+ * // Clear specific combination
8788
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
8645
8789
  *
8646
8790
  * // Clear all data
8647
8791
  * await service.clear();
8648
8792
  * ```
8649
8793
  */
8650
- this.clear = async (backtest, ctx) => {
8794
+ this.clear = async (payload) => {
8651
8795
  this.loggerService.log("liveMarkdownService clear", {
8652
- backtest,
8653
- ctx,
8796
+ payload,
8654
8797
  });
8655
- if (ctx) {
8656
- const key = CREATE_KEY_FN$8(ctx.symbol, ctx.strategyName, backtest);
8798
+ if (payload) {
8799
+ const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
8657
8800
  this.getStorage.clear(key);
8658
8801
  }
8659
8802
  else {
@@ -8680,13 +8823,21 @@ class LiveMarkdownService {
8680
8823
 
8681
8824
  /**
8682
8825
  * Creates a unique key for memoizing ReportStorage instances.
8683
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
8826
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
8684
8827
  * @param symbol - Trading pair symbol
8685
8828
  * @param strategyName - Name of the strategy
8829
+ * @param exchangeName - Exchange name
8830
+ * @param frameName - Frame name
8686
8831
  * @param backtest - Whether running in backtest mode
8687
8832
  * @returns Unique string key for memoization
8688
8833
  */
8689
- const CREATE_KEY_FN$7 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
8834
+ const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
8835
+ const parts = [symbol, strategyName, exchangeName];
8836
+ if (frameName)
8837
+ parts.push(frameName);
8838
+ parts.push(backtest ? "backtest" : "live");
8839
+ return parts.join(":");
8840
+ };
8690
8841
  /** Maximum number of events to store in schedule reports */
8691
8842
  const MAX_EVENTS$4 = 250;
8692
8843
  /**
@@ -8919,17 +9070,17 @@ class ScheduleMarkdownService {
8919
9070
  /** Logger service for debug output */
8920
9071
  this.loggerService = inject(TYPES.loggerService);
8921
9072
  /**
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.
9073
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
9074
+ * Each combination gets its own isolated storage instance.
8924
9075
  */
8925
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, backtest), () => new ReportStorage$3());
9076
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$3());
8926
9077
  /**
8927
9078
  * Processes tick events and accumulates scheduled/opened/cancelled events.
8928
9079
  * Should be called from signalEmitter subscription.
8929
9080
  *
8930
9081
  * Processes only scheduled, opened and cancelled event types.
8931
9082
  *
8932
- * @param data - Tick result from strategy execution
9083
+ * @param data - Tick result from strategy execution with frameName wrapper
8933
9084
  *
8934
9085
  * @example
8935
9086
  * ```typescript
@@ -8941,7 +9092,7 @@ class ScheduleMarkdownService {
8941
9092
  this.loggerService.log("scheduleMarkdownService tick", {
8942
9093
  data,
8943
9094
  });
8944
- const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
9095
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
8945
9096
  if (data.action === "scheduled") {
8946
9097
  storage.addScheduledEvent(data);
8947
9098
  }
@@ -8962,23 +9113,27 @@ class ScheduleMarkdownService {
8962
9113
  *
8963
9114
  * @param symbol - Trading pair symbol
8964
9115
  * @param strategyName - Strategy name to get data for
9116
+ * @param exchangeName - Exchange name
9117
+ * @param frameName - Frame name
8965
9118
  * @param backtest - True if backtest mode, false if live mode
8966
9119
  * @returns Statistical data object with all metrics
8967
9120
  *
8968
9121
  * @example
8969
9122
  * ```typescript
8970
9123
  * const service = new ScheduleMarkdownService();
8971
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
9124
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
8972
9125
  * console.log(stats.cancellationRate, stats.avgWaitTime);
8973
9126
  * ```
8974
9127
  */
8975
- this.getData = async (symbol, strategyName, backtest) => {
9128
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8976
9129
  this.loggerService.log("scheduleMarkdownService getData", {
8977
9130
  symbol,
8978
9131
  strategyName,
9132
+ exchangeName,
9133
+ frameName,
8979
9134
  backtest,
8980
9135
  });
8981
- const storage = this.getStorage(symbol, strategyName, backtest);
9136
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8982
9137
  return storage.getData();
8983
9138
  };
8984
9139
  /**
@@ -8987,6 +9142,8 @@ class ScheduleMarkdownService {
8987
9142
  *
8988
9143
  * @param symbol - Trading pair symbol
8989
9144
  * @param strategyName - Strategy name to generate report for
9145
+ * @param exchangeName - Exchange name
9146
+ * @param frameName - Frame name
8990
9147
  * @param backtest - True if backtest mode, false if live mode
8991
9148
  * @param columns - Column configuration for formatting the table
8992
9149
  * @returns Markdown formatted report string with table of all events
@@ -8994,17 +9151,19 @@ class ScheduleMarkdownService {
8994
9151
  * @example
8995
9152
  * ```typescript
8996
9153
  * const service = new ScheduleMarkdownService();
8997
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
9154
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
8998
9155
  * console.log(markdown);
8999
9156
  * ```
9000
9157
  */
9001
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
9158
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
9002
9159
  this.loggerService.log("scheduleMarkdownService getReport", {
9003
9160
  symbol,
9004
9161
  strategyName,
9162
+ exchangeName,
9163
+ frameName,
9005
9164
  backtest,
9006
9165
  });
9007
- const storage = this.getStorage(symbol, strategyName, backtest);
9166
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9008
9167
  return storage.getReport(strategyName, columns);
9009
9168
  };
9010
9169
  /**
@@ -9014,6 +9173,8 @@ class ScheduleMarkdownService {
9014
9173
  *
9015
9174
  * @param symbol - Trading pair symbol
9016
9175
  * @param strategyName - Strategy name to save report for
9176
+ * @param exchangeName - Exchange name
9177
+ * @param frameName - Frame name
9017
9178
  * @param backtest - True if backtest mode, false if live mode
9018
9179
  * @param path - Directory path to save report (default: "./dump/schedule")
9019
9180
  * @param columns - Column configuration for formatting the table
@@ -9023,48 +9184,48 @@ class ScheduleMarkdownService {
9023
9184
  * const service = new ScheduleMarkdownService();
9024
9185
  *
9025
9186
  * // Save to default path: ./dump/schedule/my-strategy.md
9026
- * await service.dump("BTCUSDT", "my-strategy", false);
9187
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
9027
9188
  *
9028
9189
  * // Save to custom path: ./custom/path/my-strategy.md
9029
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
9190
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
9030
9191
  * ```
9031
9192
  */
9032
- this.dump = async (symbol, strategyName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
9193
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
9033
9194
  this.loggerService.log("scheduleMarkdownService dump", {
9034
9195
  symbol,
9035
9196
  strategyName,
9197
+ exchangeName,
9198
+ frameName,
9036
9199
  backtest,
9037
9200
  path,
9038
9201
  });
9039
- const storage = this.getStorage(symbol, strategyName, backtest);
9202
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9040
9203
  await storage.dump(strategyName, path, columns);
9041
9204
  };
9042
9205
  /**
9043
9206
  * Clears accumulated event data from storage.
9044
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
9207
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
9045
9208
  * If nothing is provided, clears all data.
9046
9209
  *
9047
- * @param backtest - Backtest mode flag
9048
- * @param ctx - Optional context with symbol and strategyName
9210
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
9049
9211
  *
9050
9212
  * @example
9051
9213
  * ```typescript
9052
9214
  * const service = new ScheduleMarkdownService();
9053
9215
  *
9054
- * // Clear specific symbol-strategy-backtest triple
9055
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
9216
+ * // Clear specific combination
9217
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
9056
9218
  *
9057
9219
  * // Clear all data
9058
9220
  * await service.clear();
9059
9221
  * ```
9060
9222
  */
9061
- this.clear = async (backtest, ctx) => {
9223
+ this.clear = async (payload) => {
9062
9224
  this.loggerService.log("scheduleMarkdownService clear", {
9063
- backtest,
9064
- ctx,
9225
+ payload,
9065
9226
  });
9066
- if (ctx) {
9067
- const key = CREATE_KEY_FN$7(ctx.symbol, ctx.strategyName, backtest);
9227
+ if (payload) {
9228
+ const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
9068
9229
  this.getStorage.clear(key);
9069
9230
  }
9070
9231
  else {
@@ -9091,13 +9252,21 @@ class ScheduleMarkdownService {
9091
9252
 
9092
9253
  /**
9093
9254
  * Creates a unique key for memoizing PerformanceStorage instances.
9094
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
9255
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
9095
9256
  * @param symbol - Trading pair symbol
9096
9257
  * @param strategyName - Name of the strategy
9258
+ * @param exchangeName - Exchange name
9259
+ * @param frameName - Frame name
9097
9260
  * @param backtest - Whether running in backtest mode
9098
9261
  * @returns Unique string key for memoization
9099
9262
  */
9100
- const CREATE_KEY_FN$6 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
9263
+ const CREATE_KEY_FN$6 = (symbol, strategyName, exchangeName, frameName, backtest) => {
9264
+ const parts = [symbol, strategyName, exchangeName];
9265
+ if (frameName)
9266
+ parts.push(frameName);
9267
+ parts.push(backtest ? "backtest" : "live");
9268
+ return parts.join(":");
9269
+ };
9101
9270
  /**
9102
9271
  * Calculates percentile value from sorted array.
9103
9272
  */
@@ -9312,10 +9481,10 @@ class PerformanceMarkdownService {
9312
9481
  /** Logger service for debug output */
9313
9482
  this.loggerService = inject(TYPES.loggerService);
9314
9483
  /**
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.
9484
+ * Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
9485
+ * Each combination gets its own isolated storage instance.
9317
9486
  */
9318
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, backtest), () => new PerformanceStorage());
9487
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, exchangeName, frameName, backtest), () => new PerformanceStorage());
9319
9488
  /**
9320
9489
  * Processes performance events and accumulates metrics.
9321
9490
  * Should be called from performance tracking code.
@@ -9328,7 +9497,8 @@ class PerformanceMarkdownService {
9328
9497
  });
9329
9498
  const symbol = event.symbol || "global";
9330
9499
  const strategyName = event.strategyName || "global";
9331
- const storage = this.getStorage(symbol, strategyName, event.backtest);
9500
+ const exchangeName = event.exchangeName || "global";
9501
+ const storage = this.getStorage(symbol, strategyName, exchangeName, event.frameName, event.backtest);
9332
9502
  storage.addEvent(event);
9333
9503
  };
9334
9504
  /**
@@ -9336,24 +9506,28 @@ class PerformanceMarkdownService {
9336
9506
  *
9337
9507
  * @param symbol - Trading pair symbol
9338
9508
  * @param strategyName - Strategy name to get data for
9509
+ * @param exchangeName - Exchange name
9510
+ * @param frameName - Frame name
9339
9511
  * @param backtest - True if backtest mode, false if live mode
9340
9512
  * @returns Performance statistics with aggregated metrics
9341
9513
  *
9342
9514
  * @example
9343
9515
  * ```typescript
9344
- * const stats = await performanceService.getData("BTCUSDT", "my-strategy", false);
9516
+ * const stats = await performanceService.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
9345
9517
  * console.log("Total time:", stats.totalDuration);
9346
9518
  * console.log("Slowest operation:", Object.values(stats.metricStats)
9347
9519
  * .sort((a, b) => b.avgDuration - a.avgDuration)[0]);
9348
9520
  * ```
9349
9521
  */
9350
- this.getData = async (symbol, strategyName, backtest) => {
9522
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
9351
9523
  this.loggerService.log("performanceMarkdownService getData", {
9352
9524
  symbol,
9353
9525
  strategyName,
9526
+ exchangeName,
9527
+ frameName,
9354
9528
  backtest,
9355
9529
  });
9356
- const storage = this.getStorage(symbol, strategyName, backtest);
9530
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9357
9531
  return storage.getData(strategyName);
9358
9532
  };
9359
9533
  /**
@@ -9361,23 +9535,27 @@ class PerformanceMarkdownService {
9361
9535
  *
9362
9536
  * @param symbol - Trading pair symbol
9363
9537
  * @param strategyName - Strategy name to generate report for
9538
+ * @param exchangeName - Exchange name
9539
+ * @param frameName - Frame name
9364
9540
  * @param backtest - True if backtest mode, false if live mode
9365
9541
  * @param columns - Column configuration for formatting the table
9366
9542
  * @returns Markdown formatted report string
9367
9543
  *
9368
9544
  * @example
9369
9545
  * ```typescript
9370
- * const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", false);
9546
+ * const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
9371
9547
  * console.log(markdown);
9372
9548
  * ```
9373
9549
  */
9374
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
9550
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
9375
9551
  this.loggerService.log("performanceMarkdownService getReport", {
9376
9552
  symbol,
9377
9553
  strategyName,
9554
+ exchangeName,
9555
+ frameName,
9378
9556
  backtest,
9379
9557
  });
9380
- const storage = this.getStorage(symbol, strategyName, backtest);
9558
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9381
9559
  return storage.getReport(strategyName, columns);
9382
9560
  };
9383
9561
  /**
@@ -9385,6 +9563,8 @@ class PerformanceMarkdownService {
9385
9563
  *
9386
9564
  * @param symbol - Trading pair symbol
9387
9565
  * @param strategyName - Strategy name to save report for
9566
+ * @param exchangeName - Exchange name
9567
+ * @param frameName - Frame name
9388
9568
  * @param backtest - True if backtest mode, false if live mode
9389
9569
  * @param path - Directory path to save report
9390
9570
  * @param columns - Column configuration for formatting the table
@@ -9392,35 +9572,35 @@ class PerformanceMarkdownService {
9392
9572
  * @example
9393
9573
  * ```typescript
9394
9574
  * // Save to default path: ./dump/performance/my-strategy.md
9395
- * await performanceService.dump("BTCUSDT", "my-strategy", false);
9575
+ * await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
9396
9576
  *
9397
9577
  * // Save to custom path
9398
- * await performanceService.dump("BTCUSDT", "my-strategy", false, "./custom/path");
9578
+ * await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
9399
9579
  * ```
9400
9580
  */
9401
- this.dump = async (symbol, strategyName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
9581
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
9402
9582
  this.loggerService.log("performanceMarkdownService dump", {
9403
9583
  symbol,
9404
9584
  strategyName,
9585
+ exchangeName,
9586
+ frameName,
9405
9587
  backtest,
9406
9588
  path,
9407
9589
  });
9408
- const storage = this.getStorage(symbol, strategyName, backtest);
9590
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9409
9591
  await storage.dump(strategyName, path, columns);
9410
9592
  };
9411
9593
  /**
9412
9594
  * Clears accumulated performance data from storage.
9413
9595
  *
9414
- * @param backtest - Backtest mode flag
9415
- * @param ctx - Optional context with symbol and strategyName
9596
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
9416
9597
  */
9417
- this.clear = async (backtest, ctx) => {
9598
+ this.clear = async (payload) => {
9418
9599
  this.loggerService.log("performanceMarkdownService clear", {
9419
- backtest,
9420
- ctx,
9600
+ payload,
9421
9601
  });
9422
- if (ctx) {
9423
- const key = CREATE_KEY_FN$6(ctx.symbol, ctx.strategyName, backtest);
9602
+ if (payload) {
9603
+ const key = CREATE_KEY_FN$6(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
9424
9604
  this.getStorage.clear(key);
9425
9605
  }
9426
9606
  else {
@@ -9849,12 +10029,19 @@ class WalkerMarkdownService {
9849
10029
 
9850
10030
  /**
9851
10031
  * Creates a unique key for memoizing HeatmapStorage instances.
9852
- * Key format: "strategyName:backtest" or "strategyName:live"
9853
- * @param strategyName - Name of the strategy
10032
+ * Key format: "exchangeName:frameName:backtest" or "exchangeName:live"
10033
+ * @param exchangeName - Exchange name
10034
+ * @param frameName - Frame name
9854
10035
  * @param backtest - Whether running in backtest mode
9855
10036
  * @returns Unique string key for memoization
9856
10037
  */
9857
- const CREATE_KEY_FN$5 = (strategyName, backtest) => `${strategyName}:${backtest ? "backtest" : "live"}`;
10038
+ const CREATE_KEY_FN$5 = (exchangeName, frameName, backtest) => {
10039
+ const parts = [exchangeName];
10040
+ if (frameName)
10041
+ parts.push(frameName);
10042
+ parts.push(backtest ? "backtest" : "live");
10043
+ return parts.join(":");
10044
+ };
9858
10045
  const HEATMAP_METHOD_NAME_GET_DATA = "HeatMarkdownService.getData";
9859
10046
  const HEATMAP_METHOD_NAME_GET_REPORT = "HeatMarkdownService.getReport";
9860
10047
  const HEATMAP_METHOD_NAME_DUMP = "HeatMarkdownService.dump";
@@ -10195,10 +10382,10 @@ class HeatMarkdownService {
10195
10382
  /** Logger service for debug output */
10196
10383
  this.loggerService = inject(TYPES.loggerService);
10197
10384
  /**
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.
10385
+ * Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
10386
+ * Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
10200
10387
  */
10201
- this.getStorage = functoolsKit.memoize(([strategyName, backtest]) => CREATE_KEY_FN$5(strategyName, backtest), () => new HeatmapStorage());
10388
+ this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$5(exchangeName, frameName, backtest), () => new HeatmapStorage());
10202
10389
  /**
10203
10390
  * Processes tick events and accumulates closed signals.
10204
10391
  * Should be called from signal emitter subscription.
@@ -10214,20 +10401,21 @@ class HeatMarkdownService {
10214
10401
  if (data.action !== "closed") {
10215
10402
  return;
10216
10403
  }
10217
- const storage = this.getStorage(data.strategyName, data.backtest);
10404
+ const storage = this.getStorage(data.exchangeName, data.frameName, data.backtest);
10218
10405
  storage.addSignal(data);
10219
10406
  };
10220
10407
  /**
10221
- * Gets aggregated portfolio heatmap statistics for a strategy.
10408
+ * Gets aggregated portfolio heatmap statistics.
10222
10409
  *
10223
- * @param strategyName - Strategy name to get heatmap data for
10410
+ * @param exchangeName - Exchange name
10411
+ * @param frameName - Frame name
10224
10412
  * @param backtest - True if backtest mode, false if live mode
10225
10413
  * @returns Promise resolving to heatmap statistics with per-symbol and portfolio-wide metrics
10226
10414
  *
10227
10415
  * @example
10228
10416
  * ```typescript
10229
10417
  * const service = new HeatMarkdownService();
10230
- * const stats = await service.getData("my-strategy", true);
10418
+ * const stats = await service.getData("binance", "frame1", true);
10231
10419
  *
10232
10420
  * console.log(`Total symbols: ${stats.totalSymbols}`);
10233
10421
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
@@ -10237,18 +10425,21 @@ class HeatMarkdownService {
10237
10425
  * });
10238
10426
  * ```
10239
10427
  */
10240
- this.getData = async (strategyName, backtest) => {
10428
+ this.getData = async (exchangeName, frameName, backtest) => {
10241
10429
  this.loggerService.log(HEATMAP_METHOD_NAME_GET_DATA, {
10242
- strategyName,
10430
+ exchangeName,
10431
+ frameName,
10243
10432
  backtest,
10244
10433
  });
10245
- const storage = this.getStorage(strategyName, backtest);
10434
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10246
10435
  return storage.getData();
10247
10436
  };
10248
10437
  /**
10249
- * Generates markdown report with portfolio heatmap table for a strategy.
10438
+ * Generates markdown report with portfolio heatmap table.
10250
10439
  *
10251
- * @param strategyName - Strategy name to generate heatmap report for
10440
+ * @param strategyName - Strategy name for report title
10441
+ * @param exchangeName - Exchange name
10442
+ * @param frameName - Frame name
10252
10443
  * @param backtest - True if backtest mode, false if live mode
10253
10444
  * @param columns - Column configuration for formatting the table
10254
10445
  * @returns Promise resolving to markdown formatted report string
@@ -10256,7 +10447,7 @@ class HeatMarkdownService {
10256
10447
  * @example
10257
10448
  * ```typescript
10258
10449
  * const service = new HeatMarkdownService();
10259
- * const markdown = await service.getReport("my-strategy", true);
10450
+ * const markdown = await service.getReport("my-strategy", "binance", "frame1", true);
10260
10451
  * console.log(markdown);
10261
10452
  * // Output:
10262
10453
  * // # Portfolio Heatmap: my-strategy
@@ -10270,21 +10461,25 @@ class HeatMarkdownService {
10270
10461
  * // ...
10271
10462
  * ```
10272
10463
  */
10273
- this.getReport = async (strategyName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
10464
+ this.getReport = async (strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
10274
10465
  this.loggerService.log(HEATMAP_METHOD_NAME_GET_REPORT, {
10275
10466
  strategyName,
10467
+ exchangeName,
10468
+ frameName,
10276
10469
  backtest,
10277
10470
  });
10278
- const storage = this.getStorage(strategyName, backtest);
10471
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10279
10472
  return storage.getReport(strategyName, columns);
10280
10473
  };
10281
10474
  /**
10282
- * Saves heatmap report to disk for a strategy.
10475
+ * Saves heatmap report to disk.
10283
10476
  *
10284
10477
  * Creates directory if it doesn't exist.
10285
10478
  * Default filename: {strategyName}.md
10286
10479
  *
10287
- * @param strategyName - Strategy name to save heatmap report for
10480
+ * @param strategyName - Strategy name for report filename
10481
+ * @param exchangeName - Exchange name
10482
+ * @param frameName - Frame name
10288
10483
  * @param backtest - True if backtest mode, false if live mode
10289
10484
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
10290
10485
  * @param columns - Column configuration for formatting the table
@@ -10294,47 +10489,47 @@ class HeatMarkdownService {
10294
10489
  * const service = new HeatMarkdownService();
10295
10490
  *
10296
10491
  * // Save to default path: ./dump/heatmap/my-strategy.md
10297
- * await service.dump("my-strategy", true);
10492
+ * await service.dump("my-strategy", "binance", "frame1", true);
10298
10493
  *
10299
10494
  * // Save to custom path: ./reports/my-strategy.md
10300
- * await service.dump("my-strategy", true, "./reports");
10495
+ * await service.dump("my-strategy", "binance", "frame1", true, "./reports");
10301
10496
  * ```
10302
10497
  */
10303
- this.dump = async (strategyName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
10498
+ this.dump = async (strategyName, exchangeName, frameName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
10304
10499
  this.loggerService.log(HEATMAP_METHOD_NAME_DUMP, {
10305
10500
  strategyName,
10501
+ exchangeName,
10502
+ frameName,
10306
10503
  backtest,
10307
10504
  path,
10308
10505
  });
10309
- const storage = this.getStorage(strategyName, backtest);
10506
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10310
10507
  await storage.dump(strategyName, path, columns);
10311
10508
  };
10312
10509
  /**
10313
10510
  * 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.
10511
+ * If payload is provided, clears only that exchangeName+frameName+backtest combination's data.
10512
+ * If payload is omitted, clears all data.
10316
10513
  *
10317
- * @param backtest - Backtest mode flag
10318
- * @param ctx - Optional context with strategyName to clear specific data
10514
+ * @param payload - Optional payload with exchangeName, frameName, backtest to clear specific data
10319
10515
  *
10320
10516
  * @example
10321
10517
  * ```typescript
10322
10518
  * const service = new HeatMarkdownService();
10323
10519
  *
10324
- * // Clear specific strategy+backtest data
10325
- * await service.clear(true, { strategyName: "my-strategy" });
10520
+ * // Clear specific exchange+frame+backtest data
10521
+ * await service.clear({ exchangeName: "binance", frameName: "frame1", backtest: true });
10326
10522
  *
10327
10523
  * // Clear all data
10328
10524
  * await service.clear();
10329
10525
  * ```
10330
10526
  */
10331
- this.clear = async (backtest, ctx) => {
10527
+ this.clear = async (payload) => {
10332
10528
  this.loggerService.log(HEATMAP_METHOD_NAME_CLEAR, {
10333
- backtest,
10334
- ctx,
10529
+ payload,
10335
10530
  });
10336
- if (ctx) {
10337
- const key = CREATE_KEY_FN$5(ctx.strategyName, backtest);
10531
+ if (payload) {
10532
+ const key = CREATE_KEY_FN$5(payload.exchangeName, payload.frameName, payload.backtest);
10338
10533
  this.getStorage.clear(key);
10339
10534
  }
10340
10535
  else {
@@ -12192,7 +12387,7 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
12192
12387
  revenuePercent,
12193
12388
  backtest,
12194
12389
  });
12195
- await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
12390
+ await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
12196
12391
  }
12197
12392
  }
12198
12393
  if (shouldPersist) {
@@ -12242,7 +12437,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
12242
12437
  lossPercent,
12243
12438
  backtest,
12244
12439
  });
12245
- await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
12440
+ await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
12246
12441
  }
12247
12442
  }
12248
12443
  if (shouldPersist) {
@@ -12568,10 +12763,11 @@ const CREATE_KEY_FN$4 = (signalId, backtest) => `${signalId}:${backtest ? "backt
12568
12763
  * @param backtest - True if backtest mode
12569
12764
  * @param timestamp - Event timestamp in milliseconds
12570
12765
  */
12571
- const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
12766
+ const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
12572
12767
  symbol,
12573
12768
  strategyName,
12574
12769
  exchangeName,
12770
+ frameName,
12575
12771
  data,
12576
12772
  currentPrice,
12577
12773
  level,
@@ -12593,10 +12789,11 @@ const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, curren
12593
12789
  * @param backtest - True if backtest mode
12594
12790
  * @param timestamp - Event timestamp in milliseconds
12595
12791
  */
12596
- const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
12792
+ const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
12597
12793
  symbol,
12598
12794
  strategyName,
12599
12795
  exchangeName,
12796
+ frameName,
12600
12797
  data,
12601
12798
  currentPrice,
12602
12799
  level,
@@ -12748,11 +12945,21 @@ class PartialConnectionService {
12748
12945
 
12749
12946
  /**
12750
12947
  * 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
12948
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
12949
+ * @param symbol - Trading pair symbol
12950
+ * @param strategyName - Name of the strategy
12951
+ * @param exchangeName - Exchange name
12952
+ * @param frameName - Frame name
12953
+ * @param backtest - Whether running in backtest mode
12753
12954
  * @returns Unique string key for memoization
12754
12955
  */
12755
- const CREATE_KEY_FN$3 = ([symbol, strategyName, backtest]) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
12956
+ const CREATE_KEY_FN$3 = (symbol, strategyName, exchangeName, frameName, backtest) => {
12957
+ const parts = [symbol, strategyName, exchangeName];
12958
+ if (frameName)
12959
+ parts.push(frameName);
12960
+ parts.push(backtest ? "backtest" : "live");
12961
+ return parts.join(":");
12962
+ };
12756
12963
  /** Maximum number of events to store in partial reports */
12757
12964
  const MAX_EVENTS$1 = 250;
12758
12965
  /**
@@ -12924,15 +13131,15 @@ class PartialMarkdownService {
12924
13131
  /** Logger service for debug output */
12925
13132
  this.loggerService = inject(TYPES.loggerService);
12926
13133
  /**
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.
13134
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
13135
+ * Each combination gets its own isolated storage instance.
12929
13136
  */
12930
- this.getStorage = functoolsKit.memoize(CREATE_KEY_FN$3, () => new ReportStorage$1());
13137
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$3(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$1());
12931
13138
  /**
12932
13139
  * Processes profit events and accumulates them.
12933
13140
  * Should be called from partialProfitSubject subscription.
12934
13141
  *
12935
- * @param data - Profit event data
13142
+ * @param data - Profit event data with frameName wrapper
12936
13143
  *
12937
13144
  * @example
12938
13145
  * ```typescript
@@ -12944,14 +13151,14 @@ class PartialMarkdownService {
12944
13151
  this.loggerService.log("partialMarkdownService tickProfit", {
12945
13152
  data,
12946
13153
  });
12947
- const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
13154
+ const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
12948
13155
  storage.addProfitEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
12949
13156
  };
12950
13157
  /**
12951
13158
  * Processes loss events and accumulates them.
12952
13159
  * Should be called from partialLossSubject subscription.
12953
13160
  *
12954
- * @param data - Loss event data
13161
+ * @param data - Loss event data with frameName wrapper
12955
13162
  *
12956
13163
  * @example
12957
13164
  * ```typescript
@@ -12963,7 +13170,7 @@ class PartialMarkdownService {
12963
13170
  this.loggerService.log("partialMarkdownService tickLoss", {
12964
13171
  data,
12965
13172
  });
12966
- const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
13173
+ const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
12967
13174
  storage.addLossEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
12968
13175
  };
12969
13176
  /**
@@ -12972,23 +13179,27 @@ class PartialMarkdownService {
12972
13179
  *
12973
13180
  * @param symbol - Trading pair symbol to get data for
12974
13181
  * @param strategyName - Strategy name to get data for
13182
+ * @param exchangeName - Exchange name
13183
+ * @param frameName - Frame name
12975
13184
  * @param backtest - True if backtest mode, false if live mode
12976
13185
  * @returns Statistical data object with all metrics
12977
13186
  *
12978
13187
  * @example
12979
13188
  * ```typescript
12980
13189
  * const service = new PartialMarkdownService();
12981
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
13190
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
12982
13191
  * console.log(stats.totalProfit, stats.totalLoss);
12983
13192
  * ```
12984
13193
  */
12985
- this.getData = async (symbol, strategyName, backtest) => {
13194
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
12986
13195
  this.loggerService.log("partialMarkdownService getData", {
12987
13196
  symbol,
12988
13197
  strategyName,
13198
+ exchangeName,
13199
+ frameName,
12989
13200
  backtest,
12990
13201
  });
12991
- const storage = this.getStorage(symbol, strategyName, backtest);
13202
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
12992
13203
  return storage.getData();
12993
13204
  };
12994
13205
  /**
@@ -12997,6 +13208,8 @@ class PartialMarkdownService {
12997
13208
  *
12998
13209
  * @param symbol - Trading pair symbol to generate report for
12999
13210
  * @param strategyName - Strategy name to generate report for
13211
+ * @param exchangeName - Exchange name
13212
+ * @param frameName - Frame name
13000
13213
  * @param backtest - True if backtest mode, false if live mode
13001
13214
  * @param columns - Column configuration for formatting the table
13002
13215
  * @returns Markdown formatted report string with table of all events
@@ -13004,17 +13217,19 @@ class PartialMarkdownService {
13004
13217
  * @example
13005
13218
  * ```typescript
13006
13219
  * const service = new PartialMarkdownService();
13007
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
13220
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
13008
13221
  * console.log(markdown);
13009
13222
  * ```
13010
13223
  */
13011
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
13224
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
13012
13225
  this.loggerService.log("partialMarkdownService getReport", {
13013
13226
  symbol,
13014
13227
  strategyName,
13228
+ exchangeName,
13229
+ frameName,
13015
13230
  backtest,
13016
13231
  });
13017
- const storage = this.getStorage(symbol, strategyName, backtest);
13232
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13018
13233
  return storage.getReport(symbol, strategyName, columns);
13019
13234
  };
13020
13235
  /**
@@ -13024,6 +13239,8 @@ class PartialMarkdownService {
13024
13239
  *
13025
13240
  * @param symbol - Trading pair symbol to save report for
13026
13241
  * @param strategyName - Strategy name to save report for
13242
+ * @param exchangeName - Exchange name
13243
+ * @param frameName - Frame name
13027
13244
  * @param backtest - True if backtest mode, false if live mode
13028
13245
  * @param path - Directory path to save report (default: "./dump/partial")
13029
13246
  * @param columns - Column configuration for formatting the table
@@ -13033,48 +13250,48 @@ class PartialMarkdownService {
13033
13250
  * const service = new PartialMarkdownService();
13034
13251
  *
13035
13252
  * // Save to default path: ./dump/partial/BTCUSDT_my-strategy.md
13036
- * await service.dump("BTCUSDT", "my-strategy", false);
13253
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
13037
13254
  *
13038
13255
  * // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
13039
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
13256
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
13040
13257
  * ```
13041
13258
  */
13042
- this.dump = async (symbol, strategyName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
13259
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
13043
13260
  this.loggerService.log("partialMarkdownService dump", {
13044
13261
  symbol,
13045
13262
  strategyName,
13263
+ exchangeName,
13264
+ frameName,
13046
13265
  backtest,
13047
13266
  path,
13048
13267
  });
13049
- const storage = this.getStorage(symbol, strategyName, backtest);
13268
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13050
13269
  await storage.dump(symbol, strategyName, path, columns);
13051
13270
  };
13052
13271
  /**
13053
13272
  * Clears accumulated event data from storage.
13054
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
13273
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
13055
13274
  * If nothing is provided, clears all data.
13056
13275
  *
13057
- * @param backtest - Backtest mode flag
13058
- * @param ctx - Optional context with symbol and strategyName
13276
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
13059
13277
  *
13060
13278
  * @example
13061
13279
  * ```typescript
13062
13280
  * const service = new PartialMarkdownService();
13063
13281
  *
13064
- * // Clear specific symbol-strategy-backtest triple
13065
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
13282
+ * // Clear specific combination
13283
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
13066
13284
  *
13067
13285
  * // Clear all data
13068
13286
  * await service.clear();
13069
13287
  * ```
13070
13288
  */
13071
- this.clear = async (backtest, ctx) => {
13289
+ this.clear = async (payload) => {
13072
13290
  this.loggerService.log("partialMarkdownService clear", {
13073
- backtest,
13074
- ctx,
13291
+ payload,
13075
13292
  });
13076
- if (ctx) {
13077
- const key = CREATE_KEY_FN$3([ctx.symbol, ctx.strategyName, backtest]);
13293
+ if (payload) {
13294
+ const key = CREATE_KEY_FN$3(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
13078
13295
  this.getStorage.clear(key);
13079
13296
  }
13080
13297
  else {
@@ -13155,18 +13372,18 @@ class PartialGlobalService {
13155
13372
  this.riskValidationService = inject(TYPES.riskValidationService);
13156
13373
  /**
13157
13374
  * Validates strategy and associated risk configuration.
13158
- * Memoized to avoid redundant validations for the same strategy.
13375
+ * Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
13159
13376
  *
13160
- * @param strategyName - Name of the strategy to validate
13377
+ * @param context - Context with strategyName, exchangeName and frameName
13161
13378
  * @param methodName - Name of the calling method for error tracking
13162
13379
  */
13163
- this.validate = functoolsKit.memoize(([strategyName]) => `${strategyName}`, (strategyName, methodName) => {
13380
+ this.validate = functoolsKit.memoize(([context]) => `${context.strategyName}:${context.exchangeName}:${context.frameName}`, (context, methodName) => {
13164
13381
  this.loggerService.log("partialGlobalService validate", {
13165
- strategyName,
13382
+ context,
13166
13383
  methodName,
13167
13384
  });
13168
- this.strategyValidationService.validate(strategyName, methodName);
13169
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
13385
+ this.strategyValidationService.validate(context.strategyName, methodName);
13386
+ const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
13170
13387
  riskName && this.riskValidationService.validate(riskName, methodName);
13171
13388
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
13172
13389
  });
@@ -13192,7 +13409,11 @@ class PartialGlobalService {
13192
13409
  backtest,
13193
13410
  when,
13194
13411
  });
13195
- this.validate(data.strategyName, "partialGlobalService profit");
13412
+ this.validate({
13413
+ strategyName: data.strategyName,
13414
+ exchangeName: data.exchangeName,
13415
+ frameName: data.frameName
13416
+ }, "partialGlobalService profit");
13196
13417
  return await this.partialConnectionService.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
13197
13418
  };
13198
13419
  /**
@@ -13217,7 +13438,11 @@ class PartialGlobalService {
13217
13438
  backtest,
13218
13439
  when,
13219
13440
  });
13220
- this.validate(data.strategyName, "partialGlobalService loss");
13441
+ this.validate({
13442
+ strategyName: data.strategyName,
13443
+ exchangeName: data.exchangeName,
13444
+ frameName: data.frameName
13445
+ }, "partialGlobalService loss");
13221
13446
  return await this.partialConnectionService.loss(symbol, data, currentPrice, lossPercent, backtest, when);
13222
13447
  };
13223
13448
  /**
@@ -13237,7 +13462,11 @@ class PartialGlobalService {
13237
13462
  priceClose,
13238
13463
  backtest,
13239
13464
  });
13240
- this.validate(data.strategyName, "partialGlobalService clear");
13465
+ this.validate({
13466
+ strategyName: data.strategyName,
13467
+ exchangeName: data.exchangeName,
13468
+ frameName: data.frameName
13469
+ }, "partialGlobalService clear");
13241
13470
  return await this.partialConnectionService.clear(symbol, data, priceClose, backtest);
13242
13471
  };
13243
13472
  }
@@ -13247,7 +13476,7 @@ class PartialGlobalService {
13247
13476
  * Warning threshold for message size in kilobytes.
13248
13477
  * Messages exceeding this size trigger console warnings.
13249
13478
  */
13250
- const WARN_KB = 20;
13479
+ const WARN_KB = 30;
13251
13480
  /**
13252
13481
  * Internal function for dumping signal data to markdown files.
13253
13482
  * Creates a directory structure with system prompts, user messages, and LLM output.
@@ -13511,13 +13740,21 @@ class ConfigValidationService {
13511
13740
 
13512
13741
  /**
13513
13742
  * Creates a unique key for memoizing ReportStorage instances.
13514
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
13743
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
13515
13744
  * @param symbol - Trading pair symbol
13516
13745
  * @param strategyName - Name of the strategy
13746
+ * @param exchangeName - Exchange name
13747
+ * @param frameName - Frame name
13517
13748
  * @param backtest - Whether running in backtest mode
13518
13749
  * @returns Unique string key for memoization
13519
13750
  */
13520
- const CREATE_KEY_FN$2 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
13751
+ const CREATE_KEY_FN$2 = (symbol, strategyName, exchangeName, frameName, backtest) => {
13752
+ const parts = [symbol, strategyName, exchangeName];
13753
+ if (frameName)
13754
+ parts.push(frameName);
13755
+ parts.push(backtest ? "backtest" : "live");
13756
+ return parts.join(":");
13757
+ };
13521
13758
  /** Maximum number of events to store in risk reports */
13522
13759
  const MAX_EVENTS = 250;
13523
13760
  /**
@@ -13659,15 +13896,15 @@ class RiskMarkdownService {
13659
13896
  /** Logger service for debug output */
13660
13897
  this.loggerService = inject(TYPES.loggerService);
13661
13898
  /**
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.
13899
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
13900
+ * Each combination gets its own isolated storage instance.
13664
13901
  */
13665
- this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, backtest), () => new ReportStorage());
13902
+ this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage());
13666
13903
  /**
13667
13904
  * Processes risk rejection events and accumulates them.
13668
13905
  * Should be called from riskSubject subscription.
13669
13906
  *
13670
- * @param data - Risk rejection event data
13907
+ * @param data - Risk rejection event data with frameName wrapper
13671
13908
  *
13672
13909
  * @example
13673
13910
  * ```typescript
@@ -13679,7 +13916,7 @@ class RiskMarkdownService {
13679
13916
  this.loggerService.log("riskMarkdownService tickRejection", {
13680
13917
  data,
13681
13918
  });
13682
- const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
13919
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
13683
13920
  storage.addRejectionEvent(data);
13684
13921
  };
13685
13922
  /**
@@ -13688,23 +13925,27 @@ class RiskMarkdownService {
13688
13925
  *
13689
13926
  * @param symbol - Trading pair symbol to get data for
13690
13927
  * @param strategyName - Strategy name to get data for
13928
+ * @param exchangeName - Exchange name
13929
+ * @param frameName - Frame name
13691
13930
  * @param backtest - True if backtest mode, false if live mode
13692
13931
  * @returns Statistical data object with all metrics
13693
13932
  *
13694
13933
  * @example
13695
13934
  * ```typescript
13696
13935
  * const service = new RiskMarkdownService();
13697
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
13936
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
13698
13937
  * console.log(stats.totalRejections, stats.bySymbol);
13699
13938
  * ```
13700
13939
  */
13701
- this.getData = async (symbol, strategyName, backtest) => {
13940
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
13702
13941
  this.loggerService.log("riskMarkdownService getData", {
13703
13942
  symbol,
13704
13943
  strategyName,
13944
+ exchangeName,
13945
+ frameName,
13705
13946
  backtest,
13706
13947
  });
13707
- const storage = this.getStorage(symbol, strategyName, backtest);
13948
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13708
13949
  return storage.getData();
13709
13950
  };
13710
13951
  /**
@@ -13713,6 +13954,8 @@ class RiskMarkdownService {
13713
13954
  *
13714
13955
  * @param symbol - Trading pair symbol to generate report for
13715
13956
  * @param strategyName - Strategy name to generate report for
13957
+ * @param exchangeName - Exchange name
13958
+ * @param frameName - Frame name
13716
13959
  * @param backtest - True if backtest mode, false if live mode
13717
13960
  * @param columns - Column configuration for formatting the table
13718
13961
  * @returns Markdown formatted report string with table of all events
@@ -13720,17 +13963,19 @@ class RiskMarkdownService {
13720
13963
  * @example
13721
13964
  * ```typescript
13722
13965
  * const service = new RiskMarkdownService();
13723
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
13966
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
13724
13967
  * console.log(markdown);
13725
13968
  * ```
13726
13969
  */
13727
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
13970
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
13728
13971
  this.loggerService.log("riskMarkdownService getReport", {
13729
13972
  symbol,
13730
13973
  strategyName,
13974
+ exchangeName,
13975
+ frameName,
13731
13976
  backtest,
13732
13977
  });
13733
- const storage = this.getStorage(symbol, strategyName, backtest);
13978
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13734
13979
  return storage.getReport(symbol, strategyName, columns);
13735
13980
  };
13736
13981
  /**
@@ -13740,6 +13985,8 @@ class RiskMarkdownService {
13740
13985
  *
13741
13986
  * @param symbol - Trading pair symbol to save report for
13742
13987
  * @param strategyName - Strategy name to save report for
13988
+ * @param exchangeName - Exchange name
13989
+ * @param frameName - Frame name
13743
13990
  * @param backtest - True if backtest mode, false if live mode
13744
13991
  * @param path - Directory path to save report (default: "./dump/risk")
13745
13992
  * @param columns - Column configuration for formatting the table
@@ -13749,48 +13996,48 @@ class RiskMarkdownService {
13749
13996
  * const service = new RiskMarkdownService();
13750
13997
  *
13751
13998
  * // Save to default path: ./dump/risk/BTCUSDT_my-strategy.md
13752
- * await service.dump("BTCUSDT", "my-strategy", false);
13999
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
13753
14000
  *
13754
14001
  * // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
13755
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
14002
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
13756
14003
  * ```
13757
14004
  */
13758
- this.dump = async (symbol, strategyName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
14005
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
13759
14006
  this.loggerService.log("riskMarkdownService dump", {
13760
14007
  symbol,
13761
14008
  strategyName,
14009
+ exchangeName,
14010
+ frameName,
13762
14011
  backtest,
13763
14012
  path,
13764
14013
  });
13765
- const storage = this.getStorage(symbol, strategyName, backtest);
14014
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13766
14015
  await storage.dump(symbol, strategyName, path, columns);
13767
14016
  };
13768
14017
  /**
13769
14018
  * Clears accumulated event data from storage.
13770
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
14019
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
13771
14020
  * If nothing is provided, clears all data.
13772
14021
  *
13773
- * @param backtest - Backtest mode flag
13774
- * @param ctx - Optional context with symbol and strategyName
14022
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
13775
14023
  *
13776
14024
  * @example
13777
14025
  * ```typescript
13778
14026
  * const service = new RiskMarkdownService();
13779
14027
  *
13780
- * // Clear specific symbol-strategy-backtest triple
13781
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
14028
+ * // Clear specific combination
14029
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
13782
14030
  *
13783
14031
  * // Clear all data
13784
14032
  * await service.clear();
13785
14033
  * ```
13786
14034
  */
13787
- this.clear = async (backtest, ctx) => {
14035
+ this.clear = async (payload) => {
13788
14036
  this.loggerService.log("riskMarkdownService clear", {
13789
- backtest,
13790
- ctx,
14037
+ payload,
13791
14038
  });
13792
- if (ctx) {
13793
- const key = CREATE_KEY_FN$2(ctx.symbol, ctx.strategyName, backtest);
14039
+ if (payload) {
14040
+ const key = CREATE_KEY_FN$2(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
13794
14041
  this.getStorage.clear(key);
13795
14042
  }
13796
14043
  else {
@@ -14300,10 +14547,9 @@ const CANCEL_METHOD_NAME = "strategy.cancel";
14300
14547
  * await stop("BTCUSDT", "my-strategy");
14301
14548
  * ```
14302
14549
  */
14303
- async function stop(symbol, strategyName) {
14550
+ async function stop(symbol) {
14304
14551
  backtest$1.loggerService.info(STOP_METHOD_NAME, {
14305
14552
  symbol,
14306
- strategyName,
14307
14553
  });
14308
14554
  if (!ExecutionContextService.hasContext()) {
14309
14555
  throw new Error("stop requires an execution context");
@@ -14312,7 +14558,12 @@ async function stop(symbol, strategyName) {
14312
14558
  throw new Error("stop requires a method context");
14313
14559
  }
14314
14560
  const { backtest: isBacktest } = backtest$1.executionContextService.context;
14315
- await backtest$1.strategyCoreService.stop(isBacktest, { symbol, strategyName });
14561
+ const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
14562
+ await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
14563
+ exchangeName,
14564
+ frameName,
14565
+ strategyName,
14566
+ });
14316
14567
  }
14317
14568
  /**
14318
14569
  * Cancels the scheduled signal without stopping the strategy.
@@ -14336,10 +14587,9 @@ async function stop(symbol, strategyName) {
14336
14587
  * await cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
14337
14588
  * ```
14338
14589
  */
14339
- async function cancel(symbol, strategyName, cancelId) {
14590
+ async function cancel(symbol, cancelId) {
14340
14591
  backtest$1.loggerService.info(CANCEL_METHOD_NAME, {
14341
14592
  symbol,
14342
- strategyName,
14343
14593
  cancelId,
14344
14594
  });
14345
14595
  if (!ExecutionContextService.hasContext()) {
@@ -14349,7 +14599,8 @@ async function cancel(symbol, strategyName, cancelId) {
14349
14599
  throw new Error("cancel requires a method context");
14350
14600
  }
14351
14601
  const { backtest: isBacktest } = backtest$1.executionContextService.context;
14352
- await backtest$1.strategyCoreService.cancel(isBacktest, { symbol, strategyName }, cancelId);
14602
+ const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
14603
+ await backtest$1.strategyCoreService.cancel(isBacktest, symbol, { exchangeName, frameName, strategyName }, cancelId);
14353
14604
  }
14354
14605
 
14355
14606
  /**
@@ -16496,42 +16747,73 @@ class BacktestInstance {
16496
16747
  context,
16497
16748
  });
16498
16749
  {
16499
- backtest$1.backtestMarkdownService.clear(true, {
16750
+ backtest$1.backtestMarkdownService.clear({
16500
16751
  symbol,
16501
16752
  strategyName: context.strategyName,
16753
+ exchangeName: context.exchangeName,
16754
+ frameName: context.frameName,
16755
+ backtest: true,
16502
16756
  });
16503
- backtest$1.liveMarkdownService.clear(true, {
16757
+ backtest$1.liveMarkdownService.clear({
16504
16758
  symbol,
16505
16759
  strategyName: context.strategyName,
16760
+ exchangeName: context.exchangeName,
16761
+ frameName: context.frameName,
16762
+ backtest: true,
16506
16763
  });
16507
- backtest$1.scheduleMarkdownService.clear(true, {
16764
+ backtest$1.scheduleMarkdownService.clear({
16508
16765
  symbol,
16509
16766
  strategyName: context.strategyName,
16767
+ exchangeName: context.exchangeName,
16768
+ frameName: context.frameName,
16769
+ backtest: true,
16510
16770
  });
16511
- backtest$1.performanceMarkdownService.clear(true, {
16771
+ backtest$1.performanceMarkdownService.clear({
16512
16772
  symbol,
16513
16773
  strategyName: context.strategyName,
16774
+ exchangeName: context.exchangeName,
16775
+ frameName: context.frameName,
16776
+ backtest: true,
16514
16777
  });
16515
- backtest$1.partialMarkdownService.clear(true, {
16778
+ backtest$1.partialMarkdownService.clear({
16516
16779
  symbol,
16517
16780
  strategyName: context.strategyName,
16781
+ exchangeName: context.exchangeName,
16782
+ frameName: context.frameName,
16783
+ backtest: true,
16518
16784
  });
16519
- backtest$1.riskMarkdownService.clear(true, {
16785
+ backtest$1.riskMarkdownService.clear({
16520
16786
  symbol,
16521
16787
  strategyName: context.strategyName,
16788
+ exchangeName: context.exchangeName,
16789
+ frameName: context.frameName,
16790
+ backtest: true,
16522
16791
  });
16523
16792
  }
16524
16793
  {
16525
- backtest$1.strategyCoreService.clear(true, {
16794
+ backtest$1.strategyCoreService.clear({
16526
16795
  symbol,
16527
16796
  strategyName: context.strategyName,
16797
+ exchangeName: context.exchangeName,
16798
+ frameName: context.frameName,
16799
+ backtest: true,
16528
16800
  });
16529
16801
  }
16530
16802
  {
16531
16803
  const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16532
- riskName && backtest$1.riskGlobalService.clear(true, { riskName });
16804
+ riskName && backtest$1.riskGlobalService.clear({
16805
+ riskName,
16806
+ exchangeName: context.exchangeName,
16807
+ frameName: context.frameName,
16808
+ backtest: true,
16809
+ });
16533
16810
  riskList &&
16534
- riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, { riskName }));
16811
+ riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
16812
+ riskName,
16813
+ exchangeName: context.exchangeName,
16814
+ frameName: context.frameName,
16815
+ backtest: true,
16816
+ }));
16535
16817
  }
16536
16818
  return backtest$1.backtestCommandService.run(symbol, context);
16537
16819
  };
@@ -16571,12 +16853,17 @@ class BacktestInstance {
16571
16853
  }
16572
16854
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
16573
16855
  return () => {
16574
- backtest$1.strategyCoreService.stop(true, {
16575
- symbol,
16856
+ backtest$1.strategyCoreService.stop(true, symbol, {
16576
16857
  strategyName: context.strategyName,
16858
+ exchangeName: context.exchangeName,
16859
+ frameName: context.frameName,
16577
16860
  });
16578
16861
  backtest$1.strategyCoreService
16579
- .getPendingSignal(true, symbol, context.strategyName)
16862
+ .getPendingSignal(true, symbol, {
16863
+ strategyName: context.strategyName,
16864
+ exchangeName: context.exchangeName,
16865
+ frameName: context.frameName,
16866
+ })
16580
16867
  .then(async (pendingSignal) => {
16581
16868
  if (pendingSignal) {
16582
16869
  return;
@@ -16696,16 +16983,16 @@ class BacktestUtils {
16696
16983
  * }
16697
16984
  * ```
16698
16985
  */
16699
- this.getPendingSignal = async (symbol, strategyName) => {
16700
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16986
+ this.getPendingSignal = async (symbol, context) => {
16987
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16701
16988
  {
16702
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
16989
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16703
16990
  riskName &&
16704
16991
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16705
16992
  riskList &&
16706
16993
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL));
16707
16994
  }
16708
- return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, strategyName);
16995
+ return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, context);
16709
16996
  };
16710
16997
  /**
16711
16998
  * Retrieves the currently active scheduled signal for the strategy.
@@ -16723,16 +17010,16 @@ class BacktestUtils {
16723
17010
  * }
16724
17011
  * ```
16725
17012
  */
16726
- this.getScheduledSignal = async (symbol, strategyName) => {
16727
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17013
+ this.getScheduledSignal = async (symbol, context) => {
17014
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16728
17015
  {
16729
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17016
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16730
17017
  riskName &&
16731
17018
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16732
17019
  riskList &&
16733
17020
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL));
16734
17021
  }
16735
- return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, strategyName);
17022
+ return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, context);
16736
17023
  };
16737
17024
  /**
16738
17025
  * Stops the strategy from generating new signals.
@@ -16743,24 +17030,29 @@ class BacktestUtils {
16743
17030
  *
16744
17031
  * @param symbol - Trading pair symbol
16745
17032
  * @param strategyName - Strategy name to stop
17033
+ * @param context - Execution context with exchangeName and frameName
16746
17034
  * @returns Promise that resolves when stop flag is set
16747
17035
  *
16748
17036
  * @example
16749
17037
  * ```typescript
16750
17038
  * // Stop strategy after some condition
16751
- * await Backtest.stop("BTCUSDT", "my-strategy");
17039
+ * await Backtest.stop("BTCUSDT", "my-strategy", {
17040
+ * exchangeName: "binance",
17041
+ * frameName: "frame1",
17042
+ * strategyName: "my-strategy"
17043
+ * });
16752
17044
  * ```
16753
17045
  */
16754
- this.stop = async (symbol, strategyName) => {
16755
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_STOP);
17046
+ this.stop = async (symbol, context) => {
17047
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_STOP);
16756
17048
  {
16757
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17049
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16758
17050
  riskName &&
16759
17051
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP);
16760
17052
  riskList &&
16761
17053
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP));
16762
17054
  }
16763
- await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
17055
+ await backtest$1.strategyCoreService.stop(true, symbol, context);
16764
17056
  };
16765
17057
  /**
16766
17058
  * Cancels the scheduled signal without stopping the strategy.
@@ -16771,102 +17063,126 @@ class BacktestUtils {
16771
17063
  *
16772
17064
  * @param symbol - Trading pair symbol
16773
17065
  * @param strategyName - Strategy name
17066
+ * @param context - Execution context with exchangeName and frameName
16774
17067
  * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
16775
17068
  * @returns Promise that resolves when scheduled signal is cancelled
16776
17069
  *
16777
17070
  * @example
16778
17071
  * ```typescript
16779
17072
  * // Cancel scheduled signal with custom ID
16780
- * await Backtest.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17073
+ * await Backtest.cancel("BTCUSDT", "my-strategy", {
17074
+ * exchangeName: "binance",
17075
+ * frameName: "frame1",
17076
+ * strategyName: "my-strategy"
17077
+ * }, "manual-cancel-001");
16781
17078
  * ```
16782
17079
  */
16783
- this.cancel = async (symbol, strategyName, cancelId) => {
16784
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_CANCEL);
17080
+ this.cancel = async (symbol, context, cancelId) => {
17081
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_CANCEL);
16785
17082
  {
16786
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17083
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16787
17084
  riskName &&
16788
17085
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL);
16789
17086
  riskList &&
16790
17087
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL));
16791
17088
  }
16792
- await backtest$1.strategyCoreService.cancel(true, { symbol, strategyName }, cancelId);
17089
+ await backtest$1.strategyCoreService.cancel(true, symbol, context, cancelId);
16793
17090
  };
16794
17091
  /**
16795
17092
  * Gets statistical data from all closed signals for a symbol-strategy pair.
16796
17093
  *
16797
17094
  * @param symbol - Trading pair symbol
16798
17095
  * @param strategyName - Strategy name to get data for
17096
+ * @param context - Execution context with exchangeName and frameName
16799
17097
  * @returns Promise resolving to statistical data object
16800
17098
  *
16801
17099
  * @example
16802
17100
  * ```typescript
16803
- * const stats = await Backtest.getData("BTCUSDT", "my-strategy");
17101
+ * const stats = await Backtest.getData("BTCUSDT", "my-strategy", {
17102
+ * exchangeName: "binance",
17103
+ * frameName: "frame1",
17104
+ * strategyName: "my-strategy"
17105
+ * });
16804
17106
  * console.log(stats.sharpeRatio, stats.winRate);
16805
17107
  * ```
16806
17108
  */
16807
- this.getData = async (symbol, strategyName) => {
16808
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_DATA);
17109
+ this.getData = async (symbol, context) => {
17110
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_DATA);
16809
17111
  {
16810
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17112
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16811
17113
  riskName &&
16812
17114
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA);
16813
17115
  riskList &&
16814
17116
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA));
16815
17117
  }
16816
- return await backtest$1.backtestMarkdownService.getData(symbol, strategyName, true);
17118
+ return await backtest$1.backtestMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, true);
16817
17119
  };
16818
17120
  /**
16819
17121
  * Generates markdown report with all closed signals for a symbol-strategy pair.
16820
17122
  *
16821
17123
  * @param symbol - Trading pair symbol
16822
17124
  * @param strategyName - Strategy name to generate report for
17125
+ * @param context - Execution context with exchangeName and frameName
16823
17126
  * @param columns - Optional columns configuration for the report
16824
17127
  * @returns Promise resolving to markdown formatted report string
16825
17128
  *
16826
17129
  * @example
16827
17130
  * ```typescript
16828
- * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy");
17131
+ * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy", {
17132
+ * exchangeName: "binance",
17133
+ * frameName: "frame1",
17134
+ * strategyName: "my-strategy"
17135
+ * });
16829
17136
  * console.log(markdown);
16830
17137
  * ```
16831
17138
  */
16832
- this.getReport = async (symbol, strategyName, columns) => {
16833
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
17139
+ this.getReport = async (symbol, context, columns) => {
17140
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
16834
17141
  {
16835
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17142
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16836
17143
  riskName &&
16837
17144
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT);
16838
17145
  riskList &&
16839
17146
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT));
16840
17147
  }
16841
- return await backtest$1.backtestMarkdownService.getReport(symbol, strategyName, true, columns);
17148
+ return await backtest$1.backtestMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, true, columns);
16842
17149
  };
16843
17150
  /**
16844
17151
  * Saves strategy report to disk.
16845
17152
  *
16846
17153
  * @param symbol - Trading pair symbol
16847
17154
  * @param strategyName - Strategy name to save report for
17155
+ * @param context - Execution context with exchangeName and frameName
16848
17156
  * @param path - Optional directory path to save report (default: "./dump/backtest")
16849
17157
  * @param columns - Optional columns configuration for the report
16850
17158
  *
16851
17159
  * @example
16852
17160
  * ```typescript
16853
17161
  * // Save to default path: ./dump/backtest/my-strategy.md
16854
- * await Backtest.dump("BTCUSDT", "my-strategy");
17162
+ * await Backtest.dump("BTCUSDT", "my-strategy", {
17163
+ * exchangeName: "binance",
17164
+ * frameName: "frame1",
17165
+ * strategyName: "my-strategy"
17166
+ * });
16855
17167
  *
16856
17168
  * // Save to custom path: ./custom/path/my-strategy.md
16857
- * await Backtest.dump("BTCUSDT", "my-strategy", "./custom/path");
17169
+ * await Backtest.dump("BTCUSDT", "my-strategy", {
17170
+ * exchangeName: "binance",
17171
+ * frameName: "frame1",
17172
+ * strategyName: "my-strategy"
17173
+ * }, "./custom/path");
16858
17174
  * ```
16859
17175
  */
16860
- this.dump = async (symbol, strategyName, path, columns) => {
16861
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_DUMP);
17176
+ this.dump = async (symbol, context, path, columns) => {
17177
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_DUMP);
16862
17178
  {
16863
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17179
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16864
17180
  riskName &&
16865
17181
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP);
16866
17182
  riskList &&
16867
17183
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP));
16868
17184
  }
16869
- await backtest$1.backtestMarkdownService.dump(symbol, strategyName, true, path, columns);
17185
+ await backtest$1.backtestMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, true, path, columns);
16870
17186
  };
16871
17187
  /**
16872
17188
  * Lists all active backtest instances with their current status.
@@ -17041,20 +17357,36 @@ class LiveInstance {
17041
17357
  context,
17042
17358
  });
17043
17359
  {
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 });
17360
+ backtest$1.backtestMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17361
+ backtest$1.liveMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17362
+ backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17363
+ backtest$1.performanceMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17364
+ backtest$1.partialMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17365
+ backtest$1.riskMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17050
17366
  }
17051
17367
  {
17052
- backtest$1.strategyCoreService.clear(false, { symbol, strategyName: context.strategyName });
17368
+ backtest$1.strategyCoreService.clear({
17369
+ symbol,
17370
+ strategyName: context.strategyName,
17371
+ exchangeName: context.exchangeName,
17372
+ frameName: "",
17373
+ backtest: false,
17374
+ });
17053
17375
  }
17054
17376
  {
17055
17377
  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 }));
17378
+ riskName && backtest$1.riskGlobalService.clear({
17379
+ riskName,
17380
+ exchangeName: context.exchangeName,
17381
+ frameName: "",
17382
+ backtest: false
17383
+ });
17384
+ riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
17385
+ riskName,
17386
+ exchangeName: context.exchangeName,
17387
+ frameName: "",
17388
+ backtest: false
17389
+ }));
17058
17390
  }
17059
17391
  return backtest$1.liveCommandService.run(symbol, context);
17060
17392
  };
@@ -17094,9 +17426,17 @@ class LiveInstance {
17094
17426
  }
17095
17427
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
17096
17428
  return () => {
17097
- backtest$1.strategyCoreService.stop(false, { symbol, strategyName: context.strategyName });
17429
+ backtest$1.strategyCoreService.stop(false, symbol, {
17430
+ strategyName: context.strategyName,
17431
+ exchangeName: context.exchangeName,
17432
+ frameName: ""
17433
+ });
17098
17434
  backtest$1.strategyCoreService
17099
- .getPendingSignal(false, symbol, context.strategyName)
17435
+ .getPendingSignal(false, symbol, {
17436
+ strategyName: context.strategyName,
17437
+ exchangeName: context.exchangeName,
17438
+ frameName: "",
17439
+ })
17100
17440
  .then(async (pendingSignal) => {
17101
17441
  if (pendingSignal) {
17102
17442
  return;
@@ -17223,14 +17563,18 @@ class LiveUtils {
17223
17563
  * }
17224
17564
  * ```
17225
17565
  */
17226
- this.getPendingSignal = async (symbol, strategyName) => {
17227
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17566
+ this.getPendingSignal = async (symbol, context) => {
17567
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17228
17568
  {
17229
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17569
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17230
17570
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17231
17571
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL));
17232
17572
  }
17233
- return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, strategyName);
17573
+ return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, {
17574
+ strategyName: context.strategyName,
17575
+ exchangeName: context.exchangeName,
17576
+ frameName: "",
17577
+ });
17234
17578
  };
17235
17579
  /**
17236
17580
  * Retrieves the currently active scheduled signal for the strategy.
@@ -17248,14 +17592,18 @@ class LiveUtils {
17248
17592
  * }
17249
17593
  * ```
17250
17594
  */
17251
- this.getScheduledSignal = async (symbol, strategyName) => {
17252
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17595
+ this.getScheduledSignal = async (symbol, context) => {
17596
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17253
17597
  {
17254
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17598
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17255
17599
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17256
17600
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL));
17257
17601
  }
17258
- return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, strategyName);
17602
+ return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, {
17603
+ strategyName: context.strategyName,
17604
+ exchangeName: context.exchangeName,
17605
+ frameName: "",
17606
+ });
17259
17607
  };
17260
17608
  /**
17261
17609
  * Stops the strategy from generating new signals.
@@ -17274,14 +17622,18 @@ class LiveUtils {
17274
17622
  * await Live.stop("BTCUSDT", "my-strategy");
17275
17623
  * ```
17276
17624
  */
17277
- this.stop = async (symbol, strategyName) => {
17278
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_STOP);
17625
+ this.stop = async (symbol, context) => {
17626
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_STOP);
17279
17627
  {
17280
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17628
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17281
17629
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP);
17282
17630
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP));
17283
17631
  }
17284
- await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
17632
+ await backtest$1.strategyCoreService.stop(false, symbol, {
17633
+ strategyName: context.strategyName,
17634
+ exchangeName: context.exchangeName,
17635
+ frameName: "",
17636
+ });
17285
17637
  };
17286
17638
  /**
17287
17639
  * Cancels the scheduled signal without stopping the strategy.
@@ -17292,94 +17644,122 @@ class LiveUtils {
17292
17644
  *
17293
17645
  * @param symbol - Trading pair symbol
17294
17646
  * @param strategyName - Strategy name
17647
+ * @param context - Execution context with exchangeName and frameName
17295
17648
  * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
17296
17649
  * @returns Promise that resolves when scheduled signal is cancelled
17297
17650
  *
17298
17651
  * @example
17299
17652
  * ```typescript
17300
17653
  * // Cancel scheduled signal in live trading with custom ID
17301
- * await Live.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17654
+ * await Live.cancel("BTCUSDT", "my-strategy", {
17655
+ * exchangeName: "binance",
17656
+ * frameName: "",
17657
+ * strategyName: "my-strategy"
17658
+ * }, "manual-cancel-001");
17302
17659
  * ```
17303
17660
  */
17304
- this.cancel = async (symbol, strategyName, cancelId) => {
17305
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_CANCEL);
17661
+ this.cancel = async (symbol, context, cancelId) => {
17662
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_CANCEL);
17306
17663
  {
17307
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17664
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17308
17665
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL);
17309
17666
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL));
17310
17667
  }
17311
- await backtest$1.strategyCoreService.cancel(false, { symbol, strategyName }, cancelId);
17668
+ await backtest$1.strategyCoreService.cancel(false, symbol, {
17669
+ strategyName: context.strategyName,
17670
+ exchangeName: context.exchangeName,
17671
+ frameName: "",
17672
+ }, cancelId);
17312
17673
  };
17313
17674
  /**
17314
17675
  * Gets statistical data from all live trading events for a symbol-strategy pair.
17315
17676
  *
17316
17677
  * @param symbol - Trading pair symbol
17317
17678
  * @param strategyName - Strategy name to get data for
17679
+ * @param context - Execution context with exchangeName and frameName
17318
17680
  * @returns Promise resolving to statistical data object
17319
17681
  *
17320
17682
  * @example
17321
17683
  * ```typescript
17322
- * const stats = await Live.getData("BTCUSDT", "my-strategy");
17684
+ * const stats = await Live.getData("BTCUSDT", "my-strategy", {
17685
+ * exchangeName: "binance",
17686
+ * frameName: "",
17687
+ * strategyName: "my-strategy"
17688
+ * });
17323
17689
  * console.log(stats.sharpeRatio, stats.winRate);
17324
17690
  * ```
17325
17691
  */
17326
- this.getData = async (symbol, strategyName) => {
17327
- backtest$1.strategyValidationService.validate(strategyName, "LiveUtils.getData");
17692
+ this.getData = async (symbol, context) => {
17693
+ backtest$1.strategyValidationService.validate(context.strategyName, "LiveUtils.getData");
17328
17694
  {
17329
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17695
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17330
17696
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA);
17331
17697
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA));
17332
17698
  }
17333
- return await backtest$1.liveMarkdownService.getData(symbol, strategyName, false);
17699
+ return await backtest$1.liveMarkdownService.getData(symbol, context.strategyName, context.exchangeName, "", false);
17334
17700
  };
17335
17701
  /**
17336
17702
  * Generates markdown report with all events for a symbol-strategy pair.
17337
17703
  *
17338
17704
  * @param symbol - Trading pair symbol
17339
17705
  * @param strategyName - Strategy name to generate report for
17706
+ * @param context - Execution context with exchangeName and frameName
17340
17707
  * @param columns - Optional columns configuration for the report
17341
17708
  * @returns Promise resolving to markdown formatted report string
17342
17709
  *
17343
17710
  * @example
17344
17711
  * ```typescript
17345
- * const markdown = await Live.getReport("BTCUSDT", "my-strategy");
17712
+ * const markdown = await Live.getReport("BTCUSDT", "my-strategy", {
17713
+ * exchangeName: "binance",
17714
+ * frameName: "",
17715
+ * strategyName: "my-strategy"
17716
+ * });
17346
17717
  * console.log(markdown);
17347
17718
  * ```
17348
17719
  */
17349
- this.getReport = async (symbol, strategyName, columns) => {
17350
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_REPORT);
17720
+ this.getReport = async (symbol, context, columns) => {
17721
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_REPORT);
17351
17722
  {
17352
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17723
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17353
17724
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT);
17354
17725
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT));
17355
17726
  }
17356
- return await backtest$1.liveMarkdownService.getReport(symbol, strategyName, false, columns);
17727
+ return await backtest$1.liveMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, "", false, columns);
17357
17728
  };
17358
17729
  /**
17359
17730
  * Saves strategy report to disk.
17360
17731
  *
17361
17732
  * @param symbol - Trading pair symbol
17362
17733
  * @param strategyName - Strategy name to save report for
17734
+ * @param context - Execution context with exchangeName and frameName
17363
17735
  * @param path - Optional directory path to save report (default: "./dump/live")
17364
17736
  * @param columns - Optional columns configuration for the report
17365
17737
  *
17366
17738
  * @example
17367
17739
  * ```typescript
17368
17740
  * // Save to default path: ./dump/live/my-strategy.md
17369
- * await Live.dump("BTCUSDT", "my-strategy");
17741
+ * await Live.dump("BTCUSDT", "my-strategy", {
17742
+ * exchangeName: "binance",
17743
+ * frameName: "",
17744
+ * strategyName: "my-strategy"
17745
+ * });
17370
17746
  *
17371
17747
  * // Save to custom path: ./custom/path/my-strategy.md
17372
- * await Live.dump("BTCUSDT", "my-strategy", "./custom/path");
17748
+ * await Live.dump("BTCUSDT", "my-strategy", {
17749
+ * exchangeName: "binance",
17750
+ * frameName: "",
17751
+ * strategyName: "my-strategy"
17752
+ * }, "./custom/path");
17373
17753
  * ```
17374
17754
  */
17375
- this.dump = async (symbol, strategyName, path, columns) => {
17376
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_DUMP);
17755
+ this.dump = async (symbol, context, path, columns) => {
17756
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_DUMP);
17377
17757
  {
17378
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17758
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17379
17759
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP);
17380
17760
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP));
17381
17761
  }
17382
- await backtest$1.liveMarkdownService.dump(symbol, strategyName, false, path, columns);
17762
+ await backtest$1.liveMarkdownService.dump(symbol, context.strategyName, context.exchangeName, "", false, path, columns);
17383
17763
  };
17384
17764
  /**
17385
17765
  * Lists all active live trading instances with their current status.
@@ -17460,19 +17840,19 @@ class ScheduleUtils {
17460
17840
  * console.log(stats.cancellationRate, stats.avgWaitTime);
17461
17841
  * ```
17462
17842
  */
17463
- this.getData = async (symbol, strategyName, backtest = false) => {
17843
+ this.getData = async (symbol, context, backtest = false) => {
17464
17844
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_DATA, {
17465
17845
  symbol,
17466
- strategyName,
17846
+ strategyName: context.strategyName,
17467
17847
  backtest,
17468
17848
  });
17469
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
17849
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
17470
17850
  {
17471
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17851
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17472
17852
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA);
17473
17853
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA));
17474
17854
  }
17475
- return await backtest$1.scheduleMarkdownService.getData(symbol, strategyName, backtest);
17855
+ return await backtest$1.scheduleMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
17476
17856
  };
17477
17857
  /**
17478
17858
  * Generates markdown report with all scheduled events for a symbol-strategy pair.
@@ -17488,19 +17868,19 @@ class ScheduleUtils {
17488
17868
  * console.log(markdown);
17489
17869
  * ```
17490
17870
  */
17491
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
17871
+ this.getReport = async (symbol, context, backtest = false, columns) => {
17492
17872
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_REPORT, {
17493
17873
  symbol,
17494
- strategyName,
17874
+ strategyName: context.strategyName,
17495
17875
  backtest,
17496
17876
  });
17497
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
17877
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
17498
17878
  {
17499
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17879
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17500
17880
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT);
17501
17881
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT));
17502
17882
  }
17503
- return await backtest$1.scheduleMarkdownService.getReport(symbol, strategyName, backtest, columns);
17883
+ return await backtest$1.scheduleMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
17504
17884
  };
17505
17885
  /**
17506
17886
  * Saves strategy report to disk.
@@ -17519,20 +17899,20 @@ class ScheduleUtils {
17519
17899
  * await Schedule.dump("BTCUSDT", "my-strategy", "./custom/path");
17520
17900
  * ```
17521
17901
  */
17522
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
17902
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
17523
17903
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_DUMP, {
17524
17904
  symbol,
17525
- strategyName,
17905
+ strategyName: context.strategyName,
17526
17906
  backtest,
17527
17907
  path,
17528
17908
  });
17529
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_DUMP);
17909
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_DUMP);
17530
17910
  {
17531
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17911
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17532
17912
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP);
17533
17913
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP));
17534
17914
  }
17535
- await backtest$1.scheduleMarkdownService.dump(symbol, strategyName, backtest, path, columns);
17915
+ await backtest$1.scheduleMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
17536
17916
  };
17537
17917
  }
17538
17918
  }
@@ -17613,14 +17993,14 @@ class Performance {
17613
17993
  * }
17614
17994
  * ```
17615
17995
  */
17616
- static async getData(symbol, strategyName, backtest = false) {
17617
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
17996
+ static async getData(symbol, context, backtest = false) {
17997
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
17618
17998
  {
17619
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17999
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17620
18000
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA);
17621
18001
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA));
17622
18002
  }
17623
- return backtest$1.performanceMarkdownService.getData(symbol, strategyName, backtest);
18003
+ return backtest$1.performanceMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
17624
18004
  }
17625
18005
  /**
17626
18006
  * Generates markdown report with performance analysis.
@@ -17645,14 +18025,14 @@ class Performance {
17645
18025
  * await fs.writeFile("performance-report.md", markdown);
17646
18026
  * ```
17647
18027
  */
17648
- static async getReport(symbol, strategyName, backtest = false, columns) {
17649
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
18028
+ static async getReport(symbol, context, backtest = false, columns) {
18029
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
17650
18030
  {
17651
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18031
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17652
18032
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT);
17653
18033
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT));
17654
18034
  }
17655
- return backtest$1.performanceMarkdownService.getReport(symbol, strategyName, backtest, columns);
18035
+ return backtest$1.performanceMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
17656
18036
  }
17657
18037
  /**
17658
18038
  * Saves performance report to disk.
@@ -17674,14 +18054,14 @@ class Performance {
17674
18054
  * await Performance.dump("BTCUSDT", "my-strategy", "./reports/perf");
17675
18055
  * ```
17676
18056
  */
17677
- static async dump(symbol, strategyName, backtest = false, path = "./dump/performance", columns) {
17678
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_DUMP);
18057
+ static async dump(symbol, context, backtest = false, path = "./dump/performance", columns) {
18058
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_DUMP);
17679
18059
  {
17680
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18060
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17681
18061
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP);
17682
18062
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP));
17683
18063
  }
17684
- return backtest$1.performanceMarkdownService.dump(symbol, strategyName, backtest, path, columns);
18064
+ return backtest$1.performanceMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
17685
18065
  }
17686
18066
  }
17687
18067
 
@@ -17819,21 +18199,37 @@ class WalkerInstance {
17819
18199
  // Clear backtest data for all strategies
17820
18200
  for (const strategyName of walkerSchema.strategies) {
17821
18201
  {
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 });
18202
+ backtest$1.backtestMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18203
+ backtest$1.liveMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18204
+ backtest$1.scheduleMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18205
+ backtest$1.performanceMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18206
+ backtest$1.partialMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18207
+ backtest$1.riskMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
17828
18208
  }
17829
18209
  {
17830
- backtest$1.strategyCoreService.clear(true, { symbol, strategyName });
18210
+ backtest$1.strategyCoreService.clear({
18211
+ symbol,
18212
+ strategyName,
18213
+ exchangeName: walkerSchema.exchangeName,
18214
+ frameName: walkerSchema.frameName,
18215
+ backtest: true,
18216
+ });
17831
18217
  }
17832
18218
  {
17833
18219
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17834
- riskName && backtest$1.riskGlobalService.clear(true, { riskName });
18220
+ riskName && backtest$1.riskGlobalService.clear({
18221
+ riskName,
18222
+ exchangeName: walkerSchema.exchangeName,
18223
+ frameName: walkerSchema.frameName,
18224
+ backtest: true
18225
+ });
17835
18226
  riskList &&
17836
- riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, { riskName }));
18227
+ riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
18228
+ riskName,
18229
+ exchangeName: walkerSchema.exchangeName,
18230
+ frameName: walkerSchema.frameName,
18231
+ backtest: true
18232
+ }));
17837
18233
  }
17838
18234
  }
17839
18235
  return backtest$1.walkerCommandService.run(symbol, {
@@ -17878,7 +18274,11 @@ class WalkerInstance {
17878
18274
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
17879
18275
  return () => {
17880
18276
  for (const strategyName of walkerSchema.strategies) {
17881
- backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
18277
+ backtest$1.strategyCoreService.stop(true, symbol, {
18278
+ strategyName,
18279
+ exchangeName: walkerSchema.exchangeName,
18280
+ frameName: walkerSchema.frameName
18281
+ });
17882
18282
  walkerStopSubject.next({
17883
18283
  symbol,
17884
18284
  strategyName,
@@ -18019,7 +18419,11 @@ class WalkerUtils {
18019
18419
  }
18020
18420
  for (const strategyName of walkerSchema.strategies) {
18021
18421
  await walkerStopSubject.next({ symbol, strategyName, walkerName });
18022
- await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
18422
+ await backtest$1.strategyCoreService.stop(true, symbol, {
18423
+ strategyName,
18424
+ exchangeName: walkerSchema.exchangeName,
18425
+ frameName: walkerSchema.frameName
18426
+ });
18023
18427
  }
18024
18428
  };
18025
18429
  /**
@@ -18167,15 +18571,27 @@ const HEAT_METHOD_NAME_DUMP = "HeatUtils.dump";
18167
18571
  * import { Heat } from "backtest-kit";
18168
18572
  *
18169
18573
  * // Get raw heatmap data for a strategy
18170
- * const stats = await Heat.getData("my-strategy");
18574
+ * const stats = await Heat.getData({
18575
+ * strategyName: "my-strategy",
18576
+ * exchangeName: "binance",
18577
+ * frameName: "frame1"
18578
+ * });
18171
18579
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18172
18580
  *
18173
18581
  * // Generate markdown report
18174
- * const markdown = await Heat.getReport("my-strategy");
18582
+ * const markdown = await Heat.getReport({
18583
+ * strategyName: "my-strategy",
18584
+ * exchangeName: "binance",
18585
+ * frameName: "frame1"
18586
+ * });
18175
18587
  * console.log(markdown);
18176
18588
  *
18177
18589
  * // Save to disk
18178
- * await Heat.dump("my-strategy", "./reports");
18590
+ * await Heat.dump({
18591
+ * strategyName: "my-strategy",
18592
+ * exchangeName: "binance",
18593
+ * frameName: "frame1"
18594
+ * }, false, "./reports");
18179
18595
  * ```
18180
18596
  */
18181
18597
  class HeatUtils {
@@ -18186,12 +18602,17 @@ class HeatUtils {
18186
18602
  * Returns per-symbol breakdown and portfolio-wide metrics.
18187
18603
  * Data is automatically collected from all closed signals for the strategy.
18188
18604
  *
18189
- * @param strategyName - Strategy name to get heatmap data for
18605
+ * @param context - Execution context with strategyName, exchangeName and frameName
18606
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18190
18607
  * @returns Promise resolving to heatmap statistics object
18191
18608
  *
18192
18609
  * @example
18193
18610
  * ```typescript
18194
- * const stats = await Heat.getData("my-strategy");
18611
+ * const stats = await Heat.getData({
18612
+ * strategyName: "my-strategy",
18613
+ * exchangeName: "binance",
18614
+ * frameName: "frame1"
18615
+ * });
18195
18616
  *
18196
18617
  * console.log(`Total symbols: ${stats.totalSymbols}`);
18197
18618
  * console.log(`Portfolio Total PNL: ${stats.portfolioTotalPnl}%`);
@@ -18203,15 +18624,15 @@ class HeatUtils {
18203
18624
  * });
18204
18625
  * ```
18205
18626
  */
18206
- this.getData = async (strategyName, backtest = false) => {
18207
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
18208
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_DATA);
18627
+ this.getData = async (context, backtest = false) => {
18628
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName: context.strategyName });
18629
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_DATA);
18209
18630
  {
18210
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18631
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18211
18632
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
18212
18633
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
18213
18634
  }
18214
- return await backtest$1.heatMarkdownService.getData(strategyName, backtest);
18635
+ return await backtest$1.heatMarkdownService.getData(context.exchangeName, context.frameName, backtest);
18215
18636
  };
18216
18637
  /**
18217
18638
  * Generates markdown report with portfolio heatmap table for a strategy.
@@ -18219,13 +18640,18 @@ class HeatUtils {
18219
18640
  * Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
18220
18641
  * Symbols are sorted by Total PNL descending.
18221
18642
  *
18222
- * @param strategyName - Strategy name to generate heatmap report for
18643
+ * @param context - Execution context with strategyName, exchangeName and frameName
18644
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18223
18645
  * @param columns - Optional columns configuration for the report
18224
18646
  * @returns Promise resolving to markdown formatted report string
18225
18647
  *
18226
18648
  * @example
18227
18649
  * ```typescript
18228
- * const markdown = await Heat.getReport("my-strategy");
18650
+ * const markdown = await Heat.getReport({
18651
+ * strategyName: "my-strategy",
18652
+ * exchangeName: "binance",
18653
+ * frameName: "frame1"
18654
+ * });
18229
18655
  * console.log(markdown);
18230
18656
  * // Output:
18231
18657
  * // # Portfolio Heatmap: my-strategy
@@ -18239,15 +18665,15 @@ class HeatUtils {
18239
18665
  * // ...
18240
18666
  * ```
18241
18667
  */
18242
- this.getReport = async (strategyName, backtest = false, columns) => {
18243
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
18244
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_REPORT);
18668
+ this.getReport = async (context, backtest = false, columns) => {
18669
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName: context.strategyName });
18670
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_REPORT);
18245
18671
  {
18246
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18672
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18247
18673
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
18248
18674
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
18249
18675
  }
18250
- return await backtest$1.heatMarkdownService.getReport(strategyName, backtest, columns);
18676
+ return await backtest$1.heatMarkdownService.getReport(context.strategyName, context.exchangeName, context.frameName, backtest, columns);
18251
18677
  };
18252
18678
  /**
18253
18679
  * Saves heatmap report to disk for a strategy.
@@ -18255,28 +18681,37 @@ class HeatUtils {
18255
18681
  * Creates directory if it doesn't exist.
18256
18682
  * Default filename: {strategyName}.md
18257
18683
  *
18258
- * @param strategyName - Strategy name to save heatmap report for
18684
+ * @param context - Execution context with strategyName, exchangeName and frameName
18685
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18259
18686
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
18260
18687
  * @param columns - Optional columns configuration for the report
18261
18688
  *
18262
18689
  * @example
18263
18690
  * ```typescript
18264
18691
  * // Save to default path: ./dump/heatmap/my-strategy.md
18265
- * await Heat.dump("my-strategy");
18692
+ * await Heat.dump({
18693
+ * strategyName: "my-strategy",
18694
+ * exchangeName: "binance",
18695
+ * frameName: "frame1"
18696
+ * });
18266
18697
  *
18267
18698
  * // Save to custom path: ./reports/my-strategy.md
18268
- * await Heat.dump("my-strategy", "./reports");
18699
+ * await Heat.dump({
18700
+ * strategyName: "my-strategy",
18701
+ * exchangeName: "binance",
18702
+ * frameName: "frame1"
18703
+ * }, false, "./reports");
18269
18704
  * ```
18270
18705
  */
18271
- this.dump = async (strategyName, backtest = false, path, columns) => {
18272
- backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
18273
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_DUMP);
18706
+ this.dump = async (context, backtest = false, path, columns) => {
18707
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName: context.strategyName, path });
18708
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_DUMP);
18274
18709
  {
18275
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18710
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18276
18711
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
18277
18712
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
18278
18713
  }
18279
- await backtest$1.heatMarkdownService.dump(strategyName, backtest, path, columns);
18714
+ await backtest$1.heatMarkdownService.dump(context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18280
18715
  };
18281
18716
  }
18282
18717
  }
@@ -18288,7 +18723,11 @@ class HeatUtils {
18288
18723
  * import { Heat } from "backtest-kit";
18289
18724
  *
18290
18725
  * // Strategy-specific heatmap
18291
- * const stats = await Heat.getData("my-strategy");
18726
+ * const stats = await Heat.getData({
18727
+ * strategyName: "my-strategy",
18728
+ * exchangeName: "binance",
18729
+ * frameName: "frame1"
18730
+ * });
18292
18731
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18293
18732
  * console.log(`Total Symbols: ${stats.totalSymbols}`);
18294
18733
  *
@@ -18302,7 +18741,11 @@ class HeatUtils {
18302
18741
  * });
18303
18742
  *
18304
18743
  * // Generate and save report
18305
- * await Heat.dump("my-strategy", "./reports");
18744
+ * await Heat.dump({
18745
+ * strategyName: "my-strategy",
18746
+ * exchangeName: "binance",
18747
+ * frameName: "frame1"
18748
+ * }, false, "./reports");
18306
18749
  * ```
18307
18750
  */
18308
18751
  const Heat = new HeatUtils();
@@ -18592,15 +19035,15 @@ class PartialUtils {
18592
19035
  * }
18593
19036
  * ```
18594
19037
  */
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);
19038
+ this.getData = async (symbol, context, backtest = false) => {
19039
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_DATA, { symbol, strategyName: context.strategyName });
19040
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_DATA);
18598
19041
  {
18599
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19042
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18600
19043
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA);
18601
19044
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA));
18602
19045
  }
18603
- return await backtest$1.partialMarkdownService.getData(symbol, strategyName, backtest);
19046
+ return await backtest$1.partialMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
18604
19047
  };
18605
19048
  /**
18606
19049
  * Generates markdown report with all partial profit/loss events for a symbol-strategy pair.
@@ -18641,15 +19084,15 @@ class PartialUtils {
18641
19084
  * // **Loss events:** 1
18642
19085
  * ```
18643
19086
  */
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);
19087
+ this.getReport = async (symbol, context, backtest = false, columns) => {
19088
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_REPORT, { symbol, strategyName: context.strategyName });
19089
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_REPORT);
18647
19090
  {
18648
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19091
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18649
19092
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT);
18650
19093
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT));
18651
19094
  }
18652
- return await backtest$1.partialMarkdownService.getReport(symbol, strategyName, backtest, columns);
19095
+ return await backtest$1.partialMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
18653
19096
  };
18654
19097
  /**
18655
19098
  * Generates and saves markdown report to file.
@@ -18683,15 +19126,15 @@ class PartialUtils {
18683
19126
  * }
18684
19127
  * ```
18685
19128
  */
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);
19129
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
19130
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_DUMP, { symbol, strategyName: context.strategyName, path });
19131
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_DUMP);
18689
19132
  {
18690
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19133
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18691
19134
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP);
18692
19135
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP));
18693
19136
  }
18694
- await backtest$1.partialMarkdownService.dump(symbol, strategyName, backtest, path, columns);
19137
+ await backtest$1.partialMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18695
19138
  };
18696
19139
  }
18697
19140
  }
@@ -19104,7 +19547,13 @@ const INTERVAL_MINUTES = {
19104
19547
  * @param backtest - Whether running in backtest mode
19105
19548
  * @returns Cache key string
19106
19549
  */
19107
- const CREATE_KEY_FN$1 = (strategyName, exchangeName, backtest) => `${strategyName}:${exchangeName}:${backtest ? "backtest" : "live"}`;
19550
+ const CREATE_KEY_FN$1 = (strategyName, exchangeName, frameName, backtest) => {
19551
+ const parts = [strategyName, exchangeName];
19552
+ if (frameName)
19553
+ parts.push(frameName);
19554
+ parts.push(backtest ? "backtest" : "live");
19555
+ return parts.join(":");
19556
+ };
19108
19557
  /**
19109
19558
  * Instance class for caching function results with timeframe-based invalidation.
19110
19559
  *
@@ -19180,7 +19629,7 @@ class CacheInstance {
19180
19629
  throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
19181
19630
  }
19182
19631
  }
19183
- const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
19632
+ 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
19633
  const currentWhen = backtest$1.executionContextService.context.when;
19185
19634
  const cached = this._cacheMap.get(key);
19186
19635
  if (cached) {
@@ -19218,7 +19667,7 @@ class CacheInstance {
19218
19667
  * ```
19219
19668
  */
19220
19669
  this.clear = () => {
19221
- const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
19670
+ 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
19671
  this._cacheMap.delete(key);
19223
19672
  };
19224
19673
  }