backtest-kit 3.0.6 → 3.0.7

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
@@ -36307,6 +36307,11 @@ const CREATE_KEY_FN = (strategyName, exchangeName, frameName, backtest) => {
36307
36307
  parts.push(backtest ? "backtest" : "live");
36308
36308
  return parts.join(":");
36309
36309
  };
36310
+ /**
36311
+ * A unique symbol representing a value that should never occur.
36312
+ * Used as default key when no key function is provided.
36313
+ */
36314
+ const NEVER_VALUE = Symbol("never");
36310
36315
  /**
36311
36316
  * Instance class for caching function results with timeframe-based invalidation.
36312
36317
  *
@@ -36315,6 +36320,7 @@ const CREATE_KEY_FN = (strategyName, exchangeName, frameName, backtest) => {
36315
36320
  * Cache is invalidated when the current time moves to a different interval.
36316
36321
  *
36317
36322
  * @template T - Function type to cache
36323
+ * @template K - Key type for argument-based caching
36318
36324
  *
36319
36325
  * @example
36320
36326
  * ```typescript
@@ -36331,11 +36337,13 @@ class CacheInstance {
36331
36337
  *
36332
36338
  * @param fn - Function to cache
36333
36339
  * @param interval - Candle interval for cache invalidation (e.g., "1m", "1h")
36340
+ * @param key - Optional key generator function for argument-based caching
36334
36341
  */
36335
- constructor(fn, interval) {
36342
+ constructor(fn, interval, key = () => NEVER_VALUE) {
36336
36343
  this.fn = fn;
36337
36344
  this.interval = interval;
36338
- /** Cache map storing results per strategy/exchange/mode combination */
36345
+ this.key = key;
36346
+ /** Cache map storing results per strategy/exchange/mode/argKey combination */
36339
36347
  this._cacheMap = new Map();
36340
36348
  /**
36341
36349
  * Execute function with caching based on timeframe intervals.
@@ -36382,7 +36390,9 @@ class CacheInstance {
36382
36390
  throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
36383
36391
  }
36384
36392
  }
36385
- const key = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36393
+ const contextKey = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36394
+ const argKey = String(this.key(args));
36395
+ const key = `${contextKey}:${argKey}`;
36386
36396
  const currentWhen = bt.executionContextService.context.when;
36387
36397
  const cached = this._cacheMap.get(key);
36388
36398
  if (cached) {
@@ -36400,13 +36410,13 @@ class CacheInstance {
36400
36410
  return newCache;
36401
36411
  };
36402
36412
  /**
36403
- * Clear cached value for current execution context.
36413
+ * Clear cached values for current execution context.
36404
36414
  *
36405
- * Removes the cached entry for the current strategy/exchange/mode combination
36415
+ * Removes all cached entries for the current strategy/exchange/mode combination
36406
36416
  * from this instance's cache map. The next `run()` call will recompute the value.
36407
36417
  *
36408
36418
  * Requires active execution context (strategy, exchange, backtest mode) and method context
36409
- * to determine which cache entry to clear.
36419
+ * to determine which cache entries to clear.
36410
36420
  *
36411
36421
  * @example
36412
36422
  * ```typescript
@@ -36414,14 +36424,19 @@ class CacheInstance {
36414
36424
  * const result1 = instance.run("BTCUSDT", 14); // Computed
36415
36425
  * const result2 = instance.run("BTCUSDT", 14); // Cached
36416
36426
  *
36417
- * instance.clear(); // Clear cache for current context
36427
+ * instance.clear(); // Clear all cache entries for current context
36418
36428
  *
36419
36429
  * const result3 = instance.run("BTCUSDT", 14); // Recomputed
36420
36430
  * ```
36421
36431
  */
36422
36432
  this.clear = () => {
36423
- const key = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36424
- this._cacheMap.delete(key);
36433
+ const contextKey = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36434
+ const prefix = `${contextKey}:`;
36435
+ for (const key of this._cacheMap.keys()) {
36436
+ if (key.startsWith(prefix)) {
36437
+ this._cacheMap.delete(key);
36438
+ }
36439
+ }
36425
36440
  };
36426
36441
  }
36427
36442
  }
@@ -36446,7 +36461,7 @@ class CacheUtils {
36446
36461
  * Memoized function to get or create CacheInstance for a function.
36447
36462
  * Each function gets its own isolated cache instance.
36448
36463
  */
36449
- this._getInstance = functoolsKit.memoize(([run]) => run, (run, interval) => new CacheInstance(run, interval));
36464
+ this._getInstance = functoolsKit.memoize(([run]) => run, (run, interval, key) => new CacheInstance(run, interval, key));
36450
36465
  /**
36451
36466
  * Wrap a function with caching based on timeframe intervals.
36452
36467
  *
@@ -36454,8 +36469,10 @@ class CacheUtils {
36454
36469
  * and invalidates based on the specified candle interval.
36455
36470
  *
36456
36471
  * @template T - Function type to cache
36472
+ * @template K - Key type for argument-based caching
36457
36473
  * @param run - Function to wrap with caching
36458
- * @param interval - Candle interval for cache invalidation (e.g., "1m", "1h")
36474
+ * @param context.interval - Candle interval for cache invalidation (e.g., "1m", "1h")
36475
+ * @param context.key - Optional key generator function for argument-based caching
36459
36476
  * @returns Wrapped function with automatic caching
36460
36477
  *
36461
36478
  * @example
@@ -36465,9 +36482,17 @@ class CacheUtils {
36465
36482
  * return result;
36466
36483
  * };
36467
36484
  *
36468
- * const cachedCalculate = Cache.fn(calculateIndicator, "15m");
36469
- * const result = cachedCalculate("BTCUSDT", 14); // Computed
36470
- * const result2 = cachedCalculate("BTCUSDT", 14); // Cached (same 15m interval)
36485
+ * // Without key - single cache entry per context
36486
+ * const cachedCalculate = Cache.fn(calculateIndicator, { interval: "15m" });
36487
+ *
36488
+ * // With key - separate cache entries per symbol
36489
+ * const cachedCalculate = Cache.fn(calculateIndicator, {
36490
+ * interval: "15m",
36491
+ * key: ([symbol]) => symbol,
36492
+ * });
36493
+ * const result1 = cachedCalculate("BTCUSDT", 14); // Computed
36494
+ * const result2 = cachedCalculate("ETHUSDT", 14); // Computed (different key)
36495
+ * const result3 = cachedCalculate("BTCUSDT", 14); // Cached (same key, same interval)
36471
36496
  * ```
36472
36497
  */
36473
36498
  this.fn = (run, context) => {
@@ -36475,7 +36500,7 @@ class CacheUtils {
36475
36500
  context,
36476
36501
  });
36477
36502
  const wrappedFn = (...args) => {
36478
- const instance = this._getInstance(run, context.interval);
36503
+ const instance = this._getInstance(run, context.interval, context.key);
36479
36504
  return instance.run(...args).value;
36480
36505
  };
36481
36506
  return wrappedFn;
package/build/index.mjs CHANGED
@@ -36287,6 +36287,11 @@ const CREATE_KEY_FN = (strategyName, exchangeName, frameName, backtest) => {
36287
36287
  parts.push(backtest ? "backtest" : "live");
36288
36288
  return parts.join(":");
36289
36289
  };
36290
+ /**
36291
+ * A unique symbol representing a value that should never occur.
36292
+ * Used as default key when no key function is provided.
36293
+ */
36294
+ const NEVER_VALUE = Symbol("never");
36290
36295
  /**
36291
36296
  * Instance class for caching function results with timeframe-based invalidation.
36292
36297
  *
@@ -36295,6 +36300,7 @@ const CREATE_KEY_FN = (strategyName, exchangeName, frameName, backtest) => {
36295
36300
  * Cache is invalidated when the current time moves to a different interval.
36296
36301
  *
36297
36302
  * @template T - Function type to cache
36303
+ * @template K - Key type for argument-based caching
36298
36304
  *
36299
36305
  * @example
36300
36306
  * ```typescript
@@ -36311,11 +36317,13 @@ class CacheInstance {
36311
36317
  *
36312
36318
  * @param fn - Function to cache
36313
36319
  * @param interval - Candle interval for cache invalidation (e.g., "1m", "1h")
36320
+ * @param key - Optional key generator function for argument-based caching
36314
36321
  */
36315
- constructor(fn, interval) {
36322
+ constructor(fn, interval, key = () => NEVER_VALUE) {
36316
36323
  this.fn = fn;
36317
36324
  this.interval = interval;
36318
- /** Cache map storing results per strategy/exchange/mode combination */
36325
+ this.key = key;
36326
+ /** Cache map storing results per strategy/exchange/mode/argKey combination */
36319
36327
  this._cacheMap = new Map();
36320
36328
  /**
36321
36329
  * Execute function with caching based on timeframe intervals.
@@ -36362,7 +36370,9 @@ class CacheInstance {
36362
36370
  throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
36363
36371
  }
36364
36372
  }
36365
- const key = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36373
+ const contextKey = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36374
+ const argKey = String(this.key(args));
36375
+ const key = `${contextKey}:${argKey}`;
36366
36376
  const currentWhen = bt.executionContextService.context.when;
36367
36377
  const cached = this._cacheMap.get(key);
36368
36378
  if (cached) {
@@ -36380,13 +36390,13 @@ class CacheInstance {
36380
36390
  return newCache;
36381
36391
  };
36382
36392
  /**
36383
- * Clear cached value for current execution context.
36393
+ * Clear cached values for current execution context.
36384
36394
  *
36385
- * Removes the cached entry for the current strategy/exchange/mode combination
36395
+ * Removes all cached entries for the current strategy/exchange/mode combination
36386
36396
  * from this instance's cache map. The next `run()` call will recompute the value.
36387
36397
  *
36388
36398
  * Requires active execution context (strategy, exchange, backtest mode) and method context
36389
- * to determine which cache entry to clear.
36399
+ * to determine which cache entries to clear.
36390
36400
  *
36391
36401
  * @example
36392
36402
  * ```typescript
@@ -36394,14 +36404,19 @@ class CacheInstance {
36394
36404
  * const result1 = instance.run("BTCUSDT", 14); // Computed
36395
36405
  * const result2 = instance.run("BTCUSDT", 14); // Cached
36396
36406
  *
36397
- * instance.clear(); // Clear cache for current context
36407
+ * instance.clear(); // Clear all cache entries for current context
36398
36408
  *
36399
36409
  * const result3 = instance.run("BTCUSDT", 14); // Recomputed
36400
36410
  * ```
36401
36411
  */
36402
36412
  this.clear = () => {
36403
- const key = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36404
- this._cacheMap.delete(key);
36413
+ const contextKey = CREATE_KEY_FN(bt.methodContextService.context.strategyName, bt.methodContextService.context.exchangeName, bt.methodContextService.context.frameName, bt.executionContextService.context.backtest);
36414
+ const prefix = `${contextKey}:`;
36415
+ for (const key of this._cacheMap.keys()) {
36416
+ if (key.startsWith(prefix)) {
36417
+ this._cacheMap.delete(key);
36418
+ }
36419
+ }
36405
36420
  };
36406
36421
  }
36407
36422
  }
@@ -36426,7 +36441,7 @@ class CacheUtils {
36426
36441
  * Memoized function to get or create CacheInstance for a function.
36427
36442
  * Each function gets its own isolated cache instance.
36428
36443
  */
36429
- this._getInstance = memoize(([run]) => run, (run, interval) => new CacheInstance(run, interval));
36444
+ this._getInstance = memoize(([run]) => run, (run, interval, key) => new CacheInstance(run, interval, key));
36430
36445
  /**
36431
36446
  * Wrap a function with caching based on timeframe intervals.
36432
36447
  *
@@ -36434,8 +36449,10 @@ class CacheUtils {
36434
36449
  * and invalidates based on the specified candle interval.
36435
36450
  *
36436
36451
  * @template T - Function type to cache
36452
+ * @template K - Key type for argument-based caching
36437
36453
  * @param run - Function to wrap with caching
36438
- * @param interval - Candle interval for cache invalidation (e.g., "1m", "1h")
36454
+ * @param context.interval - Candle interval for cache invalidation (e.g., "1m", "1h")
36455
+ * @param context.key - Optional key generator function for argument-based caching
36439
36456
  * @returns Wrapped function with automatic caching
36440
36457
  *
36441
36458
  * @example
@@ -36445,9 +36462,17 @@ class CacheUtils {
36445
36462
  * return result;
36446
36463
  * };
36447
36464
  *
36448
- * const cachedCalculate = Cache.fn(calculateIndicator, "15m");
36449
- * const result = cachedCalculate("BTCUSDT", 14); // Computed
36450
- * const result2 = cachedCalculate("BTCUSDT", 14); // Cached (same 15m interval)
36465
+ * // Without key - single cache entry per context
36466
+ * const cachedCalculate = Cache.fn(calculateIndicator, { interval: "15m" });
36467
+ *
36468
+ * // With key - separate cache entries per symbol
36469
+ * const cachedCalculate = Cache.fn(calculateIndicator, {
36470
+ * interval: "15m",
36471
+ * key: ([symbol]) => symbol,
36472
+ * });
36473
+ * const result1 = cachedCalculate("BTCUSDT", 14); // Computed
36474
+ * const result2 = cachedCalculate("ETHUSDT", 14); // Computed (different key)
36475
+ * const result3 = cachedCalculate("BTCUSDT", 14); // Cached (same key, same interval)
36451
36476
  * ```
36452
36477
  */
36453
36478
  this.fn = (run, context) => {
@@ -36455,7 +36480,7 @@ class CacheUtils {
36455
36480
  context,
36456
36481
  });
36457
36482
  const wrappedFn = (...args) => {
36458
- const instance = this._getInstance(run, context.interval);
36483
+ const instance = this._getInstance(run, context.interval, context.key);
36459
36484
  return instance.run(...args).value;
36460
36485
  };
36461
36486
  return wrappedFn;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "3.0.6",
3
+ "version": "3.0.7",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -13901,8 +13901,10 @@ declare class CacheUtils {
13901
13901
  * and invalidates based on the specified candle interval.
13902
13902
  *
13903
13903
  * @template T - Function type to cache
13904
+ * @template K - Key type for argument-based caching
13904
13905
  * @param run - Function to wrap with caching
13905
- * @param interval - Candle interval for cache invalidation (e.g., "1m", "1h")
13906
+ * @param context.interval - Candle interval for cache invalidation (e.g., "1m", "1h")
13907
+ * @param context.key - Optional key generator function for argument-based caching
13906
13908
  * @returns Wrapped function with automatic caching
13907
13909
  *
13908
13910
  * @example
@@ -13912,13 +13914,22 @@ declare class CacheUtils {
13912
13914
  * return result;
13913
13915
  * };
13914
13916
  *
13915
- * const cachedCalculate = Cache.fn(calculateIndicator, "15m");
13916
- * const result = cachedCalculate("BTCUSDT", 14); // Computed
13917
- * const result2 = cachedCalculate("BTCUSDT", 14); // Cached (same 15m interval)
13917
+ * // Without key - single cache entry per context
13918
+ * const cachedCalculate = Cache.fn(calculateIndicator, { interval: "15m" });
13919
+ *
13920
+ * // With key - separate cache entries per symbol
13921
+ * const cachedCalculate = Cache.fn(calculateIndicator, {
13922
+ * interval: "15m",
13923
+ * key: ([symbol]) => symbol,
13924
+ * });
13925
+ * const result1 = cachedCalculate("BTCUSDT", 14); // Computed
13926
+ * const result2 = cachedCalculate("ETHUSDT", 14); // Computed (different key)
13927
+ * const result3 = cachedCalculate("BTCUSDT", 14); // Cached (same key, same interval)
13918
13928
  * ```
13919
13929
  */
13920
- fn: <T extends Function>(run: T, context: {
13930
+ fn: <T extends Function, K = symbol>(run: T, context: {
13921
13931
  interval: CandleInterval;
13932
+ key?: (args: Parameters<T>) => K;
13922
13933
  }) => T;
13923
13934
  /**
13924
13935
  * Flush (remove) cached CacheInstance for a specific function or all functions.