backtest-kit 9.8.0 → 9.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1893 -1871
  3. package/build/index.cjs +740 -259
  4. package/build/index.mjs +739 -260
  5. package/package.json +86 -86
  6. package/types.d.ts +218 -25
package/build/index.cjs CHANGED
@@ -574,6 +574,22 @@ const GLOBAL_CONFIG = {
574
574
  * Default: true (mutex locking enabled for candle fetching)
575
575
  */
576
576
  CC_ENABLE_CANDLE_FETCH_MUTEX: true,
577
+ /**
578
+ * Enables cooperative interleaving of concurrently running backtests after each candle fetch.
579
+ *
580
+ * Mechanism (implemented in `Candle.spinLock`):
581
+ * - After `getNextCandles` resolves, the current backtest awaits
582
+ * `Promise.race([_spin.toPromise(), sleep(50)])`, where `_spin` is emitted whenever
583
+ * another caller acquires the candle-fetch mutex.
584
+ * - This hands the event loop to a peer backtest waiting on the same mutex, so multiple
585
+ * parallel `Backtest.run` / `Walker` workloads progress in round-robin fashion instead
586
+ * of one monopolizing the event loop until completion.
587
+ * - The spin is skipped entirely when `Lookup.isParallel` is `false` (single active workload —
588
+ * no peer to yield to) or when `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled.
589
+ *
590
+ * Default: true (parallel backtests are interleaved on each candle fetch boundary)
591
+ */
592
+ CC_ENABLE_BACKTEST_PARALLEL_SPIN: true,
577
593
  /**
578
594
  * Enables DCA (Dollar-Cost Averaging) logic even if antirecord is not broken.
579
595
  * Allows to commitAverageBuy if currentPrice is not the lowest price since entry, but still lower than priceOpen.
@@ -934,7 +950,7 @@ async function writeFileAtomic(file, data, options = {}) {
934
950
 
935
951
  var _a$3;
936
952
  /** Logger service injected as DI singleton */
937
- const LOGGER_SERVICE$7 = new LoggerService();
953
+ const LOGGER_SERVICE$8 = new LoggerService();
938
954
  /** Symbol key for the singleshot waitForInit function on PersistBase instances. */
939
955
  const BASE_WAIT_FOR_INIT_SYMBOL = Symbol("wait-for-init");
940
956
  // Calculate step in milliseconds for candle close time validation
@@ -1057,7 +1073,7 @@ const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
1057
1073
  const BASE_UNLINK_RETRY_COUNT = 5;
1058
1074
  const BASE_UNLINK_RETRY_DELAY = 1000;
1059
1075
  const BASE_WAIT_FOR_INIT_FN = async (self) => {
1060
- LOGGER_SERVICE$7.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
1076
+ LOGGER_SERVICE$8.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
1061
1077
  entityName: self.entityName,
1062
1078
  directory: self._directory,
1063
1079
  });
@@ -1115,7 +1131,7 @@ class PersistBase {
1115
1131
  this.entityName = entityName;
1116
1132
  this.baseDir = baseDir;
1117
1133
  this[_a$3] = functoolsKit.singleshot(async () => await BASE_WAIT_FOR_INIT_FN(this));
1118
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
1134
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
1119
1135
  entityName: this.entityName,
1120
1136
  baseDir,
1121
1137
  });
@@ -1131,14 +1147,14 @@ class PersistBase {
1131
1147
  return path.join(this.baseDir, this.entityName, `${entityId}.json`);
1132
1148
  }
1133
1149
  async waitForInit(initial) {
1134
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
1150
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
1135
1151
  entityName: this.entityName,
1136
1152
  initial,
1137
1153
  });
1138
1154
  await this[BASE_WAIT_FOR_INIT_SYMBOL]();
1139
1155
  }
1140
1156
  async readValue(entityId) {
1141
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
1157
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
1142
1158
  entityName: this.entityName,
1143
1159
  entityId,
1144
1160
  });
@@ -1155,7 +1171,7 @@ class PersistBase {
1155
1171
  }
1156
1172
  }
1157
1173
  async hasValue(entityId) {
1158
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
1174
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
1159
1175
  entityName: this.entityName,
1160
1176
  entityId,
1161
1177
  });
@@ -1172,7 +1188,7 @@ class PersistBase {
1172
1188
  }
1173
1189
  }
1174
1190
  async writeValue(entityId, entity) {
1175
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
1191
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
1176
1192
  entityName: this.entityName,
1177
1193
  entityId,
1178
1194
  });
@@ -1194,7 +1210,7 @@ class PersistBase {
1194
1210
  * @throws Error if reading fails
1195
1211
  */
1196
1212
  async *keys() {
1197
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
1213
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
1198
1214
  entityName: this.entityName,
1199
1215
  });
1200
1216
  try {
@@ -1339,7 +1355,7 @@ class PersistSignalUtils {
1339
1355
  * @returns Promise resolving to signal or null if none persisted
1340
1356
  */
1341
1357
  this.readSignalData = async (symbol, strategyName, exchangeName) => {
1342
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
1358
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
1343
1359
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1344
1360
  const isInitial = !this.getStorage.has(key);
1345
1361
  const instance = this.getStorage(symbol, strategyName, exchangeName);
@@ -1357,7 +1373,7 @@ class PersistSignalUtils {
1357
1373
  * @returns Promise that resolves when write is complete
1358
1374
  */
1359
1375
  this.writeSignalData = async (signalRow, symbol, strategyName, exchangeName) => {
1360
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
1376
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
1361
1377
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1362
1378
  const isInitial = !this.getStorage.has(key);
1363
1379
  const instance = this.getStorage(symbol, strategyName, exchangeName);
@@ -1372,7 +1388,7 @@ class PersistSignalUtils {
1372
1388
  * @param Ctor - Custom IPersistSignalInstance constructor
1373
1389
  */
1374
1390
  usePersistSignalAdapter(Ctor) {
1375
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
1391
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
1376
1392
  this.PersistSignalInstanceCtor = Ctor;
1377
1393
  this.getStorage.clear();
1378
1394
  }
@@ -1381,21 +1397,21 @@ class PersistSignalUtils {
1381
1397
  * Call when process.cwd() changes between strategy iterations.
1382
1398
  */
1383
1399
  clear() {
1384
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
1400
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
1385
1401
  this.getStorage.clear();
1386
1402
  }
1387
1403
  /**
1388
1404
  * Switches to the default file-based PersistSignalInstance.
1389
1405
  */
1390
1406
  useJson() {
1391
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
1407
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
1392
1408
  this.usePersistSignalAdapter(PersistSignalInstance);
1393
1409
  }
1394
1410
  /**
1395
1411
  * Switches to PersistSignalDummyInstance (all operations are no-ops).
1396
1412
  */
1397
1413
  useDummy() {
1398
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
1414
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
1399
1415
  this.usePersistSignalAdapter(PersistSignalDummyInstance);
1400
1416
  }
1401
1417
  }
@@ -1535,7 +1551,7 @@ class PersistRiskUtils {
1535
1551
  * @returns Promise resolving to position entries (empty array if none)
1536
1552
  */
1537
1553
  this.readPositionData = async (riskName, exchangeName, when) => {
1538
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
1554
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
1539
1555
  const key = `${riskName}:${exchangeName}`;
1540
1556
  const isInitial = !this.getRiskStorage.has(key);
1541
1557
  const instance = this.getRiskStorage(riskName, exchangeName);
@@ -1553,7 +1569,7 @@ class PersistRiskUtils {
1553
1569
  * @returns Promise that resolves when write is complete
1554
1570
  */
1555
1571
  this.writePositionData = async (riskRow, riskName, exchangeName, when) => {
1556
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
1572
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
1557
1573
  const key = `${riskName}:${exchangeName}`;
1558
1574
  const isInitial = !this.getRiskStorage.has(key);
1559
1575
  const instance = this.getRiskStorage(riskName, exchangeName);
@@ -1568,7 +1584,7 @@ class PersistRiskUtils {
1568
1584
  * @param Ctor - Custom IPersistRiskInstance constructor
1569
1585
  */
1570
1586
  usePersistRiskAdapter(Ctor) {
1571
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
1587
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
1572
1588
  this.PersistRiskInstanceCtor = Ctor;
1573
1589
  this.getRiskStorage.clear();
1574
1590
  }
@@ -1577,21 +1593,21 @@ class PersistRiskUtils {
1577
1593
  * Call when process.cwd() changes between strategy iterations.
1578
1594
  */
1579
1595
  clear() {
1580
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
1596
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
1581
1597
  this.getRiskStorage.clear();
1582
1598
  }
1583
1599
  /**
1584
1600
  * Switches to the default file-based PersistRiskInstance.
1585
1601
  */
1586
1602
  useJson() {
1587
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
1603
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
1588
1604
  this.usePersistRiskAdapter(PersistRiskInstance);
1589
1605
  }
1590
1606
  /**
1591
1607
  * Switches to PersistRiskDummyInstance (all operations are no-ops).
1592
1608
  */
1593
1609
  useDummy() {
1594
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
1610
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
1595
1611
  this.usePersistRiskAdapter(PersistRiskDummyInstance);
1596
1612
  }
1597
1613
  }
@@ -1730,7 +1746,7 @@ class PersistScheduleUtils {
1730
1746
  * @returns Promise resolving to scheduled signal or null if none persisted
1731
1747
  */
1732
1748
  this.readScheduleData = async (symbol, strategyName, exchangeName) => {
1733
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
1749
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
1734
1750
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1735
1751
  const isInitial = !this.getScheduleStorage.has(key);
1736
1752
  const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
@@ -1748,7 +1764,7 @@ class PersistScheduleUtils {
1748
1764
  * @returns Promise that resolves when write is complete
1749
1765
  */
1750
1766
  this.writeScheduleData = async (scheduledSignalRow, symbol, strategyName, exchangeName) => {
1751
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
1767
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
1752
1768
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1753
1769
  const isInitial = !this.getScheduleStorage.has(key);
1754
1770
  const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
@@ -1763,7 +1779,7 @@ class PersistScheduleUtils {
1763
1779
  * @param Ctor - Custom IPersistScheduleInstance constructor
1764
1780
  */
1765
1781
  usePersistScheduleAdapter(Ctor) {
1766
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
1782
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
1767
1783
  this.PersistScheduleInstanceCtor = Ctor;
1768
1784
  this.getScheduleStorage.clear();
1769
1785
  }
@@ -1772,21 +1788,21 @@ class PersistScheduleUtils {
1772
1788
  * Call when process.cwd() changes between strategy iterations.
1773
1789
  */
1774
1790
  clear() {
1775
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
1791
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
1776
1792
  this.getScheduleStorage.clear();
1777
1793
  }
1778
1794
  /**
1779
1795
  * Switches to the default file-based PersistScheduleInstance.
1780
1796
  */
1781
1797
  useJson() {
1782
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
1798
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
1783
1799
  this.usePersistScheduleAdapter(PersistScheduleInstance);
1784
1800
  }
1785
1801
  /**
1786
1802
  * Switches to PersistScheduleDummyInstance (all operations are no-ops).
1787
1803
  */
1788
1804
  useDummy() {
1789
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
1805
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
1790
1806
  this.usePersistScheduleAdapter(PersistScheduleDummyInstance);
1791
1807
  }
1792
1808
  }
@@ -1931,7 +1947,7 @@ class PersistPartialUtils {
1931
1947
  * @returns Promise resolving to partial data record (empty object if none)
1932
1948
  */
1933
1949
  this.readPartialData = async (symbol, strategyName, signalId, exchangeName, when) => {
1934
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
1950
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
1935
1951
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1936
1952
  const isInitial = !this.getPartialStorage.has(key);
1937
1953
  const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
@@ -1951,7 +1967,7 @@ class PersistPartialUtils {
1951
1967
  * @returns Promise that resolves when write is complete
1952
1968
  */
1953
1969
  this.writePartialData = async (partialData, symbol, strategyName, signalId, exchangeName, when) => {
1954
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
1970
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
1955
1971
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1956
1972
  const isInitial = !this.getPartialStorage.has(key);
1957
1973
  const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
@@ -1966,7 +1982,7 @@ class PersistPartialUtils {
1966
1982
  * @param Ctor - Custom IPersistPartialInstance constructor
1967
1983
  */
1968
1984
  usePersistPartialAdapter(Ctor) {
1969
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
1985
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
1970
1986
  this.PersistPartialInstanceCtor = Ctor;
1971
1987
  this.getPartialStorage.clear();
1972
1988
  }
@@ -1975,21 +1991,21 @@ class PersistPartialUtils {
1975
1991
  * Call when process.cwd() changes between strategy iterations.
1976
1992
  */
1977
1993
  clear() {
1978
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
1994
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
1979
1995
  this.getPartialStorage.clear();
1980
1996
  }
1981
1997
  /**
1982
1998
  * Switches to the default file-based PersistPartialInstance.
1983
1999
  */
1984
2000
  useJson() {
1985
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
2001
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
1986
2002
  this.usePersistPartialAdapter(PersistPartialInstance);
1987
2003
  }
1988
2004
  /**
1989
2005
  * Switches to PersistPartialDummyInstance (all operations are no-ops).
1990
2006
  */
1991
2007
  useDummy() {
1992
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
2008
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
1993
2009
  this.usePersistPartialAdapter(PersistPartialDummyInstance);
1994
2010
  }
1995
2011
  }
@@ -2154,7 +2170,7 @@ class PersistBreakevenUtils {
2154
2170
  * @returns Promise resolving to breakeven data record (empty object if none)
2155
2171
  */
2156
2172
  this.readBreakevenData = async (symbol, strategyName, signalId, exchangeName, when) => {
2157
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
2173
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
2158
2174
  const key = `${symbol}:${strategyName}:${exchangeName}`;
2159
2175
  const isInitial = !this.getBreakevenStorage.has(key);
2160
2176
  const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
@@ -2174,7 +2190,7 @@ class PersistBreakevenUtils {
2174
2190
  * @returns Promise that resolves when write is complete
2175
2191
  */
2176
2192
  this.writeBreakevenData = async (breakevenData, symbol, strategyName, signalId, exchangeName, when) => {
2177
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
2193
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
2178
2194
  const key = `${symbol}:${strategyName}:${exchangeName}`;
2179
2195
  const isInitial = !this.getBreakevenStorage.has(key);
2180
2196
  const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
@@ -2189,7 +2205,7 @@ class PersistBreakevenUtils {
2189
2205
  * @param Ctor - Custom IPersistBreakevenInstance constructor
2190
2206
  */
2191
2207
  usePersistBreakevenAdapter(Ctor) {
2192
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
2208
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
2193
2209
  this.PersistBreakevenInstanceCtor = Ctor;
2194
2210
  this.getBreakevenStorage.clear();
2195
2211
  }
@@ -2198,21 +2214,21 @@ class PersistBreakevenUtils {
2198
2214
  * Call when process.cwd() changes between strategy iterations.
2199
2215
  */
2200
2216
  clear() {
2201
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
2217
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
2202
2218
  this.getBreakevenStorage.clear();
2203
2219
  }
2204
2220
  /**
2205
2221
  * Switches to the default file-based PersistBreakevenInstance.
2206
2222
  */
2207
2223
  useJson() {
2208
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
2224
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
2209
2225
  this.usePersistBreakevenAdapter(PersistBreakevenInstance);
2210
2226
  }
2211
2227
  /**
2212
2228
  * Switches to PersistBreakevenDummyInstance (all operations are no-ops).
2213
2229
  */
2214
2230
  useDummy() {
2215
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
2231
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
2216
2232
  this.usePersistBreakevenAdapter(PersistBreakevenDummyInstance);
2217
2233
  }
2218
2234
  }
@@ -2303,7 +2319,7 @@ class PersistCandleInstance {
2303
2319
  error: functoolsKit.errorData(error),
2304
2320
  message: functoolsKit.getErrorMessage(error),
2305
2321
  };
2306
- LOGGER_SERVICE$7.warn(message, payload);
2322
+ LOGGER_SERVICE$8.warn(message, payload);
2307
2323
  console.warn(message, payload);
2308
2324
  errorEmitter.next(error);
2309
2325
  return null;
@@ -2325,7 +2341,7 @@ class PersistCandleInstance {
2325
2341
  for (const candle of candles) {
2326
2342
  const candleCloseTime = candle.timestamp + stepMs;
2327
2343
  if (candleCloseTime > now) {
2328
- LOGGER_SERVICE$7.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
2344
+ LOGGER_SERVICE$8.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
2329
2345
  symbol: this.symbol,
2330
2346
  interval: this.interval,
2331
2347
  exchangeName: this.exchangeName,
@@ -2402,7 +2418,7 @@ class PersistCandleUtils {
2402
2418
  * @returns Promise resolving to candles in order, or null on cache miss
2403
2419
  */
2404
2420
  this.readCandlesData = async (symbol, interval, exchangeName, limit, sinceTimestamp, untilTimestamp) => {
2405
- LOGGER_SERVICE$7.info("PersistCandleUtils.readCandlesData", {
2421
+ LOGGER_SERVICE$8.info("PersistCandleUtils.readCandlesData", {
2406
2422
  symbol,
2407
2423
  interval,
2408
2424
  exchangeName,
@@ -2426,7 +2442,7 @@ class PersistCandleUtils {
2426
2442
  * @returns Promise that resolves when all writes are complete
2427
2443
  */
2428
2444
  this.writeCandlesData = async (candles, symbol, interval, exchangeName) => {
2429
- LOGGER_SERVICE$7.info("PersistCandleUtils.writeCandlesData", {
2445
+ LOGGER_SERVICE$8.info("PersistCandleUtils.writeCandlesData", {
2430
2446
  symbol,
2431
2447
  interval,
2432
2448
  exchangeName,
@@ -2446,7 +2462,7 @@ class PersistCandleUtils {
2446
2462
  * @param Ctor - Custom IPersistCandleInstance constructor
2447
2463
  */
2448
2464
  usePersistCandleAdapter(Ctor) {
2449
- LOGGER_SERVICE$7.info("PersistCandleUtils.usePersistCandleAdapter");
2465
+ LOGGER_SERVICE$8.info("PersistCandleUtils.usePersistCandleAdapter");
2450
2466
  this.PersistCandleInstanceCtor = Ctor;
2451
2467
  this.getCandlesStorage.clear();
2452
2468
  }
@@ -2455,21 +2471,21 @@ class PersistCandleUtils {
2455
2471
  * Call when process.cwd() changes between strategy iterations.
2456
2472
  */
2457
2473
  clear() {
2458
- LOGGER_SERVICE$7.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
2474
+ LOGGER_SERVICE$8.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
2459
2475
  this.getCandlesStorage.clear();
2460
2476
  }
2461
2477
  /**
2462
2478
  * Switches to the default file-based PersistCandleInstance.
2463
2479
  */
2464
2480
  useJson() {
2465
- LOGGER_SERVICE$7.log("PersistCandleUtils.useJson");
2481
+ LOGGER_SERVICE$8.log("PersistCandleUtils.useJson");
2466
2482
  this.usePersistCandleAdapter(PersistCandleInstance);
2467
2483
  }
2468
2484
  /**
2469
2485
  * Switches to PersistCandleDummyInstance (always returns null on read, discards writes).
2470
2486
  */
2471
2487
  useDummy() {
2472
- LOGGER_SERVICE$7.log("PersistCandleUtils.useDummy");
2488
+ LOGGER_SERVICE$8.log("PersistCandleUtils.useDummy");
2473
2489
  this.usePersistCandleAdapter(PersistCandleDummyInstance);
2474
2490
  }
2475
2491
  }
@@ -2607,7 +2623,7 @@ class PersistStorageUtils {
2607
2623
  * @returns Promise resolving to array of signal entries
2608
2624
  */
2609
2625
  this.readStorageData = async (backtest) => {
2610
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
2626
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
2611
2627
  const key = backtest ? `backtest` : `live`;
2612
2628
  const isInitial = !this.getStorage.has(key);
2613
2629
  const instance = this.getStorage(backtest);
@@ -2623,7 +2639,7 @@ class PersistStorageUtils {
2623
2639
  * @returns Promise that resolves when write is complete
2624
2640
  */
2625
2641
  this.writeStorageData = async (signalData, backtest) => {
2626
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
2642
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
2627
2643
  const key = backtest ? `backtest` : `live`;
2628
2644
  const isInitial = !this.getStorage.has(key);
2629
2645
  const instance = this.getStorage(backtest);
@@ -2638,7 +2654,7 @@ class PersistStorageUtils {
2638
2654
  * @param Ctor - Custom IPersistStorageInstance constructor
2639
2655
  */
2640
2656
  usePersistStorageAdapter(Ctor) {
2641
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
2657
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
2642
2658
  this.PersistStorageInstanceCtor = Ctor;
2643
2659
  this.getStorage.clear();
2644
2660
  }
@@ -2647,21 +2663,21 @@ class PersistStorageUtils {
2647
2663
  * Call when process.cwd() changes between strategy iterations.
2648
2664
  */
2649
2665
  clear() {
2650
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
2666
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
2651
2667
  this.getStorage.clear();
2652
2668
  }
2653
2669
  /**
2654
2670
  * Switches to the default file-based PersistStorageInstance.
2655
2671
  */
2656
2672
  useJson() {
2657
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
2673
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
2658
2674
  this.usePersistStorageAdapter(PersistStorageInstance);
2659
2675
  }
2660
2676
  /**
2661
2677
  * Switches to PersistStorageDummyInstance (all operations are no-ops).
2662
2678
  */
2663
2679
  useDummy() {
2664
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
2680
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
2665
2681
  this.usePersistStorageAdapter(PersistStorageDummyInstance);
2666
2682
  }
2667
2683
  }
@@ -2788,7 +2804,7 @@ class PersistNotificationUtils {
2788
2804
  * @returns Promise resolving to array of notification entries
2789
2805
  */
2790
2806
  this.readNotificationData = async (backtest) => {
2791
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
2807
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
2792
2808
  const key = backtest ? `backtest` : `live`;
2793
2809
  const isInitial = !this.getNotificationStorage.has(key);
2794
2810
  const instance = this.getNotificationStorage(backtest);
@@ -2804,7 +2820,7 @@ class PersistNotificationUtils {
2804
2820
  * @returns Promise that resolves when write is complete
2805
2821
  */
2806
2822
  this.writeNotificationData = async (notificationData, backtest) => {
2807
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
2823
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
2808
2824
  const key = backtest ? `backtest` : `live`;
2809
2825
  const isInitial = !this.getNotificationStorage.has(key);
2810
2826
  const instance = this.getNotificationStorage(backtest);
@@ -2819,7 +2835,7 @@ class PersistNotificationUtils {
2819
2835
  * @param Ctor - Custom IPersistNotificationInstance constructor
2820
2836
  */
2821
2837
  usePersistNotificationAdapter(Ctor) {
2822
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
2838
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
2823
2839
  this.PersistNotificationInstanceCtor = Ctor;
2824
2840
  this.getNotificationStorage.clear();
2825
2841
  }
@@ -2829,21 +2845,21 @@ class PersistNotificationUtils {
2829
2845
  * instances are created with the updated base path.
2830
2846
  */
2831
2847
  clear() {
2832
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
2848
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
2833
2849
  this.getNotificationStorage.clear();
2834
2850
  }
2835
2851
  /**
2836
2852
  * Switches to the default file-based PersistNotificationInstance.
2837
2853
  */
2838
2854
  useJson() {
2839
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
2855
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
2840
2856
  this.usePersistNotificationAdapter(PersistNotificationInstance);
2841
2857
  }
2842
2858
  /**
2843
2859
  * Switches to PersistNotificationDummyInstance (all operations are no-ops).
2844
2860
  */
2845
2861
  useDummy() {
2846
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
2862
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
2847
2863
  this.usePersistNotificationAdapter(PersistNotificationDummyInstance);
2848
2864
  }
2849
2865
  }
@@ -2967,7 +2983,7 @@ class PersistLogUtils {
2967
2983
  * @returns Promise resolving to array of log entries
2968
2984
  */
2969
2985
  this.readLogData = async () => {
2970
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
2986
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
2971
2987
  const isInitial = !this._logInstance;
2972
2988
  const instance = this.getLogInstance();
2973
2989
  await instance.waitForInit(isInitial);
@@ -2981,7 +2997,7 @@ class PersistLogUtils {
2981
2997
  * @returns Promise that resolves when write is complete
2982
2998
  */
2983
2999
  this.writeLogData = async (logData) => {
2984
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
3000
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
2985
3001
  const isInitial = !this._logInstance;
2986
3002
  const instance = this.getLogInstance();
2987
3003
  await instance.waitForInit(isInitial);
@@ -3006,7 +3022,7 @@ class PersistLogUtils {
3006
3022
  * @param Ctor - Custom IPersistLogInstance constructor
3007
3023
  */
3008
3024
  usePersistLogAdapter(Ctor) {
3009
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
3025
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
3010
3026
  this.PersistLogInstanceCtor = Ctor;
3011
3027
  this._logInstance = null;
3012
3028
  }
@@ -3015,21 +3031,21 @@ class PersistLogUtils {
3015
3031
  * Call when process.cwd() changes between strategy iterations.
3016
3032
  */
3017
3033
  clear() {
3018
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
3034
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
3019
3035
  this._logInstance = null;
3020
3036
  }
3021
3037
  /**
3022
3038
  * Switches to the default file-based PersistLogInstance.
3023
3039
  */
3024
3040
  useJson() {
3025
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
3041
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
3026
3042
  this.usePersistLogAdapter(PersistLogInstance);
3027
3043
  }
3028
3044
  /**
3029
3045
  * Switches to PersistLogDummyInstance (all operations are no-ops).
3030
3046
  */
3031
3047
  useDummy() {
3032
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
3048
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
3033
3049
  this.usePersistLogAdapter(PersistLogDummyInstance);
3034
3050
  }
3035
3051
  }
@@ -3191,7 +3207,7 @@ class PersistMeasureUtils {
3191
3207
  * @returns Promise resolving to cached value, or null if not found / soft-deleted
3192
3208
  */
3193
3209
  this.readMeasureData = async (bucket, key) => {
3194
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3210
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3195
3211
  const isInitial = !this.getMeasureStorage.has(bucket);
3196
3212
  const instance = this.getMeasureStorage(bucket);
3197
3213
  await instance.waitForInit(isInitial);
@@ -3207,7 +3223,7 @@ class PersistMeasureUtils {
3207
3223
  * @returns Promise that resolves when write is complete
3208
3224
  */
3209
3225
  this.writeMeasureData = async (data, bucket, key, when) => {
3210
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3226
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3211
3227
  const isInitial = !this.getMeasureStorage.has(bucket);
3212
3228
  const instance = this.getMeasureStorage(bucket);
3213
3229
  await instance.waitForInit(isInitial);
@@ -3222,7 +3238,7 @@ class PersistMeasureUtils {
3222
3238
  * @returns Promise that resolves when removal is complete
3223
3239
  */
3224
3240
  this.removeMeasureData = async (bucket, key) => {
3225
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3241
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3226
3242
  const isInitial = !this.getMeasureStorage.has(bucket);
3227
3243
  const instance = this.getMeasureStorage(bucket);
3228
3244
  await instance.waitForInit(isInitial);
@@ -3236,7 +3252,7 @@ class PersistMeasureUtils {
3236
3252
  * @param Ctor - Custom IPersistMeasureInstance constructor
3237
3253
  */
3238
3254
  usePersistMeasureAdapter(Ctor) {
3239
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
3255
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
3240
3256
  this.PersistMeasureInstanceCtor = Ctor;
3241
3257
  this.getMeasureStorage.clear();
3242
3258
  }
@@ -3248,7 +3264,7 @@ class PersistMeasureUtils {
3248
3264
  * @returns AsyncGenerator yielding entry keys
3249
3265
  */
3250
3266
  async *listMeasureData(bucket) {
3251
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3267
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3252
3268
  const isInitial = !this.getMeasureStorage.has(bucket);
3253
3269
  const instance = this.getMeasureStorage(bucket);
3254
3270
  await instance.waitForInit(isInitial);
@@ -3259,21 +3275,21 @@ class PersistMeasureUtils {
3259
3275
  * Call when process.cwd() changes between strategy iterations.
3260
3276
  */
3261
3277
  clear() {
3262
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
3278
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
3263
3279
  this.getMeasureStorage.clear();
3264
3280
  }
3265
3281
  /**
3266
3282
  * Switches to the default file-based PersistMeasureInstance.
3267
3283
  */
3268
3284
  useJson() {
3269
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
3285
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
3270
3286
  this.usePersistMeasureAdapter(PersistMeasureInstance);
3271
3287
  }
3272
3288
  /**
3273
3289
  * Switches to PersistMeasureDummyInstance (all operations are no-ops).
3274
3290
  */
3275
3291
  useDummy() {
3276
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
3292
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
3277
3293
  this.usePersistMeasureAdapter(PersistMeasureDummyInstance);
3278
3294
  }
3279
3295
  }
@@ -3432,7 +3448,7 @@ class PersistIntervalUtils {
3432
3448
  * @returns Promise resolving to marker data, or null if not found / soft-deleted
3433
3449
  */
3434
3450
  this.readIntervalData = async (bucket, key) => {
3435
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3451
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3436
3452
  const isInitial = !this.getIntervalStorage.has(bucket);
3437
3453
  const instance = this.getIntervalStorage(bucket);
3438
3454
  await instance.waitForInit(isInitial);
@@ -3448,7 +3464,7 @@ class PersistIntervalUtils {
3448
3464
  * @returns Promise that resolves when write is complete
3449
3465
  */
3450
3466
  this.writeIntervalData = async (data, bucket, key, when) => {
3451
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3467
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3452
3468
  const isInitial = !this.getIntervalStorage.has(bucket);
3453
3469
  const instance = this.getIntervalStorage(bucket);
3454
3470
  await instance.waitForInit(isInitial);
@@ -3463,7 +3479,7 @@ class PersistIntervalUtils {
3463
3479
  * @returns Promise that resolves when removal is complete
3464
3480
  */
3465
3481
  this.removeIntervalData = async (bucket, key) => {
3466
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3482
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3467
3483
  const isInitial = !this.getIntervalStorage.has(bucket);
3468
3484
  const instance = this.getIntervalStorage(bucket);
3469
3485
  await instance.waitForInit(isInitial);
@@ -3477,7 +3493,7 @@ class PersistIntervalUtils {
3477
3493
  * @param Ctor - Custom IPersistIntervalInstance constructor
3478
3494
  */
3479
3495
  usePersistIntervalAdapter(Ctor) {
3480
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
3496
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
3481
3497
  this.PersistIntervalInstanceCtor = Ctor;
3482
3498
  this.getIntervalStorage.clear();
3483
3499
  }
@@ -3489,7 +3505,7 @@ class PersistIntervalUtils {
3489
3505
  * @returns AsyncGenerator yielding marker keys
3490
3506
  */
3491
3507
  async *listIntervalData(bucket) {
3492
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3508
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3493
3509
  const isInitial = !this.getIntervalStorage.has(bucket);
3494
3510
  const instance = this.getIntervalStorage(bucket);
3495
3511
  await instance.waitForInit(isInitial);
@@ -3500,21 +3516,21 @@ class PersistIntervalUtils {
3500
3516
  * Call when process.cwd() changes between strategy iterations.
3501
3517
  */
3502
3518
  clear() {
3503
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
3519
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
3504
3520
  this.getIntervalStorage.clear();
3505
3521
  }
3506
3522
  /**
3507
3523
  * Switches to the default file-based PersistIntervalInstance.
3508
3524
  */
3509
3525
  useJson() {
3510
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
3526
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
3511
3527
  this.usePersistIntervalAdapter(PersistIntervalInstance);
3512
3528
  }
3513
3529
  /**
3514
3530
  * Switches to PersistIntervalDummyInstance (all operations are no-ops).
3515
3531
  */
3516
3532
  useDummy() {
3517
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
3533
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
3518
3534
  this.usePersistIntervalAdapter(PersistIntervalDummyInstance);
3519
3535
  }
3520
3536
  }
@@ -3720,7 +3736,7 @@ class PersistMemoryUtils {
3720
3736
  * @returns Promise resolving to entry data, or null if not found / soft-deleted
3721
3737
  */
3722
3738
  this.readMemoryData = async (signalId, bucketName, memoryId) => {
3723
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
3739
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
3724
3740
  const key = `${signalId}:${bucketName}`;
3725
3741
  const isInitial = !this.getMemoryStorage.has(key);
3726
3742
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3737,7 +3753,7 @@ class PersistMemoryUtils {
3737
3753
  * @returns Promise resolving to true if entry exists
3738
3754
  */
3739
3755
  this.hasMemoryData = async (signalId, bucketName, memoryId) => {
3740
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
3756
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
3741
3757
  const key = `${signalId}:${bucketName}`;
3742
3758
  const isInitial = !this.getMemoryStorage.has(key);
3743
3759
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3756,7 +3772,7 @@ class PersistMemoryUtils {
3756
3772
  * @returns Promise that resolves when write is complete
3757
3773
  */
3758
3774
  this.writeMemoryData = async (data, signalId, bucketName, memoryId, when) => {
3759
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
3775
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
3760
3776
  const key = `${signalId}:${bucketName}`;
3761
3777
  const isInitial = !this.getMemoryStorage.has(key);
3762
3778
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3773,7 +3789,7 @@ class PersistMemoryUtils {
3773
3789
  * @returns Promise that resolves when removal is complete
3774
3790
  */
3775
3791
  this.removeMemoryData = async (signalId, bucketName, memoryId) => {
3776
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
3792
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
3777
3793
  const key = `${signalId}:${bucketName}`;
3778
3794
  const isInitial = !this.getMemoryStorage.has(key);
3779
3795
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3785,7 +3801,7 @@ class PersistMemoryUtils {
3785
3801
  * Call when process.cwd() changes between strategy iterations.
3786
3802
  */
3787
3803
  this.clear = () => {
3788
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
3804
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
3789
3805
  this.getMemoryStorage.clear();
3790
3806
  };
3791
3807
  /**
@@ -3796,7 +3812,7 @@ class PersistMemoryUtils {
3796
3812
  * @param bucketName - Bucket name
3797
3813
  */
3798
3814
  this.dispose = (signalId, bucketName) => {
3799
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
3815
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
3800
3816
  const key = `${signalId}:${bucketName}`;
3801
3817
  this.getMemoryStorage.clear(key);
3802
3818
  };
@@ -3808,7 +3824,7 @@ class PersistMemoryUtils {
3808
3824
  * @param Ctor - Custom IPersistMemoryInstance constructor
3809
3825
  */
3810
3826
  usePersistMemoryAdapter(Ctor) {
3811
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
3827
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
3812
3828
  this.PersistMemoryInstanceCtor = Ctor;
3813
3829
  this.getMemoryStorage.clear();
3814
3830
  }
@@ -3822,7 +3838,7 @@ class PersistMemoryUtils {
3822
3838
  * @returns AsyncGenerator yielding `{ memoryId, data }` tuples
3823
3839
  */
3824
3840
  async *listMemoryData(signalId, bucketName) {
3825
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
3841
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
3826
3842
  const key = `${signalId}:${bucketName}`;
3827
3843
  const isInitial = !this.getMemoryStorage.has(key);
3828
3844
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3833,14 +3849,14 @@ class PersistMemoryUtils {
3833
3849
  * Switches to the default file-based PersistMemoryInstance.
3834
3850
  */
3835
3851
  useJson() {
3836
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
3852
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
3837
3853
  this.usePersistMemoryAdapter(PersistMemoryInstance);
3838
3854
  }
3839
3855
  /**
3840
3856
  * Switches to PersistMemoryDummyInstance (all operations are no-ops).
3841
3857
  */
3842
3858
  useDummy() {
3843
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
3859
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
3844
3860
  this.usePersistMemoryAdapter(PersistMemoryDummyInstance);
3845
3861
  }
3846
3862
  }
@@ -3989,7 +4005,7 @@ class PersistRecentUtils {
3989
4005
  * @returns Promise resolving to recent signal or null if none persisted
3990
4006
  */
3991
4007
  this.readRecentData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
3992
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
4008
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
3993
4009
  const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
3994
4010
  const isInitial = !this.getStorage.has(key);
3995
4011
  const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
@@ -4010,7 +4026,7 @@ class PersistRecentUtils {
4010
4026
  * @returns Promise that resolves when write is complete
4011
4027
  */
4012
4028
  this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest, when) => {
4013
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
4029
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
4014
4030
  const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
4015
4031
  const isInitial = !this.getStorage.has(key);
4016
4032
  const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
@@ -4043,7 +4059,7 @@ class PersistRecentUtils {
4043
4059
  * @param Ctor - Custom IPersistRecentInstance constructor
4044
4060
  */
4045
4061
  usePersistRecentAdapter(Ctor) {
4046
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
4062
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
4047
4063
  this.PersistRecentInstanceCtor = Ctor;
4048
4064
  this.getStorage.clear();
4049
4065
  }
@@ -4052,21 +4068,21 @@ class PersistRecentUtils {
4052
4068
  * Call when process.cwd() changes between strategy iterations.
4053
4069
  */
4054
4070
  clear() {
4055
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
4071
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
4056
4072
  this.getStorage.clear();
4057
4073
  }
4058
4074
  /**
4059
4075
  * Switches to the default file-based PersistRecentInstance.
4060
4076
  */
4061
4077
  useJson() {
4062
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
4078
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
4063
4079
  this.usePersistRecentAdapter(PersistRecentInstance);
4064
4080
  }
4065
4081
  /**
4066
4082
  * Switches to PersistRecentDummyInstance (all operations are no-ops).
4067
4083
  */
4068
4084
  useDummy() {
4069
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
4085
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
4070
4086
  this.usePersistRecentAdapter(PersistRecentDummyInstance);
4071
4087
  }
4072
4088
  }
@@ -4201,7 +4217,7 @@ class PersistStateUtils {
4201
4217
  * @returns Promise that resolves when initialization is complete
4202
4218
  */
4203
4219
  this.waitForInit = async (signalId, bucketName, initial) => {
4204
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
4220
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
4205
4221
  const key = `${signalId}:${bucketName}`;
4206
4222
  const isInitial = initial && !this.getStateStorage.has(key);
4207
4223
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4216,7 +4232,7 @@ class PersistStateUtils {
4216
4232
  * @returns Promise resolving to state data or null if none persisted
4217
4233
  */
4218
4234
  this.readStateData = async (signalId, bucketName) => {
4219
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
4235
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
4220
4236
  const key = `${signalId}:${bucketName}`;
4221
4237
  const isInitial = !this.getStateStorage.has(key);
4222
4238
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4234,7 +4250,7 @@ class PersistStateUtils {
4234
4250
  * @returns Promise that resolves when write is complete
4235
4251
  */
4236
4252
  this.writeStateData = async (data, signalId, bucketName, when) => {
4237
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
4253
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
4238
4254
  const key = `${signalId}:${bucketName}`;
4239
4255
  const isInitial = !this.getStateStorage.has(key);
4240
4256
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4245,14 +4261,14 @@ class PersistStateUtils {
4245
4261
  * Switches to PersistStateDummyInstance (all operations are no-ops).
4246
4262
  */
4247
4263
  this.useDummy = () => {
4248
- LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
4264
+ LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
4249
4265
  this.usePersistStateAdapter(PersistStateDummyInstance);
4250
4266
  };
4251
4267
  /**
4252
4268
  * Switches to the default file-based PersistStateInstance.
4253
4269
  */
4254
4270
  this.useJson = () => {
4255
- LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
4271
+ LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
4256
4272
  this.usePersistStateAdapter(PersistStateInstance);
4257
4273
  };
4258
4274
  /**
@@ -4260,7 +4276,7 @@ class PersistStateUtils {
4260
4276
  * Call when process.cwd() changes between strategy iterations.
4261
4277
  */
4262
4278
  this.clear = () => {
4263
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
4279
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
4264
4280
  this.getStateStorage.clear();
4265
4281
  };
4266
4282
  /**
@@ -4271,7 +4287,7 @@ class PersistStateUtils {
4271
4287
  * @param bucketName - Bucket name
4272
4288
  */
4273
4289
  this.dispose = (signalId, bucketName) => {
4274
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
4290
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
4275
4291
  const key = `${signalId}:${bucketName}`;
4276
4292
  this.getStateStorage.clear(key);
4277
4293
  };
@@ -4283,7 +4299,7 @@ class PersistStateUtils {
4283
4299
  * @param Ctor - Custom IPersistStateInstance constructor
4284
4300
  */
4285
4301
  usePersistStateAdapter(Ctor) {
4286
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
4302
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
4287
4303
  this.PersistStateInstanceCtor = Ctor;
4288
4304
  this.getStateStorage.clear();
4289
4305
  }
@@ -4423,7 +4439,7 @@ class PersistSessionUtils {
4423
4439
  * @returns Promise that resolves when initialization is complete
4424
4440
  */
4425
4441
  this.waitForInit = async (strategyName, exchangeName, frameName, initial) => {
4426
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
4442
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
4427
4443
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4428
4444
  const isInitial = initial && !this.getSessionStorage.has(key);
4429
4445
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4439,7 +4455,7 @@ class PersistSessionUtils {
4439
4455
  * @returns Promise resolving to session data or null if none persisted
4440
4456
  */
4441
4457
  this.readSessionData = async (strategyName, exchangeName, frameName) => {
4442
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
4458
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
4443
4459
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4444
4460
  const isInitial = !this.getSessionStorage.has(key);
4445
4461
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4458,7 +4474,7 @@ class PersistSessionUtils {
4458
4474
  * @returns Promise that resolves when write is complete
4459
4475
  */
4460
4476
  this.writeSessionData = async (data, strategyName, exchangeName, frameName, when) => {
4461
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
4477
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
4462
4478
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4463
4479
  const isInitial = !this.getSessionStorage.has(key);
4464
4480
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4469,14 +4485,14 @@ class PersistSessionUtils {
4469
4485
  * Switches to PersistSessionDummyInstance (all operations are no-ops).
4470
4486
  */
4471
4487
  this.useDummy = () => {
4472
- LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
4488
+ LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
4473
4489
  this.usePersistSessionAdapter(PersistSessionDummyInstance);
4474
4490
  };
4475
4491
  /**
4476
4492
  * Switches to the default file-based PersistSessionInstance.
4477
4493
  */
4478
4494
  this.useJson = () => {
4479
- LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
4495
+ LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
4480
4496
  this.usePersistSessionAdapter(PersistSessionInstance);
4481
4497
  };
4482
4498
  /**
@@ -4484,7 +4500,7 @@ class PersistSessionUtils {
4484
4500
  * Call when process.cwd() changes between strategy iterations.
4485
4501
  */
4486
4502
  this.clear = () => {
4487
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
4503
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
4488
4504
  this.getSessionStorage.clear();
4489
4505
  };
4490
4506
  /**
@@ -4496,7 +4512,7 @@ class PersistSessionUtils {
4496
4512
  * @param frameName - Frame identifier
4497
4513
  */
4498
4514
  this.dispose = (strategyName, exchangeName, frameName) => {
4499
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
4515
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
4500
4516
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4501
4517
  this.getSessionStorage.clear(key);
4502
4518
  };
@@ -4508,7 +4524,7 @@ class PersistSessionUtils {
4508
4524
  * @param Ctor - Custom IPersistSessionInstance constructor
4509
4525
  */
4510
4526
  usePersistSessionAdapter(Ctor) {
4511
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
4527
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
4512
4528
  this.PersistSessionInstanceCtor = Ctor;
4513
4529
  this.getSessionStorage.clear();
4514
4530
  }
@@ -4520,28 +4536,39 @@ class PersistSessionUtils {
4520
4536
  const PersistSessionAdapter = new PersistSessionUtils();
4521
4537
 
4522
4538
  var _a$2, _b$2;
4523
- const BUSY_DELAY = 100;
4524
4539
  const SET_BUSY_SYMBOL = Symbol("setBusy");
4525
4540
  const GET_BUSY_SYMBOL = Symbol("getBusy");
4526
4541
  const ACQUIRE_LOCK_SYMBOL = Symbol("acquireLock");
4527
4542
  const RELEASE_LOCK_SYMBOL = Symbol("releaseLock");
4543
+ /**
4544
+ * Body of the queued acquire operation.
4545
+ *
4546
+ * Parks the caller on `self._tick` whenever the lock is already busy: each
4547
+ * `releaseLock` emits on `_tick`, waking exactly the next queued acquirer
4548
+ * instead of polling on a fixed delay. The busy counter is bumped only after
4549
+ * the loop exits, so re-entry checks remain coherent under contention.
4550
+ *
4551
+ * @param self - The owning {@link Lock} instance.
4552
+ */
4528
4553
  const ACQUIRE_LOCK_FN = async (self) => {
4529
4554
  while (self[GET_BUSY_SYMBOL]()) {
4530
- await functoolsKit.sleep(BUSY_DELAY);
4555
+ // @ts-ignore
4556
+ await self._tick.toPromise();
4531
4557
  }
4532
4558
  self[SET_BUSY_SYMBOL](true);
4533
4559
  };
4534
4560
  /**
4535
4561
  * Mutual exclusion primitive for async TypeScript code.
4536
4562
  *
4537
- * Provides a reentrant-safe, queued lock that serializes access to a critical
4538
- * section across concurrent async callers. Internally tracks a busy counter so
4539
- * nested acquire/release pairs are detected and mis-matched releases throw
4540
- * immediately.
4563
+ * Provides a queued lock that serializes access to a critical section across
4564
+ * concurrent async callers. Wake-ups are event-driven (via an internal
4565
+ * `_tick` subject emitted on every `releaseLock`) rather than polling,
4566
+ * so contention does not incur a fixed delay.
4541
4567
  *
4542
- * Three usage styles are supported:
4568
+ * The busy counter detects mis-matched releases and throws immediately on
4569
+ * extra `releaseLock` calls.
4543
4570
  *
4544
- * **Manual acquire / release**
4571
+ * **Usage**
4545
4572
  * ```ts
4546
4573
  * await lock.acquireLock();
4547
4574
  * try {
@@ -4556,7 +4583,18 @@ const ACQUIRE_LOCK_FN = async (self) => {
4556
4583
  */
4557
4584
  class Lock {
4558
4585
  constructor() {
4586
+ /**
4587
+ * Outstanding acquires that have not yet been released.
4588
+ * Incremented in `[SET_BUSY_SYMBOL](true)`, decremented in `[SET_BUSY_SYMBOL](false)`.
4589
+ * A negative value indicates an extra `releaseLock` and throws on detection.
4590
+ */
4559
4591
  this._isBusy = 0;
4592
+ /**
4593
+ * Wake-up channel for {@link ACQUIRE_LOCK_FN}.
4594
+ * Every {@link releaseLock} emits a single tick that unblocks the next
4595
+ * queued acquirer parked on `toPromise()`.
4596
+ */
4597
+ this._tick = new functoolsKit.Subject();
4560
4598
  this[_a$2] = functoolsKit.queued(ACQUIRE_LOCK_FN);
4561
4599
  this[_b$2] = () => this[SET_BUSY_SYMBOL](false);
4562
4600
  /**
@@ -4577,16 +4615,19 @@ class Lock {
4577
4615
  await this[ACQUIRE_LOCK_SYMBOL](this);
4578
4616
  };
4579
4617
  /**
4580
- * Releases the lock previously acquired with {@link acquireLock}.
4618
+ * Releases the lock previously acquired with {@link acquireLock} and emits
4619
+ * on the internal `_tick` subject to wake the next queued acquirer.
4620
+ *
4581
4621
  * Must be called exactly once per successful {@link acquireLock} call,
4582
- * typically inside a `finally` block. Throws if called more times
4583
- * than the lock was acquired.
4622
+ * typically inside a `finally` block. Throws if called more times than
4623
+ * the lock was acquired.
4584
4624
  *
4585
4625
  * @returns {Promise<void>} Resolves once the lock has been released.
4586
4626
  * @throws {Error} If the lock is released more times than it was acquired.
4587
4627
  */
4588
4628
  this.releaseLock = async () => {
4589
4629
  await this[RELEASE_LOCK_SYMBOL]();
4630
+ await this._tick.next();
4590
4631
  };
4591
4632
  }
4592
4633
  [SET_BUSY_SYMBOL](isBusy) {
@@ -4601,18 +4642,166 @@ class Lock {
4601
4642
  }
4602
4643
  _a$2 = ACQUIRE_LOCK_SYMBOL, _b$2 = RELEASE_LOCK_SYMBOL;
4603
4644
 
4645
+ const METHOD_NAME_ADD_ACTIVITY = "LookupUtils.addActivity";
4646
+ const METHOD_NAME_REMOVE_ACTIVITY = "LookupUtils.removeActivity";
4647
+ const METHOD_NAME_LIST_ACTIVITY = "LookupUtils.listActivity";
4648
+ /** Logger service injected as DI singleton */
4649
+ const LOGGER_SERVICE$7 = new LoggerService();
4650
+ /**
4651
+ * Builds the composite {@link Key} used to register an activity in `_lookupMap`.
4652
+ *
4653
+ * Mirrors the {@link Key} type construction: appends `frameName` only when provided
4654
+ * (typical for backtest), then a `"backtest"` / `"live"` discriminator suffix.
4655
+ *
4656
+ * @param symbol - Trading pair symbol.
4657
+ * @param strategyName - Strategy schema name.
4658
+ * @param exchangeName - Exchange schema name.
4659
+ * @param frameName - Frame schema name; omitted from the key when falsy.
4660
+ * @param backtest - `true` for backtest, `false` for live.
4661
+ * @returns Colon-joined composite key.
4662
+ */
4663
+ const CREATE_KEY_FN$y = (symbol, strategyName, exchangeName, frameName, backtest) => {
4664
+ const parts = [symbol, strategyName, exchangeName];
4665
+ if (frameName)
4666
+ parts.push(frameName);
4667
+ parts.push(backtest ? "backtest" : "live");
4668
+ return parts.join(":");
4669
+ };
4670
+ /**
4671
+ * In-memory registry of currently running backtest and live activities.
4672
+ *
4673
+ * Purpose:
4674
+ * - Each `Backtest.run` / `Live.run` / per-strategy walker iteration registers an
4675
+ * {@link IActivityEntry} on start and removes it on completion.
4676
+ * - `Candle.spinLock` consults {@link isParallel} to decide whether the event-loop
4677
+ * hand-off (post-candle-fetch spin) is worth performing. With a single active
4678
+ * workload there is no peer to yield to, so the spin is skipped entirely.
4679
+ *
4680
+ * Exposed as the `Lookup` singleton; no constructor parameters.
4681
+ *
4682
+ * @example
4683
+ * ```typescript
4684
+ * Lookup.addActivity({ symbol: "BTCUSDT", context, backtest: true });
4685
+ * try {
4686
+ * for await (const _ of run(symbol, context)) { ... }
4687
+ * } finally {
4688
+ * Lookup.removeActivity({ symbol: "BTCUSDT", context, backtest: true });
4689
+ * }
4690
+ * ```
4691
+ */
4692
+ class LookupUtils {
4693
+ constructor() {
4694
+ /** Active entries keyed by their composite {@link Key}. */
4695
+ this._lookupMap = new Map();
4696
+ /**
4697
+ * Registers a backtest or live activity in the lookup map.
4698
+ * Idempotent for identical keys — duplicate calls overwrite the existing entry.
4699
+ *
4700
+ * @param activity - Activity descriptor identifying the running workload.
4701
+ */
4702
+ this.addActivity = (activity) => {
4703
+ LOGGER_SERVICE$7.info(METHOD_NAME_ADD_ACTIVITY, {
4704
+ activity,
4705
+ });
4706
+ const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
4707
+ this._lookupMap.set(key, activity);
4708
+ };
4709
+ /**
4710
+ * Removes a previously registered activity from the lookup map.
4711
+ * Must be paired with a prior {@link addActivity}, typically in a `finally` block,
4712
+ * so a thrown error in the underlying run does not leave a stale entry behind.
4713
+ *
4714
+ * @param activity - Activity descriptor matching the one passed to {@link addActivity}.
4715
+ */
4716
+ this.removeActivity = (activity) => {
4717
+ LOGGER_SERVICE$7.info(METHOD_NAME_REMOVE_ACTIVITY, {
4718
+ activity,
4719
+ });
4720
+ const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
4721
+ this._lookupMap.delete(key);
4722
+ };
4723
+ /**
4724
+ * Returns a snapshot of currently active entries.
4725
+ *
4726
+ * @returns Array of all activities present in the lookup map at call time.
4727
+ */
4728
+ this.listActivity = () => {
4729
+ LOGGER_SERVICE$7.info(METHOD_NAME_LIST_ACTIVITY);
4730
+ return Array.from(this._lookupMap.values());
4731
+ };
4732
+ }
4733
+ /**
4734
+ * `true` when more than one activity is currently registered.
4735
+ * Used by `Candle.spinLock` to decide whether yielding the event loop is useful.
4736
+ */
4737
+ get isParallel() {
4738
+ return this._lookupMap.size > 1;
4739
+ }
4740
+ }
4741
+ /**
4742
+ * Process-wide singleton instance of {@link LookupUtils}.
4743
+ * Imported by `Backtest`, `Live`, `WalkerLogicPrivateService` (registration sites)
4744
+ * and by `Candle` (read-only consumer via `isParallel`).
4745
+ */
4746
+ const Lookup = new LookupUtils();
4747
+
4604
4748
  const METHOD_NAME_ACQUIRE_LOCK = "CandleUtils.acquireLock";
4605
4749
  const METHOD_NAME_RELEASE_LOCK = "CandleUtils.releaseLock";
4750
+ const METHOD_NAME_SPIN_LOCK = "CandleUtils.spinLock";
4751
+ /**
4752
+ * Upper bound (ms) on how long `spinLock` may park before falling through.
4753
+ * If no peer backtest acquires the candle-fetch mutex within this window,
4754
+ * the spinner proceeds without further yielding.
4755
+ */
4756
+ const ROTATE_DELAY = 50;
4606
4757
  /** Logger service injected as DI singleton */
4607
4758
  const LOGGER_SERVICE$6 = new LoggerService();
4759
+ /**
4760
+ * Process-wide coordinator for candle-fetch serialization and cooperative
4761
+ * yielding between parallel backtests.
4762
+ *
4763
+ * Two complementary primitives are exposed:
4764
+ * - **Mutex** via {@link acquireLock} / {@link releaseLock}: prevents concurrent
4765
+ * candle fetches from racing on the same exchange.
4766
+ * - **Spin hand-off** via {@link spinLock}: invoked after a fetch completes to
4767
+ * give peer backtests waiting on the mutex a chance to run, so multiple
4768
+ * `Backtest.run` workloads interleave instead of one monopolizing the loop.
4769
+ *
4770
+ * All three operations are no-ops when `CC_ENABLE_CANDLE_FETCH_MUTEX` is `false`.
4771
+ * The spin additionally requires `CC_ENABLE_BACKTEST_PARALLEL_SPIN` and at least
4772
+ * two registered activities in `Lookup` (see `Lookup.isParallel`).
4773
+ *
4774
+ * @example
4775
+ * ```typescript
4776
+ * await Candle.acquireLock("ClientExchange GET_CANDLES_FN");
4777
+ * try {
4778
+ * const candles = await fetchFromExchange(...);
4779
+ * return candles;
4780
+ * } finally {
4781
+ * await Candle.releaseLock("ClientExchange GET_CANDLES_FN");
4782
+ * }
4783
+ * // Elsewhere, after a fetch completes inside a backtest loop:
4784
+ * await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
4785
+ * ```
4786
+ */
4608
4787
  class CandleUtils {
4609
4788
  constructor() {
4789
+ /** Underlying mutex serializing candle fetches across concurrent callers. */
4610
4790
  this._lock = new Lock();
4611
4791
  /**
4612
- * Acquires the candle fetch mutex if CC_ENABLE_CANDLE_FETCH_MUTEX is enabled.
4792
+ * Emits whenever {@link acquireLock} successfully takes the mutex.
4793
+ * Awaited by {@link spinLock} to detect that a peer backtest has just
4794
+ * started its own fetch — the signal that yielding now will be productive.
4795
+ */
4796
+ this._spin = new functoolsKit.Subject();
4797
+ /**
4798
+ * Acquires the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
4613
4799
  * Prevents concurrent candle fetches from the same exchange.
4614
4800
  *
4615
- * @param source - Caller identifier for logging
4801
+ * On successful acquisition, emits on the internal spin subject so any
4802
+ * peer parked inside {@link spinLock} can wake up and proceed.
4803
+ *
4804
+ * @param source - Caller identifier for logging.
4616
4805
  */
4617
4806
  this.acquireLock = async (source) => {
4618
4807
  LOGGER_SERVICE$6.info(METHOD_NAME_ACQUIRE_LOCK, {
@@ -4621,13 +4810,14 @@ class CandleUtils {
4621
4810
  if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
4622
4811
  return;
4623
4812
  }
4624
- return await this._lock.acquireLock();
4813
+ await this._lock.acquireLock();
4814
+ await this._spin.next();
4625
4815
  };
4626
4816
  /**
4627
- * Releases the candle fetch mutex if CC_ENABLE_CANDLE_FETCH_MUTEX is enabled.
4628
- * Must be called after acquireLock, typically in a finally block.
4817
+ * Releases the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
4818
+ * Must be called after {@link acquireLock}, typically in a `finally` block.
4629
4819
  *
4630
- * @param source - Caller identifier for logging
4820
+ * @param source - Caller identifier for logging.
4631
4821
  */
4632
4822
  this.releaseLock = async (source) => {
4633
4823
  LOGGER_SERVICE$6.info(METHOD_NAME_RELEASE_LOCK, {
@@ -4638,8 +4828,47 @@ class CandleUtils {
4638
4828
  }
4639
4829
  return await this._lock.releaseLock();
4640
4830
  };
4831
+ /**
4832
+ * Cooperative event-loop hand-off invoked by `BacktestLogicPrivateService`
4833
+ * after a successful `getNextCandles`. Allows peer backtests waiting on the
4834
+ * candle-fetch mutex to run before the current backtest fetches the next chunk.
4835
+ *
4836
+ * Waits for one of:
4837
+ * - a peer calling {@link acquireLock} (signalled via the spin subject), or
4838
+ * - a `ROTATE_DELAY` ms timeout, so the caller never parks indefinitely.
4839
+ *
4840
+ * Returns immediately as a no-op when any of these is true:
4841
+ * - `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled (mutex is off entirely),
4842
+ * - `CC_ENABLE_BACKTEST_PARALLEL_SPIN` is disabled (cooperative yielding off),
4843
+ * - `Lookup.isParallel` is `false` (only one active workload — no peer to yield to).
4844
+ *
4845
+ * @param source - Caller identifier for logging.
4846
+ */
4847
+ this.spinLock = async (source) => {
4848
+ LOGGER_SERVICE$6.info(METHOD_NAME_SPIN_LOCK, {
4849
+ source,
4850
+ });
4851
+ if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
4852
+ return;
4853
+ }
4854
+ if (!GLOBAL_CONFIG.CC_ENABLE_BACKTEST_PARALLEL_SPIN) {
4855
+ return;
4856
+ }
4857
+ if (!Lookup.isParallel) {
4858
+ return;
4859
+ }
4860
+ await Promise.race([
4861
+ this._spin.toPromise(),
4862
+ functoolsKit.sleep(ROTATE_DELAY),
4863
+ ]);
4864
+ };
4641
4865
  }
4642
4866
  }
4867
+ /**
4868
+ * Process-wide singleton instance of {@link CandleUtils}.
4869
+ * Imported by `ClientExchange` (mutex around exchange fetches) and by
4870
+ * `BacktestLogicPrivateService` (spin hand-off between parallel backtests).
4871
+ */
4643
4872
  const Candle = new CandleUtils();
4644
4873
 
4645
4874
  const MS_PER_MINUTE$7 = 60000;
@@ -19173,9 +19402,28 @@ const TICK_FN = async (self, symbol, when) => {
19173
19402
  return { type: "error", __error__: SYMBOL_FN_ERROR, reason: "TICK_FN", message: functoolsKit.getErrorMessage(error) };
19174
19403
  }
19175
19404
  };
19405
+ /**
19406
+ * Wraps `exchangeCoreService.getNextCandles` with error capture and a cooperative
19407
+ * event-loop hand-off after a successful fetch.
19408
+ *
19409
+ * Calls `Candle.spinLock(...)` on success: when multiple backtests run in parallel
19410
+ * (`Lookup.isParallel === true`), this yields the event loop so a peer waiting on
19411
+ * the candle-fetch mutex can take its turn, producing round-robin interleaving
19412
+ * instead of one backtest monopolizing the loop until completion. The spin is a
19413
+ * no-op for single-workload runs.
19414
+ *
19415
+ * @param self - Owning service instance, used for logging and exchange access.
19416
+ * @param symbol - Trading pair symbol.
19417
+ * @param candlesNeeded - Number of 1m candles to request.
19418
+ * @param bufferStartTime - Inclusive start time for the fetch window.
19419
+ * @param logMeta - Extra structured fields appended to the warn log on failure.
19420
+ * @returns Fetched candles, or a {@link TFnError} discriminated union on failure.
19421
+ */
19176
19422
  const GET_CANDLES_FN = async (self, symbol, candlesNeeded, bufferStartTime, logMeta) => {
19177
19423
  try {
19178
- return await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
19424
+ const result = await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
19425
+ await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
19426
+ return result;
19179
19427
  }
19180
19428
  catch (error) {
19181
19429
  console.error(`backtestLogicPrivateService getNextCandles failed symbol=${symbol} strategyName=${self.methodContextService.context.strategyName} exchangeName=${self.methodContextService.context.exchangeName}`);
@@ -20061,6 +20309,15 @@ class WalkerLogicPrivateService {
20061
20309
  exchangeName: context.exchangeName,
20062
20310
  frameName: context.frameName,
20063
20311
  });
20312
+ Lookup.addActivity({
20313
+ symbol,
20314
+ context: {
20315
+ strategyName,
20316
+ exchangeName: context.exchangeName,
20317
+ frameName: context.frameName,
20318
+ },
20319
+ backtest: true,
20320
+ });
20064
20321
  try {
20065
20322
  await functoolsKit.resolveDocuments(iterator);
20066
20323
  }
@@ -20076,6 +20333,17 @@ class WalkerLogicPrivateService {
20076
20333
  await CALL_STRATEGY_ERROR_CALLBACKS_FN(this, walkerSchema, strategyName, symbol, error);
20077
20334
  continue;
20078
20335
  }
20336
+ finally {
20337
+ Lookup.removeActivity({
20338
+ symbol,
20339
+ context: {
20340
+ strategyName,
20341
+ exchangeName: context.exchangeName,
20342
+ frameName: context.frameName,
20343
+ },
20344
+ backtest: true,
20345
+ });
20346
+ }
20079
20347
  this.loggerService.info("walkerLogicPrivateService backtest complete", {
20080
20348
  strategyName,
20081
20349
  symbol,
@@ -36095,6 +36363,7 @@ const Exchange = new ExchangeUtils();
36095
36363
 
36096
36364
  const WARM_CANDLES_METHOD_NAME = "cache.warmCandles";
36097
36365
  const CHECK_CANDLES_METHOD_NAME = "cache.checkCandles";
36366
+ const CACHE_CANDLES_METHOD_NAME = "cache.cacheCandles";
36098
36367
  const MS_PER_MINUTE$3 = 60000;
36099
36368
  const INTERVAL_MINUTES$3 = {
36100
36369
  "1m": 1,
@@ -36126,6 +36395,34 @@ const PRINT_PROGRESS_FN = (fetched, total, symbol, interval) => {
36126
36395
  process.stdout.write("\n");
36127
36396
  }
36128
36397
  };
36398
+ /**
36399
+ * Retry-wrapped pipeline: validates the cache via `checkCandles` and, on miss,
36400
+ * fills it via `warmCandles` and rethrows to trigger a retry pass that
36401
+ * re-validates the freshly cached range. Limited to 2 attempts.
36402
+ */
36403
+ const CACHE_CANDLES_FN = functoolsKit.retry(async (interval, dto, onWarmStart, onCheckStart) => {
36404
+ try {
36405
+ onWarmStart && onWarmStart(dto.symbol, interval, dto.from, dto.to);
36406
+ await checkCandles({
36407
+ exchangeName: dto.exchangeName,
36408
+ from: dto.from,
36409
+ to: dto.to,
36410
+ symbol: dto.symbol,
36411
+ interval: interval,
36412
+ });
36413
+ }
36414
+ catch (error) {
36415
+ onCheckStart && onCheckStart(dto.symbol, interval, dto.from, dto.to);
36416
+ await warmCandles({
36417
+ symbol: dto.symbol,
36418
+ exchangeName: dto.exchangeName,
36419
+ from: dto.from,
36420
+ to: dto.to,
36421
+ interval: interval,
36422
+ });
36423
+ throw error;
36424
+ }
36425
+ }, 2);
36129
36426
  /**
36130
36427
  * Checks cached candle presence via the persist adapter.
36131
36428
  * Issues one ranged read; adapter-side `hasValue` covers each expected timestamp,
@@ -36201,6 +36498,34 @@ async function warmCandles(params) {
36201
36498
  PRINT_PROGRESS_FN(fetched, totalCandles, symbol, interval);
36202
36499
  }
36203
36500
  }
36501
+ /**
36502
+ * Ensures candles for the given range are present in persist storage.
36503
+ * Runs a check-then-warm pipeline with one retry: validates the cache first
36504
+ * and, on a miss, downloads the missing data and re-validates.
36505
+ *
36506
+ * @param params - Combined cache parameters with optional lifecycle callbacks
36507
+ */
36508
+ async function cacheCandles({ symbol, interval, from, to, exchangeName, onCheckStart = (symbol, interval, from, to) => {
36509
+ process.stdout.write("\n");
36510
+ process.stdout.write(`Checking candles cache for ${symbol} ${interval} from ${from} to ${to}\n`);
36511
+ }, onWarmStart = (symbol, interval, from, to) => {
36512
+ process.stdout.write("\n\n");
36513
+ process.stdout.write(`Caching candles for ${symbol} ${interval} from ${from} to ${to}\n`);
36514
+ }, }) {
36515
+ backtest.loggerService.info(CACHE_CANDLES_METHOD_NAME, {
36516
+ symbol,
36517
+ exchangeName,
36518
+ interval,
36519
+ from,
36520
+ to,
36521
+ });
36522
+ await CACHE_CANDLES_FN(interval, {
36523
+ exchangeName,
36524
+ from,
36525
+ to,
36526
+ symbol,
36527
+ }, onWarmStart, onCheckStart);
36528
+ }
36204
36529
 
36205
36530
  const METHOD_NAME = "validate.validate";
36206
36531
  /**
@@ -37412,7 +37737,19 @@ class BrokerProxy {
37412
37737
  */
37413
37738
  class BrokerAdapter {
37414
37739
  constructor() {
37415
- this._brokerInstance = null;
37740
+ /** Factory producing the active `BrokerProxy` instance */
37741
+ this._brokerFactory = () => null;
37742
+ /**
37743
+ * Lazily constructs the `BrokerProxy` from the registered factory and
37744
+ * memoizes the result via `singleshot`.
37745
+ *
37746
+ * The proxy is built on the first call and cached for all subsequent calls.
37747
+ * Returns `null` when no adapter has been registered via `useBrokerAdapter()`.
37748
+ *
37749
+ * Reset via `clear()` so the next call rebuilds from the current factory
37750
+ * (e.g. when `process.cwd()` changes between strategy iterations).
37751
+ */
37752
+ this.getInstance = functoolsKit.singleshot(() => this._brokerFactory());
37416
37753
  /**
37417
37754
  * Forwards a signal-open event to the registered broker adapter.
37418
37755
  *
@@ -37446,7 +37783,10 @@ class BrokerAdapter {
37446
37783
  if (payload.backtest) {
37447
37784
  return;
37448
37785
  }
37449
- await this._brokerInstance?.onSignalOpenCommit(payload);
37786
+ const instance = this.getInstance();
37787
+ if (instance) {
37788
+ await instance.onSignalOpenCommit(payload);
37789
+ }
37450
37790
  };
37451
37791
  /**
37452
37792
  * Forwards a signal-close event to the registered broker adapter.
@@ -37484,7 +37824,10 @@ class BrokerAdapter {
37484
37824
  if (payload.backtest) {
37485
37825
  return;
37486
37826
  }
37487
- await this._brokerInstance?.onSignalCloseCommit(payload);
37827
+ const instance = this.getInstance();
37828
+ if (instance) {
37829
+ await instance.onSignalCloseCommit(payload);
37830
+ }
37488
37831
  };
37489
37832
  /**
37490
37833
  * Intercepts a partial-profit close before DI-core mutation.
@@ -37520,7 +37863,10 @@ class BrokerAdapter {
37520
37863
  if (payload.backtest) {
37521
37864
  return;
37522
37865
  }
37523
- await this._brokerInstance?.onPartialProfitCommit(payload);
37866
+ const instance = this.getInstance();
37867
+ if (instance) {
37868
+ await instance.onPartialProfitCommit(payload);
37869
+ }
37524
37870
  };
37525
37871
  /**
37526
37872
  * Intercepts a partial-loss close before DI-core mutation.
@@ -37556,7 +37902,10 @@ class BrokerAdapter {
37556
37902
  if (payload.backtest) {
37557
37903
  return;
37558
37904
  }
37559
- await this._brokerInstance?.onPartialLossCommit(payload);
37905
+ const instance = this.getInstance();
37906
+ if (instance) {
37907
+ await instance.onPartialLossCommit(payload);
37908
+ }
37560
37909
  };
37561
37910
  /**
37562
37911
  * Intercepts a trailing stop-loss update before DI-core mutation.
@@ -37592,7 +37941,10 @@ class BrokerAdapter {
37592
37941
  if (payload.backtest) {
37593
37942
  return;
37594
37943
  }
37595
- await this._brokerInstance?.onTrailingStopCommit(payload);
37944
+ const instance = this.getInstance();
37945
+ if (instance) {
37946
+ await instance.onTrailingStopCommit(payload);
37947
+ }
37596
37948
  };
37597
37949
  /**
37598
37950
  * Intercepts a trailing take-profit update before DI-core mutation.
@@ -37628,7 +37980,10 @@ class BrokerAdapter {
37628
37980
  if (payload.backtest) {
37629
37981
  return;
37630
37982
  }
37631
- await this._brokerInstance?.onTrailingTakeCommit(payload);
37983
+ const instance = this.getInstance();
37984
+ if (instance) {
37985
+ await instance.onTrailingTakeCommit(payload);
37986
+ }
37632
37987
  };
37633
37988
  /**
37634
37989
  * Intercepts a breakeven operation before DI-core mutation.
@@ -37665,7 +38020,10 @@ class BrokerAdapter {
37665
38020
  if (payload.backtest) {
37666
38021
  return;
37667
38022
  }
37668
- await this._brokerInstance?.onBreakevenCommit(payload);
38023
+ const instance = this.getInstance();
38024
+ if (instance) {
38025
+ await instance.onBreakevenCommit(payload);
38026
+ }
37669
38027
  };
37670
38028
  /**
37671
38029
  * Intercepts a DCA average-buy entry before DI-core mutation.
@@ -37701,7 +38059,10 @@ class BrokerAdapter {
37701
38059
  if (payload.backtest) {
37702
38060
  return;
37703
38061
  }
37704
- await this._brokerInstance?.onAverageBuyCommit(payload);
38062
+ const instance = this.getInstance();
38063
+ if (instance) {
38064
+ await instance.onAverageBuyCommit(payload);
38065
+ }
37705
38066
  };
37706
38067
  /**
37707
38068
  * Registers a broker adapter instance or constructor to receive commit* callbacks.
@@ -37725,11 +38086,12 @@ class BrokerAdapter {
37725
38086
  this.useBrokerAdapter = (broker) => {
37726
38087
  backtest.loggerService.info(BROKER_METHOD_NAME_USE_BROKER_ADAPTER, {});
37727
38088
  if (typeof broker === "function") {
37728
- const instance = Reflect.construct(broker, []);
37729
- this._brokerInstance = new BrokerProxy(instance);
37730
- return;
38089
+ this._brokerFactory = () => new BrokerProxy(Reflect.construct(broker, []));
37731
38090
  }
37732
- this._brokerInstance = new BrokerProxy(broker);
38091
+ else {
38092
+ this._brokerFactory = () => new BrokerProxy(broker);
38093
+ }
38094
+ this.getInstance.clear();
37733
38095
  };
37734
38096
  /**
37735
38097
  * Activates the broker: subscribes to syncSubject for signal-open / signal-close routing.
@@ -37756,7 +38118,8 @@ class BrokerAdapter {
37756
38118
  */
37757
38119
  this.enable = functoolsKit.singleshot(() => {
37758
38120
  backtest.loggerService.info(BROKER_METHOD_NAME_ENABLE, {});
37759
- if (!this._brokerInstance) {
38121
+ const instance = this.getInstance();
38122
+ if (!instance) {
37760
38123
  this.enable.clear();
37761
38124
  throw new Error("No broker instance provided. Call Broker.useBrokerAdapter first.");
37762
38125
  }
@@ -37844,7 +38207,7 @@ class BrokerAdapter {
37844
38207
  */
37845
38208
  this.clear = () => {
37846
38209
  backtest.loggerService.info(BROKER_METHOD_NAME_CLEAR, {});
37847
- this._brokerInstance = null;
38210
+ this.getInstance.clear();
37848
38211
  this.enable.clear();
37849
38212
  };
37850
38213
  }
@@ -41948,11 +42311,21 @@ const INSTANCE_TASK_FN$2 = async (symbol, context, self) => {
41948
42311
  self._isStopped = false;
41949
42312
  self._isDone = false;
41950
42313
  }
42314
+ Lookup.addActivity({
42315
+ symbol,
42316
+ context,
42317
+ backtest: true,
42318
+ });
41951
42319
  for await (const _ of self.run(symbol, context)) {
41952
42320
  if (self._isStopped) {
41953
42321
  break;
41954
42322
  }
41955
42323
  }
42324
+ Lookup.removeActivity({
42325
+ symbol,
42326
+ context,
42327
+ backtest: true,
42328
+ });
41956
42329
  if (!self._isDone) {
41957
42330
  await doneBacktestSubject.next({
41958
42331
  exchangeName: context.exchangeName,
@@ -44599,11 +44972,21 @@ const INSTANCE_TASK_FN$1 = async (symbol, context, self) => {
44599
44972
  self._isStopped = false;
44600
44973
  self._isDone = false;
44601
44974
  }
44975
+ Lookup.addActivity({
44976
+ symbol,
44977
+ context,
44978
+ backtest: false,
44979
+ });
44602
44980
  for await (const signal of self.run(symbol, context)) {
44603
44981
  if (signal?.action === "closed" && self._isStopped) {
44604
44982
  break;
44605
44983
  }
44606
44984
  }
44985
+ Lookup.removeActivity({
44986
+ symbol,
44987
+ context,
44988
+ backtest: false,
44989
+ });
44607
44990
  if (!self._isDone) {
44608
44991
  await doneLiveSubject.next({
44609
44992
  exchangeName: context.exchangeName,
@@ -48864,8 +49247,16 @@ class RecentMemoryLiveUtils {
48864
49247
  */
48865
49248
  class RecentBacktestAdapter {
48866
49249
  constructor() {
48867
- /** Internal storage utils instance */
48868
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
49250
+ /** Factory producing the active storage utils instance */
49251
+ this._recentBacktestFactory = () => new RecentMemoryBacktestUtils();
49252
+ /**
49253
+ * Lazily constructs the storage utils from the registered factory and memoizes
49254
+ * the result via `singleshot`.
49255
+ *
49256
+ * The instance is built on the first call and cached for all subsequent calls.
49257
+ * Reset via `clear()` so the next call rebuilds from the current factory.
49258
+ */
49259
+ this.getInstance = functoolsKit.singleshot(() => this._recentBacktestFactory());
48869
49260
  /**
48870
49261
  * Handles active ping event.
48871
49262
  * Proxies call to the underlying storage adapter.
@@ -48875,7 +49266,7 @@ class RecentBacktestAdapter {
48875
49266
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
48876
49267
  signalId: event.data.id,
48877
49268
  });
48878
- return await this._recentBacktestUtils.handleActivePing(event);
49269
+ return await this.getInstance().handleActivePing(event);
48879
49270
  };
48880
49271
  /**
48881
49272
  * Retrieves the latest signal for the given context.
@@ -48896,7 +49287,7 @@ class RecentBacktestAdapter {
48896
49287
  frameName,
48897
49288
  backtest: backtest$1,
48898
49289
  });
48899
- return await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
49290
+ return await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
48900
49291
  };
48901
49292
  /**
48902
49293
  * Returns the number of whole minutes elapsed since the latest signal's creation timestamp.
@@ -48920,7 +49311,7 @@ class RecentBacktestAdapter {
48920
49311
  backtest: backtest$1,
48921
49312
  timestamp,
48922
49313
  });
48923
- const signal = await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49314
+ const signal = await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
48924
49315
  if (!signal) {
48925
49316
  return null;
48926
49317
  }
@@ -48933,7 +49324,8 @@ class RecentBacktestAdapter {
48933
49324
  */
48934
49325
  this.useRecentAdapter = (Ctor) => {
48935
49326
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
48936
- this._recentBacktestUtils = Reflect.construct(Ctor, []);
49327
+ this._recentBacktestFactory = () => Reflect.construct(Ctor, []);
49328
+ this.getInstance.clear();
48937
49329
  };
48938
49330
  /**
48939
49331
  * Switches to persistent storage adapter.
@@ -48941,7 +49333,8 @@ class RecentBacktestAdapter {
48941
49333
  */
48942
49334
  this.usePersist = () => {
48943
49335
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
48944
- this._recentBacktestUtils = new RecentPersistBacktestUtils();
49336
+ this._recentBacktestFactory = () => new RecentPersistBacktestUtils();
49337
+ this.getInstance.clear();
48945
49338
  };
48946
49339
  /**
48947
49340
  * Switches to in-memory storage adapter (default).
@@ -48949,14 +49342,17 @@ class RecentBacktestAdapter {
48949
49342
  */
48950
49343
  this.useMemory = () => {
48951
49344
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
48952
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
49345
+ this._recentBacktestFactory = () => new RecentMemoryBacktestUtils();
49346
+ this.getInstance.clear();
48953
49347
  };
48954
49348
  /**
48955
- * Clears the cached utils instance by resetting to the default in-memory adapter.
49349
+ * Clears the memoized utils instance.
49350
+ * Call this when process.cwd() changes between strategy iterations
49351
+ * so a new instance is created with the updated base path.
48956
49352
  */
48957
49353
  this.clear = () => {
48958
49354
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
48959
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
49355
+ this.getInstance.clear();
48960
49356
  };
48961
49357
  }
48962
49358
  }
@@ -48971,8 +49367,16 @@ class RecentBacktestAdapter {
48971
49367
  */
48972
49368
  class RecentLiveAdapter {
48973
49369
  constructor() {
48974
- /** Internal storage utils instance */
48975
- this._recentLiveUtils = new RecentPersistLiveUtils();
49370
+ /** Factory producing the active storage utils instance */
49371
+ this._recentLiveFactory = () => new RecentPersistLiveUtils();
49372
+ /**
49373
+ * Lazily constructs the storage utils from the registered factory and memoizes
49374
+ * the result via `singleshot`.
49375
+ *
49376
+ * The instance is built on the first call and cached for all subsequent calls.
49377
+ * Reset via `clear()` so the next call rebuilds from the current factory.
49378
+ */
49379
+ this.getInstance = functoolsKit.singleshot(() => this._recentLiveFactory());
48976
49380
  /**
48977
49381
  * Handles active ping event.
48978
49382
  * Proxies call to the underlying storage adapter.
@@ -48982,7 +49386,7 @@ class RecentLiveAdapter {
48982
49386
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
48983
49387
  signalId: event.data.id,
48984
49388
  });
48985
- return await this._recentLiveUtils.handleActivePing(event);
49389
+ return await this.getInstance().handleActivePing(event);
48986
49390
  };
48987
49391
  /**
48988
49392
  * Retrieves the latest signal for the given context.
@@ -49003,7 +49407,7 @@ class RecentLiveAdapter {
49003
49407
  frameName,
49004
49408
  backtest: backtest$1,
49005
49409
  });
49006
- return await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
49410
+ return await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
49007
49411
  };
49008
49412
  /**
49009
49413
  * Returns the number of whole minutes elapsed since the latest signal's creation timestamp.
@@ -49027,7 +49431,7 @@ class RecentLiveAdapter {
49027
49431
  backtest: backtest$1,
49028
49432
  timestamp,
49029
49433
  });
49030
- const signal = await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49434
+ const signal = await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49031
49435
  if (!signal) {
49032
49436
  return null;
49033
49437
  }
@@ -49040,7 +49444,8 @@ class RecentLiveAdapter {
49040
49444
  */
49041
49445
  this.useRecentAdapter = (Ctor) => {
49042
49446
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
49043
- this._recentLiveUtils = Reflect.construct(Ctor, []);
49447
+ this._recentLiveFactory = () => Reflect.construct(Ctor, []);
49448
+ this.getInstance.clear();
49044
49449
  };
49045
49450
  /**
49046
49451
  * Switches to persistent storage adapter (default).
@@ -49048,7 +49453,8 @@ class RecentLiveAdapter {
49048
49453
  */
49049
49454
  this.usePersist = () => {
49050
49455
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
49051
- this._recentLiveUtils = new RecentPersistLiveUtils();
49456
+ this._recentLiveFactory = () => new RecentPersistLiveUtils();
49457
+ this.getInstance.clear();
49052
49458
  };
49053
49459
  /**
49054
49460
  * Switches to in-memory storage adapter.
@@ -49056,14 +49462,17 @@ class RecentLiveAdapter {
49056
49462
  */
49057
49463
  this.useMemory = () => {
49058
49464
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
49059
- this._recentLiveUtils = new RecentMemoryLiveUtils();
49465
+ this._recentLiveFactory = () => new RecentMemoryLiveUtils();
49466
+ this.getInstance.clear();
49060
49467
  };
49061
49468
  /**
49062
- * Clears the cached utils instance by resetting to the default persistent adapter.
49469
+ * Clears the memoized utils instance.
49470
+ * Call this when process.cwd() changes between strategy iterations
49471
+ * so a new instance is created with the updated base path.
49063
49472
  */
49064
49473
  this.clear = () => {
49065
49474
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_CLEAR);
49066
- this._recentLiveUtils = new RecentPersistLiveUtils();
49475
+ this.getInstance.clear();
49067
49476
  };
49068
49477
  }
49069
49478
  }
@@ -54388,16 +54797,26 @@ class LogDummyUtils {
54388
54797
  */
54389
54798
  class LogAdapter {
54390
54799
  constructor() {
54391
- /** Internal log utils instance */
54392
- this._log = new LogMemoryUtils();
54800
+ /** Factory producing the active log utils instance */
54801
+ this._logFactory = () => new LogMemoryUtils();
54802
+ /**
54803
+ * Lazily constructs the log utils from the registered factory and memoizes
54804
+ * the result via `singleshot`.
54805
+ *
54806
+ * The instance is built on the first call and cached for all subsequent calls.
54807
+ * Reset via `clear()` so the next call rebuilds from the current factory
54808
+ * (e.g. when `process.cwd()` changes between strategy iterations).
54809
+ */
54810
+ this.getInstance = functoolsKit.singleshot(() => this._logFactory());
54393
54811
  /**
54394
54812
  * Lists all stored log entries.
54395
54813
  * Proxies call to the underlying log adapter.
54396
54814
  * @returns Array of all log entries
54397
54815
  */
54398
54816
  this.getList = async () => {
54399
- if (this._log.getList) {
54400
- return await this._log.getList();
54817
+ const log = this.getInstance();
54818
+ if (log.getList) {
54819
+ return await log.getList();
54401
54820
  }
54402
54821
  return [];
54403
54822
  };
@@ -54408,8 +54827,9 @@ class LogAdapter {
54408
54827
  * @param args - Additional arguments
54409
54828
  */
54410
54829
  this.log = (topic, ...args) => {
54411
- if (this._log.log) {
54412
- this._log.log(topic, ...args);
54830
+ const log = this.getInstance();
54831
+ if (log.log) {
54832
+ log.log(topic, ...args);
54413
54833
  }
54414
54834
  };
54415
54835
  /**
@@ -54419,8 +54839,9 @@ class LogAdapter {
54419
54839
  * @param args - Additional arguments
54420
54840
  */
54421
54841
  this.debug = (topic, ...args) => {
54422
- if (this._log.debug) {
54423
- this._log.debug(topic, ...args);
54842
+ const log = this.getInstance();
54843
+ if (log.debug) {
54844
+ log.debug(topic, ...args);
54424
54845
  }
54425
54846
  };
54426
54847
  /**
@@ -54430,8 +54851,9 @@ class LogAdapter {
54430
54851
  * @param args - Additional arguments
54431
54852
  */
54432
54853
  this.info = (topic, ...args) => {
54433
- if (this._log.info) {
54434
- this._log.info(topic, ...args);
54854
+ const log = this.getInstance();
54855
+ if (log.info) {
54856
+ log.info(topic, ...args);
54435
54857
  }
54436
54858
  };
54437
54859
  /**
@@ -54441,8 +54863,9 @@ class LogAdapter {
54441
54863
  * @param args - Additional arguments
54442
54864
  */
54443
54865
  this.warn = (topic, ...args) => {
54444
- if (this._log.warn) {
54445
- this._log.warn(topic, ...args);
54866
+ const log = this.getInstance();
54867
+ if (log.warn) {
54868
+ log.warn(topic, ...args);
54446
54869
  }
54447
54870
  };
54448
54871
  /**
@@ -54452,7 +54875,8 @@ class LogAdapter {
54452
54875
  */
54453
54876
  this.useLogger = (Ctor) => {
54454
54877
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_LOGGER);
54455
- this._log = Reflect.construct(Ctor, []);
54878
+ this._logFactory = () => Reflect.construct(Ctor, []);
54879
+ this.getInstance.clear();
54456
54880
  };
54457
54881
  /**
54458
54882
  * Switches to persistent log adapter.
@@ -54460,7 +54884,8 @@ class LogAdapter {
54460
54884
  */
54461
54885
  this.usePersist = () => {
54462
54886
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_PERSIST);
54463
- this._log = new LogPersistUtils();
54887
+ this._logFactory = () => new LogPersistUtils();
54888
+ this.getInstance.clear();
54464
54889
  };
54465
54890
  /**
54466
54891
  * Switches to in-memory log adapter (default).
@@ -54468,7 +54893,8 @@ class LogAdapter {
54468
54893
  */
54469
54894
  this.useMemory = () => {
54470
54895
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_MEMORY);
54471
- this._log = new LogMemoryUtils();
54896
+ this._logFactory = () => new LogMemoryUtils();
54897
+ this.getInstance.clear();
54472
54898
  };
54473
54899
  /**
54474
54900
  * Switches to dummy log adapter.
@@ -54476,7 +54902,8 @@ class LogAdapter {
54476
54902
  */
54477
54903
  this.useDummy = () => {
54478
54904
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_DUMMY);
54479
- this._log = new LogDummyUtils();
54905
+ this._logFactory = () => new LogDummyUtils();
54906
+ this.getInstance.clear();
54480
54907
  };
54481
54908
  /**
54482
54909
  * Switches to JSONL file log adapter.
@@ -54486,18 +54913,22 @@ class LogAdapter {
54486
54913
  * @param fileName - Base file name without extension (default: "log")
54487
54914
  * @param dirName - Directory for the JSONL file (default: ./dump/log)
54488
54915
  */
54489
- this.useJsonl = (fileName = "log.jsonl", dirName = path.join(process.cwd(), "./dump/log")) => {
54916
+ this.useJsonl = (fileName = "log.jsonl", dirName) => {
54490
54917
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_JSONL);
54491
- this._log = new LogJsonlUtils(fileName, dirName);
54918
+ this._logFactory = () => {
54919
+ const dir = dirName || path.join(process.cwd(), "./dump/log");
54920
+ return new LogJsonlUtils(fileName, dir);
54921
+ };
54922
+ this.getInstance.clear();
54492
54923
  };
54493
54924
  /**
54494
- * Clears the cached log instance by resetting to the default in-memory adapter.
54925
+ * Clears the memoized log instance.
54495
54926
  * Call this when process.cwd() changes between strategy iterations
54496
54927
  * so a new adapter instance is created with the updated base path.
54497
54928
  */
54498
54929
  this.clear = () => {
54499
54930
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_CLEAR);
54500
- this._log = new LogMemoryUtils();
54931
+ this.getInstance.clear();
54501
54932
  };
54502
54933
  }
54503
54934
  }
@@ -58389,15 +58820,23 @@ class StorageDummyLiveUtils {
58389
58820
  */
58390
58821
  class StorageBacktestAdapter {
58391
58822
  constructor() {
58392
- /** Internal storage utils instance */
58393
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58823
+ /** Factory producing the active storage utils instance */
58824
+ this._signalBacktestFactory = () => new StorageMemoryBacktestUtils();
58825
+ /**
58826
+ * Lazily constructs the storage utils from the registered factory and memoizes
58827
+ * the result via `singleshot`.
58828
+ *
58829
+ * The instance is built on the first call and cached for all subsequent calls.
58830
+ * Reset via `clear()` so the next call rebuilds from the current factory.
58831
+ */
58832
+ this.getInstance = functoolsKit.singleshot(() => this._signalBacktestFactory());
58394
58833
  /**
58395
58834
  * Handles signal opened event.
58396
58835
  * Proxies call to the underlying storage adapter.
58397
58836
  * @param tick - The opened signal tick data
58398
58837
  */
58399
58838
  this.handleOpened = async (tick) => {
58400
- return await this._signalBacktestUtils.handleOpened(tick);
58839
+ return await this.getInstance().handleOpened(tick);
58401
58840
  };
58402
58841
  /**
58403
58842
  * Handles signal closed event.
@@ -58405,7 +58844,7 @@ class StorageBacktestAdapter {
58405
58844
  * @param tick - The closed signal tick data
58406
58845
  */
58407
58846
  this.handleClosed = async (tick) => {
58408
- return await this._signalBacktestUtils.handleClosed(tick);
58847
+ return await this.getInstance().handleClosed(tick);
58409
58848
  };
58410
58849
  /**
58411
58850
  * Handles signal scheduled event.
@@ -58413,7 +58852,7 @@ class StorageBacktestAdapter {
58413
58852
  * @param tick - The scheduled signal tick data
58414
58853
  */
58415
58854
  this.handleScheduled = async (tick) => {
58416
- return await this._signalBacktestUtils.handleScheduled(tick);
58855
+ return await this.getInstance().handleScheduled(tick);
58417
58856
  };
58418
58857
  /**
58419
58858
  * Handles signal cancelled event.
@@ -58421,7 +58860,7 @@ class StorageBacktestAdapter {
58421
58860
  * @param tick - The cancelled signal tick data
58422
58861
  */
58423
58862
  this.handleCancelled = async (tick) => {
58424
- return await this._signalBacktestUtils.handleCancelled(tick);
58863
+ return await this.getInstance().handleCancelled(tick);
58425
58864
  };
58426
58865
  /**
58427
58866
  * Finds a signal by its ID.
@@ -58430,7 +58869,7 @@ class StorageBacktestAdapter {
58430
58869
  * @returns The signal row or null if not found
58431
58870
  */
58432
58871
  this.findById = async (id) => {
58433
- return await this._signalBacktestUtils.findById(id);
58872
+ return await this.getInstance().findById(id);
58434
58873
  };
58435
58874
  /**
58436
58875
  * Lists all stored signals.
@@ -58438,13 +58877,13 @@ class StorageBacktestAdapter {
58438
58877
  * @returns Array of all signal rows
58439
58878
  */
58440
58879
  this.list = async () => {
58441
- return await this._signalBacktestUtils.list();
58880
+ return await this.getInstance().list();
58442
58881
  };
58443
58882
  this.handleActivePing = async (event) => {
58444
- return await this._signalBacktestUtils.handleActivePing(event);
58883
+ return await this.getInstance().handleActivePing(event);
58445
58884
  };
58446
58885
  this.handleSchedulePing = async (event) => {
58447
- return await this._signalBacktestUtils.handleSchedulePing(event);
58886
+ return await this.getInstance().handleSchedulePing(event);
58448
58887
  };
58449
58888
  /**
58450
58889
  * Sets the storage adapter constructor.
@@ -58454,7 +58893,8 @@ class StorageBacktestAdapter {
58454
58893
  */
58455
58894
  this.useStorageAdapter = (Ctor) => {
58456
58895
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
58457
- this._signalBacktestUtils = Reflect.construct(Ctor, []);
58896
+ this._signalBacktestFactory = () => Reflect.construct(Ctor, []);
58897
+ this.getInstance.clear();
58458
58898
  };
58459
58899
  /**
58460
58900
  * Switches to dummy storage adapter.
@@ -58462,7 +58902,8 @@ class StorageBacktestAdapter {
58462
58902
  */
58463
58903
  this.useDummy = () => {
58464
58904
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
58465
- this._signalBacktestUtils = new StorageDummyBacktestUtils();
58905
+ this._signalBacktestFactory = () => new StorageDummyBacktestUtils();
58906
+ this.getInstance.clear();
58466
58907
  };
58467
58908
  /**
58468
58909
  * Switches to persistent storage adapter (default).
@@ -58470,7 +58911,8 @@ class StorageBacktestAdapter {
58470
58911
  */
58471
58912
  this.usePersist = () => {
58472
58913
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
58473
- this._signalBacktestUtils = new StoragePersistBacktestUtils();
58914
+ this._signalBacktestFactory = () => new StoragePersistBacktestUtils();
58915
+ this.getInstance.clear();
58474
58916
  };
58475
58917
  /**
58476
58918
  * Switches to in-memory storage adapter.
@@ -58478,16 +58920,17 @@ class StorageBacktestAdapter {
58478
58920
  */
58479
58921
  this.useMemory = () => {
58480
58922
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
58481
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58923
+ this._signalBacktestFactory = () => new StorageMemoryBacktestUtils();
58924
+ this.getInstance.clear();
58482
58925
  };
58483
58926
  /**
58484
- * Clears the cached utils instance by resetting to the default in-memory adapter.
58927
+ * Clears the memoized utils instance.
58485
58928
  * Call this when process.cwd() changes between strategy iterations
58486
58929
  * so a new instance is created with the updated base path.
58487
58930
  */
58488
58931
  this.clear = () => {
58489
58932
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
58490
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58933
+ this.getInstance.clear();
58491
58934
  };
58492
58935
  }
58493
58936
  }
@@ -58502,15 +58945,23 @@ class StorageBacktestAdapter {
58502
58945
  */
58503
58946
  class StorageLiveAdapter {
58504
58947
  constructor() {
58505
- /** Internal storage utils instance */
58506
- this._signalLiveUtils = new StoragePersistLiveUtils();
58948
+ /** Factory producing the active storage utils instance */
58949
+ this._signalLiveFactory = () => new StoragePersistLiveUtils();
58950
+ /**
58951
+ * Lazily constructs the storage utils from the registered factory and memoizes
58952
+ * the result via `singleshot`.
58953
+ *
58954
+ * The instance is built on the first call and cached for all subsequent calls.
58955
+ * Reset via `clear()` so the next call rebuilds from the current factory.
58956
+ */
58957
+ this.getInstance = functoolsKit.singleshot(() => this._signalLiveFactory());
58507
58958
  /**
58508
58959
  * Handles signal opened event.
58509
58960
  * Proxies call to the underlying storage adapter.
58510
58961
  * @param tick - The opened signal tick data
58511
58962
  */
58512
58963
  this.handleOpened = async (tick) => {
58513
- return await this._signalLiveUtils.handleOpened(tick);
58964
+ return await this.getInstance().handleOpened(tick);
58514
58965
  };
58515
58966
  /**
58516
58967
  * Handles signal closed event.
@@ -58518,7 +58969,7 @@ class StorageLiveAdapter {
58518
58969
  * @param tick - The closed signal tick data
58519
58970
  */
58520
58971
  this.handleClosed = async (tick) => {
58521
- return await this._signalLiveUtils.handleClosed(tick);
58972
+ return await this.getInstance().handleClosed(tick);
58522
58973
  };
58523
58974
  /**
58524
58975
  * Handles signal scheduled event.
@@ -58526,7 +58977,7 @@ class StorageLiveAdapter {
58526
58977
  * @param tick - The scheduled signal tick data
58527
58978
  */
58528
58979
  this.handleScheduled = async (tick) => {
58529
- return await this._signalLiveUtils.handleScheduled(tick);
58980
+ return await this.getInstance().handleScheduled(tick);
58530
58981
  };
58531
58982
  /**
58532
58983
  * Handles signal cancelled event.
@@ -58534,7 +58985,7 @@ class StorageLiveAdapter {
58534
58985
  * @param tick - The cancelled signal tick data
58535
58986
  */
58536
58987
  this.handleCancelled = async (tick) => {
58537
- return await this._signalLiveUtils.handleCancelled(tick);
58988
+ return await this.getInstance().handleCancelled(tick);
58538
58989
  };
58539
58990
  /**
58540
58991
  * Finds a signal by its ID.
@@ -58543,7 +58994,7 @@ class StorageLiveAdapter {
58543
58994
  * @returns The signal row or null if not found
58544
58995
  */
58545
58996
  this.findById = async (id) => {
58546
- return await this._signalLiveUtils.findById(id);
58997
+ return await this.getInstance().findById(id);
58547
58998
  };
58548
58999
  /**
58549
59000
  * Lists all stored signals.
@@ -58551,13 +59002,13 @@ class StorageLiveAdapter {
58551
59002
  * @returns Array of all signal rows
58552
59003
  */
58553
59004
  this.list = async () => {
58554
- return await this._signalLiveUtils.list();
59005
+ return await this.getInstance().list();
58555
59006
  };
58556
59007
  this.handleActivePing = async (event) => {
58557
- return await this._signalLiveUtils.handleActivePing(event);
59008
+ return await this.getInstance().handleActivePing(event);
58558
59009
  };
58559
59010
  this.handleSchedulePing = async (event) => {
58560
- return await this._signalLiveUtils.handleSchedulePing(event);
59011
+ return await this.getInstance().handleSchedulePing(event);
58561
59012
  };
58562
59013
  /**
58563
59014
  * Sets the storage adapter constructor.
@@ -58567,7 +59018,8 @@ class StorageLiveAdapter {
58567
59018
  */
58568
59019
  this.useStorageAdapter = (Ctor) => {
58569
59020
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
58570
- this._signalLiveUtils = Reflect.construct(Ctor, []);
59021
+ this._signalLiveFactory = () => Reflect.construct(Ctor, []);
59022
+ this.getInstance.clear();
58571
59023
  };
58572
59024
  /**
58573
59025
  * Switches to dummy storage adapter.
@@ -58575,7 +59027,8 @@ class StorageLiveAdapter {
58575
59027
  */
58576
59028
  this.useDummy = () => {
58577
59029
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
58578
- this._signalLiveUtils = new StorageDummyLiveUtils();
59030
+ this._signalLiveFactory = () => new StorageDummyLiveUtils();
59031
+ this.getInstance.clear();
58579
59032
  };
58580
59033
  /**
58581
59034
  * Switches to persistent storage adapter (default).
@@ -58583,7 +59036,8 @@ class StorageLiveAdapter {
58583
59036
  */
58584
59037
  this.usePersist = () => {
58585
59038
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
58586
- this._signalLiveUtils = new StoragePersistLiveUtils();
59039
+ this._signalLiveFactory = () => new StoragePersistLiveUtils();
59040
+ this.getInstance.clear();
58587
59041
  };
58588
59042
  /**
58589
59043
  * Switches to in-memory storage adapter.
@@ -58591,16 +59045,17 @@ class StorageLiveAdapter {
58591
59045
  */
58592
59046
  this.useMemory = () => {
58593
59047
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
58594
- this._signalLiveUtils = new StorageMemoryLiveUtils();
59048
+ this._signalLiveFactory = () => new StorageMemoryLiveUtils();
59049
+ this.getInstance.clear();
58595
59050
  };
58596
59051
  /**
58597
- * Clears the cached utils instance by resetting to the default persistent adapter.
59052
+ * Clears the memoized utils instance.
58598
59053
  * Call this when process.cwd() changes between strategy iterations
58599
59054
  * so a new instance is created with the updated base path.
58600
59055
  */
58601
59056
  this.clear = () => {
58602
59057
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_CLEAR);
58603
- this._signalLiveUtils = new StoragePersistLiveUtils();
59058
+ this.getInstance.clear();
58604
59059
  };
58605
59060
  }
58606
59061
  }
@@ -60716,18 +61171,26 @@ class NotificationPersistLiveUtils {
60716
61171
  */
60717
61172
  class NotificationBacktestAdapter {
60718
61173
  constructor() {
60719
- /** Internal notification utils instance */
60720
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
61174
+ /** Factory producing the active notification utils instance */
61175
+ this._notificationBacktestFactory = () => new NotificationMemoryBacktestUtils();
61176
+ /**
61177
+ * Lazily constructs the notification utils from the registered factory and
61178
+ * memoizes the result via `singleshot`.
61179
+ *
61180
+ * The instance is built on the first call and cached for all subsequent calls.
61181
+ * Reset via `clear()` so the next call rebuilds from the current factory.
61182
+ */
61183
+ this.getInstance = functoolsKit.singleshot(() => this._notificationBacktestFactory());
60721
61184
  /**
60722
61185
  * Handles signal events.
60723
61186
  * Proxies call to the underlying notification adapter.
60724
61187
  * @param data - The strategy tick result data
60725
61188
  */
60726
61189
  this.handleSignal = async (data) => {
60727
- return await this._notificationBacktestUtils.handleSignal(data);
61190
+ return await this.getInstance().handleSignal(data);
60728
61191
  };
60729
61192
  this.handleSignalNotify = async (data) => {
60730
- return await this._notificationBacktestUtils.handleSignalNotify(data);
61193
+ return await this.getInstance().handleSignalNotify(data);
60731
61194
  };
60732
61195
  /**
60733
61196
  * Handles partial profit availability event.
@@ -60735,7 +61198,7 @@ class NotificationBacktestAdapter {
60735
61198
  * @param data - The partial profit contract data
60736
61199
  */
60737
61200
  this.handlePartialProfit = async (data) => {
60738
- return await this._notificationBacktestUtils.handlePartialProfit(data);
61201
+ return await this.getInstance().handlePartialProfit(data);
60739
61202
  };
60740
61203
  /**
60741
61204
  * Handles partial loss availability event.
@@ -60743,7 +61206,7 @@ class NotificationBacktestAdapter {
60743
61206
  * @param data - The partial loss contract data
60744
61207
  */
60745
61208
  this.handlePartialLoss = async (data) => {
60746
- return await this._notificationBacktestUtils.handlePartialLoss(data);
61209
+ return await this.getInstance().handlePartialLoss(data);
60747
61210
  };
60748
61211
  /**
60749
61212
  * Handles breakeven availability event.
@@ -60751,7 +61214,7 @@ class NotificationBacktestAdapter {
60751
61214
  * @param data - The breakeven contract data
60752
61215
  */
60753
61216
  this.handleBreakeven = async (data) => {
60754
- return await this._notificationBacktestUtils.handleBreakeven(data);
61217
+ return await this.getInstance().handleBreakeven(data);
60755
61218
  };
60756
61219
  /**
60757
61220
  * Handles strategy commit events.
@@ -60759,7 +61222,7 @@ class NotificationBacktestAdapter {
60759
61222
  * @param data - The strategy commit contract data
60760
61223
  */
60761
61224
  this.handleStrategyCommit = async (data) => {
60762
- return await this._notificationBacktestUtils.handleStrategyCommit(data);
61225
+ return await this.getInstance().handleStrategyCommit(data);
60763
61226
  };
60764
61227
  /**
60765
61228
  * Handles signal sync events (signal-open, signal-close).
@@ -60767,7 +61230,7 @@ class NotificationBacktestAdapter {
60767
61230
  * @param data - The signal sync contract data
60768
61231
  */
60769
61232
  this.handleSync = functoolsKit.trycatch(async (data) => {
60770
- return await this._notificationBacktestUtils.handleSync(data);
61233
+ return await this.getInstance().handleSync(data);
60771
61234
  }, {
60772
61235
  defaultValue: null,
60773
61236
  });
@@ -60777,7 +61240,7 @@ class NotificationBacktestAdapter {
60777
61240
  * @param data - The risk contract data
60778
61241
  */
60779
61242
  this.handleRisk = async (data) => {
60780
- return await this._notificationBacktestUtils.handleRisk(data);
61243
+ return await this.getInstance().handleRisk(data);
60781
61244
  };
60782
61245
  /**
60783
61246
  * Handles error event.
@@ -60785,7 +61248,7 @@ class NotificationBacktestAdapter {
60785
61248
  * @param error - The error object
60786
61249
  */
60787
61250
  this.handleError = async (error) => {
60788
- return await this._notificationBacktestUtils.handleError(error);
61251
+ return await this.getInstance().handleError(error);
60789
61252
  };
60790
61253
  /**
60791
61254
  * Handles critical error event.
@@ -60793,7 +61256,7 @@ class NotificationBacktestAdapter {
60793
61256
  * @param error - The error object
60794
61257
  */
60795
61258
  this.handleCriticalError = async (error) => {
60796
- return await this._notificationBacktestUtils.handleCriticalError(error);
61259
+ return await this.getInstance().handleCriticalError(error);
60797
61260
  };
60798
61261
  /**
60799
61262
  * Handles validation error event.
@@ -60801,7 +61264,7 @@ class NotificationBacktestAdapter {
60801
61264
  * @param error - The error object
60802
61265
  */
60803
61266
  this.handleValidationError = async (error) => {
60804
- return await this._notificationBacktestUtils.handleValidationError(error);
61267
+ return await this.getInstance().handleValidationError(error);
60805
61268
  };
60806
61269
  /**
60807
61270
  * Gets all stored notifications.
@@ -60809,14 +61272,14 @@ class NotificationBacktestAdapter {
60809
61272
  * @returns Array of all notification models
60810
61273
  */
60811
61274
  this.getData = async () => {
60812
- return await this._notificationBacktestUtils.getData();
61275
+ return await this.getInstance().getData();
60813
61276
  };
60814
61277
  /**
60815
61278
  * Clears all stored notifications.
60816
61279
  * Proxies call to the underlying notification adapter.
60817
61280
  */
60818
61281
  this.dispose = async () => {
60819
- return await this._notificationBacktestUtils.dispose();
61282
+ return await this.getInstance().dispose();
60820
61283
  };
60821
61284
  /**
60822
61285
  * Sets the notification adapter constructor.
@@ -60826,7 +61289,8 @@ class NotificationBacktestAdapter {
60826
61289
  */
60827
61290
  this.useNotificationAdapter = (Ctor) => {
60828
61291
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
60829
- this._notificationBacktestUtils = Reflect.construct(Ctor, []);
61292
+ this._notificationBacktestFactory = () => Reflect.construct(Ctor, []);
61293
+ this.getInstance.clear();
60830
61294
  };
60831
61295
  /**
60832
61296
  * Switches to dummy notification adapter.
@@ -60834,7 +61298,8 @@ class NotificationBacktestAdapter {
60834
61298
  */
60835
61299
  this.useDummy = () => {
60836
61300
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
60837
- this._notificationBacktestUtils = new NotificationDummyBacktestUtils();
61301
+ this._notificationBacktestFactory = () => new NotificationDummyBacktestUtils();
61302
+ this.getInstance.clear();
60838
61303
  };
60839
61304
  /**
60840
61305
  * Switches to in-memory notification adapter (default).
@@ -60842,7 +61307,8 @@ class NotificationBacktestAdapter {
60842
61307
  */
60843
61308
  this.useMemory = () => {
60844
61309
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
60845
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
61310
+ this._notificationBacktestFactory = () => new NotificationMemoryBacktestUtils();
61311
+ this.getInstance.clear();
60846
61312
  };
60847
61313
  /**
60848
61314
  * Switches to persistent notification adapter.
@@ -60850,16 +61316,17 @@ class NotificationBacktestAdapter {
60850
61316
  */
60851
61317
  this.usePersist = () => {
60852
61318
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
60853
- this._notificationBacktestUtils = new NotificationPersistBacktestUtils();
61319
+ this._notificationBacktestFactory = () => new NotificationPersistBacktestUtils();
61320
+ this.getInstance.clear();
60854
61321
  };
60855
61322
  /**
60856
- * Resets the cached utils instance to the default in-memory adapter.
61323
+ * Clears the memoized utils instance.
60857
61324
  * Call this when process.cwd() changes between strategy iterations
60858
61325
  * so a new instance is created with the updated base path.
60859
61326
  */
60860
61327
  this.clear = () => {
60861
61328
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
60862
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
61329
+ this.getInstance.clear();
60863
61330
  };
60864
61331
  }
60865
61332
  }
@@ -60874,18 +61341,26 @@ class NotificationBacktestAdapter {
60874
61341
  */
60875
61342
  class NotificationLiveAdapter {
60876
61343
  constructor() {
60877
- /** Internal notification utils instance */
60878
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61344
+ /** Factory producing the active notification utils instance */
61345
+ this._notificationLiveFactory = () => new NotificationMemoryLiveUtils();
61346
+ /**
61347
+ * Lazily constructs the notification utils from the registered factory and
61348
+ * memoizes the result via `singleshot`.
61349
+ *
61350
+ * The instance is built on the first call and cached for all subsequent calls.
61351
+ * Reset via `clear()` so the next call rebuilds from the current factory.
61352
+ */
61353
+ this.getInstance = functoolsKit.singleshot(() => this._notificationLiveFactory());
60879
61354
  /**
60880
61355
  * Handles signal events.
60881
61356
  * Proxies call to the underlying notification adapter.
60882
61357
  * @param data - The strategy tick result data
60883
61358
  */
60884
61359
  this.handleSignal = async (data) => {
60885
- return await this._notificationLiveUtils.handleSignal(data);
61360
+ return await this.getInstance().handleSignal(data);
60886
61361
  };
60887
61362
  this.handleSignalNotify = async (data) => {
60888
- return await this._notificationLiveUtils.handleSignalNotify(data);
61363
+ return await this.getInstance().handleSignalNotify(data);
60889
61364
  };
60890
61365
  /**
60891
61366
  * Handles partial profit availability event.
@@ -60893,7 +61368,7 @@ class NotificationLiveAdapter {
60893
61368
  * @param data - The partial profit contract data
60894
61369
  */
60895
61370
  this.handlePartialProfit = async (data) => {
60896
- return await this._notificationLiveUtils.handlePartialProfit(data);
61371
+ return await this.getInstance().handlePartialProfit(data);
60897
61372
  };
60898
61373
  /**
60899
61374
  * Handles partial loss availability event.
@@ -60901,7 +61376,7 @@ class NotificationLiveAdapter {
60901
61376
  * @param data - The partial loss contract data
60902
61377
  */
60903
61378
  this.handlePartialLoss = async (data) => {
60904
- return await this._notificationLiveUtils.handlePartialLoss(data);
61379
+ return await this.getInstance().handlePartialLoss(data);
60905
61380
  };
60906
61381
  /**
60907
61382
  * Handles breakeven availability event.
@@ -60909,7 +61384,7 @@ class NotificationLiveAdapter {
60909
61384
  * @param data - The breakeven contract data
60910
61385
  */
60911
61386
  this.handleBreakeven = async (data) => {
60912
- return await this._notificationLiveUtils.handleBreakeven(data);
61387
+ return await this.getInstance().handleBreakeven(data);
60913
61388
  };
60914
61389
  /**
60915
61390
  * Handles strategy commit events.
@@ -60917,7 +61392,7 @@ class NotificationLiveAdapter {
60917
61392
  * @param data - The strategy commit contract data
60918
61393
  */
60919
61394
  this.handleStrategyCommit = async (data) => {
60920
- return await this._notificationLiveUtils.handleStrategyCommit(data);
61395
+ return await this.getInstance().handleStrategyCommit(data);
60921
61396
  };
60922
61397
  /**
60923
61398
  * Handles signal sync events (signal-open, signal-close).
@@ -60925,7 +61400,7 @@ class NotificationLiveAdapter {
60925
61400
  * @param data - The signal sync contract data
60926
61401
  */
60927
61402
  this.handleSync = functoolsKit.trycatch(async (data) => {
60928
- return await this._notificationLiveUtils.handleSync(data);
61403
+ return await this.getInstance().handleSync(data);
60929
61404
  }, {
60930
61405
  defaultValue: null,
60931
61406
  });
@@ -60935,7 +61410,7 @@ class NotificationLiveAdapter {
60935
61410
  * @param data - The risk contract data
60936
61411
  */
60937
61412
  this.handleRisk = async (data) => {
60938
- return await this._notificationLiveUtils.handleRisk(data);
61413
+ return await this.getInstance().handleRisk(data);
60939
61414
  };
60940
61415
  /**
60941
61416
  * Handles error event.
@@ -60943,7 +61418,7 @@ class NotificationLiveAdapter {
60943
61418
  * @param error - The error object
60944
61419
  */
60945
61420
  this.handleError = async (error) => {
60946
- return await this._notificationLiveUtils.handleError(error);
61421
+ return await this.getInstance().handleError(error);
60947
61422
  };
60948
61423
  /**
60949
61424
  * Handles critical error event.
@@ -60951,7 +61426,7 @@ class NotificationLiveAdapter {
60951
61426
  * @param error - The error object
60952
61427
  */
60953
61428
  this.handleCriticalError = async (error) => {
60954
- return await this._notificationLiveUtils.handleCriticalError(error);
61429
+ return await this.getInstance().handleCriticalError(error);
60955
61430
  };
60956
61431
  /**
60957
61432
  * Handles validation error event.
@@ -60959,7 +61434,7 @@ class NotificationLiveAdapter {
60959
61434
  * @param error - The error object
60960
61435
  */
60961
61436
  this.handleValidationError = async (error) => {
60962
- return await this._notificationLiveUtils.handleValidationError(error);
61437
+ return await this.getInstance().handleValidationError(error);
60963
61438
  };
60964
61439
  /**
60965
61440
  * Gets all stored notifications.
@@ -60967,14 +61442,14 @@ class NotificationLiveAdapter {
60967
61442
  * @returns Array of all notification models
60968
61443
  */
60969
61444
  this.getData = async () => {
60970
- return await this._notificationLiveUtils.getData();
61445
+ return await this.getInstance().getData();
60971
61446
  };
60972
61447
  /**
60973
61448
  * Clears all stored notifications.
60974
61449
  * Proxies call to the underlying notification adapter.
60975
61450
  */
60976
61451
  this.dispose = async () => {
60977
- return await this._notificationLiveUtils.dispose();
61452
+ return await this.getInstance().dispose();
60978
61453
  };
60979
61454
  /**
60980
61455
  * Sets the notification adapter constructor.
@@ -60984,7 +61459,8 @@ class NotificationLiveAdapter {
60984
61459
  */
60985
61460
  this.useNotificationAdapter = (Ctor) => {
60986
61461
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
60987
- this._notificationLiveUtils = Reflect.construct(Ctor, []);
61462
+ this._notificationLiveFactory = () => Reflect.construct(Ctor, []);
61463
+ this.getInstance.clear();
60988
61464
  };
60989
61465
  /**
60990
61466
  * Switches to dummy notification adapter.
@@ -60992,7 +61468,8 @@ class NotificationLiveAdapter {
60992
61468
  */
60993
61469
  this.useDummy = () => {
60994
61470
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
60995
- this._notificationLiveUtils = new NotificationDummyLiveUtils();
61471
+ this._notificationLiveFactory = () => new NotificationDummyLiveUtils();
61472
+ this.getInstance.clear();
60996
61473
  };
60997
61474
  /**
60998
61475
  * Switches to in-memory notification adapter (default).
@@ -61000,7 +61477,8 @@ class NotificationLiveAdapter {
61000
61477
  */
61001
61478
  this.useMemory = () => {
61002
61479
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
61003
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61480
+ this._notificationLiveFactory = () => new NotificationMemoryLiveUtils();
61481
+ this.getInstance.clear();
61004
61482
  };
61005
61483
  /**
61006
61484
  * Switches to persistent notification adapter.
@@ -61008,16 +61486,17 @@ class NotificationLiveAdapter {
61008
61486
  */
61009
61487
  this.usePersist = () => {
61010
61488
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
61011
- this._notificationLiveUtils = new NotificationPersistLiveUtils();
61489
+ this._notificationLiveFactory = () => new NotificationPersistLiveUtils();
61490
+ this.getInstance.clear();
61012
61491
  };
61013
61492
  /**
61014
- * Resets the cached utils instance to the default in-memory adapter.
61493
+ * Clears the memoized utils instance.
61015
61494
  * Call this when process.cwd() changes between strategy iterations
61016
61495
  * so a new instance is created with the updated base path.
61017
61496
  */
61018
61497
  this.clear = () => {
61019
61498
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_CLEAR);
61020
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61499
+ this.getInstance.clear();
61021
61500
  };
61022
61501
  }
61023
61502
  }
@@ -63633,6 +64112,7 @@ exports.HighestProfit = HighestProfit;
63633
64112
  exports.Interval = Interval;
63634
64113
  exports.Live = Live;
63635
64114
  exports.Log = Log;
64115
+ exports.Lookup = Lookup;
63636
64116
  exports.Markdown = Markdown;
63637
64117
  exports.MarkdownFileBase = MarkdownFileBase;
63638
64118
  exports.MarkdownFolderBase = MarkdownFolderBase;
@@ -63714,6 +64194,7 @@ exports.addSizingSchema = addSizingSchema;
63714
64194
  exports.addStrategySchema = addStrategySchema;
63715
64195
  exports.addWalkerSchema = addWalkerSchema;
63716
64196
  exports.alignToInterval = alignToInterval;
64197
+ exports.cacheCandles = cacheCandles;
63717
64198
  exports.checkCandles = checkCandles;
63718
64199
  exports.commitActivateScheduled = commitActivateScheduled;
63719
64200
  exports.commitAverageBuy = commitAverageBuy;