backtest-kit 9.8.1 → 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 +477 -130
  4. package/build/index.mjs +476 -131
  5. package/package.json +86 -86
  6. package/types.d.ts +123 -3
package/build/index.cjs CHANGED
@@ -574,6 +574,22 @@ const GLOBAL_CONFIG = {
574
574
  * Default: true (mutex locking enabled for candle fetching)
575
575
  */
576
576
  CC_ENABLE_CANDLE_FETCH_MUTEX: true,
577
+ /**
578
+ * Enables cooperative interleaving of concurrently running backtests after each candle fetch.
579
+ *
580
+ * Mechanism (implemented in `Candle.spinLock`):
581
+ * - After `getNextCandles` resolves, the current backtest awaits
582
+ * `Promise.race([_spin.toPromise(), sleep(50)])`, where `_spin` is emitted whenever
583
+ * another caller acquires the candle-fetch mutex.
584
+ * - This hands the event loop to a peer backtest waiting on the same mutex, so multiple
585
+ * parallel `Backtest.run` / `Walker` workloads progress in round-robin fashion instead
586
+ * of one monopolizing the event loop until completion.
587
+ * - The spin is skipped entirely when `Lookup.isParallel` is `false` (single active workload —
588
+ * no peer to yield to) or when `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled.
589
+ *
590
+ * Default: true (parallel backtests are interleaved on each candle fetch boundary)
591
+ */
592
+ CC_ENABLE_BACKTEST_PARALLEL_SPIN: true,
577
593
  /**
578
594
  * Enables DCA (Dollar-Cost Averaging) logic even if antirecord is not broken.
579
595
  * Allows to commitAverageBuy if currentPrice is not the lowest price since entry, but still lower than priceOpen.
@@ -934,7 +950,7 @@ async function writeFileAtomic(file, data, options = {}) {
934
950
 
935
951
  var _a$3;
936
952
  /** Logger service injected as DI singleton */
937
- const LOGGER_SERVICE$7 = new LoggerService();
953
+ const LOGGER_SERVICE$8 = new LoggerService();
938
954
  /** Symbol key for the singleshot waitForInit function on PersistBase instances. */
939
955
  const BASE_WAIT_FOR_INIT_SYMBOL = Symbol("wait-for-init");
940
956
  // Calculate step in milliseconds for candle close time validation
@@ -1057,7 +1073,7 @@ const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
1057
1073
  const BASE_UNLINK_RETRY_COUNT = 5;
1058
1074
  const BASE_UNLINK_RETRY_DELAY = 1000;
1059
1075
  const BASE_WAIT_FOR_INIT_FN = async (self) => {
1060
- LOGGER_SERVICE$7.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
1076
+ LOGGER_SERVICE$8.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
1061
1077
  entityName: self.entityName,
1062
1078
  directory: self._directory,
1063
1079
  });
@@ -1115,7 +1131,7 @@ class PersistBase {
1115
1131
  this.entityName = entityName;
1116
1132
  this.baseDir = baseDir;
1117
1133
  this[_a$3] = functoolsKit.singleshot(async () => await BASE_WAIT_FOR_INIT_FN(this));
1118
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
1134
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
1119
1135
  entityName: this.entityName,
1120
1136
  baseDir,
1121
1137
  });
@@ -1131,14 +1147,14 @@ class PersistBase {
1131
1147
  return path.join(this.baseDir, this.entityName, `${entityId}.json`);
1132
1148
  }
1133
1149
  async waitForInit(initial) {
1134
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
1150
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
1135
1151
  entityName: this.entityName,
1136
1152
  initial,
1137
1153
  });
1138
1154
  await this[BASE_WAIT_FOR_INIT_SYMBOL]();
1139
1155
  }
1140
1156
  async readValue(entityId) {
1141
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
1157
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
1142
1158
  entityName: this.entityName,
1143
1159
  entityId,
1144
1160
  });
@@ -1155,7 +1171,7 @@ class PersistBase {
1155
1171
  }
1156
1172
  }
1157
1173
  async hasValue(entityId) {
1158
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
1174
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
1159
1175
  entityName: this.entityName,
1160
1176
  entityId,
1161
1177
  });
@@ -1172,7 +1188,7 @@ class PersistBase {
1172
1188
  }
1173
1189
  }
1174
1190
  async writeValue(entityId, entity) {
1175
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
1191
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
1176
1192
  entityName: this.entityName,
1177
1193
  entityId,
1178
1194
  });
@@ -1194,7 +1210,7 @@ class PersistBase {
1194
1210
  * @throws Error if reading fails
1195
1211
  */
1196
1212
  async *keys() {
1197
- LOGGER_SERVICE$7.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
1213
+ LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
1198
1214
  entityName: this.entityName,
1199
1215
  });
1200
1216
  try {
@@ -1339,7 +1355,7 @@ class PersistSignalUtils {
1339
1355
  * @returns Promise resolving to signal or null if none persisted
1340
1356
  */
1341
1357
  this.readSignalData = async (symbol, strategyName, exchangeName) => {
1342
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
1358
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
1343
1359
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1344
1360
  const isInitial = !this.getStorage.has(key);
1345
1361
  const instance = this.getStorage(symbol, strategyName, exchangeName);
@@ -1357,7 +1373,7 @@ class PersistSignalUtils {
1357
1373
  * @returns Promise that resolves when write is complete
1358
1374
  */
1359
1375
  this.writeSignalData = async (signalRow, symbol, strategyName, exchangeName) => {
1360
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
1376
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
1361
1377
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1362
1378
  const isInitial = !this.getStorage.has(key);
1363
1379
  const instance = this.getStorage(symbol, strategyName, exchangeName);
@@ -1372,7 +1388,7 @@ class PersistSignalUtils {
1372
1388
  * @param Ctor - Custom IPersistSignalInstance constructor
1373
1389
  */
1374
1390
  usePersistSignalAdapter(Ctor) {
1375
- LOGGER_SERVICE$7.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
1391
+ LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
1376
1392
  this.PersistSignalInstanceCtor = Ctor;
1377
1393
  this.getStorage.clear();
1378
1394
  }
@@ -1381,21 +1397,21 @@ class PersistSignalUtils {
1381
1397
  * Call when process.cwd() changes between strategy iterations.
1382
1398
  */
1383
1399
  clear() {
1384
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
1400
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
1385
1401
  this.getStorage.clear();
1386
1402
  }
1387
1403
  /**
1388
1404
  * Switches to the default file-based PersistSignalInstance.
1389
1405
  */
1390
1406
  useJson() {
1391
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
1407
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
1392
1408
  this.usePersistSignalAdapter(PersistSignalInstance);
1393
1409
  }
1394
1410
  /**
1395
1411
  * Switches to PersistSignalDummyInstance (all operations are no-ops).
1396
1412
  */
1397
1413
  useDummy() {
1398
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
1414
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
1399
1415
  this.usePersistSignalAdapter(PersistSignalDummyInstance);
1400
1416
  }
1401
1417
  }
@@ -1535,7 +1551,7 @@ class PersistRiskUtils {
1535
1551
  * @returns Promise resolving to position entries (empty array if none)
1536
1552
  */
1537
1553
  this.readPositionData = async (riskName, exchangeName, when) => {
1538
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
1554
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
1539
1555
  const key = `${riskName}:${exchangeName}`;
1540
1556
  const isInitial = !this.getRiskStorage.has(key);
1541
1557
  const instance = this.getRiskStorage(riskName, exchangeName);
@@ -1553,7 +1569,7 @@ class PersistRiskUtils {
1553
1569
  * @returns Promise that resolves when write is complete
1554
1570
  */
1555
1571
  this.writePositionData = async (riskRow, riskName, exchangeName, when) => {
1556
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
1572
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
1557
1573
  const key = `${riskName}:${exchangeName}`;
1558
1574
  const isInitial = !this.getRiskStorage.has(key);
1559
1575
  const instance = this.getRiskStorage(riskName, exchangeName);
@@ -1568,7 +1584,7 @@ class PersistRiskUtils {
1568
1584
  * @param Ctor - Custom IPersistRiskInstance constructor
1569
1585
  */
1570
1586
  usePersistRiskAdapter(Ctor) {
1571
- LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
1587
+ LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
1572
1588
  this.PersistRiskInstanceCtor = Ctor;
1573
1589
  this.getRiskStorage.clear();
1574
1590
  }
@@ -1577,21 +1593,21 @@ class PersistRiskUtils {
1577
1593
  * Call when process.cwd() changes between strategy iterations.
1578
1594
  */
1579
1595
  clear() {
1580
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
1596
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
1581
1597
  this.getRiskStorage.clear();
1582
1598
  }
1583
1599
  /**
1584
1600
  * Switches to the default file-based PersistRiskInstance.
1585
1601
  */
1586
1602
  useJson() {
1587
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
1603
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
1588
1604
  this.usePersistRiskAdapter(PersistRiskInstance);
1589
1605
  }
1590
1606
  /**
1591
1607
  * Switches to PersistRiskDummyInstance (all operations are no-ops).
1592
1608
  */
1593
1609
  useDummy() {
1594
- LOGGER_SERVICE$7.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
1610
+ LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
1595
1611
  this.usePersistRiskAdapter(PersistRiskDummyInstance);
1596
1612
  }
1597
1613
  }
@@ -1730,7 +1746,7 @@ class PersistScheduleUtils {
1730
1746
  * @returns Promise resolving to scheduled signal or null if none persisted
1731
1747
  */
1732
1748
  this.readScheduleData = async (symbol, strategyName, exchangeName) => {
1733
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
1749
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
1734
1750
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1735
1751
  const isInitial = !this.getScheduleStorage.has(key);
1736
1752
  const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
@@ -1748,7 +1764,7 @@ class PersistScheduleUtils {
1748
1764
  * @returns Promise that resolves when write is complete
1749
1765
  */
1750
1766
  this.writeScheduleData = async (scheduledSignalRow, symbol, strategyName, exchangeName) => {
1751
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
1767
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
1752
1768
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1753
1769
  const isInitial = !this.getScheduleStorage.has(key);
1754
1770
  const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
@@ -1763,7 +1779,7 @@ class PersistScheduleUtils {
1763
1779
  * @param Ctor - Custom IPersistScheduleInstance constructor
1764
1780
  */
1765
1781
  usePersistScheduleAdapter(Ctor) {
1766
- LOGGER_SERVICE$7.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
1782
+ LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
1767
1783
  this.PersistScheduleInstanceCtor = Ctor;
1768
1784
  this.getScheduleStorage.clear();
1769
1785
  }
@@ -1772,21 +1788,21 @@ class PersistScheduleUtils {
1772
1788
  * Call when process.cwd() changes between strategy iterations.
1773
1789
  */
1774
1790
  clear() {
1775
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
1791
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
1776
1792
  this.getScheduleStorage.clear();
1777
1793
  }
1778
1794
  /**
1779
1795
  * Switches to the default file-based PersistScheduleInstance.
1780
1796
  */
1781
1797
  useJson() {
1782
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
1798
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
1783
1799
  this.usePersistScheduleAdapter(PersistScheduleInstance);
1784
1800
  }
1785
1801
  /**
1786
1802
  * Switches to PersistScheduleDummyInstance (all operations are no-ops).
1787
1803
  */
1788
1804
  useDummy() {
1789
- LOGGER_SERVICE$7.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
1805
+ LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
1790
1806
  this.usePersistScheduleAdapter(PersistScheduleDummyInstance);
1791
1807
  }
1792
1808
  }
@@ -1931,7 +1947,7 @@ class PersistPartialUtils {
1931
1947
  * @returns Promise resolving to partial data record (empty object if none)
1932
1948
  */
1933
1949
  this.readPartialData = async (symbol, strategyName, signalId, exchangeName, when) => {
1934
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
1950
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
1935
1951
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1936
1952
  const isInitial = !this.getPartialStorage.has(key);
1937
1953
  const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
@@ -1951,7 +1967,7 @@ class PersistPartialUtils {
1951
1967
  * @returns Promise that resolves when write is complete
1952
1968
  */
1953
1969
  this.writePartialData = async (partialData, symbol, strategyName, signalId, exchangeName, when) => {
1954
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
1970
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
1955
1971
  const key = `${symbol}:${strategyName}:${exchangeName}`;
1956
1972
  const isInitial = !this.getPartialStorage.has(key);
1957
1973
  const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
@@ -1966,7 +1982,7 @@ class PersistPartialUtils {
1966
1982
  * @param Ctor - Custom IPersistPartialInstance constructor
1967
1983
  */
1968
1984
  usePersistPartialAdapter(Ctor) {
1969
- LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
1985
+ LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
1970
1986
  this.PersistPartialInstanceCtor = Ctor;
1971
1987
  this.getPartialStorage.clear();
1972
1988
  }
@@ -1975,21 +1991,21 @@ class PersistPartialUtils {
1975
1991
  * Call when process.cwd() changes between strategy iterations.
1976
1992
  */
1977
1993
  clear() {
1978
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
1994
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
1979
1995
  this.getPartialStorage.clear();
1980
1996
  }
1981
1997
  /**
1982
1998
  * Switches to the default file-based PersistPartialInstance.
1983
1999
  */
1984
2000
  useJson() {
1985
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
2001
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
1986
2002
  this.usePersistPartialAdapter(PersistPartialInstance);
1987
2003
  }
1988
2004
  /**
1989
2005
  * Switches to PersistPartialDummyInstance (all operations are no-ops).
1990
2006
  */
1991
2007
  useDummy() {
1992
- LOGGER_SERVICE$7.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
2008
+ LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
1993
2009
  this.usePersistPartialAdapter(PersistPartialDummyInstance);
1994
2010
  }
1995
2011
  }
@@ -2154,7 +2170,7 @@ class PersistBreakevenUtils {
2154
2170
  * @returns Promise resolving to breakeven data record (empty object if none)
2155
2171
  */
2156
2172
  this.readBreakevenData = async (symbol, strategyName, signalId, exchangeName, when) => {
2157
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
2173
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
2158
2174
  const key = `${symbol}:${strategyName}:${exchangeName}`;
2159
2175
  const isInitial = !this.getBreakevenStorage.has(key);
2160
2176
  const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
@@ -2174,7 +2190,7 @@ class PersistBreakevenUtils {
2174
2190
  * @returns Promise that resolves when write is complete
2175
2191
  */
2176
2192
  this.writeBreakevenData = async (breakevenData, symbol, strategyName, signalId, exchangeName, when) => {
2177
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
2193
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
2178
2194
  const key = `${symbol}:${strategyName}:${exchangeName}`;
2179
2195
  const isInitial = !this.getBreakevenStorage.has(key);
2180
2196
  const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
@@ -2189,7 +2205,7 @@ class PersistBreakevenUtils {
2189
2205
  * @param Ctor - Custom IPersistBreakevenInstance constructor
2190
2206
  */
2191
2207
  usePersistBreakevenAdapter(Ctor) {
2192
- LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
2208
+ LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
2193
2209
  this.PersistBreakevenInstanceCtor = Ctor;
2194
2210
  this.getBreakevenStorage.clear();
2195
2211
  }
@@ -2198,21 +2214,21 @@ class PersistBreakevenUtils {
2198
2214
  * Call when process.cwd() changes between strategy iterations.
2199
2215
  */
2200
2216
  clear() {
2201
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
2217
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
2202
2218
  this.getBreakevenStorage.clear();
2203
2219
  }
2204
2220
  /**
2205
2221
  * Switches to the default file-based PersistBreakevenInstance.
2206
2222
  */
2207
2223
  useJson() {
2208
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
2224
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
2209
2225
  this.usePersistBreakevenAdapter(PersistBreakevenInstance);
2210
2226
  }
2211
2227
  /**
2212
2228
  * Switches to PersistBreakevenDummyInstance (all operations are no-ops).
2213
2229
  */
2214
2230
  useDummy() {
2215
- LOGGER_SERVICE$7.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
2231
+ LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
2216
2232
  this.usePersistBreakevenAdapter(PersistBreakevenDummyInstance);
2217
2233
  }
2218
2234
  }
@@ -2303,7 +2319,7 @@ class PersistCandleInstance {
2303
2319
  error: functoolsKit.errorData(error),
2304
2320
  message: functoolsKit.getErrorMessage(error),
2305
2321
  };
2306
- LOGGER_SERVICE$7.warn(message, payload);
2322
+ LOGGER_SERVICE$8.warn(message, payload);
2307
2323
  console.warn(message, payload);
2308
2324
  errorEmitter.next(error);
2309
2325
  return null;
@@ -2325,7 +2341,7 @@ class PersistCandleInstance {
2325
2341
  for (const candle of candles) {
2326
2342
  const candleCloseTime = candle.timestamp + stepMs;
2327
2343
  if (candleCloseTime > now) {
2328
- LOGGER_SERVICE$7.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
2344
+ LOGGER_SERVICE$8.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
2329
2345
  symbol: this.symbol,
2330
2346
  interval: this.interval,
2331
2347
  exchangeName: this.exchangeName,
@@ -2402,7 +2418,7 @@ class PersistCandleUtils {
2402
2418
  * @returns Promise resolving to candles in order, or null on cache miss
2403
2419
  */
2404
2420
  this.readCandlesData = async (symbol, interval, exchangeName, limit, sinceTimestamp, untilTimestamp) => {
2405
- LOGGER_SERVICE$7.info("PersistCandleUtils.readCandlesData", {
2421
+ LOGGER_SERVICE$8.info("PersistCandleUtils.readCandlesData", {
2406
2422
  symbol,
2407
2423
  interval,
2408
2424
  exchangeName,
@@ -2426,7 +2442,7 @@ class PersistCandleUtils {
2426
2442
  * @returns Promise that resolves when all writes are complete
2427
2443
  */
2428
2444
  this.writeCandlesData = async (candles, symbol, interval, exchangeName) => {
2429
- LOGGER_SERVICE$7.info("PersistCandleUtils.writeCandlesData", {
2445
+ LOGGER_SERVICE$8.info("PersistCandleUtils.writeCandlesData", {
2430
2446
  symbol,
2431
2447
  interval,
2432
2448
  exchangeName,
@@ -2446,7 +2462,7 @@ class PersistCandleUtils {
2446
2462
  * @param Ctor - Custom IPersistCandleInstance constructor
2447
2463
  */
2448
2464
  usePersistCandleAdapter(Ctor) {
2449
- LOGGER_SERVICE$7.info("PersistCandleUtils.usePersistCandleAdapter");
2465
+ LOGGER_SERVICE$8.info("PersistCandleUtils.usePersistCandleAdapter");
2450
2466
  this.PersistCandleInstanceCtor = Ctor;
2451
2467
  this.getCandlesStorage.clear();
2452
2468
  }
@@ -2455,21 +2471,21 @@ class PersistCandleUtils {
2455
2471
  * Call when process.cwd() changes between strategy iterations.
2456
2472
  */
2457
2473
  clear() {
2458
- LOGGER_SERVICE$7.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
2474
+ LOGGER_SERVICE$8.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
2459
2475
  this.getCandlesStorage.clear();
2460
2476
  }
2461
2477
  /**
2462
2478
  * Switches to the default file-based PersistCandleInstance.
2463
2479
  */
2464
2480
  useJson() {
2465
- LOGGER_SERVICE$7.log("PersistCandleUtils.useJson");
2481
+ LOGGER_SERVICE$8.log("PersistCandleUtils.useJson");
2466
2482
  this.usePersistCandleAdapter(PersistCandleInstance);
2467
2483
  }
2468
2484
  /**
2469
2485
  * Switches to PersistCandleDummyInstance (always returns null on read, discards writes).
2470
2486
  */
2471
2487
  useDummy() {
2472
- LOGGER_SERVICE$7.log("PersistCandleUtils.useDummy");
2488
+ LOGGER_SERVICE$8.log("PersistCandleUtils.useDummy");
2473
2489
  this.usePersistCandleAdapter(PersistCandleDummyInstance);
2474
2490
  }
2475
2491
  }
@@ -2607,7 +2623,7 @@ class PersistStorageUtils {
2607
2623
  * @returns Promise resolving to array of signal entries
2608
2624
  */
2609
2625
  this.readStorageData = async (backtest) => {
2610
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
2626
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
2611
2627
  const key = backtest ? `backtest` : `live`;
2612
2628
  const isInitial = !this.getStorage.has(key);
2613
2629
  const instance = this.getStorage(backtest);
@@ -2623,7 +2639,7 @@ class PersistStorageUtils {
2623
2639
  * @returns Promise that resolves when write is complete
2624
2640
  */
2625
2641
  this.writeStorageData = async (signalData, backtest) => {
2626
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
2642
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
2627
2643
  const key = backtest ? `backtest` : `live`;
2628
2644
  const isInitial = !this.getStorage.has(key);
2629
2645
  const instance = this.getStorage(backtest);
@@ -2638,7 +2654,7 @@ class PersistStorageUtils {
2638
2654
  * @param Ctor - Custom IPersistStorageInstance constructor
2639
2655
  */
2640
2656
  usePersistStorageAdapter(Ctor) {
2641
- LOGGER_SERVICE$7.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
2657
+ LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
2642
2658
  this.PersistStorageInstanceCtor = Ctor;
2643
2659
  this.getStorage.clear();
2644
2660
  }
@@ -2647,21 +2663,21 @@ class PersistStorageUtils {
2647
2663
  * Call when process.cwd() changes between strategy iterations.
2648
2664
  */
2649
2665
  clear() {
2650
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
2666
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
2651
2667
  this.getStorage.clear();
2652
2668
  }
2653
2669
  /**
2654
2670
  * Switches to the default file-based PersistStorageInstance.
2655
2671
  */
2656
2672
  useJson() {
2657
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
2673
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
2658
2674
  this.usePersistStorageAdapter(PersistStorageInstance);
2659
2675
  }
2660
2676
  /**
2661
2677
  * Switches to PersistStorageDummyInstance (all operations are no-ops).
2662
2678
  */
2663
2679
  useDummy() {
2664
- LOGGER_SERVICE$7.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
2680
+ LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
2665
2681
  this.usePersistStorageAdapter(PersistStorageDummyInstance);
2666
2682
  }
2667
2683
  }
@@ -2788,7 +2804,7 @@ class PersistNotificationUtils {
2788
2804
  * @returns Promise resolving to array of notification entries
2789
2805
  */
2790
2806
  this.readNotificationData = async (backtest) => {
2791
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
2807
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
2792
2808
  const key = backtest ? `backtest` : `live`;
2793
2809
  const isInitial = !this.getNotificationStorage.has(key);
2794
2810
  const instance = this.getNotificationStorage(backtest);
@@ -2804,7 +2820,7 @@ class PersistNotificationUtils {
2804
2820
  * @returns Promise that resolves when write is complete
2805
2821
  */
2806
2822
  this.writeNotificationData = async (notificationData, backtest) => {
2807
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
2823
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
2808
2824
  const key = backtest ? `backtest` : `live`;
2809
2825
  const isInitial = !this.getNotificationStorage.has(key);
2810
2826
  const instance = this.getNotificationStorage(backtest);
@@ -2819,7 +2835,7 @@ class PersistNotificationUtils {
2819
2835
  * @param Ctor - Custom IPersistNotificationInstance constructor
2820
2836
  */
2821
2837
  usePersistNotificationAdapter(Ctor) {
2822
- LOGGER_SERVICE$7.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
2838
+ LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
2823
2839
  this.PersistNotificationInstanceCtor = Ctor;
2824
2840
  this.getNotificationStorage.clear();
2825
2841
  }
@@ -2829,21 +2845,21 @@ class PersistNotificationUtils {
2829
2845
  * instances are created with the updated base path.
2830
2846
  */
2831
2847
  clear() {
2832
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
2848
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
2833
2849
  this.getNotificationStorage.clear();
2834
2850
  }
2835
2851
  /**
2836
2852
  * Switches to the default file-based PersistNotificationInstance.
2837
2853
  */
2838
2854
  useJson() {
2839
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
2855
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
2840
2856
  this.usePersistNotificationAdapter(PersistNotificationInstance);
2841
2857
  }
2842
2858
  /**
2843
2859
  * Switches to PersistNotificationDummyInstance (all operations are no-ops).
2844
2860
  */
2845
2861
  useDummy() {
2846
- LOGGER_SERVICE$7.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
2862
+ LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
2847
2863
  this.usePersistNotificationAdapter(PersistNotificationDummyInstance);
2848
2864
  }
2849
2865
  }
@@ -2967,7 +2983,7 @@ class PersistLogUtils {
2967
2983
  * @returns Promise resolving to array of log entries
2968
2984
  */
2969
2985
  this.readLogData = async () => {
2970
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
2986
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
2971
2987
  const isInitial = !this._logInstance;
2972
2988
  const instance = this.getLogInstance();
2973
2989
  await instance.waitForInit(isInitial);
@@ -2981,7 +2997,7 @@ class PersistLogUtils {
2981
2997
  * @returns Promise that resolves when write is complete
2982
2998
  */
2983
2999
  this.writeLogData = async (logData) => {
2984
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
3000
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
2985
3001
  const isInitial = !this._logInstance;
2986
3002
  const instance = this.getLogInstance();
2987
3003
  await instance.waitForInit(isInitial);
@@ -3006,7 +3022,7 @@ class PersistLogUtils {
3006
3022
  * @param Ctor - Custom IPersistLogInstance constructor
3007
3023
  */
3008
3024
  usePersistLogAdapter(Ctor) {
3009
- LOGGER_SERVICE$7.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
3025
+ LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
3010
3026
  this.PersistLogInstanceCtor = Ctor;
3011
3027
  this._logInstance = null;
3012
3028
  }
@@ -3015,21 +3031,21 @@ class PersistLogUtils {
3015
3031
  * Call when process.cwd() changes between strategy iterations.
3016
3032
  */
3017
3033
  clear() {
3018
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
3034
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
3019
3035
  this._logInstance = null;
3020
3036
  }
3021
3037
  /**
3022
3038
  * Switches to the default file-based PersistLogInstance.
3023
3039
  */
3024
3040
  useJson() {
3025
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
3041
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
3026
3042
  this.usePersistLogAdapter(PersistLogInstance);
3027
3043
  }
3028
3044
  /**
3029
3045
  * Switches to PersistLogDummyInstance (all operations are no-ops).
3030
3046
  */
3031
3047
  useDummy() {
3032
- LOGGER_SERVICE$7.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
3048
+ LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
3033
3049
  this.usePersistLogAdapter(PersistLogDummyInstance);
3034
3050
  }
3035
3051
  }
@@ -3191,7 +3207,7 @@ class PersistMeasureUtils {
3191
3207
  * @returns Promise resolving to cached value, or null if not found / soft-deleted
3192
3208
  */
3193
3209
  this.readMeasureData = async (bucket, key) => {
3194
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3210
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3195
3211
  const isInitial = !this.getMeasureStorage.has(bucket);
3196
3212
  const instance = this.getMeasureStorage(bucket);
3197
3213
  await instance.waitForInit(isInitial);
@@ -3207,7 +3223,7 @@ class PersistMeasureUtils {
3207
3223
  * @returns Promise that resolves when write is complete
3208
3224
  */
3209
3225
  this.writeMeasureData = async (data, bucket, key, when) => {
3210
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3226
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3211
3227
  const isInitial = !this.getMeasureStorage.has(bucket);
3212
3228
  const instance = this.getMeasureStorage(bucket);
3213
3229
  await instance.waitForInit(isInitial);
@@ -3222,7 +3238,7 @@ class PersistMeasureUtils {
3222
3238
  * @returns Promise that resolves when removal is complete
3223
3239
  */
3224
3240
  this.removeMeasureData = async (bucket, key) => {
3225
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3241
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3226
3242
  const isInitial = !this.getMeasureStorage.has(bucket);
3227
3243
  const instance = this.getMeasureStorage(bucket);
3228
3244
  await instance.waitForInit(isInitial);
@@ -3236,7 +3252,7 @@ class PersistMeasureUtils {
3236
3252
  * @param Ctor - Custom IPersistMeasureInstance constructor
3237
3253
  */
3238
3254
  usePersistMeasureAdapter(Ctor) {
3239
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
3255
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
3240
3256
  this.PersistMeasureInstanceCtor = Ctor;
3241
3257
  this.getMeasureStorage.clear();
3242
3258
  }
@@ -3248,7 +3264,7 @@ class PersistMeasureUtils {
3248
3264
  * @returns AsyncGenerator yielding entry keys
3249
3265
  */
3250
3266
  async *listMeasureData(bucket) {
3251
- LOGGER_SERVICE$7.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3267
+ LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3252
3268
  const isInitial = !this.getMeasureStorage.has(bucket);
3253
3269
  const instance = this.getMeasureStorage(bucket);
3254
3270
  await instance.waitForInit(isInitial);
@@ -3259,21 +3275,21 @@ class PersistMeasureUtils {
3259
3275
  * Call when process.cwd() changes between strategy iterations.
3260
3276
  */
3261
3277
  clear() {
3262
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
3278
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
3263
3279
  this.getMeasureStorage.clear();
3264
3280
  }
3265
3281
  /**
3266
3282
  * Switches to the default file-based PersistMeasureInstance.
3267
3283
  */
3268
3284
  useJson() {
3269
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
3285
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
3270
3286
  this.usePersistMeasureAdapter(PersistMeasureInstance);
3271
3287
  }
3272
3288
  /**
3273
3289
  * Switches to PersistMeasureDummyInstance (all operations are no-ops).
3274
3290
  */
3275
3291
  useDummy() {
3276
- LOGGER_SERVICE$7.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
3292
+ LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
3277
3293
  this.usePersistMeasureAdapter(PersistMeasureDummyInstance);
3278
3294
  }
3279
3295
  }
@@ -3432,7 +3448,7 @@ class PersistIntervalUtils {
3432
3448
  * @returns Promise resolving to marker data, or null if not found / soft-deleted
3433
3449
  */
3434
3450
  this.readIntervalData = async (bucket, key) => {
3435
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3451
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
3436
3452
  const isInitial = !this.getIntervalStorage.has(bucket);
3437
3453
  const instance = this.getIntervalStorage(bucket);
3438
3454
  await instance.waitForInit(isInitial);
@@ -3448,7 +3464,7 @@ class PersistIntervalUtils {
3448
3464
  * @returns Promise that resolves when write is complete
3449
3465
  */
3450
3466
  this.writeIntervalData = async (data, bucket, key, when) => {
3451
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3467
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
3452
3468
  const isInitial = !this.getIntervalStorage.has(bucket);
3453
3469
  const instance = this.getIntervalStorage(bucket);
3454
3470
  await instance.waitForInit(isInitial);
@@ -3463,7 +3479,7 @@ class PersistIntervalUtils {
3463
3479
  * @returns Promise that resolves when removal is complete
3464
3480
  */
3465
3481
  this.removeIntervalData = async (bucket, key) => {
3466
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3482
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
3467
3483
  const isInitial = !this.getIntervalStorage.has(bucket);
3468
3484
  const instance = this.getIntervalStorage(bucket);
3469
3485
  await instance.waitForInit(isInitial);
@@ -3477,7 +3493,7 @@ class PersistIntervalUtils {
3477
3493
  * @param Ctor - Custom IPersistIntervalInstance constructor
3478
3494
  */
3479
3495
  usePersistIntervalAdapter(Ctor) {
3480
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
3496
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
3481
3497
  this.PersistIntervalInstanceCtor = Ctor;
3482
3498
  this.getIntervalStorage.clear();
3483
3499
  }
@@ -3489,7 +3505,7 @@ class PersistIntervalUtils {
3489
3505
  * @returns AsyncGenerator yielding marker keys
3490
3506
  */
3491
3507
  async *listIntervalData(bucket) {
3492
- LOGGER_SERVICE$7.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3508
+ LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
3493
3509
  const isInitial = !this.getIntervalStorage.has(bucket);
3494
3510
  const instance = this.getIntervalStorage(bucket);
3495
3511
  await instance.waitForInit(isInitial);
@@ -3500,21 +3516,21 @@ class PersistIntervalUtils {
3500
3516
  * Call when process.cwd() changes between strategy iterations.
3501
3517
  */
3502
3518
  clear() {
3503
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
3519
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
3504
3520
  this.getIntervalStorage.clear();
3505
3521
  }
3506
3522
  /**
3507
3523
  * Switches to the default file-based PersistIntervalInstance.
3508
3524
  */
3509
3525
  useJson() {
3510
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
3526
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
3511
3527
  this.usePersistIntervalAdapter(PersistIntervalInstance);
3512
3528
  }
3513
3529
  /**
3514
3530
  * Switches to PersistIntervalDummyInstance (all operations are no-ops).
3515
3531
  */
3516
3532
  useDummy() {
3517
- LOGGER_SERVICE$7.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
3533
+ LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
3518
3534
  this.usePersistIntervalAdapter(PersistIntervalDummyInstance);
3519
3535
  }
3520
3536
  }
@@ -3720,7 +3736,7 @@ class PersistMemoryUtils {
3720
3736
  * @returns Promise resolving to entry data, or null if not found / soft-deleted
3721
3737
  */
3722
3738
  this.readMemoryData = async (signalId, bucketName, memoryId) => {
3723
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
3739
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
3724
3740
  const key = `${signalId}:${bucketName}`;
3725
3741
  const isInitial = !this.getMemoryStorage.has(key);
3726
3742
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3737,7 +3753,7 @@ class PersistMemoryUtils {
3737
3753
  * @returns Promise resolving to true if entry exists
3738
3754
  */
3739
3755
  this.hasMemoryData = async (signalId, bucketName, memoryId) => {
3740
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
3756
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
3741
3757
  const key = `${signalId}:${bucketName}`;
3742
3758
  const isInitial = !this.getMemoryStorage.has(key);
3743
3759
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3756,7 +3772,7 @@ class PersistMemoryUtils {
3756
3772
  * @returns Promise that resolves when write is complete
3757
3773
  */
3758
3774
  this.writeMemoryData = async (data, signalId, bucketName, memoryId, when) => {
3759
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
3775
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
3760
3776
  const key = `${signalId}:${bucketName}`;
3761
3777
  const isInitial = !this.getMemoryStorage.has(key);
3762
3778
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3773,7 +3789,7 @@ class PersistMemoryUtils {
3773
3789
  * @returns Promise that resolves when removal is complete
3774
3790
  */
3775
3791
  this.removeMemoryData = async (signalId, bucketName, memoryId) => {
3776
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
3792
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
3777
3793
  const key = `${signalId}:${bucketName}`;
3778
3794
  const isInitial = !this.getMemoryStorage.has(key);
3779
3795
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3785,7 +3801,7 @@ class PersistMemoryUtils {
3785
3801
  * Call when process.cwd() changes between strategy iterations.
3786
3802
  */
3787
3803
  this.clear = () => {
3788
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
3804
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
3789
3805
  this.getMemoryStorage.clear();
3790
3806
  };
3791
3807
  /**
@@ -3796,7 +3812,7 @@ class PersistMemoryUtils {
3796
3812
  * @param bucketName - Bucket name
3797
3813
  */
3798
3814
  this.dispose = (signalId, bucketName) => {
3799
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
3815
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
3800
3816
  const key = `${signalId}:${bucketName}`;
3801
3817
  this.getMemoryStorage.clear(key);
3802
3818
  };
@@ -3808,7 +3824,7 @@ class PersistMemoryUtils {
3808
3824
  * @param Ctor - Custom IPersistMemoryInstance constructor
3809
3825
  */
3810
3826
  usePersistMemoryAdapter(Ctor) {
3811
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
3827
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
3812
3828
  this.PersistMemoryInstanceCtor = Ctor;
3813
3829
  this.getMemoryStorage.clear();
3814
3830
  }
@@ -3822,7 +3838,7 @@ class PersistMemoryUtils {
3822
3838
  * @returns AsyncGenerator yielding `{ memoryId, data }` tuples
3823
3839
  */
3824
3840
  async *listMemoryData(signalId, bucketName) {
3825
- LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
3841
+ LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
3826
3842
  const key = `${signalId}:${bucketName}`;
3827
3843
  const isInitial = !this.getMemoryStorage.has(key);
3828
3844
  const instance = this.getMemoryStorage(signalId, bucketName);
@@ -3833,14 +3849,14 @@ class PersistMemoryUtils {
3833
3849
  * Switches to the default file-based PersistMemoryInstance.
3834
3850
  */
3835
3851
  useJson() {
3836
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
3852
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
3837
3853
  this.usePersistMemoryAdapter(PersistMemoryInstance);
3838
3854
  }
3839
3855
  /**
3840
3856
  * Switches to PersistMemoryDummyInstance (all operations are no-ops).
3841
3857
  */
3842
3858
  useDummy() {
3843
- LOGGER_SERVICE$7.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
3859
+ LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
3844
3860
  this.usePersistMemoryAdapter(PersistMemoryDummyInstance);
3845
3861
  }
3846
3862
  }
@@ -3989,7 +4005,7 @@ class PersistRecentUtils {
3989
4005
  * @returns Promise resolving to recent signal or null if none persisted
3990
4006
  */
3991
4007
  this.readRecentData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
3992
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
4008
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
3993
4009
  const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
3994
4010
  const isInitial = !this.getStorage.has(key);
3995
4011
  const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
@@ -4010,7 +4026,7 @@ class PersistRecentUtils {
4010
4026
  * @returns Promise that resolves when write is complete
4011
4027
  */
4012
4028
  this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest, when) => {
4013
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
4029
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
4014
4030
  const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
4015
4031
  const isInitial = !this.getStorage.has(key);
4016
4032
  const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
@@ -4043,7 +4059,7 @@ class PersistRecentUtils {
4043
4059
  * @param Ctor - Custom IPersistRecentInstance constructor
4044
4060
  */
4045
4061
  usePersistRecentAdapter(Ctor) {
4046
- LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
4062
+ LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
4047
4063
  this.PersistRecentInstanceCtor = Ctor;
4048
4064
  this.getStorage.clear();
4049
4065
  }
@@ -4052,21 +4068,21 @@ class PersistRecentUtils {
4052
4068
  * Call when process.cwd() changes between strategy iterations.
4053
4069
  */
4054
4070
  clear() {
4055
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
4071
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
4056
4072
  this.getStorage.clear();
4057
4073
  }
4058
4074
  /**
4059
4075
  * Switches to the default file-based PersistRecentInstance.
4060
4076
  */
4061
4077
  useJson() {
4062
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
4078
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
4063
4079
  this.usePersistRecentAdapter(PersistRecentInstance);
4064
4080
  }
4065
4081
  /**
4066
4082
  * Switches to PersistRecentDummyInstance (all operations are no-ops).
4067
4083
  */
4068
4084
  useDummy() {
4069
- LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
4085
+ LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
4070
4086
  this.usePersistRecentAdapter(PersistRecentDummyInstance);
4071
4087
  }
4072
4088
  }
@@ -4201,7 +4217,7 @@ class PersistStateUtils {
4201
4217
  * @returns Promise that resolves when initialization is complete
4202
4218
  */
4203
4219
  this.waitForInit = async (signalId, bucketName, initial) => {
4204
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
4220
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
4205
4221
  const key = `${signalId}:${bucketName}`;
4206
4222
  const isInitial = initial && !this.getStateStorage.has(key);
4207
4223
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4216,7 +4232,7 @@ class PersistStateUtils {
4216
4232
  * @returns Promise resolving to state data or null if none persisted
4217
4233
  */
4218
4234
  this.readStateData = async (signalId, bucketName) => {
4219
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
4235
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
4220
4236
  const key = `${signalId}:${bucketName}`;
4221
4237
  const isInitial = !this.getStateStorage.has(key);
4222
4238
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4234,7 +4250,7 @@ class PersistStateUtils {
4234
4250
  * @returns Promise that resolves when write is complete
4235
4251
  */
4236
4252
  this.writeStateData = async (data, signalId, bucketName, when) => {
4237
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
4253
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
4238
4254
  const key = `${signalId}:${bucketName}`;
4239
4255
  const isInitial = !this.getStateStorage.has(key);
4240
4256
  const instance = this.getStateStorage(signalId, bucketName);
@@ -4245,14 +4261,14 @@ class PersistStateUtils {
4245
4261
  * Switches to PersistStateDummyInstance (all operations are no-ops).
4246
4262
  */
4247
4263
  this.useDummy = () => {
4248
- LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
4264
+ LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
4249
4265
  this.usePersistStateAdapter(PersistStateDummyInstance);
4250
4266
  };
4251
4267
  /**
4252
4268
  * Switches to the default file-based PersistStateInstance.
4253
4269
  */
4254
4270
  this.useJson = () => {
4255
- LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
4271
+ LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
4256
4272
  this.usePersistStateAdapter(PersistStateInstance);
4257
4273
  };
4258
4274
  /**
@@ -4260,7 +4276,7 @@ class PersistStateUtils {
4260
4276
  * Call when process.cwd() changes between strategy iterations.
4261
4277
  */
4262
4278
  this.clear = () => {
4263
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
4279
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
4264
4280
  this.getStateStorage.clear();
4265
4281
  };
4266
4282
  /**
@@ -4271,7 +4287,7 @@ class PersistStateUtils {
4271
4287
  * @param bucketName - Bucket name
4272
4288
  */
4273
4289
  this.dispose = (signalId, bucketName) => {
4274
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
4290
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
4275
4291
  const key = `${signalId}:${bucketName}`;
4276
4292
  this.getStateStorage.clear(key);
4277
4293
  };
@@ -4283,7 +4299,7 @@ class PersistStateUtils {
4283
4299
  * @param Ctor - Custom IPersistStateInstance constructor
4284
4300
  */
4285
4301
  usePersistStateAdapter(Ctor) {
4286
- LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
4302
+ LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
4287
4303
  this.PersistStateInstanceCtor = Ctor;
4288
4304
  this.getStateStorage.clear();
4289
4305
  }
@@ -4423,7 +4439,7 @@ class PersistSessionUtils {
4423
4439
  * @returns Promise that resolves when initialization is complete
4424
4440
  */
4425
4441
  this.waitForInit = async (strategyName, exchangeName, frameName, initial) => {
4426
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
4442
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
4427
4443
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4428
4444
  const isInitial = initial && !this.getSessionStorage.has(key);
4429
4445
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4439,7 +4455,7 @@ class PersistSessionUtils {
4439
4455
  * @returns Promise resolving to session data or null if none persisted
4440
4456
  */
4441
4457
  this.readSessionData = async (strategyName, exchangeName, frameName) => {
4442
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
4458
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
4443
4459
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4444
4460
  const isInitial = !this.getSessionStorage.has(key);
4445
4461
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4458,7 +4474,7 @@ class PersistSessionUtils {
4458
4474
  * @returns Promise that resolves when write is complete
4459
4475
  */
4460
4476
  this.writeSessionData = async (data, strategyName, exchangeName, frameName, when) => {
4461
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
4477
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
4462
4478
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4463
4479
  const isInitial = !this.getSessionStorage.has(key);
4464
4480
  const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
@@ -4469,14 +4485,14 @@ class PersistSessionUtils {
4469
4485
  * Switches to PersistSessionDummyInstance (all operations are no-ops).
4470
4486
  */
4471
4487
  this.useDummy = () => {
4472
- LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
4488
+ LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
4473
4489
  this.usePersistSessionAdapter(PersistSessionDummyInstance);
4474
4490
  };
4475
4491
  /**
4476
4492
  * Switches to the default file-based PersistSessionInstance.
4477
4493
  */
4478
4494
  this.useJson = () => {
4479
- LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
4495
+ LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
4480
4496
  this.usePersistSessionAdapter(PersistSessionInstance);
4481
4497
  };
4482
4498
  /**
@@ -4484,7 +4500,7 @@ class PersistSessionUtils {
4484
4500
  * Call when process.cwd() changes between strategy iterations.
4485
4501
  */
4486
4502
  this.clear = () => {
4487
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
4503
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
4488
4504
  this.getSessionStorage.clear();
4489
4505
  };
4490
4506
  /**
@@ -4496,7 +4512,7 @@ class PersistSessionUtils {
4496
4512
  * @param frameName - Frame identifier
4497
4513
  */
4498
4514
  this.dispose = (strategyName, exchangeName, frameName) => {
4499
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
4515
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
4500
4516
  const key = `${strategyName}:${exchangeName}:${frameName}`;
4501
4517
  this.getSessionStorage.clear(key);
4502
4518
  };
@@ -4508,7 +4524,7 @@ class PersistSessionUtils {
4508
4524
  * @param Ctor - Custom IPersistSessionInstance constructor
4509
4525
  */
4510
4526
  usePersistSessionAdapter(Ctor) {
4511
- LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
4527
+ LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
4512
4528
  this.PersistSessionInstanceCtor = Ctor;
4513
4529
  this.getSessionStorage.clear();
4514
4530
  }
@@ -4520,28 +4536,39 @@ class PersistSessionUtils {
4520
4536
  const PersistSessionAdapter = new PersistSessionUtils();
4521
4537
 
4522
4538
  var _a$2, _b$2;
4523
- const BUSY_DELAY = 100;
4524
4539
  const SET_BUSY_SYMBOL = Symbol("setBusy");
4525
4540
  const GET_BUSY_SYMBOL = Symbol("getBusy");
4526
4541
  const ACQUIRE_LOCK_SYMBOL = Symbol("acquireLock");
4527
4542
  const RELEASE_LOCK_SYMBOL = Symbol("releaseLock");
4543
+ /**
4544
+ * Body of the queued acquire operation.
4545
+ *
4546
+ * Parks the caller on `self._tick` whenever the lock is already busy: each
4547
+ * `releaseLock` emits on `_tick`, waking exactly the next queued acquirer
4548
+ * instead of polling on a fixed delay. The busy counter is bumped only after
4549
+ * the loop exits, so re-entry checks remain coherent under contention.
4550
+ *
4551
+ * @param self - The owning {@link Lock} instance.
4552
+ */
4528
4553
  const ACQUIRE_LOCK_FN = async (self) => {
4529
4554
  while (self[GET_BUSY_SYMBOL]()) {
4530
- await functoolsKit.sleep(BUSY_DELAY);
4555
+ // @ts-ignore
4556
+ await self._tick.toPromise();
4531
4557
  }
4532
4558
  self[SET_BUSY_SYMBOL](true);
4533
4559
  };
4534
4560
  /**
4535
4561
  * Mutual exclusion primitive for async TypeScript code.
4536
4562
  *
4537
- * Provides a reentrant-safe, queued lock that serializes access to a critical
4538
- * section across concurrent async callers. Internally tracks a busy counter so
4539
- * nested acquire/release pairs are detected and mis-matched releases throw
4540
- * immediately.
4563
+ * Provides a queued lock that serializes access to a critical section across
4564
+ * concurrent async callers. Wake-ups are event-driven (via an internal
4565
+ * `_tick` subject emitted on every `releaseLock`) rather than polling,
4566
+ * so contention does not incur a fixed delay.
4541
4567
  *
4542
- * Three usage styles are supported:
4568
+ * The busy counter detects mis-matched releases and throws immediately on
4569
+ * extra `releaseLock` calls.
4543
4570
  *
4544
- * **Manual acquire / release**
4571
+ * **Usage**
4545
4572
  * ```ts
4546
4573
  * await lock.acquireLock();
4547
4574
  * try {
@@ -4556,7 +4583,18 @@ const ACQUIRE_LOCK_FN = async (self) => {
4556
4583
  */
4557
4584
  class Lock {
4558
4585
  constructor() {
4586
+ /**
4587
+ * Outstanding acquires that have not yet been released.
4588
+ * Incremented in `[SET_BUSY_SYMBOL](true)`, decremented in `[SET_BUSY_SYMBOL](false)`.
4589
+ * A negative value indicates an extra `releaseLock` and throws on detection.
4590
+ */
4559
4591
  this._isBusy = 0;
4592
+ /**
4593
+ * Wake-up channel for {@link ACQUIRE_LOCK_FN}.
4594
+ * Every {@link releaseLock} emits a single tick that unblocks the next
4595
+ * queued acquirer parked on `toPromise()`.
4596
+ */
4597
+ this._tick = new functoolsKit.Subject();
4560
4598
  this[_a$2] = functoolsKit.queued(ACQUIRE_LOCK_FN);
4561
4599
  this[_b$2] = () => this[SET_BUSY_SYMBOL](false);
4562
4600
  /**
@@ -4577,16 +4615,19 @@ class Lock {
4577
4615
  await this[ACQUIRE_LOCK_SYMBOL](this);
4578
4616
  };
4579
4617
  /**
4580
- * Releases the lock previously acquired with {@link acquireLock}.
4618
+ * Releases the lock previously acquired with {@link acquireLock} and emits
4619
+ * on the internal `_tick` subject to wake the next queued acquirer.
4620
+ *
4581
4621
  * Must be called exactly once per successful {@link acquireLock} call,
4582
- * typically inside a `finally` block. Throws if called more times
4583
- * than the lock was acquired.
4622
+ * typically inside a `finally` block. Throws if called more times than
4623
+ * the lock was acquired.
4584
4624
  *
4585
4625
  * @returns {Promise<void>} Resolves once the lock has been released.
4586
4626
  * @throws {Error} If the lock is released more times than it was acquired.
4587
4627
  */
4588
4628
  this.releaseLock = async () => {
4589
4629
  await this[RELEASE_LOCK_SYMBOL]();
4630
+ await this._tick.next();
4590
4631
  };
4591
4632
  }
4592
4633
  [SET_BUSY_SYMBOL](isBusy) {
@@ -4601,18 +4642,166 @@ class Lock {
4601
4642
  }
4602
4643
  _a$2 = ACQUIRE_LOCK_SYMBOL, _b$2 = RELEASE_LOCK_SYMBOL;
4603
4644
 
4645
+ const METHOD_NAME_ADD_ACTIVITY = "LookupUtils.addActivity";
4646
+ const METHOD_NAME_REMOVE_ACTIVITY = "LookupUtils.removeActivity";
4647
+ const METHOD_NAME_LIST_ACTIVITY = "LookupUtils.listActivity";
4648
+ /** Logger service injected as DI singleton */
4649
+ const LOGGER_SERVICE$7 = new LoggerService();
4650
+ /**
4651
+ * Builds the composite {@link Key} used to register an activity in `_lookupMap`.
4652
+ *
4653
+ * Mirrors the {@link Key} type construction: appends `frameName` only when provided
4654
+ * (typical for backtest), then a `"backtest"` / `"live"` discriminator suffix.
4655
+ *
4656
+ * @param symbol - Trading pair symbol.
4657
+ * @param strategyName - Strategy schema name.
4658
+ * @param exchangeName - Exchange schema name.
4659
+ * @param frameName - Frame schema name; omitted from the key when falsy.
4660
+ * @param backtest - `true` for backtest, `false` for live.
4661
+ * @returns Colon-joined composite key.
4662
+ */
4663
+ const CREATE_KEY_FN$y = (symbol, strategyName, exchangeName, frameName, backtest) => {
4664
+ const parts = [symbol, strategyName, exchangeName];
4665
+ if (frameName)
4666
+ parts.push(frameName);
4667
+ parts.push(backtest ? "backtest" : "live");
4668
+ return parts.join(":");
4669
+ };
4670
+ /**
4671
+ * In-memory registry of currently running backtest and live activities.
4672
+ *
4673
+ * Purpose:
4674
+ * - Each `Backtest.run` / `Live.run` / per-strategy walker iteration registers an
4675
+ * {@link IActivityEntry} on start and removes it on completion.
4676
+ * - `Candle.spinLock` consults {@link isParallel} to decide whether the event-loop
4677
+ * hand-off (post-candle-fetch spin) is worth performing. With a single active
4678
+ * workload there is no peer to yield to, so the spin is skipped entirely.
4679
+ *
4680
+ * Exposed as the `Lookup` singleton; no constructor parameters.
4681
+ *
4682
+ * @example
4683
+ * ```typescript
4684
+ * Lookup.addActivity({ symbol: "BTCUSDT", context, backtest: true });
4685
+ * try {
4686
+ * for await (const _ of run(symbol, context)) { ... }
4687
+ * } finally {
4688
+ * Lookup.removeActivity({ symbol: "BTCUSDT", context, backtest: true });
4689
+ * }
4690
+ * ```
4691
+ */
4692
+ class LookupUtils {
4693
+ constructor() {
4694
+ /** Active entries keyed by their composite {@link Key}. */
4695
+ this._lookupMap = new Map();
4696
+ /**
4697
+ * Registers a backtest or live activity in the lookup map.
4698
+ * Idempotent for identical keys — duplicate calls overwrite the existing entry.
4699
+ *
4700
+ * @param activity - Activity descriptor identifying the running workload.
4701
+ */
4702
+ this.addActivity = (activity) => {
4703
+ LOGGER_SERVICE$7.info(METHOD_NAME_ADD_ACTIVITY, {
4704
+ activity,
4705
+ });
4706
+ const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
4707
+ this._lookupMap.set(key, activity);
4708
+ };
4709
+ /**
4710
+ * Removes a previously registered activity from the lookup map.
4711
+ * Must be paired with a prior {@link addActivity}, typically in a `finally` block,
4712
+ * so a thrown error in the underlying run does not leave a stale entry behind.
4713
+ *
4714
+ * @param activity - Activity descriptor matching the one passed to {@link addActivity}.
4715
+ */
4716
+ this.removeActivity = (activity) => {
4717
+ LOGGER_SERVICE$7.info(METHOD_NAME_REMOVE_ACTIVITY, {
4718
+ activity,
4719
+ });
4720
+ const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
4721
+ this._lookupMap.delete(key);
4722
+ };
4723
+ /**
4724
+ * Returns a snapshot of currently active entries.
4725
+ *
4726
+ * @returns Array of all activities present in the lookup map at call time.
4727
+ */
4728
+ this.listActivity = () => {
4729
+ LOGGER_SERVICE$7.info(METHOD_NAME_LIST_ACTIVITY);
4730
+ return Array.from(this._lookupMap.values());
4731
+ };
4732
+ }
4733
+ /**
4734
+ * `true` when more than one activity is currently registered.
4735
+ * Used by `Candle.spinLock` to decide whether yielding the event loop is useful.
4736
+ */
4737
+ get isParallel() {
4738
+ return this._lookupMap.size > 1;
4739
+ }
4740
+ }
4741
+ /**
4742
+ * Process-wide singleton instance of {@link LookupUtils}.
4743
+ * Imported by `Backtest`, `Live`, `WalkerLogicPrivateService` (registration sites)
4744
+ * and by `Candle` (read-only consumer via `isParallel`).
4745
+ */
4746
+ const Lookup = new LookupUtils();
4747
+
4604
4748
  const METHOD_NAME_ACQUIRE_LOCK = "CandleUtils.acquireLock";
4605
4749
  const METHOD_NAME_RELEASE_LOCK = "CandleUtils.releaseLock";
4750
+ const METHOD_NAME_SPIN_LOCK = "CandleUtils.spinLock";
4751
+ /**
4752
+ * Upper bound (ms) on how long `spinLock` may park before falling through.
4753
+ * If no peer backtest acquires the candle-fetch mutex within this window,
4754
+ * the spinner proceeds without further yielding.
4755
+ */
4756
+ const ROTATE_DELAY = 50;
4606
4757
  /** Logger service injected as DI singleton */
4607
4758
  const LOGGER_SERVICE$6 = new LoggerService();
4759
+ /**
4760
+ * Process-wide coordinator for candle-fetch serialization and cooperative
4761
+ * yielding between parallel backtests.
4762
+ *
4763
+ * Two complementary primitives are exposed:
4764
+ * - **Mutex** via {@link acquireLock} / {@link releaseLock}: prevents concurrent
4765
+ * candle fetches from racing on the same exchange.
4766
+ * - **Spin hand-off** via {@link spinLock}: invoked after a fetch completes to
4767
+ * give peer backtests waiting on the mutex a chance to run, so multiple
4768
+ * `Backtest.run` workloads interleave instead of one monopolizing the loop.
4769
+ *
4770
+ * All three operations are no-ops when `CC_ENABLE_CANDLE_FETCH_MUTEX` is `false`.
4771
+ * The spin additionally requires `CC_ENABLE_BACKTEST_PARALLEL_SPIN` and at least
4772
+ * two registered activities in `Lookup` (see `Lookup.isParallel`).
4773
+ *
4774
+ * @example
4775
+ * ```typescript
4776
+ * await Candle.acquireLock("ClientExchange GET_CANDLES_FN");
4777
+ * try {
4778
+ * const candles = await fetchFromExchange(...);
4779
+ * return candles;
4780
+ * } finally {
4781
+ * await Candle.releaseLock("ClientExchange GET_CANDLES_FN");
4782
+ * }
4783
+ * // Elsewhere, after a fetch completes inside a backtest loop:
4784
+ * await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
4785
+ * ```
4786
+ */
4608
4787
  class CandleUtils {
4609
4788
  constructor() {
4789
+ /** Underlying mutex serializing candle fetches across concurrent callers. */
4610
4790
  this._lock = new Lock();
4611
4791
  /**
4612
- * Acquires the candle fetch mutex if CC_ENABLE_CANDLE_FETCH_MUTEX is enabled.
4792
+ * Emits whenever {@link acquireLock} successfully takes the mutex.
4793
+ * Awaited by {@link spinLock} to detect that a peer backtest has just
4794
+ * started its own fetch — the signal that yielding now will be productive.
4795
+ */
4796
+ this._spin = new functoolsKit.Subject();
4797
+ /**
4798
+ * Acquires the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
4613
4799
  * Prevents concurrent candle fetches from the same exchange.
4614
4800
  *
4615
- * @param source - Caller identifier for logging
4801
+ * On successful acquisition, emits on the internal spin subject so any
4802
+ * peer parked inside {@link spinLock} can wake up and proceed.
4803
+ *
4804
+ * @param source - Caller identifier for logging.
4616
4805
  */
4617
4806
  this.acquireLock = async (source) => {
4618
4807
  LOGGER_SERVICE$6.info(METHOD_NAME_ACQUIRE_LOCK, {
@@ -4621,13 +4810,14 @@ class CandleUtils {
4621
4810
  if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
4622
4811
  return;
4623
4812
  }
4624
- return await this._lock.acquireLock();
4813
+ await this._lock.acquireLock();
4814
+ await this._spin.next();
4625
4815
  };
4626
4816
  /**
4627
- * Releases the candle fetch mutex if CC_ENABLE_CANDLE_FETCH_MUTEX is enabled.
4628
- * Must be called after acquireLock, typically in a finally block.
4817
+ * Releases the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
4818
+ * Must be called after {@link acquireLock}, typically in a `finally` block.
4629
4819
  *
4630
- * @param source - Caller identifier for logging
4820
+ * @param source - Caller identifier for logging.
4631
4821
  */
4632
4822
  this.releaseLock = async (source) => {
4633
4823
  LOGGER_SERVICE$6.info(METHOD_NAME_RELEASE_LOCK, {
@@ -4638,8 +4828,47 @@ class CandleUtils {
4638
4828
  }
4639
4829
  return await this._lock.releaseLock();
4640
4830
  };
4831
+ /**
4832
+ * Cooperative event-loop hand-off invoked by `BacktestLogicPrivateService`
4833
+ * after a successful `getNextCandles`. Allows peer backtests waiting on the
4834
+ * candle-fetch mutex to run before the current backtest fetches the next chunk.
4835
+ *
4836
+ * Waits for one of:
4837
+ * - a peer calling {@link acquireLock} (signalled via the spin subject), or
4838
+ * - a `ROTATE_DELAY` ms timeout, so the caller never parks indefinitely.
4839
+ *
4840
+ * Returns immediately as a no-op when any of these is true:
4841
+ * - `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled (mutex is off entirely),
4842
+ * - `CC_ENABLE_BACKTEST_PARALLEL_SPIN` is disabled (cooperative yielding off),
4843
+ * - `Lookup.isParallel` is `false` (only one active workload — no peer to yield to).
4844
+ *
4845
+ * @param source - Caller identifier for logging.
4846
+ */
4847
+ this.spinLock = async (source) => {
4848
+ LOGGER_SERVICE$6.info(METHOD_NAME_SPIN_LOCK, {
4849
+ source,
4850
+ });
4851
+ if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
4852
+ return;
4853
+ }
4854
+ if (!GLOBAL_CONFIG.CC_ENABLE_BACKTEST_PARALLEL_SPIN) {
4855
+ return;
4856
+ }
4857
+ if (!Lookup.isParallel) {
4858
+ return;
4859
+ }
4860
+ await Promise.race([
4861
+ this._spin.toPromise(),
4862
+ functoolsKit.sleep(ROTATE_DELAY),
4863
+ ]);
4864
+ };
4641
4865
  }
4642
4866
  }
4867
+ /**
4868
+ * Process-wide singleton instance of {@link CandleUtils}.
4869
+ * Imported by `ClientExchange` (mutex around exchange fetches) and by
4870
+ * `BacktestLogicPrivateService` (spin hand-off between parallel backtests).
4871
+ */
4643
4872
  const Candle = new CandleUtils();
4644
4873
 
4645
4874
  const MS_PER_MINUTE$7 = 60000;
@@ -19173,9 +19402,28 @@ const TICK_FN = async (self, symbol, when) => {
19173
19402
  return { type: "error", __error__: SYMBOL_FN_ERROR, reason: "TICK_FN", message: functoolsKit.getErrorMessage(error) };
19174
19403
  }
19175
19404
  };
19405
+ /**
19406
+ * Wraps `exchangeCoreService.getNextCandles` with error capture and a cooperative
19407
+ * event-loop hand-off after a successful fetch.
19408
+ *
19409
+ * Calls `Candle.spinLock(...)` on success: when multiple backtests run in parallel
19410
+ * (`Lookup.isParallel === true`), this yields the event loop so a peer waiting on
19411
+ * the candle-fetch mutex can take its turn, producing round-robin interleaving
19412
+ * instead of one backtest monopolizing the loop until completion. The spin is a
19413
+ * no-op for single-workload runs.
19414
+ *
19415
+ * @param self - Owning service instance, used for logging and exchange access.
19416
+ * @param symbol - Trading pair symbol.
19417
+ * @param candlesNeeded - Number of 1m candles to request.
19418
+ * @param bufferStartTime - Inclusive start time for the fetch window.
19419
+ * @param logMeta - Extra structured fields appended to the warn log on failure.
19420
+ * @returns Fetched candles, or a {@link TFnError} discriminated union on failure.
19421
+ */
19176
19422
  const GET_CANDLES_FN = async (self, symbol, candlesNeeded, bufferStartTime, logMeta) => {
19177
19423
  try {
19178
- return await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
19424
+ const result = await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
19425
+ await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
19426
+ return result;
19179
19427
  }
19180
19428
  catch (error) {
19181
19429
  console.error(`backtestLogicPrivateService getNextCandles failed symbol=${symbol} strategyName=${self.methodContextService.context.strategyName} exchangeName=${self.methodContextService.context.exchangeName}`);
@@ -20061,6 +20309,15 @@ class WalkerLogicPrivateService {
20061
20309
  exchangeName: context.exchangeName,
20062
20310
  frameName: context.frameName,
20063
20311
  });
20312
+ Lookup.addActivity({
20313
+ symbol,
20314
+ context: {
20315
+ strategyName,
20316
+ exchangeName: context.exchangeName,
20317
+ frameName: context.frameName,
20318
+ },
20319
+ backtest: true,
20320
+ });
20064
20321
  try {
20065
20322
  await functoolsKit.resolveDocuments(iterator);
20066
20323
  }
@@ -20076,6 +20333,17 @@ class WalkerLogicPrivateService {
20076
20333
  await CALL_STRATEGY_ERROR_CALLBACKS_FN(this, walkerSchema, strategyName, symbol, error);
20077
20334
  continue;
20078
20335
  }
20336
+ finally {
20337
+ Lookup.removeActivity({
20338
+ symbol,
20339
+ context: {
20340
+ strategyName,
20341
+ exchangeName: context.exchangeName,
20342
+ frameName: context.frameName,
20343
+ },
20344
+ backtest: true,
20345
+ });
20346
+ }
20079
20347
  this.loggerService.info("walkerLogicPrivateService backtest complete", {
20080
20348
  strategyName,
20081
20349
  symbol,
@@ -36095,6 +36363,7 @@ const Exchange = new ExchangeUtils();
36095
36363
 
36096
36364
  const WARM_CANDLES_METHOD_NAME = "cache.warmCandles";
36097
36365
  const CHECK_CANDLES_METHOD_NAME = "cache.checkCandles";
36366
+ const CACHE_CANDLES_METHOD_NAME = "cache.cacheCandles";
36098
36367
  const MS_PER_MINUTE$3 = 60000;
36099
36368
  const INTERVAL_MINUTES$3 = {
36100
36369
  "1m": 1,
@@ -36126,6 +36395,34 @@ const PRINT_PROGRESS_FN = (fetched, total, symbol, interval) => {
36126
36395
  process.stdout.write("\n");
36127
36396
  }
36128
36397
  };
36398
+ /**
36399
+ * Retry-wrapped pipeline: validates the cache via `checkCandles` and, on miss,
36400
+ * fills it via `warmCandles` and rethrows to trigger a retry pass that
36401
+ * re-validates the freshly cached range. Limited to 2 attempts.
36402
+ */
36403
+ const CACHE_CANDLES_FN = functoolsKit.retry(async (interval, dto, onWarmStart, onCheckStart) => {
36404
+ try {
36405
+ onWarmStart && onWarmStart(dto.symbol, interval, dto.from, dto.to);
36406
+ await checkCandles({
36407
+ exchangeName: dto.exchangeName,
36408
+ from: dto.from,
36409
+ to: dto.to,
36410
+ symbol: dto.symbol,
36411
+ interval: interval,
36412
+ });
36413
+ }
36414
+ catch (error) {
36415
+ onCheckStart && onCheckStart(dto.symbol, interval, dto.from, dto.to);
36416
+ await warmCandles({
36417
+ symbol: dto.symbol,
36418
+ exchangeName: dto.exchangeName,
36419
+ from: dto.from,
36420
+ to: dto.to,
36421
+ interval: interval,
36422
+ });
36423
+ throw error;
36424
+ }
36425
+ }, 2);
36129
36426
  /**
36130
36427
  * Checks cached candle presence via the persist adapter.
36131
36428
  * Issues one ranged read; adapter-side `hasValue` covers each expected timestamp,
@@ -36201,6 +36498,34 @@ async function warmCandles(params) {
36201
36498
  PRINT_PROGRESS_FN(fetched, totalCandles, symbol, interval);
36202
36499
  }
36203
36500
  }
36501
+ /**
36502
+ * Ensures candles for the given range are present in persist storage.
36503
+ * Runs a check-then-warm pipeline with one retry: validates the cache first
36504
+ * and, on a miss, downloads the missing data and re-validates.
36505
+ *
36506
+ * @param params - Combined cache parameters with optional lifecycle callbacks
36507
+ */
36508
+ async function cacheCandles({ symbol, interval, from, to, exchangeName, onCheckStart = (symbol, interval, from, to) => {
36509
+ process.stdout.write("\n");
36510
+ process.stdout.write(`Checking candles cache for ${symbol} ${interval} from ${from} to ${to}\n`);
36511
+ }, onWarmStart = (symbol, interval, from, to) => {
36512
+ process.stdout.write("\n\n");
36513
+ process.stdout.write(`Caching candles for ${symbol} ${interval} from ${from} to ${to}\n`);
36514
+ }, }) {
36515
+ backtest.loggerService.info(CACHE_CANDLES_METHOD_NAME, {
36516
+ symbol,
36517
+ exchangeName,
36518
+ interval,
36519
+ from,
36520
+ to,
36521
+ });
36522
+ await CACHE_CANDLES_FN(interval, {
36523
+ exchangeName,
36524
+ from,
36525
+ to,
36526
+ symbol,
36527
+ }, onWarmStart, onCheckStart);
36528
+ }
36204
36529
 
36205
36530
  const METHOD_NAME = "validate.validate";
36206
36531
  /**
@@ -41986,11 +42311,21 @@ const INSTANCE_TASK_FN$2 = async (symbol, context, self) => {
41986
42311
  self._isStopped = false;
41987
42312
  self._isDone = false;
41988
42313
  }
42314
+ Lookup.addActivity({
42315
+ symbol,
42316
+ context,
42317
+ backtest: true,
42318
+ });
41989
42319
  for await (const _ of self.run(symbol, context)) {
41990
42320
  if (self._isStopped) {
41991
42321
  break;
41992
42322
  }
41993
42323
  }
42324
+ Lookup.removeActivity({
42325
+ symbol,
42326
+ context,
42327
+ backtest: true,
42328
+ });
41994
42329
  if (!self._isDone) {
41995
42330
  await doneBacktestSubject.next({
41996
42331
  exchangeName: context.exchangeName,
@@ -44637,11 +44972,21 @@ const INSTANCE_TASK_FN$1 = async (symbol, context, self) => {
44637
44972
  self._isStopped = false;
44638
44973
  self._isDone = false;
44639
44974
  }
44975
+ Lookup.addActivity({
44976
+ symbol,
44977
+ context,
44978
+ backtest: false,
44979
+ });
44640
44980
  for await (const signal of self.run(symbol, context)) {
44641
44981
  if (signal?.action === "closed" && self._isStopped) {
44642
44982
  break;
44643
44983
  }
44644
44984
  }
44985
+ Lookup.removeActivity({
44986
+ symbol,
44987
+ context,
44988
+ backtest: false,
44989
+ });
44645
44990
  if (!self._isDone) {
44646
44991
  await doneLiveSubject.next({
44647
44992
  exchangeName: context.exchangeName,
@@ -63767,6 +64112,7 @@ exports.HighestProfit = HighestProfit;
63767
64112
  exports.Interval = Interval;
63768
64113
  exports.Live = Live;
63769
64114
  exports.Log = Log;
64115
+ exports.Lookup = Lookup;
63770
64116
  exports.Markdown = Markdown;
63771
64117
  exports.MarkdownFileBase = MarkdownFileBase;
63772
64118
  exports.MarkdownFolderBase = MarkdownFolderBase;
@@ -63848,6 +64194,7 @@ exports.addSizingSchema = addSizingSchema;
63848
64194
  exports.addStrategySchema = addStrategySchema;
63849
64195
  exports.addWalkerSchema = addWalkerSchema;
63850
64196
  exports.alignToInterval = alignToInterval;
64197
+ exports.cacheCandles = cacheCandles;
63851
64198
  exports.checkCandles = checkCandles;
63852
64199
  exports.commitActivateScheduled = commitActivateScheduled;
63853
64200
  exports.commitAverageBuy = commitAverageBuy;