backtest-kit 9.8.1 → 9.8.3
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 +1898 -1871
- package/build/index.cjs +949 -282
- package/build/index.mjs +944 -283
- package/package.json +86 -86
- package/types.d.ts +551 -151
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.
|
|
@@ -772,11 +788,23 @@ const maxDrawdownSubject = new Subject();
|
|
|
772
788
|
* Emits when a strategy calls commitSignalInfo() to broadcast a custom annotation.
|
|
773
789
|
*/
|
|
774
790
|
const signalNotifySubject = new Subject();
|
|
791
|
+
/**
|
|
792
|
+
* Before start emitter for strategy initialization events.
|
|
793
|
+
* Emits when the engine is about to start a new strategy execution.
|
|
794
|
+
*/
|
|
795
|
+
const beforeStartSubject = new Subject();
|
|
796
|
+
/**
|
|
797
|
+
* After end emitter for strategy completion events.
|
|
798
|
+
* Emits when the engine has completed processing a signal.
|
|
799
|
+
*/
|
|
800
|
+
const afterEndSubject = new Subject();
|
|
775
801
|
|
|
776
802
|
var emitters = /*#__PURE__*/Object.freeze({
|
|
777
803
|
__proto__: null,
|
|
778
804
|
activePingSubject: activePingSubject,
|
|
805
|
+
afterEndSubject: afterEndSubject,
|
|
779
806
|
backtestScheduleOpenSubject: backtestScheduleOpenSubject,
|
|
807
|
+
beforeStartSubject: beforeStartSubject,
|
|
780
808
|
breakevenSubject: breakevenSubject,
|
|
781
809
|
doneBacktestSubject: doneBacktestSubject,
|
|
782
810
|
doneLiveSubject: doneLiveSubject,
|
|
@@ -914,7 +942,7 @@ async function writeFileAtomic(file, data, options = {}) {
|
|
|
914
942
|
|
|
915
943
|
var _a$3;
|
|
916
944
|
/** Logger service injected as DI singleton */
|
|
917
|
-
const LOGGER_SERVICE$
|
|
945
|
+
const LOGGER_SERVICE$8 = new LoggerService();
|
|
918
946
|
/** Symbol key for the singleshot waitForInit function on PersistBase instances. */
|
|
919
947
|
const BASE_WAIT_FOR_INIT_SYMBOL = Symbol("wait-for-init");
|
|
920
948
|
// Calculate step in milliseconds for candle close time validation
|
|
@@ -1037,7 +1065,7 @@ const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
|
|
|
1037
1065
|
const BASE_UNLINK_RETRY_COUNT = 5;
|
|
1038
1066
|
const BASE_UNLINK_RETRY_DELAY = 1000;
|
|
1039
1067
|
const BASE_WAIT_FOR_INIT_FN = async (self) => {
|
|
1040
|
-
LOGGER_SERVICE$
|
|
1068
|
+
LOGGER_SERVICE$8.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
|
|
1041
1069
|
entityName: self.entityName,
|
|
1042
1070
|
directory: self._directory,
|
|
1043
1071
|
});
|
|
@@ -1095,7 +1123,7 @@ class PersistBase {
|
|
|
1095
1123
|
this.entityName = entityName;
|
|
1096
1124
|
this.baseDir = baseDir;
|
|
1097
1125
|
this[_a$3] = singleshot(async () => await BASE_WAIT_FOR_INIT_FN(this));
|
|
1098
|
-
LOGGER_SERVICE$
|
|
1126
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
|
|
1099
1127
|
entityName: this.entityName,
|
|
1100
1128
|
baseDir,
|
|
1101
1129
|
});
|
|
@@ -1111,14 +1139,14 @@ class PersistBase {
|
|
|
1111
1139
|
return join(this.baseDir, this.entityName, `${entityId}.json`);
|
|
1112
1140
|
}
|
|
1113
1141
|
async waitForInit(initial) {
|
|
1114
|
-
LOGGER_SERVICE$
|
|
1142
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
|
|
1115
1143
|
entityName: this.entityName,
|
|
1116
1144
|
initial,
|
|
1117
1145
|
});
|
|
1118
1146
|
await this[BASE_WAIT_FOR_INIT_SYMBOL]();
|
|
1119
1147
|
}
|
|
1120
1148
|
async readValue(entityId) {
|
|
1121
|
-
LOGGER_SERVICE$
|
|
1149
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
|
|
1122
1150
|
entityName: this.entityName,
|
|
1123
1151
|
entityId,
|
|
1124
1152
|
});
|
|
@@ -1135,7 +1163,7 @@ class PersistBase {
|
|
|
1135
1163
|
}
|
|
1136
1164
|
}
|
|
1137
1165
|
async hasValue(entityId) {
|
|
1138
|
-
LOGGER_SERVICE$
|
|
1166
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
|
|
1139
1167
|
entityName: this.entityName,
|
|
1140
1168
|
entityId,
|
|
1141
1169
|
});
|
|
@@ -1152,7 +1180,7 @@ class PersistBase {
|
|
|
1152
1180
|
}
|
|
1153
1181
|
}
|
|
1154
1182
|
async writeValue(entityId, entity) {
|
|
1155
|
-
LOGGER_SERVICE$
|
|
1183
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
|
|
1156
1184
|
entityName: this.entityName,
|
|
1157
1185
|
entityId,
|
|
1158
1186
|
});
|
|
@@ -1174,7 +1202,7 @@ class PersistBase {
|
|
|
1174
1202
|
* @throws Error if reading fails
|
|
1175
1203
|
*/
|
|
1176
1204
|
async *keys() {
|
|
1177
|
-
LOGGER_SERVICE$
|
|
1205
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
|
|
1178
1206
|
entityName: this.entityName,
|
|
1179
1207
|
});
|
|
1180
1208
|
try {
|
|
@@ -1319,7 +1347,7 @@ class PersistSignalUtils {
|
|
|
1319
1347
|
* @returns Promise resolving to signal or null if none persisted
|
|
1320
1348
|
*/
|
|
1321
1349
|
this.readSignalData = async (symbol, strategyName, exchangeName) => {
|
|
1322
|
-
LOGGER_SERVICE$
|
|
1350
|
+
LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
|
|
1323
1351
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1324
1352
|
const isInitial = !this.getStorage.has(key);
|
|
1325
1353
|
const instance = this.getStorage(symbol, strategyName, exchangeName);
|
|
@@ -1337,7 +1365,7 @@ class PersistSignalUtils {
|
|
|
1337
1365
|
* @returns Promise that resolves when write is complete
|
|
1338
1366
|
*/
|
|
1339
1367
|
this.writeSignalData = async (signalRow, symbol, strategyName, exchangeName) => {
|
|
1340
|
-
LOGGER_SERVICE$
|
|
1368
|
+
LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1341
1369
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1342
1370
|
const isInitial = !this.getStorage.has(key);
|
|
1343
1371
|
const instance = this.getStorage(symbol, strategyName, exchangeName);
|
|
@@ -1352,7 +1380,7 @@ class PersistSignalUtils {
|
|
|
1352
1380
|
* @param Ctor - Custom IPersistSignalInstance constructor
|
|
1353
1381
|
*/
|
|
1354
1382
|
usePersistSignalAdapter(Ctor) {
|
|
1355
|
-
LOGGER_SERVICE$
|
|
1383
|
+
LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
|
|
1356
1384
|
this.PersistSignalInstanceCtor = Ctor;
|
|
1357
1385
|
this.getStorage.clear();
|
|
1358
1386
|
}
|
|
@@ -1361,21 +1389,21 @@ class PersistSignalUtils {
|
|
|
1361
1389
|
* Call when process.cwd() changes between strategy iterations.
|
|
1362
1390
|
*/
|
|
1363
1391
|
clear() {
|
|
1364
|
-
LOGGER_SERVICE$
|
|
1392
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
|
|
1365
1393
|
this.getStorage.clear();
|
|
1366
1394
|
}
|
|
1367
1395
|
/**
|
|
1368
1396
|
* Switches to the default file-based PersistSignalInstance.
|
|
1369
1397
|
*/
|
|
1370
1398
|
useJson() {
|
|
1371
|
-
LOGGER_SERVICE$
|
|
1399
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
|
|
1372
1400
|
this.usePersistSignalAdapter(PersistSignalInstance);
|
|
1373
1401
|
}
|
|
1374
1402
|
/**
|
|
1375
1403
|
* Switches to PersistSignalDummyInstance (all operations are no-ops).
|
|
1376
1404
|
*/
|
|
1377
1405
|
useDummy() {
|
|
1378
|
-
LOGGER_SERVICE$
|
|
1406
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1379
1407
|
this.usePersistSignalAdapter(PersistSignalDummyInstance);
|
|
1380
1408
|
}
|
|
1381
1409
|
}
|
|
@@ -1515,7 +1543,7 @@ class PersistRiskUtils {
|
|
|
1515
1543
|
* @returns Promise resolving to position entries (empty array if none)
|
|
1516
1544
|
*/
|
|
1517
1545
|
this.readPositionData = async (riskName, exchangeName, when) => {
|
|
1518
|
-
LOGGER_SERVICE$
|
|
1546
|
+
LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
|
|
1519
1547
|
const key = `${riskName}:${exchangeName}`;
|
|
1520
1548
|
const isInitial = !this.getRiskStorage.has(key);
|
|
1521
1549
|
const instance = this.getRiskStorage(riskName, exchangeName);
|
|
@@ -1533,7 +1561,7 @@ class PersistRiskUtils {
|
|
|
1533
1561
|
* @returns Promise that resolves when write is complete
|
|
1534
1562
|
*/
|
|
1535
1563
|
this.writePositionData = async (riskRow, riskName, exchangeName, when) => {
|
|
1536
|
-
LOGGER_SERVICE$
|
|
1564
|
+
LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1537
1565
|
const key = `${riskName}:${exchangeName}`;
|
|
1538
1566
|
const isInitial = !this.getRiskStorage.has(key);
|
|
1539
1567
|
const instance = this.getRiskStorage(riskName, exchangeName);
|
|
@@ -1548,7 +1576,7 @@ class PersistRiskUtils {
|
|
|
1548
1576
|
* @param Ctor - Custom IPersistRiskInstance constructor
|
|
1549
1577
|
*/
|
|
1550
1578
|
usePersistRiskAdapter(Ctor) {
|
|
1551
|
-
LOGGER_SERVICE$
|
|
1579
|
+
LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
|
|
1552
1580
|
this.PersistRiskInstanceCtor = Ctor;
|
|
1553
1581
|
this.getRiskStorage.clear();
|
|
1554
1582
|
}
|
|
@@ -1557,21 +1585,21 @@ class PersistRiskUtils {
|
|
|
1557
1585
|
* Call when process.cwd() changes between strategy iterations.
|
|
1558
1586
|
*/
|
|
1559
1587
|
clear() {
|
|
1560
|
-
LOGGER_SERVICE$
|
|
1588
|
+
LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
|
|
1561
1589
|
this.getRiskStorage.clear();
|
|
1562
1590
|
}
|
|
1563
1591
|
/**
|
|
1564
1592
|
* Switches to the default file-based PersistRiskInstance.
|
|
1565
1593
|
*/
|
|
1566
1594
|
useJson() {
|
|
1567
|
-
LOGGER_SERVICE$
|
|
1595
|
+
LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
|
|
1568
1596
|
this.usePersistRiskAdapter(PersistRiskInstance);
|
|
1569
1597
|
}
|
|
1570
1598
|
/**
|
|
1571
1599
|
* Switches to PersistRiskDummyInstance (all operations are no-ops).
|
|
1572
1600
|
*/
|
|
1573
1601
|
useDummy() {
|
|
1574
|
-
LOGGER_SERVICE$
|
|
1602
|
+
LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1575
1603
|
this.usePersistRiskAdapter(PersistRiskDummyInstance);
|
|
1576
1604
|
}
|
|
1577
1605
|
}
|
|
@@ -1710,7 +1738,7 @@ class PersistScheduleUtils {
|
|
|
1710
1738
|
* @returns Promise resolving to scheduled signal or null if none persisted
|
|
1711
1739
|
*/
|
|
1712
1740
|
this.readScheduleData = async (symbol, strategyName, exchangeName) => {
|
|
1713
|
-
LOGGER_SERVICE$
|
|
1741
|
+
LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
|
|
1714
1742
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1715
1743
|
const isInitial = !this.getScheduleStorage.has(key);
|
|
1716
1744
|
const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
|
|
@@ -1728,7 +1756,7 @@ class PersistScheduleUtils {
|
|
|
1728
1756
|
* @returns Promise that resolves when write is complete
|
|
1729
1757
|
*/
|
|
1730
1758
|
this.writeScheduleData = async (scheduledSignalRow, symbol, strategyName, exchangeName) => {
|
|
1731
|
-
LOGGER_SERVICE$
|
|
1759
|
+
LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1732
1760
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1733
1761
|
const isInitial = !this.getScheduleStorage.has(key);
|
|
1734
1762
|
const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
|
|
@@ -1743,7 +1771,7 @@ class PersistScheduleUtils {
|
|
|
1743
1771
|
* @param Ctor - Custom IPersistScheduleInstance constructor
|
|
1744
1772
|
*/
|
|
1745
1773
|
usePersistScheduleAdapter(Ctor) {
|
|
1746
|
-
LOGGER_SERVICE$
|
|
1774
|
+
LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
|
|
1747
1775
|
this.PersistScheduleInstanceCtor = Ctor;
|
|
1748
1776
|
this.getScheduleStorage.clear();
|
|
1749
1777
|
}
|
|
@@ -1752,21 +1780,21 @@ class PersistScheduleUtils {
|
|
|
1752
1780
|
* Call when process.cwd() changes between strategy iterations.
|
|
1753
1781
|
*/
|
|
1754
1782
|
clear() {
|
|
1755
|
-
LOGGER_SERVICE$
|
|
1783
|
+
LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
|
|
1756
1784
|
this.getScheduleStorage.clear();
|
|
1757
1785
|
}
|
|
1758
1786
|
/**
|
|
1759
1787
|
* Switches to the default file-based PersistScheduleInstance.
|
|
1760
1788
|
*/
|
|
1761
1789
|
useJson() {
|
|
1762
|
-
LOGGER_SERVICE$
|
|
1790
|
+
LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
|
|
1763
1791
|
this.usePersistScheduleAdapter(PersistScheduleInstance);
|
|
1764
1792
|
}
|
|
1765
1793
|
/**
|
|
1766
1794
|
* Switches to PersistScheduleDummyInstance (all operations are no-ops).
|
|
1767
1795
|
*/
|
|
1768
1796
|
useDummy() {
|
|
1769
|
-
LOGGER_SERVICE$
|
|
1797
|
+
LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1770
1798
|
this.usePersistScheduleAdapter(PersistScheduleDummyInstance);
|
|
1771
1799
|
}
|
|
1772
1800
|
}
|
|
@@ -1911,7 +1939,7 @@ class PersistPartialUtils {
|
|
|
1911
1939
|
* @returns Promise resolving to partial data record (empty object if none)
|
|
1912
1940
|
*/
|
|
1913
1941
|
this.readPartialData = async (symbol, strategyName, signalId, exchangeName, when) => {
|
|
1914
|
-
LOGGER_SERVICE$
|
|
1942
|
+
LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
|
|
1915
1943
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1916
1944
|
const isInitial = !this.getPartialStorage.has(key);
|
|
1917
1945
|
const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
|
|
@@ -1931,7 +1959,7 @@ class PersistPartialUtils {
|
|
|
1931
1959
|
* @returns Promise that resolves when write is complete
|
|
1932
1960
|
*/
|
|
1933
1961
|
this.writePartialData = async (partialData, symbol, strategyName, signalId, exchangeName, when) => {
|
|
1934
|
-
LOGGER_SERVICE$
|
|
1962
|
+
LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1935
1963
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1936
1964
|
const isInitial = !this.getPartialStorage.has(key);
|
|
1937
1965
|
const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
|
|
@@ -1946,7 +1974,7 @@ class PersistPartialUtils {
|
|
|
1946
1974
|
* @param Ctor - Custom IPersistPartialInstance constructor
|
|
1947
1975
|
*/
|
|
1948
1976
|
usePersistPartialAdapter(Ctor) {
|
|
1949
|
-
LOGGER_SERVICE$
|
|
1977
|
+
LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
|
|
1950
1978
|
this.PersistPartialInstanceCtor = Ctor;
|
|
1951
1979
|
this.getPartialStorage.clear();
|
|
1952
1980
|
}
|
|
@@ -1955,21 +1983,21 @@ class PersistPartialUtils {
|
|
|
1955
1983
|
* Call when process.cwd() changes between strategy iterations.
|
|
1956
1984
|
*/
|
|
1957
1985
|
clear() {
|
|
1958
|
-
LOGGER_SERVICE$
|
|
1986
|
+
LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
|
|
1959
1987
|
this.getPartialStorage.clear();
|
|
1960
1988
|
}
|
|
1961
1989
|
/**
|
|
1962
1990
|
* Switches to the default file-based PersistPartialInstance.
|
|
1963
1991
|
*/
|
|
1964
1992
|
useJson() {
|
|
1965
|
-
LOGGER_SERVICE$
|
|
1993
|
+
LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
|
|
1966
1994
|
this.usePersistPartialAdapter(PersistPartialInstance);
|
|
1967
1995
|
}
|
|
1968
1996
|
/**
|
|
1969
1997
|
* Switches to PersistPartialDummyInstance (all operations are no-ops).
|
|
1970
1998
|
*/
|
|
1971
1999
|
useDummy() {
|
|
1972
|
-
LOGGER_SERVICE$
|
|
2000
|
+
LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1973
2001
|
this.usePersistPartialAdapter(PersistPartialDummyInstance);
|
|
1974
2002
|
}
|
|
1975
2003
|
}
|
|
@@ -2134,7 +2162,7 @@ class PersistBreakevenUtils {
|
|
|
2134
2162
|
* @returns Promise resolving to breakeven data record (empty object if none)
|
|
2135
2163
|
*/
|
|
2136
2164
|
this.readBreakevenData = async (symbol, strategyName, signalId, exchangeName, when) => {
|
|
2137
|
-
LOGGER_SERVICE$
|
|
2165
|
+
LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
|
|
2138
2166
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
2139
2167
|
const isInitial = !this.getBreakevenStorage.has(key);
|
|
2140
2168
|
const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
|
|
@@ -2154,7 +2182,7 @@ class PersistBreakevenUtils {
|
|
|
2154
2182
|
* @returns Promise that resolves when write is complete
|
|
2155
2183
|
*/
|
|
2156
2184
|
this.writeBreakevenData = async (breakevenData, symbol, strategyName, signalId, exchangeName, when) => {
|
|
2157
|
-
LOGGER_SERVICE$
|
|
2185
|
+
LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2158
2186
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
2159
2187
|
const isInitial = !this.getBreakevenStorage.has(key);
|
|
2160
2188
|
const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
|
|
@@ -2169,7 +2197,7 @@ class PersistBreakevenUtils {
|
|
|
2169
2197
|
* @param Ctor - Custom IPersistBreakevenInstance constructor
|
|
2170
2198
|
*/
|
|
2171
2199
|
usePersistBreakevenAdapter(Ctor) {
|
|
2172
|
-
LOGGER_SERVICE$
|
|
2200
|
+
LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
|
|
2173
2201
|
this.PersistBreakevenInstanceCtor = Ctor;
|
|
2174
2202
|
this.getBreakevenStorage.clear();
|
|
2175
2203
|
}
|
|
@@ -2178,21 +2206,21 @@ class PersistBreakevenUtils {
|
|
|
2178
2206
|
* Call when process.cwd() changes between strategy iterations.
|
|
2179
2207
|
*/
|
|
2180
2208
|
clear() {
|
|
2181
|
-
LOGGER_SERVICE$
|
|
2209
|
+
LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
|
|
2182
2210
|
this.getBreakevenStorage.clear();
|
|
2183
2211
|
}
|
|
2184
2212
|
/**
|
|
2185
2213
|
* Switches to the default file-based PersistBreakevenInstance.
|
|
2186
2214
|
*/
|
|
2187
2215
|
useJson() {
|
|
2188
|
-
LOGGER_SERVICE$
|
|
2216
|
+
LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
|
|
2189
2217
|
this.usePersistBreakevenAdapter(PersistBreakevenInstance);
|
|
2190
2218
|
}
|
|
2191
2219
|
/**
|
|
2192
2220
|
* Switches to PersistBreakevenDummyInstance (all operations are no-ops).
|
|
2193
2221
|
*/
|
|
2194
2222
|
useDummy() {
|
|
2195
|
-
LOGGER_SERVICE$
|
|
2223
|
+
LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2196
2224
|
this.usePersistBreakevenAdapter(PersistBreakevenDummyInstance);
|
|
2197
2225
|
}
|
|
2198
2226
|
}
|
|
@@ -2283,7 +2311,7 @@ class PersistCandleInstance {
|
|
|
2283
2311
|
error: errorData(error),
|
|
2284
2312
|
message: getErrorMessage(error),
|
|
2285
2313
|
};
|
|
2286
|
-
LOGGER_SERVICE$
|
|
2314
|
+
LOGGER_SERVICE$8.warn(message, payload);
|
|
2287
2315
|
console.warn(message, payload);
|
|
2288
2316
|
errorEmitter.next(error);
|
|
2289
2317
|
return null;
|
|
@@ -2305,7 +2333,7 @@ class PersistCandleInstance {
|
|
|
2305
2333
|
for (const candle of candles) {
|
|
2306
2334
|
const candleCloseTime = candle.timestamp + stepMs;
|
|
2307
2335
|
if (candleCloseTime > now) {
|
|
2308
|
-
LOGGER_SERVICE$
|
|
2336
|
+
LOGGER_SERVICE$8.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
|
|
2309
2337
|
symbol: this.symbol,
|
|
2310
2338
|
interval: this.interval,
|
|
2311
2339
|
exchangeName: this.exchangeName,
|
|
@@ -2382,7 +2410,7 @@ class PersistCandleUtils {
|
|
|
2382
2410
|
* @returns Promise resolving to candles in order, or null on cache miss
|
|
2383
2411
|
*/
|
|
2384
2412
|
this.readCandlesData = async (symbol, interval, exchangeName, limit, sinceTimestamp, untilTimestamp) => {
|
|
2385
|
-
LOGGER_SERVICE$
|
|
2413
|
+
LOGGER_SERVICE$8.info("PersistCandleUtils.readCandlesData", {
|
|
2386
2414
|
symbol,
|
|
2387
2415
|
interval,
|
|
2388
2416
|
exchangeName,
|
|
@@ -2406,7 +2434,7 @@ class PersistCandleUtils {
|
|
|
2406
2434
|
* @returns Promise that resolves when all writes are complete
|
|
2407
2435
|
*/
|
|
2408
2436
|
this.writeCandlesData = async (candles, symbol, interval, exchangeName) => {
|
|
2409
|
-
LOGGER_SERVICE$
|
|
2437
|
+
LOGGER_SERVICE$8.info("PersistCandleUtils.writeCandlesData", {
|
|
2410
2438
|
symbol,
|
|
2411
2439
|
interval,
|
|
2412
2440
|
exchangeName,
|
|
@@ -2426,7 +2454,7 @@ class PersistCandleUtils {
|
|
|
2426
2454
|
* @param Ctor - Custom IPersistCandleInstance constructor
|
|
2427
2455
|
*/
|
|
2428
2456
|
usePersistCandleAdapter(Ctor) {
|
|
2429
|
-
LOGGER_SERVICE$
|
|
2457
|
+
LOGGER_SERVICE$8.info("PersistCandleUtils.usePersistCandleAdapter");
|
|
2430
2458
|
this.PersistCandleInstanceCtor = Ctor;
|
|
2431
2459
|
this.getCandlesStorage.clear();
|
|
2432
2460
|
}
|
|
@@ -2435,21 +2463,21 @@ class PersistCandleUtils {
|
|
|
2435
2463
|
* Call when process.cwd() changes between strategy iterations.
|
|
2436
2464
|
*/
|
|
2437
2465
|
clear() {
|
|
2438
|
-
LOGGER_SERVICE$
|
|
2466
|
+
LOGGER_SERVICE$8.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
|
|
2439
2467
|
this.getCandlesStorage.clear();
|
|
2440
2468
|
}
|
|
2441
2469
|
/**
|
|
2442
2470
|
* Switches to the default file-based PersistCandleInstance.
|
|
2443
2471
|
*/
|
|
2444
2472
|
useJson() {
|
|
2445
|
-
LOGGER_SERVICE$
|
|
2473
|
+
LOGGER_SERVICE$8.log("PersistCandleUtils.useJson");
|
|
2446
2474
|
this.usePersistCandleAdapter(PersistCandleInstance);
|
|
2447
2475
|
}
|
|
2448
2476
|
/**
|
|
2449
2477
|
* Switches to PersistCandleDummyInstance (always returns null on read, discards writes).
|
|
2450
2478
|
*/
|
|
2451
2479
|
useDummy() {
|
|
2452
|
-
LOGGER_SERVICE$
|
|
2480
|
+
LOGGER_SERVICE$8.log("PersistCandleUtils.useDummy");
|
|
2453
2481
|
this.usePersistCandleAdapter(PersistCandleDummyInstance);
|
|
2454
2482
|
}
|
|
2455
2483
|
}
|
|
@@ -2587,7 +2615,7 @@ class PersistStorageUtils {
|
|
|
2587
2615
|
* @returns Promise resolving to array of signal entries
|
|
2588
2616
|
*/
|
|
2589
2617
|
this.readStorageData = async (backtest) => {
|
|
2590
|
-
LOGGER_SERVICE$
|
|
2618
|
+
LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
|
|
2591
2619
|
const key = backtest ? `backtest` : `live`;
|
|
2592
2620
|
const isInitial = !this.getStorage.has(key);
|
|
2593
2621
|
const instance = this.getStorage(backtest);
|
|
@@ -2603,7 +2631,7 @@ class PersistStorageUtils {
|
|
|
2603
2631
|
* @returns Promise that resolves when write is complete
|
|
2604
2632
|
*/
|
|
2605
2633
|
this.writeStorageData = async (signalData, backtest) => {
|
|
2606
|
-
LOGGER_SERVICE$
|
|
2634
|
+
LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2607
2635
|
const key = backtest ? `backtest` : `live`;
|
|
2608
2636
|
const isInitial = !this.getStorage.has(key);
|
|
2609
2637
|
const instance = this.getStorage(backtest);
|
|
@@ -2618,7 +2646,7 @@ class PersistStorageUtils {
|
|
|
2618
2646
|
* @param Ctor - Custom IPersistStorageInstance constructor
|
|
2619
2647
|
*/
|
|
2620
2648
|
usePersistStorageAdapter(Ctor) {
|
|
2621
|
-
LOGGER_SERVICE$
|
|
2649
|
+
LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
|
|
2622
2650
|
this.PersistStorageInstanceCtor = Ctor;
|
|
2623
2651
|
this.getStorage.clear();
|
|
2624
2652
|
}
|
|
@@ -2627,21 +2655,21 @@ class PersistStorageUtils {
|
|
|
2627
2655
|
* Call when process.cwd() changes between strategy iterations.
|
|
2628
2656
|
*/
|
|
2629
2657
|
clear() {
|
|
2630
|
-
LOGGER_SERVICE$
|
|
2658
|
+
LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
|
|
2631
2659
|
this.getStorage.clear();
|
|
2632
2660
|
}
|
|
2633
2661
|
/**
|
|
2634
2662
|
* Switches to the default file-based PersistStorageInstance.
|
|
2635
2663
|
*/
|
|
2636
2664
|
useJson() {
|
|
2637
|
-
LOGGER_SERVICE$
|
|
2665
|
+
LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
|
|
2638
2666
|
this.usePersistStorageAdapter(PersistStorageInstance);
|
|
2639
2667
|
}
|
|
2640
2668
|
/**
|
|
2641
2669
|
* Switches to PersistStorageDummyInstance (all operations are no-ops).
|
|
2642
2670
|
*/
|
|
2643
2671
|
useDummy() {
|
|
2644
|
-
LOGGER_SERVICE$
|
|
2672
|
+
LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2645
2673
|
this.usePersistStorageAdapter(PersistStorageDummyInstance);
|
|
2646
2674
|
}
|
|
2647
2675
|
}
|
|
@@ -2768,7 +2796,7 @@ class PersistNotificationUtils {
|
|
|
2768
2796
|
* @returns Promise resolving to array of notification entries
|
|
2769
2797
|
*/
|
|
2770
2798
|
this.readNotificationData = async (backtest) => {
|
|
2771
|
-
LOGGER_SERVICE$
|
|
2799
|
+
LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
|
|
2772
2800
|
const key = backtest ? `backtest` : `live`;
|
|
2773
2801
|
const isInitial = !this.getNotificationStorage.has(key);
|
|
2774
2802
|
const instance = this.getNotificationStorage(backtest);
|
|
@@ -2784,7 +2812,7 @@ class PersistNotificationUtils {
|
|
|
2784
2812
|
* @returns Promise that resolves when write is complete
|
|
2785
2813
|
*/
|
|
2786
2814
|
this.writeNotificationData = async (notificationData, backtest) => {
|
|
2787
|
-
LOGGER_SERVICE$
|
|
2815
|
+
LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2788
2816
|
const key = backtest ? `backtest` : `live`;
|
|
2789
2817
|
const isInitial = !this.getNotificationStorage.has(key);
|
|
2790
2818
|
const instance = this.getNotificationStorage(backtest);
|
|
@@ -2799,7 +2827,7 @@ class PersistNotificationUtils {
|
|
|
2799
2827
|
* @param Ctor - Custom IPersistNotificationInstance constructor
|
|
2800
2828
|
*/
|
|
2801
2829
|
usePersistNotificationAdapter(Ctor) {
|
|
2802
|
-
LOGGER_SERVICE$
|
|
2830
|
+
LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
|
|
2803
2831
|
this.PersistNotificationInstanceCtor = Ctor;
|
|
2804
2832
|
this.getNotificationStorage.clear();
|
|
2805
2833
|
}
|
|
@@ -2809,21 +2837,21 @@ class PersistNotificationUtils {
|
|
|
2809
2837
|
* instances are created with the updated base path.
|
|
2810
2838
|
*/
|
|
2811
2839
|
clear() {
|
|
2812
|
-
LOGGER_SERVICE$
|
|
2840
|
+
LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
|
|
2813
2841
|
this.getNotificationStorage.clear();
|
|
2814
2842
|
}
|
|
2815
2843
|
/**
|
|
2816
2844
|
* Switches to the default file-based PersistNotificationInstance.
|
|
2817
2845
|
*/
|
|
2818
2846
|
useJson() {
|
|
2819
|
-
LOGGER_SERVICE$
|
|
2847
|
+
LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
|
|
2820
2848
|
this.usePersistNotificationAdapter(PersistNotificationInstance);
|
|
2821
2849
|
}
|
|
2822
2850
|
/**
|
|
2823
2851
|
* Switches to PersistNotificationDummyInstance (all operations are no-ops).
|
|
2824
2852
|
*/
|
|
2825
2853
|
useDummy() {
|
|
2826
|
-
LOGGER_SERVICE$
|
|
2854
|
+
LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2827
2855
|
this.usePersistNotificationAdapter(PersistNotificationDummyInstance);
|
|
2828
2856
|
}
|
|
2829
2857
|
}
|
|
@@ -2947,7 +2975,7 @@ class PersistLogUtils {
|
|
|
2947
2975
|
* @returns Promise resolving to array of log entries
|
|
2948
2976
|
*/
|
|
2949
2977
|
this.readLogData = async () => {
|
|
2950
|
-
LOGGER_SERVICE$
|
|
2978
|
+
LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
|
|
2951
2979
|
const isInitial = !this._logInstance;
|
|
2952
2980
|
const instance = this.getLogInstance();
|
|
2953
2981
|
await instance.waitForInit(isInitial);
|
|
@@ -2961,7 +2989,7 @@ class PersistLogUtils {
|
|
|
2961
2989
|
* @returns Promise that resolves when write is complete
|
|
2962
2990
|
*/
|
|
2963
2991
|
this.writeLogData = async (logData) => {
|
|
2964
|
-
LOGGER_SERVICE$
|
|
2992
|
+
LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2965
2993
|
const isInitial = !this._logInstance;
|
|
2966
2994
|
const instance = this.getLogInstance();
|
|
2967
2995
|
await instance.waitForInit(isInitial);
|
|
@@ -2986,7 +3014,7 @@ class PersistLogUtils {
|
|
|
2986
3014
|
* @param Ctor - Custom IPersistLogInstance constructor
|
|
2987
3015
|
*/
|
|
2988
3016
|
usePersistLogAdapter(Ctor) {
|
|
2989
|
-
LOGGER_SERVICE$
|
|
3017
|
+
LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
|
|
2990
3018
|
this.PersistLogInstanceCtor = Ctor;
|
|
2991
3019
|
this._logInstance = null;
|
|
2992
3020
|
}
|
|
@@ -2995,21 +3023,21 @@ class PersistLogUtils {
|
|
|
2995
3023
|
* Call when process.cwd() changes between strategy iterations.
|
|
2996
3024
|
*/
|
|
2997
3025
|
clear() {
|
|
2998
|
-
LOGGER_SERVICE$
|
|
3026
|
+
LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
|
|
2999
3027
|
this._logInstance = null;
|
|
3000
3028
|
}
|
|
3001
3029
|
/**
|
|
3002
3030
|
* Switches to the default file-based PersistLogInstance.
|
|
3003
3031
|
*/
|
|
3004
3032
|
useJson() {
|
|
3005
|
-
LOGGER_SERVICE$
|
|
3033
|
+
LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
|
|
3006
3034
|
this.usePersistLogAdapter(PersistLogInstance);
|
|
3007
3035
|
}
|
|
3008
3036
|
/**
|
|
3009
3037
|
* Switches to PersistLogDummyInstance (all operations are no-ops).
|
|
3010
3038
|
*/
|
|
3011
3039
|
useDummy() {
|
|
3012
|
-
LOGGER_SERVICE$
|
|
3040
|
+
LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3013
3041
|
this.usePersistLogAdapter(PersistLogDummyInstance);
|
|
3014
3042
|
}
|
|
3015
3043
|
}
|
|
@@ -3171,7 +3199,7 @@ class PersistMeasureUtils {
|
|
|
3171
3199
|
* @returns Promise resolving to cached value, or null if not found / soft-deleted
|
|
3172
3200
|
*/
|
|
3173
3201
|
this.readMeasureData = async (bucket, key) => {
|
|
3174
|
-
LOGGER_SERVICE$
|
|
3202
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
|
|
3175
3203
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3176
3204
|
const instance = this.getMeasureStorage(bucket);
|
|
3177
3205
|
await instance.waitForInit(isInitial);
|
|
@@ -3187,7 +3215,7 @@ class PersistMeasureUtils {
|
|
|
3187
3215
|
* @returns Promise that resolves when write is complete
|
|
3188
3216
|
*/
|
|
3189
3217
|
this.writeMeasureData = async (data, bucket, key, when) => {
|
|
3190
|
-
LOGGER_SERVICE$
|
|
3218
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
|
|
3191
3219
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3192
3220
|
const instance = this.getMeasureStorage(bucket);
|
|
3193
3221
|
await instance.waitForInit(isInitial);
|
|
@@ -3202,7 +3230,7 @@ class PersistMeasureUtils {
|
|
|
3202
3230
|
* @returns Promise that resolves when removal is complete
|
|
3203
3231
|
*/
|
|
3204
3232
|
this.removeMeasureData = async (bucket, key) => {
|
|
3205
|
-
LOGGER_SERVICE$
|
|
3233
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
|
|
3206
3234
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3207
3235
|
const instance = this.getMeasureStorage(bucket);
|
|
3208
3236
|
await instance.waitForInit(isInitial);
|
|
@@ -3216,7 +3244,7 @@ class PersistMeasureUtils {
|
|
|
3216
3244
|
* @param Ctor - Custom IPersistMeasureInstance constructor
|
|
3217
3245
|
*/
|
|
3218
3246
|
usePersistMeasureAdapter(Ctor) {
|
|
3219
|
-
LOGGER_SERVICE$
|
|
3247
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
|
|
3220
3248
|
this.PersistMeasureInstanceCtor = Ctor;
|
|
3221
3249
|
this.getMeasureStorage.clear();
|
|
3222
3250
|
}
|
|
@@ -3228,7 +3256,7 @@ class PersistMeasureUtils {
|
|
|
3228
3256
|
* @returns AsyncGenerator yielding entry keys
|
|
3229
3257
|
*/
|
|
3230
3258
|
async *listMeasureData(bucket) {
|
|
3231
|
-
LOGGER_SERVICE$
|
|
3259
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
|
|
3232
3260
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3233
3261
|
const instance = this.getMeasureStorage(bucket);
|
|
3234
3262
|
await instance.waitForInit(isInitial);
|
|
@@ -3239,21 +3267,21 @@ class PersistMeasureUtils {
|
|
|
3239
3267
|
* Call when process.cwd() changes between strategy iterations.
|
|
3240
3268
|
*/
|
|
3241
3269
|
clear() {
|
|
3242
|
-
LOGGER_SERVICE$
|
|
3270
|
+
LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
|
|
3243
3271
|
this.getMeasureStorage.clear();
|
|
3244
3272
|
}
|
|
3245
3273
|
/**
|
|
3246
3274
|
* Switches to the default file-based PersistMeasureInstance.
|
|
3247
3275
|
*/
|
|
3248
3276
|
useJson() {
|
|
3249
|
-
LOGGER_SERVICE$
|
|
3277
|
+
LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
|
|
3250
3278
|
this.usePersistMeasureAdapter(PersistMeasureInstance);
|
|
3251
3279
|
}
|
|
3252
3280
|
/**
|
|
3253
3281
|
* Switches to PersistMeasureDummyInstance (all operations are no-ops).
|
|
3254
3282
|
*/
|
|
3255
3283
|
useDummy() {
|
|
3256
|
-
LOGGER_SERVICE$
|
|
3284
|
+
LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3257
3285
|
this.usePersistMeasureAdapter(PersistMeasureDummyInstance);
|
|
3258
3286
|
}
|
|
3259
3287
|
}
|
|
@@ -3412,7 +3440,7 @@ class PersistIntervalUtils {
|
|
|
3412
3440
|
* @returns Promise resolving to marker data, or null if not found / soft-deleted
|
|
3413
3441
|
*/
|
|
3414
3442
|
this.readIntervalData = async (bucket, key) => {
|
|
3415
|
-
LOGGER_SERVICE$
|
|
3443
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
|
|
3416
3444
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3417
3445
|
const instance = this.getIntervalStorage(bucket);
|
|
3418
3446
|
await instance.waitForInit(isInitial);
|
|
@@ -3428,7 +3456,7 @@ class PersistIntervalUtils {
|
|
|
3428
3456
|
* @returns Promise that resolves when write is complete
|
|
3429
3457
|
*/
|
|
3430
3458
|
this.writeIntervalData = async (data, bucket, key, when) => {
|
|
3431
|
-
LOGGER_SERVICE$
|
|
3459
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
|
|
3432
3460
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3433
3461
|
const instance = this.getIntervalStorage(bucket);
|
|
3434
3462
|
await instance.waitForInit(isInitial);
|
|
@@ -3443,7 +3471,7 @@ class PersistIntervalUtils {
|
|
|
3443
3471
|
* @returns Promise that resolves when removal is complete
|
|
3444
3472
|
*/
|
|
3445
3473
|
this.removeIntervalData = async (bucket, key) => {
|
|
3446
|
-
LOGGER_SERVICE$
|
|
3474
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
|
|
3447
3475
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3448
3476
|
const instance = this.getIntervalStorage(bucket);
|
|
3449
3477
|
await instance.waitForInit(isInitial);
|
|
@@ -3457,7 +3485,7 @@ class PersistIntervalUtils {
|
|
|
3457
3485
|
* @param Ctor - Custom IPersistIntervalInstance constructor
|
|
3458
3486
|
*/
|
|
3459
3487
|
usePersistIntervalAdapter(Ctor) {
|
|
3460
|
-
LOGGER_SERVICE$
|
|
3488
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
|
|
3461
3489
|
this.PersistIntervalInstanceCtor = Ctor;
|
|
3462
3490
|
this.getIntervalStorage.clear();
|
|
3463
3491
|
}
|
|
@@ -3469,7 +3497,7 @@ class PersistIntervalUtils {
|
|
|
3469
3497
|
* @returns AsyncGenerator yielding marker keys
|
|
3470
3498
|
*/
|
|
3471
3499
|
async *listIntervalData(bucket) {
|
|
3472
|
-
LOGGER_SERVICE$
|
|
3500
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
|
|
3473
3501
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3474
3502
|
const instance = this.getIntervalStorage(bucket);
|
|
3475
3503
|
await instance.waitForInit(isInitial);
|
|
@@ -3480,21 +3508,21 @@ class PersistIntervalUtils {
|
|
|
3480
3508
|
* Call when process.cwd() changes between strategy iterations.
|
|
3481
3509
|
*/
|
|
3482
3510
|
clear() {
|
|
3483
|
-
LOGGER_SERVICE$
|
|
3511
|
+
LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
|
|
3484
3512
|
this.getIntervalStorage.clear();
|
|
3485
3513
|
}
|
|
3486
3514
|
/**
|
|
3487
3515
|
* Switches to the default file-based PersistIntervalInstance.
|
|
3488
3516
|
*/
|
|
3489
3517
|
useJson() {
|
|
3490
|
-
LOGGER_SERVICE$
|
|
3518
|
+
LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
|
|
3491
3519
|
this.usePersistIntervalAdapter(PersistIntervalInstance);
|
|
3492
3520
|
}
|
|
3493
3521
|
/**
|
|
3494
3522
|
* Switches to PersistIntervalDummyInstance (all operations are no-ops).
|
|
3495
3523
|
*/
|
|
3496
3524
|
useDummy() {
|
|
3497
|
-
LOGGER_SERVICE$
|
|
3525
|
+
LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3498
3526
|
this.usePersistIntervalAdapter(PersistIntervalDummyInstance);
|
|
3499
3527
|
}
|
|
3500
3528
|
}
|
|
@@ -3700,7 +3728,7 @@ class PersistMemoryUtils {
|
|
|
3700
3728
|
* @returns Promise resolving to entry data, or null if not found / soft-deleted
|
|
3701
3729
|
*/
|
|
3702
3730
|
this.readMemoryData = async (signalId, bucketName, memoryId) => {
|
|
3703
|
-
LOGGER_SERVICE$
|
|
3731
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
|
|
3704
3732
|
const key = `${signalId}:${bucketName}`;
|
|
3705
3733
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3706
3734
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3717,7 +3745,7 @@ class PersistMemoryUtils {
|
|
|
3717
3745
|
* @returns Promise resolving to true if entry exists
|
|
3718
3746
|
*/
|
|
3719
3747
|
this.hasMemoryData = async (signalId, bucketName, memoryId) => {
|
|
3720
|
-
LOGGER_SERVICE$
|
|
3748
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
|
|
3721
3749
|
const key = `${signalId}:${bucketName}`;
|
|
3722
3750
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3723
3751
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3736,7 +3764,7 @@ class PersistMemoryUtils {
|
|
|
3736
3764
|
* @returns Promise that resolves when write is complete
|
|
3737
3765
|
*/
|
|
3738
3766
|
this.writeMemoryData = async (data, signalId, bucketName, memoryId, when) => {
|
|
3739
|
-
LOGGER_SERVICE$
|
|
3767
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
|
|
3740
3768
|
const key = `${signalId}:${bucketName}`;
|
|
3741
3769
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3742
3770
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3753,7 +3781,7 @@ class PersistMemoryUtils {
|
|
|
3753
3781
|
* @returns Promise that resolves when removal is complete
|
|
3754
3782
|
*/
|
|
3755
3783
|
this.removeMemoryData = async (signalId, bucketName, memoryId) => {
|
|
3756
|
-
LOGGER_SERVICE$
|
|
3784
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
|
|
3757
3785
|
const key = `${signalId}:${bucketName}`;
|
|
3758
3786
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3759
3787
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3765,7 +3793,7 @@ class PersistMemoryUtils {
|
|
|
3765
3793
|
* Call when process.cwd() changes between strategy iterations.
|
|
3766
3794
|
*/
|
|
3767
3795
|
this.clear = () => {
|
|
3768
|
-
LOGGER_SERVICE$
|
|
3796
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
|
|
3769
3797
|
this.getMemoryStorage.clear();
|
|
3770
3798
|
};
|
|
3771
3799
|
/**
|
|
@@ -3776,7 +3804,7 @@ class PersistMemoryUtils {
|
|
|
3776
3804
|
* @param bucketName - Bucket name
|
|
3777
3805
|
*/
|
|
3778
3806
|
this.dispose = (signalId, bucketName) => {
|
|
3779
|
-
LOGGER_SERVICE$
|
|
3807
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
|
|
3780
3808
|
const key = `${signalId}:${bucketName}`;
|
|
3781
3809
|
this.getMemoryStorage.clear(key);
|
|
3782
3810
|
};
|
|
@@ -3788,7 +3816,7 @@ class PersistMemoryUtils {
|
|
|
3788
3816
|
* @param Ctor - Custom IPersistMemoryInstance constructor
|
|
3789
3817
|
*/
|
|
3790
3818
|
usePersistMemoryAdapter(Ctor) {
|
|
3791
|
-
LOGGER_SERVICE$
|
|
3819
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
|
|
3792
3820
|
this.PersistMemoryInstanceCtor = Ctor;
|
|
3793
3821
|
this.getMemoryStorage.clear();
|
|
3794
3822
|
}
|
|
@@ -3802,7 +3830,7 @@ class PersistMemoryUtils {
|
|
|
3802
3830
|
* @returns AsyncGenerator yielding `{ memoryId, data }` tuples
|
|
3803
3831
|
*/
|
|
3804
3832
|
async *listMemoryData(signalId, bucketName) {
|
|
3805
|
-
LOGGER_SERVICE$
|
|
3833
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
|
|
3806
3834
|
const key = `${signalId}:${bucketName}`;
|
|
3807
3835
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3808
3836
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3813,14 +3841,14 @@ class PersistMemoryUtils {
|
|
|
3813
3841
|
* Switches to the default file-based PersistMemoryInstance.
|
|
3814
3842
|
*/
|
|
3815
3843
|
useJson() {
|
|
3816
|
-
LOGGER_SERVICE$
|
|
3844
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
|
|
3817
3845
|
this.usePersistMemoryAdapter(PersistMemoryInstance);
|
|
3818
3846
|
}
|
|
3819
3847
|
/**
|
|
3820
3848
|
* Switches to PersistMemoryDummyInstance (all operations are no-ops).
|
|
3821
3849
|
*/
|
|
3822
3850
|
useDummy() {
|
|
3823
|
-
LOGGER_SERVICE$
|
|
3851
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3824
3852
|
this.usePersistMemoryAdapter(PersistMemoryDummyInstance);
|
|
3825
3853
|
}
|
|
3826
3854
|
}
|
|
@@ -3969,7 +3997,7 @@ class PersistRecentUtils {
|
|
|
3969
3997
|
* @returns Promise resolving to recent signal or null if none persisted
|
|
3970
3998
|
*/
|
|
3971
3999
|
this.readRecentData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
3972
|
-
LOGGER_SERVICE$
|
|
4000
|
+
LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
|
|
3973
4001
|
const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
|
|
3974
4002
|
const isInitial = !this.getStorage.has(key);
|
|
3975
4003
|
const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
@@ -3990,7 +4018,7 @@ class PersistRecentUtils {
|
|
|
3990
4018
|
* @returns Promise that resolves when write is complete
|
|
3991
4019
|
*/
|
|
3992
4020
|
this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest, when) => {
|
|
3993
|
-
LOGGER_SERVICE$
|
|
4021
|
+
LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
|
|
3994
4022
|
const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
|
|
3995
4023
|
const isInitial = !this.getStorage.has(key);
|
|
3996
4024
|
const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
@@ -4023,7 +4051,7 @@ class PersistRecentUtils {
|
|
|
4023
4051
|
* @param Ctor - Custom IPersistRecentInstance constructor
|
|
4024
4052
|
*/
|
|
4025
4053
|
usePersistRecentAdapter(Ctor) {
|
|
4026
|
-
LOGGER_SERVICE$
|
|
4054
|
+
LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
|
|
4027
4055
|
this.PersistRecentInstanceCtor = Ctor;
|
|
4028
4056
|
this.getStorage.clear();
|
|
4029
4057
|
}
|
|
@@ -4032,21 +4060,21 @@ class PersistRecentUtils {
|
|
|
4032
4060
|
* Call when process.cwd() changes between strategy iterations.
|
|
4033
4061
|
*/
|
|
4034
4062
|
clear() {
|
|
4035
|
-
LOGGER_SERVICE$
|
|
4063
|
+
LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
|
|
4036
4064
|
this.getStorage.clear();
|
|
4037
4065
|
}
|
|
4038
4066
|
/**
|
|
4039
4067
|
* Switches to the default file-based PersistRecentInstance.
|
|
4040
4068
|
*/
|
|
4041
4069
|
useJson() {
|
|
4042
|
-
LOGGER_SERVICE$
|
|
4070
|
+
LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
|
|
4043
4071
|
this.usePersistRecentAdapter(PersistRecentInstance);
|
|
4044
4072
|
}
|
|
4045
4073
|
/**
|
|
4046
4074
|
* Switches to PersistRecentDummyInstance (all operations are no-ops).
|
|
4047
4075
|
*/
|
|
4048
4076
|
useDummy() {
|
|
4049
|
-
LOGGER_SERVICE$
|
|
4077
|
+
LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
|
|
4050
4078
|
this.usePersistRecentAdapter(PersistRecentDummyInstance);
|
|
4051
4079
|
}
|
|
4052
4080
|
}
|
|
@@ -4181,7 +4209,7 @@ class PersistStateUtils {
|
|
|
4181
4209
|
* @returns Promise that resolves when initialization is complete
|
|
4182
4210
|
*/
|
|
4183
4211
|
this.waitForInit = async (signalId, bucketName, initial) => {
|
|
4184
|
-
LOGGER_SERVICE$
|
|
4212
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
|
|
4185
4213
|
const key = `${signalId}:${bucketName}`;
|
|
4186
4214
|
const isInitial = initial && !this.getStateStorage.has(key);
|
|
4187
4215
|
const instance = this.getStateStorage(signalId, bucketName);
|
|
@@ -4196,7 +4224,7 @@ class PersistStateUtils {
|
|
|
4196
4224
|
* @returns Promise resolving to state data or null if none persisted
|
|
4197
4225
|
*/
|
|
4198
4226
|
this.readStateData = async (signalId, bucketName) => {
|
|
4199
|
-
LOGGER_SERVICE$
|
|
4227
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
|
|
4200
4228
|
const key = `${signalId}:${bucketName}`;
|
|
4201
4229
|
const isInitial = !this.getStateStorage.has(key);
|
|
4202
4230
|
const instance = this.getStateStorage(signalId, bucketName);
|
|
@@ -4214,7 +4242,7 @@ class PersistStateUtils {
|
|
|
4214
4242
|
* @returns Promise that resolves when write is complete
|
|
4215
4243
|
*/
|
|
4216
4244
|
this.writeStateData = async (data, signalId, bucketName, when) => {
|
|
4217
|
-
LOGGER_SERVICE$
|
|
4245
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
|
|
4218
4246
|
const key = `${signalId}:${bucketName}`;
|
|
4219
4247
|
const isInitial = !this.getStateStorage.has(key);
|
|
4220
4248
|
const instance = this.getStateStorage(signalId, bucketName);
|
|
@@ -4225,14 +4253,14 @@ class PersistStateUtils {
|
|
|
4225
4253
|
* Switches to PersistStateDummyInstance (all operations are no-ops).
|
|
4226
4254
|
*/
|
|
4227
4255
|
this.useDummy = () => {
|
|
4228
|
-
LOGGER_SERVICE$
|
|
4256
|
+
LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
4229
4257
|
this.usePersistStateAdapter(PersistStateDummyInstance);
|
|
4230
4258
|
};
|
|
4231
4259
|
/**
|
|
4232
4260
|
* Switches to the default file-based PersistStateInstance.
|
|
4233
4261
|
*/
|
|
4234
4262
|
this.useJson = () => {
|
|
4235
|
-
LOGGER_SERVICE$
|
|
4263
|
+
LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
|
|
4236
4264
|
this.usePersistStateAdapter(PersistStateInstance);
|
|
4237
4265
|
};
|
|
4238
4266
|
/**
|
|
@@ -4240,7 +4268,7 @@ class PersistStateUtils {
|
|
|
4240
4268
|
* Call when process.cwd() changes between strategy iterations.
|
|
4241
4269
|
*/
|
|
4242
4270
|
this.clear = () => {
|
|
4243
|
-
LOGGER_SERVICE$
|
|
4271
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
|
|
4244
4272
|
this.getStateStorage.clear();
|
|
4245
4273
|
};
|
|
4246
4274
|
/**
|
|
@@ -4251,7 +4279,7 @@ class PersistStateUtils {
|
|
|
4251
4279
|
* @param bucketName - Bucket name
|
|
4252
4280
|
*/
|
|
4253
4281
|
this.dispose = (signalId, bucketName) => {
|
|
4254
|
-
LOGGER_SERVICE$
|
|
4282
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
|
|
4255
4283
|
const key = `${signalId}:${bucketName}`;
|
|
4256
4284
|
this.getStateStorage.clear(key);
|
|
4257
4285
|
};
|
|
@@ -4263,7 +4291,7 @@ class PersistStateUtils {
|
|
|
4263
4291
|
* @param Ctor - Custom IPersistStateInstance constructor
|
|
4264
4292
|
*/
|
|
4265
4293
|
usePersistStateAdapter(Ctor) {
|
|
4266
|
-
LOGGER_SERVICE$
|
|
4294
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
|
|
4267
4295
|
this.PersistStateInstanceCtor = Ctor;
|
|
4268
4296
|
this.getStateStorage.clear();
|
|
4269
4297
|
}
|
|
@@ -4403,7 +4431,7 @@ class PersistSessionUtils {
|
|
|
4403
4431
|
* @returns Promise that resolves when initialization is complete
|
|
4404
4432
|
*/
|
|
4405
4433
|
this.waitForInit = async (strategyName, exchangeName, frameName, initial) => {
|
|
4406
|
-
LOGGER_SERVICE$
|
|
4434
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
|
|
4407
4435
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4408
4436
|
const isInitial = initial && !this.getSessionStorage.has(key);
|
|
4409
4437
|
const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
@@ -4419,7 +4447,7 @@ class PersistSessionUtils {
|
|
|
4419
4447
|
* @returns Promise resolving to session data or null if none persisted
|
|
4420
4448
|
*/
|
|
4421
4449
|
this.readSessionData = async (strategyName, exchangeName, frameName) => {
|
|
4422
|
-
LOGGER_SERVICE$
|
|
4450
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
|
|
4423
4451
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4424
4452
|
const isInitial = !this.getSessionStorage.has(key);
|
|
4425
4453
|
const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
@@ -4438,7 +4466,7 @@ class PersistSessionUtils {
|
|
|
4438
4466
|
* @returns Promise that resolves when write is complete
|
|
4439
4467
|
*/
|
|
4440
4468
|
this.writeSessionData = async (data, strategyName, exchangeName, frameName, when) => {
|
|
4441
|
-
LOGGER_SERVICE$
|
|
4469
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
|
|
4442
4470
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4443
4471
|
const isInitial = !this.getSessionStorage.has(key);
|
|
4444
4472
|
const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
@@ -4449,14 +4477,14 @@ class PersistSessionUtils {
|
|
|
4449
4477
|
* Switches to PersistSessionDummyInstance (all operations are no-ops).
|
|
4450
4478
|
*/
|
|
4451
4479
|
this.useDummy = () => {
|
|
4452
|
-
LOGGER_SERVICE$
|
|
4480
|
+
LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
|
|
4453
4481
|
this.usePersistSessionAdapter(PersistSessionDummyInstance);
|
|
4454
4482
|
};
|
|
4455
4483
|
/**
|
|
4456
4484
|
* Switches to the default file-based PersistSessionInstance.
|
|
4457
4485
|
*/
|
|
4458
4486
|
this.useJson = () => {
|
|
4459
|
-
LOGGER_SERVICE$
|
|
4487
|
+
LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
|
|
4460
4488
|
this.usePersistSessionAdapter(PersistSessionInstance);
|
|
4461
4489
|
};
|
|
4462
4490
|
/**
|
|
@@ -4464,7 +4492,7 @@ class PersistSessionUtils {
|
|
|
4464
4492
|
* Call when process.cwd() changes between strategy iterations.
|
|
4465
4493
|
*/
|
|
4466
4494
|
this.clear = () => {
|
|
4467
|
-
LOGGER_SERVICE$
|
|
4495
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
|
|
4468
4496
|
this.getSessionStorage.clear();
|
|
4469
4497
|
};
|
|
4470
4498
|
/**
|
|
@@ -4476,7 +4504,7 @@ class PersistSessionUtils {
|
|
|
4476
4504
|
* @param frameName - Frame identifier
|
|
4477
4505
|
*/
|
|
4478
4506
|
this.dispose = (strategyName, exchangeName, frameName) => {
|
|
4479
|
-
LOGGER_SERVICE$
|
|
4507
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
|
|
4480
4508
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4481
4509
|
this.getSessionStorage.clear(key);
|
|
4482
4510
|
};
|
|
@@ -4488,7 +4516,7 @@ class PersistSessionUtils {
|
|
|
4488
4516
|
* @param Ctor - Custom IPersistSessionInstance constructor
|
|
4489
4517
|
*/
|
|
4490
4518
|
usePersistSessionAdapter(Ctor) {
|
|
4491
|
-
LOGGER_SERVICE$
|
|
4519
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
|
|
4492
4520
|
this.PersistSessionInstanceCtor = Ctor;
|
|
4493
4521
|
this.getSessionStorage.clear();
|
|
4494
4522
|
}
|
|
@@ -4500,28 +4528,39 @@ class PersistSessionUtils {
|
|
|
4500
4528
|
const PersistSessionAdapter = new PersistSessionUtils();
|
|
4501
4529
|
|
|
4502
4530
|
var _a$2, _b$2;
|
|
4503
|
-
const BUSY_DELAY = 100;
|
|
4504
4531
|
const SET_BUSY_SYMBOL = Symbol("setBusy");
|
|
4505
4532
|
const GET_BUSY_SYMBOL = Symbol("getBusy");
|
|
4506
4533
|
const ACQUIRE_LOCK_SYMBOL = Symbol("acquireLock");
|
|
4507
4534
|
const RELEASE_LOCK_SYMBOL = Symbol("releaseLock");
|
|
4535
|
+
/**
|
|
4536
|
+
* Body of the queued acquire operation.
|
|
4537
|
+
*
|
|
4538
|
+
* Parks the caller on `self._tick` whenever the lock is already busy: each
|
|
4539
|
+
* `releaseLock` emits on `_tick`, waking exactly the next queued acquirer
|
|
4540
|
+
* instead of polling on a fixed delay. The busy counter is bumped only after
|
|
4541
|
+
* the loop exits, so re-entry checks remain coherent under contention.
|
|
4542
|
+
*
|
|
4543
|
+
* @param self - The owning {@link Lock} instance.
|
|
4544
|
+
*/
|
|
4508
4545
|
const ACQUIRE_LOCK_FN = async (self) => {
|
|
4509
4546
|
while (self[GET_BUSY_SYMBOL]()) {
|
|
4510
|
-
|
|
4547
|
+
// @ts-ignore
|
|
4548
|
+
await self._tick.toPromise();
|
|
4511
4549
|
}
|
|
4512
4550
|
self[SET_BUSY_SYMBOL](true);
|
|
4513
4551
|
};
|
|
4514
4552
|
/**
|
|
4515
4553
|
* Mutual exclusion primitive for async TypeScript code.
|
|
4516
4554
|
*
|
|
4517
|
-
* Provides a
|
|
4518
|
-
*
|
|
4519
|
-
*
|
|
4520
|
-
*
|
|
4555
|
+
* Provides a queued lock that serializes access to a critical section across
|
|
4556
|
+
* concurrent async callers. Wake-ups are event-driven (via an internal
|
|
4557
|
+
* `_tick` subject emitted on every `releaseLock`) rather than polling,
|
|
4558
|
+
* so contention does not incur a fixed delay.
|
|
4521
4559
|
*
|
|
4522
|
-
*
|
|
4560
|
+
* The busy counter detects mis-matched releases and throws immediately on
|
|
4561
|
+
* extra `releaseLock` calls.
|
|
4523
4562
|
*
|
|
4524
|
-
* **
|
|
4563
|
+
* **Usage**
|
|
4525
4564
|
* ```ts
|
|
4526
4565
|
* await lock.acquireLock();
|
|
4527
4566
|
* try {
|
|
@@ -4536,7 +4575,18 @@ const ACQUIRE_LOCK_FN = async (self) => {
|
|
|
4536
4575
|
*/
|
|
4537
4576
|
class Lock {
|
|
4538
4577
|
constructor() {
|
|
4578
|
+
/**
|
|
4579
|
+
* Outstanding acquires that have not yet been released.
|
|
4580
|
+
* Incremented in `[SET_BUSY_SYMBOL](true)`, decremented in `[SET_BUSY_SYMBOL](false)`.
|
|
4581
|
+
* A negative value indicates an extra `releaseLock` and throws on detection.
|
|
4582
|
+
*/
|
|
4539
4583
|
this._isBusy = 0;
|
|
4584
|
+
/**
|
|
4585
|
+
* Wake-up channel for {@link ACQUIRE_LOCK_FN}.
|
|
4586
|
+
* Every {@link releaseLock} emits a single tick that unblocks the next
|
|
4587
|
+
* queued acquirer parked on `toPromise()`.
|
|
4588
|
+
*/
|
|
4589
|
+
this._tick = new Subject();
|
|
4540
4590
|
this[_a$2] = queued(ACQUIRE_LOCK_FN);
|
|
4541
4591
|
this[_b$2] = () => this[SET_BUSY_SYMBOL](false);
|
|
4542
4592
|
/**
|
|
@@ -4557,16 +4607,19 @@ class Lock {
|
|
|
4557
4607
|
await this[ACQUIRE_LOCK_SYMBOL](this);
|
|
4558
4608
|
};
|
|
4559
4609
|
/**
|
|
4560
|
-
* Releases the lock previously acquired with {@link acquireLock}
|
|
4610
|
+
* Releases the lock previously acquired with {@link acquireLock} and emits
|
|
4611
|
+
* on the internal `_tick` subject to wake the next queued acquirer.
|
|
4612
|
+
*
|
|
4561
4613
|
* Must be called exactly once per successful {@link acquireLock} call,
|
|
4562
|
-
* typically inside a `finally` block. Throws if called more times
|
|
4563
|
-
*
|
|
4614
|
+
* typically inside a `finally` block. Throws if called more times than
|
|
4615
|
+
* the lock was acquired.
|
|
4564
4616
|
*
|
|
4565
4617
|
* @returns {Promise<void>} Resolves once the lock has been released.
|
|
4566
4618
|
* @throws {Error} If the lock is released more times than it was acquired.
|
|
4567
4619
|
*/
|
|
4568
4620
|
this.releaseLock = async () => {
|
|
4569
4621
|
await this[RELEASE_LOCK_SYMBOL]();
|
|
4622
|
+
await this._tick.next();
|
|
4570
4623
|
};
|
|
4571
4624
|
}
|
|
4572
4625
|
[SET_BUSY_SYMBOL](isBusy) {
|
|
@@ -4581,18 +4634,166 @@ class Lock {
|
|
|
4581
4634
|
}
|
|
4582
4635
|
_a$2 = ACQUIRE_LOCK_SYMBOL, _b$2 = RELEASE_LOCK_SYMBOL;
|
|
4583
4636
|
|
|
4637
|
+
const METHOD_NAME_ADD_ACTIVITY = "LookupUtils.addActivity";
|
|
4638
|
+
const METHOD_NAME_REMOVE_ACTIVITY = "LookupUtils.removeActivity";
|
|
4639
|
+
const METHOD_NAME_LIST_ACTIVITY = "LookupUtils.listActivity";
|
|
4640
|
+
/** Logger service injected as DI singleton */
|
|
4641
|
+
const LOGGER_SERVICE$7 = new LoggerService();
|
|
4642
|
+
/**
|
|
4643
|
+
* Builds the composite {@link Key} used to register an activity in `_lookupMap`.
|
|
4644
|
+
*
|
|
4645
|
+
* Mirrors the {@link Key} type construction: appends `frameName` only when provided
|
|
4646
|
+
* (typical for backtest), then a `"backtest"` / `"live"` discriminator suffix.
|
|
4647
|
+
*
|
|
4648
|
+
* @param symbol - Trading pair symbol.
|
|
4649
|
+
* @param strategyName - Strategy schema name.
|
|
4650
|
+
* @param exchangeName - Exchange schema name.
|
|
4651
|
+
* @param frameName - Frame schema name; omitted from the key when falsy.
|
|
4652
|
+
* @param backtest - `true` for backtest, `false` for live.
|
|
4653
|
+
* @returns Colon-joined composite key.
|
|
4654
|
+
*/
|
|
4655
|
+
const CREATE_KEY_FN$y = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
4656
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
4657
|
+
if (frameName)
|
|
4658
|
+
parts.push(frameName);
|
|
4659
|
+
parts.push(backtest ? "backtest" : "live");
|
|
4660
|
+
return parts.join(":");
|
|
4661
|
+
};
|
|
4662
|
+
/**
|
|
4663
|
+
* In-memory registry of currently running backtest and live activities.
|
|
4664
|
+
*
|
|
4665
|
+
* Purpose:
|
|
4666
|
+
* - Each `Backtest.run` / `Live.run` / per-strategy walker iteration registers an
|
|
4667
|
+
* {@link IActivityEntry} on start and removes it on completion.
|
|
4668
|
+
* - `Candle.spinLock` consults {@link isParallel} to decide whether the event-loop
|
|
4669
|
+
* hand-off (post-candle-fetch spin) is worth performing. With a single active
|
|
4670
|
+
* workload there is no peer to yield to, so the spin is skipped entirely.
|
|
4671
|
+
*
|
|
4672
|
+
* Exposed as the `Lookup` singleton; no constructor parameters.
|
|
4673
|
+
*
|
|
4674
|
+
* @example
|
|
4675
|
+
* ```typescript
|
|
4676
|
+
* Lookup.addActivity({ symbol: "BTCUSDT", context, backtest: true });
|
|
4677
|
+
* try {
|
|
4678
|
+
* for await (const _ of run(symbol, context)) { ... }
|
|
4679
|
+
* } finally {
|
|
4680
|
+
* Lookup.removeActivity({ symbol: "BTCUSDT", context, backtest: true });
|
|
4681
|
+
* }
|
|
4682
|
+
* ```
|
|
4683
|
+
*/
|
|
4684
|
+
class LookupUtils {
|
|
4685
|
+
constructor() {
|
|
4686
|
+
/** Active entries keyed by their composite {@link Key}. */
|
|
4687
|
+
this._lookupMap = new Map();
|
|
4688
|
+
/**
|
|
4689
|
+
* Registers a backtest or live activity in the lookup map.
|
|
4690
|
+
* Idempotent for identical keys — duplicate calls overwrite the existing entry.
|
|
4691
|
+
*
|
|
4692
|
+
* @param activity - Activity descriptor identifying the running workload.
|
|
4693
|
+
*/
|
|
4694
|
+
this.addActivity = (activity) => {
|
|
4695
|
+
LOGGER_SERVICE$7.info(METHOD_NAME_ADD_ACTIVITY, {
|
|
4696
|
+
activity,
|
|
4697
|
+
});
|
|
4698
|
+
const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
|
|
4699
|
+
this._lookupMap.set(key, activity);
|
|
4700
|
+
};
|
|
4701
|
+
/**
|
|
4702
|
+
* Removes a previously registered activity from the lookup map.
|
|
4703
|
+
* Must be paired with a prior {@link addActivity}, typically in a `finally` block,
|
|
4704
|
+
* so a thrown error in the underlying run does not leave a stale entry behind.
|
|
4705
|
+
*
|
|
4706
|
+
* @param activity - Activity descriptor matching the one passed to {@link addActivity}.
|
|
4707
|
+
*/
|
|
4708
|
+
this.removeActivity = (activity) => {
|
|
4709
|
+
LOGGER_SERVICE$7.info(METHOD_NAME_REMOVE_ACTIVITY, {
|
|
4710
|
+
activity,
|
|
4711
|
+
});
|
|
4712
|
+
const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
|
|
4713
|
+
this._lookupMap.delete(key);
|
|
4714
|
+
};
|
|
4715
|
+
/**
|
|
4716
|
+
* Returns a snapshot of currently active entries.
|
|
4717
|
+
*
|
|
4718
|
+
* @returns Array of all activities present in the lookup map at call time.
|
|
4719
|
+
*/
|
|
4720
|
+
this.listActivity = () => {
|
|
4721
|
+
LOGGER_SERVICE$7.info(METHOD_NAME_LIST_ACTIVITY);
|
|
4722
|
+
return Array.from(this._lookupMap.values());
|
|
4723
|
+
};
|
|
4724
|
+
}
|
|
4725
|
+
/**
|
|
4726
|
+
* `true` when more than one activity is currently registered.
|
|
4727
|
+
* Used by `Candle.spinLock` to decide whether yielding the event loop is useful.
|
|
4728
|
+
*/
|
|
4729
|
+
get isParallel() {
|
|
4730
|
+
return this._lookupMap.size > 1;
|
|
4731
|
+
}
|
|
4732
|
+
}
|
|
4733
|
+
/**
|
|
4734
|
+
* Process-wide singleton instance of {@link LookupUtils}.
|
|
4735
|
+
* Imported by `Backtest`, `Live`, `WalkerLogicPrivateService` (registration sites)
|
|
4736
|
+
* and by `Candle` (read-only consumer via `isParallel`).
|
|
4737
|
+
*/
|
|
4738
|
+
const Lookup = new LookupUtils();
|
|
4739
|
+
|
|
4584
4740
|
const METHOD_NAME_ACQUIRE_LOCK = "CandleUtils.acquireLock";
|
|
4585
4741
|
const METHOD_NAME_RELEASE_LOCK = "CandleUtils.releaseLock";
|
|
4742
|
+
const METHOD_NAME_SPIN_LOCK = "CandleUtils.spinLock";
|
|
4743
|
+
/**
|
|
4744
|
+
* Upper bound (ms) on how long `spinLock` may park before falling through.
|
|
4745
|
+
* If no peer backtest acquires the candle-fetch mutex within this window,
|
|
4746
|
+
* the spinner proceeds without further yielding.
|
|
4747
|
+
*/
|
|
4748
|
+
const ROTATE_DELAY = 50;
|
|
4586
4749
|
/** Logger service injected as DI singleton */
|
|
4587
4750
|
const LOGGER_SERVICE$6 = new LoggerService();
|
|
4751
|
+
/**
|
|
4752
|
+
* Process-wide coordinator for candle-fetch serialization and cooperative
|
|
4753
|
+
* yielding between parallel backtests.
|
|
4754
|
+
*
|
|
4755
|
+
* Two complementary primitives are exposed:
|
|
4756
|
+
* - **Mutex** via {@link acquireLock} / {@link releaseLock}: prevents concurrent
|
|
4757
|
+
* candle fetches from racing on the same exchange.
|
|
4758
|
+
* - **Spin hand-off** via {@link spinLock}: invoked after a fetch completes to
|
|
4759
|
+
* give peer backtests waiting on the mutex a chance to run, so multiple
|
|
4760
|
+
* `Backtest.run` workloads interleave instead of one monopolizing the loop.
|
|
4761
|
+
*
|
|
4762
|
+
* All three operations are no-ops when `CC_ENABLE_CANDLE_FETCH_MUTEX` is `false`.
|
|
4763
|
+
* The spin additionally requires `CC_ENABLE_BACKTEST_PARALLEL_SPIN` and at least
|
|
4764
|
+
* two registered activities in `Lookup` (see `Lookup.isParallel`).
|
|
4765
|
+
*
|
|
4766
|
+
* @example
|
|
4767
|
+
* ```typescript
|
|
4768
|
+
* await Candle.acquireLock("ClientExchange GET_CANDLES_FN");
|
|
4769
|
+
* try {
|
|
4770
|
+
* const candles = await fetchFromExchange(...);
|
|
4771
|
+
* return candles;
|
|
4772
|
+
* } finally {
|
|
4773
|
+
* await Candle.releaseLock("ClientExchange GET_CANDLES_FN");
|
|
4774
|
+
* }
|
|
4775
|
+
* // Elsewhere, after a fetch completes inside a backtest loop:
|
|
4776
|
+
* await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
|
|
4777
|
+
* ```
|
|
4778
|
+
*/
|
|
4588
4779
|
class CandleUtils {
|
|
4589
4780
|
constructor() {
|
|
4781
|
+
/** Underlying mutex serializing candle fetches across concurrent callers. */
|
|
4590
4782
|
this._lock = new Lock();
|
|
4591
4783
|
/**
|
|
4592
|
-
*
|
|
4784
|
+
* Emits whenever {@link acquireLock} successfully takes the mutex.
|
|
4785
|
+
* Awaited by {@link spinLock} to detect that a peer backtest has just
|
|
4786
|
+
* started its own fetch — the signal that yielding now will be productive.
|
|
4787
|
+
*/
|
|
4788
|
+
this._spin = new Subject();
|
|
4789
|
+
/**
|
|
4790
|
+
* Acquires the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
|
|
4593
4791
|
* Prevents concurrent candle fetches from the same exchange.
|
|
4594
4792
|
*
|
|
4595
|
-
*
|
|
4793
|
+
* On successful acquisition, emits on the internal spin subject so any
|
|
4794
|
+
* peer parked inside {@link spinLock} can wake up and proceed.
|
|
4795
|
+
*
|
|
4796
|
+
* @param source - Caller identifier for logging.
|
|
4596
4797
|
*/
|
|
4597
4798
|
this.acquireLock = async (source) => {
|
|
4598
4799
|
LOGGER_SERVICE$6.info(METHOD_NAME_ACQUIRE_LOCK, {
|
|
@@ -4601,13 +4802,14 @@ class CandleUtils {
|
|
|
4601
4802
|
if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
|
|
4602
4803
|
return;
|
|
4603
4804
|
}
|
|
4604
|
-
|
|
4805
|
+
await this._lock.acquireLock();
|
|
4806
|
+
await this._spin.next();
|
|
4605
4807
|
};
|
|
4606
4808
|
/**
|
|
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.
|
|
4809
|
+
* Releases the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
|
|
4810
|
+
* Must be called after {@link acquireLock}, typically in a `finally` block.
|
|
4609
4811
|
*
|
|
4610
|
-
* @param source - Caller identifier for logging
|
|
4812
|
+
* @param source - Caller identifier for logging.
|
|
4611
4813
|
*/
|
|
4612
4814
|
this.releaseLock = async (source) => {
|
|
4613
4815
|
LOGGER_SERVICE$6.info(METHOD_NAME_RELEASE_LOCK, {
|
|
@@ -4618,8 +4820,47 @@ class CandleUtils {
|
|
|
4618
4820
|
}
|
|
4619
4821
|
return await this._lock.releaseLock();
|
|
4620
4822
|
};
|
|
4823
|
+
/**
|
|
4824
|
+
* Cooperative event-loop hand-off invoked by `BacktestLogicPrivateService`
|
|
4825
|
+
* after a successful `getNextCandles`. Allows peer backtests waiting on the
|
|
4826
|
+
* candle-fetch mutex to run before the current backtest fetches the next chunk.
|
|
4827
|
+
*
|
|
4828
|
+
* Waits for one of:
|
|
4829
|
+
* - a peer calling {@link acquireLock} (signalled via the spin subject), or
|
|
4830
|
+
* - a `ROTATE_DELAY` ms timeout, so the caller never parks indefinitely.
|
|
4831
|
+
*
|
|
4832
|
+
* Returns immediately as a no-op when any of these is true:
|
|
4833
|
+
* - `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled (mutex is off entirely),
|
|
4834
|
+
* - `CC_ENABLE_BACKTEST_PARALLEL_SPIN` is disabled (cooperative yielding off),
|
|
4835
|
+
* - `Lookup.isParallel` is `false` (only one active workload — no peer to yield to).
|
|
4836
|
+
*
|
|
4837
|
+
* @param source - Caller identifier for logging.
|
|
4838
|
+
*/
|
|
4839
|
+
this.spinLock = async (source) => {
|
|
4840
|
+
LOGGER_SERVICE$6.info(METHOD_NAME_SPIN_LOCK, {
|
|
4841
|
+
source,
|
|
4842
|
+
});
|
|
4843
|
+
if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
|
|
4844
|
+
return;
|
|
4845
|
+
}
|
|
4846
|
+
if (!GLOBAL_CONFIG.CC_ENABLE_BACKTEST_PARALLEL_SPIN) {
|
|
4847
|
+
return;
|
|
4848
|
+
}
|
|
4849
|
+
if (!Lookup.isParallel) {
|
|
4850
|
+
return;
|
|
4851
|
+
}
|
|
4852
|
+
await Promise.race([
|
|
4853
|
+
this._spin.toPromise(),
|
|
4854
|
+
sleep(ROTATE_DELAY),
|
|
4855
|
+
]);
|
|
4856
|
+
};
|
|
4621
4857
|
}
|
|
4622
4858
|
}
|
|
4859
|
+
/**
|
|
4860
|
+
* Process-wide singleton instance of {@link CandleUtils}.
|
|
4861
|
+
* Imported by `ClientExchange` (mutex around exchange fetches) and by
|
|
4862
|
+
* `BacktestLogicPrivateService` (spin hand-off between parallel backtests).
|
|
4863
|
+
*/
|
|
4623
4864
|
const Candle = new CandleUtils();
|
|
4624
4865
|
|
|
4625
4866
|
const MS_PER_MINUTE$7 = 60000;
|
|
@@ -19153,9 +19394,28 @@ const TICK_FN = async (self, symbol, when) => {
|
|
|
19153
19394
|
return { type: "error", __error__: SYMBOL_FN_ERROR, reason: "TICK_FN", message: getErrorMessage(error) };
|
|
19154
19395
|
}
|
|
19155
19396
|
};
|
|
19397
|
+
/**
|
|
19398
|
+
* Wraps `exchangeCoreService.getNextCandles` with error capture and a cooperative
|
|
19399
|
+
* event-loop hand-off after a successful fetch.
|
|
19400
|
+
*
|
|
19401
|
+
* Calls `Candle.spinLock(...)` on success: when multiple backtests run in parallel
|
|
19402
|
+
* (`Lookup.isParallel === true`), this yields the event loop so a peer waiting on
|
|
19403
|
+
* the candle-fetch mutex can take its turn, producing round-robin interleaving
|
|
19404
|
+
* instead of one backtest monopolizing the loop until completion. The spin is a
|
|
19405
|
+
* no-op for single-workload runs.
|
|
19406
|
+
*
|
|
19407
|
+
* @param self - Owning service instance, used for logging and exchange access.
|
|
19408
|
+
* @param symbol - Trading pair symbol.
|
|
19409
|
+
* @param candlesNeeded - Number of 1m candles to request.
|
|
19410
|
+
* @param bufferStartTime - Inclusive start time for the fetch window.
|
|
19411
|
+
* @param logMeta - Extra structured fields appended to the warn log on failure.
|
|
19412
|
+
* @returns Fetched candles, or a {@link TFnError} discriminated union on failure.
|
|
19413
|
+
*/
|
|
19156
19414
|
const GET_CANDLES_FN = async (self, symbol, candlesNeeded, bufferStartTime, logMeta) => {
|
|
19157
19415
|
try {
|
|
19158
|
-
|
|
19416
|
+
const result = await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
|
|
19417
|
+
await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
|
|
19418
|
+
return result;
|
|
19159
19419
|
}
|
|
19160
19420
|
catch (error) {
|
|
19161
19421
|
console.error(`backtestLogicPrivateService getNextCandles failed symbol=${symbol} strategyName=${self.methodContextService.context.strategyName} exchangeName=${self.methodContextService.context.exchangeName}`);
|
|
@@ -20041,6 +20301,15 @@ class WalkerLogicPrivateService {
|
|
|
20041
20301
|
exchangeName: context.exchangeName,
|
|
20042
20302
|
frameName: context.frameName,
|
|
20043
20303
|
});
|
|
20304
|
+
Lookup.addActivity({
|
|
20305
|
+
symbol,
|
|
20306
|
+
context: {
|
|
20307
|
+
strategyName,
|
|
20308
|
+
exchangeName: context.exchangeName,
|
|
20309
|
+
frameName: context.frameName,
|
|
20310
|
+
},
|
|
20311
|
+
backtest: true,
|
|
20312
|
+
});
|
|
20044
20313
|
try {
|
|
20045
20314
|
await resolveDocuments(iterator);
|
|
20046
20315
|
}
|
|
@@ -20056,6 +20325,17 @@ class WalkerLogicPrivateService {
|
|
|
20056
20325
|
await CALL_STRATEGY_ERROR_CALLBACKS_FN(this, walkerSchema, strategyName, symbol, error);
|
|
20057
20326
|
continue;
|
|
20058
20327
|
}
|
|
20328
|
+
finally {
|
|
20329
|
+
Lookup.removeActivity({
|
|
20330
|
+
symbol,
|
|
20331
|
+
context: {
|
|
20332
|
+
strategyName,
|
|
20333
|
+
exchangeName: context.exchangeName,
|
|
20334
|
+
frameName: context.frameName,
|
|
20335
|
+
},
|
|
20336
|
+
backtest: true,
|
|
20337
|
+
});
|
|
20338
|
+
}
|
|
20059
20339
|
this.loggerService.info("walkerLogicPrivateService backtest complete", {
|
|
20060
20340
|
strategyName,
|
|
20061
20341
|
symbol,
|
|
@@ -20132,6 +20412,110 @@ class WalkerLogicPrivateService {
|
|
|
20132
20412
|
}
|
|
20133
20413
|
}
|
|
20134
20414
|
|
|
20415
|
+
/**
|
|
20416
|
+
* Run iterator function for backtest logic.
|
|
20417
|
+
*
|
|
20418
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20419
|
+
* @param context - Execution context with strategy, exchange, and frame names
|
|
20420
|
+
* @param self - Instance of BacktestLogicPublicService
|
|
20421
|
+
* @returns Async iterator for backtest results
|
|
20422
|
+
*/
|
|
20423
|
+
const RUN_ITERATOR_FN$1 = (self, symbol, context) => {
|
|
20424
|
+
return MethodContextService.runAsyncIterator(self.backtestLogicPrivateService.run(symbol), {
|
|
20425
|
+
exchangeName: context.exchangeName,
|
|
20426
|
+
strategyName: context.strategyName,
|
|
20427
|
+
frameName: context.frameName,
|
|
20428
|
+
});
|
|
20429
|
+
};
|
|
20430
|
+
/**
|
|
20431
|
+
* Call before start execution for backtest logic.
|
|
20432
|
+
* This function is responsible for triggering the beforeStartSubject
|
|
20433
|
+
* with the appropriate context and symbol information.
|
|
20434
|
+
*/
|
|
20435
|
+
const CALL_BEFORE_START_FN$1 = trycatch(async (self, symbol, context) => {
|
|
20436
|
+
const { startDate } = self.frameSchemaService.get(context.frameName);
|
|
20437
|
+
const when = alignToInterval(startDate, "1m");
|
|
20438
|
+
await MethodContextService.runInContext(async () => {
|
|
20439
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20440
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20441
|
+
await beforeStartSubject.next({
|
|
20442
|
+
symbol,
|
|
20443
|
+
exchangeName: context.exchangeName,
|
|
20444
|
+
strategyName: context.strategyName,
|
|
20445
|
+
frameName: context.frameName,
|
|
20446
|
+
backtest: true,
|
|
20447
|
+
when,
|
|
20448
|
+
timestamp: when.getTime(),
|
|
20449
|
+
currentPrice,
|
|
20450
|
+
});
|
|
20451
|
+
}, {
|
|
20452
|
+
symbol,
|
|
20453
|
+
when,
|
|
20454
|
+
backtest: true,
|
|
20455
|
+
});
|
|
20456
|
+
}, {
|
|
20457
|
+
exchangeName: context.exchangeName,
|
|
20458
|
+
strategyName: context.strategyName,
|
|
20459
|
+
frameName: context.frameName,
|
|
20460
|
+
});
|
|
20461
|
+
}, {
|
|
20462
|
+
fallback: (error, self) => {
|
|
20463
|
+
const message = "BacktestLogicPublicService CALL_BEFORE_START_FN thrown";
|
|
20464
|
+
const payload = {
|
|
20465
|
+
error: errorData(error),
|
|
20466
|
+
message: getErrorMessage(error),
|
|
20467
|
+
};
|
|
20468
|
+
self.loggerService.warn(message, payload);
|
|
20469
|
+
console.error(message, payload);
|
|
20470
|
+
errorEmitter.next(error);
|
|
20471
|
+
},
|
|
20472
|
+
});
|
|
20473
|
+
/**
|
|
20474
|
+
* Call after end execution for backtest logic.
|
|
20475
|
+
* This function is responsible for triggering the afterEndSubject
|
|
20476
|
+
* with the appropriate context and symbol information.
|
|
20477
|
+
*/
|
|
20478
|
+
const CALL_AFTER_END_FN$1 = trycatch(async (self, symbol, context) => {
|
|
20479
|
+
const { startDate } = self.frameSchemaService.get(context.frameName);
|
|
20480
|
+
const timestamp = self.timeMetaService.hasTimestamp(symbol, context, true)
|
|
20481
|
+
? await self.timeMetaService.getTimestamp(symbol, context, true)
|
|
20482
|
+
: startDate.getTime();
|
|
20483
|
+
const when = new Date(timestamp);
|
|
20484
|
+
await MethodContextService.runInContext(async () => {
|
|
20485
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20486
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20487
|
+
await afterEndSubject.next({
|
|
20488
|
+
symbol,
|
|
20489
|
+
exchangeName: context.exchangeName,
|
|
20490
|
+
strategyName: context.strategyName,
|
|
20491
|
+
frameName: context.frameName,
|
|
20492
|
+
backtest: true,
|
|
20493
|
+
when,
|
|
20494
|
+
timestamp,
|
|
20495
|
+
currentPrice,
|
|
20496
|
+
});
|
|
20497
|
+
}, {
|
|
20498
|
+
symbol,
|
|
20499
|
+
when,
|
|
20500
|
+
backtest: true,
|
|
20501
|
+
});
|
|
20502
|
+
}, {
|
|
20503
|
+
exchangeName: context.exchangeName,
|
|
20504
|
+
strategyName: context.strategyName,
|
|
20505
|
+
frameName: context.frameName,
|
|
20506
|
+
});
|
|
20507
|
+
}, {
|
|
20508
|
+
fallback: (error, self) => {
|
|
20509
|
+
const message = "BacktestLogicPublicService CALL_AFTER_END_FN thrown";
|
|
20510
|
+
const payload = {
|
|
20511
|
+
error: errorData(error),
|
|
20512
|
+
message: getErrorMessage(error),
|
|
20513
|
+
};
|
|
20514
|
+
self.loggerService.warn(message, payload);
|
|
20515
|
+
console.error(message, payload);
|
|
20516
|
+
errorEmitter.next(error);
|
|
20517
|
+
},
|
|
20518
|
+
});
|
|
20135
20519
|
/**
|
|
20136
20520
|
* Public service for backtest orchestration with context management.
|
|
20137
20521
|
*
|
|
@@ -20160,30 +20544,134 @@ class BacktestLogicPublicService {
|
|
|
20160
20544
|
constructor() {
|
|
20161
20545
|
this.loggerService = inject(TYPES.loggerService);
|
|
20162
20546
|
this.backtestLogicPrivateService = inject(TYPES.backtestLogicPrivateService);
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
20166
|
-
|
|
20167
|
-
|
|
20168
|
-
|
|
20169
|
-
|
|
20170
|
-
|
|
20171
|
-
|
|
20172
|
-
|
|
20173
|
-
|
|
20174
|
-
|
|
20547
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
20548
|
+
this.frameSchemaService = inject(TYPES.frameSchemaService);
|
|
20549
|
+
this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
|
|
20550
|
+
}
|
|
20551
|
+
/**
|
|
20552
|
+
* Runs backtest for a symbol with context propagation.
|
|
20553
|
+
*
|
|
20554
|
+
* Streams closed signals as async generator. Context is automatically
|
|
20555
|
+
* injected into all framework functions called during iteration.
|
|
20556
|
+
*
|
|
20557
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20558
|
+
* @param context - Execution context with strategy, exchange, and frame names
|
|
20559
|
+
* @returns Async generator yielding closed signals with PNL
|
|
20560
|
+
*/
|
|
20561
|
+
async *run(symbol, context) {
|
|
20562
|
+
this.loggerService.log("backtestLogicPublicService run", {
|
|
20563
|
+
symbol,
|
|
20564
|
+
context,
|
|
20565
|
+
});
|
|
20566
|
+
await CALL_BEFORE_START_FN$1(this, symbol, context);
|
|
20567
|
+
try {
|
|
20568
|
+
yield* RUN_ITERATOR_FN$1(this, symbol, context);
|
|
20569
|
+
}
|
|
20570
|
+
finally {
|
|
20571
|
+
await CALL_AFTER_END_FN$1(this, symbol, context);
|
|
20572
|
+
}
|
|
20573
|
+
}
|
|
20574
|
+
}
|
|
20575
|
+
|
|
20576
|
+
/**
|
|
20577
|
+
* Run iterator function for live logic.
|
|
20578
|
+
*
|
|
20579
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20580
|
+
* @param context - Execution context with strategy and exchange names
|
|
20581
|
+
* @param self - Instance of LiveLogicPublicService
|
|
20582
|
+
* @returns Async iterator for live trading results
|
|
20583
|
+
*/
|
|
20584
|
+
const RUN_ITERATOR_FN = (self, symbol, context) => {
|
|
20585
|
+
return MethodContextService.runAsyncIterator(self.liveLogicPrivateService.run(symbol), {
|
|
20586
|
+
exchangeName: context.exchangeName,
|
|
20587
|
+
strategyName: context.strategyName,
|
|
20588
|
+
frameName: "",
|
|
20589
|
+
});
|
|
20590
|
+
};
|
|
20591
|
+
/**
|
|
20592
|
+
* Call before start execution for live logic.
|
|
20593
|
+
* This function is responsible for triggering the beforeStartSubject
|
|
20594
|
+
* with the appropriate context and symbol information.
|
|
20595
|
+
*/
|
|
20596
|
+
const CALL_BEFORE_START_FN = trycatch(async (self, symbol, context) => {
|
|
20597
|
+
const when = alignToInterval(new Date(), "1m");
|
|
20598
|
+
await MethodContextService.runInContext(async () => {
|
|
20599
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20600
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20601
|
+
await beforeStartSubject.next({
|
|
20175
20602
|
symbol,
|
|
20176
|
-
context,
|
|
20603
|
+
exchangeName: context.exchangeName,
|
|
20604
|
+
strategyName: context.strategyName,
|
|
20605
|
+
frameName: "",
|
|
20606
|
+
backtest: false,
|
|
20607
|
+
currentPrice,
|
|
20608
|
+
when,
|
|
20609
|
+
timestamp: when.getTime(),
|
|
20177
20610
|
});
|
|
20178
|
-
|
|
20611
|
+
}, {
|
|
20612
|
+
symbol,
|
|
20613
|
+
when,
|
|
20614
|
+
backtest: false,
|
|
20615
|
+
});
|
|
20616
|
+
}, {
|
|
20617
|
+
exchangeName: context.exchangeName,
|
|
20618
|
+
strategyName: context.strategyName,
|
|
20619
|
+
frameName: "",
|
|
20620
|
+
});
|
|
20621
|
+
}, {
|
|
20622
|
+
fallback: (error, self) => {
|
|
20623
|
+
const message = "LiveLogicPublicService CALL_BEFORE_START_FN thrown";
|
|
20624
|
+
const payload = {
|
|
20625
|
+
error: errorData(error),
|
|
20626
|
+
message: getErrorMessage(error),
|
|
20627
|
+
};
|
|
20628
|
+
self.loggerService.warn(message, payload);
|
|
20629
|
+
console.error(message, payload);
|
|
20630
|
+
errorEmitter.next(error);
|
|
20631
|
+
},
|
|
20632
|
+
});
|
|
20633
|
+
/**
|
|
20634
|
+
* Call after end execution for live logic.
|
|
20635
|
+
* This function is responsible for triggering the afterEndSubject
|
|
20636
|
+
* with the appropriate context and symbol information.
|
|
20637
|
+
*/
|
|
20638
|
+
const CALL_AFTER_END_FN = trycatch(async (self, symbol, context) => {
|
|
20639
|
+
const when = alignToInterval(new Date(), "1m");
|
|
20640
|
+
await MethodContextService.runInContext(async () => {
|
|
20641
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20642
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20643
|
+
await afterEndSubject.next({
|
|
20644
|
+
symbol,
|
|
20179
20645
|
exchangeName: context.exchangeName,
|
|
20180
20646
|
strategyName: context.strategyName,
|
|
20181
|
-
frameName:
|
|
20647
|
+
frameName: "",
|
|
20648
|
+
backtest: false,
|
|
20649
|
+
currentPrice,
|
|
20650
|
+
when,
|
|
20651
|
+
timestamp: when.getTime(),
|
|
20182
20652
|
});
|
|
20653
|
+
}, {
|
|
20654
|
+
symbol,
|
|
20655
|
+
when,
|
|
20656
|
+
backtest: false,
|
|
20657
|
+
});
|
|
20658
|
+
}, {
|
|
20659
|
+
exchangeName: context.exchangeName,
|
|
20660
|
+
strategyName: context.strategyName,
|
|
20661
|
+
frameName: "",
|
|
20662
|
+
});
|
|
20663
|
+
}, {
|
|
20664
|
+
fallback: (error, self) => {
|
|
20665
|
+
const message = "LiveLogicPublicService CALL_AFTER_END_FN thrown";
|
|
20666
|
+
const payload = {
|
|
20667
|
+
error: errorData(error),
|
|
20668
|
+
message: getErrorMessage(error),
|
|
20183
20669
|
};
|
|
20184
|
-
|
|
20185
|
-
|
|
20186
|
-
|
|
20670
|
+
self.loggerService.warn(message, payload);
|
|
20671
|
+
console.error(message, payload);
|
|
20672
|
+
errorEmitter.next(error);
|
|
20673
|
+
},
|
|
20674
|
+
});
|
|
20187
20675
|
/**
|
|
20188
20676
|
* Public service for live trading orchestration with context management.
|
|
20189
20677
|
*
|
|
@@ -20219,28 +20707,31 @@ class LiveLogicPublicService {
|
|
|
20219
20707
|
constructor() {
|
|
20220
20708
|
this.loggerService = inject(TYPES.loggerService);
|
|
20221
20709
|
this.liveLogicPrivateService = inject(TYPES.liveLogicPrivateService);
|
|
20222
|
-
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20227
|
-
|
|
20228
|
-
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
}
|
|
20710
|
+
this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
|
|
20711
|
+
}
|
|
20712
|
+
/**
|
|
20713
|
+
* Runs live trading for a symbol with context propagation.
|
|
20714
|
+
*
|
|
20715
|
+
* Streams opened and closed signals as infinite async generator.
|
|
20716
|
+
* Context is automatically injected into all framework functions.
|
|
20717
|
+
* Process can crash and restart - state will be recovered from disk.
|
|
20718
|
+
*
|
|
20719
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20720
|
+
* @param context - Execution context with strategy and exchange names
|
|
20721
|
+
* @returns Infinite async generator yielding opened and closed signals
|
|
20722
|
+
*/
|
|
20723
|
+
async *run(symbol, context) {
|
|
20724
|
+
this.loggerService.log("liveLogicPublicService run", {
|
|
20725
|
+
symbol,
|
|
20726
|
+
context,
|
|
20727
|
+
});
|
|
20728
|
+
await CALL_BEFORE_START_FN(this, symbol, context);
|
|
20729
|
+
try {
|
|
20730
|
+
yield* RUN_ITERATOR_FN(this, symbol, context);
|
|
20731
|
+
}
|
|
20732
|
+
finally {
|
|
20733
|
+
await CALL_AFTER_END_FN(this, symbol, context);
|
|
20734
|
+
}
|
|
20244
20735
|
}
|
|
20245
20736
|
}
|
|
20246
20737
|
|
|
@@ -34444,6 +34935,21 @@ class TimeMetaService {
|
|
|
34444
34935
|
* Instances are cached until clear() is called.
|
|
34445
34936
|
*/
|
|
34446
34937
|
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
|
|
34938
|
+
/**
|
|
34939
|
+
* Checks if a timestamp exists for the given symbol and context.
|
|
34940
|
+
*
|
|
34941
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
34942
|
+
* @param context - Strategy, exchange, and frame identifiers
|
|
34943
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
34944
|
+
* @returns True if a timestamp is available, false otherwise
|
|
34945
|
+
*/
|
|
34946
|
+
this.hasTimestamp = (symbol, context, backtest) => {
|
|
34947
|
+
const key = CREATE_KEY_FN$a(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
34948
|
+
if (!this.getSource.has(key)) {
|
|
34949
|
+
return false;
|
|
34950
|
+
}
|
|
34951
|
+
return !!this.getSource.get(key)?.data;
|
|
34952
|
+
};
|
|
34447
34953
|
/**
|
|
34448
34954
|
* Returns the current candle timestamp (in milliseconds) for the given symbol and context.
|
|
34449
34955
|
*
|
|
@@ -36075,6 +36581,7 @@ const Exchange = new ExchangeUtils();
|
|
|
36075
36581
|
|
|
36076
36582
|
const WARM_CANDLES_METHOD_NAME = "cache.warmCandles";
|
|
36077
36583
|
const CHECK_CANDLES_METHOD_NAME = "cache.checkCandles";
|
|
36584
|
+
const CACHE_CANDLES_METHOD_NAME = "cache.cacheCandles";
|
|
36078
36585
|
const MS_PER_MINUTE$3 = 60000;
|
|
36079
36586
|
const INTERVAL_MINUTES$3 = {
|
|
36080
36587
|
"1m": 1,
|
|
@@ -36106,6 +36613,34 @@ const PRINT_PROGRESS_FN = (fetched, total, symbol, interval) => {
|
|
|
36106
36613
|
process.stdout.write("\n");
|
|
36107
36614
|
}
|
|
36108
36615
|
};
|
|
36616
|
+
/**
|
|
36617
|
+
* Retry-wrapped pipeline: validates the cache via `checkCandles` and, on miss,
|
|
36618
|
+
* fills it via `warmCandles` and rethrows to trigger a retry pass that
|
|
36619
|
+
* re-validates the freshly cached range. Limited to 2 attempts.
|
|
36620
|
+
*/
|
|
36621
|
+
const CACHE_CANDLES_FN = retry(async (interval, dto, onWarmStart, onCheckStart) => {
|
|
36622
|
+
try {
|
|
36623
|
+
onCheckStart && onCheckStart(dto.symbol, interval, dto.from, dto.to);
|
|
36624
|
+
await checkCandles({
|
|
36625
|
+
exchangeName: dto.exchangeName,
|
|
36626
|
+
from: dto.from,
|
|
36627
|
+
to: dto.to,
|
|
36628
|
+
symbol: dto.symbol,
|
|
36629
|
+
interval: interval,
|
|
36630
|
+
});
|
|
36631
|
+
}
|
|
36632
|
+
catch (error) {
|
|
36633
|
+
onWarmStart && onWarmStart(dto.symbol, interval, dto.from, dto.to);
|
|
36634
|
+
await warmCandles({
|
|
36635
|
+
symbol: dto.symbol,
|
|
36636
|
+
exchangeName: dto.exchangeName,
|
|
36637
|
+
from: dto.from,
|
|
36638
|
+
to: dto.to,
|
|
36639
|
+
interval: interval,
|
|
36640
|
+
});
|
|
36641
|
+
throw error;
|
|
36642
|
+
}
|
|
36643
|
+
}, 2);
|
|
36109
36644
|
/**
|
|
36110
36645
|
* Checks cached candle presence via the persist adapter.
|
|
36111
36646
|
* Issues one ranged read; adapter-side `hasValue` covers each expected timestamp,
|
|
@@ -36181,6 +36716,34 @@ async function warmCandles(params) {
|
|
|
36181
36716
|
PRINT_PROGRESS_FN(fetched, totalCandles, symbol, interval);
|
|
36182
36717
|
}
|
|
36183
36718
|
}
|
|
36719
|
+
/**
|
|
36720
|
+
* Ensures candles for the given range are present in persist storage.
|
|
36721
|
+
* Runs a check-then-warm pipeline with one retry: validates the cache first
|
|
36722
|
+
* and, on a miss, downloads the missing data and re-validates.
|
|
36723
|
+
*
|
|
36724
|
+
* @param params - Combined cache parameters with optional lifecycle callbacks
|
|
36725
|
+
*/
|
|
36726
|
+
async function cacheCandles({ symbol, interval, from, to, exchangeName, onCheckStart = (symbol, interval, from, to) => {
|
|
36727
|
+
process.stdout.write("\n");
|
|
36728
|
+
process.stdout.write(`Checking candles cache for ${symbol} ${interval} from ${from} to ${to}\n`);
|
|
36729
|
+
}, onWarmStart = (symbol, interval, from, to) => {
|
|
36730
|
+
process.stdout.write("\n\n");
|
|
36731
|
+
process.stdout.write(`Caching candles for ${symbol} ${interval} from ${from} to ${to}\n`);
|
|
36732
|
+
}, }) {
|
|
36733
|
+
backtest.loggerService.info(CACHE_CANDLES_METHOD_NAME, {
|
|
36734
|
+
symbol,
|
|
36735
|
+
exchangeName,
|
|
36736
|
+
interval,
|
|
36737
|
+
from,
|
|
36738
|
+
to,
|
|
36739
|
+
});
|
|
36740
|
+
await CACHE_CANDLES_FN(interval, {
|
|
36741
|
+
exchangeName,
|
|
36742
|
+
from,
|
|
36743
|
+
to,
|
|
36744
|
+
symbol,
|
|
36745
|
+
}, onWarmStart, onCheckStart);
|
|
36746
|
+
}
|
|
36184
36747
|
|
|
36185
36748
|
const METHOD_NAME = "validate.validate";
|
|
36186
36749
|
/**
|
|
@@ -36600,11 +37163,6 @@ const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
|
36600
37163
|
const GET_CLOSE_PRICE_METHOD_NAME = "exchange.getClosePrice";
|
|
36601
37164
|
const FORMAT_PRICE_METHOD_NAME = "exchange.formatPrice";
|
|
36602
37165
|
const FORMAT_QUANTITY_METHOD_NAME = "exchange.formatQuantity";
|
|
36603
|
-
const GET_DATE_METHOD_NAME = "exchange.getDate";
|
|
36604
|
-
const GET_TIMESTAMP_METHOD_NAME = "exchange.getTimestamp";
|
|
36605
|
-
const GET_MODE_METHOD_NAME = "exchange.getMode";
|
|
36606
|
-
const GET_SYMBOL_METHOD_NAME = "exchange.getSymbol";
|
|
36607
|
-
const GET_CONTEXT_METHOD_NAME = "exchange.getContext";
|
|
36608
37166
|
const HAS_TRADE_CONTEXT_METHOD_NAME = "exchange.hasTradeContext";
|
|
36609
37167
|
const GET_ORDER_BOOK_METHOD_NAME = "exchange.getOrderBook";
|
|
36610
37168
|
const GET_RAW_CANDLES_METHOD_NAME = "exchange.getRawCandles";
|
|
@@ -36771,113 +37329,6 @@ async function formatQuantity(symbol, quantity) {
|
|
|
36771
37329
|
}
|
|
36772
37330
|
return await backtest.exchangeConnectionService.formatQuantity(symbol, quantity);
|
|
36773
37331
|
}
|
|
36774
|
-
/**
|
|
36775
|
-
* Gets the current date from execution context.
|
|
36776
|
-
*
|
|
36777
|
-
* In backtest mode: returns the current timeframe date being processed
|
|
36778
|
-
* In live mode: returns current real-time date
|
|
36779
|
-
*
|
|
36780
|
-
* @returns Promise resolving to current execution context date
|
|
36781
|
-
*
|
|
36782
|
-
* @example
|
|
36783
|
-
* ```typescript
|
|
36784
|
-
* const date = await getDate();
|
|
36785
|
-
* console.log(date); // 2024-01-01T12:00:00.000Z
|
|
36786
|
-
* ```
|
|
36787
|
-
*/
|
|
36788
|
-
async function getDate() {
|
|
36789
|
-
backtest.loggerService.info(GET_DATE_METHOD_NAME);
|
|
36790
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36791
|
-
throw new Error("getDate requires an execution context");
|
|
36792
|
-
}
|
|
36793
|
-
const { when } = backtest.executionContextService.context;
|
|
36794
|
-
return new Date(when.getTime());
|
|
36795
|
-
}
|
|
36796
|
-
/**
|
|
36797
|
-
* Gets the current timestamp from execution context.
|
|
36798
|
-
*
|
|
36799
|
-
* In backtest mode: returns the current timeframe timestamp being processed
|
|
36800
|
-
* In live mode: returns current real-time timestamp
|
|
36801
|
-
*
|
|
36802
|
-
* @returns Promise resolving to current execution context timestamp in milliseconds
|
|
36803
|
-
* @example
|
|
36804
|
-
* ```typescript
|
|
36805
|
-
* const timestamp = await getTimestamp();
|
|
36806
|
-
* console.log(timestamp); // 1700000000000
|
|
36807
|
-
* ```
|
|
36808
|
-
*/
|
|
36809
|
-
async function getTimestamp() {
|
|
36810
|
-
backtest.loggerService.info(GET_TIMESTAMP_METHOD_NAME);
|
|
36811
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36812
|
-
throw new Error("getTimestamp requires an execution context");
|
|
36813
|
-
}
|
|
36814
|
-
return getContextTimestamp();
|
|
36815
|
-
}
|
|
36816
|
-
/**
|
|
36817
|
-
* Gets the current execution mode.
|
|
36818
|
-
*
|
|
36819
|
-
* @returns Promise resolving to "backtest" or "live"
|
|
36820
|
-
*
|
|
36821
|
-
* @example
|
|
36822
|
-
* ```typescript
|
|
36823
|
-
* const mode = await getMode();
|
|
36824
|
-
* if (mode === "backtest") {
|
|
36825
|
-
* console.log("Running in backtest mode");
|
|
36826
|
-
* } else {
|
|
36827
|
-
* console.log("Running in live mode");
|
|
36828
|
-
* }
|
|
36829
|
-
* ```
|
|
36830
|
-
*/
|
|
36831
|
-
async function getMode() {
|
|
36832
|
-
backtest.loggerService.info(GET_MODE_METHOD_NAME);
|
|
36833
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36834
|
-
throw new Error("getMode requires an execution context");
|
|
36835
|
-
}
|
|
36836
|
-
const { backtest: bt } = backtest.executionContextService.context;
|
|
36837
|
-
return bt ? "backtest" : "live";
|
|
36838
|
-
}
|
|
36839
|
-
/**
|
|
36840
|
-
* Gets the current trading symbol from execution context.
|
|
36841
|
-
*
|
|
36842
|
-
* @returns Promise resolving to the current trading symbol (e.g., "BTCUSDT")
|
|
36843
|
-
* @throws Error if execution context is not active
|
|
36844
|
-
*
|
|
36845
|
-
* @example
|
|
36846
|
-
* ```typescript
|
|
36847
|
-
* const symbol = await getSymbol();
|
|
36848
|
-
* console.log(symbol); // "BTCUSDT"
|
|
36849
|
-
* ```
|
|
36850
|
-
*/
|
|
36851
|
-
async function getSymbol() {
|
|
36852
|
-
backtest.loggerService.info(GET_SYMBOL_METHOD_NAME);
|
|
36853
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36854
|
-
throw new Error("getSymbol requires an execution context");
|
|
36855
|
-
}
|
|
36856
|
-
const { symbol } = backtest.executionContextService.context;
|
|
36857
|
-
return symbol;
|
|
36858
|
-
}
|
|
36859
|
-
/**
|
|
36860
|
-
* Gets the current method context.
|
|
36861
|
-
*
|
|
36862
|
-
* Returns the context object from the method context service, which contains
|
|
36863
|
-
* information about the current method execution environment.
|
|
36864
|
-
*
|
|
36865
|
-
* @returns Promise resolving to the current method context object
|
|
36866
|
-
* @throws Error if method context is not active
|
|
36867
|
-
*
|
|
36868
|
-
* @example
|
|
36869
|
-
* ```typescript
|
|
36870
|
-
* const context = await getContext();
|
|
36871
|
-
* console.log(context); // { ...method context data... }
|
|
36872
|
-
* ```
|
|
36873
|
-
*/
|
|
36874
|
-
async function getContext() {
|
|
36875
|
-
backtest.loggerService.info(GET_CONTEXT_METHOD_NAME);
|
|
36876
|
-
if (!MethodContextService.hasContext()) {
|
|
36877
|
-
throw new Error("getContext requires a method context");
|
|
36878
|
-
}
|
|
36879
|
-
return backtest.methodContextService.context;
|
|
36880
|
-
}
|
|
36881
37332
|
/**
|
|
36882
37333
|
* Fetches order book for a trading pair from the registered exchange.
|
|
36883
37334
|
*
|
|
@@ -40418,6 +40869,10 @@ const LISTEN_MAX_DRAWDOWN_METHOD_NAME = "event.listenMaxDrawdown";
|
|
|
40418
40869
|
const LISTEN_MAX_DRAWDOWN_ONCE_METHOD_NAME = "event.listenMaxDrawdownOnce";
|
|
40419
40870
|
const LISTEN_SIGNAL_NOTIFY_METHOD_NAME = "event.listenSignalNotify";
|
|
40420
40871
|
const LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME = "event.listenSignalNotifyOnce";
|
|
40872
|
+
const LISTEN_BEFORE_START_METHOD_NAME = "event.listenBeforeStart";
|
|
40873
|
+
const LISTEN_BEFORE_START_ONCE_METHOD_NAME = "event.listenBeforeStartOnce";
|
|
40874
|
+
const LISTEN_AFTER_END_METHOD_NAME = "event.listenAfterEnd";
|
|
40875
|
+
const LISTEN_AFTER_END_ONCE_METHOD_NAME = "event.listenAfterEndOnce";
|
|
40421
40876
|
/**
|
|
40422
40877
|
* Subscribes to all signal events with queued async processing.
|
|
40423
40878
|
*
|
|
@@ -41888,6 +42343,68 @@ function listenSignalNotifyOnce(filterFn, fn) {
|
|
|
41888
42343
|
};
|
|
41889
42344
|
return disposeFn = listenSignalNotify(wrappedFn);
|
|
41890
42345
|
}
|
|
42346
|
+
/**
|
|
42347
|
+
* Subscribes to before start events with queued async processing.
|
|
42348
|
+
* Emits when the engine is about to start a new strategy execution for a symbol.
|
|
42349
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
42350
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
42351
|
+
* @param fn - Callback function to handle before start events
|
|
42352
|
+
* @return Unsubscribe function to stop listening to events
|
|
42353
|
+
*/
|
|
42354
|
+
function listenBeforeStart(fn) {
|
|
42355
|
+
backtest.loggerService.log(LISTEN_BEFORE_START_METHOD_NAME);
|
|
42356
|
+
return beforeStartSubject.subscribe(queued(async (event) => fn(event)));
|
|
42357
|
+
}
|
|
42358
|
+
/**
|
|
42359
|
+
* Subscribes to filtered before start events with one-time execution.
|
|
42360
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
42361
|
+
* and automatically unsubscribes.
|
|
42362
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
42363
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
42364
|
+
* @return Unsubscribe function to cancel the listener before it fires
|
|
42365
|
+
*/
|
|
42366
|
+
function listenBeforeStartOnce(filterFn, fn) {
|
|
42367
|
+
backtest.loggerService.log(LISTEN_BEFORE_START_ONCE_METHOD_NAME);
|
|
42368
|
+
let disposeFn;
|
|
42369
|
+
const wrappedFn = async (event) => {
|
|
42370
|
+
if (filterFn(event)) {
|
|
42371
|
+
await fn(event);
|
|
42372
|
+
disposeFn && disposeFn();
|
|
42373
|
+
}
|
|
42374
|
+
};
|
|
42375
|
+
return disposeFn = listenBeforeStart(wrappedFn);
|
|
42376
|
+
}
|
|
42377
|
+
/**
|
|
42378
|
+
* Subscribes to after end events with queued async processing.
|
|
42379
|
+
* Emits when the engine has completed processing a strategy execution for a symbol.
|
|
42380
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
42381
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
42382
|
+
* @param fn - Callback function to handle after end events
|
|
42383
|
+
* @return Unsubscribe function to stop listening to events
|
|
42384
|
+
*/
|
|
42385
|
+
function listenAfterEnd(fn) {
|
|
42386
|
+
backtest.loggerService.log(LISTEN_AFTER_END_METHOD_NAME);
|
|
42387
|
+
return afterEndSubject.subscribe(queued(async (event) => fn(event)));
|
|
42388
|
+
}
|
|
42389
|
+
/**
|
|
42390
|
+
* Subscribes to filtered after end events with one-time execution.
|
|
42391
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
42392
|
+
* and automatically unsubscribes.
|
|
42393
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
42394
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
42395
|
+
* @return Unsubscribe function to cancel the listener before it fires
|
|
42396
|
+
*/
|
|
42397
|
+
function listenAfterEndOnce(filterFn, fn) {
|
|
42398
|
+
backtest.loggerService.log(LISTEN_AFTER_END_ONCE_METHOD_NAME);
|
|
42399
|
+
let disposeFn;
|
|
42400
|
+
const wrappedFn = async (event) => {
|
|
42401
|
+
if (filterFn(event)) {
|
|
42402
|
+
await fn(event);
|
|
42403
|
+
disposeFn && disposeFn();
|
|
42404
|
+
}
|
|
42405
|
+
};
|
|
42406
|
+
return disposeFn = listenAfterEnd(wrappedFn);
|
|
42407
|
+
}
|
|
41891
42408
|
|
|
41892
42409
|
const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
|
|
41893
42410
|
const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
|
|
@@ -41966,11 +42483,21 @@ const INSTANCE_TASK_FN$2 = async (symbol, context, self) => {
|
|
|
41966
42483
|
self._isStopped = false;
|
|
41967
42484
|
self._isDone = false;
|
|
41968
42485
|
}
|
|
42486
|
+
Lookup.addActivity({
|
|
42487
|
+
symbol,
|
|
42488
|
+
context,
|
|
42489
|
+
backtest: true,
|
|
42490
|
+
});
|
|
41969
42491
|
for await (const _ of self.run(symbol, context)) {
|
|
41970
42492
|
if (self._isStopped) {
|
|
41971
42493
|
break;
|
|
41972
42494
|
}
|
|
41973
42495
|
}
|
|
42496
|
+
Lookup.removeActivity({
|
|
42497
|
+
symbol,
|
|
42498
|
+
context,
|
|
42499
|
+
backtest: true,
|
|
42500
|
+
});
|
|
41974
42501
|
if (!self._isDone) {
|
|
41975
42502
|
await doneBacktestSubject.next({
|
|
41976
42503
|
exchangeName: context.exchangeName,
|
|
@@ -44617,11 +45144,21 @@ const INSTANCE_TASK_FN$1 = async (symbol, context, self) => {
|
|
|
44617
45144
|
self._isStopped = false;
|
|
44618
45145
|
self._isDone = false;
|
|
44619
45146
|
}
|
|
45147
|
+
Lookup.addActivity({
|
|
45148
|
+
symbol,
|
|
45149
|
+
context,
|
|
45150
|
+
backtest: false,
|
|
45151
|
+
});
|
|
44620
45152
|
for await (const signal of self.run(symbol, context)) {
|
|
44621
45153
|
if (signal?.action === "closed" && self._isStopped) {
|
|
44622
45154
|
break;
|
|
44623
45155
|
}
|
|
44624
45156
|
}
|
|
45157
|
+
Lookup.removeActivity({
|
|
45158
|
+
symbol,
|
|
45159
|
+
context,
|
|
45160
|
+
backtest: false,
|
|
45161
|
+
});
|
|
44625
45162
|
if (!self._isDone) {
|
|
44626
45163
|
await doneLiveSubject.next({
|
|
44627
45164
|
exchangeName: context.exchangeName,
|
|
@@ -48556,6 +49093,128 @@ async function listRiskSchema() {
|
|
|
48556
49093
|
return await backtest.riskValidationService.list();
|
|
48557
49094
|
}
|
|
48558
49095
|
|
|
49096
|
+
const GET_DATE_METHOD_NAME = "meta.getDate";
|
|
49097
|
+
const GET_TIMESTAMP_METHOD_NAME = "meta.getTimestamp";
|
|
49098
|
+
const GET_MODE_METHOD_NAME = "meta.getMode";
|
|
49099
|
+
const GET_SYMBOL_METHOD_NAME = "meta.getSymbol";
|
|
49100
|
+
const GET_CONTEXT_METHOD_NAME = "meta.getContext";
|
|
49101
|
+
/**
|
|
49102
|
+
* Gets the current date from execution context.
|
|
49103
|
+
*
|
|
49104
|
+
* In backtest mode: returns the current timeframe date being processed
|
|
49105
|
+
* In live mode: returns current real-time date
|
|
49106
|
+
*
|
|
49107
|
+
* @returns Promise resolving to current execution context date
|
|
49108
|
+
*
|
|
49109
|
+
* @example
|
|
49110
|
+
* ```typescript
|
|
49111
|
+
* const date = await getDate();
|
|
49112
|
+
* console.log(date); // 2024-01-01T12:00:00.000Z
|
|
49113
|
+
* ```
|
|
49114
|
+
*/
|
|
49115
|
+
async function getDate() {
|
|
49116
|
+
backtest.loggerService.info(GET_DATE_METHOD_NAME);
|
|
49117
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49118
|
+
throw new Error("getDate requires an execution context");
|
|
49119
|
+
}
|
|
49120
|
+
const { when } = backtest.executionContextService.context;
|
|
49121
|
+
return new Date(when.getTime());
|
|
49122
|
+
}
|
|
49123
|
+
/**
|
|
49124
|
+
* Gets the current timestamp from execution context.
|
|
49125
|
+
*
|
|
49126
|
+
* In backtest mode: returns the current timeframe timestamp being processed
|
|
49127
|
+
* In live mode: returns current real-time timestamp
|
|
49128
|
+
*
|
|
49129
|
+
* @returns Promise resolving to current execution context timestamp in milliseconds
|
|
49130
|
+
* @example
|
|
49131
|
+
* ```typescript
|
|
49132
|
+
* const timestamp = await getTimestamp();
|
|
49133
|
+
* console.log(timestamp); // 1700000000000
|
|
49134
|
+
* ```
|
|
49135
|
+
*/
|
|
49136
|
+
async function getTimestamp() {
|
|
49137
|
+
backtest.loggerService.info(GET_TIMESTAMP_METHOD_NAME);
|
|
49138
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49139
|
+
throw new Error("getTimestamp requires an execution context");
|
|
49140
|
+
}
|
|
49141
|
+
if (!MethodContextService.hasContext()) {
|
|
49142
|
+
throw new Error("getTimestamp requires a method context");
|
|
49143
|
+
}
|
|
49144
|
+
const { symbol, backtest: isBacktest } = backtest.executionContextService.context;
|
|
49145
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
49146
|
+
return backtest.timeMetaService.getTimestamp(symbol, {
|
|
49147
|
+
exchangeName,
|
|
49148
|
+
frameName,
|
|
49149
|
+
strategyName,
|
|
49150
|
+
}, isBacktest);
|
|
49151
|
+
}
|
|
49152
|
+
/**
|
|
49153
|
+
* Gets the current execution mode.
|
|
49154
|
+
*
|
|
49155
|
+
* @returns Promise resolving to "backtest" or "live"
|
|
49156
|
+
*
|
|
49157
|
+
* @example
|
|
49158
|
+
* ```typescript
|
|
49159
|
+
* const mode = await getMode();
|
|
49160
|
+
* if (mode === "backtest") {
|
|
49161
|
+
* console.log("Running in backtest mode");
|
|
49162
|
+
* } else {
|
|
49163
|
+
* console.log("Running in live mode");
|
|
49164
|
+
* }
|
|
49165
|
+
* ```
|
|
49166
|
+
*/
|
|
49167
|
+
async function getMode() {
|
|
49168
|
+
backtest.loggerService.info(GET_MODE_METHOD_NAME);
|
|
49169
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49170
|
+
throw new Error("getMode requires an execution context");
|
|
49171
|
+
}
|
|
49172
|
+
const { backtest: bt } = backtest.executionContextService.context;
|
|
49173
|
+
return bt ? "backtest" : "live";
|
|
49174
|
+
}
|
|
49175
|
+
/**
|
|
49176
|
+
* Gets the current trading symbol from execution context.
|
|
49177
|
+
*
|
|
49178
|
+
* @returns Promise resolving to the current trading symbol (e.g., "BTCUSDT")
|
|
49179
|
+
* @throws Error if execution context is not active
|
|
49180
|
+
*
|
|
49181
|
+
* @example
|
|
49182
|
+
* ```typescript
|
|
49183
|
+
* const symbol = await getSymbol();
|
|
49184
|
+
* console.log(symbol); // "BTCUSDT"
|
|
49185
|
+
* ```
|
|
49186
|
+
*/
|
|
49187
|
+
async function getSymbol() {
|
|
49188
|
+
backtest.loggerService.info(GET_SYMBOL_METHOD_NAME);
|
|
49189
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49190
|
+
throw new Error("getSymbol requires an execution context");
|
|
49191
|
+
}
|
|
49192
|
+
const { symbol } = backtest.executionContextService.context;
|
|
49193
|
+
return symbol;
|
|
49194
|
+
}
|
|
49195
|
+
/**
|
|
49196
|
+
* Gets the current method context.
|
|
49197
|
+
*
|
|
49198
|
+
* Returns the context object from the method context service, which contains
|
|
49199
|
+
* information about the current method execution environment.
|
|
49200
|
+
*
|
|
49201
|
+
* @returns Promise resolving to the current method context object
|
|
49202
|
+
* @throws Error if method context is not active
|
|
49203
|
+
*
|
|
49204
|
+
* @example
|
|
49205
|
+
* ```typescript
|
|
49206
|
+
* const context = await getContext();
|
|
49207
|
+
* console.log(context); // { ...method context data... }
|
|
49208
|
+
* ```
|
|
49209
|
+
*/
|
|
49210
|
+
async function getContext() {
|
|
49211
|
+
backtest.loggerService.info(GET_CONTEXT_METHOD_NAME);
|
|
49212
|
+
if (!MethodContextService.hasContext()) {
|
|
49213
|
+
throw new Error("getContext requires a method context");
|
|
49214
|
+
}
|
|
49215
|
+
return backtest.methodContextService.context;
|
|
49216
|
+
}
|
|
49217
|
+
|
|
48559
49218
|
const RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistBacktestUtils.handleActivePing";
|
|
48560
49219
|
const RECENT_PERSIST_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL = "RecentPersistBacktestUtils.getLatestSignal";
|
|
48561
49220
|
const RECENT_PERSIST_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistLiveUtils.handleActivePing";
|
|
@@ -54600,6 +55259,8 @@ const SUBJECT_ISOLATION_LIST = [
|
|
|
54600
55259
|
syncSubject,
|
|
54601
55260
|
validationSubject,
|
|
54602
55261
|
signalNotifySubject,
|
|
55262
|
+
beforeStartSubject,
|
|
55263
|
+
afterEndSubject
|
|
54603
55264
|
];
|
|
54604
55265
|
/**
|
|
54605
55266
|
* Creates a snapshot function for a given subject by clearing its internal
|
|
@@ -63732,4 +64393,4 @@ const validateSignal = (signal, currentPrice) => {
|
|
|
63732
64393
|
return !errors.length;
|
|
63733
64394
|
};
|
|
63734
64395
|
|
|
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 };
|
|
64396
|
+
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, listenAfterEnd, listenAfterEndOnce, listenBacktestProgress, listenBeforeStart, listenBeforeStartOnce, 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 };
|