backtest-kit 9.7.0 → 9.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1871 -1871
  3. package/build/index.cjs +283 -180
  4. package/build/index.mjs +284 -181
  5. package/package.json +86 -86
  6. package/types.d.ts +100 -28
package/build/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { scoped } from 'di-scoped';
3
3
  import { singleton } from 'di-singleton';
4
4
  import { Subject, makeExtendable, singleshot, getErrorMessage, memoize, not, errorData, trycatch, retry, queued, sleep, randomString, str, isObject, ToolRegistry, typo, and, Source, resolveDocuments, timeout, TIMEOUT_SYMBOL as TIMEOUT_SYMBOL$1, compose, BehaviorSubject, waitForNext, singlerun } from 'functools-kit';
5
5
  import * as fs from 'fs/promises';
6
- import fs__default, { stat, opendir, readFile } from 'fs/promises';
6
+ import fs__default from 'fs/promises';
7
7
  import path, { join, dirname } from 'path';
8
8
  import crypto from 'crypto';
9
9
  import os from 'os';
@@ -36107,72 +36107,41 @@ const PRINT_PROGRESS_FN = (fetched, total, symbol, interval) => {
36107
36107
  }
36108
36108
  };
36109
36109
  /**
36110
- * Checks cached candle timestamps for correct interval alignment.
36111
- * Reads JSON files directly from persist storage without using abstractions.
36110
+ * Checks cached candle presence via the persist adapter.
36111
+ * Issues one ranged read; adapter-side `hasValue` covers each expected timestamp,
36112
+ * so a single missing or unaligned candle yields a miss without loading the whole dataset.
36112
36113
  *
36113
36114
  * @param params - Validation parameters
36114
36115
  */
36115
36116
  async function checkCandles(params) {
36116
- const { symbol, exchangeName, interval, from, to, baseDir = "./dump/data/candle" } = params;
36117
+ const { symbol, exchangeName, interval, from, to } = params;
36117
36118
  backtest.loggerService.info(CHECK_CANDLES_METHOD_NAME, params);
36118
36119
  const step = INTERVAL_MINUTES$3[interval];
36119
36120
  if (!step) {
36120
36121
  throw new Error(`checkCandles: unsupported interval=${interval}`);
36121
36122
  }
36122
36123
  const stepMs = step * MS_PER_MINUTE$3;
36123
- const dir = join(baseDir, exchangeName, symbol, interval);
36124
36124
  const fromTs = ALIGN_TO_INTERVAL_FN(from.getTime(), step);
36125
36125
  const toTs = ALIGN_TO_INTERVAL_FN(to.getTime(), step);
36126
- try {
36127
- await stat(dir);
36128
- }
36129
- catch {
36130
- throw new Error(`checkCandles: cache directory not found: ${dir}`);
36131
- }
36132
- // Collect only filenames (strings) in range via async iterator — no full readdir in memory
36133
- const files = [];
36134
- for await (const entry of await opendir(dir)) {
36135
- if (!entry.isFile() || !entry.name.endsWith(".json")) {
36136
- continue;
36137
- }
36138
- const ts = Number(entry.name.replace(".json", ""));
36139
- if (ts >= fromTs && ts < toTs) {
36140
- files.push(entry.name);
36141
- }
36142
- }
36143
- if (files.length === 0) {
36144
- throw new Error(`checkCandles: no cached candles in range [${fromTs}, ${toTs}) in ${dir}`);
36126
+ const totalCandles = Math.floor((toTs - fromTs) / stepMs);
36127
+ if (totalCandles <= 0) {
36128
+ throw new Error(`checkCandles: empty range [${fromTs}, ${toTs}) for ${symbol} ${interval}`);
36145
36129
  }
36146
- files.sort();
36147
- let prevTimestamp = null;
36148
- let prevName = null;
36149
- PRINT_PROGRESS_FN(0, files.length, symbol, interval);
36150
- for (let i = 0; i < files.length; i++) {
36151
- const filePath = join(dir, files[i]);
36152
- const raw = await readFile(filePath, "utf-8");
36153
- let candle;
36154
- try {
36155
- candle = JSON.parse(raw);
36156
- }
36157
- catch {
36158
- throw new Error(`checkCandles: ${files[i]} contains invalid JSON`);
36159
- }
36160
- const { timestamp } = candle;
36161
- const aligned = ALIGN_TO_INTERVAL_FN(timestamp, step);
36162
- if (timestamp !== aligned) {
36163
- throw new Error(`checkCandles: ${files[i]} timestamp not aligned to ${interval} boundary (actual=${timestamp}, expected=${aligned})`);
36164
- }
36165
- if (prevTimestamp !== null) {
36166
- const gap = timestamp - prevTimestamp;
36167
- if (gap !== stepMs) {
36168
- throw new Error(`checkCandles: gap between ${prevName} and ${files[i]} (actual=${gap}ms, expected=${stepMs}ms)`);
36169
- }
36130
+ let checked = 0;
36131
+ let currentSince = fromTs;
36132
+ PRINT_PROGRESS_FN(checked, totalCandles, symbol, interval);
36133
+ while (checked < totalCandles) {
36134
+ const chunkLimit = Math.min(totalCandles - checked, GLOBAL_CONFIG.CC_MAX_CANDLES_PER_REQUEST);
36135
+ const chunkUntil = currentSince + chunkLimit * stepMs;
36136
+ const candles = await PersistCandleAdapter.readCandlesData(symbol, interval, exchangeName, chunkLimit, currentSince, chunkUntil);
36137
+ if (!candles) {
36138
+ throw new Error(`checkCandles: cache miss for ${symbol} ${interval} [${currentSince}, ${chunkUntil})`);
36170
36139
  }
36171
- prevTimestamp = timestamp;
36172
- prevName = files[i];
36173
- PRINT_PROGRESS_FN(i + 1, files.length, symbol, interval);
36140
+ checked += chunkLimit;
36141
+ currentSince = chunkUntil;
36142
+ PRINT_PROGRESS_FN(checked, totalCandles, symbol, interval);
36174
36143
  }
36175
- console.log(`checkCandles: OK ${files.length} candles ${symbol} ${interval}`);
36144
+ console.log(`checkCandles: OK ${totalCandles} candles ${symbol} ${interval}`);
36176
36145
  }
36177
36146
  /**
36178
36147
  * Pre-caches candles for a date range into persist storage.
@@ -37423,7 +37392,19 @@ class BrokerProxy {
37423
37392
  */
37424
37393
  class BrokerAdapter {
37425
37394
  constructor() {
37426
- this._brokerInstance = null;
37395
+ /** Factory producing the active `BrokerProxy` instance */
37396
+ this._brokerFactory = () => null;
37397
+ /**
37398
+ * Lazily constructs the `BrokerProxy` from the registered factory and
37399
+ * memoizes the result via `singleshot`.
37400
+ *
37401
+ * The proxy is built on the first call and cached for all subsequent calls.
37402
+ * Returns `null` when no adapter has been registered via `useBrokerAdapter()`.
37403
+ *
37404
+ * Reset via `clear()` so the next call rebuilds from the current factory
37405
+ * (e.g. when `process.cwd()` changes between strategy iterations).
37406
+ */
37407
+ this.getInstance = singleshot(() => this._brokerFactory());
37427
37408
  /**
37428
37409
  * Forwards a signal-open event to the registered broker adapter.
37429
37410
  *
@@ -37457,7 +37438,10 @@ class BrokerAdapter {
37457
37438
  if (payload.backtest) {
37458
37439
  return;
37459
37440
  }
37460
- await this._brokerInstance?.onSignalOpenCommit(payload);
37441
+ const instance = this.getInstance();
37442
+ if (instance) {
37443
+ await instance.onSignalOpenCommit(payload);
37444
+ }
37461
37445
  };
37462
37446
  /**
37463
37447
  * Forwards a signal-close event to the registered broker adapter.
@@ -37495,7 +37479,10 @@ class BrokerAdapter {
37495
37479
  if (payload.backtest) {
37496
37480
  return;
37497
37481
  }
37498
- await this._brokerInstance?.onSignalCloseCommit(payload);
37482
+ const instance = this.getInstance();
37483
+ if (instance) {
37484
+ await instance.onSignalCloseCommit(payload);
37485
+ }
37499
37486
  };
37500
37487
  /**
37501
37488
  * Intercepts a partial-profit close before DI-core mutation.
@@ -37531,7 +37518,10 @@ class BrokerAdapter {
37531
37518
  if (payload.backtest) {
37532
37519
  return;
37533
37520
  }
37534
- await this._brokerInstance?.onPartialProfitCommit(payload);
37521
+ const instance = this.getInstance();
37522
+ if (instance) {
37523
+ await instance.onPartialProfitCommit(payload);
37524
+ }
37535
37525
  };
37536
37526
  /**
37537
37527
  * Intercepts a partial-loss close before DI-core mutation.
@@ -37567,7 +37557,10 @@ class BrokerAdapter {
37567
37557
  if (payload.backtest) {
37568
37558
  return;
37569
37559
  }
37570
- await this._brokerInstance?.onPartialLossCommit(payload);
37560
+ const instance = this.getInstance();
37561
+ if (instance) {
37562
+ await instance.onPartialLossCommit(payload);
37563
+ }
37571
37564
  };
37572
37565
  /**
37573
37566
  * Intercepts a trailing stop-loss update before DI-core mutation.
@@ -37603,7 +37596,10 @@ class BrokerAdapter {
37603
37596
  if (payload.backtest) {
37604
37597
  return;
37605
37598
  }
37606
- await this._brokerInstance?.onTrailingStopCommit(payload);
37599
+ const instance = this.getInstance();
37600
+ if (instance) {
37601
+ await instance.onTrailingStopCommit(payload);
37602
+ }
37607
37603
  };
37608
37604
  /**
37609
37605
  * Intercepts a trailing take-profit update before DI-core mutation.
@@ -37639,7 +37635,10 @@ class BrokerAdapter {
37639
37635
  if (payload.backtest) {
37640
37636
  return;
37641
37637
  }
37642
- await this._brokerInstance?.onTrailingTakeCommit(payload);
37638
+ const instance = this.getInstance();
37639
+ if (instance) {
37640
+ await instance.onTrailingTakeCommit(payload);
37641
+ }
37643
37642
  };
37644
37643
  /**
37645
37644
  * Intercepts a breakeven operation before DI-core mutation.
@@ -37676,7 +37675,10 @@ class BrokerAdapter {
37676
37675
  if (payload.backtest) {
37677
37676
  return;
37678
37677
  }
37679
- await this._brokerInstance?.onBreakevenCommit(payload);
37678
+ const instance = this.getInstance();
37679
+ if (instance) {
37680
+ await instance.onBreakevenCommit(payload);
37681
+ }
37680
37682
  };
37681
37683
  /**
37682
37684
  * Intercepts a DCA average-buy entry before DI-core mutation.
@@ -37712,7 +37714,10 @@ class BrokerAdapter {
37712
37714
  if (payload.backtest) {
37713
37715
  return;
37714
37716
  }
37715
- await this._brokerInstance?.onAverageBuyCommit(payload);
37717
+ const instance = this.getInstance();
37718
+ if (instance) {
37719
+ await instance.onAverageBuyCommit(payload);
37720
+ }
37716
37721
  };
37717
37722
  /**
37718
37723
  * Registers a broker adapter instance or constructor to receive commit* callbacks.
@@ -37736,11 +37741,12 @@ class BrokerAdapter {
37736
37741
  this.useBrokerAdapter = (broker) => {
37737
37742
  backtest.loggerService.info(BROKER_METHOD_NAME_USE_BROKER_ADAPTER, {});
37738
37743
  if (typeof broker === "function") {
37739
- const instance = Reflect.construct(broker, []);
37740
- this._brokerInstance = new BrokerProxy(instance);
37741
- return;
37744
+ this._brokerFactory = () => new BrokerProxy(Reflect.construct(broker, []));
37745
+ }
37746
+ else {
37747
+ this._brokerFactory = () => new BrokerProxy(broker);
37742
37748
  }
37743
- this._brokerInstance = new BrokerProxy(broker);
37749
+ this.getInstance.clear();
37744
37750
  };
37745
37751
  /**
37746
37752
  * Activates the broker: subscribes to syncSubject for signal-open / signal-close routing.
@@ -37767,7 +37773,8 @@ class BrokerAdapter {
37767
37773
  */
37768
37774
  this.enable = singleshot(() => {
37769
37775
  backtest.loggerService.info(BROKER_METHOD_NAME_ENABLE, {});
37770
- if (!this._brokerInstance) {
37776
+ const instance = this.getInstance();
37777
+ if (!instance) {
37771
37778
  this.enable.clear();
37772
37779
  throw new Error("No broker instance provided. Call Broker.useBrokerAdapter first.");
37773
37780
  }
@@ -37855,7 +37862,7 @@ class BrokerAdapter {
37855
37862
  */
37856
37863
  this.clear = () => {
37857
37864
  backtest.loggerService.info(BROKER_METHOD_NAME_CLEAR, {});
37858
- this._brokerInstance = null;
37865
+ this.getInstance.clear();
37859
37866
  this.enable.clear();
37860
37867
  };
37861
37868
  }
@@ -48875,8 +48882,16 @@ class RecentMemoryLiveUtils {
48875
48882
  */
48876
48883
  class RecentBacktestAdapter {
48877
48884
  constructor() {
48878
- /** Internal storage utils instance */
48879
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
48885
+ /** Factory producing the active storage utils instance */
48886
+ this._recentBacktestFactory = () => new RecentMemoryBacktestUtils();
48887
+ /**
48888
+ * Lazily constructs the storage utils from the registered factory and memoizes
48889
+ * the result via `singleshot`.
48890
+ *
48891
+ * The instance is built on the first call and cached for all subsequent calls.
48892
+ * Reset via `clear()` so the next call rebuilds from the current factory.
48893
+ */
48894
+ this.getInstance = singleshot(() => this._recentBacktestFactory());
48880
48895
  /**
48881
48896
  * Handles active ping event.
48882
48897
  * Proxies call to the underlying storage adapter.
@@ -48886,7 +48901,7 @@ class RecentBacktestAdapter {
48886
48901
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
48887
48902
  signalId: event.data.id,
48888
48903
  });
48889
- return await this._recentBacktestUtils.handleActivePing(event);
48904
+ return await this.getInstance().handleActivePing(event);
48890
48905
  };
48891
48906
  /**
48892
48907
  * Retrieves the latest signal for the given context.
@@ -48907,7 +48922,7 @@ class RecentBacktestAdapter {
48907
48922
  frameName,
48908
48923
  backtest: backtest$1,
48909
48924
  });
48910
- return await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
48925
+ return await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
48911
48926
  };
48912
48927
  /**
48913
48928
  * Returns the number of whole minutes elapsed since the latest signal's creation timestamp.
@@ -48931,7 +48946,7 @@ class RecentBacktestAdapter {
48931
48946
  backtest: backtest$1,
48932
48947
  timestamp,
48933
48948
  });
48934
- const signal = await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
48949
+ const signal = await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
48935
48950
  if (!signal) {
48936
48951
  return null;
48937
48952
  }
@@ -48944,7 +48959,8 @@ class RecentBacktestAdapter {
48944
48959
  */
48945
48960
  this.useRecentAdapter = (Ctor) => {
48946
48961
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
48947
- this._recentBacktestUtils = Reflect.construct(Ctor, []);
48962
+ this._recentBacktestFactory = () => Reflect.construct(Ctor, []);
48963
+ this.getInstance.clear();
48948
48964
  };
48949
48965
  /**
48950
48966
  * Switches to persistent storage adapter.
@@ -48952,7 +48968,8 @@ class RecentBacktestAdapter {
48952
48968
  */
48953
48969
  this.usePersist = () => {
48954
48970
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
48955
- this._recentBacktestUtils = new RecentPersistBacktestUtils();
48971
+ this._recentBacktestFactory = () => new RecentPersistBacktestUtils();
48972
+ this.getInstance.clear();
48956
48973
  };
48957
48974
  /**
48958
48975
  * Switches to in-memory storage adapter (default).
@@ -48960,14 +48977,17 @@ class RecentBacktestAdapter {
48960
48977
  */
48961
48978
  this.useMemory = () => {
48962
48979
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
48963
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
48980
+ this._recentBacktestFactory = () => new RecentMemoryBacktestUtils();
48981
+ this.getInstance.clear();
48964
48982
  };
48965
48983
  /**
48966
- * Clears the cached utils instance by resetting to the default in-memory adapter.
48984
+ * Clears the memoized utils instance.
48985
+ * Call this when process.cwd() changes between strategy iterations
48986
+ * so a new instance is created with the updated base path.
48967
48987
  */
48968
48988
  this.clear = () => {
48969
48989
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
48970
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
48990
+ this.getInstance.clear();
48971
48991
  };
48972
48992
  }
48973
48993
  }
@@ -48982,8 +49002,16 @@ class RecentBacktestAdapter {
48982
49002
  */
48983
49003
  class RecentLiveAdapter {
48984
49004
  constructor() {
48985
- /** Internal storage utils instance */
48986
- this._recentLiveUtils = new RecentPersistLiveUtils();
49005
+ /** Factory producing the active storage utils instance */
49006
+ this._recentLiveFactory = () => new RecentPersistLiveUtils();
49007
+ /**
49008
+ * Lazily constructs the storage utils from the registered factory and memoizes
49009
+ * the result via `singleshot`.
49010
+ *
49011
+ * The instance is built on the first call and cached for all subsequent calls.
49012
+ * Reset via `clear()` so the next call rebuilds from the current factory.
49013
+ */
49014
+ this.getInstance = singleshot(() => this._recentLiveFactory());
48987
49015
  /**
48988
49016
  * Handles active ping event.
48989
49017
  * Proxies call to the underlying storage adapter.
@@ -48993,7 +49021,7 @@ class RecentLiveAdapter {
48993
49021
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
48994
49022
  signalId: event.data.id,
48995
49023
  });
48996
- return await this._recentLiveUtils.handleActivePing(event);
49024
+ return await this.getInstance().handleActivePing(event);
48997
49025
  };
48998
49026
  /**
48999
49027
  * Retrieves the latest signal for the given context.
@@ -49014,7 +49042,7 @@ class RecentLiveAdapter {
49014
49042
  frameName,
49015
49043
  backtest: backtest$1,
49016
49044
  });
49017
- return await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
49045
+ return await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
49018
49046
  };
49019
49047
  /**
49020
49048
  * Returns the number of whole minutes elapsed since the latest signal's creation timestamp.
@@ -49038,7 +49066,7 @@ class RecentLiveAdapter {
49038
49066
  backtest: backtest$1,
49039
49067
  timestamp,
49040
49068
  });
49041
- const signal = await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49069
+ const signal = await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49042
49070
  if (!signal) {
49043
49071
  return null;
49044
49072
  }
@@ -49051,7 +49079,8 @@ class RecentLiveAdapter {
49051
49079
  */
49052
49080
  this.useRecentAdapter = (Ctor) => {
49053
49081
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
49054
- this._recentLiveUtils = Reflect.construct(Ctor, []);
49082
+ this._recentLiveFactory = () => Reflect.construct(Ctor, []);
49083
+ this.getInstance.clear();
49055
49084
  };
49056
49085
  /**
49057
49086
  * Switches to persistent storage adapter (default).
@@ -49059,7 +49088,8 @@ class RecentLiveAdapter {
49059
49088
  */
49060
49089
  this.usePersist = () => {
49061
49090
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
49062
- this._recentLiveUtils = new RecentPersistLiveUtils();
49091
+ this._recentLiveFactory = () => new RecentPersistLiveUtils();
49092
+ this.getInstance.clear();
49063
49093
  };
49064
49094
  /**
49065
49095
  * Switches to in-memory storage adapter.
@@ -49067,14 +49097,17 @@ class RecentLiveAdapter {
49067
49097
  */
49068
49098
  this.useMemory = () => {
49069
49099
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
49070
- this._recentLiveUtils = new RecentMemoryLiveUtils();
49100
+ this._recentLiveFactory = () => new RecentMemoryLiveUtils();
49101
+ this.getInstance.clear();
49071
49102
  };
49072
49103
  /**
49073
- * Clears the cached utils instance by resetting to the default persistent adapter.
49104
+ * Clears the memoized utils instance.
49105
+ * Call this when process.cwd() changes between strategy iterations
49106
+ * so a new instance is created with the updated base path.
49074
49107
  */
49075
49108
  this.clear = () => {
49076
49109
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_CLEAR);
49077
- this._recentLiveUtils = new RecentPersistLiveUtils();
49110
+ this.getInstance.clear();
49078
49111
  };
49079
49112
  }
49080
49113
  }
@@ -54399,16 +54432,26 @@ class LogDummyUtils {
54399
54432
  */
54400
54433
  class LogAdapter {
54401
54434
  constructor() {
54402
- /** Internal log utils instance */
54403
- this._log = new LogMemoryUtils();
54435
+ /** Factory producing the active log utils instance */
54436
+ this._logFactory = () => new LogMemoryUtils();
54437
+ /**
54438
+ * Lazily constructs the log utils from the registered factory and memoizes
54439
+ * the result via `singleshot`.
54440
+ *
54441
+ * The instance is built on the first call and cached for all subsequent calls.
54442
+ * Reset via `clear()` so the next call rebuilds from the current factory
54443
+ * (e.g. when `process.cwd()` changes between strategy iterations).
54444
+ */
54445
+ this.getInstance = singleshot(() => this._logFactory());
54404
54446
  /**
54405
54447
  * Lists all stored log entries.
54406
54448
  * Proxies call to the underlying log adapter.
54407
54449
  * @returns Array of all log entries
54408
54450
  */
54409
54451
  this.getList = async () => {
54410
- if (this._log.getList) {
54411
- return await this._log.getList();
54452
+ const log = this.getInstance();
54453
+ if (log.getList) {
54454
+ return await log.getList();
54412
54455
  }
54413
54456
  return [];
54414
54457
  };
@@ -54419,8 +54462,9 @@ class LogAdapter {
54419
54462
  * @param args - Additional arguments
54420
54463
  */
54421
54464
  this.log = (topic, ...args) => {
54422
- if (this._log.log) {
54423
- this._log.log(topic, ...args);
54465
+ const log = this.getInstance();
54466
+ if (log.log) {
54467
+ log.log(topic, ...args);
54424
54468
  }
54425
54469
  };
54426
54470
  /**
@@ -54430,8 +54474,9 @@ class LogAdapter {
54430
54474
  * @param args - Additional arguments
54431
54475
  */
54432
54476
  this.debug = (topic, ...args) => {
54433
- if (this._log.debug) {
54434
- this._log.debug(topic, ...args);
54477
+ const log = this.getInstance();
54478
+ if (log.debug) {
54479
+ log.debug(topic, ...args);
54435
54480
  }
54436
54481
  };
54437
54482
  /**
@@ -54441,8 +54486,9 @@ class LogAdapter {
54441
54486
  * @param args - Additional arguments
54442
54487
  */
54443
54488
  this.info = (topic, ...args) => {
54444
- if (this._log.info) {
54445
- this._log.info(topic, ...args);
54489
+ const log = this.getInstance();
54490
+ if (log.info) {
54491
+ log.info(topic, ...args);
54446
54492
  }
54447
54493
  };
54448
54494
  /**
@@ -54452,8 +54498,9 @@ class LogAdapter {
54452
54498
  * @param args - Additional arguments
54453
54499
  */
54454
54500
  this.warn = (topic, ...args) => {
54455
- if (this._log.warn) {
54456
- this._log.warn(topic, ...args);
54501
+ const log = this.getInstance();
54502
+ if (log.warn) {
54503
+ log.warn(topic, ...args);
54457
54504
  }
54458
54505
  };
54459
54506
  /**
@@ -54463,7 +54510,8 @@ class LogAdapter {
54463
54510
  */
54464
54511
  this.useLogger = (Ctor) => {
54465
54512
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_LOGGER);
54466
- this._log = Reflect.construct(Ctor, []);
54513
+ this._logFactory = () => Reflect.construct(Ctor, []);
54514
+ this.getInstance.clear();
54467
54515
  };
54468
54516
  /**
54469
54517
  * Switches to persistent log adapter.
@@ -54471,7 +54519,8 @@ class LogAdapter {
54471
54519
  */
54472
54520
  this.usePersist = () => {
54473
54521
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_PERSIST);
54474
- this._log = new LogPersistUtils();
54522
+ this._logFactory = () => new LogPersistUtils();
54523
+ this.getInstance.clear();
54475
54524
  };
54476
54525
  /**
54477
54526
  * Switches to in-memory log adapter (default).
@@ -54479,7 +54528,8 @@ class LogAdapter {
54479
54528
  */
54480
54529
  this.useMemory = () => {
54481
54530
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_MEMORY);
54482
- this._log = new LogMemoryUtils();
54531
+ this._logFactory = () => new LogMemoryUtils();
54532
+ this.getInstance.clear();
54483
54533
  };
54484
54534
  /**
54485
54535
  * Switches to dummy log adapter.
@@ -54487,7 +54537,8 @@ class LogAdapter {
54487
54537
  */
54488
54538
  this.useDummy = () => {
54489
54539
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_DUMMY);
54490
- this._log = new LogDummyUtils();
54540
+ this._logFactory = () => new LogDummyUtils();
54541
+ this.getInstance.clear();
54491
54542
  };
54492
54543
  /**
54493
54544
  * Switches to JSONL file log adapter.
@@ -54497,18 +54548,22 @@ class LogAdapter {
54497
54548
  * @param fileName - Base file name without extension (default: "log")
54498
54549
  * @param dirName - Directory for the JSONL file (default: ./dump/log)
54499
54550
  */
54500
- this.useJsonl = (fileName = "log.jsonl", dirName = join(process.cwd(), "./dump/log")) => {
54551
+ this.useJsonl = (fileName = "log.jsonl", dirName) => {
54501
54552
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_JSONL);
54502
- this._log = new LogJsonlUtils(fileName, dirName);
54553
+ this._logFactory = () => {
54554
+ const dir = dirName || join(process.cwd(), "./dump/log");
54555
+ return new LogJsonlUtils(fileName, dir);
54556
+ };
54557
+ this.getInstance.clear();
54503
54558
  };
54504
54559
  /**
54505
- * Clears the cached log instance by resetting to the default in-memory adapter.
54560
+ * Clears the memoized log instance.
54506
54561
  * Call this when process.cwd() changes between strategy iterations
54507
54562
  * so a new adapter instance is created with the updated base path.
54508
54563
  */
54509
54564
  this.clear = () => {
54510
54565
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_CLEAR);
54511
- this._log = new LogMemoryUtils();
54566
+ this.getInstance.clear();
54512
54567
  };
54513
54568
  }
54514
54569
  }
@@ -58400,15 +58455,23 @@ class StorageDummyLiveUtils {
58400
58455
  */
58401
58456
  class StorageBacktestAdapter {
58402
58457
  constructor() {
58403
- /** Internal storage utils instance */
58404
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58458
+ /** Factory producing the active storage utils instance */
58459
+ this._signalBacktestFactory = () => new StorageMemoryBacktestUtils();
58460
+ /**
58461
+ * Lazily constructs the storage utils from the registered factory and memoizes
58462
+ * the result via `singleshot`.
58463
+ *
58464
+ * The instance is built on the first call and cached for all subsequent calls.
58465
+ * Reset via `clear()` so the next call rebuilds from the current factory.
58466
+ */
58467
+ this.getInstance = singleshot(() => this._signalBacktestFactory());
58405
58468
  /**
58406
58469
  * Handles signal opened event.
58407
58470
  * Proxies call to the underlying storage adapter.
58408
58471
  * @param tick - The opened signal tick data
58409
58472
  */
58410
58473
  this.handleOpened = async (tick) => {
58411
- return await this._signalBacktestUtils.handleOpened(tick);
58474
+ return await this.getInstance().handleOpened(tick);
58412
58475
  };
58413
58476
  /**
58414
58477
  * Handles signal closed event.
@@ -58416,7 +58479,7 @@ class StorageBacktestAdapter {
58416
58479
  * @param tick - The closed signal tick data
58417
58480
  */
58418
58481
  this.handleClosed = async (tick) => {
58419
- return await this._signalBacktestUtils.handleClosed(tick);
58482
+ return await this.getInstance().handleClosed(tick);
58420
58483
  };
58421
58484
  /**
58422
58485
  * Handles signal scheduled event.
@@ -58424,7 +58487,7 @@ class StorageBacktestAdapter {
58424
58487
  * @param tick - The scheduled signal tick data
58425
58488
  */
58426
58489
  this.handleScheduled = async (tick) => {
58427
- return await this._signalBacktestUtils.handleScheduled(tick);
58490
+ return await this.getInstance().handleScheduled(tick);
58428
58491
  };
58429
58492
  /**
58430
58493
  * Handles signal cancelled event.
@@ -58432,7 +58495,7 @@ class StorageBacktestAdapter {
58432
58495
  * @param tick - The cancelled signal tick data
58433
58496
  */
58434
58497
  this.handleCancelled = async (tick) => {
58435
- return await this._signalBacktestUtils.handleCancelled(tick);
58498
+ return await this.getInstance().handleCancelled(tick);
58436
58499
  };
58437
58500
  /**
58438
58501
  * Finds a signal by its ID.
@@ -58441,7 +58504,7 @@ class StorageBacktestAdapter {
58441
58504
  * @returns The signal row or null if not found
58442
58505
  */
58443
58506
  this.findById = async (id) => {
58444
- return await this._signalBacktestUtils.findById(id);
58507
+ return await this.getInstance().findById(id);
58445
58508
  };
58446
58509
  /**
58447
58510
  * Lists all stored signals.
@@ -58449,13 +58512,13 @@ class StorageBacktestAdapter {
58449
58512
  * @returns Array of all signal rows
58450
58513
  */
58451
58514
  this.list = async () => {
58452
- return await this._signalBacktestUtils.list();
58515
+ return await this.getInstance().list();
58453
58516
  };
58454
58517
  this.handleActivePing = async (event) => {
58455
- return await this._signalBacktestUtils.handleActivePing(event);
58518
+ return await this.getInstance().handleActivePing(event);
58456
58519
  };
58457
58520
  this.handleSchedulePing = async (event) => {
58458
- return await this._signalBacktestUtils.handleSchedulePing(event);
58521
+ return await this.getInstance().handleSchedulePing(event);
58459
58522
  };
58460
58523
  /**
58461
58524
  * Sets the storage adapter constructor.
@@ -58465,7 +58528,8 @@ class StorageBacktestAdapter {
58465
58528
  */
58466
58529
  this.useStorageAdapter = (Ctor) => {
58467
58530
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
58468
- this._signalBacktestUtils = Reflect.construct(Ctor, []);
58531
+ this._signalBacktestFactory = () => Reflect.construct(Ctor, []);
58532
+ this.getInstance.clear();
58469
58533
  };
58470
58534
  /**
58471
58535
  * Switches to dummy storage adapter.
@@ -58473,7 +58537,8 @@ class StorageBacktestAdapter {
58473
58537
  */
58474
58538
  this.useDummy = () => {
58475
58539
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
58476
- this._signalBacktestUtils = new StorageDummyBacktestUtils();
58540
+ this._signalBacktestFactory = () => new StorageDummyBacktestUtils();
58541
+ this.getInstance.clear();
58477
58542
  };
58478
58543
  /**
58479
58544
  * Switches to persistent storage adapter (default).
@@ -58481,7 +58546,8 @@ class StorageBacktestAdapter {
58481
58546
  */
58482
58547
  this.usePersist = () => {
58483
58548
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
58484
- this._signalBacktestUtils = new StoragePersistBacktestUtils();
58549
+ this._signalBacktestFactory = () => new StoragePersistBacktestUtils();
58550
+ this.getInstance.clear();
58485
58551
  };
58486
58552
  /**
58487
58553
  * Switches to in-memory storage adapter.
@@ -58489,16 +58555,17 @@ class StorageBacktestAdapter {
58489
58555
  */
58490
58556
  this.useMemory = () => {
58491
58557
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
58492
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58558
+ this._signalBacktestFactory = () => new StorageMemoryBacktestUtils();
58559
+ this.getInstance.clear();
58493
58560
  };
58494
58561
  /**
58495
- * Clears the cached utils instance by resetting to the default in-memory adapter.
58562
+ * Clears the memoized utils instance.
58496
58563
  * Call this when process.cwd() changes between strategy iterations
58497
58564
  * so a new instance is created with the updated base path.
58498
58565
  */
58499
58566
  this.clear = () => {
58500
58567
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
58501
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58568
+ this.getInstance.clear();
58502
58569
  };
58503
58570
  }
58504
58571
  }
@@ -58513,15 +58580,23 @@ class StorageBacktestAdapter {
58513
58580
  */
58514
58581
  class StorageLiveAdapter {
58515
58582
  constructor() {
58516
- /** Internal storage utils instance */
58517
- this._signalLiveUtils = new StoragePersistLiveUtils();
58583
+ /** Factory producing the active storage utils instance */
58584
+ this._signalLiveFactory = () => new StoragePersistLiveUtils();
58585
+ /**
58586
+ * Lazily constructs the storage utils from the registered factory and memoizes
58587
+ * the result via `singleshot`.
58588
+ *
58589
+ * The instance is built on the first call and cached for all subsequent calls.
58590
+ * Reset via `clear()` so the next call rebuilds from the current factory.
58591
+ */
58592
+ this.getInstance = singleshot(() => this._signalLiveFactory());
58518
58593
  /**
58519
58594
  * Handles signal opened event.
58520
58595
  * Proxies call to the underlying storage adapter.
58521
58596
  * @param tick - The opened signal tick data
58522
58597
  */
58523
58598
  this.handleOpened = async (tick) => {
58524
- return await this._signalLiveUtils.handleOpened(tick);
58599
+ return await this.getInstance().handleOpened(tick);
58525
58600
  };
58526
58601
  /**
58527
58602
  * Handles signal closed event.
@@ -58529,7 +58604,7 @@ class StorageLiveAdapter {
58529
58604
  * @param tick - The closed signal tick data
58530
58605
  */
58531
58606
  this.handleClosed = async (tick) => {
58532
- return await this._signalLiveUtils.handleClosed(tick);
58607
+ return await this.getInstance().handleClosed(tick);
58533
58608
  };
58534
58609
  /**
58535
58610
  * Handles signal scheduled event.
@@ -58537,7 +58612,7 @@ class StorageLiveAdapter {
58537
58612
  * @param tick - The scheduled signal tick data
58538
58613
  */
58539
58614
  this.handleScheduled = async (tick) => {
58540
- return await this._signalLiveUtils.handleScheduled(tick);
58615
+ return await this.getInstance().handleScheduled(tick);
58541
58616
  };
58542
58617
  /**
58543
58618
  * Handles signal cancelled event.
@@ -58545,7 +58620,7 @@ class StorageLiveAdapter {
58545
58620
  * @param tick - The cancelled signal tick data
58546
58621
  */
58547
58622
  this.handleCancelled = async (tick) => {
58548
- return await this._signalLiveUtils.handleCancelled(tick);
58623
+ return await this.getInstance().handleCancelled(tick);
58549
58624
  };
58550
58625
  /**
58551
58626
  * Finds a signal by its ID.
@@ -58554,7 +58629,7 @@ class StorageLiveAdapter {
58554
58629
  * @returns The signal row or null if not found
58555
58630
  */
58556
58631
  this.findById = async (id) => {
58557
- return await this._signalLiveUtils.findById(id);
58632
+ return await this.getInstance().findById(id);
58558
58633
  };
58559
58634
  /**
58560
58635
  * Lists all stored signals.
@@ -58562,13 +58637,13 @@ class StorageLiveAdapter {
58562
58637
  * @returns Array of all signal rows
58563
58638
  */
58564
58639
  this.list = async () => {
58565
- return await this._signalLiveUtils.list();
58640
+ return await this.getInstance().list();
58566
58641
  };
58567
58642
  this.handleActivePing = async (event) => {
58568
- return await this._signalLiveUtils.handleActivePing(event);
58643
+ return await this.getInstance().handleActivePing(event);
58569
58644
  };
58570
58645
  this.handleSchedulePing = async (event) => {
58571
- return await this._signalLiveUtils.handleSchedulePing(event);
58646
+ return await this.getInstance().handleSchedulePing(event);
58572
58647
  };
58573
58648
  /**
58574
58649
  * Sets the storage adapter constructor.
@@ -58578,7 +58653,8 @@ class StorageLiveAdapter {
58578
58653
  */
58579
58654
  this.useStorageAdapter = (Ctor) => {
58580
58655
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
58581
- this._signalLiveUtils = Reflect.construct(Ctor, []);
58656
+ this._signalLiveFactory = () => Reflect.construct(Ctor, []);
58657
+ this.getInstance.clear();
58582
58658
  };
58583
58659
  /**
58584
58660
  * Switches to dummy storage adapter.
@@ -58586,7 +58662,8 @@ class StorageLiveAdapter {
58586
58662
  */
58587
58663
  this.useDummy = () => {
58588
58664
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
58589
- this._signalLiveUtils = new StorageDummyLiveUtils();
58665
+ this._signalLiveFactory = () => new StorageDummyLiveUtils();
58666
+ this.getInstance.clear();
58590
58667
  };
58591
58668
  /**
58592
58669
  * Switches to persistent storage adapter (default).
@@ -58594,7 +58671,8 @@ class StorageLiveAdapter {
58594
58671
  */
58595
58672
  this.usePersist = () => {
58596
58673
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
58597
- this._signalLiveUtils = new StoragePersistLiveUtils();
58674
+ this._signalLiveFactory = () => new StoragePersistLiveUtils();
58675
+ this.getInstance.clear();
58598
58676
  };
58599
58677
  /**
58600
58678
  * Switches to in-memory storage adapter.
@@ -58602,16 +58680,17 @@ class StorageLiveAdapter {
58602
58680
  */
58603
58681
  this.useMemory = () => {
58604
58682
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
58605
- this._signalLiveUtils = new StorageMemoryLiveUtils();
58683
+ this._signalLiveFactory = () => new StorageMemoryLiveUtils();
58684
+ this.getInstance.clear();
58606
58685
  };
58607
58686
  /**
58608
- * Clears the cached utils instance by resetting to the default persistent adapter.
58687
+ * Clears the memoized utils instance.
58609
58688
  * Call this when process.cwd() changes between strategy iterations
58610
58689
  * so a new instance is created with the updated base path.
58611
58690
  */
58612
58691
  this.clear = () => {
58613
58692
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_CLEAR);
58614
- this._signalLiveUtils = new StoragePersistLiveUtils();
58693
+ this.getInstance.clear();
58615
58694
  };
58616
58695
  }
58617
58696
  }
@@ -60727,18 +60806,26 @@ class NotificationPersistLiveUtils {
60727
60806
  */
60728
60807
  class NotificationBacktestAdapter {
60729
60808
  constructor() {
60730
- /** Internal notification utils instance */
60731
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
60809
+ /** Factory producing the active notification utils instance */
60810
+ this._notificationBacktestFactory = () => new NotificationMemoryBacktestUtils();
60811
+ /**
60812
+ * Lazily constructs the notification utils from the registered factory and
60813
+ * memoizes the result via `singleshot`.
60814
+ *
60815
+ * The instance is built on the first call and cached for all subsequent calls.
60816
+ * Reset via `clear()` so the next call rebuilds from the current factory.
60817
+ */
60818
+ this.getInstance = singleshot(() => this._notificationBacktestFactory());
60732
60819
  /**
60733
60820
  * Handles signal events.
60734
60821
  * Proxies call to the underlying notification adapter.
60735
60822
  * @param data - The strategy tick result data
60736
60823
  */
60737
60824
  this.handleSignal = async (data) => {
60738
- return await this._notificationBacktestUtils.handleSignal(data);
60825
+ return await this.getInstance().handleSignal(data);
60739
60826
  };
60740
60827
  this.handleSignalNotify = async (data) => {
60741
- return await this._notificationBacktestUtils.handleSignalNotify(data);
60828
+ return await this.getInstance().handleSignalNotify(data);
60742
60829
  };
60743
60830
  /**
60744
60831
  * Handles partial profit availability event.
@@ -60746,7 +60833,7 @@ class NotificationBacktestAdapter {
60746
60833
  * @param data - The partial profit contract data
60747
60834
  */
60748
60835
  this.handlePartialProfit = async (data) => {
60749
- return await this._notificationBacktestUtils.handlePartialProfit(data);
60836
+ return await this.getInstance().handlePartialProfit(data);
60750
60837
  };
60751
60838
  /**
60752
60839
  * Handles partial loss availability event.
@@ -60754,7 +60841,7 @@ class NotificationBacktestAdapter {
60754
60841
  * @param data - The partial loss contract data
60755
60842
  */
60756
60843
  this.handlePartialLoss = async (data) => {
60757
- return await this._notificationBacktestUtils.handlePartialLoss(data);
60844
+ return await this.getInstance().handlePartialLoss(data);
60758
60845
  };
60759
60846
  /**
60760
60847
  * Handles breakeven availability event.
@@ -60762,7 +60849,7 @@ class NotificationBacktestAdapter {
60762
60849
  * @param data - The breakeven contract data
60763
60850
  */
60764
60851
  this.handleBreakeven = async (data) => {
60765
- return await this._notificationBacktestUtils.handleBreakeven(data);
60852
+ return await this.getInstance().handleBreakeven(data);
60766
60853
  };
60767
60854
  /**
60768
60855
  * Handles strategy commit events.
@@ -60770,7 +60857,7 @@ class NotificationBacktestAdapter {
60770
60857
  * @param data - The strategy commit contract data
60771
60858
  */
60772
60859
  this.handleStrategyCommit = async (data) => {
60773
- return await this._notificationBacktestUtils.handleStrategyCommit(data);
60860
+ return await this.getInstance().handleStrategyCommit(data);
60774
60861
  };
60775
60862
  /**
60776
60863
  * Handles signal sync events (signal-open, signal-close).
@@ -60778,7 +60865,7 @@ class NotificationBacktestAdapter {
60778
60865
  * @param data - The signal sync contract data
60779
60866
  */
60780
60867
  this.handleSync = trycatch(async (data) => {
60781
- return await this._notificationBacktestUtils.handleSync(data);
60868
+ return await this.getInstance().handleSync(data);
60782
60869
  }, {
60783
60870
  defaultValue: null,
60784
60871
  });
@@ -60788,7 +60875,7 @@ class NotificationBacktestAdapter {
60788
60875
  * @param data - The risk contract data
60789
60876
  */
60790
60877
  this.handleRisk = async (data) => {
60791
- return await this._notificationBacktestUtils.handleRisk(data);
60878
+ return await this.getInstance().handleRisk(data);
60792
60879
  };
60793
60880
  /**
60794
60881
  * Handles error event.
@@ -60796,7 +60883,7 @@ class NotificationBacktestAdapter {
60796
60883
  * @param error - The error object
60797
60884
  */
60798
60885
  this.handleError = async (error) => {
60799
- return await this._notificationBacktestUtils.handleError(error);
60886
+ return await this.getInstance().handleError(error);
60800
60887
  };
60801
60888
  /**
60802
60889
  * Handles critical error event.
@@ -60804,7 +60891,7 @@ class NotificationBacktestAdapter {
60804
60891
  * @param error - The error object
60805
60892
  */
60806
60893
  this.handleCriticalError = async (error) => {
60807
- return await this._notificationBacktestUtils.handleCriticalError(error);
60894
+ return await this.getInstance().handleCriticalError(error);
60808
60895
  };
60809
60896
  /**
60810
60897
  * Handles validation error event.
@@ -60812,7 +60899,7 @@ class NotificationBacktestAdapter {
60812
60899
  * @param error - The error object
60813
60900
  */
60814
60901
  this.handleValidationError = async (error) => {
60815
- return await this._notificationBacktestUtils.handleValidationError(error);
60902
+ return await this.getInstance().handleValidationError(error);
60816
60903
  };
60817
60904
  /**
60818
60905
  * Gets all stored notifications.
@@ -60820,14 +60907,14 @@ class NotificationBacktestAdapter {
60820
60907
  * @returns Array of all notification models
60821
60908
  */
60822
60909
  this.getData = async () => {
60823
- return await this._notificationBacktestUtils.getData();
60910
+ return await this.getInstance().getData();
60824
60911
  };
60825
60912
  /**
60826
60913
  * Clears all stored notifications.
60827
60914
  * Proxies call to the underlying notification adapter.
60828
60915
  */
60829
60916
  this.dispose = async () => {
60830
- return await this._notificationBacktestUtils.dispose();
60917
+ return await this.getInstance().dispose();
60831
60918
  };
60832
60919
  /**
60833
60920
  * Sets the notification adapter constructor.
@@ -60837,7 +60924,8 @@ class NotificationBacktestAdapter {
60837
60924
  */
60838
60925
  this.useNotificationAdapter = (Ctor) => {
60839
60926
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
60840
- this._notificationBacktestUtils = Reflect.construct(Ctor, []);
60927
+ this._notificationBacktestFactory = () => Reflect.construct(Ctor, []);
60928
+ this.getInstance.clear();
60841
60929
  };
60842
60930
  /**
60843
60931
  * Switches to dummy notification adapter.
@@ -60845,7 +60933,8 @@ class NotificationBacktestAdapter {
60845
60933
  */
60846
60934
  this.useDummy = () => {
60847
60935
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
60848
- this._notificationBacktestUtils = new NotificationDummyBacktestUtils();
60936
+ this._notificationBacktestFactory = () => new NotificationDummyBacktestUtils();
60937
+ this.getInstance.clear();
60849
60938
  };
60850
60939
  /**
60851
60940
  * Switches to in-memory notification adapter (default).
@@ -60853,7 +60942,8 @@ class NotificationBacktestAdapter {
60853
60942
  */
60854
60943
  this.useMemory = () => {
60855
60944
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
60856
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
60945
+ this._notificationBacktestFactory = () => new NotificationMemoryBacktestUtils();
60946
+ this.getInstance.clear();
60857
60947
  };
60858
60948
  /**
60859
60949
  * Switches to persistent notification adapter.
@@ -60861,16 +60951,17 @@ class NotificationBacktestAdapter {
60861
60951
  */
60862
60952
  this.usePersist = () => {
60863
60953
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
60864
- this._notificationBacktestUtils = new NotificationPersistBacktestUtils();
60954
+ this._notificationBacktestFactory = () => new NotificationPersistBacktestUtils();
60955
+ this.getInstance.clear();
60865
60956
  };
60866
60957
  /**
60867
- * Resets the cached utils instance to the default in-memory adapter.
60958
+ * Clears the memoized utils instance.
60868
60959
  * Call this when process.cwd() changes between strategy iterations
60869
60960
  * so a new instance is created with the updated base path.
60870
60961
  */
60871
60962
  this.clear = () => {
60872
60963
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
60873
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
60964
+ this.getInstance.clear();
60874
60965
  };
60875
60966
  }
60876
60967
  }
@@ -60885,18 +60976,26 @@ class NotificationBacktestAdapter {
60885
60976
  */
60886
60977
  class NotificationLiveAdapter {
60887
60978
  constructor() {
60888
- /** Internal notification utils instance */
60889
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
60979
+ /** Factory producing the active notification utils instance */
60980
+ this._notificationLiveFactory = () => new NotificationMemoryLiveUtils();
60981
+ /**
60982
+ * Lazily constructs the notification utils from the registered factory and
60983
+ * memoizes the result via `singleshot`.
60984
+ *
60985
+ * The instance is built on the first call and cached for all subsequent calls.
60986
+ * Reset via `clear()` so the next call rebuilds from the current factory.
60987
+ */
60988
+ this.getInstance = singleshot(() => this._notificationLiveFactory());
60890
60989
  /**
60891
60990
  * Handles signal events.
60892
60991
  * Proxies call to the underlying notification adapter.
60893
60992
  * @param data - The strategy tick result data
60894
60993
  */
60895
60994
  this.handleSignal = async (data) => {
60896
- return await this._notificationLiveUtils.handleSignal(data);
60995
+ return await this.getInstance().handleSignal(data);
60897
60996
  };
60898
60997
  this.handleSignalNotify = async (data) => {
60899
- return await this._notificationLiveUtils.handleSignalNotify(data);
60998
+ return await this.getInstance().handleSignalNotify(data);
60900
60999
  };
60901
61000
  /**
60902
61001
  * Handles partial profit availability event.
@@ -60904,7 +61003,7 @@ class NotificationLiveAdapter {
60904
61003
  * @param data - The partial profit contract data
60905
61004
  */
60906
61005
  this.handlePartialProfit = async (data) => {
60907
- return await this._notificationLiveUtils.handlePartialProfit(data);
61006
+ return await this.getInstance().handlePartialProfit(data);
60908
61007
  };
60909
61008
  /**
60910
61009
  * Handles partial loss availability event.
@@ -60912,7 +61011,7 @@ class NotificationLiveAdapter {
60912
61011
  * @param data - The partial loss contract data
60913
61012
  */
60914
61013
  this.handlePartialLoss = async (data) => {
60915
- return await this._notificationLiveUtils.handlePartialLoss(data);
61014
+ return await this.getInstance().handlePartialLoss(data);
60916
61015
  };
60917
61016
  /**
60918
61017
  * Handles breakeven availability event.
@@ -60920,7 +61019,7 @@ class NotificationLiveAdapter {
60920
61019
  * @param data - The breakeven contract data
60921
61020
  */
60922
61021
  this.handleBreakeven = async (data) => {
60923
- return await this._notificationLiveUtils.handleBreakeven(data);
61022
+ return await this.getInstance().handleBreakeven(data);
60924
61023
  };
60925
61024
  /**
60926
61025
  * Handles strategy commit events.
@@ -60928,7 +61027,7 @@ class NotificationLiveAdapter {
60928
61027
  * @param data - The strategy commit contract data
60929
61028
  */
60930
61029
  this.handleStrategyCommit = async (data) => {
60931
- return await this._notificationLiveUtils.handleStrategyCommit(data);
61030
+ return await this.getInstance().handleStrategyCommit(data);
60932
61031
  };
60933
61032
  /**
60934
61033
  * Handles signal sync events (signal-open, signal-close).
@@ -60936,7 +61035,7 @@ class NotificationLiveAdapter {
60936
61035
  * @param data - The signal sync contract data
60937
61036
  */
60938
61037
  this.handleSync = trycatch(async (data) => {
60939
- return await this._notificationLiveUtils.handleSync(data);
61038
+ return await this.getInstance().handleSync(data);
60940
61039
  }, {
60941
61040
  defaultValue: null,
60942
61041
  });
@@ -60946,7 +61045,7 @@ class NotificationLiveAdapter {
60946
61045
  * @param data - The risk contract data
60947
61046
  */
60948
61047
  this.handleRisk = async (data) => {
60949
- return await this._notificationLiveUtils.handleRisk(data);
61048
+ return await this.getInstance().handleRisk(data);
60950
61049
  };
60951
61050
  /**
60952
61051
  * Handles error event.
@@ -60954,7 +61053,7 @@ class NotificationLiveAdapter {
60954
61053
  * @param error - The error object
60955
61054
  */
60956
61055
  this.handleError = async (error) => {
60957
- return await this._notificationLiveUtils.handleError(error);
61056
+ return await this.getInstance().handleError(error);
60958
61057
  };
60959
61058
  /**
60960
61059
  * Handles critical error event.
@@ -60962,7 +61061,7 @@ class NotificationLiveAdapter {
60962
61061
  * @param error - The error object
60963
61062
  */
60964
61063
  this.handleCriticalError = async (error) => {
60965
- return await this._notificationLiveUtils.handleCriticalError(error);
61064
+ return await this.getInstance().handleCriticalError(error);
60966
61065
  };
60967
61066
  /**
60968
61067
  * Handles validation error event.
@@ -60970,7 +61069,7 @@ class NotificationLiveAdapter {
60970
61069
  * @param error - The error object
60971
61070
  */
60972
61071
  this.handleValidationError = async (error) => {
60973
- return await this._notificationLiveUtils.handleValidationError(error);
61072
+ return await this.getInstance().handleValidationError(error);
60974
61073
  };
60975
61074
  /**
60976
61075
  * Gets all stored notifications.
@@ -60978,14 +61077,14 @@ class NotificationLiveAdapter {
60978
61077
  * @returns Array of all notification models
60979
61078
  */
60980
61079
  this.getData = async () => {
60981
- return await this._notificationLiveUtils.getData();
61080
+ return await this.getInstance().getData();
60982
61081
  };
60983
61082
  /**
60984
61083
  * Clears all stored notifications.
60985
61084
  * Proxies call to the underlying notification adapter.
60986
61085
  */
60987
61086
  this.dispose = async () => {
60988
- return await this._notificationLiveUtils.dispose();
61087
+ return await this.getInstance().dispose();
60989
61088
  };
60990
61089
  /**
60991
61090
  * Sets the notification adapter constructor.
@@ -60995,7 +61094,8 @@ class NotificationLiveAdapter {
60995
61094
  */
60996
61095
  this.useNotificationAdapter = (Ctor) => {
60997
61096
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
60998
- this._notificationLiveUtils = Reflect.construct(Ctor, []);
61097
+ this._notificationLiveFactory = () => Reflect.construct(Ctor, []);
61098
+ this.getInstance.clear();
60999
61099
  };
61000
61100
  /**
61001
61101
  * Switches to dummy notification adapter.
@@ -61003,7 +61103,8 @@ class NotificationLiveAdapter {
61003
61103
  */
61004
61104
  this.useDummy = () => {
61005
61105
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
61006
- this._notificationLiveUtils = new NotificationDummyLiveUtils();
61106
+ this._notificationLiveFactory = () => new NotificationDummyLiveUtils();
61107
+ this.getInstance.clear();
61007
61108
  };
61008
61109
  /**
61009
61110
  * Switches to in-memory notification adapter (default).
@@ -61011,7 +61112,8 @@ class NotificationLiveAdapter {
61011
61112
  */
61012
61113
  this.useMemory = () => {
61013
61114
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
61014
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61115
+ this._notificationLiveFactory = () => new NotificationMemoryLiveUtils();
61116
+ this.getInstance.clear();
61015
61117
  };
61016
61118
  /**
61017
61119
  * Switches to persistent notification adapter.
@@ -61019,16 +61121,17 @@ class NotificationLiveAdapter {
61019
61121
  */
61020
61122
  this.usePersist = () => {
61021
61123
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
61022
- this._notificationLiveUtils = new NotificationPersistLiveUtils();
61124
+ this._notificationLiveFactory = () => new NotificationPersistLiveUtils();
61125
+ this.getInstance.clear();
61023
61126
  };
61024
61127
  /**
61025
- * Resets the cached utils instance to the default in-memory adapter.
61128
+ * Clears the memoized utils instance.
61026
61129
  * Call this when process.cwd() changes between strategy iterations
61027
61130
  * so a new instance is created with the updated base path.
61028
61131
  */
61029
61132
  this.clear = () => {
61030
61133
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_CLEAR);
61031
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61134
+ this.getInstance.clear();
61032
61135
  };
61033
61136
  }
61034
61137
  }