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.mjs CHANGED
@@ -554,6 +554,22 @@ const GLOBAL_CONFIG = {
554
554
  * Default: true (mutex locking enabled for candle fetching)
555
555
  */
556
556
  CC_ENABLE_CANDLE_FETCH_MUTEX: true,
557
+ /**
558
+ * Enables cooperative interleaving of concurrently running backtests after each candle fetch.
559
+ *
560
+ * Mechanism (implemented in `Candle.spinLock`):
561
+ * - After `getNextCandles` resolves, the current backtest awaits
562
+ * `Promise.race([_spin.toPromise(), sleep(50)])`, where `_spin` is emitted whenever
563
+ * another caller acquires the candle-fetch mutex.
564
+ * - This hands the event loop to a peer backtest waiting on the same mutex, so multiple
565
+ * parallel `Backtest.run` / `Walker` workloads progress in round-robin fashion instead
566
+ * of one monopolizing the event loop until completion.
567
+ * - The spin is skipped entirely when `Lookup.isParallel` is `false` (single active workload —
568
+ * no peer to yield to) or when `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled.
569
+ *
570
+ * Default: true (parallel backtests are interleaved on each candle fetch boundary)
571
+ */
572
+ CC_ENABLE_BACKTEST_PARALLEL_SPIN: true,
557
573
  /**
558
574
  * Enables DCA (Dollar-Cost Averaging) logic even if antirecord is not broken.
559
575
  * Allows to commitAverageBuy if currentPrice is not the lowest price since entry, but still lower than priceOpen.
@@ -914,7 +930,7 @@ async function writeFileAtomic(file, data, options = {}) {
914
930
 
915
931
  var _a$3;
916
932
  /** Logger service injected as DI singleton */
917
- const LOGGER_SERVICE$7 = new LoggerService();
933
+ const LOGGER_SERVICE$8 = new LoggerService();
918
934
  /** Symbol key for the singleshot waitForInit function on PersistBase instances. */
919
935
  const BASE_WAIT_FOR_INIT_SYMBOL = Symbol("wait-for-init");
920
936
  // Calculate step in milliseconds for candle close time validation
@@ -1037,7 +1053,7 @@ const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
1037
1053
  const BASE_UNLINK_RETRY_COUNT = 5;
1038
1054
  const BASE_UNLINK_RETRY_DELAY = 1000;
1039
1055
  const BASE_WAIT_FOR_INIT_FN = async (self) => {
1040
- LOGGER_SERVICE$7.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
1056
+ LOGGER_SERVICE$8.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
1041
1057
  entityName: self.entityName,
1042
1058
  directory: self._directory,
1043
1059
  });
@@ -1095,7 +1111,7 @@ class PersistBase {
1095
1111
  this.entityName = entityName;
1096
1112
  this.baseDir = baseDir;
1097
1113
  this[_a$3] = singleshot(async () => await BASE_WAIT_FOR_INIT_FN(this));
1098
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
1114
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
1099
1115
  entityName: this.entityName,
1100
1116
  baseDir,
1101
1117
  });
@@ -1111,14 +1127,14 @@ class PersistBase {
1111
1127
  return join(this.baseDir, this.entityName, `${entityId}.json`);
1112
1128
  }
1113
1129
  async waitForInit(initial) {
1114
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
1130
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
1115
1131
  entityName: this.entityName,
1116
1132
  initial,
1117
1133
  });
1118
1134
  await this[BASE_WAIT_FOR_INIT_SYMBOL]();
1119
1135
  }
1120
1136
  async readValue(entityId) {
1121
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
1137
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
1122
1138
  entityName: this.entityName,
1123
1139
  entityId,
1124
1140
  });
@@ -1135,7 +1151,7 @@ class PersistBase {
1135
1151
  }
1136
1152
  }
1137
1153
  async hasValue(entityId) {
1138
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
1154
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
1139
1155
  entityName: this.entityName,
1140
1156
  entityId,
1141
1157
  });
@@ -1152,7 +1168,7 @@ class PersistBase {
1152
1168
  }
1153
1169
  }
1154
1170
  async writeValue(entityId, entity) {
1155
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
1171
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
1156
1172
  entityName: this.entityName,
1157
1173
  entityId,
1158
1174
  });
@@ -1174,7 +1190,7 @@ class PersistBase {
1174
1190
  * @throws Error if reading fails
1175
1191
  */
1176
1192
  async *keys() {
1177
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
1193
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
1178
1194
  entityName: this.entityName,
1179
1195
  });
1180
1196
  try {
@@ -1319,7 +1335,7 @@ class PersistSignalUtils {
1319
1335
  * @returns Promise resolving to signal or null if none persisted
1320
1336
  */
1321
1337
  this.readSignalData = async (symbol, strategyName, exchangeName) => {
1322
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
1338
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
1323
1339
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1324
1340
  const isInitial = !this.getStorage.has(key);
1325
1341
  const instance = this.getStorage(symbol, strategyName, exchangeName);
@@ -1337,7 +1353,7 @@ class PersistSignalUtils {
1337
1353
  * @returns Promise that resolves when write is complete
1338
1354
  */
1339
1355
  this.writeSignalData = async (signalRow, symbol, strategyName, exchangeName) => {
1340
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
1356
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
1341
1357
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1342
1358
  const isInitial = !this.getStorage.has(key);
1343
1359
  const instance = this.getStorage(symbol, strategyName, exchangeName);
@@ -1352,7 +1368,7 @@ class PersistSignalUtils {
1352
1368
  * @param Ctor - Custom IPersistSignalInstance constructor
1353
1369
  */
1354
1370
  usePersistSignalAdapter(Ctor) {
1355
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
1371
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
1356
1372
  this.PersistSignalInstanceCtor = Ctor;
1357
1373
  this.getStorage.clear();
1358
1374
  }
@@ -1361,21 +1377,21 @@ class PersistSignalUtils {
1361
1377
  * Call when process.cwd() changes between strategy iterations.
1362
1378
  */
1363
1379
  clear() {
1364
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
1380
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
1365
1381
  this.getStorage.clear();
1366
1382
  }
1367
1383
  /**
1368
1384
  * Switches to the default file-based PersistSignalInstance.
1369
1385
  */
1370
1386
  useJson() {
1371
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
1387
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
1372
1388
  this.usePersistSignalAdapter(PersistSignalInstance);
1373
1389
  }
1374
1390
  /**
1375
1391
  * Switches to PersistSignalDummyInstance (all operations are no-ops).
1376
1392
  */
1377
1393
  useDummy() {
1378
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
1394
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
1379
1395
  this.usePersistSignalAdapter(PersistSignalDummyInstance);
1380
1396
  }
1381
1397
  }
@@ -1515,7 +1531,7 @@ class PersistRiskUtils {
1515
1531
  * @returns Promise resolving to position entries (empty array if none)
1516
1532
  */
1517
1533
  this.readPositionData = async (riskName, exchangeName, when) => {
1518
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
1534
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
1519
1535
  const key = `${riskName}:${exchangeName}`;
1520
1536
  const isInitial = !this.getRiskStorage.has(key);
1521
1537
  const instance = this.getRiskStorage(riskName, exchangeName);
@@ -1533,7 +1549,7 @@ class PersistRiskUtils {
1533
1549
  * @returns Promise that resolves when write is complete
1534
1550
  */
1535
1551
  this.writePositionData = async (riskRow, riskName, exchangeName, when) => {
1536
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
1552
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
1537
1553
  const key = `${riskName}:${exchangeName}`;
1538
1554
  const isInitial = !this.getRiskStorage.has(key);
1539
1555
  const instance = this.getRiskStorage(riskName, exchangeName);
@@ -1548,7 +1564,7 @@ class PersistRiskUtils {
1548
1564
  * @param Ctor - Custom IPersistRiskInstance constructor
1549
1565
  */
1550
1566
  usePersistRiskAdapter(Ctor) {
1551
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
1567
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
1552
1568
  this.PersistRiskInstanceCtor = Ctor;
1553
1569
  this.getRiskStorage.clear();
1554
1570
  }
@@ -1557,21 +1573,21 @@ class PersistRiskUtils {
1557
1573
  * Call when process.cwd() changes between strategy iterations.
1558
1574
  */
1559
1575
  clear() {
1560
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
1576
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
1561
1577
  this.getRiskStorage.clear();
1562
1578
  }
1563
1579
  /**
1564
1580
  * Switches to the default file-based PersistRiskInstance.
1565
1581
  */
1566
1582
  useJson() {
1567
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
1583
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
1568
1584
  this.usePersistRiskAdapter(PersistRiskInstance);
1569
1585
  }
1570
1586
  /**
1571
1587
  * Switches to PersistRiskDummyInstance (all operations are no-ops).
1572
1588
  */
1573
1589
  useDummy() {
1574
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
1590
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
1575
1591
  this.usePersistRiskAdapter(PersistRiskDummyInstance);
1576
1592
  }
1577
1593
  }
@@ -1710,7 +1726,7 @@ class PersistScheduleUtils {
1710
1726
  * @returns Promise resolving to scheduled signal or null if none persisted
1711
1727
  */
1712
1728
  this.readScheduleData = async (symbol, strategyName, exchangeName) => {
1713
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
1729
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
1714
1730
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1715
1731
  const isInitial = !this.getScheduleStorage.has(key);
1716
1732
  const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
@@ -1728,7 +1744,7 @@ class PersistScheduleUtils {
1728
1744
  * @returns Promise that resolves when write is complete
1729
1745
  */
1730
1746
  this.writeScheduleData = async (scheduledSignalRow, symbol, strategyName, exchangeName) => {
1731
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
1747
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
1732
1748
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1733
1749
  const isInitial = !this.getScheduleStorage.has(key);
1734
1750
  const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
@@ -1743,7 +1759,7 @@ class PersistScheduleUtils {
1743
1759
  * @param Ctor - Custom IPersistScheduleInstance constructor
1744
1760
  */
1745
1761
  usePersistScheduleAdapter(Ctor) {
1746
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
1762
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
1747
1763
  this.PersistScheduleInstanceCtor = Ctor;
1748
1764
  this.getScheduleStorage.clear();
1749
1765
  }
@@ -1752,21 +1768,21 @@ class PersistScheduleUtils {
1752
1768
  * Call when process.cwd() changes between strategy iterations.
1753
1769
  */
1754
1770
  clear() {
1755
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
1771
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
1756
1772
  this.getScheduleStorage.clear();
1757
1773
  }
1758
1774
  /**
1759
1775
  * Switches to the default file-based PersistScheduleInstance.
1760
1776
  */
1761
1777
  useJson() {
1762
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
1778
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
1763
1779
  this.usePersistScheduleAdapter(PersistScheduleInstance);
1764
1780
  }
1765
1781
  /**
1766
1782
  * Switches to PersistScheduleDummyInstance (all operations are no-ops).
1767
1783
  */
1768
1784
  useDummy() {
1769
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
1785
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
1770
1786
  this.usePersistScheduleAdapter(PersistScheduleDummyInstance);
1771
1787
  }
1772
1788
  }
@@ -1911,7 +1927,7 @@ class PersistPartialUtils {
1911
1927
  * @returns Promise resolving to partial data record (empty object if none)
1912
1928
  */
1913
1929
  this.readPartialData = async (symbol, strategyName, signalId, exchangeName, when) => {
1914
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
1930
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
1915
1931
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1916
1932
  const isInitial = !this.getPartialStorage.has(key);
1917
1933
  const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
@@ -1931,7 +1947,7 @@ class PersistPartialUtils {
1931
1947
  * @returns Promise that resolves when write is complete
1932
1948
  */
1933
1949
  this.writePartialData = async (partialData, symbol, strategyName, signalId, exchangeName, when) => {
1934
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
1950
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_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);
@@ -1946,7 +1962,7 @@ class PersistPartialUtils {
1946
1962
  * @param Ctor - Custom IPersistPartialInstance constructor
1947
1963
  */
1948
1964
  usePersistPartialAdapter(Ctor) {
1949
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
1965
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
1950
1966
  this.PersistPartialInstanceCtor = Ctor;
1951
1967
  this.getPartialStorage.clear();
1952
1968
  }
@@ -1955,21 +1971,21 @@ class PersistPartialUtils {
1955
1971
  * Call when process.cwd() changes between strategy iterations.
1956
1972
  */
1957
1973
  clear() {
1958
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
1974
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
1959
1975
  this.getPartialStorage.clear();
1960
1976
  }
1961
1977
  /**
1962
1978
  * Switches to the default file-based PersistPartialInstance.
1963
1979
  */
1964
1980
  useJson() {
1965
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
1981
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
1966
1982
  this.usePersistPartialAdapter(PersistPartialInstance);
1967
1983
  }
1968
1984
  /**
1969
1985
  * Switches to PersistPartialDummyInstance (all operations are no-ops).
1970
1986
  */
1971
1987
  useDummy() {
1972
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
1988
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
1973
1989
  this.usePersistPartialAdapter(PersistPartialDummyInstance);
1974
1990
  }
1975
1991
  }
@@ -2134,7 +2150,7 @@ class PersistBreakevenUtils {
2134
2150
  * @returns Promise resolving to breakeven data record (empty object if none)
2135
2151
  */
2136
2152
  this.readBreakevenData = async (symbol, strategyName, signalId, exchangeName, when) => {
2137
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
2153
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
2138
2154
  const key = `${symbol}:${strategyName}:${exchangeName}`;
2139
2155
  const isInitial = !this.getBreakevenStorage.has(key);
2140
2156
  const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
@@ -2154,7 +2170,7 @@ class PersistBreakevenUtils {
2154
2170
  * @returns Promise that resolves when write is complete
2155
2171
  */
2156
2172
  this.writeBreakevenData = async (breakevenData, symbol, strategyName, signalId, exchangeName, when) => {
2157
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
2173
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_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);
@@ -2169,7 +2185,7 @@ class PersistBreakevenUtils {
2169
2185
  * @param Ctor - Custom IPersistBreakevenInstance constructor
2170
2186
  */
2171
2187
  usePersistBreakevenAdapter(Ctor) {
2172
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
2188
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
2173
2189
  this.PersistBreakevenInstanceCtor = Ctor;
2174
2190
  this.getBreakevenStorage.clear();
2175
2191
  }
@@ -2178,21 +2194,21 @@ class PersistBreakevenUtils {
2178
2194
  * Call when process.cwd() changes between strategy iterations.
2179
2195
  */
2180
2196
  clear() {
2181
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
2197
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
2182
2198
  this.getBreakevenStorage.clear();
2183
2199
  }
2184
2200
  /**
2185
2201
  * Switches to the default file-based PersistBreakevenInstance.
2186
2202
  */
2187
2203
  useJson() {
2188
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
2204
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
2189
2205
  this.usePersistBreakevenAdapter(PersistBreakevenInstance);
2190
2206
  }
2191
2207
  /**
2192
2208
  * Switches to PersistBreakevenDummyInstance (all operations are no-ops).
2193
2209
  */
2194
2210
  useDummy() {
2195
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
2211
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
2196
2212
  this.usePersistBreakevenAdapter(PersistBreakevenDummyInstance);
2197
2213
  }
2198
2214
  }
@@ -2283,7 +2299,7 @@ class PersistCandleInstance {
2283
2299
  error: errorData(error),
2284
2300
  message: getErrorMessage(error),
2285
2301
  };
2286
- LOGGER_SERVICE$7.warn(message, payload);
2302
+ LOGGER_SERVICE$8.warn(message, payload);
2287
2303
  console.warn(message, payload);
2288
2304
  errorEmitter.next(error);
2289
2305
  return null;
@@ -2305,7 +2321,7 @@ class PersistCandleInstance {
2305
2321
  for (const candle of candles) {
2306
2322
  const candleCloseTime = candle.timestamp + stepMs;
2307
2323
  if (candleCloseTime > now) {
2308
- LOGGER_SERVICE$7.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
2324
+ LOGGER_SERVICE$8.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
2309
2325
  symbol: this.symbol,
2310
2326
  interval: this.interval,
2311
2327
  exchangeName: this.exchangeName,
@@ -2382,7 +2398,7 @@ class PersistCandleUtils {
2382
2398
  * @returns Promise resolving to candles in order, or null on cache miss
2383
2399
  */
2384
2400
  this.readCandlesData = async (symbol, interval, exchangeName, limit, sinceTimestamp, untilTimestamp) => {
2385
- LOGGER_SERVICE$7.info("PersistCandleUtils.readCandlesData", {
2401
+ LOGGER_SERVICE$8.info("PersistCandleUtils.readCandlesData", {
2386
2402
  symbol,
2387
2403
  interval,
2388
2404
  exchangeName,
@@ -2406,7 +2422,7 @@ class PersistCandleUtils {
2406
2422
  * @returns Promise that resolves when all writes are complete
2407
2423
  */
2408
2424
  this.writeCandlesData = async (candles, symbol, interval, exchangeName) => {
2409
- LOGGER_SERVICE$7.info("PersistCandleUtils.writeCandlesData", {
2425
+ LOGGER_SERVICE$8.info("PersistCandleUtils.writeCandlesData", {
2410
2426
  symbol,
2411
2427
  interval,
2412
2428
  exchangeName,
@@ -2426,7 +2442,7 @@ class PersistCandleUtils {
2426
2442
  * @param Ctor - Custom IPersistCandleInstance constructor
2427
2443
  */
2428
2444
  usePersistCandleAdapter(Ctor) {
2429
- LOGGER_SERVICE$7.info("PersistCandleUtils.usePersistCandleAdapter");
2445
+ LOGGER_SERVICE$8.info("PersistCandleUtils.usePersistCandleAdapter");
2430
2446
  this.PersistCandleInstanceCtor = Ctor;
2431
2447
  this.getCandlesStorage.clear();
2432
2448
  }
@@ -2435,21 +2451,21 @@ class PersistCandleUtils {
2435
2451
  * Call when process.cwd() changes between strategy iterations.
2436
2452
  */
2437
2453
  clear() {
2438
- LOGGER_SERVICE$7.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
2454
+ LOGGER_SERVICE$8.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
2439
2455
  this.getCandlesStorage.clear();
2440
2456
  }
2441
2457
  /**
2442
2458
  * Switches to the default file-based PersistCandleInstance.
2443
2459
  */
2444
2460
  useJson() {
2445
- LOGGER_SERVICE$7.log("PersistCandleUtils.useJson");
2461
+ LOGGER_SERVICE$8.log("PersistCandleUtils.useJson");
2446
2462
  this.usePersistCandleAdapter(PersistCandleInstance);
2447
2463
  }
2448
2464
  /**
2449
2465
  * Switches to PersistCandleDummyInstance (always returns null on read, discards writes).
2450
2466
  */
2451
2467
  useDummy() {
2452
- LOGGER_SERVICE$7.log("PersistCandleUtils.useDummy");
2468
+ LOGGER_SERVICE$8.log("PersistCandleUtils.useDummy");
2453
2469
  this.usePersistCandleAdapter(PersistCandleDummyInstance);
2454
2470
  }
2455
2471
  }
@@ -2587,7 +2603,7 @@ class PersistStorageUtils {
2587
2603
  * @returns Promise resolving to array of signal entries
2588
2604
  */
2589
2605
  this.readStorageData = async (backtest) => {
2590
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
2606
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
2591
2607
  const key = backtest ? `backtest` : `live`;
2592
2608
  const isInitial = !this.getStorage.has(key);
2593
2609
  const instance = this.getStorage(backtest);
@@ -2603,7 +2619,7 @@ class PersistStorageUtils {
2603
2619
  * @returns Promise that resolves when write is complete
2604
2620
  */
2605
2621
  this.writeStorageData = async (signalData, backtest) => {
2606
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
2622
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
2607
2623
  const key = backtest ? `backtest` : `live`;
2608
2624
  const isInitial = !this.getStorage.has(key);
2609
2625
  const instance = this.getStorage(backtest);
@@ -2618,7 +2634,7 @@ class PersistStorageUtils {
2618
2634
  * @param Ctor - Custom IPersistStorageInstance constructor
2619
2635
  */
2620
2636
  usePersistStorageAdapter(Ctor) {
2621
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
2637
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
2622
2638
  this.PersistStorageInstanceCtor = Ctor;
2623
2639
  this.getStorage.clear();
2624
2640
  }
@@ -2627,21 +2643,21 @@ class PersistStorageUtils {
2627
2643
  * Call when process.cwd() changes between strategy iterations.
2628
2644
  */
2629
2645
  clear() {
2630
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
2646
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
2631
2647
  this.getStorage.clear();
2632
2648
  }
2633
2649
  /**
2634
2650
  * Switches to the default file-based PersistStorageInstance.
2635
2651
  */
2636
2652
  useJson() {
2637
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
2653
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
2638
2654
  this.usePersistStorageAdapter(PersistStorageInstance);
2639
2655
  }
2640
2656
  /**
2641
2657
  * Switches to PersistStorageDummyInstance (all operations are no-ops).
2642
2658
  */
2643
2659
  useDummy() {
2644
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
2660
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
2645
2661
  this.usePersistStorageAdapter(PersistStorageDummyInstance);
2646
2662
  }
2647
2663
  }
@@ -2768,7 +2784,7 @@ class PersistNotificationUtils {
2768
2784
  * @returns Promise resolving to array of notification entries
2769
2785
  */
2770
2786
  this.readNotificationData = async (backtest) => {
2771
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
2787
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
2772
2788
  const key = backtest ? `backtest` : `live`;
2773
2789
  const isInitial = !this.getNotificationStorage.has(key);
2774
2790
  const instance = this.getNotificationStorage(backtest);
@@ -2784,7 +2800,7 @@ class PersistNotificationUtils {
2784
2800
  * @returns Promise that resolves when write is complete
2785
2801
  */
2786
2802
  this.writeNotificationData = async (notificationData, backtest) => {
2787
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
2803
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
2788
2804
  const key = backtest ? `backtest` : `live`;
2789
2805
  const isInitial = !this.getNotificationStorage.has(key);
2790
2806
  const instance = this.getNotificationStorage(backtest);
@@ -2799,7 +2815,7 @@ class PersistNotificationUtils {
2799
2815
  * @param Ctor - Custom IPersistNotificationInstance constructor
2800
2816
  */
2801
2817
  usePersistNotificationAdapter(Ctor) {
2802
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
2818
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
2803
2819
  this.PersistNotificationInstanceCtor = Ctor;
2804
2820
  this.getNotificationStorage.clear();
2805
2821
  }
@@ -2809,21 +2825,21 @@ class PersistNotificationUtils {
2809
2825
  * instances are created with the updated base path.
2810
2826
  */
2811
2827
  clear() {
2812
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
2828
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
2813
2829
  this.getNotificationStorage.clear();
2814
2830
  }
2815
2831
  /**
2816
2832
  * Switches to the default file-based PersistNotificationInstance.
2817
2833
  */
2818
2834
  useJson() {
2819
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
2835
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
2820
2836
  this.usePersistNotificationAdapter(PersistNotificationInstance);
2821
2837
  }
2822
2838
  /**
2823
2839
  * Switches to PersistNotificationDummyInstance (all operations are no-ops).
2824
2840
  */
2825
2841
  useDummy() {
2826
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
2842
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
2827
2843
  this.usePersistNotificationAdapter(PersistNotificationDummyInstance);
2828
2844
  }
2829
2845
  }
@@ -2947,7 +2963,7 @@ class PersistLogUtils {
2947
2963
  * @returns Promise resolving to array of log entries
2948
2964
  */
2949
2965
  this.readLogData = async () => {
2950
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
2966
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
2951
2967
  const isInitial = !this._logInstance;
2952
2968
  const instance = this.getLogInstance();
2953
2969
  await instance.waitForInit(isInitial);
@@ -2961,7 +2977,7 @@ class PersistLogUtils {
2961
2977
  * @returns Promise that resolves when write is complete
2962
2978
  */
2963
2979
  this.writeLogData = async (logData) => {
2964
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
2980
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
2965
2981
  const isInitial = !this._logInstance;
2966
2982
  const instance = this.getLogInstance();
2967
2983
  await instance.waitForInit(isInitial);
@@ -2986,7 +3002,7 @@ class PersistLogUtils {
2986
3002
  * @param Ctor - Custom IPersistLogInstance constructor
2987
3003
  */
2988
3004
  usePersistLogAdapter(Ctor) {
2989
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
3005
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
2990
3006
  this.PersistLogInstanceCtor = Ctor;
2991
3007
  this._logInstance = null;
2992
3008
  }
@@ -2995,21 +3011,21 @@ class PersistLogUtils {
2995
3011
  * Call when process.cwd() changes between strategy iterations.
2996
3012
  */
2997
3013
  clear() {
2998
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
3014
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
2999
3015
  this._logInstance = null;
3000
3016
  }
3001
3017
  /**
3002
3018
  * Switches to the default file-based PersistLogInstance.
3003
3019
  */
3004
3020
  useJson() {
3005
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
3021
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
3006
3022
  this.usePersistLogAdapter(PersistLogInstance);
3007
3023
  }
3008
3024
  /**
3009
3025
  * Switches to PersistLogDummyInstance (all operations are no-ops).
3010
3026
  */
3011
3027
  useDummy() {
3012
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
3028
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
3013
3029
  this.usePersistLogAdapter(PersistLogDummyInstance);
3014
3030
  }
3015
3031
  }
@@ -3171,7 +3187,7 @@ class PersistMeasureUtils {
3171
3187
  * @returns Promise resolving to cached value, or null if not found / soft-deleted
3172
3188
  */
3173
3189
  this.readMeasureData = async (bucket, key) => {
3174
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3190
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3175
3191
  const isInitial = !this.getMeasureStorage.has(bucket);
3176
3192
  const instance = this.getMeasureStorage(bucket);
3177
3193
  await instance.waitForInit(isInitial);
@@ -3187,7 +3203,7 @@ class PersistMeasureUtils {
3187
3203
  * @returns Promise that resolves when write is complete
3188
3204
  */
3189
3205
  this.writeMeasureData = async (data, bucket, key, when) => {
3190
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3206
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3191
3207
  const isInitial = !this.getMeasureStorage.has(bucket);
3192
3208
  const instance = this.getMeasureStorage(bucket);
3193
3209
  await instance.waitForInit(isInitial);
@@ -3202,7 +3218,7 @@ class PersistMeasureUtils {
3202
3218
  * @returns Promise that resolves when removal is complete
3203
3219
  */
3204
3220
  this.removeMeasureData = async (bucket, key) => {
3205
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3221
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3206
3222
  const isInitial = !this.getMeasureStorage.has(bucket);
3207
3223
  const instance = this.getMeasureStorage(bucket);
3208
3224
  await instance.waitForInit(isInitial);
@@ -3216,7 +3232,7 @@ class PersistMeasureUtils {
3216
3232
  * @param Ctor - Custom IPersistMeasureInstance constructor
3217
3233
  */
3218
3234
  usePersistMeasureAdapter(Ctor) {
3219
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
3235
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
3220
3236
  this.PersistMeasureInstanceCtor = Ctor;
3221
3237
  this.getMeasureStorage.clear();
3222
3238
  }
@@ -3228,7 +3244,7 @@ class PersistMeasureUtils {
3228
3244
  * @returns AsyncGenerator yielding entry keys
3229
3245
  */
3230
3246
  async *listMeasureData(bucket) {
3231
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3247
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3232
3248
  const isInitial = !this.getMeasureStorage.has(bucket);
3233
3249
  const instance = this.getMeasureStorage(bucket);
3234
3250
  await instance.waitForInit(isInitial);
@@ -3239,21 +3255,21 @@ class PersistMeasureUtils {
3239
3255
  * Call when process.cwd() changes between strategy iterations.
3240
3256
  */
3241
3257
  clear() {
3242
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
3258
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
3243
3259
  this.getMeasureStorage.clear();
3244
3260
  }
3245
3261
  /**
3246
3262
  * Switches to the default file-based PersistMeasureInstance.
3247
3263
  */
3248
3264
  useJson() {
3249
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
3265
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
3250
3266
  this.usePersistMeasureAdapter(PersistMeasureInstance);
3251
3267
  }
3252
3268
  /**
3253
3269
  * Switches to PersistMeasureDummyInstance (all operations are no-ops).
3254
3270
  */
3255
3271
  useDummy() {
3256
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
3272
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
3257
3273
  this.usePersistMeasureAdapter(PersistMeasureDummyInstance);
3258
3274
  }
3259
3275
  }
@@ -3412,7 +3428,7 @@ class PersistIntervalUtils {
3412
3428
  * @returns Promise resolving to marker data, or null if not found / soft-deleted
3413
3429
  */
3414
3430
  this.readIntervalData = async (bucket, key) => {
3415
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3431
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3416
3432
  const isInitial = !this.getIntervalStorage.has(bucket);
3417
3433
  const instance = this.getIntervalStorage(bucket);
3418
3434
  await instance.waitForInit(isInitial);
@@ -3428,7 +3444,7 @@ class PersistIntervalUtils {
3428
3444
  * @returns Promise that resolves when write is complete
3429
3445
  */
3430
3446
  this.writeIntervalData = async (data, bucket, key, when) => {
3431
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3447
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3432
3448
  const isInitial = !this.getIntervalStorage.has(bucket);
3433
3449
  const instance = this.getIntervalStorage(bucket);
3434
3450
  await instance.waitForInit(isInitial);
@@ -3443,7 +3459,7 @@ class PersistIntervalUtils {
3443
3459
  * @returns Promise that resolves when removal is complete
3444
3460
  */
3445
3461
  this.removeIntervalData = async (bucket, key) => {
3446
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3462
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3447
3463
  const isInitial = !this.getIntervalStorage.has(bucket);
3448
3464
  const instance = this.getIntervalStorage(bucket);
3449
3465
  await instance.waitForInit(isInitial);
@@ -3457,7 +3473,7 @@ class PersistIntervalUtils {
3457
3473
  * @param Ctor - Custom IPersistIntervalInstance constructor
3458
3474
  */
3459
3475
  usePersistIntervalAdapter(Ctor) {
3460
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
3476
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
3461
3477
  this.PersistIntervalInstanceCtor = Ctor;
3462
3478
  this.getIntervalStorage.clear();
3463
3479
  }
@@ -3469,7 +3485,7 @@ class PersistIntervalUtils {
3469
3485
  * @returns AsyncGenerator yielding marker keys
3470
3486
  */
3471
3487
  async *listIntervalData(bucket) {
3472
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3488
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3473
3489
  const isInitial = !this.getIntervalStorage.has(bucket);
3474
3490
  const instance = this.getIntervalStorage(bucket);
3475
3491
  await instance.waitForInit(isInitial);
@@ -3480,21 +3496,21 @@ class PersistIntervalUtils {
3480
3496
  * Call when process.cwd() changes between strategy iterations.
3481
3497
  */
3482
3498
  clear() {
3483
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
3499
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
3484
3500
  this.getIntervalStorage.clear();
3485
3501
  }
3486
3502
  /**
3487
3503
  * Switches to the default file-based PersistIntervalInstance.
3488
3504
  */
3489
3505
  useJson() {
3490
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
3506
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
3491
3507
  this.usePersistIntervalAdapter(PersistIntervalInstance);
3492
3508
  }
3493
3509
  /**
3494
3510
  * Switches to PersistIntervalDummyInstance (all operations are no-ops).
3495
3511
  */
3496
3512
  useDummy() {
3497
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
3513
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
3498
3514
  this.usePersistIntervalAdapter(PersistIntervalDummyInstance);
3499
3515
  }
3500
3516
  }
@@ -3700,7 +3716,7 @@ class PersistMemoryUtils {
3700
3716
  * @returns Promise resolving to entry data, or null if not found / soft-deleted
3701
3717
  */
3702
3718
  this.readMemoryData = async (signalId, bucketName, memoryId) => {
3703
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
3719
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
3704
3720
  const key = `${signalId}:${bucketName}`;
3705
3721
  const isInitial = !this.getMemoryStorage.has(key);
3706
3722
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3717,7 +3733,7 @@ class PersistMemoryUtils {
3717
3733
  * @returns Promise resolving to true if entry exists
3718
3734
  */
3719
3735
  this.hasMemoryData = async (signalId, bucketName, memoryId) => {
3720
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
3736
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
3721
3737
  const key = `${signalId}:${bucketName}`;
3722
3738
  const isInitial = !this.getMemoryStorage.has(key);
3723
3739
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3736,7 +3752,7 @@ class PersistMemoryUtils {
3736
3752
  * @returns Promise that resolves when write is complete
3737
3753
  */
3738
3754
  this.writeMemoryData = async (data, signalId, bucketName, memoryId, when) => {
3739
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
3755
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
3740
3756
  const key = `${signalId}:${bucketName}`;
3741
3757
  const isInitial = !this.getMemoryStorage.has(key);
3742
3758
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3753,7 +3769,7 @@ class PersistMemoryUtils {
3753
3769
  * @returns Promise that resolves when removal is complete
3754
3770
  */
3755
3771
  this.removeMemoryData = async (signalId, bucketName, memoryId) => {
3756
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
3772
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
3757
3773
  const key = `${signalId}:${bucketName}`;
3758
3774
  const isInitial = !this.getMemoryStorage.has(key);
3759
3775
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3765,7 +3781,7 @@ class PersistMemoryUtils {
3765
3781
  * Call when process.cwd() changes between strategy iterations.
3766
3782
  */
3767
3783
  this.clear = () => {
3768
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
3784
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
3769
3785
  this.getMemoryStorage.clear();
3770
3786
  };
3771
3787
  /**
@@ -3776,7 +3792,7 @@ class PersistMemoryUtils {
3776
3792
  * @param bucketName - Bucket name
3777
3793
  */
3778
3794
  this.dispose = (signalId, bucketName) => {
3779
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
3795
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
3780
3796
  const key = `${signalId}:${bucketName}`;
3781
3797
  this.getMemoryStorage.clear(key);
3782
3798
  };
@@ -3788,7 +3804,7 @@ class PersistMemoryUtils {
3788
3804
  * @param Ctor - Custom IPersistMemoryInstance constructor
3789
3805
  */
3790
3806
  usePersistMemoryAdapter(Ctor) {
3791
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
3807
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
3792
3808
  this.PersistMemoryInstanceCtor = Ctor;
3793
3809
  this.getMemoryStorage.clear();
3794
3810
  }
@@ -3802,7 +3818,7 @@ class PersistMemoryUtils {
3802
3818
  * @returns AsyncGenerator yielding `{ memoryId, data }` tuples
3803
3819
  */
3804
3820
  async *listMemoryData(signalId, bucketName) {
3805
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
3821
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
3806
3822
  const key = `${signalId}:${bucketName}`;
3807
3823
  const isInitial = !this.getMemoryStorage.has(key);
3808
3824
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3813,14 +3829,14 @@ class PersistMemoryUtils {
3813
3829
  * Switches to the default file-based PersistMemoryInstance.
3814
3830
  */
3815
3831
  useJson() {
3816
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
3832
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
3817
3833
  this.usePersistMemoryAdapter(PersistMemoryInstance);
3818
3834
  }
3819
3835
  /**
3820
3836
  * Switches to PersistMemoryDummyInstance (all operations are no-ops).
3821
3837
  */
3822
3838
  useDummy() {
3823
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
3839
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
3824
3840
  this.usePersistMemoryAdapter(PersistMemoryDummyInstance);
3825
3841
  }
3826
3842
  }
@@ -3969,7 +3985,7 @@ class PersistRecentUtils {
3969
3985
  * @returns Promise resolving to recent signal or null if none persisted
3970
3986
  */
3971
3987
  this.readRecentData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
3972
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
3988
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
3973
3989
  const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
3974
3990
  const isInitial = !this.getStorage.has(key);
3975
3991
  const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
@@ -3990,7 +4006,7 @@ class PersistRecentUtils {
3990
4006
  * @returns Promise that resolves when write is complete
3991
4007
  */
3992
4008
  this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest, when) => {
3993
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
4009
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
3994
4010
  const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
3995
4011
  const isInitial = !this.getStorage.has(key);
3996
4012
  const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
@@ -4023,7 +4039,7 @@ class PersistRecentUtils {
4023
4039
  * @param Ctor - Custom IPersistRecentInstance constructor
4024
4040
  */
4025
4041
  usePersistRecentAdapter(Ctor) {
4026
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
4042
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
4027
4043
  this.PersistRecentInstanceCtor = Ctor;
4028
4044
  this.getStorage.clear();
4029
4045
  }
@@ -4032,21 +4048,21 @@ class PersistRecentUtils {
4032
4048
  * Call when process.cwd() changes between strategy iterations.
4033
4049
  */
4034
4050
  clear() {
4035
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
4051
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
4036
4052
  this.getStorage.clear();
4037
4053
  }
4038
4054
  /**
4039
4055
  * Switches to the default file-based PersistRecentInstance.
4040
4056
  */
4041
4057
  useJson() {
4042
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
4058
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
4043
4059
  this.usePersistRecentAdapter(PersistRecentInstance);
4044
4060
  }
4045
4061
  /**
4046
4062
  * Switches to PersistRecentDummyInstance (all operations are no-ops).
4047
4063
  */
4048
4064
  useDummy() {
4049
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
4065
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
4050
4066
  this.usePersistRecentAdapter(PersistRecentDummyInstance);
4051
4067
  }
4052
4068
  }
@@ -4181,7 +4197,7 @@ class PersistStateUtils {
4181
4197
  * @returns Promise that resolves when initialization is complete
4182
4198
  */
4183
4199
  this.waitForInit = async (signalId, bucketName, initial) => {
4184
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
4200
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
4185
4201
  const key = `${signalId}:${bucketName}`;
4186
4202
  const isInitial = initial && !this.getStateStorage.has(key);
4187
4203
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4196,7 +4212,7 @@ class PersistStateUtils {
4196
4212
  * @returns Promise resolving to state data or null if none persisted
4197
4213
  */
4198
4214
  this.readStateData = async (signalId, bucketName) => {
4199
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
4215
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
4200
4216
  const key = `${signalId}:${bucketName}`;
4201
4217
  const isInitial = !this.getStateStorage.has(key);
4202
4218
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4214,7 +4230,7 @@ class PersistStateUtils {
4214
4230
  * @returns Promise that resolves when write is complete
4215
4231
  */
4216
4232
  this.writeStateData = async (data, signalId, bucketName, when) => {
4217
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
4233
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
4218
4234
  const key = `${signalId}:${bucketName}`;
4219
4235
  const isInitial = !this.getStateStorage.has(key);
4220
4236
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4225,14 +4241,14 @@ class PersistStateUtils {
4225
4241
  * Switches to PersistStateDummyInstance (all operations are no-ops).
4226
4242
  */
4227
4243
  this.useDummy = () => {
4228
- LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
4244
+ LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
4229
4245
  this.usePersistStateAdapter(PersistStateDummyInstance);
4230
4246
  };
4231
4247
  /**
4232
4248
  * Switches to the default file-based PersistStateInstance.
4233
4249
  */
4234
4250
  this.useJson = () => {
4235
- LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
4251
+ LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
4236
4252
  this.usePersistStateAdapter(PersistStateInstance);
4237
4253
  };
4238
4254
  /**
@@ -4240,7 +4256,7 @@ class PersistStateUtils {
4240
4256
  * Call when process.cwd() changes between strategy iterations.
4241
4257
  */
4242
4258
  this.clear = () => {
4243
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
4259
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
4244
4260
  this.getStateStorage.clear();
4245
4261
  };
4246
4262
  /**
@@ -4251,7 +4267,7 @@ class PersistStateUtils {
4251
4267
  * @param bucketName - Bucket name
4252
4268
  */
4253
4269
  this.dispose = (signalId, bucketName) => {
4254
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
4270
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
4255
4271
  const key = `${signalId}:${bucketName}`;
4256
4272
  this.getStateStorage.clear(key);
4257
4273
  };
@@ -4263,7 +4279,7 @@ class PersistStateUtils {
4263
4279
  * @param Ctor - Custom IPersistStateInstance constructor
4264
4280
  */
4265
4281
  usePersistStateAdapter(Ctor) {
4266
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
4282
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
4267
4283
  this.PersistStateInstanceCtor = Ctor;
4268
4284
  this.getStateStorage.clear();
4269
4285
  }
@@ -4403,7 +4419,7 @@ class PersistSessionUtils {
4403
4419
  * @returns Promise that resolves when initialization is complete
4404
4420
  */
4405
4421
  this.waitForInit = async (strategyName, exchangeName, frameName, initial) => {
4406
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
4422
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
4407
4423
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4408
4424
  const isInitial = initial && !this.getSessionStorage.has(key);
4409
4425
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4419,7 +4435,7 @@ class PersistSessionUtils {
4419
4435
  * @returns Promise resolving to session data or null if none persisted
4420
4436
  */
4421
4437
  this.readSessionData = async (strategyName, exchangeName, frameName) => {
4422
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
4438
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
4423
4439
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4424
4440
  const isInitial = !this.getSessionStorage.has(key);
4425
4441
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4438,7 +4454,7 @@ class PersistSessionUtils {
4438
4454
  * @returns Promise that resolves when write is complete
4439
4455
  */
4440
4456
  this.writeSessionData = async (data, strategyName, exchangeName, frameName, when) => {
4441
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
4457
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
4442
4458
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4443
4459
  const isInitial = !this.getSessionStorage.has(key);
4444
4460
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4449,14 +4465,14 @@ class PersistSessionUtils {
4449
4465
  * Switches to PersistSessionDummyInstance (all operations are no-ops).
4450
4466
  */
4451
4467
  this.useDummy = () => {
4452
- LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
4468
+ LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
4453
4469
  this.usePersistSessionAdapter(PersistSessionDummyInstance);
4454
4470
  };
4455
4471
  /**
4456
4472
  * Switches to the default file-based PersistSessionInstance.
4457
4473
  */
4458
4474
  this.useJson = () => {
4459
- LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
4475
+ LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
4460
4476
  this.usePersistSessionAdapter(PersistSessionInstance);
4461
4477
  };
4462
4478
  /**
@@ -4464,7 +4480,7 @@ class PersistSessionUtils {
4464
4480
  * Call when process.cwd() changes between strategy iterations.
4465
4481
  */
4466
4482
  this.clear = () => {
4467
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
4483
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
4468
4484
  this.getSessionStorage.clear();
4469
4485
  };
4470
4486
  /**
@@ -4476,7 +4492,7 @@ class PersistSessionUtils {
4476
4492
  * @param frameName - Frame identifier
4477
4493
  */
4478
4494
  this.dispose = (strategyName, exchangeName, frameName) => {
4479
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
4495
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
4480
4496
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4481
4497
  this.getSessionStorage.clear(key);
4482
4498
  };
@@ -4488,7 +4504,7 @@ class PersistSessionUtils {
4488
4504
  * @param Ctor - Custom IPersistSessionInstance constructor
4489
4505
  */
4490
4506
  usePersistSessionAdapter(Ctor) {
4491
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
4507
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
4492
4508
  this.PersistSessionInstanceCtor = Ctor;
4493
4509
  this.getSessionStorage.clear();
4494
4510
  }
@@ -4500,28 +4516,39 @@ class PersistSessionUtils {
4500
4516
  const PersistSessionAdapter = new PersistSessionUtils();
4501
4517
 
4502
4518
  var _a$2, _b$2;
4503
- const BUSY_DELAY = 100;
4504
4519
  const SET_BUSY_SYMBOL = Symbol("setBusy");
4505
4520
  const GET_BUSY_SYMBOL = Symbol("getBusy");
4506
4521
  const ACQUIRE_LOCK_SYMBOL = Symbol("acquireLock");
4507
4522
  const RELEASE_LOCK_SYMBOL = Symbol("releaseLock");
4523
+ /**
4524
+ * Body of the queued acquire operation.
4525
+ *
4526
+ * Parks the caller on `self._tick` whenever the lock is already busy: each
4527
+ * `releaseLock` emits on `_tick`, waking exactly the next queued acquirer
4528
+ * instead of polling on a fixed delay. The busy counter is bumped only after
4529
+ * the loop exits, so re-entry checks remain coherent under contention.
4530
+ *
4531
+ * @param self - The owning {@link Lock} instance.
4532
+ */
4508
4533
  const ACQUIRE_LOCK_FN = async (self) => {
4509
4534
  while (self[GET_BUSY_SYMBOL]()) {
4510
- await sleep(BUSY_DELAY);
4535
+ // @ts-ignore
4536
+ await self._tick.toPromise();
4511
4537
  }
4512
4538
  self[SET_BUSY_SYMBOL](true);
4513
4539
  };
4514
4540
  /**
4515
4541
  * Mutual exclusion primitive for async TypeScript code.
4516
4542
  *
4517
- * Provides a reentrant-safe, queued lock that serializes access to a critical
4518
- * section across concurrent async callers. Internally tracks a busy counter so
4519
- * nested acquire/release pairs are detected and mis-matched releases throw
4520
- * immediately.
4543
+ * Provides a queued lock that serializes access to a critical section across
4544
+ * concurrent async callers. Wake-ups are event-driven (via an internal
4545
+ * `_tick` subject emitted on every `releaseLock`) rather than polling,
4546
+ * so contention does not incur a fixed delay.
4521
4547
  *
4522
- * Three usage styles are supported:
4548
+ * The busy counter detects mis-matched releases and throws immediately on
4549
+ * extra `releaseLock` calls.
4523
4550
  *
4524
- * **Manual acquire / release**
4551
+ * **Usage**
4525
4552
  * ```ts
4526
4553
  * await lock.acquireLock();
4527
4554
  * try {
@@ -4536,7 +4563,18 @@ const ACQUIRE_LOCK_FN = async (self) => {
4536
4563
  */
4537
4564
  class Lock {
4538
4565
  constructor() {
4566
+ /**
4567
+ * Outstanding acquires that have not yet been released.
4568
+ * Incremented in `[SET_BUSY_SYMBOL](true)`, decremented in `[SET_BUSY_SYMBOL](false)`.
4569
+ * A negative value indicates an extra `releaseLock` and throws on detection.
4570
+ */
4539
4571
  this._isBusy = 0;
4572
+ /**
4573
+ * Wake-up channel for {@link ACQUIRE_LOCK_FN}.
4574
+ * Every {@link releaseLock} emits a single tick that unblocks the next
4575
+ * queued acquirer parked on `toPromise()`.
4576
+ */
4577
+ this._tick = new Subject();
4540
4578
  this[_a$2] = queued(ACQUIRE_LOCK_FN);
4541
4579
  this[_b$2] = () => this[SET_BUSY_SYMBOL](false);
4542
4580
  /**
@@ -4557,16 +4595,19 @@ class Lock {
4557
4595
  await this[ACQUIRE_LOCK_SYMBOL](this);
4558
4596
  };
4559
4597
  /**
4560
- * Releases the lock previously acquired with {@link acquireLock}.
4598
+ * Releases the lock previously acquired with {@link acquireLock} and emits
4599
+ * on the internal `_tick` subject to wake the next queued acquirer.
4600
+ *
4561
4601
  * Must be called exactly once per successful {@link acquireLock} call,
4562
- * typically inside a `finally` block. Throws if called more times
4563
- * than the lock was acquired.
4602
+ * typically inside a `finally` block. Throws if called more times than
4603
+ * the lock was acquired.
4564
4604
  *
4565
4605
  * @returns {Promise<void>} Resolves once the lock has been released.
4566
4606
  * @throws {Error} If the lock is released more times than it was acquired.
4567
4607
  */
4568
4608
  this.releaseLock = async () => {
4569
4609
  await this[RELEASE_LOCK_SYMBOL]();
4610
+ await this._tick.next();
4570
4611
  };
4571
4612
  }
4572
4613
  [SET_BUSY_SYMBOL](isBusy) {
@@ -4581,18 +4622,166 @@ class Lock {
4581
4622
  }
4582
4623
  _a$2 = ACQUIRE_LOCK_SYMBOL, _b$2 = RELEASE_LOCK_SYMBOL;
4583
4624
 
4625
+ const METHOD_NAME_ADD_ACTIVITY = "LookupUtils.addActivity";
4626
+ const METHOD_NAME_REMOVE_ACTIVITY = "LookupUtils.removeActivity";
4627
+ const METHOD_NAME_LIST_ACTIVITY = "LookupUtils.listActivity";
4628
+ /** Logger service injected as DI singleton */
4629
+ const LOGGER_SERVICE$7 = new LoggerService();
4630
+ /**
4631
+ * Builds the composite {@link Key} used to register an activity in `_lookupMap`.
4632
+ *
4633
+ * Mirrors the {@link Key} type construction: appends `frameName` only when provided
4634
+ * (typical for backtest), then a `"backtest"` / `"live"` discriminator suffix.
4635
+ *
4636
+ * @param symbol - Trading pair symbol.
4637
+ * @param strategyName - Strategy schema name.
4638
+ * @param exchangeName - Exchange schema name.
4639
+ * @param frameName - Frame schema name; omitted from the key when falsy.
4640
+ * @param backtest - `true` for backtest, `false` for live.
4641
+ * @returns Colon-joined composite key.
4642
+ */
4643
+ const CREATE_KEY_FN$y = (symbol, strategyName, exchangeName, frameName, backtest) => {
4644
+ const parts = [symbol, strategyName, exchangeName];
4645
+ if (frameName)
4646
+ parts.push(frameName);
4647
+ parts.push(backtest ? "backtest" : "live");
4648
+ return parts.join(":");
4649
+ };
4650
+ /**
4651
+ * In-memory registry of currently running backtest and live activities.
4652
+ *
4653
+ * Purpose:
4654
+ * - Each `Backtest.run` / `Live.run` / per-strategy walker iteration registers an
4655
+ * {@link IActivityEntry} on start and removes it on completion.
4656
+ * - `Candle.spinLock` consults {@link isParallel} to decide whether the event-loop
4657
+ * hand-off (post-candle-fetch spin) is worth performing. With a single active
4658
+ * workload there is no peer to yield to, so the spin is skipped entirely.
4659
+ *
4660
+ * Exposed as the `Lookup` singleton; no constructor parameters.
4661
+ *
4662
+ * @example
4663
+ * ```typescript
4664
+ * Lookup.addActivity({ symbol: "BTCUSDT", context, backtest: true });
4665
+ * try {
4666
+ * for await (const _ of run(symbol, context)) { ... }
4667
+ * } finally {
4668
+ * Lookup.removeActivity({ symbol: "BTCUSDT", context, backtest: true });
4669
+ * }
4670
+ * ```
4671
+ */
4672
+ class LookupUtils {
4673
+ constructor() {
4674
+ /** Active entries keyed by their composite {@link Key}. */
4675
+ this._lookupMap = new Map();
4676
+ /**
4677
+ * Registers a backtest or live activity in the lookup map.
4678
+ * Idempotent for identical keys — duplicate calls overwrite the existing entry.
4679
+ *
4680
+ * @param activity - Activity descriptor identifying the running workload.
4681
+ */
4682
+ this.addActivity = (activity) => {
4683
+ LOGGER_SERVICE$7.info(METHOD_NAME_ADD_ACTIVITY, {
4684
+ activity,
4685
+ });
4686
+ const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
4687
+ this._lookupMap.set(key, activity);
4688
+ };
4689
+ /**
4690
+ * Removes a previously registered activity from the lookup map.
4691
+ * Must be paired with a prior {@link addActivity}, typically in a `finally` block,
4692
+ * so a thrown error in the underlying run does not leave a stale entry behind.
4693
+ *
4694
+ * @param activity - Activity descriptor matching the one passed to {@link addActivity}.
4695
+ */
4696
+ this.removeActivity = (activity) => {
4697
+ LOGGER_SERVICE$7.info(METHOD_NAME_REMOVE_ACTIVITY, {
4698
+ activity,
4699
+ });
4700
+ const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
4701
+ this._lookupMap.delete(key);
4702
+ };
4703
+ /**
4704
+ * Returns a snapshot of currently active entries.
4705
+ *
4706
+ * @returns Array of all activities present in the lookup map at call time.
4707
+ */
4708
+ this.listActivity = () => {
4709
+ LOGGER_SERVICE$7.info(METHOD_NAME_LIST_ACTIVITY);
4710
+ return Array.from(this._lookupMap.values());
4711
+ };
4712
+ }
4713
+ /**
4714
+ * `true` when more than one activity is currently registered.
4715
+ * Used by `Candle.spinLock` to decide whether yielding the event loop is useful.
4716
+ */
4717
+ get isParallel() {
4718
+ return this._lookupMap.size > 1;
4719
+ }
4720
+ }
4721
+ /**
4722
+ * Process-wide singleton instance of {@link LookupUtils}.
4723
+ * Imported by `Backtest`, `Live`, `WalkerLogicPrivateService` (registration sites)
4724
+ * and by `Candle` (read-only consumer via `isParallel`).
4725
+ */
4726
+ const Lookup = new LookupUtils();
4727
+
4584
4728
  const METHOD_NAME_ACQUIRE_LOCK = "CandleUtils.acquireLock";
4585
4729
  const METHOD_NAME_RELEASE_LOCK = "CandleUtils.releaseLock";
4730
+ const METHOD_NAME_SPIN_LOCK = "CandleUtils.spinLock";
4731
+ /**
4732
+ * Upper bound (ms) on how long `spinLock` may park before falling through.
4733
+ * If no peer backtest acquires the candle-fetch mutex within this window,
4734
+ * the spinner proceeds without further yielding.
4735
+ */
4736
+ const ROTATE_DELAY = 50;
4586
4737
  /** Logger service injected as DI singleton */
4587
4738
  const LOGGER_SERVICE$6 = new LoggerService();
4739
+ /**
4740
+ * Process-wide coordinator for candle-fetch serialization and cooperative
4741
+ * yielding between parallel backtests.
4742
+ *
4743
+ * Two complementary primitives are exposed:
4744
+ * - **Mutex** via {@link acquireLock} / {@link releaseLock}: prevents concurrent
4745
+ * candle fetches from racing on the same exchange.
4746
+ * - **Spin hand-off** via {@link spinLock}: invoked after a fetch completes to
4747
+ * give peer backtests waiting on the mutex a chance to run, so multiple
4748
+ * `Backtest.run` workloads interleave instead of one monopolizing the loop.
4749
+ *
4750
+ * All three operations are no-ops when `CC_ENABLE_CANDLE_FETCH_MUTEX` is `false`.
4751
+ * The spin additionally requires `CC_ENABLE_BACKTEST_PARALLEL_SPIN` and at least
4752
+ * two registered activities in `Lookup` (see `Lookup.isParallel`).
4753
+ *
4754
+ * @example
4755
+ * ```typescript
4756
+ * await Candle.acquireLock("ClientExchange GET_CANDLES_FN");
4757
+ * try {
4758
+ * const candles = await fetchFromExchange(...);
4759
+ * return candles;
4760
+ * } finally {
4761
+ * await Candle.releaseLock("ClientExchange GET_CANDLES_FN");
4762
+ * }
4763
+ * // Elsewhere, after a fetch completes inside a backtest loop:
4764
+ * await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
4765
+ * ```
4766
+ */
4588
4767
  class CandleUtils {
4589
4768
  constructor() {
4769
+ /** Underlying mutex serializing candle fetches across concurrent callers. */
4590
4770
  this._lock = new Lock();
4591
4771
  /**
4592
- * Acquires the candle fetch mutex if CC_ENABLE_CANDLE_FETCH_MUTEX is enabled.
4772
+ * Emits whenever {@link acquireLock} successfully takes the mutex.
4773
+ * Awaited by {@link spinLock} to detect that a peer backtest has just
4774
+ * started its own fetch — the signal that yielding now will be productive.
4775
+ */
4776
+ this._spin = new Subject();
4777
+ /**
4778
+ * Acquires the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
4593
4779
  * Prevents concurrent candle fetches from the same exchange.
4594
4780
  *
4595
- * @param source - Caller identifier for logging
4781
+ * On successful acquisition, emits on the internal spin subject so any
4782
+ * peer parked inside {@link spinLock} can wake up and proceed.
4783
+ *
4784
+ * @param source - Caller identifier for logging.
4596
4785
  */
4597
4786
  this.acquireLock = async (source) => {
4598
4787
  LOGGER_SERVICE$6.info(METHOD_NAME_ACQUIRE_LOCK, {
@@ -4601,13 +4790,14 @@ class CandleUtils {
4601
4790
  if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
4602
4791
  return;
4603
4792
  }
4604
- return await this._lock.acquireLock();
4793
+ await this._lock.acquireLock();
4794
+ await this._spin.next();
4605
4795
  };
4606
4796
  /**
4607
- * Releases the candle fetch mutex if CC_ENABLE_CANDLE_FETCH_MUTEX is enabled.
4608
- * Must be called after acquireLock, typically in a finally block.
4797
+ * Releases the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
4798
+ * Must be called after {@link acquireLock}, typically in a `finally` block.
4609
4799
  *
4610
- * @param source - Caller identifier for logging
4800
+ * @param source - Caller identifier for logging.
4611
4801
  */
4612
4802
  this.releaseLock = async (source) => {
4613
4803
  LOGGER_SERVICE$6.info(METHOD_NAME_RELEASE_LOCK, {
@@ -4618,8 +4808,47 @@ class CandleUtils {
4618
4808
  }
4619
4809
  return await this._lock.releaseLock();
4620
4810
  };
4811
+ /**
4812
+ * Cooperative event-loop hand-off invoked by `BacktestLogicPrivateService`
4813
+ * after a successful `getNextCandles`. Allows peer backtests waiting on the
4814
+ * candle-fetch mutex to run before the current backtest fetches the next chunk.
4815
+ *
4816
+ * Waits for one of:
4817
+ * - a peer calling {@link acquireLock} (signalled via the spin subject), or
4818
+ * - a `ROTATE_DELAY` ms timeout, so the caller never parks indefinitely.
4819
+ *
4820
+ * Returns immediately as a no-op when any of these is true:
4821
+ * - `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled (mutex is off entirely),
4822
+ * - `CC_ENABLE_BACKTEST_PARALLEL_SPIN` is disabled (cooperative yielding off),
4823
+ * - `Lookup.isParallel` is `false` (only one active workload — no peer to yield to).
4824
+ *
4825
+ * @param source - Caller identifier for logging.
4826
+ */
4827
+ this.spinLock = async (source) => {
4828
+ LOGGER_SERVICE$6.info(METHOD_NAME_SPIN_LOCK, {
4829
+ source,
4830
+ });
4831
+ if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
4832
+ return;
4833
+ }
4834
+ if (!GLOBAL_CONFIG.CC_ENABLE_BACKTEST_PARALLEL_SPIN) {
4835
+ return;
4836
+ }
4837
+ if (!Lookup.isParallel) {
4838
+ return;
4839
+ }
4840
+ await Promise.race([
4841
+ this._spin.toPromise(),
4842
+ sleep(ROTATE_DELAY),
4843
+ ]);
4844
+ };
4621
4845
  }
4622
4846
  }
4847
+ /**
4848
+ * Process-wide singleton instance of {@link CandleUtils}.
4849
+ * Imported by `ClientExchange` (mutex around exchange fetches) and by
4850
+ * `BacktestLogicPrivateService` (spin hand-off between parallel backtests).
4851
+ */
4623
4852
  const Candle = new CandleUtils();
4624
4853
 
4625
4854
  const MS_PER_MINUTE$7 = 60000;
@@ -19153,9 +19382,28 @@ const TICK_FN = async (self, symbol, when) => {
19153
19382
  return { type: "error", __error__: SYMBOL_FN_ERROR, reason: "TICK_FN", message: getErrorMessage(error) };
19154
19383
  }
19155
19384
  };
19385
+ /**
19386
+ * Wraps `exchangeCoreService.getNextCandles` with error capture and a cooperative
19387
+ * event-loop hand-off after a successful fetch.
19388
+ *
19389
+ * Calls `Candle.spinLock(...)` on success: when multiple backtests run in parallel
19390
+ * (`Lookup.isParallel === true`), this yields the event loop so a peer waiting on
19391
+ * the candle-fetch mutex can take its turn, producing round-robin interleaving
19392
+ * instead of one backtest monopolizing the loop until completion. The spin is a
19393
+ * no-op for single-workload runs.
19394
+ *
19395
+ * @param self - Owning service instance, used for logging and exchange access.
19396
+ * @param symbol - Trading pair symbol.
19397
+ * @param candlesNeeded - Number of 1m candles to request.
19398
+ * @param bufferStartTime - Inclusive start time for the fetch window.
19399
+ * @param logMeta - Extra structured fields appended to the warn log on failure.
19400
+ * @returns Fetched candles, or a {@link TFnError} discriminated union on failure.
19401
+ */
19156
19402
  const GET_CANDLES_FN = async (self, symbol, candlesNeeded, bufferStartTime, logMeta) => {
19157
19403
  try {
19158
- return await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
19404
+ const result = await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
19405
+ await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
19406
+ return result;
19159
19407
  }
19160
19408
  catch (error) {
19161
19409
  console.error(`backtestLogicPrivateService getNextCandles failed symbol=${symbol} strategyName=${self.methodContextService.context.strategyName} exchangeName=${self.methodContextService.context.exchangeName}`);
@@ -20041,6 +20289,15 @@ class WalkerLogicPrivateService {
20041
20289
  exchangeName: context.exchangeName,
20042
20290
  frameName: context.frameName,
20043
20291
  });
20292
+ Lookup.addActivity({
20293
+ symbol,
20294
+ context: {
20295
+ strategyName,
20296
+ exchangeName: context.exchangeName,
20297
+ frameName: context.frameName,
20298
+ },
20299
+ backtest: true,
20300
+ });
20044
20301
  try {
20045
20302
  await resolveDocuments(iterator);
20046
20303
  }
@@ -20056,6 +20313,17 @@ class WalkerLogicPrivateService {
20056
20313
  await CALL_STRATEGY_ERROR_CALLBACKS_FN(this, walkerSchema, strategyName, symbol, error);
20057
20314
  continue;
20058
20315
  }
20316
+ finally {
20317
+ Lookup.removeActivity({
20318
+ symbol,
20319
+ context: {
20320
+ strategyName,
20321
+ exchangeName: context.exchangeName,
20322
+ frameName: context.frameName,
20323
+ },
20324
+ backtest: true,
20325
+ });
20326
+ }
20059
20327
  this.loggerService.info("walkerLogicPrivateService backtest complete", {
20060
20328
  strategyName,
20061
20329
  symbol,
@@ -36075,6 +36343,7 @@ const Exchange = new ExchangeUtils();
36075
36343
 
36076
36344
  const WARM_CANDLES_METHOD_NAME = "cache.warmCandles";
36077
36345
  const CHECK_CANDLES_METHOD_NAME = "cache.checkCandles";
36346
+ const CACHE_CANDLES_METHOD_NAME = "cache.cacheCandles";
36078
36347
  const MS_PER_MINUTE$3 = 60000;
36079
36348
  const INTERVAL_MINUTES$3 = {
36080
36349
  "1m": 1,
@@ -36106,6 +36375,34 @@ const PRINT_PROGRESS_FN = (fetched, total, symbol, interval) => {
36106
36375
  process.stdout.write("\n");
36107
36376
  }
36108
36377
  };
36378
+ /**
36379
+ * Retry-wrapped pipeline: validates the cache via `checkCandles` and, on miss,
36380
+ * fills it via `warmCandles` and rethrows to trigger a retry pass that
36381
+ * re-validates the freshly cached range. Limited to 2 attempts.
36382
+ */
36383
+ const CACHE_CANDLES_FN = retry(async (interval, dto, onWarmStart, onCheckStart) => {
36384
+ try {
36385
+ onWarmStart && onWarmStart(dto.symbol, interval, dto.from, dto.to);
36386
+ await checkCandles({
36387
+ exchangeName: dto.exchangeName,
36388
+ from: dto.from,
36389
+ to: dto.to,
36390
+ symbol: dto.symbol,
36391
+ interval: interval,
36392
+ });
36393
+ }
36394
+ catch (error) {
36395
+ onCheckStart && onCheckStart(dto.symbol, interval, dto.from, dto.to);
36396
+ await warmCandles({
36397
+ symbol: dto.symbol,
36398
+ exchangeName: dto.exchangeName,
36399
+ from: dto.from,
36400
+ to: dto.to,
36401
+ interval: interval,
36402
+ });
36403
+ throw error;
36404
+ }
36405
+ }, 2);
36109
36406
  /**
36110
36407
  * Checks cached candle presence via the persist adapter.
36111
36408
  * Issues one ranged read; adapter-side `hasValue` covers each expected timestamp,
@@ -36181,6 +36478,34 @@ async function warmCandles(params) {
36181
36478
  PRINT_PROGRESS_FN(fetched, totalCandles, symbol, interval);
36182
36479
  }
36183
36480
  }
36481
+ /**
36482
+ * Ensures candles for the given range are present in persist storage.
36483
+ * Runs a check-then-warm pipeline with one retry: validates the cache first
36484
+ * and, on a miss, downloads the missing data and re-validates.
36485
+ *
36486
+ * @param params - Combined cache parameters with optional lifecycle callbacks
36487
+ */
36488
+ async function cacheCandles({ symbol, interval, from, to, exchangeName, onCheckStart = (symbol, interval, from, to) => {
36489
+ process.stdout.write("\n");
36490
+ process.stdout.write(`Checking candles cache for ${symbol} ${interval} from ${from} to ${to}\n`);
36491
+ }, onWarmStart = (symbol, interval, from, to) => {
36492
+ process.stdout.write("\n\n");
36493
+ process.stdout.write(`Caching candles for ${symbol} ${interval} from ${from} to ${to}\n`);
36494
+ }, }) {
36495
+ backtest.loggerService.info(CACHE_CANDLES_METHOD_NAME, {
36496
+ symbol,
36497
+ exchangeName,
36498
+ interval,
36499
+ from,
36500
+ to,
36501
+ });
36502
+ await CACHE_CANDLES_FN(interval, {
36503
+ exchangeName,
36504
+ from,
36505
+ to,
36506
+ symbol,
36507
+ }, onWarmStart, onCheckStart);
36508
+ }
36184
36509
 
36185
36510
  const METHOD_NAME = "validate.validate";
36186
36511
  /**
@@ -37392,7 +37717,19 @@ class BrokerProxy {
37392
37717
  */
37393
37718
  class BrokerAdapter {
37394
37719
  constructor() {
37395
- this._brokerInstance = null;
37720
+ /** Factory producing the active `BrokerProxy` instance */
37721
+ this._brokerFactory = () => null;
37722
+ /**
37723
+ * Lazily constructs the `BrokerProxy` from the registered factory and
37724
+ * memoizes the result via `singleshot`.
37725
+ *
37726
+ * The proxy is built on the first call and cached for all subsequent calls.
37727
+ * Returns `null` when no adapter has been registered via `useBrokerAdapter()`.
37728
+ *
37729
+ * Reset via `clear()` so the next call rebuilds from the current factory
37730
+ * (e.g. when `process.cwd()` changes between strategy iterations).
37731
+ */
37732
+ this.getInstance = singleshot(() => this._brokerFactory());
37396
37733
  /**
37397
37734
  * Forwards a signal-open event to the registered broker adapter.
37398
37735
  *
@@ -37426,7 +37763,10 @@ class BrokerAdapter {
37426
37763
  if (payload.backtest) {
37427
37764
  return;
37428
37765
  }
37429
- await this._brokerInstance?.onSignalOpenCommit(payload);
37766
+ const instance = this.getInstance();
37767
+ if (instance) {
37768
+ await instance.onSignalOpenCommit(payload);
37769
+ }
37430
37770
  };
37431
37771
  /**
37432
37772
  * Forwards a signal-close event to the registered broker adapter.
@@ -37464,7 +37804,10 @@ class BrokerAdapter {
37464
37804
  if (payload.backtest) {
37465
37805
  return;
37466
37806
  }
37467
- await this._brokerInstance?.onSignalCloseCommit(payload);
37807
+ const instance = this.getInstance();
37808
+ if (instance) {
37809
+ await instance.onSignalCloseCommit(payload);
37810
+ }
37468
37811
  };
37469
37812
  /**
37470
37813
  * Intercepts a partial-profit close before DI-core mutation.
@@ -37500,7 +37843,10 @@ class BrokerAdapter {
37500
37843
  if (payload.backtest) {
37501
37844
  return;
37502
37845
  }
37503
- await this._brokerInstance?.onPartialProfitCommit(payload);
37846
+ const instance = this.getInstance();
37847
+ if (instance) {
37848
+ await instance.onPartialProfitCommit(payload);
37849
+ }
37504
37850
  };
37505
37851
  /**
37506
37852
  * Intercepts a partial-loss close before DI-core mutation.
@@ -37536,7 +37882,10 @@ class BrokerAdapter {
37536
37882
  if (payload.backtest) {
37537
37883
  return;
37538
37884
  }
37539
- await this._brokerInstance?.onPartialLossCommit(payload);
37885
+ const instance = this.getInstance();
37886
+ if (instance) {
37887
+ await instance.onPartialLossCommit(payload);
37888
+ }
37540
37889
  };
37541
37890
  /**
37542
37891
  * Intercepts a trailing stop-loss update before DI-core mutation.
@@ -37572,7 +37921,10 @@ class BrokerAdapter {
37572
37921
  if (payload.backtest) {
37573
37922
  return;
37574
37923
  }
37575
- await this._brokerInstance?.onTrailingStopCommit(payload);
37924
+ const instance = this.getInstance();
37925
+ if (instance) {
37926
+ await instance.onTrailingStopCommit(payload);
37927
+ }
37576
37928
  };
37577
37929
  /**
37578
37930
  * Intercepts a trailing take-profit update before DI-core mutation.
@@ -37608,7 +37960,10 @@ class BrokerAdapter {
37608
37960
  if (payload.backtest) {
37609
37961
  return;
37610
37962
  }
37611
- await this._brokerInstance?.onTrailingTakeCommit(payload);
37963
+ const instance = this.getInstance();
37964
+ if (instance) {
37965
+ await instance.onTrailingTakeCommit(payload);
37966
+ }
37612
37967
  };
37613
37968
  /**
37614
37969
  * Intercepts a breakeven operation before DI-core mutation.
@@ -37645,7 +38000,10 @@ class BrokerAdapter {
37645
38000
  if (payload.backtest) {
37646
38001
  return;
37647
38002
  }
37648
- await this._brokerInstance?.onBreakevenCommit(payload);
38003
+ const instance = this.getInstance();
38004
+ if (instance) {
38005
+ await instance.onBreakevenCommit(payload);
38006
+ }
37649
38007
  };
37650
38008
  /**
37651
38009
  * Intercepts a DCA average-buy entry before DI-core mutation.
@@ -37681,7 +38039,10 @@ class BrokerAdapter {
37681
38039
  if (payload.backtest) {
37682
38040
  return;
37683
38041
  }
37684
- await this._brokerInstance?.onAverageBuyCommit(payload);
38042
+ const instance = this.getInstance();
38043
+ if (instance) {
38044
+ await instance.onAverageBuyCommit(payload);
38045
+ }
37685
38046
  };
37686
38047
  /**
37687
38048
  * Registers a broker adapter instance or constructor to receive commit* callbacks.
@@ -37705,11 +38066,12 @@ class BrokerAdapter {
37705
38066
  this.useBrokerAdapter = (broker) => {
37706
38067
  backtest.loggerService.info(BROKER_METHOD_NAME_USE_BROKER_ADAPTER, {});
37707
38068
  if (typeof broker === "function") {
37708
- const instance = Reflect.construct(broker, []);
37709
- this._brokerInstance = new BrokerProxy(instance);
37710
- return;
38069
+ this._brokerFactory = () => new BrokerProxy(Reflect.construct(broker, []));
37711
38070
  }
37712
- this._brokerInstance = new BrokerProxy(broker);
38071
+ else {
38072
+ this._brokerFactory = () => new BrokerProxy(broker);
38073
+ }
38074
+ this.getInstance.clear();
37713
38075
  };
37714
38076
  /**
37715
38077
  * Activates the broker: subscribes to syncSubject for signal-open / signal-close routing.
@@ -37736,7 +38098,8 @@ class BrokerAdapter {
37736
38098
  */
37737
38099
  this.enable = singleshot(() => {
37738
38100
  backtest.loggerService.info(BROKER_METHOD_NAME_ENABLE, {});
37739
- if (!this._brokerInstance) {
38101
+ const instance = this.getInstance();
38102
+ if (!instance) {
37740
38103
  this.enable.clear();
37741
38104
  throw new Error("No broker instance provided. Call Broker.useBrokerAdapter first.");
37742
38105
  }
@@ -37824,7 +38187,7 @@ class BrokerAdapter {
37824
38187
  */
37825
38188
  this.clear = () => {
37826
38189
  backtest.loggerService.info(BROKER_METHOD_NAME_CLEAR, {});
37827
- this._brokerInstance = null;
38190
+ this.getInstance.clear();
37828
38191
  this.enable.clear();
37829
38192
  };
37830
38193
  }
@@ -41928,11 +42291,21 @@ const INSTANCE_TASK_FN$2 = async (symbol, context, self) => {
41928
42291
  self._isStopped = false;
41929
42292
  self._isDone = false;
41930
42293
  }
42294
+ Lookup.addActivity({
42295
+ symbol,
42296
+ context,
42297
+ backtest: true,
42298
+ });
41931
42299
  for await (const _ of self.run(symbol, context)) {
41932
42300
  if (self._isStopped) {
41933
42301
  break;
41934
42302
  }
41935
42303
  }
42304
+ Lookup.removeActivity({
42305
+ symbol,
42306
+ context,
42307
+ backtest: true,
42308
+ });
41936
42309
  if (!self._isDone) {
41937
42310
  await doneBacktestSubject.next({
41938
42311
  exchangeName: context.exchangeName,
@@ -44579,11 +44952,21 @@ const INSTANCE_TASK_FN$1 = async (symbol, context, self) => {
44579
44952
  self._isStopped = false;
44580
44953
  self._isDone = false;
44581
44954
  }
44955
+ Lookup.addActivity({
44956
+ symbol,
44957
+ context,
44958
+ backtest: false,
44959
+ });
44582
44960
  for await (const signal of self.run(symbol, context)) {
44583
44961
  if (signal?.action === "closed" && self._isStopped) {
44584
44962
  break;
44585
44963
  }
44586
44964
  }
44965
+ Lookup.removeActivity({
44966
+ symbol,
44967
+ context,
44968
+ backtest: false,
44969
+ });
44587
44970
  if (!self._isDone) {
44588
44971
  await doneLiveSubject.next({
44589
44972
  exchangeName: context.exchangeName,
@@ -48844,8 +49227,16 @@ class RecentMemoryLiveUtils {
48844
49227
  */
48845
49228
  class RecentBacktestAdapter {
48846
49229
  constructor() {
48847
- /** Internal storage utils instance */
48848
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
49230
+ /** Factory producing the active storage utils instance */
49231
+ this._recentBacktestFactory = () => new RecentMemoryBacktestUtils();
49232
+ /**
49233
+ * Lazily constructs the storage utils from the registered factory and memoizes
49234
+ * the result via `singleshot`.
49235
+ *
49236
+ * The instance is built on the first call and cached for all subsequent calls.
49237
+ * Reset via `clear()` so the next call rebuilds from the current factory.
49238
+ */
49239
+ this.getInstance = singleshot(() => this._recentBacktestFactory());
48849
49240
  /**
48850
49241
  * Handles active ping event.
48851
49242
  * Proxies call to the underlying storage adapter.
@@ -48855,7 +49246,7 @@ class RecentBacktestAdapter {
48855
49246
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
48856
49247
  signalId: event.data.id,
48857
49248
  });
48858
- return await this._recentBacktestUtils.handleActivePing(event);
49249
+ return await this.getInstance().handleActivePing(event);
48859
49250
  };
48860
49251
  /**
48861
49252
  * Retrieves the latest signal for the given context.
@@ -48876,7 +49267,7 @@ class RecentBacktestAdapter {
48876
49267
  frameName,
48877
49268
  backtest: backtest$1,
48878
49269
  });
48879
- return await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
49270
+ return await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
48880
49271
  };
48881
49272
  /**
48882
49273
  * Returns the number of whole minutes elapsed since the latest signal's creation timestamp.
@@ -48900,7 +49291,7 @@ class RecentBacktestAdapter {
48900
49291
  backtest: backtest$1,
48901
49292
  timestamp,
48902
49293
  });
48903
- const signal = await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49294
+ const signal = await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
48904
49295
  if (!signal) {
48905
49296
  return null;
48906
49297
  }
@@ -48913,7 +49304,8 @@ class RecentBacktestAdapter {
48913
49304
  */
48914
49305
  this.useRecentAdapter = (Ctor) => {
48915
49306
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
48916
- this._recentBacktestUtils = Reflect.construct(Ctor, []);
49307
+ this._recentBacktestFactory = () => Reflect.construct(Ctor, []);
49308
+ this.getInstance.clear();
48917
49309
  };
48918
49310
  /**
48919
49311
  * Switches to persistent storage adapter.
@@ -48921,7 +49313,8 @@ class RecentBacktestAdapter {
48921
49313
  */
48922
49314
  this.usePersist = () => {
48923
49315
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
48924
- this._recentBacktestUtils = new RecentPersistBacktestUtils();
49316
+ this._recentBacktestFactory = () => new RecentPersistBacktestUtils();
49317
+ this.getInstance.clear();
48925
49318
  };
48926
49319
  /**
48927
49320
  * Switches to in-memory storage adapter (default).
@@ -48929,14 +49322,17 @@ class RecentBacktestAdapter {
48929
49322
  */
48930
49323
  this.useMemory = () => {
48931
49324
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
48932
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
49325
+ this._recentBacktestFactory = () => new RecentMemoryBacktestUtils();
49326
+ this.getInstance.clear();
48933
49327
  };
48934
49328
  /**
48935
- * Clears the cached utils instance by resetting to the default in-memory adapter.
49329
+ * Clears the memoized utils instance.
49330
+ * Call this when process.cwd() changes between strategy iterations
49331
+ * so a new instance is created with the updated base path.
48936
49332
  */
48937
49333
  this.clear = () => {
48938
49334
  backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
48939
- this._recentBacktestUtils = new RecentMemoryBacktestUtils();
49335
+ this.getInstance.clear();
48940
49336
  };
48941
49337
  }
48942
49338
  }
@@ -48951,8 +49347,16 @@ class RecentBacktestAdapter {
48951
49347
  */
48952
49348
  class RecentLiveAdapter {
48953
49349
  constructor() {
48954
- /** Internal storage utils instance */
48955
- this._recentLiveUtils = new RecentPersistLiveUtils();
49350
+ /** Factory producing the active storage utils instance */
49351
+ this._recentLiveFactory = () => new RecentPersistLiveUtils();
49352
+ /**
49353
+ * Lazily constructs the storage utils from the registered factory and memoizes
49354
+ * the result via `singleshot`.
49355
+ *
49356
+ * The instance is built on the first call and cached for all subsequent calls.
49357
+ * Reset via `clear()` so the next call rebuilds from the current factory.
49358
+ */
49359
+ this.getInstance = singleshot(() => this._recentLiveFactory());
48956
49360
  /**
48957
49361
  * Handles active ping event.
48958
49362
  * Proxies call to the underlying storage adapter.
@@ -48962,7 +49366,7 @@ class RecentLiveAdapter {
48962
49366
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
48963
49367
  signalId: event.data.id,
48964
49368
  });
48965
- return await this._recentLiveUtils.handleActivePing(event);
49369
+ return await this.getInstance().handleActivePing(event);
48966
49370
  };
48967
49371
  /**
48968
49372
  * Retrieves the latest signal for the given context.
@@ -48983,7 +49387,7 @@ class RecentLiveAdapter {
48983
49387
  frameName,
48984
49388
  backtest: backtest$1,
48985
49389
  });
48986
- return await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
49390
+ return await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, when);
48987
49391
  };
48988
49392
  /**
48989
49393
  * Returns the number of whole minutes elapsed since the latest signal's creation timestamp.
@@ -49007,7 +49411,7 @@ class RecentLiveAdapter {
49007
49411
  backtest: backtest$1,
49008
49412
  timestamp,
49009
49413
  });
49010
- const signal = await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49414
+ const signal = await this.getInstance().getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1, new Date(timestamp));
49011
49415
  if (!signal) {
49012
49416
  return null;
49013
49417
  }
@@ -49020,7 +49424,8 @@ class RecentLiveAdapter {
49020
49424
  */
49021
49425
  this.useRecentAdapter = (Ctor) => {
49022
49426
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
49023
- this._recentLiveUtils = Reflect.construct(Ctor, []);
49427
+ this._recentLiveFactory = () => Reflect.construct(Ctor, []);
49428
+ this.getInstance.clear();
49024
49429
  };
49025
49430
  /**
49026
49431
  * Switches to persistent storage adapter (default).
@@ -49028,7 +49433,8 @@ class RecentLiveAdapter {
49028
49433
  */
49029
49434
  this.usePersist = () => {
49030
49435
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
49031
- this._recentLiveUtils = new RecentPersistLiveUtils();
49436
+ this._recentLiveFactory = () => new RecentPersistLiveUtils();
49437
+ this.getInstance.clear();
49032
49438
  };
49033
49439
  /**
49034
49440
  * Switches to in-memory storage adapter.
@@ -49036,14 +49442,17 @@ class RecentLiveAdapter {
49036
49442
  */
49037
49443
  this.useMemory = () => {
49038
49444
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
49039
- this._recentLiveUtils = new RecentMemoryLiveUtils();
49445
+ this._recentLiveFactory = () => new RecentMemoryLiveUtils();
49446
+ this.getInstance.clear();
49040
49447
  };
49041
49448
  /**
49042
- * Clears the cached utils instance by resetting to the default persistent adapter.
49449
+ * Clears the memoized utils instance.
49450
+ * Call this when process.cwd() changes between strategy iterations
49451
+ * so a new instance is created with the updated base path.
49043
49452
  */
49044
49453
  this.clear = () => {
49045
49454
  backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_CLEAR);
49046
- this._recentLiveUtils = new RecentPersistLiveUtils();
49455
+ this.getInstance.clear();
49047
49456
  };
49048
49457
  }
49049
49458
  }
@@ -54368,16 +54777,26 @@ class LogDummyUtils {
54368
54777
  */
54369
54778
  class LogAdapter {
54370
54779
  constructor() {
54371
- /** Internal log utils instance */
54372
- this._log = new LogMemoryUtils();
54780
+ /** Factory producing the active log utils instance */
54781
+ this._logFactory = () => new LogMemoryUtils();
54782
+ /**
54783
+ * Lazily constructs the log utils from the registered factory and memoizes
54784
+ * the result via `singleshot`.
54785
+ *
54786
+ * The instance is built on the first call and cached for all subsequent calls.
54787
+ * Reset via `clear()` so the next call rebuilds from the current factory
54788
+ * (e.g. when `process.cwd()` changes between strategy iterations).
54789
+ */
54790
+ this.getInstance = singleshot(() => this._logFactory());
54373
54791
  /**
54374
54792
  * Lists all stored log entries.
54375
54793
  * Proxies call to the underlying log adapter.
54376
54794
  * @returns Array of all log entries
54377
54795
  */
54378
54796
  this.getList = async () => {
54379
- if (this._log.getList) {
54380
- return await this._log.getList();
54797
+ const log = this.getInstance();
54798
+ if (log.getList) {
54799
+ return await log.getList();
54381
54800
  }
54382
54801
  return [];
54383
54802
  };
@@ -54388,8 +54807,9 @@ class LogAdapter {
54388
54807
  * @param args - Additional arguments
54389
54808
  */
54390
54809
  this.log = (topic, ...args) => {
54391
- if (this._log.log) {
54392
- this._log.log(topic, ...args);
54810
+ const log = this.getInstance();
54811
+ if (log.log) {
54812
+ log.log(topic, ...args);
54393
54813
  }
54394
54814
  };
54395
54815
  /**
@@ -54399,8 +54819,9 @@ class LogAdapter {
54399
54819
  * @param args - Additional arguments
54400
54820
  */
54401
54821
  this.debug = (topic, ...args) => {
54402
- if (this._log.debug) {
54403
- this._log.debug(topic, ...args);
54822
+ const log = this.getInstance();
54823
+ if (log.debug) {
54824
+ log.debug(topic, ...args);
54404
54825
  }
54405
54826
  };
54406
54827
  /**
@@ -54410,8 +54831,9 @@ class LogAdapter {
54410
54831
  * @param args - Additional arguments
54411
54832
  */
54412
54833
  this.info = (topic, ...args) => {
54413
- if (this._log.info) {
54414
- this._log.info(topic, ...args);
54834
+ const log = this.getInstance();
54835
+ if (log.info) {
54836
+ log.info(topic, ...args);
54415
54837
  }
54416
54838
  };
54417
54839
  /**
@@ -54421,8 +54843,9 @@ class LogAdapter {
54421
54843
  * @param args - Additional arguments
54422
54844
  */
54423
54845
  this.warn = (topic, ...args) => {
54424
- if (this._log.warn) {
54425
- this._log.warn(topic, ...args);
54846
+ const log = this.getInstance();
54847
+ if (log.warn) {
54848
+ log.warn(topic, ...args);
54426
54849
  }
54427
54850
  };
54428
54851
  /**
@@ -54432,7 +54855,8 @@ class LogAdapter {
54432
54855
  */
54433
54856
  this.useLogger = (Ctor) => {
54434
54857
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_LOGGER);
54435
- this._log = Reflect.construct(Ctor, []);
54858
+ this._logFactory = () => Reflect.construct(Ctor, []);
54859
+ this.getInstance.clear();
54436
54860
  };
54437
54861
  /**
54438
54862
  * Switches to persistent log adapter.
@@ -54440,7 +54864,8 @@ class LogAdapter {
54440
54864
  */
54441
54865
  this.usePersist = () => {
54442
54866
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_PERSIST);
54443
- this._log = new LogPersistUtils();
54867
+ this._logFactory = () => new LogPersistUtils();
54868
+ this.getInstance.clear();
54444
54869
  };
54445
54870
  /**
54446
54871
  * Switches to in-memory log adapter (default).
@@ -54448,7 +54873,8 @@ class LogAdapter {
54448
54873
  */
54449
54874
  this.useMemory = () => {
54450
54875
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_MEMORY);
54451
- this._log = new LogMemoryUtils();
54876
+ this._logFactory = () => new LogMemoryUtils();
54877
+ this.getInstance.clear();
54452
54878
  };
54453
54879
  /**
54454
54880
  * Switches to dummy log adapter.
@@ -54456,7 +54882,8 @@ class LogAdapter {
54456
54882
  */
54457
54883
  this.useDummy = () => {
54458
54884
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_DUMMY);
54459
- this._log = new LogDummyUtils();
54885
+ this._logFactory = () => new LogDummyUtils();
54886
+ this.getInstance.clear();
54460
54887
  };
54461
54888
  /**
54462
54889
  * Switches to JSONL file log adapter.
@@ -54466,18 +54893,22 @@ class LogAdapter {
54466
54893
  * @param fileName - Base file name without extension (default: "log")
54467
54894
  * @param dirName - Directory for the JSONL file (default: ./dump/log)
54468
54895
  */
54469
- this.useJsonl = (fileName = "log.jsonl", dirName = join(process.cwd(), "./dump/log")) => {
54896
+ this.useJsonl = (fileName = "log.jsonl", dirName) => {
54470
54897
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_JSONL);
54471
- this._log = new LogJsonlUtils(fileName, dirName);
54898
+ this._logFactory = () => {
54899
+ const dir = dirName || join(process.cwd(), "./dump/log");
54900
+ return new LogJsonlUtils(fileName, dir);
54901
+ };
54902
+ this.getInstance.clear();
54472
54903
  };
54473
54904
  /**
54474
- * Clears the cached log instance by resetting to the default in-memory adapter.
54905
+ * Clears the memoized log instance.
54475
54906
  * Call this when process.cwd() changes between strategy iterations
54476
54907
  * so a new adapter instance is created with the updated base path.
54477
54908
  */
54478
54909
  this.clear = () => {
54479
54910
  backtest.loggerService.info(LOG_ADAPTER_METHOD_NAME_CLEAR);
54480
- this._log = new LogMemoryUtils();
54911
+ this.getInstance.clear();
54481
54912
  };
54482
54913
  }
54483
54914
  }
@@ -58369,15 +58800,23 @@ class StorageDummyLiveUtils {
58369
58800
  */
58370
58801
  class StorageBacktestAdapter {
58371
58802
  constructor() {
58372
- /** Internal storage utils instance */
58373
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58803
+ /** Factory producing the active storage utils instance */
58804
+ this._signalBacktestFactory = () => new StorageMemoryBacktestUtils();
58805
+ /**
58806
+ * Lazily constructs the storage utils from the registered factory and memoizes
58807
+ * the result via `singleshot`.
58808
+ *
58809
+ * The instance is built on the first call and cached for all subsequent calls.
58810
+ * Reset via `clear()` so the next call rebuilds from the current factory.
58811
+ */
58812
+ this.getInstance = singleshot(() => this._signalBacktestFactory());
58374
58813
  /**
58375
58814
  * Handles signal opened event.
58376
58815
  * Proxies call to the underlying storage adapter.
58377
58816
  * @param tick - The opened signal tick data
58378
58817
  */
58379
58818
  this.handleOpened = async (tick) => {
58380
- return await this._signalBacktestUtils.handleOpened(tick);
58819
+ return await this.getInstance().handleOpened(tick);
58381
58820
  };
58382
58821
  /**
58383
58822
  * Handles signal closed event.
@@ -58385,7 +58824,7 @@ class StorageBacktestAdapter {
58385
58824
  * @param tick - The closed signal tick data
58386
58825
  */
58387
58826
  this.handleClosed = async (tick) => {
58388
- return await this._signalBacktestUtils.handleClosed(tick);
58827
+ return await this.getInstance().handleClosed(tick);
58389
58828
  };
58390
58829
  /**
58391
58830
  * Handles signal scheduled event.
@@ -58393,7 +58832,7 @@ class StorageBacktestAdapter {
58393
58832
  * @param tick - The scheduled signal tick data
58394
58833
  */
58395
58834
  this.handleScheduled = async (tick) => {
58396
- return await this._signalBacktestUtils.handleScheduled(tick);
58835
+ return await this.getInstance().handleScheduled(tick);
58397
58836
  };
58398
58837
  /**
58399
58838
  * Handles signal cancelled event.
@@ -58401,7 +58840,7 @@ class StorageBacktestAdapter {
58401
58840
  * @param tick - The cancelled signal tick data
58402
58841
  */
58403
58842
  this.handleCancelled = async (tick) => {
58404
- return await this._signalBacktestUtils.handleCancelled(tick);
58843
+ return await this.getInstance().handleCancelled(tick);
58405
58844
  };
58406
58845
  /**
58407
58846
  * Finds a signal by its ID.
@@ -58410,7 +58849,7 @@ class StorageBacktestAdapter {
58410
58849
  * @returns The signal row or null if not found
58411
58850
  */
58412
58851
  this.findById = async (id) => {
58413
- return await this._signalBacktestUtils.findById(id);
58852
+ return await this.getInstance().findById(id);
58414
58853
  };
58415
58854
  /**
58416
58855
  * Lists all stored signals.
@@ -58418,13 +58857,13 @@ class StorageBacktestAdapter {
58418
58857
  * @returns Array of all signal rows
58419
58858
  */
58420
58859
  this.list = async () => {
58421
- return await this._signalBacktestUtils.list();
58860
+ return await this.getInstance().list();
58422
58861
  };
58423
58862
  this.handleActivePing = async (event) => {
58424
- return await this._signalBacktestUtils.handleActivePing(event);
58863
+ return await this.getInstance().handleActivePing(event);
58425
58864
  };
58426
58865
  this.handleSchedulePing = async (event) => {
58427
- return await this._signalBacktestUtils.handleSchedulePing(event);
58866
+ return await this.getInstance().handleSchedulePing(event);
58428
58867
  };
58429
58868
  /**
58430
58869
  * Sets the storage adapter constructor.
@@ -58434,7 +58873,8 @@ class StorageBacktestAdapter {
58434
58873
  */
58435
58874
  this.useStorageAdapter = (Ctor) => {
58436
58875
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
58437
- this._signalBacktestUtils = Reflect.construct(Ctor, []);
58876
+ this._signalBacktestFactory = () => Reflect.construct(Ctor, []);
58877
+ this.getInstance.clear();
58438
58878
  };
58439
58879
  /**
58440
58880
  * Switches to dummy storage adapter.
@@ -58442,7 +58882,8 @@ class StorageBacktestAdapter {
58442
58882
  */
58443
58883
  this.useDummy = () => {
58444
58884
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
58445
- this._signalBacktestUtils = new StorageDummyBacktestUtils();
58885
+ this._signalBacktestFactory = () => new StorageDummyBacktestUtils();
58886
+ this.getInstance.clear();
58446
58887
  };
58447
58888
  /**
58448
58889
  * Switches to persistent storage adapter (default).
@@ -58450,7 +58891,8 @@ class StorageBacktestAdapter {
58450
58891
  */
58451
58892
  this.usePersist = () => {
58452
58893
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
58453
- this._signalBacktestUtils = new StoragePersistBacktestUtils();
58894
+ this._signalBacktestFactory = () => new StoragePersistBacktestUtils();
58895
+ this.getInstance.clear();
58454
58896
  };
58455
58897
  /**
58456
58898
  * Switches to in-memory storage adapter.
@@ -58458,16 +58900,17 @@ class StorageBacktestAdapter {
58458
58900
  */
58459
58901
  this.useMemory = () => {
58460
58902
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
58461
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58903
+ this._signalBacktestFactory = () => new StorageMemoryBacktestUtils();
58904
+ this.getInstance.clear();
58462
58905
  };
58463
58906
  /**
58464
- * Clears the cached utils instance by resetting to the default in-memory adapter.
58907
+ * Clears the memoized utils instance.
58465
58908
  * Call this when process.cwd() changes between strategy iterations
58466
58909
  * so a new instance is created with the updated base path.
58467
58910
  */
58468
58911
  this.clear = () => {
58469
58912
  backtest.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
58470
- this._signalBacktestUtils = new StorageMemoryBacktestUtils();
58913
+ this.getInstance.clear();
58471
58914
  };
58472
58915
  }
58473
58916
  }
@@ -58482,15 +58925,23 @@ class StorageBacktestAdapter {
58482
58925
  */
58483
58926
  class StorageLiveAdapter {
58484
58927
  constructor() {
58485
- /** Internal storage utils instance */
58486
- this._signalLiveUtils = new StoragePersistLiveUtils();
58928
+ /** Factory producing the active storage utils instance */
58929
+ this._signalLiveFactory = () => new StoragePersistLiveUtils();
58930
+ /**
58931
+ * Lazily constructs the storage utils from the registered factory and memoizes
58932
+ * the result via `singleshot`.
58933
+ *
58934
+ * The instance is built on the first call and cached for all subsequent calls.
58935
+ * Reset via `clear()` so the next call rebuilds from the current factory.
58936
+ */
58937
+ this.getInstance = singleshot(() => this._signalLiveFactory());
58487
58938
  /**
58488
58939
  * Handles signal opened event.
58489
58940
  * Proxies call to the underlying storage adapter.
58490
58941
  * @param tick - The opened signal tick data
58491
58942
  */
58492
58943
  this.handleOpened = async (tick) => {
58493
- return await this._signalLiveUtils.handleOpened(tick);
58944
+ return await this.getInstance().handleOpened(tick);
58494
58945
  };
58495
58946
  /**
58496
58947
  * Handles signal closed event.
@@ -58498,7 +58949,7 @@ class StorageLiveAdapter {
58498
58949
  * @param tick - The closed signal tick data
58499
58950
  */
58500
58951
  this.handleClosed = async (tick) => {
58501
- return await this._signalLiveUtils.handleClosed(tick);
58952
+ return await this.getInstance().handleClosed(tick);
58502
58953
  };
58503
58954
  /**
58504
58955
  * Handles signal scheduled event.
@@ -58506,7 +58957,7 @@ class StorageLiveAdapter {
58506
58957
  * @param tick - The scheduled signal tick data
58507
58958
  */
58508
58959
  this.handleScheduled = async (tick) => {
58509
- return await this._signalLiveUtils.handleScheduled(tick);
58960
+ return await this.getInstance().handleScheduled(tick);
58510
58961
  };
58511
58962
  /**
58512
58963
  * Handles signal cancelled event.
@@ -58514,7 +58965,7 @@ class StorageLiveAdapter {
58514
58965
  * @param tick - The cancelled signal tick data
58515
58966
  */
58516
58967
  this.handleCancelled = async (tick) => {
58517
- return await this._signalLiveUtils.handleCancelled(tick);
58968
+ return await this.getInstance().handleCancelled(tick);
58518
58969
  };
58519
58970
  /**
58520
58971
  * Finds a signal by its ID.
@@ -58523,7 +58974,7 @@ class StorageLiveAdapter {
58523
58974
  * @returns The signal row or null if not found
58524
58975
  */
58525
58976
  this.findById = async (id) => {
58526
- return await this._signalLiveUtils.findById(id);
58977
+ return await this.getInstance().findById(id);
58527
58978
  };
58528
58979
  /**
58529
58980
  * Lists all stored signals.
@@ -58531,13 +58982,13 @@ class StorageLiveAdapter {
58531
58982
  * @returns Array of all signal rows
58532
58983
  */
58533
58984
  this.list = async () => {
58534
- return await this._signalLiveUtils.list();
58985
+ return await this.getInstance().list();
58535
58986
  };
58536
58987
  this.handleActivePing = async (event) => {
58537
- return await this._signalLiveUtils.handleActivePing(event);
58988
+ return await this.getInstance().handleActivePing(event);
58538
58989
  };
58539
58990
  this.handleSchedulePing = async (event) => {
58540
- return await this._signalLiveUtils.handleSchedulePing(event);
58991
+ return await this.getInstance().handleSchedulePing(event);
58541
58992
  };
58542
58993
  /**
58543
58994
  * Sets the storage adapter constructor.
@@ -58547,7 +58998,8 @@ class StorageLiveAdapter {
58547
58998
  */
58548
58999
  this.useStorageAdapter = (Ctor) => {
58549
59000
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
58550
- this._signalLiveUtils = Reflect.construct(Ctor, []);
59001
+ this._signalLiveFactory = () => Reflect.construct(Ctor, []);
59002
+ this.getInstance.clear();
58551
59003
  };
58552
59004
  /**
58553
59005
  * Switches to dummy storage adapter.
@@ -58555,7 +59007,8 @@ class StorageLiveAdapter {
58555
59007
  */
58556
59008
  this.useDummy = () => {
58557
59009
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
58558
- this._signalLiveUtils = new StorageDummyLiveUtils();
59010
+ this._signalLiveFactory = () => new StorageDummyLiveUtils();
59011
+ this.getInstance.clear();
58559
59012
  };
58560
59013
  /**
58561
59014
  * Switches to persistent storage adapter (default).
@@ -58563,7 +59016,8 @@ class StorageLiveAdapter {
58563
59016
  */
58564
59017
  this.usePersist = () => {
58565
59018
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
58566
- this._signalLiveUtils = new StoragePersistLiveUtils();
59019
+ this._signalLiveFactory = () => new StoragePersistLiveUtils();
59020
+ this.getInstance.clear();
58567
59021
  };
58568
59022
  /**
58569
59023
  * Switches to in-memory storage adapter.
@@ -58571,16 +59025,17 @@ class StorageLiveAdapter {
58571
59025
  */
58572
59026
  this.useMemory = () => {
58573
59027
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
58574
- this._signalLiveUtils = new StorageMemoryLiveUtils();
59028
+ this._signalLiveFactory = () => new StorageMemoryLiveUtils();
59029
+ this.getInstance.clear();
58575
59030
  };
58576
59031
  /**
58577
- * Clears the cached utils instance by resetting to the default persistent adapter.
59032
+ * Clears the memoized utils instance.
58578
59033
  * Call this when process.cwd() changes between strategy iterations
58579
59034
  * so a new instance is created with the updated base path.
58580
59035
  */
58581
59036
  this.clear = () => {
58582
59037
  backtest.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_CLEAR);
58583
- this._signalLiveUtils = new StoragePersistLiveUtils();
59038
+ this.getInstance.clear();
58584
59039
  };
58585
59040
  }
58586
59041
  }
@@ -60696,18 +61151,26 @@ class NotificationPersistLiveUtils {
60696
61151
  */
60697
61152
  class NotificationBacktestAdapter {
60698
61153
  constructor() {
60699
- /** Internal notification utils instance */
60700
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
61154
+ /** Factory producing the active notification utils instance */
61155
+ this._notificationBacktestFactory = () => new NotificationMemoryBacktestUtils();
61156
+ /**
61157
+ * Lazily constructs the notification utils from the registered factory and
61158
+ * memoizes the result via `singleshot`.
61159
+ *
61160
+ * The instance is built on the first call and cached for all subsequent calls.
61161
+ * Reset via `clear()` so the next call rebuilds from the current factory.
61162
+ */
61163
+ this.getInstance = singleshot(() => this._notificationBacktestFactory());
60701
61164
  /**
60702
61165
  * Handles signal events.
60703
61166
  * Proxies call to the underlying notification adapter.
60704
61167
  * @param data - The strategy tick result data
60705
61168
  */
60706
61169
  this.handleSignal = async (data) => {
60707
- return await this._notificationBacktestUtils.handleSignal(data);
61170
+ return await this.getInstance().handleSignal(data);
60708
61171
  };
60709
61172
  this.handleSignalNotify = async (data) => {
60710
- return await this._notificationBacktestUtils.handleSignalNotify(data);
61173
+ return await this.getInstance().handleSignalNotify(data);
60711
61174
  };
60712
61175
  /**
60713
61176
  * Handles partial profit availability event.
@@ -60715,7 +61178,7 @@ class NotificationBacktestAdapter {
60715
61178
  * @param data - The partial profit contract data
60716
61179
  */
60717
61180
  this.handlePartialProfit = async (data) => {
60718
- return await this._notificationBacktestUtils.handlePartialProfit(data);
61181
+ return await this.getInstance().handlePartialProfit(data);
60719
61182
  };
60720
61183
  /**
60721
61184
  * Handles partial loss availability event.
@@ -60723,7 +61186,7 @@ class NotificationBacktestAdapter {
60723
61186
  * @param data - The partial loss contract data
60724
61187
  */
60725
61188
  this.handlePartialLoss = async (data) => {
60726
- return await this._notificationBacktestUtils.handlePartialLoss(data);
61189
+ return await this.getInstance().handlePartialLoss(data);
60727
61190
  };
60728
61191
  /**
60729
61192
  * Handles breakeven availability event.
@@ -60731,7 +61194,7 @@ class NotificationBacktestAdapter {
60731
61194
  * @param data - The breakeven contract data
60732
61195
  */
60733
61196
  this.handleBreakeven = async (data) => {
60734
- return await this._notificationBacktestUtils.handleBreakeven(data);
61197
+ return await this.getInstance().handleBreakeven(data);
60735
61198
  };
60736
61199
  /**
60737
61200
  * Handles strategy commit events.
@@ -60739,7 +61202,7 @@ class NotificationBacktestAdapter {
60739
61202
  * @param data - The strategy commit contract data
60740
61203
  */
60741
61204
  this.handleStrategyCommit = async (data) => {
60742
- return await this._notificationBacktestUtils.handleStrategyCommit(data);
61205
+ return await this.getInstance().handleStrategyCommit(data);
60743
61206
  };
60744
61207
  /**
60745
61208
  * Handles signal sync events (signal-open, signal-close).
@@ -60747,7 +61210,7 @@ class NotificationBacktestAdapter {
60747
61210
  * @param data - The signal sync contract data
60748
61211
  */
60749
61212
  this.handleSync = trycatch(async (data) => {
60750
- return await this._notificationBacktestUtils.handleSync(data);
61213
+ return await this.getInstance().handleSync(data);
60751
61214
  }, {
60752
61215
  defaultValue: null,
60753
61216
  });
@@ -60757,7 +61220,7 @@ class NotificationBacktestAdapter {
60757
61220
  * @param data - The risk contract data
60758
61221
  */
60759
61222
  this.handleRisk = async (data) => {
60760
- return await this._notificationBacktestUtils.handleRisk(data);
61223
+ return await this.getInstance().handleRisk(data);
60761
61224
  };
60762
61225
  /**
60763
61226
  * Handles error event.
@@ -60765,7 +61228,7 @@ class NotificationBacktestAdapter {
60765
61228
  * @param error - The error object
60766
61229
  */
60767
61230
  this.handleError = async (error) => {
60768
- return await this._notificationBacktestUtils.handleError(error);
61231
+ return await this.getInstance().handleError(error);
60769
61232
  };
60770
61233
  /**
60771
61234
  * Handles critical error event.
@@ -60773,7 +61236,7 @@ class NotificationBacktestAdapter {
60773
61236
  * @param error - The error object
60774
61237
  */
60775
61238
  this.handleCriticalError = async (error) => {
60776
- return await this._notificationBacktestUtils.handleCriticalError(error);
61239
+ return await this.getInstance().handleCriticalError(error);
60777
61240
  };
60778
61241
  /**
60779
61242
  * Handles validation error event.
@@ -60781,7 +61244,7 @@ class NotificationBacktestAdapter {
60781
61244
  * @param error - The error object
60782
61245
  */
60783
61246
  this.handleValidationError = async (error) => {
60784
- return await this._notificationBacktestUtils.handleValidationError(error);
61247
+ return await this.getInstance().handleValidationError(error);
60785
61248
  };
60786
61249
  /**
60787
61250
  * Gets all stored notifications.
@@ -60789,14 +61252,14 @@ class NotificationBacktestAdapter {
60789
61252
  * @returns Array of all notification models
60790
61253
  */
60791
61254
  this.getData = async () => {
60792
- return await this._notificationBacktestUtils.getData();
61255
+ return await this.getInstance().getData();
60793
61256
  };
60794
61257
  /**
60795
61258
  * Clears all stored notifications.
60796
61259
  * Proxies call to the underlying notification adapter.
60797
61260
  */
60798
61261
  this.dispose = async () => {
60799
- return await this._notificationBacktestUtils.dispose();
61262
+ return await this.getInstance().dispose();
60800
61263
  };
60801
61264
  /**
60802
61265
  * Sets the notification adapter constructor.
@@ -60806,7 +61269,8 @@ class NotificationBacktestAdapter {
60806
61269
  */
60807
61270
  this.useNotificationAdapter = (Ctor) => {
60808
61271
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
60809
- this._notificationBacktestUtils = Reflect.construct(Ctor, []);
61272
+ this._notificationBacktestFactory = () => Reflect.construct(Ctor, []);
61273
+ this.getInstance.clear();
60810
61274
  };
60811
61275
  /**
60812
61276
  * Switches to dummy notification adapter.
@@ -60814,7 +61278,8 @@ class NotificationBacktestAdapter {
60814
61278
  */
60815
61279
  this.useDummy = () => {
60816
61280
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
60817
- this._notificationBacktestUtils = new NotificationDummyBacktestUtils();
61281
+ this._notificationBacktestFactory = () => new NotificationDummyBacktestUtils();
61282
+ this.getInstance.clear();
60818
61283
  };
60819
61284
  /**
60820
61285
  * Switches to in-memory notification adapter (default).
@@ -60822,7 +61287,8 @@ class NotificationBacktestAdapter {
60822
61287
  */
60823
61288
  this.useMemory = () => {
60824
61289
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
60825
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
61290
+ this._notificationBacktestFactory = () => new NotificationMemoryBacktestUtils();
61291
+ this.getInstance.clear();
60826
61292
  };
60827
61293
  /**
60828
61294
  * Switches to persistent notification adapter.
@@ -60830,16 +61296,17 @@ class NotificationBacktestAdapter {
60830
61296
  */
60831
61297
  this.usePersist = () => {
60832
61298
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
60833
- this._notificationBacktestUtils = new NotificationPersistBacktestUtils();
61299
+ this._notificationBacktestFactory = () => new NotificationPersistBacktestUtils();
61300
+ this.getInstance.clear();
60834
61301
  };
60835
61302
  /**
60836
- * Resets the cached utils instance to the default in-memory adapter.
61303
+ * Clears the memoized utils instance.
60837
61304
  * Call this when process.cwd() changes between strategy iterations
60838
61305
  * so a new instance is created with the updated base path.
60839
61306
  */
60840
61307
  this.clear = () => {
60841
61308
  backtest.loggerService.info(NOTIFICATION_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
60842
- this._notificationBacktestUtils = new NotificationMemoryBacktestUtils();
61309
+ this.getInstance.clear();
60843
61310
  };
60844
61311
  }
60845
61312
  }
@@ -60854,18 +61321,26 @@ class NotificationBacktestAdapter {
60854
61321
  */
60855
61322
  class NotificationLiveAdapter {
60856
61323
  constructor() {
60857
- /** Internal notification utils instance */
60858
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61324
+ /** Factory producing the active notification utils instance */
61325
+ this._notificationLiveFactory = () => new NotificationMemoryLiveUtils();
61326
+ /**
61327
+ * Lazily constructs the notification utils from the registered factory and
61328
+ * memoizes the result via `singleshot`.
61329
+ *
61330
+ * The instance is built on the first call and cached for all subsequent calls.
61331
+ * Reset via `clear()` so the next call rebuilds from the current factory.
61332
+ */
61333
+ this.getInstance = singleshot(() => this._notificationLiveFactory());
60859
61334
  /**
60860
61335
  * Handles signal events.
60861
61336
  * Proxies call to the underlying notification adapter.
60862
61337
  * @param data - The strategy tick result data
60863
61338
  */
60864
61339
  this.handleSignal = async (data) => {
60865
- return await this._notificationLiveUtils.handleSignal(data);
61340
+ return await this.getInstance().handleSignal(data);
60866
61341
  };
60867
61342
  this.handleSignalNotify = async (data) => {
60868
- return await this._notificationLiveUtils.handleSignalNotify(data);
61343
+ return await this.getInstance().handleSignalNotify(data);
60869
61344
  };
60870
61345
  /**
60871
61346
  * Handles partial profit availability event.
@@ -60873,7 +61348,7 @@ class NotificationLiveAdapter {
60873
61348
  * @param data - The partial profit contract data
60874
61349
  */
60875
61350
  this.handlePartialProfit = async (data) => {
60876
- return await this._notificationLiveUtils.handlePartialProfit(data);
61351
+ return await this.getInstance().handlePartialProfit(data);
60877
61352
  };
60878
61353
  /**
60879
61354
  * Handles partial loss availability event.
@@ -60881,7 +61356,7 @@ class NotificationLiveAdapter {
60881
61356
  * @param data - The partial loss contract data
60882
61357
  */
60883
61358
  this.handlePartialLoss = async (data) => {
60884
- return await this._notificationLiveUtils.handlePartialLoss(data);
61359
+ return await this.getInstance().handlePartialLoss(data);
60885
61360
  };
60886
61361
  /**
60887
61362
  * Handles breakeven availability event.
@@ -60889,7 +61364,7 @@ class NotificationLiveAdapter {
60889
61364
  * @param data - The breakeven contract data
60890
61365
  */
60891
61366
  this.handleBreakeven = async (data) => {
60892
- return await this._notificationLiveUtils.handleBreakeven(data);
61367
+ return await this.getInstance().handleBreakeven(data);
60893
61368
  };
60894
61369
  /**
60895
61370
  * Handles strategy commit events.
@@ -60897,7 +61372,7 @@ class NotificationLiveAdapter {
60897
61372
  * @param data - The strategy commit contract data
60898
61373
  */
60899
61374
  this.handleStrategyCommit = async (data) => {
60900
- return await this._notificationLiveUtils.handleStrategyCommit(data);
61375
+ return await this.getInstance().handleStrategyCommit(data);
60901
61376
  };
60902
61377
  /**
60903
61378
  * Handles signal sync events (signal-open, signal-close).
@@ -60905,7 +61380,7 @@ class NotificationLiveAdapter {
60905
61380
  * @param data - The signal sync contract data
60906
61381
  */
60907
61382
  this.handleSync = trycatch(async (data) => {
60908
- return await this._notificationLiveUtils.handleSync(data);
61383
+ return await this.getInstance().handleSync(data);
60909
61384
  }, {
60910
61385
  defaultValue: null,
60911
61386
  });
@@ -60915,7 +61390,7 @@ class NotificationLiveAdapter {
60915
61390
  * @param data - The risk contract data
60916
61391
  */
60917
61392
  this.handleRisk = async (data) => {
60918
- return await this._notificationLiveUtils.handleRisk(data);
61393
+ return await this.getInstance().handleRisk(data);
60919
61394
  };
60920
61395
  /**
60921
61396
  * Handles error event.
@@ -60923,7 +61398,7 @@ class NotificationLiveAdapter {
60923
61398
  * @param error - The error object
60924
61399
  */
60925
61400
  this.handleError = async (error) => {
60926
- return await this._notificationLiveUtils.handleError(error);
61401
+ return await this.getInstance().handleError(error);
60927
61402
  };
60928
61403
  /**
60929
61404
  * Handles critical error event.
@@ -60931,7 +61406,7 @@ class NotificationLiveAdapter {
60931
61406
  * @param error - The error object
60932
61407
  */
60933
61408
  this.handleCriticalError = async (error) => {
60934
- return await this._notificationLiveUtils.handleCriticalError(error);
61409
+ return await this.getInstance().handleCriticalError(error);
60935
61410
  };
60936
61411
  /**
60937
61412
  * Handles validation error event.
@@ -60939,7 +61414,7 @@ class NotificationLiveAdapter {
60939
61414
  * @param error - The error object
60940
61415
  */
60941
61416
  this.handleValidationError = async (error) => {
60942
- return await this._notificationLiveUtils.handleValidationError(error);
61417
+ return await this.getInstance().handleValidationError(error);
60943
61418
  };
60944
61419
  /**
60945
61420
  * Gets all stored notifications.
@@ -60947,14 +61422,14 @@ class NotificationLiveAdapter {
60947
61422
  * @returns Array of all notification models
60948
61423
  */
60949
61424
  this.getData = async () => {
60950
- return await this._notificationLiveUtils.getData();
61425
+ return await this.getInstance().getData();
60951
61426
  };
60952
61427
  /**
60953
61428
  * Clears all stored notifications.
60954
61429
  * Proxies call to the underlying notification adapter.
60955
61430
  */
60956
61431
  this.dispose = async () => {
60957
- return await this._notificationLiveUtils.dispose();
61432
+ return await this.getInstance().dispose();
60958
61433
  };
60959
61434
  /**
60960
61435
  * Sets the notification adapter constructor.
@@ -60964,7 +61439,8 @@ class NotificationLiveAdapter {
60964
61439
  */
60965
61440
  this.useNotificationAdapter = (Ctor) => {
60966
61441
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
60967
- this._notificationLiveUtils = Reflect.construct(Ctor, []);
61442
+ this._notificationLiveFactory = () => Reflect.construct(Ctor, []);
61443
+ this.getInstance.clear();
60968
61444
  };
60969
61445
  /**
60970
61446
  * Switches to dummy notification adapter.
@@ -60972,7 +61448,8 @@ class NotificationLiveAdapter {
60972
61448
  */
60973
61449
  this.useDummy = () => {
60974
61450
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
60975
- this._notificationLiveUtils = new NotificationDummyLiveUtils();
61451
+ this._notificationLiveFactory = () => new NotificationDummyLiveUtils();
61452
+ this.getInstance.clear();
60976
61453
  };
60977
61454
  /**
60978
61455
  * Switches to in-memory notification adapter (default).
@@ -60980,7 +61457,8 @@ class NotificationLiveAdapter {
60980
61457
  */
60981
61458
  this.useMemory = () => {
60982
61459
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
60983
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61460
+ this._notificationLiveFactory = () => new NotificationMemoryLiveUtils();
61461
+ this.getInstance.clear();
60984
61462
  };
60985
61463
  /**
60986
61464
  * Switches to persistent notification adapter.
@@ -60988,16 +61466,17 @@ class NotificationLiveAdapter {
60988
61466
  */
60989
61467
  this.usePersist = () => {
60990
61468
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
60991
- this._notificationLiveUtils = new NotificationPersistLiveUtils();
61469
+ this._notificationLiveFactory = () => new NotificationPersistLiveUtils();
61470
+ this.getInstance.clear();
60992
61471
  };
60993
61472
  /**
60994
- * Resets the cached utils instance to the default in-memory adapter.
61473
+ * Clears the memoized utils instance.
60995
61474
  * Call this when process.cwd() changes between strategy iterations
60996
61475
  * so a new instance is created with the updated base path.
60997
61476
  */
60998
61477
  this.clear = () => {
60999
61478
  backtest.loggerService.info(NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_CLEAR);
61000
- this._notificationLiveUtils = new NotificationMemoryLiveUtils();
61479
+ this.getInstance.clear();
61001
61480
  };
61002
61481
  }
61003
61482
  }
@@ -63598,4 +64077,4 @@ const validateSignal = (signal, currentPrice) => {
63598
64077
  return !errors.length;
63599
64078
  };
63600
64079
 
63601
- export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MemoryBacktest, MemoryBacktestAdapter, MemoryLive, MemoryLiveAdapter, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistBreakevenInstance, PersistCandleAdapter, PersistCandleInstance, PersistIntervalAdapter, PersistIntervalInstance, PersistLogAdapter, PersistLogInstance, PersistMeasureAdapter, PersistMeasureInstance, PersistMemoryAdapter, PersistMemoryInstance, PersistNotificationAdapter, PersistNotificationInstance, PersistPartialAdapter, PersistPartialInstance, PersistRecentAdapter, PersistRecentInstance, PersistRiskAdapter, PersistRiskInstance, PersistScheduleAdapter, PersistScheduleInstance, PersistSessionAdapter, PersistSessionInstance, PersistSignalAdapter, PersistSignalInstance, PersistStateAdapter, PersistStateInstance, PersistStorageAdapter, PersistStorageInstance, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, SessionBacktest, SessionLive, State, StateBacktest, StateBacktestAdapter, StateLive, StateLiveAdapter, Storage, StorageBacktest, StorageLive, Strategy, Sync, System, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitSignalNotify, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, createSignalState, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getClosePrice, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMinutesSinceLatestSignalCreated, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionActiveMinutes, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getPositionWaitingMinutes, getRawCandles, getRiskSchema, getScheduledSignal, getSessionData, getSignalState, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, intervalStepMs, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenIdlePing, listenIdlePingOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalNotify, listenSignalNotifyOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, setSessionData, setSignalState, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, waitForReady, warmCandles, writeMemory };
64080
+ export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Lookup, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MemoryBacktest, MemoryBacktestAdapter, MemoryLive, MemoryLiveAdapter, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistBreakevenInstance, PersistCandleAdapter, PersistCandleInstance, PersistIntervalAdapter, PersistIntervalInstance, PersistLogAdapter, PersistLogInstance, PersistMeasureAdapter, PersistMeasureInstance, PersistMemoryAdapter, PersistMemoryInstance, PersistNotificationAdapter, PersistNotificationInstance, PersistPartialAdapter, PersistPartialInstance, PersistRecentAdapter, PersistRecentInstance, PersistRiskAdapter, PersistRiskInstance, PersistScheduleAdapter, PersistScheduleInstance, PersistSessionAdapter, PersistSessionInstance, PersistSignalAdapter, PersistSignalInstance, PersistStateAdapter, PersistStateInstance, PersistStorageAdapter, PersistStorageInstance, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, SessionBacktest, SessionLive, State, StateBacktest, StateBacktestAdapter, StateLive, StateLiveAdapter, Storage, StorageBacktest, StorageLive, Strategy, Sync, System, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, cacheCandles, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitSignalNotify, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, createSignalState, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getClosePrice, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMinutesSinceLatestSignalCreated, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionActiveMinutes, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getPositionWaitingMinutes, getRawCandles, getRiskSchema, getScheduledSignal, getSessionData, getSignalState, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, intervalStepMs, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenIdlePing, listenIdlePingOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalNotify, listenSignalNotifyOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, setSessionData, setSignalState, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, waitForReady, warmCandles, writeMemory };