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.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
  /**
@@ -41966,11 +42291,21 @@ const INSTANCE_TASK_FN$2 = async (symbol, context, self) => {
41966
42291
  self._isStopped = false;
41967
42292
  self._isDone = false;
41968
42293
  }
42294
+ Lookup.addActivity({
42295
+ symbol,
42296
+ context,
42297
+ backtest: true,
42298
+ });
41969
42299
  for await (const _ of self.run(symbol, context)) {
41970
42300
  if (self._isStopped) {
41971
42301
  break;
41972
42302
  }
41973
42303
  }
42304
+ Lookup.removeActivity({
42305
+ symbol,
42306
+ context,
42307
+ backtest: true,
42308
+ });
41974
42309
  if (!self._isDone) {
41975
42310
  await doneBacktestSubject.next({
41976
42311
  exchangeName: context.exchangeName,
@@ -44617,11 +44952,21 @@ const INSTANCE_TASK_FN$1 = async (symbol, context, self) => {
44617
44952
  self._isStopped = false;
44618
44953
  self._isDone = false;
44619
44954
  }
44955
+ Lookup.addActivity({
44956
+ symbol,
44957
+ context,
44958
+ backtest: false,
44959
+ });
44620
44960
  for await (const signal of self.run(symbol, context)) {
44621
44961
  if (signal?.action === "closed" && self._isStopped) {
44622
44962
  break;
44623
44963
  }
44624
44964
  }
44965
+ Lookup.removeActivity({
44966
+ symbol,
44967
+ context,
44968
+ backtest: false,
44969
+ });
44625
44970
  if (!self._isDone) {
44626
44971
  await doneLiveSubject.next({
44627
44972
  exchangeName: context.exchangeName,
@@ -63732,4 +64077,4 @@ const validateSignal = (signal, currentPrice) => {
63732
64077
  return !errors.length;
63733
64078
  };
63734
64079
 
63735
- 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 };