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 +117 -26
- package/build/index.mjs +117 -26
- package/package.json +1 -1
- package/types.d.ts +49 -15
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
|
|
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
|
-
|
|
18510
|
-
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
|
|
18514
|
-
|
|
18515
|
-
|
|
18516
|
-
|
|
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.
|
|
18634
|
+
backtest$1.loggerService.info(CACHE_METHOD_NAME_FN, {
|
|
18584
18635
|
context,
|
|
18585
18636
|
});
|
|
18586
|
-
|
|
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
|
-
*
|
|
18644
|
+
* Flush (remove) cached CacheInstance for a specific function or all functions.
|
|
18593
18645
|
*
|
|
18594
|
-
* This method
|
|
18595
|
-
*
|
|
18596
|
-
* all
|
|
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
|
-
* -
|
|
18600
|
-
* - Free memory by removing unused
|
|
18601
|
-
* - Reset all
|
|
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
|
-
*
|
|
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
|
|
18663
|
+
* const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
|
|
18608
18664
|
*
|
|
18609
|
-
* //
|
|
18610
|
-
* Cache.
|
|
18665
|
+
* // Flush CacheInstance for specific function
|
|
18666
|
+
* Cache.flush(calculateIndicator);
|
|
18611
18667
|
*
|
|
18612
|
-
* //
|
|
18613
|
-
* Cache.
|
|
18668
|
+
* // Flush all CacheInstances
|
|
18669
|
+
* Cache.flush();
|
|
18614
18670
|
* ```
|
|
18615
18671
|
*/
|
|
18616
|
-
this.
|
|
18617
|
-
backtest$1.loggerService.
|
|
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
|
|
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
|
-
|
|
18508
|
-
|
|
18509
|
-
|
|
18510
|
-
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
|
|
18514
|
-
|
|
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.
|
|
18632
|
+
backtest$1.loggerService.info(CACHE_METHOD_NAME_FN, {
|
|
18582
18633
|
context,
|
|
18583
18634
|
});
|
|
18584
|
-
|
|
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
|
-
*
|
|
18642
|
+
* Flush (remove) cached CacheInstance for a specific function or all functions.
|
|
18591
18643
|
*
|
|
18592
|
-
* This method
|
|
18593
|
-
*
|
|
18594
|
-
* all
|
|
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
|
-
* -
|
|
18598
|
-
* - Free memory by removing unused
|
|
18599
|
-
* - Reset all
|
|
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
|
-
*
|
|
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
|
|
18661
|
+
* const cachedFn = Cache.fn(calculateIndicator, { interval: "1h" });
|
|
18606
18662
|
*
|
|
18607
|
-
* //
|
|
18608
|
-
* Cache.
|
|
18663
|
+
* // Flush CacheInstance for specific function
|
|
18664
|
+
* Cache.flush(calculateIndicator);
|
|
18609
18665
|
*
|
|
18610
|
-
* //
|
|
18611
|
-
* Cache.
|
|
18666
|
+
* // Flush all CacheInstances
|
|
18667
|
+
* Cache.flush();
|
|
18612
18668
|
* ```
|
|
18613
18669
|
*/
|
|
18614
|
-
this.
|
|
18615
|
-
backtest$1.loggerService.
|
|
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
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
|
-
}) =>
|
|
7868
|
+
}) => T;
|
|
7869
7869
|
/**
|
|
7870
|
-
*
|
|
7870
|
+
* Flush (remove) cached CacheInstance for a specific function or all functions.
|
|
7871
7871
|
*
|
|
7872
|
-
* This method
|
|
7873
|
-
*
|
|
7874
|
-
* all
|
|
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
|
-
* -
|
|
7878
|
-
* - Free memory by removing unused
|
|
7879
|
-
* - Reset all
|
|
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
|
-
*
|
|
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
|
|
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
|
|
7888
|
-
* Cache.clear(calculateIndicator);
|
|
7922
|
+
* Cache.clear(calculateIndicator); // Clear cache for current context only
|
|
7889
7923
|
*
|
|
7890
|
-
* //
|
|
7891
|
-
*
|
|
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
|
|
7928
|
+
clear: <T extends Function>(run: T) => void;
|
|
7895
7929
|
}
|
|
7896
7930
|
/**
|
|
7897
7931
|
* Singleton instance of CacheUtils for convenient function caching.
|