backtest-kit 1.5.36 → 1.5.38

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
@@ -2879,6 +2879,9 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
2879
2879
  errors.push(`position must be "long" or "short", got "${signal.position}"`);
2880
2880
  }
2881
2881
  // ЗАЩИТА ОТ NaN/Infinity: currentPrice должна быть конечным числом
2882
+ if (typeof currentPrice !== "number") {
2883
+ errors.push(`currentPrice must be a number type, got ${currentPrice} (${typeof currentPrice})`);
2884
+ }
2882
2885
  if (!isFinite(currentPrice)) {
2883
2886
  errors.push(`currentPrice must be a finite number, got ${currentPrice} (${typeof currentPrice})`);
2884
2887
  }
@@ -2886,12 +2889,21 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
2886
2889
  errors.push(`currentPrice must be positive, got ${currentPrice}`);
2887
2890
  }
2888
2891
  // ЗАЩИТА ОТ NaN/Infinity: все цены должны быть конечными числами
2892
+ if (typeof signal.priceOpen !== "number") {
2893
+ errors.push(`priceOpen must be a number type, got ${signal.priceOpen} (${typeof signal.priceOpen})`);
2894
+ }
2889
2895
  if (!isFinite(signal.priceOpen)) {
2890
2896
  errors.push(`priceOpen must be a finite number, got ${signal.priceOpen} (${typeof signal.priceOpen})`);
2891
2897
  }
2898
+ if (typeof signal.priceTakeProfit !== "number") {
2899
+ errors.push(`priceTakeProfit must be a number type, got ${signal.priceTakeProfit} (${typeof signal.priceTakeProfit})`);
2900
+ }
2892
2901
  if (!isFinite(signal.priceTakeProfit)) {
2893
2902
  errors.push(`priceTakeProfit must be a finite number, got ${signal.priceTakeProfit} (${typeof signal.priceTakeProfit})`);
2894
2903
  }
2904
+ if (typeof signal.priceStopLoss !== "number") {
2905
+ errors.push(`priceStopLoss must be a number type, got ${signal.priceStopLoss} (${typeof signal.priceStopLoss})`);
2906
+ }
2895
2907
  if (!isFinite(signal.priceStopLoss)) {
2896
2908
  errors.push(`priceStopLoss must be a finite number, got ${signal.priceStopLoss} (${typeof signal.priceStopLoss})`);
2897
2909
  }
@@ -3030,12 +3042,18 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
3030
3042
  }
3031
3043
  }
3032
3044
  // Валидация временных параметров
3045
+ if (typeof signal.minuteEstimatedTime !== "number") {
3046
+ errors.push(`minuteEstimatedTime must be a number type, got ${signal.minuteEstimatedTime} (${typeof signal.minuteEstimatedTime})`);
3047
+ }
3033
3048
  if (signal.minuteEstimatedTime <= 0) {
3034
3049
  errors.push(`minuteEstimatedTime must be positive, got ${signal.minuteEstimatedTime}`);
3035
3050
  }
3036
3051
  if (!Number.isInteger(signal.minuteEstimatedTime)) {
3037
3052
  errors.push(`minuteEstimatedTime must be an integer (whole number), got ${signal.minuteEstimatedTime}`);
3038
3053
  }
3054
+ if (!isFinite(signal.minuteEstimatedTime)) {
3055
+ errors.push(`minuteEstimatedTime must be a finite number, got ${signal.minuteEstimatedTime}`);
3056
+ }
3039
3057
  // ЗАЩИТА ОТ ВЕЧНЫХ СИГНАЛОВ: ограничиваем максимальное время жизни сигнала
3040
3058
  if (GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES && GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
3041
3059
  if (signal.minuteEstimatedTime > GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
@@ -3046,9 +3064,15 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
3046
3064
  `Eternal signals block risk limits and prevent new trades.`);
3047
3065
  }
3048
3066
  }
3067
+ if (typeof signal.scheduledAt !== "number") {
3068
+ errors.push(`scheduledAt must be a number type, got ${signal.scheduledAt} (${typeof signal.scheduledAt})`);
3069
+ }
3049
3070
  if (signal.scheduledAt <= 0) {
3050
3071
  errors.push(`scheduledAt must be positive, got ${signal.scheduledAt}`);
3051
3072
  }
3073
+ if (typeof signal.pendingAt !== "number") {
3074
+ errors.push(`pendingAt must be a number type, got ${signal.pendingAt} (${typeof signal.pendingAt})`);
3075
+ }
3052
3076
  if (signal.pendingAt <= 0) {
3053
3077
  errors.push(`pendingAt must be positive, got ${signal.pendingAt}`);
3054
3078
  }
@@ -18426,7 +18450,8 @@ class ExchangeUtils {
18426
18450
  */
18427
18451
  const Exchange = new ExchangeUtils();
18428
18452
 
18429
- const CACHE_METHOD_NAME_CLEAR = "CacheUtils.clear";
18453
+ const CACHE_METHOD_NAME_FLUSH = "CacheUtils.flush";
18454
+ const CACHE_METHOD_NAME_CLEAR = "CacheInstance.clear";
18430
18455
  const CACHE_METHOD_NAME_RUN = "CacheInstance.run";
18431
18456
  const CACHE_METHOD_NAME_FN = "CacheUtils.fn";
18432
18457
  const INTERVAL_MINUTES = {
@@ -18506,14 +18531,16 @@ class CacheInstance {
18506
18531
  this.run = (...args) => {
18507
18532
  backtest$1.loggerService.debug(CACHE_METHOD_NAME_RUN, { args });
18508
18533
  const step = INTERVAL_MINUTES[this.interval];
18509
- if (!step) {
18510
- throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
18511
- }
18512
- if (!MethodContextService.hasContext()) {
18513
- throw new Error("CacheInstance run requires method context");
18514
- }
18515
- if (!ExecutionContextService.hasContext()) {
18516
- throw new Error("CacheInstance run requires execution context");
18534
+ {
18535
+ if (!MethodContextService.hasContext()) {
18536
+ throw new Error("CacheInstance run requires method context");
18537
+ }
18538
+ if (!ExecutionContextService.hasContext()) {
18539
+ throw new Error("CacheInstance run requires execution context");
18540
+ }
18541
+ if (!step) {
18542
+ throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
18543
+ }
18517
18544
  }
18518
18545
  const key = createKey(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
18519
18546
  const currentWhen = backtest$1.executionContextService.context.when;
@@ -18532,6 +18559,30 @@ class CacheInstance {
18532
18559
  this._cacheMap.set(key, newCache);
18533
18560
  return newCache;
18534
18561
  };
18562
+ /**
18563
+ * Clear cached value for current execution context.
18564
+ *
18565
+ * Removes the cached entry for the current strategy/exchange/mode combination
18566
+ * from this instance's cache map. The next `run()` call will recompute the value.
18567
+ *
18568
+ * Requires active execution context (strategy, exchange, backtest mode) and method context
18569
+ * to determine which cache entry to clear.
18570
+ *
18571
+ * @example
18572
+ * ```typescript
18573
+ * const instance = new CacheInstance(calculateIndicator, "1h");
18574
+ * const result1 = instance.run("BTCUSDT", 14); // Computed
18575
+ * const result2 = instance.run("BTCUSDT", 14); // Cached
18576
+ *
18577
+ * instance.clear(); // Clear cache for current context
18578
+ *
18579
+ * const result3 = instance.run("BTCUSDT", 14); // Recomputed
18580
+ * ```
18581
+ */
18582
+ this.clear = () => {
18583
+ const key = createKey(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
18584
+ this._cacheMap.delete(key);
18585
+ };
18535
18586
  }
18536
18587
  }
18537
18588
  /**
@@ -18580,45 +18631,85 @@ class CacheUtils {
18580
18631
  * ```
18581
18632
  */
18582
18633
  this.fn = (run, context) => {
18583
- backtest$1.loggerService.debug(CACHE_METHOD_NAME_FN, {
18634
+ backtest$1.loggerService.info(CACHE_METHOD_NAME_FN, {
18584
18635
  context,
18585
18636
  });
18586
- return (...args) => {
18637
+ const wrappedFn = (...args) => {
18587
18638
  const instance = this._getInstance(run, context.interval);
18588
18639
  return instance.run(...args).value;
18589
18640
  };
18641
+ return wrappedFn;
18590
18642
  };
18591
18643
  /**
18592
- * Clear cached instances for specific function or all cached functions.
18644
+ * Flush (remove) cached CacheInstance for a specific function or all functions.
18593
18645
  *
18594
- * This method delegates to the memoized `_getInstance` function's clear method,
18595
- * which removes cached CacheInstance objects. When a CacheInstance is removed,
18596
- * all cached function results for that instance are also discarded.
18646
+ * This method removes CacheInstance objects from the internal memoization cache.
18647
+ * When a CacheInstance is flushed, all cached results across all contexts
18648
+ * (all strategy/exchange/mode combinations) for that function are discarded.
18597
18649
  *
18598
18650
  * Use cases:
18599
- * - Clear cache for a specific function when its implementation changes
18600
- * - Free memory by removing unused cached instances
18601
- * - Reset all caches when switching contexts (e.g., between different backtests)
18651
+ * - Remove specific function's CacheInstance when implementation changes
18652
+ * - Free memory by removing unused CacheInstances
18653
+ * - Reset all CacheInstances when switching between different test scenarios
18602
18654
  *
18603
- * @param run - Optional function to clear cache for. If omitted, clears all cached instances.
18655
+ * Note: This is different from `clear()` which only removes cached values
18656
+ * for the current context within an existing CacheInstance.
18657
+ *
18658
+ * @template T - Function type
18659
+ * @param run - Optional function to flush CacheInstance for. If omitted, flushes all CacheInstances.
18604
18660
  *
18605
18661
  * @example
18606
18662
  * ```typescript
18607
- * const cachedCalc = Cache.fn(calculateIndicator, { interval: "1h" });
18663
+ * const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
18608
18664
  *
18609
- * // Clear cache for specific function
18610
- * Cache.clear(calculateIndicator);
18665
+ * // Flush CacheInstance for specific function
18666
+ * Cache.flush(calculateIndicator);
18611
18667
  *
18612
- * // Clear all cached instances
18613
- * Cache.clear();
18668
+ * // Flush all CacheInstances
18669
+ * Cache.flush();
18614
18670
  * ```
18615
18671
  */
18616
- this.clear = (run) => {
18617
- backtest$1.loggerService.debug(CACHE_METHOD_NAME_CLEAR, {
18672
+ this.flush = (run) => {
18673
+ backtest$1.loggerService.info(CACHE_METHOD_NAME_FLUSH, {
18618
18674
  run,
18619
18675
  });
18620
18676
  this._getInstance.clear(run);
18621
18677
  };
18678
+ /**
18679
+ * Clear cached value for current execution context of a specific function.
18680
+ *
18681
+ * Removes the cached entry for the current strategy/exchange/mode combination
18682
+ * from the specified function's CacheInstance. The next call to the wrapped function
18683
+ * will recompute the value for that context.
18684
+ *
18685
+ * This only clears the cache for the current execution context, not all contexts.
18686
+ * Use `flush()` to remove the entire CacheInstance across all contexts.
18687
+ *
18688
+ * Requires active execution context (strategy, exchange, backtest mode) and method context.
18689
+ *
18690
+ * @template T - Function type
18691
+ * @param run - Function whose cache should be cleared for current context
18692
+ *
18693
+ * @example
18694
+ * ```typescript
18695
+ * const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
18696
+ *
18697
+ * // Within strategy execution context
18698
+ * const result1 = cachedFn("BTCUSDT", 14); // Computed
18699
+ * const result2 = cachedFn("BTCUSDT", 14); // Cached
18700
+ *
18701
+ * Cache.clear(calculateIndicator); // Clear cache for current context only
18702
+ *
18703
+ * const result3 = cachedFn("BTCUSDT", 14); // Recomputed for this context
18704
+ * // Other contexts (different strategies/exchanges) remain cached
18705
+ * ```
18706
+ */
18707
+ this.clear = (run) => {
18708
+ backtest$1.loggerService.info(CACHE_METHOD_NAME_CLEAR, {
18709
+ run,
18710
+ });
18711
+ this._getInstance.get(run).clear();
18712
+ };
18622
18713
  }
18623
18714
  }
18624
18715
  /**
package/build/index.mjs CHANGED
@@ -2877,6 +2877,9 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
2877
2877
  errors.push(`position must be "long" or "short", got "${signal.position}"`);
2878
2878
  }
2879
2879
  // ЗАЩИТА ОТ NaN/Infinity: currentPrice должна быть конечным числом
2880
+ if (typeof currentPrice !== "number") {
2881
+ errors.push(`currentPrice must be a number type, got ${currentPrice} (${typeof currentPrice})`);
2882
+ }
2880
2883
  if (!isFinite(currentPrice)) {
2881
2884
  errors.push(`currentPrice must be a finite number, got ${currentPrice} (${typeof currentPrice})`);
2882
2885
  }
@@ -2884,12 +2887,21 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
2884
2887
  errors.push(`currentPrice must be positive, got ${currentPrice}`);
2885
2888
  }
2886
2889
  // ЗАЩИТА ОТ NaN/Infinity: все цены должны быть конечными числами
2890
+ if (typeof signal.priceOpen !== "number") {
2891
+ errors.push(`priceOpen must be a number type, got ${signal.priceOpen} (${typeof signal.priceOpen})`);
2892
+ }
2887
2893
  if (!isFinite(signal.priceOpen)) {
2888
2894
  errors.push(`priceOpen must be a finite number, got ${signal.priceOpen} (${typeof signal.priceOpen})`);
2889
2895
  }
2896
+ if (typeof signal.priceTakeProfit !== "number") {
2897
+ errors.push(`priceTakeProfit must be a number type, got ${signal.priceTakeProfit} (${typeof signal.priceTakeProfit})`);
2898
+ }
2890
2899
  if (!isFinite(signal.priceTakeProfit)) {
2891
2900
  errors.push(`priceTakeProfit must be a finite number, got ${signal.priceTakeProfit} (${typeof signal.priceTakeProfit})`);
2892
2901
  }
2902
+ if (typeof signal.priceStopLoss !== "number") {
2903
+ errors.push(`priceStopLoss must be a number type, got ${signal.priceStopLoss} (${typeof signal.priceStopLoss})`);
2904
+ }
2893
2905
  if (!isFinite(signal.priceStopLoss)) {
2894
2906
  errors.push(`priceStopLoss must be a finite number, got ${signal.priceStopLoss} (${typeof signal.priceStopLoss})`);
2895
2907
  }
@@ -3028,12 +3040,18 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
3028
3040
  }
3029
3041
  }
3030
3042
  // Валидация временных параметров
3043
+ if (typeof signal.minuteEstimatedTime !== "number") {
3044
+ errors.push(`minuteEstimatedTime must be a number type, got ${signal.minuteEstimatedTime} (${typeof signal.minuteEstimatedTime})`);
3045
+ }
3031
3046
  if (signal.minuteEstimatedTime <= 0) {
3032
3047
  errors.push(`minuteEstimatedTime must be positive, got ${signal.minuteEstimatedTime}`);
3033
3048
  }
3034
3049
  if (!Number.isInteger(signal.minuteEstimatedTime)) {
3035
3050
  errors.push(`minuteEstimatedTime must be an integer (whole number), got ${signal.minuteEstimatedTime}`);
3036
3051
  }
3052
+ if (!isFinite(signal.minuteEstimatedTime)) {
3053
+ errors.push(`minuteEstimatedTime must be a finite number, got ${signal.minuteEstimatedTime}`);
3054
+ }
3037
3055
  // ЗАЩИТА ОТ ВЕЧНЫХ СИГНАЛОВ: ограничиваем максимальное время жизни сигнала
3038
3056
  if (GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES && GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
3039
3057
  if (signal.minuteEstimatedTime > GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
@@ -3044,9 +3062,15 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
3044
3062
  `Eternal signals block risk limits and prevent new trades.`);
3045
3063
  }
3046
3064
  }
3065
+ if (typeof signal.scheduledAt !== "number") {
3066
+ errors.push(`scheduledAt must be a number type, got ${signal.scheduledAt} (${typeof signal.scheduledAt})`);
3067
+ }
3047
3068
  if (signal.scheduledAt <= 0) {
3048
3069
  errors.push(`scheduledAt must be positive, got ${signal.scheduledAt}`);
3049
3070
  }
3071
+ if (typeof signal.pendingAt !== "number") {
3072
+ errors.push(`pendingAt must be a number type, got ${signal.pendingAt} (${typeof signal.pendingAt})`);
3073
+ }
3050
3074
  if (signal.pendingAt <= 0) {
3051
3075
  errors.push(`pendingAt must be positive, got ${signal.pendingAt}`);
3052
3076
  }
@@ -18424,7 +18448,8 @@ class ExchangeUtils {
18424
18448
  */
18425
18449
  const Exchange = new ExchangeUtils();
18426
18450
 
18427
- const CACHE_METHOD_NAME_CLEAR = "CacheUtils.clear";
18451
+ const CACHE_METHOD_NAME_FLUSH = "CacheUtils.flush";
18452
+ const CACHE_METHOD_NAME_CLEAR = "CacheInstance.clear";
18428
18453
  const CACHE_METHOD_NAME_RUN = "CacheInstance.run";
18429
18454
  const CACHE_METHOD_NAME_FN = "CacheUtils.fn";
18430
18455
  const INTERVAL_MINUTES = {
@@ -18504,14 +18529,16 @@ class CacheInstance {
18504
18529
  this.run = (...args) => {
18505
18530
  backtest$1.loggerService.debug(CACHE_METHOD_NAME_RUN, { args });
18506
18531
  const step = INTERVAL_MINUTES[this.interval];
18507
- if (!step) {
18508
- throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
18509
- }
18510
- if (!MethodContextService.hasContext()) {
18511
- throw new Error("CacheInstance run requires method context");
18512
- }
18513
- if (!ExecutionContextService.hasContext()) {
18514
- throw new Error("CacheInstance run requires execution context");
18532
+ {
18533
+ if (!MethodContextService.hasContext()) {
18534
+ throw new Error("CacheInstance run requires method context");
18535
+ }
18536
+ if (!ExecutionContextService.hasContext()) {
18537
+ throw new Error("CacheInstance run requires execution context");
18538
+ }
18539
+ if (!step) {
18540
+ throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
18541
+ }
18515
18542
  }
18516
18543
  const key = createKey(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
18517
18544
  const currentWhen = backtest$1.executionContextService.context.when;
@@ -18530,6 +18557,30 @@ class CacheInstance {
18530
18557
  this._cacheMap.set(key, newCache);
18531
18558
  return newCache;
18532
18559
  };
18560
+ /**
18561
+ * Clear cached value for current execution context.
18562
+ *
18563
+ * Removes the cached entry for the current strategy/exchange/mode combination
18564
+ * from this instance's cache map. The next `run()` call will recompute the value.
18565
+ *
18566
+ * Requires active execution context (strategy, exchange, backtest mode) and method context
18567
+ * to determine which cache entry to clear.
18568
+ *
18569
+ * @example
18570
+ * ```typescript
18571
+ * const instance = new CacheInstance(calculateIndicator, "1h");
18572
+ * const result1 = instance.run("BTCUSDT", 14); // Computed
18573
+ * const result2 = instance.run("BTCUSDT", 14); // Cached
18574
+ *
18575
+ * instance.clear(); // Clear cache for current context
18576
+ *
18577
+ * const result3 = instance.run("BTCUSDT", 14); // Recomputed
18578
+ * ```
18579
+ */
18580
+ this.clear = () => {
18581
+ const key = createKey(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
18582
+ this._cacheMap.delete(key);
18583
+ };
18533
18584
  }
18534
18585
  }
18535
18586
  /**
@@ -18578,45 +18629,85 @@ class CacheUtils {
18578
18629
  * ```
18579
18630
  */
18580
18631
  this.fn = (run, context) => {
18581
- backtest$1.loggerService.debug(CACHE_METHOD_NAME_FN, {
18632
+ backtest$1.loggerService.info(CACHE_METHOD_NAME_FN, {
18582
18633
  context,
18583
18634
  });
18584
- return (...args) => {
18635
+ const wrappedFn = (...args) => {
18585
18636
  const instance = this._getInstance(run, context.interval);
18586
18637
  return instance.run(...args).value;
18587
18638
  };
18639
+ return wrappedFn;
18588
18640
  };
18589
18641
  /**
18590
- * Clear cached instances for specific function or all cached functions.
18642
+ * Flush (remove) cached CacheInstance for a specific function or all functions.
18591
18643
  *
18592
- * This method delegates to the memoized `_getInstance` function's clear method,
18593
- * which removes cached CacheInstance objects. When a CacheInstance is removed,
18594
- * all cached function results for that instance are also discarded.
18644
+ * This method removes CacheInstance objects from the internal memoization cache.
18645
+ * When a CacheInstance is flushed, all cached results across all contexts
18646
+ * (all strategy/exchange/mode combinations) for that function are discarded.
18595
18647
  *
18596
18648
  * Use cases:
18597
- * - Clear cache for a specific function when its implementation changes
18598
- * - Free memory by removing unused cached instances
18599
- * - Reset all caches when switching contexts (e.g., between different backtests)
18649
+ * - Remove specific function's CacheInstance when implementation changes
18650
+ * - Free memory by removing unused CacheInstances
18651
+ * - Reset all CacheInstances when switching between different test scenarios
18600
18652
  *
18601
- * @param run - Optional function to clear cache for. If omitted, clears all cached instances.
18653
+ * Note: This is different from `clear()` which only removes cached values
18654
+ * for the current context within an existing CacheInstance.
18655
+ *
18656
+ * @template T - Function type
18657
+ * @param run - Optional function to flush CacheInstance for. If omitted, flushes all CacheInstances.
18602
18658
  *
18603
18659
  * @example
18604
18660
  * ```typescript
18605
- * const cachedCalc = Cache.fn(calculateIndicator, { interval: "1h" });
18661
+ * const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
18606
18662
  *
18607
- * // Clear cache for specific function
18608
- * Cache.clear(calculateIndicator);
18663
+ * // Flush CacheInstance for specific function
18664
+ * Cache.flush(calculateIndicator);
18609
18665
  *
18610
- * // Clear all cached instances
18611
- * Cache.clear();
18666
+ * // Flush all CacheInstances
18667
+ * Cache.flush();
18612
18668
  * ```
18613
18669
  */
18614
- this.clear = (run) => {
18615
- backtest$1.loggerService.debug(CACHE_METHOD_NAME_CLEAR, {
18670
+ this.flush = (run) => {
18671
+ backtest$1.loggerService.info(CACHE_METHOD_NAME_FLUSH, {
18616
18672
  run,
18617
18673
  });
18618
18674
  this._getInstance.clear(run);
18619
18675
  };
18676
+ /**
18677
+ * Clear cached value for current execution context of a specific function.
18678
+ *
18679
+ * Removes the cached entry for the current strategy/exchange/mode combination
18680
+ * from the specified function's CacheInstance. The next call to the wrapped function
18681
+ * will recompute the value for that context.
18682
+ *
18683
+ * This only clears the cache for the current execution context, not all contexts.
18684
+ * Use `flush()` to remove the entire CacheInstance across all contexts.
18685
+ *
18686
+ * Requires active execution context (strategy, exchange, backtest mode) and method context.
18687
+ *
18688
+ * @template T - Function type
18689
+ * @param run - Function whose cache should be cleared for current context
18690
+ *
18691
+ * @example
18692
+ * ```typescript
18693
+ * const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
18694
+ *
18695
+ * // Within strategy execution context
18696
+ * const result1 = cachedFn("BTCUSDT", 14); // Computed
18697
+ * const result2 = cachedFn("BTCUSDT", 14); // Cached
18698
+ *
18699
+ * Cache.clear(calculateIndicator); // Clear cache for current context only
18700
+ *
18701
+ * const result3 = cachedFn("BTCUSDT", 14); // Recomputed for this context
18702
+ * // Other contexts (different strategies/exchanges) remain cached
18703
+ * ```
18704
+ */
18705
+ this.clear = (run) => {
18706
+ backtest$1.loggerService.info(CACHE_METHOD_NAME_CLEAR, {
18707
+ run,
18708
+ });
18709
+ this._getInstance.get(run).clear();
18710
+ };
18620
18711
  }
18621
18712
  }
18622
18713
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "1.5.36",
3
+ "version": "1.5.38",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -7865,33 +7865,67 @@ declare class CacheUtils {
7865
7865
  */
7866
7866
  fn: <T extends Function>(run: T, context: {
7867
7867
  interval: CandleInterval;
7868
- }) => Function;
7868
+ }) => T;
7869
7869
  /**
7870
- * Clear cached instances for specific function or all cached functions.
7870
+ * Flush (remove) cached CacheInstance for a specific function or all functions.
7871
7871
  *
7872
- * This method delegates to the memoized `_getInstance` function's clear method,
7873
- * which removes cached CacheInstance objects. When a CacheInstance is removed,
7874
- * all cached function results for that instance are also discarded.
7872
+ * This method removes CacheInstance objects from the internal memoization cache.
7873
+ * When a CacheInstance is flushed, all cached results across all contexts
7874
+ * (all strategy/exchange/mode combinations) for that function are discarded.
7875
7875
  *
7876
7876
  * Use cases:
7877
- * - Clear cache for a specific function when its implementation changes
7878
- * - Free memory by removing unused cached instances
7879
- * - Reset all caches when switching contexts (e.g., between different backtests)
7877
+ * - Remove specific function's CacheInstance when implementation changes
7878
+ * - Free memory by removing unused CacheInstances
7879
+ * - Reset all CacheInstances when switching between different test scenarios
7880
7880
  *
7881
- * @param run - Optional function to clear cache for. If omitted, clears all cached instances.
7881
+ * Note: This is different from `clear()` which only removes cached values
7882
+ * for the current context within an existing CacheInstance.
7883
+ *
7884
+ * @template T - Function type
7885
+ * @param run - Optional function to flush CacheInstance for. If omitted, flushes all CacheInstances.
7886
+ *
7887
+ * @example
7888
+ * ```typescript
7889
+ * const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
7890
+ *
7891
+ * // Flush CacheInstance for specific function
7892
+ * Cache.flush(calculateIndicator);
7893
+ *
7894
+ * // Flush all CacheInstances
7895
+ * Cache.flush();
7896
+ * ```
7897
+ */
7898
+ flush: <T extends Function>(run?: T) => void;
7899
+ /**
7900
+ * Clear cached value for current execution context of a specific function.
7901
+ *
7902
+ * Removes the cached entry for the current strategy/exchange/mode combination
7903
+ * from the specified function's CacheInstance. The next call to the wrapped function
7904
+ * will recompute the value for that context.
7905
+ *
7906
+ * This only clears the cache for the current execution context, not all contexts.
7907
+ * Use `flush()` to remove the entire CacheInstance across all contexts.
7908
+ *
7909
+ * Requires active execution context (strategy, exchange, backtest mode) and method context.
7910
+ *
7911
+ * @template T - Function type
7912
+ * @param run - Function whose cache should be cleared for current context
7882
7913
  *
7883
7914
  * @example
7884
7915
  * ```typescript
7885
- * const cachedCalc = Cache.fn(calculateIndicator, { interval: "1h" });
7916
+ * const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
7917
+ *
7918
+ * // Within strategy execution context
7919
+ * const result1 = cachedFn("BTCUSDT", 14); // Computed
7920
+ * const result2 = cachedFn("BTCUSDT", 14); // Cached
7886
7921
  *
7887
- * // Clear cache for specific function
7888
- * Cache.clear(calculateIndicator);
7922
+ * Cache.clear(calculateIndicator); // Clear cache for current context only
7889
7923
  *
7890
- * // Clear all cached instances
7891
- * Cache.clear();
7924
+ * const result3 = cachedFn("BTCUSDT", 14); // Recomputed for this context
7925
+ * // Other contexts (different strategies/exchanges) remain cached
7892
7926
  * ```
7893
7927
  */
7894
- clear: <T extends Function>(run?: T) => void;
7928
+ clear: <T extends Function>(run: T) => void;
7895
7929
  }
7896
7930
  /**
7897
7931
  * Singleton instance of CacheUtils for convenient function caching.