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.
- package/LICENSE +21 -21
- package/README.md +1893 -1871
- package/build/index.cjs +477 -130
- package/build/index.mjs +476 -131
- package/package.json +86 -86
- 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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
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
|
|
4538
|
-
*
|
|
4539
|
-
*
|
|
4540
|
-
*
|
|
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
|
-
*
|
|
4568
|
+
* The busy counter detects mis-matched releases and throws immediately on
|
|
4569
|
+
* extra `releaseLock` calls.
|
|
4543
4570
|
*
|
|
4544
|
-
* **
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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;
|