backtest-kit 1.7.1 → 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.
package/build/index.cjs CHANGED
@@ -3402,7 +3402,7 @@ class ClientStrategy {
3402
3402
  * // Existing signal will continue until natural close
3403
3403
  * ```
3404
3404
  */
3405
- async stop(symbol) {
3405
+ async stop(symbol, backtest) {
3406
3406
  this.params.logger.debug("ClientStrategy stop", {
3407
3407
  symbol,
3408
3408
  hasPendingSignal: this._pendingSignal !== null,
@@ -3414,7 +3414,7 @@ class ClientStrategy {
3414
3414
  return;
3415
3415
  }
3416
3416
  this._scheduledSignal = null;
3417
- if (this.params.execution.context.backtest) {
3417
+ if (backtest) {
3418
3418
  return;
3419
3419
  }
3420
3420
  await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
@@ -3440,12 +3440,10 @@ class ClientStrategy {
3440
3440
  * // Strategy continues, can generate new signals
3441
3441
  * ```
3442
3442
  */
3443
- async cancel(symbol, cancelId) {
3443
+ async cancel(symbol, backtest, cancelId) {
3444
3444
  this.params.logger.debug("ClientStrategy cancel", {
3445
3445
  symbol,
3446
- strategyName: this.params.method.context.strategyName,
3447
3446
  hasScheduledSignal: this._scheduledSignal !== null,
3448
- backtest: this.params.execution.context.backtest,
3449
3447
  cancelId,
3450
3448
  });
3451
3449
  // Save cancelled signal for next tick to emit cancelled event
@@ -3455,7 +3453,7 @@ class ClientStrategy {
3455
3453
  });
3456
3454
  this._scheduledSignal = null;
3457
3455
  }
3458
- if (this.params.execution.context.backtest) {
3456
+ if (backtest) {
3459
3457
  return;
3460
3458
  }
3461
3459
  await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
@@ -4040,7 +4038,7 @@ class StrategyConnectionService {
4040
4038
  context,
4041
4039
  });
4042
4040
  const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4043
- await strategy.stop(symbol);
4041
+ await strategy.stop(symbol, backtest);
4044
4042
  };
4045
4043
  /**
4046
4044
  * Clears the memoized ClientStrategy instance from cache.
@@ -4084,7 +4082,7 @@ class StrategyConnectionService {
4084
4082
  cancelId,
4085
4083
  });
4086
4084
  const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4087
- await strategy.cancel(symbol, cancelId);
4085
+ await strategy.cancel(symbol, backtest, cancelId);
4088
4086
  };
4089
4087
  }
4090
4088
  }
@@ -5018,19 +5016,19 @@ class StrategyCoreService {
5018
5016
  /**
5019
5017
  * Validates strategy and associated risk configuration.
5020
5018
  *
5021
- * Memoized to avoid redundant validations for the same symbol-strategy pair.
5019
+ * Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
5022
5020
  * Logs validation activity.
5023
5021
  * @param symbol - Trading pair symbol
5024
- * @param strategyName - Name of the strategy to validate
5022
+ * @param context - Execution context with strategyName, exchangeName, frameName
5025
5023
  * @returns Promise that resolves when validation is complete
5026
5024
  */
5027
- this.validate = functoolsKit.memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, async (symbol, strategyName) => {
5025
+ this.validate = functoolsKit.memoize(([symbol, context]) => `${symbol}:${context.strategyName}:${context.exchangeName}:${context.frameName}`, async (symbol, context) => {
5028
5026
  this.loggerService.log(METHOD_NAME_VALIDATE, {
5029
5027
  symbol,
5030
- strategyName,
5028
+ context,
5031
5029
  });
5032
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
5033
- this.strategyValidationService.validate(strategyName, METHOD_NAME_VALIDATE);
5030
+ const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
5031
+ this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
5034
5032
  riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
5035
5033
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
5036
5034
  });
@@ -5049,7 +5047,7 @@ class StrategyCoreService {
5049
5047
  symbol,
5050
5048
  context,
5051
5049
  });
5052
- await this.validate(symbol, context.strategyName);
5050
+ await this.validate(symbol, context);
5053
5051
  return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
5054
5052
  };
5055
5053
  /**
@@ -5067,7 +5065,7 @@ class StrategyCoreService {
5067
5065
  symbol,
5068
5066
  context,
5069
5067
  });
5070
- await this.validate(symbol, context.strategyName);
5068
+ await this.validate(symbol, context);
5071
5069
  return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
5072
5070
  };
5073
5071
  /**
@@ -5087,7 +5085,7 @@ class StrategyCoreService {
5087
5085
  context,
5088
5086
  backtest,
5089
5087
  });
5090
- await this.validate(symbol, context.strategyName);
5088
+ await this.validate(symbol, context);
5091
5089
  return await this.strategyConnectionService.getStopped(backtest, symbol, context);
5092
5090
  };
5093
5091
  /**
@@ -5109,7 +5107,7 @@ class StrategyCoreService {
5109
5107
  backtest,
5110
5108
  context,
5111
5109
  });
5112
- await this.validate(symbol, context.strategyName);
5110
+ await this.validate(symbol, context);
5113
5111
  return await ExecutionContextService.runInContext(async () => {
5114
5112
  return await this.strategyConnectionService.tick(symbol, context);
5115
5113
  }, {
@@ -5139,7 +5137,7 @@ class StrategyCoreService {
5139
5137
  backtest,
5140
5138
  context,
5141
5139
  });
5142
- await this.validate(symbol, context.strategyName);
5140
+ await this.validate(symbol, context);
5143
5141
  return await ExecutionContextService.runInContext(async () => {
5144
5142
  return await this.strategyConnectionService.backtest(symbol, context, candles);
5145
5143
  }, {
@@ -5165,7 +5163,7 @@ class StrategyCoreService {
5165
5163
  context,
5166
5164
  backtest,
5167
5165
  });
5168
- await this.validate(symbol, context.strategyName);
5166
+ await this.validate(symbol, context);
5169
5167
  return await this.strategyConnectionService.stop(backtest, symbol, context);
5170
5168
  };
5171
5169
  /**
@@ -5188,7 +5186,7 @@ class StrategyCoreService {
5188
5186
  backtest,
5189
5187
  cancelId,
5190
5188
  });
5191
- await this.validate(symbol, context.strategyName);
5189
+ await this.validate(symbol, context);
5192
5190
  return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
5193
5191
  };
5194
5192
  /**
@@ -5204,7 +5202,11 @@ class StrategyCoreService {
5204
5202
  payload,
5205
5203
  });
5206
5204
  if (payload) {
5207
- await this.validate(payload.symbol, payload.strategyName);
5205
+ await this.validate(payload.symbol, {
5206
+ strategyName: payload.strategyName,
5207
+ exchangeName: payload.exchangeName,
5208
+ frameName: payload.frameName
5209
+ });
5208
5210
  }
5209
5211
  return await this.strategyConnectionService.clear(payload);
5210
5212
  };
@@ -5287,16 +5289,16 @@ class RiskGlobalService {
5287
5289
  this.riskValidationService = inject(TYPES.riskValidationService);
5288
5290
  /**
5289
5291
  * Validates risk configuration.
5290
- * Memoized to avoid redundant validations for the same risk instance.
5292
+ * Memoized to avoid redundant validations for the same risk-exchange-frame combination.
5291
5293
  * Logs validation activity.
5292
- * @param riskName - Name of the risk instance to validate
5294
+ * @param payload - Payload with riskName, exchangeName and frameName
5293
5295
  * @returns Promise that resolves when validation is complete
5294
5296
  */
5295
- this.validate = functoolsKit.memoize(([riskName]) => `${riskName}`, async (riskName) => {
5297
+ this.validate = functoolsKit.memoize(([payload]) => `${payload.riskName}:${payload.exchangeName}:${payload.frameName}`, async (payload) => {
5296
5298
  this.loggerService.log("riskGlobalService validate", {
5297
- riskName,
5299
+ payload,
5298
5300
  });
5299
- this.riskValidationService.validate(riskName, "riskGlobalService validate");
5301
+ this.riskValidationService.validate(payload.riskName, "riskGlobalService validate");
5300
5302
  });
5301
5303
  /**
5302
5304
  * Checks if a signal should be allowed based on risk limits.
@@ -5310,7 +5312,7 @@ class RiskGlobalService {
5310
5312
  symbol: params.symbol,
5311
5313
  payload,
5312
5314
  });
5313
- await this.validate(payload.riskName);
5315
+ await this.validate(payload);
5314
5316
  return await this.riskConnectionService.checkSignal(params, payload);
5315
5317
  };
5316
5318
  /**
@@ -5324,7 +5326,7 @@ class RiskGlobalService {
5324
5326
  symbol,
5325
5327
  payload,
5326
5328
  });
5327
- await this.validate(payload.riskName);
5329
+ await this.validate(payload);
5328
5330
  await this.riskConnectionService.addSignal(symbol, payload);
5329
5331
  };
5330
5332
  /**
@@ -5338,7 +5340,7 @@ class RiskGlobalService {
5338
5340
  symbol,
5339
5341
  payload,
5340
5342
  });
5341
- await this.validate(payload.riskName);
5343
+ await this.validate(payload);
5342
5344
  await this.riskConnectionService.removeSignal(symbol, payload);
5343
5345
  };
5344
5346
  /**
@@ -5352,7 +5354,7 @@ class RiskGlobalService {
5352
5354
  payload,
5353
5355
  });
5354
5356
  if (payload) {
5355
- await this.validate(payload.riskName);
5357
+ await this.validate(payload);
5356
5358
  }
5357
5359
  return await this.riskConnectionService.clear(payload);
5358
5360
  };
@@ -13370,18 +13372,18 @@ class PartialGlobalService {
13370
13372
  this.riskValidationService = inject(TYPES.riskValidationService);
13371
13373
  /**
13372
13374
  * Validates strategy and associated risk configuration.
13373
- * Memoized to avoid redundant validations for the same strategy.
13375
+ * Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
13374
13376
  *
13375
- * @param strategyName - Name of the strategy to validate
13377
+ * @param context - Context with strategyName, exchangeName and frameName
13376
13378
  * @param methodName - Name of the calling method for error tracking
13377
13379
  */
13378
- this.validate = functoolsKit.memoize(([strategyName]) => `${strategyName}`, (strategyName, methodName) => {
13380
+ this.validate = functoolsKit.memoize(([context]) => `${context.strategyName}:${context.exchangeName}:${context.frameName}`, (context, methodName) => {
13379
13381
  this.loggerService.log("partialGlobalService validate", {
13380
- strategyName,
13382
+ context,
13381
13383
  methodName,
13382
13384
  });
13383
- this.strategyValidationService.validate(strategyName, methodName);
13384
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
13385
+ this.strategyValidationService.validate(context.strategyName, methodName);
13386
+ const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
13385
13387
  riskName && this.riskValidationService.validate(riskName, methodName);
13386
13388
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
13387
13389
  });
@@ -13407,7 +13409,11 @@ class PartialGlobalService {
13407
13409
  backtest,
13408
13410
  when,
13409
13411
  });
13410
- this.validate(data.strategyName, "partialGlobalService profit");
13412
+ this.validate({
13413
+ strategyName: data.strategyName,
13414
+ exchangeName: data.exchangeName,
13415
+ frameName: data.frameName
13416
+ }, "partialGlobalService profit");
13411
13417
  return await this.partialConnectionService.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
13412
13418
  };
13413
13419
  /**
@@ -13432,7 +13438,11 @@ class PartialGlobalService {
13432
13438
  backtest,
13433
13439
  when,
13434
13440
  });
13435
- this.validate(data.strategyName, "partialGlobalService loss");
13441
+ this.validate({
13442
+ strategyName: data.strategyName,
13443
+ exchangeName: data.exchangeName,
13444
+ frameName: data.frameName
13445
+ }, "partialGlobalService loss");
13436
13446
  return await this.partialConnectionService.loss(symbol, data, currentPrice, lossPercent, backtest, when);
13437
13447
  };
13438
13448
  /**
@@ -13452,7 +13462,11 @@ class PartialGlobalService {
13452
13462
  priceClose,
13453
13463
  backtest,
13454
13464
  });
13455
- this.validate(data.strategyName, "partialGlobalService clear");
13465
+ this.validate({
13466
+ strategyName: data.strategyName,
13467
+ exchangeName: data.exchangeName,
13468
+ frameName: data.frameName
13469
+ }, "partialGlobalService clear");
13456
13470
  return await this.partialConnectionService.clear(symbol, data, priceClose, backtest);
13457
13471
  };
13458
13472
  }
@@ -18557,15 +18571,27 @@ const HEAT_METHOD_NAME_DUMP = "HeatUtils.dump";
18557
18571
  * import { Heat } from "backtest-kit";
18558
18572
  *
18559
18573
  * // Get raw heatmap data for a strategy
18560
- * const stats = await Heat.getData("my-strategy");
18574
+ * const stats = await Heat.getData({
18575
+ * strategyName: "my-strategy",
18576
+ * exchangeName: "binance",
18577
+ * frameName: "frame1"
18578
+ * });
18561
18579
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18562
18580
  *
18563
18581
  * // Generate markdown report
18564
- * const markdown = await Heat.getReport("my-strategy");
18582
+ * const markdown = await Heat.getReport({
18583
+ * strategyName: "my-strategy",
18584
+ * exchangeName: "binance",
18585
+ * frameName: "frame1"
18586
+ * });
18565
18587
  * console.log(markdown);
18566
18588
  *
18567
18589
  * // Save to disk
18568
- * await Heat.dump("my-strategy", "./reports");
18590
+ * await Heat.dump({
18591
+ * strategyName: "my-strategy",
18592
+ * exchangeName: "binance",
18593
+ * frameName: "frame1"
18594
+ * }, false, "./reports");
18569
18595
  * ```
18570
18596
  */
18571
18597
  class HeatUtils {
@@ -18576,14 +18602,14 @@ class HeatUtils {
18576
18602
  * Returns per-symbol breakdown and portfolio-wide metrics.
18577
18603
  * Data is automatically collected from all closed signals for the strategy.
18578
18604
  *
18579
- * @param strategyName - Strategy name to get heatmap data for
18580
- * @param context - Execution context with exchangeName and frameName
18605
+ * @param context - Execution context with strategyName, exchangeName and frameName
18581
18606
  * @param backtest - True if backtest mode, false if live mode (default: false)
18582
18607
  * @returns Promise resolving to heatmap statistics object
18583
18608
  *
18584
18609
  * @example
18585
18610
  * ```typescript
18586
- * const stats = await Heat.getData("my-strategy", {
18611
+ * const stats = await Heat.getData({
18612
+ * strategyName: "my-strategy",
18587
18613
  * exchangeName: "binance",
18588
18614
  * frameName: "frame1"
18589
18615
  * });
@@ -18598,11 +18624,11 @@ class HeatUtils {
18598
18624
  * });
18599
18625
  * ```
18600
18626
  */
18601
- this.getData = async (strategyName, context, backtest = false) => {
18602
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
18603
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_DATA);
18627
+ this.getData = async (context, backtest = false) => {
18628
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName: context.strategyName });
18629
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_DATA);
18604
18630
  {
18605
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18631
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18606
18632
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
18607
18633
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
18608
18634
  }
@@ -18614,15 +18640,15 @@ class HeatUtils {
18614
18640
  * Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
18615
18641
  * Symbols are sorted by Total PNL descending.
18616
18642
  *
18617
- * @param strategyName - Strategy name to generate heatmap report for
18618
- * @param context - Execution context with exchangeName and frameName
18643
+ * @param context - Execution context with strategyName, exchangeName and frameName
18619
18644
  * @param backtest - True if backtest mode, false if live mode (default: false)
18620
18645
  * @param columns - Optional columns configuration for the report
18621
18646
  * @returns Promise resolving to markdown formatted report string
18622
18647
  *
18623
18648
  * @example
18624
18649
  * ```typescript
18625
- * const markdown = await Heat.getReport("my-strategy", {
18650
+ * const markdown = await Heat.getReport({
18651
+ * strategyName: "my-strategy",
18626
18652
  * exchangeName: "binance",
18627
18653
  * frameName: "frame1"
18628
18654
  * });
@@ -18639,15 +18665,15 @@ class HeatUtils {
18639
18665
  * // ...
18640
18666
  * ```
18641
18667
  */
18642
- this.getReport = async (strategyName, context, backtest = false, columns) => {
18643
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
18644
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_REPORT);
18668
+ this.getReport = async (context, backtest = false, columns) => {
18669
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName: context.strategyName });
18670
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_REPORT);
18645
18671
  {
18646
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18672
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18647
18673
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
18648
18674
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
18649
18675
  }
18650
- return await backtest$1.heatMarkdownService.getReport(strategyName, context.exchangeName, context.frameName, backtest, columns);
18676
+ return await backtest$1.heatMarkdownService.getReport(context.strategyName, context.exchangeName, context.frameName, backtest, columns);
18651
18677
  };
18652
18678
  /**
18653
18679
  * Saves heatmap report to disk for a strategy.
@@ -18655,8 +18681,7 @@ class HeatUtils {
18655
18681
  * Creates directory if it doesn't exist.
18656
18682
  * Default filename: {strategyName}.md
18657
18683
  *
18658
- * @param strategyName - Strategy name to save heatmap report for
18659
- * @param context - Execution context with exchangeName and frameName
18684
+ * @param context - Execution context with strategyName, exchangeName and frameName
18660
18685
  * @param backtest - True if backtest mode, false if live mode (default: false)
18661
18686
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
18662
18687
  * @param columns - Optional columns configuration for the report
@@ -18664,27 +18689,29 @@ class HeatUtils {
18664
18689
  * @example
18665
18690
  * ```typescript
18666
18691
  * // Save to default path: ./dump/heatmap/my-strategy.md
18667
- * await Heat.dump("my-strategy", {
18692
+ * await Heat.dump({
18693
+ * strategyName: "my-strategy",
18668
18694
  * exchangeName: "binance",
18669
18695
  * frameName: "frame1"
18670
18696
  * });
18671
18697
  *
18672
18698
  * // Save to custom path: ./reports/my-strategy.md
18673
- * await Heat.dump("my-strategy", {
18699
+ * await Heat.dump({
18700
+ * strategyName: "my-strategy",
18674
18701
  * exchangeName: "binance",
18675
18702
  * frameName: "frame1"
18676
18703
  * }, false, "./reports");
18677
18704
  * ```
18678
18705
  */
18679
- this.dump = async (strategyName, context, backtest = false, path, columns) => {
18680
- backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
18681
- backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_DUMP);
18706
+ this.dump = async (context, backtest = false, path, columns) => {
18707
+ backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName: context.strategyName, path });
18708
+ backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_DUMP);
18682
18709
  {
18683
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18710
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18684
18711
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
18685
18712
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
18686
18713
  }
18687
- await backtest$1.heatMarkdownService.dump(strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18714
+ await backtest$1.heatMarkdownService.dump(context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18688
18715
  };
18689
18716
  }
18690
18717
  }
@@ -18696,7 +18723,11 @@ class HeatUtils {
18696
18723
  * import { Heat } from "backtest-kit";
18697
18724
  *
18698
18725
  * // Strategy-specific heatmap
18699
- * const stats = await Heat.getData("my-strategy");
18726
+ * const stats = await Heat.getData({
18727
+ * strategyName: "my-strategy",
18728
+ * exchangeName: "binance",
18729
+ * frameName: "frame1"
18730
+ * });
18700
18731
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18701
18732
  * console.log(`Total Symbols: ${stats.totalSymbols}`);
18702
18733
  *
@@ -18710,7 +18741,11 @@ class HeatUtils {
18710
18741
  * });
18711
18742
  *
18712
18743
  * // Generate and save report
18713
- * await Heat.dump("my-strategy", "./reports");
18744
+ * await Heat.dump({
18745
+ * strategyName: "my-strategy",
18746
+ * exchangeName: "binance",
18747
+ * frameName: "frame1"
18748
+ * }, false, "./reports");
18714
18749
  * ```
18715
18750
  */
18716
18751
  const Heat = new HeatUtils();
package/build/index.mjs CHANGED
@@ -3400,7 +3400,7 @@ class ClientStrategy {
3400
3400
  * // Existing signal will continue until natural close
3401
3401
  * ```
3402
3402
  */
3403
- async stop(symbol) {
3403
+ async stop(symbol, backtest) {
3404
3404
  this.params.logger.debug("ClientStrategy stop", {
3405
3405
  symbol,
3406
3406
  hasPendingSignal: this._pendingSignal !== null,
@@ -3412,7 +3412,7 @@ class ClientStrategy {
3412
3412
  return;
3413
3413
  }
3414
3414
  this._scheduledSignal = null;
3415
- if (this.params.execution.context.backtest) {
3415
+ if (backtest) {
3416
3416
  return;
3417
3417
  }
3418
3418
  await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
@@ -3438,12 +3438,10 @@ class ClientStrategy {
3438
3438
  * // Strategy continues, can generate new signals
3439
3439
  * ```
3440
3440
  */
3441
- async cancel(symbol, cancelId) {
3441
+ async cancel(symbol, backtest, cancelId) {
3442
3442
  this.params.logger.debug("ClientStrategy cancel", {
3443
3443
  symbol,
3444
- strategyName: this.params.method.context.strategyName,
3445
3444
  hasScheduledSignal: this._scheduledSignal !== null,
3446
- backtest: this.params.execution.context.backtest,
3447
3445
  cancelId,
3448
3446
  });
3449
3447
  // Save cancelled signal for next tick to emit cancelled event
@@ -3453,7 +3451,7 @@ class ClientStrategy {
3453
3451
  });
3454
3452
  this._scheduledSignal = null;
3455
3453
  }
3456
- if (this.params.execution.context.backtest) {
3454
+ if (backtest) {
3457
3455
  return;
3458
3456
  }
3459
3457
  await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
@@ -4038,7 +4036,7 @@ class StrategyConnectionService {
4038
4036
  context,
4039
4037
  });
4040
4038
  const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4041
- await strategy.stop(symbol);
4039
+ await strategy.stop(symbol, backtest);
4042
4040
  };
4043
4041
  /**
4044
4042
  * Clears the memoized ClientStrategy instance from cache.
@@ -4082,7 +4080,7 @@ class StrategyConnectionService {
4082
4080
  cancelId,
4083
4081
  });
4084
4082
  const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
4085
- await strategy.cancel(symbol, cancelId);
4083
+ await strategy.cancel(symbol, backtest, cancelId);
4086
4084
  };
4087
4085
  }
4088
4086
  }
@@ -5016,19 +5014,19 @@ class StrategyCoreService {
5016
5014
  /**
5017
5015
  * Validates strategy and associated risk configuration.
5018
5016
  *
5019
- * 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.
5020
5018
  * Logs validation activity.
5021
5019
  * @param symbol - Trading pair symbol
5022
- * @param strategyName - Name of the strategy to validate
5020
+ * @param context - Execution context with strategyName, exchangeName, frameName
5023
5021
  * @returns Promise that resolves when validation is complete
5024
5022
  */
5025
- 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) => {
5026
5024
  this.loggerService.log(METHOD_NAME_VALIDATE, {
5027
5025
  symbol,
5028
- strategyName,
5026
+ context,
5029
5027
  });
5030
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
5031
- 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);
5032
5030
  riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
5033
5031
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
5034
5032
  });
@@ -5047,7 +5045,7 @@ class StrategyCoreService {
5047
5045
  symbol,
5048
5046
  context,
5049
5047
  });
5050
- await this.validate(symbol, context.strategyName);
5048
+ await this.validate(symbol, context);
5051
5049
  return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
5052
5050
  };
5053
5051
  /**
@@ -5065,7 +5063,7 @@ class StrategyCoreService {
5065
5063
  symbol,
5066
5064
  context,
5067
5065
  });
5068
- await this.validate(symbol, context.strategyName);
5066
+ await this.validate(symbol, context);
5069
5067
  return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
5070
5068
  };
5071
5069
  /**
@@ -5085,7 +5083,7 @@ class StrategyCoreService {
5085
5083
  context,
5086
5084
  backtest,
5087
5085
  });
5088
- await this.validate(symbol, context.strategyName);
5086
+ await this.validate(symbol, context);
5089
5087
  return await this.strategyConnectionService.getStopped(backtest, symbol, context);
5090
5088
  };
5091
5089
  /**
@@ -5107,7 +5105,7 @@ class StrategyCoreService {
5107
5105
  backtest,
5108
5106
  context,
5109
5107
  });
5110
- await this.validate(symbol, context.strategyName);
5108
+ await this.validate(symbol, context);
5111
5109
  return await ExecutionContextService.runInContext(async () => {
5112
5110
  return await this.strategyConnectionService.tick(symbol, context);
5113
5111
  }, {
@@ -5137,7 +5135,7 @@ class StrategyCoreService {
5137
5135
  backtest,
5138
5136
  context,
5139
5137
  });
5140
- await this.validate(symbol, context.strategyName);
5138
+ await this.validate(symbol, context);
5141
5139
  return await ExecutionContextService.runInContext(async () => {
5142
5140
  return await this.strategyConnectionService.backtest(symbol, context, candles);
5143
5141
  }, {
@@ -5163,7 +5161,7 @@ class StrategyCoreService {
5163
5161
  context,
5164
5162
  backtest,
5165
5163
  });
5166
- await this.validate(symbol, context.strategyName);
5164
+ await this.validate(symbol, context);
5167
5165
  return await this.strategyConnectionService.stop(backtest, symbol, context);
5168
5166
  };
5169
5167
  /**
@@ -5186,7 +5184,7 @@ class StrategyCoreService {
5186
5184
  backtest,
5187
5185
  cancelId,
5188
5186
  });
5189
- await this.validate(symbol, context.strategyName);
5187
+ await this.validate(symbol, context);
5190
5188
  return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
5191
5189
  };
5192
5190
  /**
@@ -5202,7 +5200,11 @@ class StrategyCoreService {
5202
5200
  payload,
5203
5201
  });
5204
5202
  if (payload) {
5205
- await this.validate(payload.symbol, payload.strategyName);
5203
+ await this.validate(payload.symbol, {
5204
+ strategyName: payload.strategyName,
5205
+ exchangeName: payload.exchangeName,
5206
+ frameName: payload.frameName
5207
+ });
5206
5208
  }
5207
5209
  return await this.strategyConnectionService.clear(payload);
5208
5210
  };
@@ -5285,16 +5287,16 @@ class RiskGlobalService {
5285
5287
  this.riskValidationService = inject(TYPES.riskValidationService);
5286
5288
  /**
5287
5289
  * Validates risk configuration.
5288
- * Memoized to avoid redundant validations for the same risk instance.
5290
+ * Memoized to avoid redundant validations for the same risk-exchange-frame combination.
5289
5291
  * Logs validation activity.
5290
- * @param riskName - Name of the risk instance to validate
5292
+ * @param payload - Payload with riskName, exchangeName and frameName
5291
5293
  * @returns Promise that resolves when validation is complete
5292
5294
  */
5293
- this.validate = memoize(([riskName]) => `${riskName}`, async (riskName) => {
5295
+ this.validate = memoize(([payload]) => `${payload.riskName}:${payload.exchangeName}:${payload.frameName}`, async (payload) => {
5294
5296
  this.loggerService.log("riskGlobalService validate", {
5295
- riskName,
5297
+ payload,
5296
5298
  });
5297
- this.riskValidationService.validate(riskName, "riskGlobalService validate");
5299
+ this.riskValidationService.validate(payload.riskName, "riskGlobalService validate");
5298
5300
  });
5299
5301
  /**
5300
5302
  * Checks if a signal should be allowed based on risk limits.
@@ -5308,7 +5310,7 @@ class RiskGlobalService {
5308
5310
  symbol: params.symbol,
5309
5311
  payload,
5310
5312
  });
5311
- await this.validate(payload.riskName);
5313
+ await this.validate(payload);
5312
5314
  return await this.riskConnectionService.checkSignal(params, payload);
5313
5315
  };
5314
5316
  /**
@@ -5322,7 +5324,7 @@ class RiskGlobalService {
5322
5324
  symbol,
5323
5325
  payload,
5324
5326
  });
5325
- await this.validate(payload.riskName);
5327
+ await this.validate(payload);
5326
5328
  await this.riskConnectionService.addSignal(symbol, payload);
5327
5329
  };
5328
5330
  /**
@@ -5336,7 +5338,7 @@ class RiskGlobalService {
5336
5338
  symbol,
5337
5339
  payload,
5338
5340
  });
5339
- await this.validate(payload.riskName);
5341
+ await this.validate(payload);
5340
5342
  await this.riskConnectionService.removeSignal(symbol, payload);
5341
5343
  };
5342
5344
  /**
@@ -5350,7 +5352,7 @@ class RiskGlobalService {
5350
5352
  payload,
5351
5353
  });
5352
5354
  if (payload) {
5353
- await this.validate(payload.riskName);
5355
+ await this.validate(payload);
5354
5356
  }
5355
5357
  return await this.riskConnectionService.clear(payload);
5356
5358
  };
@@ -13368,18 +13370,18 @@ class PartialGlobalService {
13368
13370
  this.riskValidationService = inject(TYPES.riskValidationService);
13369
13371
  /**
13370
13372
  * Validates strategy and associated risk configuration.
13371
- * Memoized to avoid redundant validations for the same strategy.
13373
+ * Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
13372
13374
  *
13373
- * @param strategyName - Name of the strategy to validate
13375
+ * @param context - Context with strategyName, exchangeName and frameName
13374
13376
  * @param methodName - Name of the calling method for error tracking
13375
13377
  */
13376
- this.validate = memoize(([strategyName]) => `${strategyName}`, (strategyName, methodName) => {
13378
+ this.validate = memoize(([context]) => `${context.strategyName}:${context.exchangeName}:${context.frameName}`, (context, methodName) => {
13377
13379
  this.loggerService.log("partialGlobalService validate", {
13378
- strategyName,
13380
+ context,
13379
13381
  methodName,
13380
13382
  });
13381
- this.strategyValidationService.validate(strategyName, methodName);
13382
- const { riskName, riskList } = this.strategySchemaService.get(strategyName);
13383
+ this.strategyValidationService.validate(context.strategyName, methodName);
13384
+ const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
13383
13385
  riskName && this.riskValidationService.validate(riskName, methodName);
13384
13386
  riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
13385
13387
  });
@@ -13405,7 +13407,11 @@ class PartialGlobalService {
13405
13407
  backtest,
13406
13408
  when,
13407
13409
  });
13408
- this.validate(data.strategyName, "partialGlobalService profit");
13410
+ this.validate({
13411
+ strategyName: data.strategyName,
13412
+ exchangeName: data.exchangeName,
13413
+ frameName: data.frameName
13414
+ }, "partialGlobalService profit");
13409
13415
  return await this.partialConnectionService.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
13410
13416
  };
13411
13417
  /**
@@ -13430,7 +13436,11 @@ class PartialGlobalService {
13430
13436
  backtest,
13431
13437
  when,
13432
13438
  });
13433
- this.validate(data.strategyName, "partialGlobalService loss");
13439
+ this.validate({
13440
+ strategyName: data.strategyName,
13441
+ exchangeName: data.exchangeName,
13442
+ frameName: data.frameName
13443
+ }, "partialGlobalService loss");
13434
13444
  return await this.partialConnectionService.loss(symbol, data, currentPrice, lossPercent, backtest, when);
13435
13445
  };
13436
13446
  /**
@@ -13450,7 +13460,11 @@ class PartialGlobalService {
13450
13460
  priceClose,
13451
13461
  backtest,
13452
13462
  });
13453
- this.validate(data.strategyName, "partialGlobalService clear");
13463
+ this.validate({
13464
+ strategyName: data.strategyName,
13465
+ exchangeName: data.exchangeName,
13466
+ frameName: data.frameName
13467
+ }, "partialGlobalService clear");
13454
13468
  return await this.partialConnectionService.clear(symbol, data, priceClose, backtest);
13455
13469
  };
13456
13470
  }
@@ -18555,15 +18569,27 @@ const HEAT_METHOD_NAME_DUMP = "HeatUtils.dump";
18555
18569
  * import { Heat } from "backtest-kit";
18556
18570
  *
18557
18571
  * // Get raw heatmap data for a strategy
18558
- * const stats = await Heat.getData("my-strategy");
18572
+ * const stats = await Heat.getData({
18573
+ * strategyName: "my-strategy",
18574
+ * exchangeName: "binance",
18575
+ * frameName: "frame1"
18576
+ * });
18559
18577
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18560
18578
  *
18561
18579
  * // Generate markdown report
18562
- * const markdown = await Heat.getReport("my-strategy");
18580
+ * const markdown = await Heat.getReport({
18581
+ * strategyName: "my-strategy",
18582
+ * exchangeName: "binance",
18583
+ * frameName: "frame1"
18584
+ * });
18563
18585
  * console.log(markdown);
18564
18586
  *
18565
18587
  * // Save to disk
18566
- * await Heat.dump("my-strategy", "./reports");
18588
+ * await Heat.dump({
18589
+ * strategyName: "my-strategy",
18590
+ * exchangeName: "binance",
18591
+ * frameName: "frame1"
18592
+ * }, false, "./reports");
18567
18593
  * ```
18568
18594
  */
18569
18595
  class HeatUtils {
@@ -18574,14 +18600,14 @@ class HeatUtils {
18574
18600
  * Returns per-symbol breakdown and portfolio-wide metrics.
18575
18601
  * Data is automatically collected from all closed signals for the strategy.
18576
18602
  *
18577
- * @param strategyName - Strategy name to get heatmap data for
18578
- * @param context - Execution context with exchangeName and frameName
18603
+ * @param context - Execution context with strategyName, exchangeName and frameName
18579
18604
  * @param backtest - True if backtest mode, false if live mode (default: false)
18580
18605
  * @returns Promise resolving to heatmap statistics object
18581
18606
  *
18582
18607
  * @example
18583
18608
  * ```typescript
18584
- * const stats = await Heat.getData("my-strategy", {
18609
+ * const stats = await Heat.getData({
18610
+ * strategyName: "my-strategy",
18585
18611
  * exchangeName: "binance",
18586
18612
  * frameName: "frame1"
18587
18613
  * });
@@ -18596,11 +18622,11 @@ class HeatUtils {
18596
18622
  * });
18597
18623
  * ```
18598
18624
  */
18599
- this.getData = async (strategyName, context, backtest = false) => {
18600
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
18601
- 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);
18602
18628
  {
18603
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18629
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18604
18630
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
18605
18631
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
18606
18632
  }
@@ -18612,15 +18638,15 @@ class HeatUtils {
18612
18638
  * Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
18613
18639
  * Symbols are sorted by Total PNL descending.
18614
18640
  *
18615
- * @param strategyName - Strategy name to generate heatmap report for
18616
- * @param context - Execution context with exchangeName and frameName
18641
+ * @param context - Execution context with strategyName, exchangeName and frameName
18617
18642
  * @param backtest - True if backtest mode, false if live mode (default: false)
18618
18643
  * @param columns - Optional columns configuration for the report
18619
18644
  * @returns Promise resolving to markdown formatted report string
18620
18645
  *
18621
18646
  * @example
18622
18647
  * ```typescript
18623
- * const markdown = await Heat.getReport("my-strategy", {
18648
+ * const markdown = await Heat.getReport({
18649
+ * strategyName: "my-strategy",
18624
18650
  * exchangeName: "binance",
18625
18651
  * frameName: "frame1"
18626
18652
  * });
@@ -18637,15 +18663,15 @@ class HeatUtils {
18637
18663
  * // ...
18638
18664
  * ```
18639
18665
  */
18640
- this.getReport = async (strategyName, context, backtest = false, columns) => {
18641
- backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
18642
- 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);
18643
18669
  {
18644
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18670
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18645
18671
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
18646
18672
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
18647
18673
  }
18648
- return await backtest$1.heatMarkdownService.getReport(strategyName, context.exchangeName, context.frameName, backtest, columns);
18674
+ return await backtest$1.heatMarkdownService.getReport(context.strategyName, context.exchangeName, context.frameName, backtest, columns);
18649
18675
  };
18650
18676
  /**
18651
18677
  * Saves heatmap report to disk for a strategy.
@@ -18653,8 +18679,7 @@ class HeatUtils {
18653
18679
  * Creates directory if it doesn't exist.
18654
18680
  * Default filename: {strategyName}.md
18655
18681
  *
18656
- * @param strategyName - Strategy name to save heatmap report for
18657
- * @param context - Execution context with exchangeName and frameName
18682
+ * @param context - Execution context with strategyName, exchangeName and frameName
18658
18683
  * @param backtest - True if backtest mode, false if live mode (default: false)
18659
18684
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
18660
18685
  * @param columns - Optional columns configuration for the report
@@ -18662,27 +18687,29 @@ class HeatUtils {
18662
18687
  * @example
18663
18688
  * ```typescript
18664
18689
  * // Save to default path: ./dump/heatmap/my-strategy.md
18665
- * await Heat.dump("my-strategy", {
18690
+ * await Heat.dump({
18691
+ * strategyName: "my-strategy",
18666
18692
  * exchangeName: "binance",
18667
18693
  * frameName: "frame1"
18668
18694
  * });
18669
18695
  *
18670
18696
  * // Save to custom path: ./reports/my-strategy.md
18671
- * await Heat.dump("my-strategy", {
18697
+ * await Heat.dump({
18698
+ * strategyName: "my-strategy",
18672
18699
  * exchangeName: "binance",
18673
18700
  * frameName: "frame1"
18674
18701
  * }, false, "./reports");
18675
18702
  * ```
18676
18703
  */
18677
- this.dump = async (strategyName, context, backtest = false, path, columns) => {
18678
- backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
18679
- 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);
18680
18707
  {
18681
- const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
18708
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
18682
18709
  riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
18683
18710
  riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
18684
18711
  }
18685
- await backtest$1.heatMarkdownService.dump(strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18712
+ await backtest$1.heatMarkdownService.dump(context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
18686
18713
  };
18687
18714
  }
18688
18715
  }
@@ -18694,7 +18721,11 @@ class HeatUtils {
18694
18721
  * import { Heat } from "backtest-kit";
18695
18722
  *
18696
18723
  * // Strategy-specific heatmap
18697
- * const stats = await Heat.getData("my-strategy");
18724
+ * const stats = await Heat.getData({
18725
+ * strategyName: "my-strategy",
18726
+ * exchangeName: "binance",
18727
+ * frameName: "frame1"
18728
+ * });
18698
18729
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
18699
18730
  * console.log(`Total Symbols: ${stats.totalSymbols}`);
18700
18731
  *
@@ -18708,7 +18739,11 @@ class HeatUtils {
18708
18739
  * });
18709
18740
  *
18710
18741
  * // Generate and save report
18711
- * await Heat.dump("my-strategy", "./reports");
18742
+ * await Heat.dump({
18743
+ * strategyName: "my-strategy",
18744
+ * exchangeName: "binance",
18745
+ * frameName: "frame1"
18746
+ * }, false, "./reports");
18712
18747
  * ```
18713
18748
  */
18714
18749
  const Heat = new HeatUtils();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "1.7.1",
3
+ "version": "1.7.2",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -7588,15 +7588,27 @@ declare class HeatMarkdownService {
7588
7588
  * import { Heat } from "backtest-kit";
7589
7589
  *
7590
7590
  * // Get raw heatmap data for a strategy
7591
- * const stats = await Heat.getData("my-strategy");
7591
+ * const stats = await Heat.getData({
7592
+ * strategyName: "my-strategy",
7593
+ * exchangeName: "binance",
7594
+ * frameName: "frame1"
7595
+ * });
7592
7596
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
7593
7597
  *
7594
7598
  * // Generate markdown report
7595
- * const markdown = await Heat.getReport("my-strategy");
7599
+ * const markdown = await Heat.getReport({
7600
+ * strategyName: "my-strategy",
7601
+ * exchangeName: "binance",
7602
+ * frameName: "frame1"
7603
+ * });
7596
7604
  * console.log(markdown);
7597
7605
  *
7598
7606
  * // Save to disk
7599
- * await Heat.dump("my-strategy", "./reports");
7607
+ * await Heat.dump({
7608
+ * strategyName: "my-strategy",
7609
+ * exchangeName: "binance",
7610
+ * frameName: "frame1"
7611
+ * }, false, "./reports");
7600
7612
  * ```
7601
7613
  */
7602
7614
  declare class HeatUtils {
@@ -7606,14 +7618,14 @@ declare class HeatUtils {
7606
7618
  * Returns per-symbol breakdown and portfolio-wide metrics.
7607
7619
  * Data is automatically collected from all closed signals for the strategy.
7608
7620
  *
7609
- * @param strategyName - Strategy name to get heatmap data for
7610
- * @param context - Execution context with exchangeName and frameName
7621
+ * @param context - Execution context with strategyName, exchangeName and frameName
7611
7622
  * @param backtest - True if backtest mode, false if live mode (default: false)
7612
7623
  * @returns Promise resolving to heatmap statistics object
7613
7624
  *
7614
7625
  * @example
7615
7626
  * ```typescript
7616
- * const stats = await Heat.getData("my-strategy", {
7627
+ * const stats = await Heat.getData({
7628
+ * strategyName: "my-strategy",
7617
7629
  * exchangeName: "binance",
7618
7630
  * frameName: "frame1"
7619
7631
  * });
@@ -7628,7 +7640,8 @@ declare class HeatUtils {
7628
7640
  * });
7629
7641
  * ```
7630
7642
  */
7631
- getData: (strategyName: StrategyName, context: {
7643
+ getData: (context: {
7644
+ strategyName: string;
7632
7645
  exchangeName: string;
7633
7646
  frameName: string;
7634
7647
  }, backtest?: boolean) => Promise<HeatmapStatisticsModel>;
@@ -7638,15 +7651,15 @@ declare class HeatUtils {
7638
7651
  * Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
7639
7652
  * Symbols are sorted by Total PNL descending.
7640
7653
  *
7641
- * @param strategyName - Strategy name to generate heatmap report for
7642
- * @param context - Execution context with exchangeName and frameName
7654
+ * @param context - Execution context with strategyName, exchangeName and frameName
7643
7655
  * @param backtest - True if backtest mode, false if live mode (default: false)
7644
7656
  * @param columns - Optional columns configuration for the report
7645
7657
  * @returns Promise resolving to markdown formatted report string
7646
7658
  *
7647
7659
  * @example
7648
7660
  * ```typescript
7649
- * const markdown = await Heat.getReport("my-strategy", {
7661
+ * const markdown = await Heat.getReport({
7662
+ * strategyName: "my-strategy",
7650
7663
  * exchangeName: "binance",
7651
7664
  * frameName: "frame1"
7652
7665
  * });
@@ -7663,7 +7676,8 @@ declare class HeatUtils {
7663
7676
  * // ...
7664
7677
  * ```
7665
7678
  */
7666
- getReport: (strategyName: StrategyName, context: {
7679
+ getReport: (context: {
7680
+ strategyName: string;
7667
7681
  exchangeName: string;
7668
7682
  frameName: string;
7669
7683
  }, backtest?: boolean, columns?: Columns$2[]) => Promise<string>;
@@ -7673,8 +7687,7 @@ declare class HeatUtils {
7673
7687
  * Creates directory if it doesn't exist.
7674
7688
  * Default filename: {strategyName}.md
7675
7689
  *
7676
- * @param strategyName - Strategy name to save heatmap report for
7677
- * @param context - Execution context with exchangeName and frameName
7690
+ * @param context - Execution context with strategyName, exchangeName and frameName
7678
7691
  * @param backtest - True if backtest mode, false if live mode (default: false)
7679
7692
  * @param path - Optional directory path to save report (default: "./dump/heatmap")
7680
7693
  * @param columns - Optional columns configuration for the report
@@ -7682,19 +7695,22 @@ declare class HeatUtils {
7682
7695
  * @example
7683
7696
  * ```typescript
7684
7697
  * // Save to default path: ./dump/heatmap/my-strategy.md
7685
- * await Heat.dump("my-strategy", {
7698
+ * await Heat.dump({
7699
+ * strategyName: "my-strategy",
7686
7700
  * exchangeName: "binance",
7687
7701
  * frameName: "frame1"
7688
7702
  * });
7689
7703
  *
7690
7704
  * // Save to custom path: ./reports/my-strategy.md
7691
- * await Heat.dump("my-strategy", {
7705
+ * await Heat.dump({
7706
+ * strategyName: "my-strategy",
7692
7707
  * exchangeName: "binance",
7693
7708
  * frameName: "frame1"
7694
7709
  * }, false, "./reports");
7695
7710
  * ```
7696
7711
  */
7697
- dump: (strategyName: StrategyName, context: {
7712
+ dump: (context: {
7713
+ strategyName: string;
7698
7714
  exchangeName: string;
7699
7715
  frameName: string;
7700
7716
  }, backtest?: boolean, path?: string, columns?: Columns$2[]) => Promise<void>;
@@ -7707,7 +7723,11 @@ declare class HeatUtils {
7707
7723
  * import { Heat } from "backtest-kit";
7708
7724
  *
7709
7725
  * // Strategy-specific heatmap
7710
- * const stats = await Heat.getData("my-strategy");
7726
+ * const stats = await Heat.getData({
7727
+ * strategyName: "my-strategy",
7728
+ * exchangeName: "binance",
7729
+ * frameName: "frame1"
7730
+ * });
7711
7731
  * console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
7712
7732
  * console.log(`Total Symbols: ${stats.totalSymbols}`);
7713
7733
  *
@@ -7721,7 +7741,11 @@ declare class HeatUtils {
7721
7741
  * });
7722
7742
  *
7723
7743
  * // Generate and save report
7724
- * await Heat.dump("my-strategy", "./reports");
7744
+ * await Heat.dump({
7745
+ * strategyName: "my-strategy",
7746
+ * exchangeName: "binance",
7747
+ * frameName: "frame1"
7748
+ * }, false, "./reports");
7725
7749
  * ```
7726
7750
  */
7727
7751
  declare const Heat: HeatUtils;
@@ -10127,10 +10151,10 @@ declare class StrategyCoreService {
10127
10151
  /**
10128
10152
  * Validates strategy and associated risk configuration.
10129
10153
  *
10130
- * Memoized to avoid redundant validations for the same symbol-strategy pair.
10154
+ * Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
10131
10155
  * Logs validation activity.
10132
10156
  * @param symbol - Trading pair symbol
10133
- * @param strategyName - Name of the strategy to validate
10157
+ * @param context - Execution context with strategyName, exchangeName, frameName
10134
10158
  * @returns Promise that resolves when validation is complete
10135
10159
  */
10136
10160
  private validate;
@@ -10319,9 +10343,9 @@ declare class RiskGlobalService {
10319
10343
  private readonly riskValidationService;
10320
10344
  /**
10321
10345
  * Validates risk configuration.
10322
- * Memoized to avoid redundant validations for the same risk instance.
10346
+ * Memoized to avoid redundant validations for the same risk-exchange-frame combination.
10323
10347
  * Logs validation activity.
10324
- * @param riskName - Name of the risk instance to validate
10348
+ * @param payload - Payload with riskName, exchangeName and frameName
10325
10349
  * @returns Promise that resolves when validation is complete
10326
10350
  */
10327
10351
  private validate;
@@ -11721,9 +11745,9 @@ declare class PartialGlobalService {
11721
11745
  private readonly riskValidationService;
11722
11746
  /**
11723
11747
  * Validates strategy and associated risk configuration.
11724
- * Memoized to avoid redundant validations for the same strategy.
11748
+ * Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
11725
11749
  *
11726
- * @param strategyName - Name of the strategy to validate
11750
+ * @param context - Context with strategyName, exchangeName and frameName
11727
11751
  * @param methodName - Name of the calling method for error tracking
11728
11752
  */
11729
11753
  private validate;