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.mjs CHANGED
@@ -2093,6 +2093,7 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
2093
2093
  symbol: self.params.execution.context.symbol,
2094
2094
  strategyName: self.params.method.context.strategyName,
2095
2095
  exchangeName: self.params.method.context.exchangeName,
2096
+ frameName: self.params.method.context.frameName,
2096
2097
  currentPrice,
2097
2098
  timestamp: currentTime,
2098
2099
  }))) {
@@ -2119,6 +2120,7 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
2119
2120
  symbol: self.params.execution.context.symbol,
2120
2121
  exchangeName: self.params.method.context.exchangeName,
2121
2122
  strategyName: self.params.method.context.strategyName,
2123
+ frameName: self.params.method.context.frameName,
2122
2124
  scheduledAt: currentTime,
2123
2125
  pendingAt: currentTime, // Для immediate signal оба времени одинаковые
2124
2126
  _isScheduled: false,
@@ -2139,6 +2141,7 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
2139
2141
  symbol: self.params.execution.context.symbol,
2140
2142
  exchangeName: self.params.method.context.exchangeName,
2141
2143
  strategyName: self.params.method.context.strategyName,
2144
+ frameName: self.params.method.context.frameName,
2142
2145
  scheduledAt: currentTime,
2143
2146
  pendingAt: currentTime, // Временно, обновится при активации
2144
2147
  _isScheduled: true,
@@ -2155,6 +2158,7 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
2155
2158
  symbol: self.params.execution.context.symbol,
2156
2159
  exchangeName: self.params.method.context.exchangeName,
2157
2160
  strategyName: self.params.method.context.strategyName,
2161
+ frameName: self.params.method.context.frameName,
2158
2162
  scheduledAt: currentTime,
2159
2163
  pendingAt: currentTime, // Для immediate signal оба времени одинаковые
2160
2164
  _isScheduled: false,
@@ -2248,6 +2252,7 @@ const CHECK_SCHEDULED_SIGNAL_TIMEOUT_FN = async (self, scheduled, currentPrice)
2248
2252
  closeTimestamp: currentTime,
2249
2253
  strategyName: self.params.method.context.strategyName,
2250
2254
  exchangeName: self.params.method.context.exchangeName,
2255
+ frameName: self.params.method.context.frameName,
2251
2256
  symbol: self.params.execution.context.symbol,
2252
2257
  backtest: self.params.execution.context.backtest,
2253
2258
  reason: "timeout",
@@ -2305,6 +2310,7 @@ const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPr
2305
2310
  closeTimestamp: self.params.execution.context.when.getTime(),
2306
2311
  strategyName: self.params.method.context.strategyName,
2307
2312
  exchangeName: self.params.method.context.exchangeName,
2313
+ frameName: self.params.method.context.frameName,
2308
2314
  symbol: self.params.execution.context.symbol,
2309
2315
  backtest: self.params.execution.context.backtest,
2310
2316
  reason: "price_reject",
@@ -2343,6 +2349,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
2343
2349
  pendingSignal: scheduled,
2344
2350
  strategyName: self.params.method.context.strategyName,
2345
2351
  exchangeName: self.params.method.context.exchangeName,
2352
+ frameName: self.params.method.context.frameName,
2346
2353
  currentPrice: scheduled.priceOpen,
2347
2354
  timestamp: activationTime,
2348
2355
  }))) {
@@ -2364,6 +2371,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
2364
2371
  await self.params.risk.addSignal(self.params.execution.context.symbol, {
2365
2372
  strategyName: self.params.method.context.strategyName,
2366
2373
  riskName: self.params.riskName,
2374
+ exchangeName: self.params.method.context.exchangeName,
2375
+ frameName: self.params.method.context.frameName,
2367
2376
  });
2368
2377
  if (self.params.callbacks?.onOpen) {
2369
2378
  self.params.callbacks.onOpen(self.params.execution.context.symbol, self._pendingSignal, self._pendingSignal.priceOpen, self.params.execution.context.backtest);
@@ -2373,6 +2382,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
2373
2382
  signal: self._pendingSignal,
2374
2383
  strategyName: self.params.method.context.strategyName,
2375
2384
  exchangeName: self.params.method.context.exchangeName,
2385
+ frameName: self.params.method.context.frameName,
2376
2386
  symbol: self.params.execution.context.symbol,
2377
2387
  currentPrice: self._pendingSignal.priceOpen,
2378
2388
  backtest: self.params.execution.context.backtest,
@@ -2409,6 +2419,7 @@ const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice)
2409
2419
  currentPrice: currentPrice,
2410
2420
  strategyName: self.params.method.context.strategyName,
2411
2421
  exchangeName: self.params.method.context.exchangeName,
2422
+ frameName: self.params.method.context.frameName,
2412
2423
  symbol: self.params.execution.context.symbol,
2413
2424
  percentTp: 0,
2414
2425
  percentSl: 0,
@@ -2436,6 +2447,7 @@ const OPEN_NEW_SCHEDULED_SIGNAL_FN = async (self, signal) => {
2436
2447
  signal: signal,
2437
2448
  strategyName: self.params.method.context.strategyName,
2438
2449
  exchangeName: self.params.method.context.exchangeName,
2450
+ frameName: self.params.method.context.frameName,
2439
2451
  symbol: self.params.execution.context.symbol,
2440
2452
  currentPrice: currentPrice,
2441
2453
  backtest: self.params.execution.context.backtest,
@@ -2451,6 +2463,7 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
2451
2463
  symbol: self.params.execution.context.symbol,
2452
2464
  strategyName: self.params.method.context.strategyName,
2453
2465
  exchangeName: self.params.method.context.exchangeName,
2466
+ frameName: self.params.method.context.frameName,
2454
2467
  currentPrice: signal.priceOpen,
2455
2468
  timestamp: self.params.execution.context.when.getTime(),
2456
2469
  }))) {
@@ -2459,6 +2472,8 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
2459
2472
  await self.params.risk.addSignal(self.params.execution.context.symbol, {
2460
2473
  strategyName: self.params.method.context.strategyName,
2461
2474
  riskName: self.params.riskName,
2475
+ exchangeName: self.params.method.context.exchangeName,
2476
+ frameName: self.params.method.context.frameName,
2462
2477
  });
2463
2478
  if (self.params.callbacks?.onOpen) {
2464
2479
  self.params.callbacks.onOpen(self.params.execution.context.symbol, signal, signal.priceOpen, self.params.execution.context.backtest);
@@ -2468,6 +2483,7 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
2468
2483
  signal: signal,
2469
2484
  strategyName: self.params.method.context.strategyName,
2470
2485
  exchangeName: self.params.method.context.exchangeName,
2486
+ frameName: self.params.method.context.frameName,
2471
2487
  symbol: self.params.execution.context.symbol,
2472
2488
  currentPrice: signal.priceOpen,
2473
2489
  backtest: self.params.execution.context.backtest,
@@ -2523,6 +2539,8 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
2523
2539
  await self.params.risk.removeSignal(self.params.execution.context.symbol, {
2524
2540
  strategyName: self.params.method.context.strategyName,
2525
2541
  riskName: self.params.riskName,
2542
+ exchangeName: self.params.method.context.exchangeName,
2543
+ frameName: self.params.method.context.frameName,
2526
2544
  });
2527
2545
  await self.setPendingSignal(null);
2528
2546
  const result = {
@@ -2534,6 +2552,7 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
2534
2552
  pnl: pnl,
2535
2553
  strategyName: self.params.method.context.strategyName,
2536
2554
  exchangeName: self.params.method.context.exchangeName,
2555
+ frameName: self.params.method.context.frameName,
2537
2556
  symbol: self.params.execution.context.symbol,
2538
2557
  backtest: self.params.execution.context.backtest,
2539
2558
  };
@@ -2602,6 +2621,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice) => {
2602
2621
  currentPrice: currentPrice,
2603
2622
  strategyName: self.params.method.context.strategyName,
2604
2623
  exchangeName: self.params.method.context.exchangeName,
2624
+ frameName: self.params.method.context.frameName,
2605
2625
  symbol: self.params.execution.context.symbol,
2606
2626
  percentTp,
2607
2627
  percentSl,
@@ -2621,6 +2641,7 @@ const RETURN_IDLE_FN = async (self, currentPrice) => {
2621
2641
  signal: null,
2622
2642
  strategyName: self.params.method.context.strategyName,
2623
2643
  exchangeName: self.params.method.context.exchangeName,
2644
+ frameName: self.params.method.context.frameName,
2624
2645
  symbol: self.params.execution.context.symbol,
2625
2646
  currentPrice: currentPrice,
2626
2647
  backtest: self.params.execution.context.backtest,
@@ -2650,6 +2671,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
2650
2671
  closeTimestamp: closeTimestamp,
2651
2672
  strategyName: self.params.method.context.strategyName,
2652
2673
  exchangeName: self.params.method.context.exchangeName,
2674
+ frameName: self.params.method.context.frameName,
2653
2675
  symbol: self.params.execution.context.symbol,
2654
2676
  backtest: self.params.execution.context.backtest,
2655
2677
  reason,
@@ -2685,6 +2707,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
2685
2707
  symbol: self.params.execution.context.symbol,
2686
2708
  strategyName: self.params.method.context.strategyName,
2687
2709
  exchangeName: self.params.method.context.exchangeName,
2710
+ frameName: self.params.method.context.frameName,
2688
2711
  currentPrice: scheduled.priceOpen,
2689
2712
  timestamp: activationTime,
2690
2713
  }))) {
@@ -2706,6 +2729,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
2706
2729
  await self.params.risk.addSignal(self.params.execution.context.symbol, {
2707
2730
  strategyName: self.params.method.context.strategyName,
2708
2731
  riskName: self.params.riskName,
2732
+ exchangeName: self.params.method.context.exchangeName,
2733
+ frameName: self.params.method.context.frameName,
2709
2734
  });
2710
2735
  if (self.params.callbacks?.onOpen) {
2711
2736
  self.params.callbacks.onOpen(self.params.execution.context.symbol, activatedSignal, activatedSignal.priceOpen, self.params.execution.context.backtest);
@@ -2736,6 +2761,8 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
2736
2761
  await self.params.risk.removeSignal(self.params.execution.context.symbol, {
2737
2762
  strategyName: self.params.method.context.strategyName,
2738
2763
  riskName: self.params.riskName,
2764
+ exchangeName: self.params.method.context.exchangeName,
2765
+ frameName: self.params.method.context.frameName,
2739
2766
  });
2740
2767
  await self.setPendingSignal(null);
2741
2768
  const result = {
@@ -2747,6 +2774,7 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
2747
2774
  pnl: pnl,
2748
2775
  strategyName: self.params.method.context.strategyName,
2749
2776
  exchangeName: self.params.method.context.exchangeName,
2777
+ frameName: self.params.method.context.frameName,
2750
2778
  symbol: self.params.execution.context.symbol,
2751
2779
  backtest: self.params.execution.context.backtest,
2752
2780
  };
@@ -3043,10 +3071,9 @@ class ClientStrategy {
3043
3071
  * If no signal is pending, returns null.
3044
3072
  * @returns Promise resolving to the pending signal or null.
3045
3073
  */
3046
- async getPendingSignal(symbol, strategyName) {
3074
+ async getPendingSignal(symbol) {
3047
3075
  this.params.logger.debug("ClientStrategy getPendingSignal", {
3048
3076
  symbol,
3049
- strategyName,
3050
3077
  });
3051
3078
  return this._pendingSignal;
3052
3079
  }
@@ -3055,10 +3082,9 @@ class ClientStrategy {
3055
3082
  * If no scheduled signal exists, returns null.
3056
3083
  * @returns Promise resolving to the scheduled signal or null.
3057
3084
  */
3058
- async getScheduledSignal(symbol, strategyName) {
3085
+ async getScheduledSignal(symbol) {
3059
3086
  this.params.logger.debug("ClientStrategy getScheduledSignal", {
3060
3087
  symbol,
3061
- strategyName,
3062
3088
  });
3063
3089
  return this._scheduledSignal;
3064
3090
  }
@@ -3069,13 +3095,12 @@ class ClientStrategy {
3069
3095
  * not continue processing new ticks or signals.
3070
3096
  *
3071
3097
  * @param symbol - Trading pair symbol
3072
- * @param strategyName - Name of the strategy
3073
3098
  * @returns Promise resolving to true if strategy is stopped, false otherwise
3074
3099
  */
3075
- async getStopped(symbol, strategyName) {
3100
+ async getStopped(symbol) {
3076
3101
  this.params.logger.debug("ClientStrategy getStopped", {
3077
3102
  symbol,
3078
- strategyName,
3103
+ strategyName: this.params.method.context.strategyName,
3079
3104
  });
3080
3105
  return this._isStopped;
3081
3106
  }
@@ -3141,6 +3166,7 @@ class ClientStrategy {
3141
3166
  closeTimestamp: currentTime,
3142
3167
  strategyName: this.params.method.context.strategyName,
3143
3168
  exchangeName: this.params.method.context.exchangeName,
3169
+ frameName: this.params.method.context.frameName,
3144
3170
  symbol: this.params.execution.context.symbol,
3145
3171
  backtest: this.params.execution.context.backtest,
3146
3172
  reason: "user",
@@ -3254,6 +3280,7 @@ class ClientStrategy {
3254
3280
  closeTimestamp: this.params.execution.context.when.getTime(),
3255
3281
  strategyName: this.params.method.context.strategyName,
3256
3282
  exchangeName: this.params.method.context.exchangeName,
3283
+ frameName: this.params.method.context.frameName,
3257
3284
  symbol: this.params.execution.context.symbol,
3258
3285
  backtest: true,
3259
3286
  reason: "user",
@@ -3316,6 +3343,7 @@ class ClientStrategy {
3316
3343
  percentTp: 0,
3317
3344
  strategyName: this.params.method.context.strategyName,
3318
3345
  exchangeName: this.params.method.context.exchangeName,
3346
+ frameName: this.params.method.context.frameName,
3319
3347
  symbol: this.params.execution.context.symbol,
3320
3348
  backtest: this.params.execution.context.backtest,
3321
3349
  };
@@ -3372,13 +3400,11 @@ class ClientStrategy {
3372
3400
  * // Existing signal will continue until natural close
3373
3401
  * ```
3374
3402
  */
3375
- async stop(symbol, strategyName, backtest) {
3403
+ async stop(symbol, backtest) {
3376
3404
  this.params.logger.debug("ClientStrategy stop", {
3377
3405
  symbol,
3378
- strategyName,
3379
3406
  hasPendingSignal: this._pendingSignal !== null,
3380
3407
  hasScheduledSignal: this._scheduledSignal !== null,
3381
- backtest,
3382
3408
  });
3383
3409
  this._isStopped = true;
3384
3410
  // Clear scheduled signal if exists
@@ -3389,7 +3415,7 @@ class ClientStrategy {
3389
3415
  if (backtest) {
3390
3416
  return;
3391
3417
  }
3392
- await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
3418
+ await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
3393
3419
  }
3394
3420
  /**
3395
3421
  * Cancels the scheduled signal without stopping the strategy.
@@ -3412,12 +3438,10 @@ class ClientStrategy {
3412
3438
  * // Strategy continues, can generate new signals
3413
3439
  * ```
3414
3440
  */
3415
- async cancel(symbol, strategyName, backtest, cancelId) {
3441
+ async cancel(symbol, backtest, cancelId) {
3416
3442
  this.params.logger.debug("ClientStrategy cancel", {
3417
3443
  symbol,
3418
- strategyName,
3419
3444
  hasScheduledSignal: this._scheduledSignal !== null,
3420
- backtest,
3421
3445
  cancelId,
3422
3446
  });
3423
3447
  // Save cancelled signal for next tick to emit cancelled event
@@ -3430,7 +3454,7 @@ class ClientStrategy {
3430
3454
  if (backtest) {
3431
3455
  return;
3432
3456
  }
3433
- await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
3457
+ await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
3434
3458
  }
3435
3459
  }
3436
3460
 
@@ -3506,7 +3530,7 @@ class MergeRisk {
3506
3530
  * Used to track active positions across all risk management systems.
3507
3531
  *
3508
3532
  * @param symbol - Trading pair symbol
3509
- * @param context - Context with strategyName and riskName
3533
+ * @param context - Context with strategyName, riskName, exchangeName and frameName
3510
3534
  * @returns Promise that resolves when all risks have registered the signal
3511
3535
  */
3512
3536
  async addSignal(symbol, context) {
@@ -3523,7 +3547,7 @@ class MergeRisk {
3523
3547
  * Used to update risk state when a position closes.
3524
3548
  *
3525
3549
  * @param symbol - Trading pair symbol
3526
- * @param context - Context with strategyName and riskName
3550
+ * @param context - Context with strategyName, riskName, exchangeName and frameName
3527
3551
  * @returns Promise that resolves when all risks have removed the signal
3528
3552
  */
3529
3553
  async removeSignal(symbol, context) {
@@ -3595,20 +3619,20 @@ class RiskUtils {
3595
3619
  * }
3596
3620
  * ```
3597
3621
  */
3598
- this.getData = async (symbol, strategyName, backtest = false) => {
3622
+ this.getData = async (symbol, context, backtest = false) => {
3599
3623
  backtest$1.loggerService.info(RISK_METHOD_NAME_GET_DATA, {
3600
3624
  symbol,
3601
- strategyName,
3625
+ strategyName: context.strategyName,
3602
3626
  });
3603
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_DATA);
3627
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_DATA);
3604
3628
  {
3605
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3629
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3606
3630
  riskName &&
3607
3631
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA);
3608
3632
  riskList &&
3609
3633
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
3610
3634
  }
3611
- return await backtest$1.riskMarkdownService.getData(symbol, strategyName, backtest);
3635
+ return await backtest$1.riskMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3612
3636
  };
3613
3637
  /**
3614
3638
  * Generates markdown report with all risk rejection events for a symbol-strategy pair.
@@ -3651,20 +3675,20 @@ class RiskUtils {
3651
3675
  * // - my-strategy: 1
3652
3676
  * ```
3653
3677
  */
3654
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
3678
+ this.getReport = async (symbol, context, backtest = false, columns) => {
3655
3679
  backtest$1.loggerService.info(RISK_METHOD_NAME_GET_REPORT, {
3656
3680
  symbol,
3657
- strategyName,
3681
+ strategyName: context.strategyName,
3658
3682
  });
3659
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_REPORT);
3683
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_REPORT);
3660
3684
  {
3661
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3685
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3662
3686
  riskName &&
3663
3687
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT);
3664
3688
  riskList &&
3665
3689
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
3666
3690
  }
3667
- return await backtest$1.riskMarkdownService.getReport(symbol, strategyName, backtest, columns);
3691
+ return await backtest$1.riskMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
3668
3692
  };
3669
3693
  /**
3670
3694
  * Generates and saves markdown report to file.
@@ -3698,21 +3722,21 @@ class RiskUtils {
3698
3722
  * }
3699
3723
  * ```
3700
3724
  */
3701
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
3725
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
3702
3726
  backtest$1.loggerService.info(RISK_METHOD_NAME_DUMP, {
3703
3727
  symbol,
3704
- strategyName,
3728
+ strategyName: context.strategyName,
3705
3729
  path,
3706
3730
  });
3707
- backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_DUMP);
3731
+ backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_DUMP);
3708
3732
  {
3709
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
3733
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
3710
3734
  riskName &&
3711
3735
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP);
3712
3736
  riskList &&
3713
3737
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
3714
3738
  }
3715
- await backtest$1.riskMarkdownService.dump(symbol, strategyName, backtest, path, columns);
3739
+ await backtest$1.riskMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
3716
3740
  };
3717
3741
  }
3718
3742
  }
@@ -3745,10 +3769,12 @@ const NOOP_RISK = {
3745
3769
  * Determines the appropriate IRisk instance based on provided riskName and riskList.
3746
3770
  * @param dto - Object containing riskName and riskList
3747
3771
  * @param backtest - Whether running in backtest mode
3772
+ * @param exchangeName - Exchange name for risk isolation
3773
+ * @param frameName - Frame name for risk isolation
3748
3774
  * @param self - Reference to StrategyConnectionService instance
3749
3775
  * @returns Configured IRisk instance (single or merged)
3750
3776
  */
3751
- const GET_RISK_FN = (dto, backtest, self) => {
3777
+ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
3752
3778
  const hasRiskName = !!dto.riskName;
3753
3779
  const hasRiskList = !!dto.riskList?.length;
3754
3780
  // Нет ни riskName, ни riskList
@@ -3757,27 +3783,35 @@ const GET_RISK_FN = (dto, backtest, self) => {
3757
3783
  }
3758
3784
  // Есть только riskName (без riskList)
3759
3785
  if (hasRiskName && !hasRiskList) {
3760
- return self.riskConnectionService.getRisk(dto.riskName, backtest);
3786
+ return self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest);
3761
3787
  }
3762
3788
  // Есть только riskList (без riskName)
3763
3789
  if (!hasRiskName && hasRiskList) {
3764
- return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)));
3790
+ return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)));
3765
3791
  }
3766
3792
  // Есть и riskName, и riskList - объединяем (riskName в начало)
3767
3793
  return new MergeRisk([
3768
- self.riskConnectionService.getRisk(dto.riskName, backtest),
3769
- ...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
3794
+ self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest),
3795
+ ...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)),
3770
3796
  ]);
3771
3797
  };
3772
3798
  /**
3773
3799
  * Creates a unique key for memoizing ClientStrategy instances.
3774
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
3800
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
3775
3801
  * @param symbol - Trading pair symbol
3776
3802
  * @param strategyName - Name of the strategy
3803
+ * @param exchangeName - Exchange name
3804
+ * @param frameName - Frame name (empty string for live)
3777
3805
  * @param backtest - Whether running in backtest mode
3778
3806
  * @returns Unique string key for memoization
3779
3807
  */
3780
- const CREATE_KEY_FN$b = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
3808
+ const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
3809
+ const parts = [symbol, strategyName, exchangeName];
3810
+ if (frameName)
3811
+ parts.push(frameName);
3812
+ parts.push(backtest ? "backtest" : "live");
3813
+ return parts.join(":");
3814
+ };
3781
3815
  /**
3782
3816
  * Callback function for emitting ping events to pingSubject.
3783
3817
  *
@@ -3826,32 +3860,34 @@ class StrategyConnectionService {
3826
3860
  this.strategySchemaService = inject(TYPES.strategySchemaService);
3827
3861
  this.riskConnectionService = inject(TYPES.riskConnectionService);
3828
3862
  this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
3829
- this.methodContextService = inject(TYPES.methodContextService);
3830
3863
  this.partialConnectionService = inject(TYPES.partialConnectionService);
3831
3864
  /**
3832
- * Retrieves memoized ClientStrategy instance for given symbol-strategy pair.
3865
+ * Retrieves memoized ClientStrategy instance for given symbol-strategy pair with exchange and frame isolation.
3833
3866
  *
3834
3867
  * Creates ClientStrategy on first call, returns cached instance on subsequent calls.
3835
- * Cache key is symbol:strategyName string.
3868
+ * Cache key includes exchangeName and frameName for proper isolation.
3836
3869
  *
3837
3870
  * @param symbol - Trading pair symbol
3838
3871
  * @param strategyName - Name of registered strategy schema
3872
+ * @param exchangeName - Exchange name
3873
+ * @param frameName - Frame name (empty string for live)
3874
+ * @param backtest - Whether running in backtest mode
3839
3875
  * @returns Configured ClientStrategy instance
3840
3876
  */
3841
- this.getStrategy = memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, backtest), (symbol, strategyName, backtest) => {
3877
+ this.getStrategy = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
3842
3878
  const { riskName = "", riskList = [], getSignal, interval, callbacks, } = this.strategySchemaService.get(strategyName);
3843
3879
  return new ClientStrategy({
3844
3880
  symbol,
3845
3881
  interval,
3846
3882
  execution: this.executionContextService,
3847
- method: this.methodContextService,
3883
+ method: { context: { strategyName, exchangeName, frameName } },
3848
3884
  logger: this.loggerService,
3849
3885
  partial: this.partialConnectionService,
3850
3886
  exchange: this.exchangeConnectionService,
3851
3887
  risk: GET_RISK_FN({
3852
3888
  riskName,
3853
3889
  riskList,
3854
- }, backtest, this),
3890
+ }, backtest, exchangeName, frameName, this),
3855
3891
  riskName,
3856
3892
  strategyName,
3857
3893
  getSignal,
@@ -3864,38 +3900,40 @@ class StrategyConnectionService {
3864
3900
  * If no active signal exists, returns null.
3865
3901
  * Used internally for monitoring TP/SL and time expiration.
3866
3902
  *
3903
+ * @param backtest - Whether running in backtest mode
3867
3904
  * @param symbol - Trading pair symbol
3868
- * @param strategyName - Name of strategy to get pending signal for
3905
+ * @param context - Execution context with strategyName, exchangeName, frameName
3869
3906
  *
3870
3907
  * @returns Promise resolving to pending signal or null
3871
3908
  */
3872
- this.getPendingSignal = async (backtest, symbol, strategyName) => {
3909
+ this.getPendingSignal = async (backtest, symbol, context) => {
3873
3910
  this.loggerService.log("strategyConnectionService getPendingSignal", {
3874
3911
  symbol,
3875
- strategyName,
3912
+ context,
3876
3913
  backtest,
3877
3914
  });
3878
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3879
- return await strategy.getPendingSignal(symbol, strategyName);
3915
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3916
+ return await strategy.getPendingSignal(symbol);
3880
3917
  };
3881
3918
  /**
3882
3919
  * Retrieves the currently active scheduled signal for the strategy.
3883
3920
  * If no scheduled signal exists, returns null.
3884
3921
  * Used internally for monitoring scheduled signal activation.
3885
3922
  *
3923
+ * @param backtest - Whether running in backtest mode
3886
3924
  * @param symbol - Trading pair symbol
3887
- * @param strategyName - Name of strategy to get scheduled signal for
3925
+ * @param context - Execution context with strategyName, exchangeName, frameName
3888
3926
  *
3889
3927
  * @returns Promise resolving to scheduled signal or null
3890
3928
  */
3891
- this.getScheduledSignal = async (backtest, symbol, strategyName) => {
3929
+ this.getScheduledSignal = async (backtest, symbol, context) => {
3892
3930
  this.loggerService.log("strategyConnectionService getScheduledSignal", {
3893
3931
  symbol,
3894
- strategyName,
3932
+ context,
3895
3933
  backtest,
3896
3934
  });
3897
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3898
- return await strategy.getScheduledSignal(symbol, strategyName);
3935
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3936
+ return await strategy.getScheduledSignal(symbol);
3899
3937
  };
3900
3938
  /**
3901
3939
  * Retrieves the stopped state of the strategy.
@@ -3903,18 +3941,19 @@ class StrategyConnectionService {
3903
3941
  * Delegates to the underlying strategy instance to check if it has been
3904
3942
  * marked as stopped and should cease operation.
3905
3943
  *
3944
+ * @param backtest - Whether running in backtest mode
3906
3945
  * @param symbol - Trading pair symbol
3907
- * @param strategyName - Name of the strategy
3946
+ * @param context - Execution context with strategyName, exchangeName, frameName
3908
3947
  * @returns Promise resolving to true if strategy is stopped, false otherwise
3909
3948
  */
3910
- this.getStopped = async (backtest, symbol, strategyName) => {
3949
+ this.getStopped = async (backtest, symbol, context) => {
3911
3950
  this.loggerService.log("strategyConnectionService getStopped", {
3912
3951
  symbol,
3913
- strategyName,
3952
+ context,
3914
3953
  backtest,
3915
3954
  });
3916
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3917
- return await strategy.getStopped(symbol, strategyName);
3955
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3956
+ return await strategy.getStopped(symbol);
3918
3957
  };
3919
3958
  /**
3920
3959
  * Executes live trading tick for current strategy.
@@ -3923,18 +3962,19 @@ class StrategyConnectionService {
3923
3962
  * Evaluates current market conditions and returns signal state.
3924
3963
  *
3925
3964
  * @param symbol - Trading pair symbol
3926
- * @param strategyName - Name of strategy to tick
3965
+ * @param context - Execution context with strategyName, exchangeName, frameName
3927
3966
  * @returns Promise resolving to tick result (idle, opened, active, closed)
3928
3967
  */
3929
- this.tick = async (symbol, strategyName) => {
3968
+ this.tick = async (symbol, context) => {
3969
+ const backtest = this.executionContextService.context.backtest;
3930
3970
  this.loggerService.log("strategyConnectionService tick", {
3931
3971
  symbol,
3932
- strategyName,
3972
+ context,
3973
+ backtest,
3933
3974
  });
3934
- const backtest = this.executionContextService.context.backtest;
3935
- const strategy = this.getStrategy(symbol, strategyName, backtest);
3975
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3936
3976
  await strategy.waitForInit();
3937
- const tick = await strategy.tick(symbol, strategyName);
3977
+ const tick = await strategy.tick(symbol, context.strategyName);
3938
3978
  {
3939
3979
  if (this.executionContextService.context.backtest) {
3940
3980
  await signalBacktestEmitter.next(tick);
@@ -3953,24 +3993,28 @@ class StrategyConnectionService {
3953
3993
  * Evaluates strategy signals against historical data.
3954
3994
  *
3955
3995
  * @param symbol - Trading pair symbol
3956
- * @param strategyName - Name of strategy to backtest
3996
+ * @param context - Execution context with strategyName, exchangeName, frameName
3957
3997
  * @param candles - Array of historical candle data to backtest
3958
3998
  * @returns Promise resolving to backtest result (signal or idle)
3959
3999
  */
3960
- this.backtest = async (symbol, strategyName, candles) => {
4000
+ this.backtest = async (symbol, context, candles) => {
4001
+ const backtest = this.executionContextService.context.backtest;
3961
4002
  this.loggerService.log("strategyConnectionService backtest", {
3962
4003
  symbol,
3963
- strategyName,
4004
+ context,
3964
4005
  candleCount: candles.length,
4006
+ backtest,
3965
4007
  });
3966
- const backtest = this.executionContextService.context.backtest;
3967
- const strategy = this.getStrategy(symbol, strategyName, backtest);
4008
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
3968
4009
  await strategy.waitForInit();
3969
- const tick = await strategy.backtest(symbol, strategyName, candles);
4010
+ const tick = await strategy.backtest(symbol, context.strategyName, candles);
3970
4011
  {
3971
4012
  if (this.executionContextService.context.backtest) {
3972
4013
  await signalBacktestEmitter.next(tick);
3973
4014
  }
4015
+ if (!this.executionContextService.context.backtest) {
4016
+ await signalLiveEmitter.next(tick);
4017
+ }
3974
4018
  await signalEmitter.next(tick);
3975
4019
  }
3976
4020
  return tick;
@@ -3981,16 +4025,18 @@ class StrategyConnectionService {
3981
4025
  * Delegates to ClientStrategy.stop() which sets internal flag to prevent
3982
4026
  * getSignal from being called on subsequent ticks.
3983
4027
  *
4028
+ * @param backtest - Whether running in backtest mode
3984
4029
  * @param symbol - Trading pair symbol
3985
- * @param strategyName - Name of strategy to stop
4030
+ * @param ctx - Context with strategyName, exchangeName, frameName
3986
4031
  * @returns Promise that resolves when stop flag is set
3987
4032
  */
3988
- this.stop = async (backtest, ctx) => {
4033
+ this.stop = async (backtest, symbol, context) => {
3989
4034
  this.loggerService.log("strategyConnectionService stop", {
3990
- ctx,
4035
+ symbol,
4036
+ context,
3991
4037
  });
3992
- const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
3993
- await strategy.stop(ctx.symbol, ctx.strategyName, backtest);
4038
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4039
+ await strategy.stop(symbol, backtest);
3994
4040
  };
3995
4041
  /**
3996
4042
  * Clears the memoized ClientStrategy instance from cache.
@@ -3998,14 +4044,14 @@ class StrategyConnectionService {
3998
4044
  * Forces re-initialization of strategy on next getStrategy call.
3999
4045
  * Useful for resetting strategy state or releasing resources.
4000
4046
  *
4001
- * @param ctx - Optional context with symbol and strategyName (clears all if not provided)
4047
+ * @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
4002
4048
  */
4003
- this.clear = async (backtest, ctx) => {
4049
+ this.clear = async (payload) => {
4004
4050
  this.loggerService.log("strategyConnectionService clear", {
4005
- ctx,
4051
+ payload,
4006
4052
  });
4007
- if (ctx) {
4008
- const key = CREATE_KEY_FN$b(ctx.symbol, ctx.strategyName, backtest);
4053
+ if (payload) {
4054
+ const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
4009
4055
  this.getStrategy.clear(key);
4010
4056
  }
4011
4057
  else {
@@ -4022,17 +4068,19 @@ class StrategyConnectionService {
4022
4068
  * detects the scheduled signal was cancelled.
4023
4069
  *
4024
4070
  * @param backtest - Whether running in backtest mode
4025
- * @param ctx - Context with symbol and strategyName
4071
+ * @param symbol - Trading pair symbol
4072
+ * @param ctx - Context with strategyName, exchangeName, frameName
4026
4073
  * @param cancelId - Optional cancellation ID for user-initiated cancellations
4027
4074
  * @returns Promise that resolves when scheduled signal is cancelled
4028
4075
  */
4029
- this.cancel = async (backtest, ctx, cancelId) => {
4076
+ this.cancel = async (backtest, symbol, context, cancelId) => {
4030
4077
  this.loggerService.log("strategyConnectionService cancel", {
4031
- ctx,
4078
+ symbol,
4079
+ context,
4032
4080
  cancelId,
4033
4081
  });
4034
- const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
4035
- await strategy.cancel(ctx.symbol, ctx.strategyName, backtest, cancelId);
4082
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4083
+ await strategy.cancel(symbol, backtest, cancelId);
4036
4084
  };
4037
4085
  }
4038
4086
  }
@@ -4418,7 +4466,7 @@ const get = (object, path) => {
4418
4466
  /** Symbol indicating that positions need to be fetched from persistence */
4419
4467
  const POSITION_NEED_FETCH = Symbol("risk-need-fetch");
4420
4468
  /** Key generator for active position map */
4421
- const GET_KEY_FN = (strategyName, symbol) => `${strategyName}:${symbol}`;
4469
+ const CREATE_NAME_FN = (strategyName, exchangeName, symbol) => `${strategyName}_${exchangeName}_${symbol}`;
4422
4470
  /** Wrapper to execute risk validation function with error handling */
4423
4471
  const DO_VALIDATION_FN = async (validation, params) => {
4424
4472
  try {
@@ -4578,12 +4626,11 @@ class ClientRisk {
4578
4626
  if (this._activePositions === POSITION_NEED_FETCH) {
4579
4627
  await this.waitForInit();
4580
4628
  }
4581
- const key = GET_KEY_FN(context.strategyName, symbol);
4629
+ const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
4582
4630
  const riskMap = this._activePositions;
4583
4631
  riskMap.set(key, {
4584
- signal: null, // Signal details not needed for position tracking
4585
4632
  strategyName: context.strategyName,
4586
- exchangeName: "",
4633
+ exchangeName: context.exchangeName,
4587
4634
  openTimestamp: Date.now(),
4588
4635
  });
4589
4636
  await this._updatePositions();
@@ -4601,7 +4648,7 @@ class ClientRisk {
4601
4648
  if (this._activePositions === POSITION_NEED_FETCH) {
4602
4649
  await this.waitForInit();
4603
4650
  }
4604
- const key = GET_KEY_FN(context.strategyName, symbol);
4651
+ const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
4605
4652
  const riskMap = this._activePositions;
4606
4653
  riskMap.delete(key);
4607
4654
  await this._updatePositions();
@@ -4610,12 +4657,20 @@ class ClientRisk {
4610
4657
 
4611
4658
  /**
4612
4659
  * Creates a unique key for memoizing ClientRisk instances.
4613
- * Key format: "riskName:backtest" or "riskName:live"
4660
+ * Key format: "riskName:exchangeName:frameName:backtest" or "riskName:exchangeName:live"
4614
4661
  * @param riskName - Name of the risk schema
4662
+ * @param exchangeName - Exchange name
4663
+ * @param frameName - Frame name (empty string for live)
4615
4664
  * @param backtest - Whether running in backtest mode
4616
4665
  * @returns Unique string key for memoization
4617
4666
  */
4618
- const CREATE_KEY_FN$a = (riskName, backtest) => `${riskName}:${backtest ? "backtest" : "live"}`;
4667
+ const CREATE_KEY_FN$a = (riskName, exchangeName, frameName, backtest) => {
4668
+ const parts = [riskName, exchangeName];
4669
+ if (frameName)
4670
+ parts.push(frameName);
4671
+ parts.push(backtest ? "backtest" : "live");
4672
+ return parts.join(":");
4673
+ };
4619
4674
  /**
4620
4675
  * Callback function for emitting risk rejection events to riskSubject.
4621
4676
  *
@@ -4628,16 +4683,19 @@ const CREATE_KEY_FN$a = (riskName, backtest) => `${riskName}:${backtest ? "backt
4628
4683
  * @param rejectionResult - Rejection result with id and note
4629
4684
  * @param timestamp - Event timestamp in milliseconds
4630
4685
  * @param backtest - True if backtest mode, false if live mode
4686
+ * @param exchangeName - Exchange name
4687
+ * @param frameName - Frame name
4631
4688
  */
4632
- const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => await riskSubject.next({
4689
+ const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName) => await riskSubject.next({
4633
4690
  symbol,
4634
4691
  pendingSignal: params.pendingSignal,
4635
4692
  strategyName: params.strategyName,
4636
- exchangeName: params.exchangeName,
4693
+ exchangeName,
4637
4694
  currentPrice: params.currentPrice,
4638
4695
  activePositionCount,
4639
4696
  rejectionId: rejectionResult.id,
4640
4697
  rejectionNote: rejectionResult.note,
4698
+ frameName,
4641
4699
  timestamp,
4642
4700
  backtest,
4643
4701
  });
@@ -4678,22 +4736,24 @@ class RiskConnectionService {
4678
4736
  this.loggerService = inject(TYPES.loggerService);
4679
4737
  this.riskSchemaService = inject(TYPES.riskSchemaService);
4680
4738
  /**
4681
- * Retrieves memoized ClientRisk instance for given risk name and backtest mode.
4739
+ * Retrieves memoized ClientRisk instance for given risk name, exchange, frame and backtest mode.
4682
4740
  *
4683
4741
  * Creates ClientRisk on first call, returns cached instance on subsequent calls.
4684
- * Cache key is "riskName:backtest" string to separate live and backtest instances.
4742
+ * Cache key includes exchangeName and frameName to isolate risk per exchange+frame.
4685
4743
  *
4686
4744
  * @param riskName - Name of registered risk schema
4745
+ * @param exchangeName - Exchange name
4746
+ * @param frameName - Frame name (empty string for live)
4687
4747
  * @param backtest - True if backtest mode, false if live mode
4688
4748
  * @returns Configured ClientRisk instance
4689
4749
  */
4690
- this.getRisk = memoize(([riskName, backtest]) => CREATE_KEY_FN$a(riskName, backtest), (riskName, backtest) => {
4750
+ this.getRisk = memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
4691
4751
  const schema = this.riskSchemaService.get(riskName);
4692
4752
  return new ClientRisk({
4693
4753
  ...schema,
4694
4754
  logger: this.loggerService,
4695
4755
  backtest,
4696
- onRejected: COMMIT_REJECTION_FN,
4756
+ onRejected: (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => COMMIT_REJECTION_FN(symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName),
4697
4757
  });
4698
4758
  });
4699
4759
  /**
@@ -4704,57 +4764,55 @@ class RiskConnectionService {
4704
4764
  * ClientRisk will emit riskSubject event via onRejected callback when signal is rejected.
4705
4765
  *
4706
4766
  * @param params - Risk check arguments (portfolio state, position details)
4707
- * @param context - Execution context with risk name and backtest mode
4767
+ * @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
4708
4768
  * @returns Promise resolving to risk check result
4709
4769
  */
4710
- this.checkSignal = async (params, context) => {
4770
+ this.checkSignal = async (params, payload) => {
4711
4771
  this.loggerService.log("riskConnectionService checkSignal", {
4712
4772
  symbol: params.symbol,
4713
- context,
4773
+ payload,
4714
4774
  });
4715
- return await this.getRisk(context.riskName, context.backtest).checkSignal(params);
4775
+ return await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).checkSignal(params);
4716
4776
  };
4717
4777
  /**
4718
4778
  * Registers an opened signal with the risk management system.
4719
4779
  * Routes to appropriate ClientRisk instance.
4720
4780
  *
4721
4781
  * @param symbol - Trading pair symbol
4722
- * @param context - Context information (strategyName, riskName, backtest)
4782
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
4723
4783
  */
4724
- this.addSignal = async (symbol, context) => {
4784
+ this.addSignal = async (symbol, payload) => {
4725
4785
  this.loggerService.log("riskConnectionService addSignal", {
4726
4786
  symbol,
4727
- context,
4787
+ payload,
4728
4788
  });
4729
- await this.getRisk(context.riskName, context.backtest).addSignal(symbol, context);
4789
+ await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).addSignal(symbol, payload);
4730
4790
  };
4731
4791
  /**
4732
4792
  * Removes a closed signal from the risk management system.
4733
4793
  * Routes to appropriate ClientRisk instance.
4734
4794
  *
4735
4795
  * @param symbol - Trading pair symbol
4736
- * @param context - Context information (strategyName, riskName, backtest)
4796
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
4737
4797
  */
4738
- this.removeSignal = async (symbol, context) => {
4798
+ this.removeSignal = async (symbol, payload) => {
4739
4799
  this.loggerService.log("riskConnectionService removeSignal", {
4740
4800
  symbol,
4741
- context,
4801
+ payload,
4742
4802
  });
4743
- await this.getRisk(context.riskName, context.backtest).removeSignal(symbol, context);
4803
+ await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).removeSignal(symbol, payload);
4744
4804
  };
4745
4805
  /**
4746
4806
  * Clears the cached ClientRisk instance for the given risk name.
4747
4807
  *
4748
- * @param backtest - Whether running in backtest mode
4749
- * @param ctx - Optional context with riskName (clears all if not provided)
4808
+ * @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
4750
4809
  */
4751
- this.clear = async (backtest, ctx) => {
4810
+ this.clear = async (payload) => {
4752
4811
  this.loggerService.log("riskConnectionService clear", {
4753
- ctx,
4754
- backtest,
4812
+ payload,
4755
4813
  });
4756
- if (ctx) {
4757
- const key = CREATE_KEY_FN$a(ctx.riskName, backtest);
4814
+ if (payload) {
4815
+ const key = CREATE_KEY_FN$a(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
4758
4816
  this.getRisk.clear(key);
4759
4817
  }
4760
4818
  else {
@@ -4953,23 +5011,22 @@ class StrategyCoreService {
4953
5011
  this.strategySchemaService = inject(TYPES.strategySchemaService);
4954
5012
  this.riskValidationService = inject(TYPES.riskValidationService);
4955
5013
  this.strategyValidationService = inject(TYPES.strategyValidationService);
4956
- this.methodContextService = inject(TYPES.methodContextService);
4957
5014
  /**
4958
5015
  * Validates strategy and associated risk configuration.
4959
5016
  *
4960
- * Memoized to avoid redundant validations for the same symbol-strategy pair.
5017
+ * Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
4961
5018
  * Logs validation activity.
4962
5019
  * @param symbol - Trading pair symbol
4963
- * @param strategyName - Name of the strategy to validate
5020
+ * @param context - Execution context with strategyName, exchangeName, frameName
4964
5021
  * @returns Promise that resolves when validation is complete
4965
5022
  */
4966
- this.validate = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, async (symbol, strategyName) => {
5023
+ this.validate = memoize(([symbol, context]) => `${symbol}:${context.strategyName}:${context.exchangeName}:${context.frameName}`, async (symbol, context) => {
4967
5024
  this.loggerService.log(METHOD_NAME_VALIDATE, {
4968
5025
  symbol,
4969
- strategyName,
5026
+ context,
4970
5027
  });
4971
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
4972
- this.strategyValidationService.validate(strategyName, METHOD_NAME_VALIDATE);
5028
+ const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
5029
+ this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
4973
5030
  riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
4974
5031
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
4975
5032
  });
@@ -4978,34 +5035,36 @@ class StrategyCoreService {
4978
5035
  * If no active signal exists, returns null.
4979
5036
  * Used internally for monitoring TP/SL and time expiration.
4980
5037
  *
5038
+ * @param backtest - Whether running in backtest mode
4981
5039
  * @param symbol - Trading pair symbol
4982
- * @param strategyName - Name of the strategy
5040
+ * @param context - Execution context with strategyName, exchangeName, frameName
4983
5041
  * @returns Promise resolving to pending signal or null
4984
5042
  */
4985
- this.getPendingSignal = async (backtest, symbol, strategyName) => {
5043
+ this.getPendingSignal = async (backtest, symbol, context) => {
4986
5044
  this.loggerService.log("strategyCoreService getPendingSignal", {
4987
5045
  symbol,
4988
- strategyName,
5046
+ context,
4989
5047
  });
4990
- await this.validate(symbol, strategyName);
4991
- return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
5048
+ await this.validate(symbol, context);
5049
+ return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
4992
5050
  };
4993
5051
  /**
4994
5052
  * Retrieves the currently active scheduled signal for the symbol.
4995
5053
  * If no scheduled signal exists, returns null.
4996
5054
  * Used internally for monitoring scheduled signal activation.
4997
5055
  *
5056
+ * @param backtest - Whether running in backtest mode
4998
5057
  * @param symbol - Trading pair symbol
4999
- * @param strategyName - Name of the strategy
5058
+ * @param context - Execution context with strategyName, exchangeName, frameName
5000
5059
  * @returns Promise resolving to scheduled signal or null
5001
5060
  */
5002
- this.getScheduledSignal = async (backtest, symbol, strategyName) => {
5061
+ this.getScheduledSignal = async (backtest, symbol, context) => {
5003
5062
  this.loggerService.log("strategyCoreService getScheduledSignal", {
5004
5063
  symbol,
5005
- strategyName,
5064
+ context,
5006
5065
  });
5007
- await this.validate(symbol, strategyName);
5008
- return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, strategyName);
5066
+ await this.validate(symbol, context);
5067
+ return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
5009
5068
  };
5010
5069
  /**
5011
5070
  * Checks if the strategy has been stopped.
@@ -5013,18 +5072,19 @@ class StrategyCoreService {
5013
5072
  * Validates strategy existence and delegates to connection service
5014
5073
  * to retrieve the stopped state from the strategy instance.
5015
5074
  *
5075
+ * @param backtest - Whether running in backtest mode
5016
5076
  * @param symbol - Trading pair symbol
5017
- * @param strategyName - Name of the strategy
5077
+ * @param context - Execution context with strategyName, exchangeName, frameName
5018
5078
  * @returns Promise resolving to true if strategy is stopped, false otherwise
5019
5079
  */
5020
- this.getStopped = async (backtest, symbol, strategyName) => {
5080
+ this.getStopped = async (backtest, symbol, context) => {
5021
5081
  this.loggerService.log("strategyCoreService getStopped", {
5022
5082
  symbol,
5023
- strategyName,
5083
+ context,
5024
5084
  backtest,
5025
5085
  });
5026
- await this.validate(symbol, strategyName);
5027
- return await this.strategyConnectionService.getStopped(backtest, symbol, strategyName);
5086
+ await this.validate(symbol, context);
5087
+ return await this.strategyConnectionService.getStopped(backtest, symbol, context);
5028
5088
  };
5029
5089
  /**
5030
5090
  * Checks signal status at a specific timestamp.
@@ -5035,21 +5095,19 @@ class StrategyCoreService {
5035
5095
  * @param symbol - Trading pair symbol
5036
5096
  * @param when - Timestamp for tick evaluation
5037
5097
  * @param backtest - Whether running in backtest mode
5098
+ * @param context - Execution context with strategyName, exchangeName, frameName
5038
5099
  * @returns Discriminated union of tick result (idle, opened, active, closed)
5039
5100
  */
5040
- this.tick = async (symbol, when, backtest) => {
5101
+ this.tick = async (symbol, when, backtest, context) => {
5041
5102
  this.loggerService.log("strategyCoreService tick", {
5042
5103
  symbol,
5043
5104
  when,
5044
5105
  backtest,
5106
+ context,
5045
5107
  });
5046
- if (!MethodContextService.hasContext()) {
5047
- throw new Error("strategyCoreService tick requires a method context");
5048
- }
5049
- const strategyName = this.methodContextService.context.strategyName;
5050
- await this.validate(symbol, strategyName);
5108
+ await this.validate(symbol, context);
5051
5109
  return await ExecutionContextService.runInContext(async () => {
5052
- return await this.strategyConnectionService.tick(symbol, strategyName);
5110
+ return await this.strategyConnectionService.tick(symbol, context);
5053
5111
  }, {
5054
5112
  symbol,
5055
5113
  when,
@@ -5066,22 +5124,20 @@ class StrategyCoreService {
5066
5124
  * @param candles - Array of historical candles to test against
5067
5125
  * @param when - Starting timestamp for backtest
5068
5126
  * @param backtest - Whether running in backtest mode (typically true)
5127
+ * @param context - Execution context with strategyName, exchangeName, frameName
5069
5128
  * @returns Closed signal result with PNL
5070
5129
  */
5071
- this.backtest = async (symbol, candles, when, backtest) => {
5130
+ this.backtest = async (symbol, candles, when, backtest, context) => {
5072
5131
  this.loggerService.log("strategyCoreService backtest", {
5073
5132
  symbol,
5074
5133
  candleCount: candles.length,
5075
5134
  when,
5076
5135
  backtest,
5136
+ context,
5077
5137
  });
5078
- if (!MethodContextService.hasContext()) {
5079
- throw new Error("strategyCoreService backtest requires a method context");
5080
- }
5081
- const strategyName = this.methodContextService.context.strategyName;
5082
- await this.validate(symbol, strategyName);
5138
+ await this.validate(symbol, context);
5083
5139
  return await ExecutionContextService.runInContext(async () => {
5084
- return await this.strategyConnectionService.backtest(symbol, strategyName, candles);
5140
+ return await this.strategyConnectionService.backtest(symbol, context, candles);
5085
5141
  }, {
5086
5142
  symbol,
5087
5143
  when,
@@ -5094,17 +5150,19 @@ class StrategyCoreService {
5094
5150
  * Delegates to StrategyConnectionService.stop() to set internal flag.
5095
5151
  * Does not require execution context.
5096
5152
  *
5153
+ * @param backtest - Whether running in backtest mode
5097
5154
  * @param symbol - Trading pair symbol
5098
- * @param strategyName - Name of strategy to stop
5155
+ * @param ctx - Context with strategyName, exchangeName, frameName
5099
5156
  * @returns Promise that resolves when stop flag is set
5100
5157
  */
5101
- this.stop = async (backtest, ctx) => {
5158
+ this.stop = async (backtest, symbol, context) => {
5102
5159
  this.loggerService.log("strategyCoreService stop", {
5103
- ctx,
5160
+ symbol,
5161
+ context,
5104
5162
  backtest,
5105
5163
  });
5106
- await this.validate(ctx.symbol, ctx.strategyName);
5107
- return await this.strategyConnectionService.stop(backtest, ctx);
5164
+ await this.validate(symbol, context);
5165
+ return await this.strategyConnectionService.stop(backtest, symbol, context);
5108
5166
  };
5109
5167
  /**
5110
5168
  * Cancels the scheduled signal without stopping the strategy.
@@ -5114,18 +5172,20 @@ class StrategyCoreService {
5114
5172
  * Does not require execution context.
5115
5173
  *
5116
5174
  * @param backtest - Whether running in backtest mode
5117
- * @param ctx - Context with symbol and strategyName
5175
+ * @param symbol - Trading pair symbol
5176
+ * @param ctx - Context with strategyName, exchangeName, frameName
5118
5177
  * @param cancelId - Optional cancellation ID for user-initiated cancellations
5119
5178
  * @returns Promise that resolves when scheduled signal is cancelled
5120
5179
  */
5121
- this.cancel = async (backtest, ctx, cancelId) => {
5180
+ this.cancel = async (backtest, symbol, context, cancelId) => {
5122
5181
  this.loggerService.log("strategyCoreService cancel", {
5123
- ctx,
5182
+ symbol,
5183
+ context,
5124
5184
  backtest,
5125
5185
  cancelId,
5126
5186
  });
5127
- await this.validate(ctx.symbol, ctx.strategyName);
5128
- return await this.strategyConnectionService.cancel(backtest, ctx, cancelId);
5187
+ await this.validate(symbol, context);
5188
+ return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
5129
5189
  };
5130
5190
  /**
5131
5191
  * Clears the memoized ClientStrategy instance from cache.
@@ -5133,16 +5193,20 @@ class StrategyCoreService {
5133
5193
  * Delegates to StrategyConnectionService.clear() to remove strategy from cache.
5134
5194
  * Forces re-initialization of strategy on next operation.
5135
5195
  *
5136
- * @param ctx - Optional context with symbol and strategyName (clears all if not provided)
5196
+ * @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
5137
5197
  */
5138
- this.clear = async (backtest, ctx) => {
5198
+ this.clear = async (payload) => {
5139
5199
  this.loggerService.log("strategyCoreService clear", {
5140
- ctx,
5200
+ payload,
5141
5201
  });
5142
- if (ctx) {
5143
- await this.validate(ctx.symbol, ctx.strategyName);
5202
+ if (payload) {
5203
+ await this.validate(payload.symbol, {
5204
+ strategyName: payload.strategyName,
5205
+ exchangeName: payload.exchangeName,
5206
+ frameName: payload.frameName
5207
+ });
5144
5208
  }
5145
- return await this.strategyConnectionService.clear(backtest, ctx);
5209
+ return await this.strategyConnectionService.clear(payload);
5146
5210
  };
5147
5211
  }
5148
5212
  }
@@ -5223,76 +5287,74 @@ class RiskGlobalService {
5223
5287
  this.riskValidationService = inject(TYPES.riskValidationService);
5224
5288
  /**
5225
5289
  * Validates risk configuration.
5226
- * Memoized to avoid redundant validations for the same risk instance.
5290
+ * Memoized to avoid redundant validations for the same risk-exchange-frame combination.
5227
5291
  * Logs validation activity.
5228
- * @param riskName - Name of the risk instance to validate
5292
+ * @param payload - Payload with riskName, exchangeName and frameName
5229
5293
  * @returns Promise that resolves when validation is complete
5230
5294
  */
5231
- this.validate = memoize(([riskName]) => `${riskName}`, async (riskName) => {
5295
+ this.validate = memoize(([payload]) => `${payload.riskName}:${payload.exchangeName}:${payload.frameName}`, async (payload) => {
5232
5296
  this.loggerService.log("riskGlobalService validate", {
5233
- riskName,
5297
+ payload,
5234
5298
  });
5235
- this.riskValidationService.validate(riskName, "riskGlobalService validate");
5299
+ this.riskValidationService.validate(payload.riskName, "riskGlobalService validate");
5236
5300
  });
5237
5301
  /**
5238
5302
  * Checks if a signal should be allowed based on risk limits.
5239
5303
  *
5240
5304
  * @param params - Risk check arguments (portfolio state, position details)
5241
- * @param context - Execution context with risk name
5305
+ * @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
5242
5306
  * @returns Promise resolving to risk check result
5243
5307
  */
5244
- this.checkSignal = async (params, context) => {
5308
+ this.checkSignal = async (params, payload) => {
5245
5309
  this.loggerService.log("riskGlobalService checkSignal", {
5246
5310
  symbol: params.symbol,
5247
- context,
5311
+ payload,
5248
5312
  });
5249
- await this.validate(context.riskName);
5250
- return await this.riskConnectionService.checkSignal(params, context);
5313
+ await this.validate(payload);
5314
+ return await this.riskConnectionService.checkSignal(params, payload);
5251
5315
  };
5252
5316
  /**
5253
5317
  * Registers an opened signal with the risk management system.
5254
5318
  *
5255
5319
  * @param symbol - Trading pair symbol
5256
- * @param context - Context information (strategyName, riskName)
5320
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
5257
5321
  */
5258
- this.addSignal = async (symbol, context) => {
5322
+ this.addSignal = async (symbol, payload) => {
5259
5323
  this.loggerService.log("riskGlobalService addSignal", {
5260
5324
  symbol,
5261
- context,
5325
+ payload,
5262
5326
  });
5263
- await this.validate(context.riskName);
5264
- await this.riskConnectionService.addSignal(symbol, context);
5327
+ await this.validate(payload);
5328
+ await this.riskConnectionService.addSignal(symbol, payload);
5265
5329
  };
5266
5330
  /**
5267
5331
  * Removes a closed signal from the risk management system.
5268
5332
  *
5269
5333
  * @param symbol - Trading pair symbol
5270
- * @param context - Context information (strategyName, riskName)
5334
+ * @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
5271
5335
  */
5272
- this.removeSignal = async (symbol, context) => {
5336
+ this.removeSignal = async (symbol, payload) => {
5273
5337
  this.loggerService.log("riskGlobalService removeSignal", {
5274
5338
  symbol,
5275
- context,
5339
+ payload,
5276
5340
  });
5277
- await this.validate(context.riskName);
5278
- await this.riskConnectionService.removeSignal(symbol, context);
5341
+ await this.validate(payload);
5342
+ await this.riskConnectionService.removeSignal(symbol, payload);
5279
5343
  };
5280
5344
  /**
5281
5345
  * Clears risk data.
5282
- * If ctx is provided, clears data for that specific risk instance.
5283
- * If no ctx is provided, clears all risk data.
5284
- * @param backtest - Whether running in backtest mode
5285
- * @param ctx - Optional context with riskName (clears all if not provided)
5346
+ * If payload is provided, clears data for that specific risk instance.
5347
+ * If no payload is provided, clears all risk data.
5348
+ * @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
5286
5349
  */
5287
- this.clear = async (backtest, ctx) => {
5350
+ this.clear = async (payload) => {
5288
5351
  this.loggerService.log("riskGlobalService clear", {
5289
- ctx,
5290
- backtest,
5352
+ payload,
5291
5353
  });
5292
- if (ctx) {
5293
- await this.validate(ctx.riskName);
5354
+ if (payload) {
5355
+ await this.validate(payload);
5294
5356
  }
5295
- return await this.riskConnectionService.clear(backtest, ctx);
5357
+ return await this.riskConnectionService.clear(payload);
5296
5358
  };
5297
5359
  }
5298
5360
  }
@@ -5843,7 +5905,11 @@ class BacktestLogicPrivateService {
5843
5905
  });
5844
5906
  }
5845
5907
  // Check if strategy should stop before processing next frame
5846
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
5908
+ if (await this.strategyCoreService.getStopped(true, symbol, {
5909
+ strategyName: this.methodContextService.context.strategyName,
5910
+ exchangeName: this.methodContextService.context.exchangeName,
5911
+ frameName: this.methodContextService.context.frameName,
5912
+ })) {
5847
5913
  this.loggerService.info("backtestLogicPrivateService stopped by user request (before tick)", {
5848
5914
  symbol,
5849
5915
  when: when.toISOString(),
@@ -5854,7 +5920,11 @@ class BacktestLogicPrivateService {
5854
5920
  }
5855
5921
  let result;
5856
5922
  try {
5857
- result = await this.strategyCoreService.tick(symbol, when, true);
5923
+ result = await this.strategyCoreService.tick(symbol, when, true, {
5924
+ strategyName: this.methodContextService.context.strategyName,
5925
+ exchangeName: this.methodContextService.context.exchangeName,
5926
+ frameName: this.methodContextService.context.frameName,
5927
+ });
5858
5928
  }
5859
5929
  catch (error) {
5860
5930
  console.warn(`backtestLogicPrivateService tick failed, skipping timeframe when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -5868,7 +5938,11 @@ class BacktestLogicPrivateService {
5868
5938
  continue;
5869
5939
  }
5870
5940
  // Check if strategy should stop when idle (no active signal)
5871
- if (await and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName))) {
5941
+ if (await and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, {
5942
+ strategyName: this.methodContextService.context.strategyName,
5943
+ exchangeName: this.methodContextService.context.exchangeName,
5944
+ frameName: this.methodContextService.context.frameName,
5945
+ }))) {
5872
5946
  this.loggerService.info("backtestLogicPrivateService stopped by user request (idle state)", {
5873
5947
  symbol,
5874
5948
  when: when.toISOString(),
@@ -5927,7 +6001,11 @@ class BacktestLogicPrivateService {
5927
6001
  // и если активируется - продолжит с TP/SL мониторингом
5928
6002
  let backtestResult;
5929
6003
  try {
5930
- backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true);
6004
+ backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
6005
+ strategyName: this.methodContextService.context.strategyName,
6006
+ exchangeName: this.methodContextService.context.exchangeName,
6007
+ frameName: this.methodContextService.context.frameName,
6008
+ });
5931
6009
  }
5932
6010
  catch (error) {
5933
6011
  console.warn(`backtestLogicPrivateService backtest failed for scheduled signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -5959,6 +6037,7 @@ class BacktestLogicPrivateService {
5959
6037
  duration: signalEndTime - signalStartTime,
5960
6038
  strategyName: this.methodContextService.context.strategyName,
5961
6039
  exchangeName: this.methodContextService.context.exchangeName,
6040
+ frameName: this.methodContextService.context.frameName,
5962
6041
  symbol,
5963
6042
  backtest: true,
5964
6043
  });
@@ -5970,7 +6049,11 @@ class BacktestLogicPrivateService {
5970
6049
  }
5971
6050
  yield backtestResult;
5972
6051
  // Check if strategy should stop after signal is closed
5973
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
6052
+ if (await this.strategyCoreService.getStopped(true, symbol, {
6053
+ strategyName: this.methodContextService.context.strategyName,
6054
+ exchangeName: this.methodContextService.context.exchangeName,
6055
+ frameName: this.methodContextService.context.frameName,
6056
+ })) {
5974
6057
  this.loggerService.info("backtestLogicPrivateService stopped by user request (after scheduled signal closed)", {
5975
6058
  symbol,
5976
6059
  signalId: backtestResult.signal.id,
@@ -6024,7 +6107,11 @@ class BacktestLogicPrivateService {
6024
6107
  // Вызываем backtest - всегда возвращает closed
6025
6108
  let backtestResult;
6026
6109
  try {
6027
- backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true);
6110
+ backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
6111
+ strategyName: this.methodContextService.context.strategyName,
6112
+ exchangeName: this.methodContextService.context.exchangeName,
6113
+ frameName: this.methodContextService.context.frameName,
6114
+ });
6028
6115
  }
6029
6116
  catch (error) {
6030
6117
  console.warn(`backtestLogicPrivateService backtest failed for opened signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -6052,6 +6139,7 @@ class BacktestLogicPrivateService {
6052
6139
  duration: signalEndTime - signalStartTime,
6053
6140
  strategyName: this.methodContextService.context.strategyName,
6054
6141
  exchangeName: this.methodContextService.context.exchangeName,
6142
+ frameName: this.methodContextService.context.frameName,
6055
6143
  symbol,
6056
6144
  backtest: true,
6057
6145
  });
@@ -6063,7 +6151,11 @@ class BacktestLogicPrivateService {
6063
6151
  }
6064
6152
  yield backtestResult;
6065
6153
  // Check if strategy should stop after signal is closed
6066
- if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
6154
+ if (await this.strategyCoreService.getStopped(true, symbol, {
6155
+ strategyName: this.methodContextService.context.strategyName,
6156
+ exchangeName: this.methodContextService.context.exchangeName,
6157
+ frameName: this.methodContextService.context.frameName,
6158
+ })) {
6067
6159
  this.loggerService.info("backtestLogicPrivateService stopped by user request (after signal closed)", {
6068
6160
  symbol,
6069
6161
  signalId: backtestResult.signal.id,
@@ -6083,6 +6175,7 @@ class BacktestLogicPrivateService {
6083
6175
  duration: timeframeEndTime - timeframeStartTime,
6084
6176
  strategyName: this.methodContextService.context.strategyName,
6085
6177
  exchangeName: this.methodContextService.context.exchangeName,
6178
+ frameName: this.methodContextService.context.frameName,
6086
6179
  symbol,
6087
6180
  backtest: true,
6088
6181
  });
@@ -6110,6 +6203,7 @@ class BacktestLogicPrivateService {
6110
6203
  duration: backtestEndTime - backtestStartTime,
6111
6204
  strategyName: this.methodContextService.context.strategyName,
6112
6205
  exchangeName: this.methodContextService.context.exchangeName,
6206
+ frameName: this.methodContextService.context.frameName,
6113
6207
  symbol,
6114
6208
  backtest: true,
6115
6209
  });
@@ -6172,7 +6266,11 @@ class LiveLogicPrivateService {
6172
6266
  const when = new Date();
6173
6267
  let result;
6174
6268
  try {
6175
- result = await this.strategyCoreService.tick(symbol, when, false);
6269
+ result = await this.strategyCoreService.tick(symbol, when, false, {
6270
+ strategyName: this.methodContextService.context.strategyName,
6271
+ exchangeName: this.methodContextService.context.exchangeName,
6272
+ frameName: this.methodContextService.context.frameName,
6273
+ });
6176
6274
  }
6177
6275
  catch (error) {
6178
6276
  console.warn(`backtestLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
@@ -6200,13 +6298,18 @@ class LiveLogicPrivateService {
6200
6298
  duration: tickEndTime - tickStartTime,
6201
6299
  strategyName: this.methodContextService.context.strategyName,
6202
6300
  exchangeName: this.methodContextService.context.exchangeName,
6301
+ frameName: this.methodContextService.context.frameName,
6203
6302
  symbol,
6204
6303
  backtest: false,
6205
6304
  });
6206
6305
  previousEventTimestamp = currentTimestamp;
6207
6306
  // Check if strategy should stop when idle (no active signal)
6208
6307
  if (result.action === "idle") {
6209
- if (await and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName))) {
6308
+ if (await and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, {
6309
+ strategyName: this.methodContextService.context.strategyName,
6310
+ exchangeName: this.methodContextService.context.exchangeName,
6311
+ frameName: this.methodContextService.context.frameName,
6312
+ }))) {
6210
6313
  this.loggerService.info("liveLogicPrivateService stopped by user request (idle state)", {
6211
6314
  symbol,
6212
6315
  when: when.toISOString(),
@@ -6228,7 +6331,11 @@ class LiveLogicPrivateService {
6228
6331
  yield result;
6229
6332
  // Check if strategy should stop after signal is closed
6230
6333
  if (result.action === "closed") {
6231
- if (await this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName)) {
6334
+ if (await this.strategyCoreService.getStopped(false, symbol, {
6335
+ strategyName: this.methodContextService.context.strategyName,
6336
+ exchangeName: this.methodContextService.context.exchangeName,
6337
+ frameName: this.methodContextService.context.frameName,
6338
+ })) {
6232
6339
  this.loggerService.info("liveLogicPrivateService stopped by user request (after signal closed)", {
6233
6340
  symbol,
6234
6341
  signalId: result.signal.id,
@@ -6360,7 +6467,7 @@ class WalkerLogicPrivateService {
6360
6467
  symbol,
6361
6468
  });
6362
6469
  // Get statistics from BacktestMarkdownService
6363
- const stats = await this.backtestMarkdownService.getData(symbol, strategyName, true);
6470
+ const stats = await this.backtestMarkdownService.getData(symbol, strategyName, context.exchangeName, context.frameName, true);
6364
6471
  // Extract metric value
6365
6472
  const value = stats[metric];
6366
6473
  const metricValue = value !== null &&
@@ -6424,7 +6531,7 @@ class WalkerLogicPrivateService {
6424
6531
  bestStrategy,
6425
6532
  bestMetric,
6426
6533
  bestStats: bestStrategy !== null
6427
- ? await this.backtestMarkdownService.getData(symbol, bestStrategy, true)
6534
+ ? await this.backtestMarkdownService.getData(symbol, bestStrategy, context.exchangeName, context.frameName, true)
6428
6535
  : null,
6429
6536
  };
6430
6537
  // Call onComplete callback if provided with final best results
@@ -7787,13 +7894,21 @@ const DEFAULT_COLUMNS = Object.freeze({ ...COLUMN_CONFIG });
7787
7894
 
7788
7895
  /**
7789
7896
  * Creates a unique key for memoizing ReportStorage instances.
7790
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
7897
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
7791
7898
  * @param symbol - Trading pair symbol
7792
7899
  * @param strategyName - Name of the strategy
7900
+ * @param exchangeName - Exchange name
7901
+ * @param frameName - Frame name
7793
7902
  * @param backtest - Whether running in backtest mode
7794
7903
  * @returns Unique string key for memoization
7795
7904
  */
7796
- const CREATE_KEY_FN$9 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
7905
+ const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
7906
+ const parts = [symbol, strategyName, exchangeName];
7907
+ if (frameName)
7908
+ parts.push(frameName);
7909
+ parts.push(backtest ? "backtest" : "live");
7910
+ return parts.join(":");
7911
+ };
7797
7912
  /**
7798
7913
  * Checks if a value is unsafe for display (not a number, NaN, or Infinity).
7799
7914
  *
@@ -7999,17 +8114,17 @@ class BacktestMarkdownService {
7999
8114
  /** Logger service for debug output */
8000
8115
  this.loggerService = inject(TYPES.loggerService);
8001
8116
  /**
8002
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
8003
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
8117
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
8118
+ * Each combination gets its own isolated storage instance.
8004
8119
  */
8005
- this.getStorage = memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, backtest), () => new ReportStorage$5());
8120
+ this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$5());
8006
8121
  /**
8007
8122
  * Processes tick events and accumulates closed signals.
8008
8123
  * Should be called from IStrategyCallbacks.onTick.
8009
8124
  *
8010
8125
  * Only processes closed signals - opened signals are ignored.
8011
8126
  *
8012
- * @param data - Tick result from strategy execution (opened or closed)
8127
+ * @param data - Tick result from strategy execution (opened or closed) with frameName wrapper
8013
8128
  *
8014
8129
  * @example
8015
8130
  * ```typescript
@@ -8029,7 +8144,7 @@ class BacktestMarkdownService {
8029
8144
  if (data.action !== "closed") {
8030
8145
  return;
8031
8146
  }
8032
- const storage = this.getStorage(data.symbol, data.strategyName, true);
8147
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, true);
8033
8148
  storage.addSignal(data);
8034
8149
  };
8035
8150
  /**
@@ -8038,23 +8153,27 @@ class BacktestMarkdownService {
8038
8153
  *
8039
8154
  * @param symbol - Trading pair symbol
8040
8155
  * @param strategyName - Strategy name to get data for
8156
+ * @param exchangeName - Exchange name
8157
+ * @param frameName - Frame name
8041
8158
  * @param backtest - True if backtest mode, false if live mode
8042
8159
  * @returns Statistical data object with all metrics
8043
8160
  *
8044
8161
  * @example
8045
8162
  * ```typescript
8046
8163
  * const service = new BacktestMarkdownService();
8047
- * const stats = await service.getData("BTCUSDT", "my-strategy", true);
8164
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", true);
8048
8165
  * console.log(stats.sharpeRatio, stats.winRate);
8049
8166
  * ```
8050
8167
  */
8051
- this.getData = async (symbol, strategyName, backtest) => {
8168
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8052
8169
  this.loggerService.log("backtestMarkdownService getData", {
8053
8170
  symbol,
8054
8171
  strategyName,
8172
+ exchangeName,
8173
+ frameName,
8055
8174
  backtest,
8056
8175
  });
8057
- const storage = this.getStorage(symbol, strategyName, backtest);
8176
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8058
8177
  return storage.getData();
8059
8178
  };
8060
8179
  /**
@@ -8063,6 +8182,8 @@ class BacktestMarkdownService {
8063
8182
  *
8064
8183
  * @param symbol - Trading pair symbol
8065
8184
  * @param strategyName - Strategy name to generate report for
8185
+ * @param exchangeName - Exchange name
8186
+ * @param frameName - Frame name
8066
8187
  * @param backtest - True if backtest mode, false if live mode
8067
8188
  * @param columns - Column configuration for formatting the table
8068
8189
  * @returns Markdown formatted report string with table of all closed signals
@@ -8070,17 +8191,19 @@ class BacktestMarkdownService {
8070
8191
  * @example
8071
8192
  * ```typescript
8072
8193
  * const service = new BacktestMarkdownService();
8073
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", true);
8194
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", true);
8074
8195
  * console.log(markdown);
8075
8196
  * ```
8076
8197
  */
8077
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
8198
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
8078
8199
  this.loggerService.log("backtestMarkdownService getReport", {
8079
8200
  symbol,
8080
8201
  strategyName,
8202
+ exchangeName,
8203
+ frameName,
8081
8204
  backtest,
8082
8205
  });
8083
- const storage = this.getStorage(symbol, strategyName, backtest);
8206
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8084
8207
  return storage.getReport(strategyName, columns);
8085
8208
  };
8086
8209
  /**
@@ -8090,6 +8213,8 @@ class BacktestMarkdownService {
8090
8213
  *
8091
8214
  * @param symbol - Trading pair symbol
8092
8215
  * @param strategyName - Strategy name to save report for
8216
+ * @param exchangeName - Exchange name
8217
+ * @param frameName - Frame name
8093
8218
  * @param backtest - True if backtest mode, false if live mode
8094
8219
  * @param path - Directory path to save report (default: "./dump/backtest")
8095
8220
  * @param columns - Column configuration for formatting the table
@@ -8099,48 +8224,48 @@ class BacktestMarkdownService {
8099
8224
  * const service = new BacktestMarkdownService();
8100
8225
  *
8101
8226
  * // Save to default path: ./dump/backtest/my-strategy.md
8102
- * await service.dump("BTCUSDT", "my-strategy", true);
8227
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true);
8103
8228
  *
8104
8229
  * // Save to custom path: ./custom/path/my-strategy.md
8105
- * await service.dump("BTCUSDT", "my-strategy", true, "./custom/path");
8230
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true, "./custom/path");
8106
8231
  * ```
8107
8232
  */
8108
- this.dump = async (symbol, strategyName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
8233
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
8109
8234
  this.loggerService.log("backtestMarkdownService dump", {
8110
8235
  symbol,
8111
8236
  strategyName,
8237
+ exchangeName,
8238
+ frameName,
8112
8239
  backtest,
8113
8240
  path,
8114
8241
  });
8115
- const storage = this.getStorage(symbol, strategyName, backtest);
8242
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8116
8243
  await storage.dump(strategyName, path, columns);
8117
8244
  };
8118
8245
  /**
8119
8246
  * Clears accumulated signal data from storage.
8120
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
8247
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
8121
8248
  * If nothing is provided, clears all data.
8122
8249
  *
8123
- * @param backtest - Backtest mode flag
8124
- * @param ctx - Optional context with symbol and strategyName
8250
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
8125
8251
  *
8126
8252
  * @example
8127
8253
  * ```typescript
8128
8254
  * const service = new BacktestMarkdownService();
8129
8255
  *
8130
- * // Clear specific symbol-strategy-backtest triple
8131
- * await service.clear(true, { symbol: "BTCUSDT", strategyName: "my-strategy" });
8256
+ * // Clear specific combination
8257
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: true });
8132
8258
  *
8133
8259
  * // Clear all data
8134
8260
  * await service.clear();
8135
8261
  * ```
8136
8262
  */
8137
- this.clear = async (backtest, ctx) => {
8263
+ this.clear = async (payload) => {
8138
8264
  this.loggerService.log("backtestMarkdownService clear", {
8139
- backtest,
8140
- ctx,
8265
+ payload,
8141
8266
  });
8142
- if (ctx) {
8143
- const key = CREATE_KEY_FN$9(ctx.symbol, ctx.strategyName, backtest);
8267
+ if (payload) {
8268
+ const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
8144
8269
  this.getStorage.clear(key);
8145
8270
  }
8146
8271
  else {
@@ -8167,13 +8292,21 @@ class BacktestMarkdownService {
8167
8292
 
8168
8293
  /**
8169
8294
  * Creates a unique key for memoizing ReportStorage instances.
8170
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
8295
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
8171
8296
  * @param symbol - Trading pair symbol
8172
8297
  * @param strategyName - Name of the strategy
8298
+ * @param exchangeName - Exchange name
8299
+ * @param frameName - Frame name
8173
8300
  * @param backtest - Whether running in backtest mode
8174
8301
  * @returns Unique string key for memoization
8175
8302
  */
8176
- const CREATE_KEY_FN$8 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
8303
+ const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
8304
+ const parts = [symbol, strategyName, exchangeName];
8305
+ if (frameName)
8306
+ parts.push(frameName);
8307
+ parts.push(backtest ? "backtest" : "live");
8308
+ return parts.join(":");
8309
+ };
8177
8310
  /**
8178
8311
  * Checks if a value is unsafe for display (not a number, NaN, or Infinity).
8179
8312
  *
@@ -8500,17 +8633,17 @@ class LiveMarkdownService {
8500
8633
  /** Logger service for debug output */
8501
8634
  this.loggerService = inject(TYPES.loggerService);
8502
8635
  /**
8503
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
8504
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
8636
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
8637
+ * Each combination gets its own isolated storage instance.
8505
8638
  */
8506
- this.getStorage = memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, backtest), () => new ReportStorage$4());
8639
+ this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$4());
8507
8640
  /**
8508
8641
  * Processes tick events and accumulates all event types.
8509
8642
  * Should be called from IStrategyCallbacks.onTick.
8510
8643
  *
8511
8644
  * Processes all event types: idle, opened, active, closed.
8512
8645
  *
8513
- * @param data - Tick result from strategy execution
8646
+ * @param data - Tick result from strategy execution with frameName wrapper
8514
8647
  *
8515
8648
  * @example
8516
8649
  * ```typescript
@@ -8529,7 +8662,7 @@ class LiveMarkdownService {
8529
8662
  this.loggerService.log("liveMarkdownService tick", {
8530
8663
  data,
8531
8664
  });
8532
- const storage = this.getStorage(data.symbol, data.strategyName, false);
8665
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, false);
8533
8666
  if (data.action === "idle") {
8534
8667
  storage.addIdleEvent(data.currentPrice);
8535
8668
  }
@@ -8549,23 +8682,27 @@ class LiveMarkdownService {
8549
8682
  *
8550
8683
  * @param symbol - Trading pair symbol
8551
8684
  * @param strategyName - Strategy name to get data for
8685
+ * @param exchangeName - Exchange name
8686
+ * @param frameName - Frame name
8552
8687
  * @param backtest - True if backtest mode, false if live mode
8553
8688
  * @returns Statistical data object with all metrics
8554
8689
  *
8555
8690
  * @example
8556
8691
  * ```typescript
8557
8692
  * const service = new LiveMarkdownService();
8558
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
8693
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
8559
8694
  * console.log(stats.sharpeRatio, stats.winRate);
8560
8695
  * ```
8561
8696
  */
8562
- this.getData = async (symbol, strategyName, backtest) => {
8697
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8563
8698
  this.loggerService.log("liveMarkdownService getData", {
8564
8699
  symbol,
8565
8700
  strategyName,
8701
+ exchangeName,
8702
+ frameName,
8566
8703
  backtest,
8567
8704
  });
8568
- const storage = this.getStorage(symbol, strategyName, backtest);
8705
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8569
8706
  return storage.getData();
8570
8707
  };
8571
8708
  /**
@@ -8574,6 +8711,8 @@ class LiveMarkdownService {
8574
8711
  *
8575
8712
  * @param symbol - Trading pair symbol
8576
8713
  * @param strategyName - Strategy name to generate report for
8714
+ * @param exchangeName - Exchange name
8715
+ * @param frameName - Frame name
8577
8716
  * @param backtest - True if backtest mode, false if live mode
8578
8717
  * @param columns - Column configuration for formatting the table
8579
8718
  * @returns Markdown formatted report string with table of all events
@@ -8581,17 +8720,19 @@ class LiveMarkdownService {
8581
8720
  * @example
8582
8721
  * ```typescript
8583
8722
  * const service = new LiveMarkdownService();
8584
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
8723
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
8585
8724
  * console.log(markdown);
8586
8725
  * ```
8587
8726
  */
8588
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.live_columns) => {
8727
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.live_columns) => {
8589
8728
  this.loggerService.log("liveMarkdownService getReport", {
8590
8729
  symbol,
8591
8730
  strategyName,
8731
+ exchangeName,
8732
+ frameName,
8592
8733
  backtest,
8593
8734
  });
8594
- const storage = this.getStorage(symbol, strategyName, backtest);
8735
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8595
8736
  return storage.getReport(strategyName, columns);
8596
8737
  };
8597
8738
  /**
@@ -8601,6 +8742,8 @@ class LiveMarkdownService {
8601
8742
  *
8602
8743
  * @param symbol - Trading pair symbol
8603
8744
  * @param strategyName - Strategy name to save report for
8745
+ * @param exchangeName - Exchange name
8746
+ * @param frameName - Frame name
8604
8747
  * @param backtest - True if backtest mode, false if live mode
8605
8748
  * @param path - Directory path to save report (default: "./dump/live")
8606
8749
  * @param columns - Column configuration for formatting the table
@@ -8610,48 +8753,48 @@ class LiveMarkdownService {
8610
8753
  * const service = new LiveMarkdownService();
8611
8754
  *
8612
8755
  * // Save to default path: ./dump/live/my-strategy.md
8613
- * await service.dump("BTCUSDT", "my-strategy", false);
8756
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
8614
8757
  *
8615
8758
  * // Save to custom path: ./custom/path/my-strategy.md
8616
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
8759
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
8617
8760
  * ```
8618
8761
  */
8619
- this.dump = async (symbol, strategyName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
8762
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
8620
8763
  this.loggerService.log("liveMarkdownService dump", {
8621
8764
  symbol,
8622
8765
  strategyName,
8766
+ exchangeName,
8767
+ frameName,
8623
8768
  backtest,
8624
8769
  path,
8625
8770
  });
8626
- const storage = this.getStorage(symbol, strategyName, backtest);
8771
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8627
8772
  await storage.dump(strategyName, path, columns);
8628
8773
  };
8629
8774
  /**
8630
8775
  * Clears accumulated event data from storage.
8631
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
8776
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
8632
8777
  * If nothing is provided, clears all data.
8633
8778
  *
8634
- * @param backtest - Backtest mode flag
8635
- * @param ctx - Optional context with symbol and strategyName
8779
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
8636
8780
  *
8637
8781
  * @example
8638
8782
  * ```typescript
8639
8783
  * const service = new LiveMarkdownService();
8640
8784
  *
8641
- * // Clear specific symbol-strategy-backtest triple
8642
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
8785
+ * // Clear specific combination
8786
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
8643
8787
  *
8644
8788
  * // Clear all data
8645
8789
  * await service.clear();
8646
8790
  * ```
8647
8791
  */
8648
- this.clear = async (backtest, ctx) => {
8792
+ this.clear = async (payload) => {
8649
8793
  this.loggerService.log("liveMarkdownService clear", {
8650
- backtest,
8651
- ctx,
8794
+ payload,
8652
8795
  });
8653
- if (ctx) {
8654
- const key = CREATE_KEY_FN$8(ctx.symbol, ctx.strategyName, backtest);
8796
+ if (payload) {
8797
+ const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
8655
8798
  this.getStorage.clear(key);
8656
8799
  }
8657
8800
  else {
@@ -8678,13 +8821,21 @@ class LiveMarkdownService {
8678
8821
 
8679
8822
  /**
8680
8823
  * Creates a unique key for memoizing ReportStorage instances.
8681
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
8824
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
8682
8825
  * @param symbol - Trading pair symbol
8683
8826
  * @param strategyName - Name of the strategy
8827
+ * @param exchangeName - Exchange name
8828
+ * @param frameName - Frame name
8684
8829
  * @param backtest - Whether running in backtest mode
8685
8830
  * @returns Unique string key for memoization
8686
8831
  */
8687
- const CREATE_KEY_FN$7 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
8832
+ const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
8833
+ const parts = [symbol, strategyName, exchangeName];
8834
+ if (frameName)
8835
+ parts.push(frameName);
8836
+ parts.push(backtest ? "backtest" : "live");
8837
+ return parts.join(":");
8838
+ };
8688
8839
  /** Maximum number of events to store in schedule reports */
8689
8840
  const MAX_EVENTS$4 = 250;
8690
8841
  /**
@@ -8917,17 +9068,17 @@ class ScheduleMarkdownService {
8917
9068
  /** Logger service for debug output */
8918
9069
  this.loggerService = inject(TYPES.loggerService);
8919
9070
  /**
8920
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
8921
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
9071
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
9072
+ * Each combination gets its own isolated storage instance.
8922
9073
  */
8923
- this.getStorage = memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, backtest), () => new ReportStorage$3());
9074
+ this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$3());
8924
9075
  /**
8925
9076
  * Processes tick events and accumulates scheduled/opened/cancelled events.
8926
9077
  * Should be called from signalEmitter subscription.
8927
9078
  *
8928
9079
  * Processes only scheduled, opened and cancelled event types.
8929
9080
  *
8930
- * @param data - Tick result from strategy execution
9081
+ * @param data - Tick result from strategy execution with frameName wrapper
8931
9082
  *
8932
9083
  * @example
8933
9084
  * ```typescript
@@ -8939,7 +9090,7 @@ class ScheduleMarkdownService {
8939
9090
  this.loggerService.log("scheduleMarkdownService tick", {
8940
9091
  data,
8941
9092
  });
8942
- const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
9093
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
8943
9094
  if (data.action === "scheduled") {
8944
9095
  storage.addScheduledEvent(data);
8945
9096
  }
@@ -8960,23 +9111,27 @@ class ScheduleMarkdownService {
8960
9111
  *
8961
9112
  * @param symbol - Trading pair symbol
8962
9113
  * @param strategyName - Strategy name to get data for
9114
+ * @param exchangeName - Exchange name
9115
+ * @param frameName - Frame name
8963
9116
  * @param backtest - True if backtest mode, false if live mode
8964
9117
  * @returns Statistical data object with all metrics
8965
9118
  *
8966
9119
  * @example
8967
9120
  * ```typescript
8968
9121
  * const service = new ScheduleMarkdownService();
8969
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
9122
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
8970
9123
  * console.log(stats.cancellationRate, stats.avgWaitTime);
8971
9124
  * ```
8972
9125
  */
8973
- this.getData = async (symbol, strategyName, backtest) => {
9126
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
8974
9127
  this.loggerService.log("scheduleMarkdownService getData", {
8975
9128
  symbol,
8976
9129
  strategyName,
9130
+ exchangeName,
9131
+ frameName,
8977
9132
  backtest,
8978
9133
  });
8979
- const storage = this.getStorage(symbol, strategyName, backtest);
9134
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
8980
9135
  return storage.getData();
8981
9136
  };
8982
9137
  /**
@@ -8985,6 +9140,8 @@ class ScheduleMarkdownService {
8985
9140
  *
8986
9141
  * @param symbol - Trading pair symbol
8987
9142
  * @param strategyName - Strategy name to generate report for
9143
+ * @param exchangeName - Exchange name
9144
+ * @param frameName - Frame name
8988
9145
  * @param backtest - True if backtest mode, false if live mode
8989
9146
  * @param columns - Column configuration for formatting the table
8990
9147
  * @returns Markdown formatted report string with table of all events
@@ -8992,17 +9149,19 @@ class ScheduleMarkdownService {
8992
9149
  * @example
8993
9150
  * ```typescript
8994
9151
  * const service = new ScheduleMarkdownService();
8995
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
9152
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
8996
9153
  * console.log(markdown);
8997
9154
  * ```
8998
9155
  */
8999
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
9156
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
9000
9157
  this.loggerService.log("scheduleMarkdownService getReport", {
9001
9158
  symbol,
9002
9159
  strategyName,
9160
+ exchangeName,
9161
+ frameName,
9003
9162
  backtest,
9004
9163
  });
9005
- const storage = this.getStorage(symbol, strategyName, backtest);
9164
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9006
9165
  return storage.getReport(strategyName, columns);
9007
9166
  };
9008
9167
  /**
@@ -9012,6 +9171,8 @@ class ScheduleMarkdownService {
9012
9171
  *
9013
9172
  * @param symbol - Trading pair symbol
9014
9173
  * @param strategyName - Strategy name to save report for
9174
+ * @param exchangeName - Exchange name
9175
+ * @param frameName - Frame name
9015
9176
  * @param backtest - True if backtest mode, false if live mode
9016
9177
  * @param path - Directory path to save report (default: "./dump/schedule")
9017
9178
  * @param columns - Column configuration for formatting the table
@@ -9021,48 +9182,48 @@ class ScheduleMarkdownService {
9021
9182
  * const service = new ScheduleMarkdownService();
9022
9183
  *
9023
9184
  * // Save to default path: ./dump/schedule/my-strategy.md
9024
- * await service.dump("BTCUSDT", "my-strategy", false);
9185
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
9025
9186
  *
9026
9187
  * // Save to custom path: ./custom/path/my-strategy.md
9027
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
9188
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
9028
9189
  * ```
9029
9190
  */
9030
- this.dump = async (symbol, strategyName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
9191
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
9031
9192
  this.loggerService.log("scheduleMarkdownService dump", {
9032
9193
  symbol,
9033
9194
  strategyName,
9195
+ exchangeName,
9196
+ frameName,
9034
9197
  backtest,
9035
9198
  path,
9036
9199
  });
9037
- const storage = this.getStorage(symbol, strategyName, backtest);
9200
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9038
9201
  await storage.dump(strategyName, path, columns);
9039
9202
  };
9040
9203
  /**
9041
9204
  * Clears accumulated event data from storage.
9042
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
9205
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
9043
9206
  * If nothing is provided, clears all data.
9044
9207
  *
9045
- * @param backtest - Backtest mode flag
9046
- * @param ctx - Optional context with symbol and strategyName
9208
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
9047
9209
  *
9048
9210
  * @example
9049
9211
  * ```typescript
9050
9212
  * const service = new ScheduleMarkdownService();
9051
9213
  *
9052
- * // Clear specific symbol-strategy-backtest triple
9053
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
9214
+ * // Clear specific combination
9215
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
9054
9216
  *
9055
9217
  * // Clear all data
9056
9218
  * await service.clear();
9057
9219
  * ```
9058
9220
  */
9059
- this.clear = async (backtest, ctx) => {
9221
+ this.clear = async (payload) => {
9060
9222
  this.loggerService.log("scheduleMarkdownService clear", {
9061
- backtest,
9062
- ctx,
9223
+ payload,
9063
9224
  });
9064
- if (ctx) {
9065
- const key = CREATE_KEY_FN$7(ctx.symbol, ctx.strategyName, backtest);
9225
+ if (payload) {
9226
+ const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
9066
9227
  this.getStorage.clear(key);
9067
9228
  }
9068
9229
  else {
@@ -9089,13 +9250,21 @@ class ScheduleMarkdownService {
9089
9250
 
9090
9251
  /**
9091
9252
  * Creates a unique key for memoizing PerformanceStorage instances.
9092
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
9253
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
9093
9254
  * @param symbol - Trading pair symbol
9094
9255
  * @param strategyName - Name of the strategy
9256
+ * @param exchangeName - Exchange name
9257
+ * @param frameName - Frame name
9095
9258
  * @param backtest - Whether running in backtest mode
9096
9259
  * @returns Unique string key for memoization
9097
9260
  */
9098
- const CREATE_KEY_FN$6 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
9261
+ const CREATE_KEY_FN$6 = (symbol, strategyName, exchangeName, frameName, backtest) => {
9262
+ const parts = [symbol, strategyName, exchangeName];
9263
+ if (frameName)
9264
+ parts.push(frameName);
9265
+ parts.push(backtest ? "backtest" : "live");
9266
+ return parts.join(":");
9267
+ };
9099
9268
  /**
9100
9269
  * Calculates percentile value from sorted array.
9101
9270
  */
@@ -9310,10 +9479,10 @@ class PerformanceMarkdownService {
9310
9479
  /** Logger service for debug output */
9311
9480
  this.loggerService = inject(TYPES.loggerService);
9312
9481
  /**
9313
- * Memoized function to get or create PerformanceStorage for a symbol-strategy-backtest triple.
9314
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
9482
+ * Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
9483
+ * Each combination gets its own isolated storage instance.
9315
9484
  */
9316
- this.getStorage = memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, backtest), () => new PerformanceStorage());
9485
+ this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, exchangeName, frameName, backtest), () => new PerformanceStorage());
9317
9486
  /**
9318
9487
  * Processes performance events and accumulates metrics.
9319
9488
  * Should be called from performance tracking code.
@@ -9326,7 +9495,8 @@ class PerformanceMarkdownService {
9326
9495
  });
9327
9496
  const symbol = event.symbol || "global";
9328
9497
  const strategyName = event.strategyName || "global";
9329
- const storage = this.getStorage(symbol, strategyName, event.backtest);
9498
+ const exchangeName = event.exchangeName || "global";
9499
+ const storage = this.getStorage(symbol, strategyName, exchangeName, event.frameName, event.backtest);
9330
9500
  storage.addEvent(event);
9331
9501
  };
9332
9502
  /**
@@ -9334,24 +9504,28 @@ class PerformanceMarkdownService {
9334
9504
  *
9335
9505
  * @param symbol - Trading pair symbol
9336
9506
  * @param strategyName - Strategy name to get data for
9507
+ * @param exchangeName - Exchange name
9508
+ * @param frameName - Frame name
9337
9509
  * @param backtest - True if backtest mode, false if live mode
9338
9510
  * @returns Performance statistics with aggregated metrics
9339
9511
  *
9340
9512
  * @example
9341
9513
  * ```typescript
9342
- * const stats = await performanceService.getData("BTCUSDT", "my-strategy", false);
9514
+ * const stats = await performanceService.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
9343
9515
  * console.log("Total time:", stats.totalDuration);
9344
9516
  * console.log("Slowest operation:", Object.values(stats.metricStats)
9345
9517
  * .sort((a, b) => b.avgDuration - a.avgDuration)[0]);
9346
9518
  * ```
9347
9519
  */
9348
- this.getData = async (symbol, strategyName, backtest) => {
9520
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
9349
9521
  this.loggerService.log("performanceMarkdownService getData", {
9350
9522
  symbol,
9351
9523
  strategyName,
9524
+ exchangeName,
9525
+ frameName,
9352
9526
  backtest,
9353
9527
  });
9354
- const storage = this.getStorage(symbol, strategyName, backtest);
9528
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9355
9529
  return storage.getData(strategyName);
9356
9530
  };
9357
9531
  /**
@@ -9359,23 +9533,27 @@ class PerformanceMarkdownService {
9359
9533
  *
9360
9534
  * @param symbol - Trading pair symbol
9361
9535
  * @param strategyName - Strategy name to generate report for
9536
+ * @param exchangeName - Exchange name
9537
+ * @param frameName - Frame name
9362
9538
  * @param backtest - True if backtest mode, false if live mode
9363
9539
  * @param columns - Column configuration for formatting the table
9364
9540
  * @returns Markdown formatted report string
9365
9541
  *
9366
9542
  * @example
9367
9543
  * ```typescript
9368
- * const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", false);
9544
+ * const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
9369
9545
  * console.log(markdown);
9370
9546
  * ```
9371
9547
  */
9372
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
9548
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
9373
9549
  this.loggerService.log("performanceMarkdownService getReport", {
9374
9550
  symbol,
9375
9551
  strategyName,
9552
+ exchangeName,
9553
+ frameName,
9376
9554
  backtest,
9377
9555
  });
9378
- const storage = this.getStorage(symbol, strategyName, backtest);
9556
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9379
9557
  return storage.getReport(strategyName, columns);
9380
9558
  };
9381
9559
  /**
@@ -9383,6 +9561,8 @@ class PerformanceMarkdownService {
9383
9561
  *
9384
9562
  * @param symbol - Trading pair symbol
9385
9563
  * @param strategyName - Strategy name to save report for
9564
+ * @param exchangeName - Exchange name
9565
+ * @param frameName - Frame name
9386
9566
  * @param backtest - True if backtest mode, false if live mode
9387
9567
  * @param path - Directory path to save report
9388
9568
  * @param columns - Column configuration for formatting the table
@@ -9390,35 +9570,35 @@ class PerformanceMarkdownService {
9390
9570
  * @example
9391
9571
  * ```typescript
9392
9572
  * // Save to default path: ./dump/performance/my-strategy.md
9393
- * await performanceService.dump("BTCUSDT", "my-strategy", false);
9573
+ * await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
9394
9574
  *
9395
9575
  * // Save to custom path
9396
- * await performanceService.dump("BTCUSDT", "my-strategy", false, "./custom/path");
9576
+ * await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
9397
9577
  * ```
9398
9578
  */
9399
- this.dump = async (symbol, strategyName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
9579
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
9400
9580
  this.loggerService.log("performanceMarkdownService dump", {
9401
9581
  symbol,
9402
9582
  strategyName,
9583
+ exchangeName,
9584
+ frameName,
9403
9585
  backtest,
9404
9586
  path,
9405
9587
  });
9406
- const storage = this.getStorage(symbol, strategyName, backtest);
9588
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
9407
9589
  await storage.dump(strategyName, path, columns);
9408
9590
  };
9409
9591
  /**
9410
9592
  * Clears accumulated performance data from storage.
9411
9593
  *
9412
- * @param backtest - Backtest mode flag
9413
- * @param ctx - Optional context with symbol and strategyName
9594
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
9414
9595
  */
9415
- this.clear = async (backtest, ctx) => {
9596
+ this.clear = async (payload) => {
9416
9597
  this.loggerService.log("performanceMarkdownService clear", {
9417
- backtest,
9418
- ctx,
9598
+ payload,
9419
9599
  });
9420
- if (ctx) {
9421
- const key = CREATE_KEY_FN$6(ctx.symbol, ctx.strategyName, backtest);
9600
+ if (payload) {
9601
+ const key = CREATE_KEY_FN$6(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
9422
9602
  this.getStorage.clear(key);
9423
9603
  }
9424
9604
  else {
@@ -9847,12 +10027,19 @@ class WalkerMarkdownService {
9847
10027
 
9848
10028
  /**
9849
10029
  * Creates a unique key for memoizing HeatmapStorage instances.
9850
- * Key format: "strategyName:backtest" or "strategyName:live"
9851
- * @param strategyName - Name of the strategy
10030
+ * Key format: "exchangeName:frameName:backtest" or "exchangeName:live"
10031
+ * @param exchangeName - Exchange name
10032
+ * @param frameName - Frame name
9852
10033
  * @param backtest - Whether running in backtest mode
9853
10034
  * @returns Unique string key for memoization
9854
10035
  */
9855
- const CREATE_KEY_FN$5 = (strategyName, backtest) => `${strategyName}:${backtest ? "backtest" : "live"}`;
10036
+ const CREATE_KEY_FN$5 = (exchangeName, frameName, backtest) => {
10037
+ const parts = [exchangeName];
10038
+ if (frameName)
10039
+ parts.push(frameName);
10040
+ parts.push(backtest ? "backtest" : "live");
10041
+ return parts.join(":");
10042
+ };
9856
10043
  const HEATMAP_METHOD_NAME_GET_DATA = "HeatMarkdownService.getData";
9857
10044
  const HEATMAP_METHOD_NAME_GET_REPORT = "HeatMarkdownService.getReport";
9858
10045
  const HEATMAP_METHOD_NAME_DUMP = "HeatMarkdownService.dump";
@@ -10193,10 +10380,10 @@ class HeatMarkdownService {
10193
10380
  /** Logger service for debug output */
10194
10381
  this.loggerService = inject(TYPES.loggerService);
10195
10382
  /**
10196
- * Memoized function to get or create HeatmapStorage for a strategy and backtest mode.
10197
- * Each strategy + backtest mode combination gets its own isolated heatmap storage instance.
10383
+ * Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
10384
+ * Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
10198
10385
  */
10199
- this.getStorage = memoize(([strategyName, backtest]) => CREATE_KEY_FN$5(strategyName, backtest), () => new HeatmapStorage());
10386
+ this.getStorage = memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$5(exchangeName, frameName, backtest), () => new HeatmapStorage());
10200
10387
  /**
10201
10388
  * Processes tick events and accumulates closed signals.
10202
10389
  * Should be called from signal emitter subscription.
@@ -10212,20 +10399,21 @@ class HeatMarkdownService {
10212
10399
  if (data.action !== "closed") {
10213
10400
  return;
10214
10401
  }
10215
- const storage = this.getStorage(data.strategyName, data.backtest);
10402
+ const storage = this.getStorage(data.exchangeName, data.frameName, data.backtest);
10216
10403
  storage.addSignal(data);
10217
10404
  };
10218
10405
  /**
10219
- * Gets aggregated portfolio heatmap statistics for a strategy.
10406
+ * Gets aggregated portfolio heatmap statistics.
10220
10407
  *
10221
- * @param strategyName - Strategy name to get heatmap data for
10408
+ * @param exchangeName - Exchange name
10409
+ * @param frameName - Frame name
10222
10410
  * @param backtest - True if backtest mode, false if live mode
10223
10411
  * @returns Promise resolving to heatmap statistics with per-symbol and portfolio-wide metrics
10224
10412
  *
10225
10413
  * @example
10226
10414
  * ```typescript
10227
10415
  * const service = new HeatMarkdownService();
10228
- * const stats = await service.getData("my-strategy", true);
10416
+ * const stats = await service.getData("binance", "frame1", true);
10229
10417
  *
10230
10418
  * console.log(`Total symbols: ${stats.totalSymbols}`);
10231
10419
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
@@ -10235,18 +10423,21 @@ class HeatMarkdownService {
10235
10423
  * });
10236
10424
  * ```
10237
10425
  */
10238
- this.getData = async (strategyName, backtest) => {
10426
+ this.getData = async (exchangeName, frameName, backtest) => {
10239
10427
  this.loggerService.log(HEATMAP_METHOD_NAME_GET_DATA, {
10240
- strategyName,
10428
+ exchangeName,
10429
+ frameName,
10241
10430
  backtest,
10242
10431
  });
10243
- const storage = this.getStorage(strategyName, backtest);
10432
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10244
10433
  return storage.getData();
10245
10434
  };
10246
10435
  /**
10247
- * Generates markdown report with portfolio heatmap table for a strategy.
10436
+ * Generates markdown report with portfolio heatmap table.
10248
10437
  *
10249
- * @param strategyName - Strategy name to generate heatmap report for
10438
+ * @param strategyName - Strategy name for report title
10439
+ * @param exchangeName - Exchange name
10440
+ * @param frameName - Frame name
10250
10441
  * @param backtest - True if backtest mode, false if live mode
10251
10442
  * @param columns - Column configuration for formatting the table
10252
10443
  * @returns Promise resolving to markdown formatted report string
@@ -10254,7 +10445,7 @@ class HeatMarkdownService {
10254
10445
  * @example
10255
10446
  * ```typescript
10256
10447
  * const service = new HeatMarkdownService();
10257
- * const markdown = await service.getReport("my-strategy", true);
10448
+ * const markdown = await service.getReport("my-strategy", "binance", "frame1", true);
10258
10449
  * console.log(markdown);
10259
10450
  * // Output:
10260
10451
  * // # Portfolio Heatmap: my-strategy
@@ -10268,21 +10459,25 @@ class HeatMarkdownService {
10268
10459
  * // ...
10269
10460
  * ```
10270
10461
  */
10271
- this.getReport = async (strategyName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
10462
+ this.getReport = async (strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
10272
10463
  this.loggerService.log(HEATMAP_METHOD_NAME_GET_REPORT, {
10273
10464
  strategyName,
10465
+ exchangeName,
10466
+ frameName,
10274
10467
  backtest,
10275
10468
  });
10276
- const storage = this.getStorage(strategyName, backtest);
10469
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10277
10470
  return storage.getReport(strategyName, columns);
10278
10471
  };
10279
10472
  /**
10280
- * Saves heatmap report to disk for a strategy.
10473
+ * Saves heatmap report to disk.
10281
10474
  *
10282
10475
  * Creates directory if it doesn't exist.
10283
10476
  * Default filename: {strategyName}.md
10284
10477
  *
10285
- * @param strategyName - Strategy name to save heatmap report for
10478
+ * @param strategyName - Strategy name for report filename
10479
+ * @param exchangeName - Exchange name
10480
+ * @param frameName - Frame name
10286
10481
  * @param backtest - True if backtest mode, false if live mode
10287
10482
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
10288
10483
  * @param columns - Column configuration for formatting the table
@@ -10292,47 +10487,47 @@ class HeatMarkdownService {
10292
10487
  * const service = new HeatMarkdownService();
10293
10488
  *
10294
10489
  * // Save to default path: ./dump/heatmap/my-strategy.md
10295
- * await service.dump("my-strategy", true);
10490
+ * await service.dump("my-strategy", "binance", "frame1", true);
10296
10491
  *
10297
10492
  * // Save to custom path: ./reports/my-strategy.md
10298
- * await service.dump("my-strategy", true, "./reports");
10493
+ * await service.dump("my-strategy", "binance", "frame1", true, "./reports");
10299
10494
  * ```
10300
10495
  */
10301
- this.dump = async (strategyName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
10496
+ this.dump = async (strategyName, exchangeName, frameName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
10302
10497
  this.loggerService.log(HEATMAP_METHOD_NAME_DUMP, {
10303
10498
  strategyName,
10499
+ exchangeName,
10500
+ frameName,
10304
10501
  backtest,
10305
10502
  path,
10306
10503
  });
10307
- const storage = this.getStorage(strategyName, backtest);
10504
+ const storage = this.getStorage(exchangeName, frameName, backtest);
10308
10505
  await storage.dump(strategyName, path, columns);
10309
10506
  };
10310
10507
  /**
10311
10508
  * Clears accumulated heatmap data from storage.
10312
- * If ctx is provided, clears only that strategy+backtest combination's data.
10313
- * If ctx is omitted, clears all data.
10509
+ * If payload is provided, clears only that exchangeName+frameName+backtest combination's data.
10510
+ * If payload is omitted, clears all data.
10314
10511
  *
10315
- * @param backtest - Backtest mode flag
10316
- * @param ctx - Optional context with strategyName to clear specific data
10512
+ * @param payload - Optional payload with exchangeName, frameName, backtest to clear specific data
10317
10513
  *
10318
10514
  * @example
10319
10515
  * ```typescript
10320
10516
  * const service = new HeatMarkdownService();
10321
10517
  *
10322
- * // Clear specific strategy+backtest data
10323
- * await service.clear(true, { strategyName: "my-strategy" });
10518
+ * // Clear specific exchange+frame+backtest data
10519
+ * await service.clear({ exchangeName: "binance", frameName: "frame1", backtest: true });
10324
10520
  *
10325
10521
  * // Clear all data
10326
10522
  * await service.clear();
10327
10523
  * ```
10328
10524
  */
10329
- this.clear = async (backtest, ctx) => {
10525
+ this.clear = async (payload) => {
10330
10526
  this.loggerService.log(HEATMAP_METHOD_NAME_CLEAR, {
10331
- backtest,
10332
- ctx,
10527
+ payload,
10333
10528
  });
10334
- if (ctx) {
10335
- const key = CREATE_KEY_FN$5(ctx.strategyName, backtest);
10529
+ if (payload) {
10530
+ const key = CREATE_KEY_FN$5(payload.exchangeName, payload.frameName, payload.backtest);
10336
10531
  this.getStorage.clear(key);
10337
10532
  }
10338
10533
  else {
@@ -12190,7 +12385,7 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
12190
12385
  revenuePercent,
12191
12386
  backtest,
12192
12387
  });
12193
- await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
12388
+ await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
12194
12389
  }
12195
12390
  }
12196
12391
  if (shouldPersist) {
@@ -12240,7 +12435,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
12240
12435
  lossPercent,
12241
12436
  backtest,
12242
12437
  });
12243
- await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
12438
+ await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
12244
12439
  }
12245
12440
  }
12246
12441
  if (shouldPersist) {
@@ -12566,10 +12761,11 @@ const CREATE_KEY_FN$4 = (signalId, backtest) => `${signalId}:${backtest ? "backt
12566
12761
  * @param backtest - True if backtest mode
12567
12762
  * @param timestamp - Event timestamp in milliseconds
12568
12763
  */
12569
- const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
12764
+ const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
12570
12765
  symbol,
12571
12766
  strategyName,
12572
12767
  exchangeName,
12768
+ frameName,
12573
12769
  data,
12574
12770
  currentPrice,
12575
12771
  level,
@@ -12591,10 +12787,11 @@ const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, curren
12591
12787
  * @param backtest - True if backtest mode
12592
12788
  * @param timestamp - Event timestamp in milliseconds
12593
12789
  */
12594
- const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
12790
+ const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
12595
12791
  symbol,
12596
12792
  strategyName,
12597
12793
  exchangeName,
12794
+ frameName,
12598
12795
  data,
12599
12796
  currentPrice,
12600
12797
  level,
@@ -12746,11 +12943,21 @@ class PartialConnectionService {
12746
12943
 
12747
12944
  /**
12748
12945
  * Creates a unique key for memoizing ReportStorage instances.
12749
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
12750
- * @param param0 - Tuple of symbol, strategyName and backtest boolean
12946
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
12947
+ * @param symbol - Trading pair symbol
12948
+ * @param strategyName - Name of the strategy
12949
+ * @param exchangeName - Exchange name
12950
+ * @param frameName - Frame name
12951
+ * @param backtest - Whether running in backtest mode
12751
12952
  * @returns Unique string key for memoization
12752
12953
  */
12753
- const CREATE_KEY_FN$3 = ([symbol, strategyName, backtest]) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
12954
+ const CREATE_KEY_FN$3 = (symbol, strategyName, exchangeName, frameName, backtest) => {
12955
+ const parts = [symbol, strategyName, exchangeName];
12956
+ if (frameName)
12957
+ parts.push(frameName);
12958
+ parts.push(backtest ? "backtest" : "live");
12959
+ return parts.join(":");
12960
+ };
12754
12961
  /** Maximum number of events to store in partial reports */
12755
12962
  const MAX_EVENTS$1 = 250;
12756
12963
  /**
@@ -12922,15 +13129,15 @@ class PartialMarkdownService {
12922
13129
  /** Logger service for debug output */
12923
13130
  this.loggerService = inject(TYPES.loggerService);
12924
13131
  /**
12925
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
12926
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
13132
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
13133
+ * Each combination gets its own isolated storage instance.
12927
13134
  */
12928
- this.getStorage = memoize(CREATE_KEY_FN$3, () => new ReportStorage$1());
13135
+ this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$3(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$1());
12929
13136
  /**
12930
13137
  * Processes profit events and accumulates them.
12931
13138
  * Should be called from partialProfitSubject subscription.
12932
13139
  *
12933
- * @param data - Profit event data
13140
+ * @param data - Profit event data with frameName wrapper
12934
13141
  *
12935
13142
  * @example
12936
13143
  * ```typescript
@@ -12942,14 +13149,14 @@ class PartialMarkdownService {
12942
13149
  this.loggerService.log("partialMarkdownService tickProfit", {
12943
13150
  data,
12944
13151
  });
12945
- const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
13152
+ const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
12946
13153
  storage.addProfitEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
12947
13154
  };
12948
13155
  /**
12949
13156
  * Processes loss events and accumulates them.
12950
13157
  * Should be called from partialLossSubject subscription.
12951
13158
  *
12952
- * @param data - Loss event data
13159
+ * @param data - Loss event data with frameName wrapper
12953
13160
  *
12954
13161
  * @example
12955
13162
  * ```typescript
@@ -12961,7 +13168,7 @@ class PartialMarkdownService {
12961
13168
  this.loggerService.log("partialMarkdownService tickLoss", {
12962
13169
  data,
12963
13170
  });
12964
- const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
13171
+ const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
12965
13172
  storage.addLossEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
12966
13173
  };
12967
13174
  /**
@@ -12970,23 +13177,27 @@ class PartialMarkdownService {
12970
13177
  *
12971
13178
  * @param symbol - Trading pair symbol to get data for
12972
13179
  * @param strategyName - Strategy name to get data for
13180
+ * @param exchangeName - Exchange name
13181
+ * @param frameName - Frame name
12973
13182
  * @param backtest - True if backtest mode, false if live mode
12974
13183
  * @returns Statistical data object with all metrics
12975
13184
  *
12976
13185
  * @example
12977
13186
  * ```typescript
12978
13187
  * const service = new PartialMarkdownService();
12979
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
13188
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
12980
13189
  * console.log(stats.totalProfit, stats.totalLoss);
12981
13190
  * ```
12982
13191
  */
12983
- this.getData = async (symbol, strategyName, backtest) => {
13192
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
12984
13193
  this.loggerService.log("partialMarkdownService getData", {
12985
13194
  symbol,
12986
13195
  strategyName,
13196
+ exchangeName,
13197
+ frameName,
12987
13198
  backtest,
12988
13199
  });
12989
- const storage = this.getStorage(symbol, strategyName, backtest);
13200
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
12990
13201
  return storage.getData();
12991
13202
  };
12992
13203
  /**
@@ -12995,6 +13206,8 @@ class PartialMarkdownService {
12995
13206
  *
12996
13207
  * @param symbol - Trading pair symbol to generate report for
12997
13208
  * @param strategyName - Strategy name to generate report for
13209
+ * @param exchangeName - Exchange name
13210
+ * @param frameName - Frame name
12998
13211
  * @param backtest - True if backtest mode, false if live mode
12999
13212
  * @param columns - Column configuration for formatting the table
13000
13213
  * @returns Markdown formatted report string with table of all events
@@ -13002,17 +13215,19 @@ class PartialMarkdownService {
13002
13215
  * @example
13003
13216
  * ```typescript
13004
13217
  * const service = new PartialMarkdownService();
13005
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
13218
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
13006
13219
  * console.log(markdown);
13007
13220
  * ```
13008
13221
  */
13009
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
13222
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
13010
13223
  this.loggerService.log("partialMarkdownService getReport", {
13011
13224
  symbol,
13012
13225
  strategyName,
13226
+ exchangeName,
13227
+ frameName,
13013
13228
  backtest,
13014
13229
  });
13015
- const storage = this.getStorage(symbol, strategyName, backtest);
13230
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13016
13231
  return storage.getReport(symbol, strategyName, columns);
13017
13232
  };
13018
13233
  /**
@@ -13022,6 +13237,8 @@ class PartialMarkdownService {
13022
13237
  *
13023
13238
  * @param symbol - Trading pair symbol to save report for
13024
13239
  * @param strategyName - Strategy name to save report for
13240
+ * @param exchangeName - Exchange name
13241
+ * @param frameName - Frame name
13025
13242
  * @param backtest - True if backtest mode, false if live mode
13026
13243
  * @param path - Directory path to save report (default: "./dump/partial")
13027
13244
  * @param columns - Column configuration for formatting the table
@@ -13031,48 +13248,48 @@ class PartialMarkdownService {
13031
13248
  * const service = new PartialMarkdownService();
13032
13249
  *
13033
13250
  * // Save to default path: ./dump/partial/BTCUSDT_my-strategy.md
13034
- * await service.dump("BTCUSDT", "my-strategy", false);
13251
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
13035
13252
  *
13036
13253
  * // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
13037
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
13254
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
13038
13255
  * ```
13039
13256
  */
13040
- this.dump = async (symbol, strategyName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
13257
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
13041
13258
  this.loggerService.log("partialMarkdownService dump", {
13042
13259
  symbol,
13043
13260
  strategyName,
13261
+ exchangeName,
13262
+ frameName,
13044
13263
  backtest,
13045
13264
  path,
13046
13265
  });
13047
- const storage = this.getStorage(symbol, strategyName, backtest);
13266
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13048
13267
  await storage.dump(symbol, strategyName, path, columns);
13049
13268
  };
13050
13269
  /**
13051
13270
  * Clears accumulated event data from storage.
13052
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
13271
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
13053
13272
  * If nothing is provided, clears all data.
13054
13273
  *
13055
- * @param backtest - Backtest mode flag
13056
- * @param ctx - Optional context with symbol and strategyName
13274
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
13057
13275
  *
13058
13276
  * @example
13059
13277
  * ```typescript
13060
13278
  * const service = new PartialMarkdownService();
13061
13279
  *
13062
- * // Clear specific symbol-strategy-backtest triple
13063
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
13280
+ * // Clear specific combination
13281
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
13064
13282
  *
13065
13283
  * // Clear all data
13066
13284
  * await service.clear();
13067
13285
  * ```
13068
13286
  */
13069
- this.clear = async (backtest, ctx) => {
13287
+ this.clear = async (payload) => {
13070
13288
  this.loggerService.log("partialMarkdownService clear", {
13071
- backtest,
13072
- ctx,
13289
+ payload,
13073
13290
  });
13074
- if (ctx) {
13075
- const key = CREATE_KEY_FN$3([ctx.symbol, ctx.strategyName, backtest]);
13291
+ if (payload) {
13292
+ const key = CREATE_KEY_FN$3(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
13076
13293
  this.getStorage.clear(key);
13077
13294
  }
13078
13295
  else {
@@ -13153,18 +13370,18 @@ class PartialGlobalService {
13153
13370
  this.riskValidationService = inject(TYPES.riskValidationService);
13154
13371
  /**
13155
13372
  * Validates strategy and associated risk configuration.
13156
- * Memoized to avoid redundant validations for the same strategy.
13373
+ * Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
13157
13374
  *
13158
- * @param strategyName - Name of the strategy to validate
13375
+ * @param context - Context with strategyName, exchangeName and frameName
13159
13376
  * @param methodName - Name of the calling method for error tracking
13160
13377
  */
13161
- this.validate = memoize(([strategyName]) => `${strategyName}`, (strategyName, methodName) => {
13378
+ this.validate = memoize(([context]) => `${context.strategyName}:${context.exchangeName}:${context.frameName}`, (context, methodName) => {
13162
13379
  this.loggerService.log("partialGlobalService validate", {
13163
- strategyName,
13380
+ context,
13164
13381
  methodName,
13165
13382
  });
13166
- this.strategyValidationService.validate(strategyName, methodName);
13167
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
13383
+ this.strategyValidationService.validate(context.strategyName, methodName);
13384
+ const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
13168
13385
  riskName && this.riskValidationService.validate(riskName, methodName);
13169
13386
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
13170
13387
  });
@@ -13190,7 +13407,11 @@ class PartialGlobalService {
13190
13407
  backtest,
13191
13408
  when,
13192
13409
  });
13193
- this.validate(data.strategyName, "partialGlobalService profit");
13410
+ this.validate({
13411
+ strategyName: data.strategyName,
13412
+ exchangeName: data.exchangeName,
13413
+ frameName: data.frameName
13414
+ }, "partialGlobalService profit");
13194
13415
  return await this.partialConnectionService.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
13195
13416
  };
13196
13417
  /**
@@ -13215,7 +13436,11 @@ class PartialGlobalService {
13215
13436
  backtest,
13216
13437
  when,
13217
13438
  });
13218
- this.validate(data.strategyName, "partialGlobalService loss");
13439
+ this.validate({
13440
+ strategyName: data.strategyName,
13441
+ exchangeName: data.exchangeName,
13442
+ frameName: data.frameName
13443
+ }, "partialGlobalService loss");
13219
13444
  return await this.partialConnectionService.loss(symbol, data, currentPrice, lossPercent, backtest, when);
13220
13445
  };
13221
13446
  /**
@@ -13235,7 +13460,11 @@ class PartialGlobalService {
13235
13460
  priceClose,
13236
13461
  backtest,
13237
13462
  });
13238
- this.validate(data.strategyName, "partialGlobalService clear");
13463
+ this.validate({
13464
+ strategyName: data.strategyName,
13465
+ exchangeName: data.exchangeName,
13466
+ frameName: data.frameName
13467
+ }, "partialGlobalService clear");
13239
13468
  return await this.partialConnectionService.clear(symbol, data, priceClose, backtest);
13240
13469
  };
13241
13470
  }
@@ -13245,7 +13474,7 @@ class PartialGlobalService {
13245
13474
  * Warning threshold for message size in kilobytes.
13246
13475
  * Messages exceeding this size trigger console warnings.
13247
13476
  */
13248
- const WARN_KB = 20;
13477
+ const WARN_KB = 30;
13249
13478
  /**
13250
13479
  * Internal function for dumping signal data to markdown files.
13251
13480
  * Creates a directory structure with system prompts, user messages, and LLM output.
@@ -13509,13 +13738,21 @@ class ConfigValidationService {
13509
13738
 
13510
13739
  /**
13511
13740
  * Creates a unique key for memoizing ReportStorage instances.
13512
- * Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
13741
+ * Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
13513
13742
  * @param symbol - Trading pair symbol
13514
13743
  * @param strategyName - Name of the strategy
13744
+ * @param exchangeName - Exchange name
13745
+ * @param frameName - Frame name
13515
13746
  * @param backtest - Whether running in backtest mode
13516
13747
  * @returns Unique string key for memoization
13517
13748
  */
13518
- const CREATE_KEY_FN$2 = (symbol, strategyName, backtest) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`;
13749
+ const CREATE_KEY_FN$2 = (symbol, strategyName, exchangeName, frameName, backtest) => {
13750
+ const parts = [symbol, strategyName, exchangeName];
13751
+ if (frameName)
13752
+ parts.push(frameName);
13753
+ parts.push(backtest ? "backtest" : "live");
13754
+ return parts.join(":");
13755
+ };
13519
13756
  /** Maximum number of events to store in risk reports */
13520
13757
  const MAX_EVENTS = 250;
13521
13758
  /**
@@ -13657,15 +13894,15 @@ class RiskMarkdownService {
13657
13894
  /** Logger service for debug output */
13658
13895
  this.loggerService = inject(TYPES.loggerService);
13659
13896
  /**
13660
- * Memoized function to get or create ReportStorage for a symbol-strategy-backtest triple.
13661
- * Each symbol-strategy-backtest combination gets its own isolated storage instance.
13897
+ * Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
13898
+ * Each combination gets its own isolated storage instance.
13662
13899
  */
13663
- this.getStorage = memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, backtest), () => new ReportStorage());
13900
+ this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage());
13664
13901
  /**
13665
13902
  * Processes risk rejection events and accumulates them.
13666
13903
  * Should be called from riskSubject subscription.
13667
13904
  *
13668
- * @param data - Risk rejection event data
13905
+ * @param data - Risk rejection event data with frameName wrapper
13669
13906
  *
13670
13907
  * @example
13671
13908
  * ```typescript
@@ -13677,7 +13914,7 @@ class RiskMarkdownService {
13677
13914
  this.loggerService.log("riskMarkdownService tickRejection", {
13678
13915
  data,
13679
13916
  });
13680
- const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
13917
+ const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
13681
13918
  storage.addRejectionEvent(data);
13682
13919
  };
13683
13920
  /**
@@ -13686,23 +13923,27 @@ class RiskMarkdownService {
13686
13923
  *
13687
13924
  * @param symbol - Trading pair symbol to get data for
13688
13925
  * @param strategyName - Strategy name to get data for
13926
+ * @param exchangeName - Exchange name
13927
+ * @param frameName - Frame name
13689
13928
  * @param backtest - True if backtest mode, false if live mode
13690
13929
  * @returns Statistical data object with all metrics
13691
13930
  *
13692
13931
  * @example
13693
13932
  * ```typescript
13694
13933
  * const service = new RiskMarkdownService();
13695
- * const stats = await service.getData("BTCUSDT", "my-strategy", false);
13934
+ * const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
13696
13935
  * console.log(stats.totalRejections, stats.bySymbol);
13697
13936
  * ```
13698
13937
  */
13699
- this.getData = async (symbol, strategyName, backtest) => {
13938
+ this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
13700
13939
  this.loggerService.log("riskMarkdownService getData", {
13701
13940
  symbol,
13702
13941
  strategyName,
13942
+ exchangeName,
13943
+ frameName,
13703
13944
  backtest,
13704
13945
  });
13705
- const storage = this.getStorage(symbol, strategyName, backtest);
13946
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13706
13947
  return storage.getData();
13707
13948
  };
13708
13949
  /**
@@ -13711,6 +13952,8 @@ class RiskMarkdownService {
13711
13952
  *
13712
13953
  * @param symbol - Trading pair symbol to generate report for
13713
13954
  * @param strategyName - Strategy name to generate report for
13955
+ * @param exchangeName - Exchange name
13956
+ * @param frameName - Frame name
13714
13957
  * @param backtest - True if backtest mode, false if live mode
13715
13958
  * @param columns - Column configuration for formatting the table
13716
13959
  * @returns Markdown formatted report string with table of all events
@@ -13718,17 +13961,19 @@ class RiskMarkdownService {
13718
13961
  * @example
13719
13962
  * ```typescript
13720
13963
  * const service = new RiskMarkdownService();
13721
- * const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
13964
+ * const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
13722
13965
  * console.log(markdown);
13723
13966
  * ```
13724
13967
  */
13725
- this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
13968
+ this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
13726
13969
  this.loggerService.log("riskMarkdownService getReport", {
13727
13970
  symbol,
13728
13971
  strategyName,
13972
+ exchangeName,
13973
+ frameName,
13729
13974
  backtest,
13730
13975
  });
13731
- const storage = this.getStorage(symbol, strategyName, backtest);
13976
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13732
13977
  return storage.getReport(symbol, strategyName, columns);
13733
13978
  };
13734
13979
  /**
@@ -13738,6 +13983,8 @@ class RiskMarkdownService {
13738
13983
  *
13739
13984
  * @param symbol - Trading pair symbol to save report for
13740
13985
  * @param strategyName - Strategy name to save report for
13986
+ * @param exchangeName - Exchange name
13987
+ * @param frameName - Frame name
13741
13988
  * @param backtest - True if backtest mode, false if live mode
13742
13989
  * @param path - Directory path to save report (default: "./dump/risk")
13743
13990
  * @param columns - Column configuration for formatting the table
@@ -13747,48 +13994,48 @@ class RiskMarkdownService {
13747
13994
  * const service = new RiskMarkdownService();
13748
13995
  *
13749
13996
  * // Save to default path: ./dump/risk/BTCUSDT_my-strategy.md
13750
- * await service.dump("BTCUSDT", "my-strategy", false);
13997
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
13751
13998
  *
13752
13999
  * // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
13753
- * await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
14000
+ * await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
13754
14001
  * ```
13755
14002
  */
13756
- this.dump = async (symbol, strategyName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
14003
+ this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
13757
14004
  this.loggerService.log("riskMarkdownService dump", {
13758
14005
  symbol,
13759
14006
  strategyName,
14007
+ exchangeName,
14008
+ frameName,
13760
14009
  backtest,
13761
14010
  path,
13762
14011
  });
13763
- const storage = this.getStorage(symbol, strategyName, backtest);
14012
+ const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
13764
14013
  await storage.dump(symbol, strategyName, path, columns);
13765
14014
  };
13766
14015
  /**
13767
14016
  * Clears accumulated event data from storage.
13768
- * If ctx is provided, clears only that specific symbol-strategy-backtest triple's data.
14017
+ * If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
13769
14018
  * If nothing is provided, clears all data.
13770
14019
  *
13771
- * @param backtest - Backtest mode flag
13772
- * @param ctx - Optional context with symbol and strategyName
14020
+ * @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
13773
14021
  *
13774
14022
  * @example
13775
14023
  * ```typescript
13776
14024
  * const service = new RiskMarkdownService();
13777
14025
  *
13778
- * // Clear specific symbol-strategy-backtest triple
13779
- * await service.clear(false, { symbol: "BTCUSDT", strategyName: "my-strategy" });
14026
+ * // Clear specific combination
14027
+ * await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
13780
14028
  *
13781
14029
  * // Clear all data
13782
14030
  * await service.clear();
13783
14031
  * ```
13784
14032
  */
13785
- this.clear = async (backtest, ctx) => {
14033
+ this.clear = async (payload) => {
13786
14034
  this.loggerService.log("riskMarkdownService clear", {
13787
- backtest,
13788
- ctx,
14035
+ payload,
13789
14036
  });
13790
- if (ctx) {
13791
- const key = CREATE_KEY_FN$2(ctx.symbol, ctx.strategyName, backtest);
14037
+ if (payload) {
14038
+ const key = CREATE_KEY_FN$2(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
13792
14039
  this.getStorage.clear(key);
13793
14040
  }
13794
14041
  else {
@@ -14298,10 +14545,9 @@ const CANCEL_METHOD_NAME = "strategy.cancel";
14298
14545
  * await stop("BTCUSDT", "my-strategy");
14299
14546
  * ```
14300
14547
  */
14301
- async function stop(symbol, strategyName) {
14548
+ async function stop(symbol) {
14302
14549
  backtest$1.loggerService.info(STOP_METHOD_NAME, {
14303
14550
  symbol,
14304
- strategyName,
14305
14551
  });
14306
14552
  if (!ExecutionContextService.hasContext()) {
14307
14553
  throw new Error("stop requires an execution context");
@@ -14310,7 +14556,12 @@ async function stop(symbol, strategyName) {
14310
14556
  throw new Error("stop requires a method context");
14311
14557
  }
14312
14558
  const { backtest: isBacktest } = backtest$1.executionContextService.context;
14313
- await backtest$1.strategyCoreService.stop(isBacktest, { symbol, strategyName });
14559
+ const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
14560
+ await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
14561
+ exchangeName,
14562
+ frameName,
14563
+ strategyName,
14564
+ });
14314
14565
  }
14315
14566
  /**
14316
14567
  * Cancels the scheduled signal without stopping the strategy.
@@ -14334,10 +14585,9 @@ async function stop(symbol, strategyName) {
14334
14585
  * await cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
14335
14586
  * ```
14336
14587
  */
14337
- async function cancel(symbol, strategyName, cancelId) {
14588
+ async function cancel(symbol, cancelId) {
14338
14589
  backtest$1.loggerService.info(CANCEL_METHOD_NAME, {
14339
14590
  symbol,
14340
- strategyName,
14341
14591
  cancelId,
14342
14592
  });
14343
14593
  if (!ExecutionContextService.hasContext()) {
@@ -14347,7 +14597,8 @@ async function cancel(symbol, strategyName, cancelId) {
14347
14597
  throw new Error("cancel requires a method context");
14348
14598
  }
14349
14599
  const { backtest: isBacktest } = backtest$1.executionContextService.context;
14350
- await backtest$1.strategyCoreService.cancel(isBacktest, { symbol, strategyName }, cancelId);
14600
+ const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
14601
+ await backtest$1.strategyCoreService.cancel(isBacktest, symbol, { exchangeName, frameName, strategyName }, cancelId);
14351
14602
  }
14352
14603
 
14353
14604
  /**
@@ -16494,42 +16745,73 @@ class BacktestInstance {
16494
16745
  context,
16495
16746
  });
16496
16747
  {
16497
- backtest$1.backtestMarkdownService.clear(true, {
16748
+ backtest$1.backtestMarkdownService.clear({
16498
16749
  symbol,
16499
16750
  strategyName: context.strategyName,
16751
+ exchangeName: context.exchangeName,
16752
+ frameName: context.frameName,
16753
+ backtest: true,
16500
16754
  });
16501
- backtest$1.liveMarkdownService.clear(true, {
16755
+ backtest$1.liveMarkdownService.clear({
16502
16756
  symbol,
16503
16757
  strategyName: context.strategyName,
16758
+ exchangeName: context.exchangeName,
16759
+ frameName: context.frameName,
16760
+ backtest: true,
16504
16761
  });
16505
- backtest$1.scheduleMarkdownService.clear(true, {
16762
+ backtest$1.scheduleMarkdownService.clear({
16506
16763
  symbol,
16507
16764
  strategyName: context.strategyName,
16765
+ exchangeName: context.exchangeName,
16766
+ frameName: context.frameName,
16767
+ backtest: true,
16508
16768
  });
16509
- backtest$1.performanceMarkdownService.clear(true, {
16769
+ backtest$1.performanceMarkdownService.clear({
16510
16770
  symbol,
16511
16771
  strategyName: context.strategyName,
16772
+ exchangeName: context.exchangeName,
16773
+ frameName: context.frameName,
16774
+ backtest: true,
16512
16775
  });
16513
- backtest$1.partialMarkdownService.clear(true, {
16776
+ backtest$1.partialMarkdownService.clear({
16514
16777
  symbol,
16515
16778
  strategyName: context.strategyName,
16779
+ exchangeName: context.exchangeName,
16780
+ frameName: context.frameName,
16781
+ backtest: true,
16516
16782
  });
16517
- backtest$1.riskMarkdownService.clear(true, {
16783
+ backtest$1.riskMarkdownService.clear({
16518
16784
  symbol,
16519
16785
  strategyName: context.strategyName,
16786
+ exchangeName: context.exchangeName,
16787
+ frameName: context.frameName,
16788
+ backtest: true,
16520
16789
  });
16521
16790
  }
16522
16791
  {
16523
- backtest$1.strategyCoreService.clear(true, {
16792
+ backtest$1.strategyCoreService.clear({
16524
16793
  symbol,
16525
16794
  strategyName: context.strategyName,
16795
+ exchangeName: context.exchangeName,
16796
+ frameName: context.frameName,
16797
+ backtest: true,
16526
16798
  });
16527
16799
  }
16528
16800
  {
16529
16801
  const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16530
- riskName && backtest$1.riskGlobalService.clear(true, { riskName });
16802
+ riskName && backtest$1.riskGlobalService.clear({
16803
+ riskName,
16804
+ exchangeName: context.exchangeName,
16805
+ frameName: context.frameName,
16806
+ backtest: true,
16807
+ });
16531
16808
  riskList &&
16532
- riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, { riskName }));
16809
+ riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
16810
+ riskName,
16811
+ exchangeName: context.exchangeName,
16812
+ frameName: context.frameName,
16813
+ backtest: true,
16814
+ }));
16533
16815
  }
16534
16816
  return backtest$1.backtestCommandService.run(symbol, context);
16535
16817
  };
@@ -16569,12 +16851,17 @@ class BacktestInstance {
16569
16851
  }
16570
16852
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
16571
16853
  return () => {
16572
- backtest$1.strategyCoreService.stop(true, {
16573
- symbol,
16854
+ backtest$1.strategyCoreService.stop(true, symbol, {
16574
16855
  strategyName: context.strategyName,
16856
+ exchangeName: context.exchangeName,
16857
+ frameName: context.frameName,
16575
16858
  });
16576
16859
  backtest$1.strategyCoreService
16577
- .getPendingSignal(true, symbol, context.strategyName)
16860
+ .getPendingSignal(true, symbol, {
16861
+ strategyName: context.strategyName,
16862
+ exchangeName: context.exchangeName,
16863
+ frameName: context.frameName,
16864
+ })
16578
16865
  .then(async (pendingSignal) => {
16579
16866
  if (pendingSignal) {
16580
16867
  return;
@@ -16694,16 +16981,16 @@ class BacktestUtils {
16694
16981
  * }
16695
16982
  * ```
16696
16983
  */
16697
- this.getPendingSignal = async (symbol, strategyName) => {
16698
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16984
+ this.getPendingSignal = async (symbol, context) => {
16985
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16699
16986
  {
16700
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
16987
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16701
16988
  riskName &&
16702
16989
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16703
16990
  riskList &&
16704
16991
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL));
16705
16992
  }
16706
- return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, strategyName);
16993
+ return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, context);
16707
16994
  };
16708
16995
  /**
16709
16996
  * Retrieves the currently active scheduled signal for the strategy.
@@ -16721,16 +17008,16 @@ class BacktestUtils {
16721
17008
  * }
16722
17009
  * ```
16723
17010
  */
16724
- this.getScheduledSignal = async (symbol, strategyName) => {
16725
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17011
+ this.getScheduledSignal = async (symbol, context) => {
17012
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16726
17013
  {
16727
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17014
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16728
17015
  riskName &&
16729
17016
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16730
17017
  riskList &&
16731
17018
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL));
16732
17019
  }
16733
- return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, strategyName);
17020
+ return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, context);
16734
17021
  };
16735
17022
  /**
16736
17023
  * Stops the strategy from generating new signals.
@@ -16741,24 +17028,29 @@ class BacktestUtils {
16741
17028
  *
16742
17029
  * @param symbol - Trading pair symbol
16743
17030
  * @param strategyName - Strategy name to stop
17031
+ * @param context - Execution context with exchangeName and frameName
16744
17032
  * @returns Promise that resolves when stop flag is set
16745
17033
  *
16746
17034
  * @example
16747
17035
  * ```typescript
16748
17036
  * // Stop strategy after some condition
16749
- * await Backtest.stop("BTCUSDT", "my-strategy");
17037
+ * await Backtest.stop("BTCUSDT", "my-strategy", {
17038
+ * exchangeName: "binance",
17039
+ * frameName: "frame1",
17040
+ * strategyName: "my-strategy"
17041
+ * });
16750
17042
  * ```
16751
17043
  */
16752
- this.stop = async (symbol, strategyName) => {
16753
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_STOP);
17044
+ this.stop = async (symbol, context) => {
17045
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_STOP);
16754
17046
  {
16755
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17047
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16756
17048
  riskName &&
16757
17049
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP);
16758
17050
  riskList &&
16759
17051
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP));
16760
17052
  }
16761
- await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
17053
+ await backtest$1.strategyCoreService.stop(true, symbol, context);
16762
17054
  };
16763
17055
  /**
16764
17056
  * Cancels the scheduled signal without stopping the strategy.
@@ -16769,102 +17061,126 @@ class BacktestUtils {
16769
17061
  *
16770
17062
  * @param symbol - Trading pair symbol
16771
17063
  * @param strategyName - Strategy name
17064
+ * @param context - Execution context with exchangeName and frameName
16772
17065
  * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
16773
17066
  * @returns Promise that resolves when scheduled signal is cancelled
16774
17067
  *
16775
17068
  * @example
16776
17069
  * ```typescript
16777
17070
  * // Cancel scheduled signal with custom ID
16778
- * await Backtest.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17071
+ * await Backtest.cancel("BTCUSDT", "my-strategy", {
17072
+ * exchangeName: "binance",
17073
+ * frameName: "frame1",
17074
+ * strategyName: "my-strategy"
17075
+ * }, "manual-cancel-001");
16779
17076
  * ```
16780
17077
  */
16781
- this.cancel = async (symbol, strategyName, cancelId) => {
16782
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_CANCEL);
17078
+ this.cancel = async (symbol, context, cancelId) => {
17079
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_CANCEL);
16783
17080
  {
16784
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17081
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16785
17082
  riskName &&
16786
17083
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL);
16787
17084
  riskList &&
16788
17085
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL));
16789
17086
  }
16790
- await backtest$1.strategyCoreService.cancel(true, { symbol, strategyName }, cancelId);
17087
+ await backtest$1.strategyCoreService.cancel(true, symbol, context, cancelId);
16791
17088
  };
16792
17089
  /**
16793
17090
  * Gets statistical data from all closed signals for a symbol-strategy pair.
16794
17091
  *
16795
17092
  * @param symbol - Trading pair symbol
16796
17093
  * @param strategyName - Strategy name to get data for
17094
+ * @param context - Execution context with exchangeName and frameName
16797
17095
  * @returns Promise resolving to statistical data object
16798
17096
  *
16799
17097
  * @example
16800
17098
  * ```typescript
16801
- * const stats = await Backtest.getData("BTCUSDT", "my-strategy");
17099
+ * const stats = await Backtest.getData("BTCUSDT", "my-strategy", {
17100
+ * exchangeName: "binance",
17101
+ * frameName: "frame1",
17102
+ * strategyName: "my-strategy"
17103
+ * });
16802
17104
  * console.log(stats.sharpeRatio, stats.winRate);
16803
17105
  * ```
16804
17106
  */
16805
- this.getData = async (symbol, strategyName) => {
16806
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_DATA);
17107
+ this.getData = async (symbol, context) => {
17108
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_DATA);
16807
17109
  {
16808
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17110
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16809
17111
  riskName &&
16810
17112
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA);
16811
17113
  riskList &&
16812
17114
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA));
16813
17115
  }
16814
- return await backtest$1.backtestMarkdownService.getData(symbol, strategyName, true);
17116
+ return await backtest$1.backtestMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, true);
16815
17117
  };
16816
17118
  /**
16817
17119
  * Generates markdown report with all closed signals for a symbol-strategy pair.
16818
17120
  *
16819
17121
  * @param symbol - Trading pair symbol
16820
17122
  * @param strategyName - Strategy name to generate report for
17123
+ * @param context - Execution context with exchangeName and frameName
16821
17124
  * @param columns - Optional columns configuration for the report
16822
17125
  * @returns Promise resolving to markdown formatted report string
16823
17126
  *
16824
17127
  * @example
16825
17128
  * ```typescript
16826
- * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy");
17129
+ * const markdown = await Backtest.getReport("BTCUSDT", "my-strategy", {
17130
+ * exchangeName: "binance",
17131
+ * frameName: "frame1",
17132
+ * strategyName: "my-strategy"
17133
+ * });
16827
17134
  * console.log(markdown);
16828
17135
  * ```
16829
17136
  */
16830
- this.getReport = async (symbol, strategyName, columns) => {
16831
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
17137
+ this.getReport = async (symbol, context, columns) => {
17138
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
16832
17139
  {
16833
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17140
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16834
17141
  riskName &&
16835
17142
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT);
16836
17143
  riskList &&
16837
17144
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT));
16838
17145
  }
16839
- return await backtest$1.backtestMarkdownService.getReport(symbol, strategyName, true, columns);
17146
+ return await backtest$1.backtestMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, true, columns);
16840
17147
  };
16841
17148
  /**
16842
17149
  * Saves strategy report to disk.
16843
17150
  *
16844
17151
  * @param symbol - Trading pair symbol
16845
17152
  * @param strategyName - Strategy name to save report for
17153
+ * @param context - Execution context with exchangeName and frameName
16846
17154
  * @param path - Optional directory path to save report (default: "./dump/backtest")
16847
17155
  * @param columns - Optional columns configuration for the report
16848
17156
  *
16849
17157
  * @example
16850
17158
  * ```typescript
16851
17159
  * // Save to default path: ./dump/backtest/my-strategy.md
16852
- * await Backtest.dump("BTCUSDT", "my-strategy");
17160
+ * await Backtest.dump("BTCUSDT", "my-strategy", {
17161
+ * exchangeName: "binance",
17162
+ * frameName: "frame1",
17163
+ * strategyName: "my-strategy"
17164
+ * });
16853
17165
  *
16854
17166
  * // Save to custom path: ./custom/path/my-strategy.md
16855
- * await Backtest.dump("BTCUSDT", "my-strategy", "./custom/path");
17167
+ * await Backtest.dump("BTCUSDT", "my-strategy", {
17168
+ * exchangeName: "binance",
17169
+ * frameName: "frame1",
17170
+ * strategyName: "my-strategy"
17171
+ * }, "./custom/path");
16856
17172
  * ```
16857
17173
  */
16858
- this.dump = async (symbol, strategyName, path, columns) => {
16859
- backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_DUMP);
17174
+ this.dump = async (symbol, context, path, columns) => {
17175
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_DUMP);
16860
17176
  {
16861
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17177
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
16862
17178
  riskName &&
16863
17179
  backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP);
16864
17180
  riskList &&
16865
17181
  riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP));
16866
17182
  }
16867
- await backtest$1.backtestMarkdownService.dump(symbol, strategyName, true, path, columns);
17183
+ await backtest$1.backtestMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, true, path, columns);
16868
17184
  };
16869
17185
  /**
16870
17186
  * Lists all active backtest instances with their current status.
@@ -17039,20 +17355,36 @@ class LiveInstance {
17039
17355
  context,
17040
17356
  });
17041
17357
  {
17042
- backtest$1.backtestMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17043
- backtest$1.liveMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17044
- backtest$1.scheduleMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17045
- backtest$1.performanceMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17046
- backtest$1.partialMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17047
- backtest$1.riskMarkdownService.clear(false, { symbol, strategyName: context.strategyName });
17358
+ backtest$1.backtestMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17359
+ backtest$1.liveMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17360
+ backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17361
+ backtest$1.performanceMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17362
+ backtest$1.partialMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17363
+ backtest$1.riskMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
17048
17364
  }
17049
17365
  {
17050
- backtest$1.strategyCoreService.clear(false, { symbol, strategyName: context.strategyName });
17366
+ backtest$1.strategyCoreService.clear({
17367
+ symbol,
17368
+ strategyName: context.strategyName,
17369
+ exchangeName: context.exchangeName,
17370
+ frameName: "",
17371
+ backtest: false,
17372
+ });
17051
17373
  }
17052
17374
  {
17053
17375
  const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17054
- riskName && backtest$1.riskGlobalService.clear(false, { riskName });
17055
- riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(false, { riskName }));
17376
+ riskName && backtest$1.riskGlobalService.clear({
17377
+ riskName,
17378
+ exchangeName: context.exchangeName,
17379
+ frameName: "",
17380
+ backtest: false
17381
+ });
17382
+ riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
17383
+ riskName,
17384
+ exchangeName: context.exchangeName,
17385
+ frameName: "",
17386
+ backtest: false
17387
+ }));
17056
17388
  }
17057
17389
  return backtest$1.liveCommandService.run(symbol, context);
17058
17390
  };
@@ -17092,9 +17424,17 @@ class LiveInstance {
17092
17424
  }
17093
17425
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
17094
17426
  return () => {
17095
- backtest$1.strategyCoreService.stop(false, { symbol, strategyName: context.strategyName });
17427
+ backtest$1.strategyCoreService.stop(false, symbol, {
17428
+ strategyName: context.strategyName,
17429
+ exchangeName: context.exchangeName,
17430
+ frameName: ""
17431
+ });
17096
17432
  backtest$1.strategyCoreService
17097
- .getPendingSignal(false, symbol, context.strategyName)
17433
+ .getPendingSignal(false, symbol, {
17434
+ strategyName: context.strategyName,
17435
+ exchangeName: context.exchangeName,
17436
+ frameName: "",
17437
+ })
17098
17438
  .then(async (pendingSignal) => {
17099
17439
  if (pendingSignal) {
17100
17440
  return;
@@ -17221,14 +17561,18 @@ class LiveUtils {
17221
17561
  * }
17222
17562
  * ```
17223
17563
  */
17224
- this.getPendingSignal = async (symbol, strategyName) => {
17225
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17564
+ this.getPendingSignal = async (symbol, context) => {
17565
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17226
17566
  {
17227
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17567
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17228
17568
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17229
17569
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL));
17230
17570
  }
17231
- return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, strategyName);
17571
+ return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, {
17572
+ strategyName: context.strategyName,
17573
+ exchangeName: context.exchangeName,
17574
+ frameName: "",
17575
+ });
17232
17576
  };
17233
17577
  /**
17234
17578
  * Retrieves the currently active scheduled signal for the strategy.
@@ -17246,14 +17590,18 @@ class LiveUtils {
17246
17590
  * }
17247
17591
  * ```
17248
17592
  */
17249
- this.getScheduledSignal = async (symbol, strategyName) => {
17250
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17593
+ this.getScheduledSignal = async (symbol, context) => {
17594
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17251
17595
  {
17252
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17596
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17253
17597
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17254
17598
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL));
17255
17599
  }
17256
- return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, strategyName);
17600
+ return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, {
17601
+ strategyName: context.strategyName,
17602
+ exchangeName: context.exchangeName,
17603
+ frameName: "",
17604
+ });
17257
17605
  };
17258
17606
  /**
17259
17607
  * Stops the strategy from generating new signals.
@@ -17272,14 +17620,18 @@ class LiveUtils {
17272
17620
  * await Live.stop("BTCUSDT", "my-strategy");
17273
17621
  * ```
17274
17622
  */
17275
- this.stop = async (symbol, strategyName) => {
17276
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_STOP);
17623
+ this.stop = async (symbol, context) => {
17624
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_STOP);
17277
17625
  {
17278
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17626
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17279
17627
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP);
17280
17628
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP));
17281
17629
  }
17282
- await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
17630
+ await backtest$1.strategyCoreService.stop(false, symbol, {
17631
+ strategyName: context.strategyName,
17632
+ exchangeName: context.exchangeName,
17633
+ frameName: "",
17634
+ });
17283
17635
  };
17284
17636
  /**
17285
17637
  * Cancels the scheduled signal without stopping the strategy.
@@ -17290,94 +17642,122 @@ class LiveUtils {
17290
17642
  *
17291
17643
  * @param symbol - Trading pair symbol
17292
17644
  * @param strategyName - Strategy name
17645
+ * @param context - Execution context with exchangeName and frameName
17293
17646
  * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
17294
17647
  * @returns Promise that resolves when scheduled signal is cancelled
17295
17648
  *
17296
17649
  * @example
17297
17650
  * ```typescript
17298
17651
  * // Cancel scheduled signal in live trading with custom ID
17299
- * await Live.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17652
+ * await Live.cancel("BTCUSDT", "my-strategy", {
17653
+ * exchangeName: "binance",
17654
+ * frameName: "",
17655
+ * strategyName: "my-strategy"
17656
+ * }, "manual-cancel-001");
17300
17657
  * ```
17301
17658
  */
17302
- this.cancel = async (symbol, strategyName, cancelId) => {
17303
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_CANCEL);
17659
+ this.cancel = async (symbol, context, cancelId) => {
17660
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_CANCEL);
17304
17661
  {
17305
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17662
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17306
17663
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL);
17307
17664
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL));
17308
17665
  }
17309
- await backtest$1.strategyCoreService.cancel(false, { symbol, strategyName }, cancelId);
17666
+ await backtest$1.strategyCoreService.cancel(false, symbol, {
17667
+ strategyName: context.strategyName,
17668
+ exchangeName: context.exchangeName,
17669
+ frameName: "",
17670
+ }, cancelId);
17310
17671
  };
17311
17672
  /**
17312
17673
  * Gets statistical data from all live trading events for a symbol-strategy pair.
17313
17674
  *
17314
17675
  * @param symbol - Trading pair symbol
17315
17676
  * @param strategyName - Strategy name to get data for
17677
+ * @param context - Execution context with exchangeName and frameName
17316
17678
  * @returns Promise resolving to statistical data object
17317
17679
  *
17318
17680
  * @example
17319
17681
  * ```typescript
17320
- * const stats = await Live.getData("BTCUSDT", "my-strategy");
17682
+ * const stats = await Live.getData("BTCUSDT", "my-strategy", {
17683
+ * exchangeName: "binance",
17684
+ * frameName: "",
17685
+ * strategyName: "my-strategy"
17686
+ * });
17321
17687
  * console.log(stats.sharpeRatio, stats.winRate);
17322
17688
  * ```
17323
17689
  */
17324
- this.getData = async (symbol, strategyName) => {
17325
- backtest$1.strategyValidationService.validate(strategyName, "LiveUtils.getData");
17690
+ this.getData = async (symbol, context) => {
17691
+ backtest$1.strategyValidationService.validate(context.strategyName, "LiveUtils.getData");
17326
17692
  {
17327
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17693
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17328
17694
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA);
17329
17695
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA));
17330
17696
  }
17331
- return await backtest$1.liveMarkdownService.getData(symbol, strategyName, false);
17697
+ return await backtest$1.liveMarkdownService.getData(symbol, context.strategyName, context.exchangeName, "", false);
17332
17698
  };
17333
17699
  /**
17334
17700
  * Generates markdown report with all events for a symbol-strategy pair.
17335
17701
  *
17336
17702
  * @param symbol - Trading pair symbol
17337
17703
  * @param strategyName - Strategy name to generate report for
17704
+ * @param context - Execution context with exchangeName and frameName
17338
17705
  * @param columns - Optional columns configuration for the report
17339
17706
  * @returns Promise resolving to markdown formatted report string
17340
17707
  *
17341
17708
  * @example
17342
17709
  * ```typescript
17343
- * const markdown = await Live.getReport("BTCUSDT", "my-strategy");
17710
+ * const markdown = await Live.getReport("BTCUSDT", "my-strategy", {
17711
+ * exchangeName: "binance",
17712
+ * frameName: "",
17713
+ * strategyName: "my-strategy"
17714
+ * });
17344
17715
  * console.log(markdown);
17345
17716
  * ```
17346
17717
  */
17347
- this.getReport = async (symbol, strategyName, columns) => {
17348
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_REPORT);
17718
+ this.getReport = async (symbol, context, columns) => {
17719
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_REPORT);
17349
17720
  {
17350
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17721
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17351
17722
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT);
17352
17723
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT));
17353
17724
  }
17354
- return await backtest$1.liveMarkdownService.getReport(symbol, strategyName, false, columns);
17725
+ return await backtest$1.liveMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, "", false, columns);
17355
17726
  };
17356
17727
  /**
17357
17728
  * Saves strategy report to disk.
17358
17729
  *
17359
17730
  * @param symbol - Trading pair symbol
17360
17731
  * @param strategyName - Strategy name to save report for
17732
+ * @param context - Execution context with exchangeName and frameName
17361
17733
  * @param path - Optional directory path to save report (default: "./dump/live")
17362
17734
  * @param columns - Optional columns configuration for the report
17363
17735
  *
17364
17736
  * @example
17365
17737
  * ```typescript
17366
17738
  * // Save to default path: ./dump/live/my-strategy.md
17367
- * await Live.dump("BTCUSDT", "my-strategy");
17739
+ * await Live.dump("BTCUSDT", "my-strategy", {
17740
+ * exchangeName: "binance",
17741
+ * frameName: "",
17742
+ * strategyName: "my-strategy"
17743
+ * });
17368
17744
  *
17369
17745
  * // Save to custom path: ./custom/path/my-strategy.md
17370
- * await Live.dump("BTCUSDT", "my-strategy", "./custom/path");
17746
+ * await Live.dump("BTCUSDT", "my-strategy", {
17747
+ * exchangeName: "binance",
17748
+ * frameName: "",
17749
+ * strategyName: "my-strategy"
17750
+ * }, "./custom/path");
17371
17751
  * ```
17372
17752
  */
17373
- this.dump = async (symbol, strategyName, path, columns) => {
17374
- backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_DUMP);
17753
+ this.dump = async (symbol, context, path, columns) => {
17754
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_DUMP);
17375
17755
  {
17376
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17756
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17377
17757
  riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP);
17378
17758
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP));
17379
17759
  }
17380
- await backtest$1.liveMarkdownService.dump(symbol, strategyName, false, path, columns);
17760
+ await backtest$1.liveMarkdownService.dump(symbol, context.strategyName, context.exchangeName, "", false, path, columns);
17381
17761
  };
17382
17762
  /**
17383
17763
  * Lists all active live trading instances with their current status.
@@ -17458,19 +17838,19 @@ class ScheduleUtils {
17458
17838
  * console.log(stats.cancellationRate, stats.avgWaitTime);
17459
17839
  * ```
17460
17840
  */
17461
- this.getData = async (symbol, strategyName, backtest = false) => {
17841
+ this.getData = async (symbol, context, backtest = false) => {
17462
17842
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_DATA, {
17463
17843
  symbol,
17464
- strategyName,
17844
+ strategyName: context.strategyName,
17465
17845
  backtest,
17466
17846
  });
17467
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
17847
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
17468
17848
  {
17469
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17849
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17470
17850
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA);
17471
17851
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA));
17472
17852
  }
17473
- return await backtest$1.scheduleMarkdownService.getData(symbol, strategyName, backtest);
17853
+ return await backtest$1.scheduleMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
17474
17854
  };
17475
17855
  /**
17476
17856
  * Generates markdown report with all scheduled events for a symbol-strategy pair.
@@ -17486,19 +17866,19 @@ class ScheduleUtils {
17486
17866
  * console.log(markdown);
17487
17867
  * ```
17488
17868
  */
17489
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
17869
+ this.getReport = async (symbol, context, backtest = false, columns) => {
17490
17870
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_REPORT, {
17491
17871
  symbol,
17492
- strategyName,
17872
+ strategyName: context.strategyName,
17493
17873
  backtest,
17494
17874
  });
17495
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
17875
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
17496
17876
  {
17497
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17877
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17498
17878
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT);
17499
17879
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT));
17500
17880
  }
17501
- return await backtest$1.scheduleMarkdownService.getReport(symbol, strategyName, backtest, columns);
17881
+ return await backtest$1.scheduleMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
17502
17882
  };
17503
17883
  /**
17504
17884
  * Saves strategy report to disk.
@@ -17517,20 +17897,20 @@ class ScheduleUtils {
17517
17897
  * await Schedule.dump("BTCUSDT", "my-strategy", "./custom/path");
17518
17898
  * ```
17519
17899
  */
17520
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
17900
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
17521
17901
  backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_DUMP, {
17522
17902
  symbol,
17523
- strategyName,
17903
+ strategyName: context.strategyName,
17524
17904
  backtest,
17525
17905
  path,
17526
17906
  });
17527
- backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_DUMP);
17907
+ backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_DUMP);
17528
17908
  {
17529
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17909
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17530
17910
  riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP);
17531
17911
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP));
17532
17912
  }
17533
- await backtest$1.scheduleMarkdownService.dump(symbol, strategyName, backtest, path, columns);
17913
+ await backtest$1.scheduleMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
17534
17914
  };
17535
17915
  }
17536
17916
  }
@@ -17611,14 +17991,14 @@ class Performance {
17611
17991
  * }
17612
17992
  * ```
17613
17993
  */
17614
- static async getData(symbol, strategyName, backtest = false) {
17615
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
17994
+ static async getData(symbol, context, backtest = false) {
17995
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
17616
17996
  {
17617
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17997
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17618
17998
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA);
17619
17999
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA));
17620
18000
  }
17621
- return backtest$1.performanceMarkdownService.getData(symbol, strategyName, backtest);
18001
+ return backtest$1.performanceMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
17622
18002
  }
17623
18003
  /**
17624
18004
  * Generates markdown report with performance analysis.
@@ -17643,14 +18023,14 @@ class Performance {
17643
18023
  * await fs.writeFile("performance-report.md", markdown);
17644
18024
  * ```
17645
18025
  */
17646
- static async getReport(symbol, strategyName, backtest = false, columns) {
17647
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
18026
+ static async getReport(symbol, context, backtest = false, columns) {
18027
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
17648
18028
  {
17649
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18029
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17650
18030
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT);
17651
18031
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT));
17652
18032
  }
17653
- return backtest$1.performanceMarkdownService.getReport(symbol, strategyName, backtest, columns);
18033
+ return backtest$1.performanceMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
17654
18034
  }
17655
18035
  /**
17656
18036
  * Saves performance report to disk.
@@ -17672,14 +18052,14 @@ class Performance {
17672
18052
  * await Performance.dump("BTCUSDT", "my-strategy", "./reports/perf");
17673
18053
  * ```
17674
18054
  */
17675
- static async dump(symbol, strategyName, backtest = false, path = "./dump/performance", columns) {
17676
- backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_DUMP);
18055
+ static async dump(symbol, context, backtest = false, path = "./dump/performance", columns) {
18056
+ backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_DUMP);
17677
18057
  {
17678
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18058
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
17679
18059
  riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP);
17680
18060
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP));
17681
18061
  }
17682
- return backtest$1.performanceMarkdownService.dump(symbol, strategyName, backtest, path, columns);
18062
+ return backtest$1.performanceMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
17683
18063
  }
17684
18064
  }
17685
18065
 
@@ -17817,21 +18197,37 @@ class WalkerInstance {
17817
18197
  // Clear backtest data for all strategies
17818
18198
  for (const strategyName of walkerSchema.strategies) {
17819
18199
  {
17820
- backtest$1.backtestMarkdownService.clear(true, { symbol, strategyName });
17821
- backtest$1.liveMarkdownService.clear(true, { symbol, strategyName });
17822
- backtest$1.scheduleMarkdownService.clear(true, { symbol, strategyName });
17823
- backtest$1.performanceMarkdownService.clear(true, { symbol, strategyName });
17824
- backtest$1.partialMarkdownService.clear(true, { symbol, strategyName });
17825
- backtest$1.riskMarkdownService.clear(true, { symbol, strategyName });
18200
+ backtest$1.backtestMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18201
+ backtest$1.liveMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18202
+ backtest$1.scheduleMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18203
+ backtest$1.performanceMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18204
+ backtest$1.partialMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
18205
+ backtest$1.riskMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
17826
18206
  }
17827
18207
  {
17828
- backtest$1.strategyCoreService.clear(true, { symbol, strategyName });
18208
+ backtest$1.strategyCoreService.clear({
18209
+ symbol,
18210
+ strategyName,
18211
+ exchangeName: walkerSchema.exchangeName,
18212
+ frameName: walkerSchema.frameName,
18213
+ backtest: true,
18214
+ });
17829
18215
  }
17830
18216
  {
17831
18217
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17832
- riskName && backtest$1.riskGlobalService.clear(true, { riskName });
18218
+ riskName && backtest$1.riskGlobalService.clear({
18219
+ riskName,
18220
+ exchangeName: walkerSchema.exchangeName,
18221
+ frameName: walkerSchema.frameName,
18222
+ backtest: true
18223
+ });
17833
18224
  riskList &&
17834
- riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, { riskName }));
18225
+ riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
18226
+ riskName,
18227
+ exchangeName: walkerSchema.exchangeName,
18228
+ frameName: walkerSchema.frameName,
18229
+ backtest: true
18230
+ }));
17835
18231
  }
17836
18232
  }
17837
18233
  return backtest$1.walkerCommandService.run(symbol, {
@@ -17876,7 +18272,11 @@ class WalkerInstance {
17876
18272
  this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
17877
18273
  return () => {
17878
18274
  for (const strategyName of walkerSchema.strategies) {
17879
- backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
18275
+ backtest$1.strategyCoreService.stop(true, symbol, {
18276
+ strategyName,
18277
+ exchangeName: walkerSchema.exchangeName,
18278
+ frameName: walkerSchema.frameName
18279
+ });
17880
18280
  walkerStopSubject.next({
17881
18281
  symbol,
17882
18282
  strategyName,
@@ -18017,7 +18417,11 @@ class WalkerUtils {
18017
18417
  }
18018
18418
  for (const strategyName of walkerSchema.strategies) {
18019
18419
  await walkerStopSubject.next({ symbol, strategyName, walkerName });
18020
- await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
18420
+ await backtest$1.strategyCoreService.stop(true, symbol, {
18421
+ strategyName,
18422
+ exchangeName: walkerSchema.exchangeName,
18423
+ frameName: walkerSchema.frameName
18424
+ });
18021
18425
  }
18022
18426
  };
18023
18427
  /**
@@ -18165,15 +18569,27 @@ const HEAT_METHOD_NAME_DUMP = "HeatUtils.dump";
18165
18569
  * import { Heat } from "backtest-kit";
18166
18570
  *
18167
18571
  * // Get raw heatmap data for a strategy
18168
- * const stats = await Heat.getData("my-strategy");
18572
+ * const stats = await Heat.getData({
18573
+ * strategyName: "my-strategy",
18574
+ * exchangeName: "binance",
18575
+ * frameName: "frame1"
18576
+ * });
18169
18577
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18170
18578
  *
18171
18579
  * // Generate markdown report
18172
- * const markdown = await Heat.getReport("my-strategy");
18580
+ * const markdown = await Heat.getReport({
18581
+ * strategyName: "my-strategy",
18582
+ * exchangeName: "binance",
18583
+ * frameName: "frame1"
18584
+ * });
18173
18585
  * console.log(markdown);
18174
18586
  *
18175
18587
  * // Save to disk
18176
- * await Heat.dump("my-strategy", "./reports");
18588
+ * await Heat.dump({
18589
+ * strategyName: "my-strategy",
18590
+ * exchangeName: "binance",
18591
+ * frameName: "frame1"
18592
+ * }, false, "./reports");
18177
18593
  * ```
18178
18594
  */
18179
18595
  class HeatUtils {
@@ -18184,12 +18600,17 @@ class HeatUtils {
18184
18600
  * Returns per-symbol breakdown and portfolio-wide metrics.
18185
18601
  * Data is automatically collected from all closed signals for the strategy.
18186
18602
  *
18187
- * @param strategyName - Strategy name to get heatmap data for
18603
+ * @param context - Execution context with strategyName, exchangeName and frameName
18604
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18188
18605
  * @returns Promise resolving to heatmap statistics object
18189
18606
  *
18190
18607
  * @example
18191
18608
  * ```typescript
18192
- * const stats = await Heat.getData("my-strategy");
18609
+ * const stats = await Heat.getData({
18610
+ * strategyName: "my-strategy",
18611
+ * exchangeName: "binance",
18612
+ * frameName: "frame1"
18613
+ * });
18193
18614
  *
18194
18615
  * console.log(`Total symbols: ${stats.totalSymbols}`);
18195
18616
  * console.log(`Portfolio Total PNL: ${stats.portfolioTotalPnl}%`);
@@ -18201,15 +18622,15 @@ class HeatUtils {
18201
18622
  * });
18202
18623
  * ```
18203
18624
  */
18204
- this.getData = async (strategyName, backtest = false) => {
18205
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
18206
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_DATA);
18625
+ this.getData = async (context, backtest = false) => {
18626
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName: context.strategyName });
18627
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_DATA);
18207
18628
  {
18208
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18629
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18209
18630
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
18210
18631
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
18211
18632
  }
18212
- return await backtest$1.heatMarkdownService.getData(strategyName, backtest);
18633
+ return await backtest$1.heatMarkdownService.getData(context.exchangeName, context.frameName, backtest);
18213
18634
  };
18214
18635
  /**
18215
18636
  * Generates markdown report with portfolio heatmap table for a strategy.
@@ -18217,13 +18638,18 @@ class HeatUtils {
18217
18638
  * Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
18218
18639
  * Symbols are sorted by Total PNL descending.
18219
18640
  *
18220
- * @param strategyName - Strategy name to generate heatmap report for
18641
+ * @param context - Execution context with strategyName, exchangeName and frameName
18642
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18221
18643
  * @param columns - Optional columns configuration for the report
18222
18644
  * @returns Promise resolving to markdown formatted report string
18223
18645
  *
18224
18646
  * @example
18225
18647
  * ```typescript
18226
- * const markdown = await Heat.getReport("my-strategy");
18648
+ * const markdown = await Heat.getReport({
18649
+ * strategyName: "my-strategy",
18650
+ * exchangeName: "binance",
18651
+ * frameName: "frame1"
18652
+ * });
18227
18653
  * console.log(markdown);
18228
18654
  * // Output:
18229
18655
  * // # Portfolio Heatmap: my-strategy
@@ -18237,15 +18663,15 @@ class HeatUtils {
18237
18663
  * // ...
18238
18664
  * ```
18239
18665
  */
18240
- this.getReport = async (strategyName, backtest = false, columns) => {
18241
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
18242
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_REPORT);
18666
+ this.getReport = async (context, backtest = false, columns) => {
18667
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName: context.strategyName });
18668
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_REPORT);
18243
18669
  {
18244
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18670
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18245
18671
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
18246
18672
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
18247
18673
  }
18248
- return await backtest$1.heatMarkdownService.getReport(strategyName, backtest, columns);
18674
+ return await backtest$1.heatMarkdownService.getReport(context.strategyName, context.exchangeName, context.frameName, backtest, columns);
18249
18675
  };
18250
18676
  /**
18251
18677
  * Saves heatmap report to disk for a strategy.
@@ -18253,28 +18679,37 @@ class HeatUtils {
18253
18679
  * Creates directory if it doesn't exist.
18254
18680
  * Default filename: {strategyName}.md
18255
18681
  *
18256
- * @param strategyName - Strategy name to save heatmap report for
18682
+ * @param context - Execution context with strategyName, exchangeName and frameName
18683
+ * @param backtest - True if backtest mode, false if live mode (default: false)
18257
18684
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
18258
18685
  * @param columns - Optional columns configuration for the report
18259
18686
  *
18260
18687
  * @example
18261
18688
  * ```typescript
18262
18689
  * // Save to default path: ./dump/heatmap/my-strategy.md
18263
- * await Heat.dump("my-strategy");
18690
+ * await Heat.dump({
18691
+ * strategyName: "my-strategy",
18692
+ * exchangeName: "binance",
18693
+ * frameName: "frame1"
18694
+ * });
18264
18695
  *
18265
18696
  * // Save to custom path: ./reports/my-strategy.md
18266
- * await Heat.dump("my-strategy", "./reports");
18697
+ * await Heat.dump({
18698
+ * strategyName: "my-strategy",
18699
+ * exchangeName: "binance",
18700
+ * frameName: "frame1"
18701
+ * }, false, "./reports");
18267
18702
  * ```
18268
18703
  */
18269
- this.dump = async (strategyName, backtest = false, path, columns) => {
18270
- backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
18271
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_DUMP);
18704
+ this.dump = async (context, backtest = false, path, columns) => {
18705
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName: context.strategyName, path });
18706
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_DUMP);
18272
18707
  {
18273
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18708
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18274
18709
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
18275
18710
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
18276
18711
  }
18277
- await backtest$1.heatMarkdownService.dump(strategyName, backtest, path, columns);
18712
+ await backtest$1.heatMarkdownService.dump(context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18278
18713
  };
18279
18714
  }
18280
18715
  }
@@ -18286,7 +18721,11 @@ class HeatUtils {
18286
18721
  * import { Heat } from "backtest-kit";
18287
18722
  *
18288
18723
  * // Strategy-specific heatmap
18289
- * const stats = await Heat.getData("my-strategy");
18724
+ * const stats = await Heat.getData({
18725
+ * strategyName: "my-strategy",
18726
+ * exchangeName: "binance",
18727
+ * frameName: "frame1"
18728
+ * });
18290
18729
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18291
18730
  * console.log(`Total Symbols: ${stats.totalSymbols}`);
18292
18731
  *
@@ -18300,7 +18739,11 @@ class HeatUtils {
18300
18739
  * });
18301
18740
  *
18302
18741
  * // Generate and save report
18303
- * await Heat.dump("my-strategy", "./reports");
18742
+ * await Heat.dump({
18743
+ * strategyName: "my-strategy",
18744
+ * exchangeName: "binance",
18745
+ * frameName: "frame1"
18746
+ * }, false, "./reports");
18304
18747
  * ```
18305
18748
  */
18306
18749
  const Heat = new HeatUtils();
@@ -18590,15 +19033,15 @@ class PartialUtils {
18590
19033
  * }
18591
19034
  * ```
18592
19035
  */
18593
- this.getData = async (symbol, strategyName, backtest = false) => {
18594
- backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_DATA, { symbol, strategyName });
18595
- backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_GET_DATA);
19036
+ this.getData = async (symbol, context, backtest = false) => {
19037
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_DATA, { symbol, strategyName: context.strategyName });
19038
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_DATA);
18596
19039
  {
18597
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19040
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18598
19041
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA);
18599
19042
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA));
18600
19043
  }
18601
- return await backtest$1.partialMarkdownService.getData(symbol, strategyName, backtest);
19044
+ return await backtest$1.partialMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
18602
19045
  };
18603
19046
  /**
18604
19047
  * Generates markdown report with all partial profit/loss events for a symbol-strategy pair.
@@ -18639,15 +19082,15 @@ class PartialUtils {
18639
19082
  * // **Loss events:** 1
18640
19083
  * ```
18641
19084
  */
18642
- this.getReport = async (symbol, strategyName, backtest = false, columns) => {
18643
- backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_REPORT, { symbol, strategyName });
18644
- backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_GET_REPORT);
19085
+ this.getReport = async (symbol, context, backtest = false, columns) => {
19086
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_REPORT, { symbol, strategyName: context.strategyName });
19087
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_REPORT);
18645
19088
  {
18646
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19089
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18647
19090
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT);
18648
19091
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT));
18649
19092
  }
18650
- return await backtest$1.partialMarkdownService.getReport(symbol, strategyName, backtest, columns);
19093
+ return await backtest$1.partialMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
18651
19094
  };
18652
19095
  /**
18653
19096
  * Generates and saves markdown report to file.
@@ -18681,15 +19124,15 @@ class PartialUtils {
18681
19124
  * }
18682
19125
  * ```
18683
19126
  */
18684
- this.dump = async (symbol, strategyName, backtest = false, path, columns) => {
18685
- backtest$1.loggerService.info(PARTIAL_METHOD_NAME_DUMP, { symbol, strategyName, path });
18686
- backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_DUMP);
19127
+ this.dump = async (symbol, context, backtest = false, path, columns) => {
19128
+ backtest$1.loggerService.info(PARTIAL_METHOD_NAME_DUMP, { symbol, strategyName: context.strategyName, path });
19129
+ backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_DUMP);
18687
19130
  {
18688
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
19131
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18689
19132
  riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP);
18690
19133
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP));
18691
19134
  }
18692
- await backtest$1.partialMarkdownService.dump(symbol, strategyName, backtest, path, columns);
19135
+ await backtest$1.partialMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18693
19136
  };
18694
19137
  }
18695
19138
  }
@@ -19102,7 +19545,13 @@ const INTERVAL_MINUTES = {
19102
19545
  * @param backtest - Whether running in backtest mode
19103
19546
  * @returns Cache key string
19104
19547
  */
19105
- const CREATE_KEY_FN$1 = (strategyName, exchangeName, backtest) => `${strategyName}:${exchangeName}:${backtest ? "backtest" : "live"}`;
19548
+ const CREATE_KEY_FN$1 = (strategyName, exchangeName, frameName, backtest) => {
19549
+ const parts = [strategyName, exchangeName];
19550
+ if (frameName)
19551
+ parts.push(frameName);
19552
+ parts.push(backtest ? "backtest" : "live");
19553
+ return parts.join(":");
19554
+ };
19106
19555
  /**
19107
19556
  * Instance class for caching function results with timeframe-based invalidation.
19108
19557
  *
@@ -19178,7 +19627,7 @@ class CacheInstance {
19178
19627
  throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
19179
19628
  }
19180
19629
  }
19181
- const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
19630
+ 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);
19182
19631
  const currentWhen = backtest$1.executionContextService.context.when;
19183
19632
  const cached = this._cacheMap.get(key);
19184
19633
  if (cached) {
@@ -19216,7 +19665,7 @@ class CacheInstance {
19216
19665
  * ```
19217
19666
  */
19218
19667
  this.clear = () => {
19219
- const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
19668
+ 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);
19220
19669
  this._cacheMap.delete(key);
19221
19670
  };
19222
19671
  }