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.cjs
CHANGED
|
@@ -574,6 +574,22 @@ const GLOBAL_CONFIG = {
|
|
|
574
574
|
* Default: true (mutex locking enabled for candle fetching)
|
|
575
575
|
*/
|
|
576
576
|
CC_ENABLE_CANDLE_FETCH_MUTEX: true,
|
|
577
|
+
/**
|
|
578
|
+
* Enables cooperative interleaving of concurrently running backtests after each candle fetch.
|
|
579
|
+
*
|
|
580
|
+
* Mechanism (implemented in `Candle.spinLock`):
|
|
581
|
+
* - After `getNextCandles` resolves, the current backtest awaits
|
|
582
|
+
* `Promise.race([_spin.toPromise(), sleep(50)])`, where `_spin` is emitted whenever
|
|
583
|
+
* another caller acquires the candle-fetch mutex.
|
|
584
|
+
* - This hands the event loop to a peer backtest waiting on the same mutex, so multiple
|
|
585
|
+
* parallel `Backtest.run` / `Walker` workloads progress in round-robin fashion instead
|
|
586
|
+
* of one monopolizing the event loop until completion.
|
|
587
|
+
* - The spin is skipped entirely when `Lookup.isParallel` is `false` (single active workload —
|
|
588
|
+
* no peer to yield to) or when `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled.
|
|
589
|
+
*
|
|
590
|
+
* Default: true (parallel backtests are interleaved on each candle fetch boundary)
|
|
591
|
+
*/
|
|
592
|
+
CC_ENABLE_BACKTEST_PARALLEL_SPIN: true,
|
|
577
593
|
/**
|
|
578
594
|
* Enables DCA (Dollar-Cost Averaging) logic even if antirecord is not broken.
|
|
579
595
|
* Allows to commitAverageBuy if currentPrice is not the lowest price since entry, but still lower than priceOpen.
|
|
@@ -792,11 +808,23 @@ const maxDrawdownSubject = new functoolsKit.Subject();
|
|
|
792
808
|
* Emits when a strategy calls commitSignalInfo() to broadcast a custom annotation.
|
|
793
809
|
*/
|
|
794
810
|
const signalNotifySubject = new functoolsKit.Subject();
|
|
811
|
+
/**
|
|
812
|
+
* Before start emitter for strategy initialization events.
|
|
813
|
+
* Emits when the engine is about to start a new strategy execution.
|
|
814
|
+
*/
|
|
815
|
+
const beforeStartSubject = new functoolsKit.Subject();
|
|
816
|
+
/**
|
|
817
|
+
* After end emitter for strategy completion events.
|
|
818
|
+
* Emits when the engine has completed processing a signal.
|
|
819
|
+
*/
|
|
820
|
+
const afterEndSubject = new functoolsKit.Subject();
|
|
795
821
|
|
|
796
822
|
var emitters = /*#__PURE__*/Object.freeze({
|
|
797
823
|
__proto__: null,
|
|
798
824
|
activePingSubject: activePingSubject,
|
|
825
|
+
afterEndSubject: afterEndSubject,
|
|
799
826
|
backtestScheduleOpenSubject: backtestScheduleOpenSubject,
|
|
827
|
+
beforeStartSubject: beforeStartSubject,
|
|
800
828
|
breakevenSubject: breakevenSubject,
|
|
801
829
|
doneBacktestSubject: doneBacktestSubject,
|
|
802
830
|
doneLiveSubject: doneLiveSubject,
|
|
@@ -934,7 +962,7 @@ async function writeFileAtomic(file, data, options = {}) {
|
|
|
934
962
|
|
|
935
963
|
var _a$3;
|
|
936
964
|
/** Logger service injected as DI singleton */
|
|
937
|
-
const LOGGER_SERVICE$
|
|
965
|
+
const LOGGER_SERVICE$8 = new LoggerService();
|
|
938
966
|
/** Symbol key for the singleshot waitForInit function on PersistBase instances. */
|
|
939
967
|
const BASE_WAIT_FOR_INIT_SYMBOL = Symbol("wait-for-init");
|
|
940
968
|
// Calculate step in milliseconds for candle close time validation
|
|
@@ -1057,7 +1085,7 @@ const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
|
|
|
1057
1085
|
const BASE_UNLINK_RETRY_COUNT = 5;
|
|
1058
1086
|
const BASE_UNLINK_RETRY_DELAY = 1000;
|
|
1059
1087
|
const BASE_WAIT_FOR_INIT_FN = async (self) => {
|
|
1060
|
-
LOGGER_SERVICE$
|
|
1088
|
+
LOGGER_SERVICE$8.debug(BASE_WAIT_FOR_INIT_FN_METHOD_NAME, {
|
|
1061
1089
|
entityName: self.entityName,
|
|
1062
1090
|
directory: self._directory,
|
|
1063
1091
|
});
|
|
@@ -1115,7 +1143,7 @@ class PersistBase {
|
|
|
1115
1143
|
this.entityName = entityName;
|
|
1116
1144
|
this.baseDir = baseDir;
|
|
1117
1145
|
this[_a$3] = functoolsKit.singleshot(async () => await BASE_WAIT_FOR_INIT_FN(this));
|
|
1118
|
-
LOGGER_SERVICE$
|
|
1146
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_CTOR, {
|
|
1119
1147
|
entityName: this.entityName,
|
|
1120
1148
|
baseDir,
|
|
1121
1149
|
});
|
|
@@ -1131,14 +1159,14 @@ class PersistBase {
|
|
|
1131
1159
|
return path.join(this.baseDir, this.entityName, `${entityId}.json`);
|
|
1132
1160
|
}
|
|
1133
1161
|
async waitForInit(initial) {
|
|
1134
|
-
LOGGER_SERVICE$
|
|
1162
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WAIT_FOR_INIT, {
|
|
1135
1163
|
entityName: this.entityName,
|
|
1136
1164
|
initial,
|
|
1137
1165
|
});
|
|
1138
1166
|
await this[BASE_WAIT_FOR_INIT_SYMBOL]();
|
|
1139
1167
|
}
|
|
1140
1168
|
async readValue(entityId) {
|
|
1141
|
-
LOGGER_SERVICE$
|
|
1169
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_READ_VALUE, {
|
|
1142
1170
|
entityName: this.entityName,
|
|
1143
1171
|
entityId,
|
|
1144
1172
|
});
|
|
@@ -1155,7 +1183,7 @@ class PersistBase {
|
|
|
1155
1183
|
}
|
|
1156
1184
|
}
|
|
1157
1185
|
async hasValue(entityId) {
|
|
1158
|
-
LOGGER_SERVICE$
|
|
1186
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_HAS_VALUE, {
|
|
1159
1187
|
entityName: this.entityName,
|
|
1160
1188
|
entityId,
|
|
1161
1189
|
});
|
|
@@ -1172,7 +1200,7 @@ class PersistBase {
|
|
|
1172
1200
|
}
|
|
1173
1201
|
}
|
|
1174
1202
|
async writeValue(entityId, entity) {
|
|
1175
|
-
LOGGER_SERVICE$
|
|
1203
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_WRITE_VALUE, {
|
|
1176
1204
|
entityName: this.entityName,
|
|
1177
1205
|
entityId,
|
|
1178
1206
|
});
|
|
@@ -1194,7 +1222,7 @@ class PersistBase {
|
|
|
1194
1222
|
* @throws Error if reading fails
|
|
1195
1223
|
*/
|
|
1196
1224
|
async *keys() {
|
|
1197
|
-
LOGGER_SERVICE$
|
|
1225
|
+
LOGGER_SERVICE$8.debug(PERSIST_BASE_METHOD_NAME_KEYS, {
|
|
1198
1226
|
entityName: this.entityName,
|
|
1199
1227
|
});
|
|
1200
1228
|
try {
|
|
@@ -1339,7 +1367,7 @@ class PersistSignalUtils {
|
|
|
1339
1367
|
* @returns Promise resolving to signal or null if none persisted
|
|
1340
1368
|
*/
|
|
1341
1369
|
this.readSignalData = async (symbol, strategyName, exchangeName) => {
|
|
1342
|
-
LOGGER_SERVICE$
|
|
1370
|
+
LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
|
|
1343
1371
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1344
1372
|
const isInitial = !this.getStorage.has(key);
|
|
1345
1373
|
const instance = this.getStorage(symbol, strategyName, exchangeName);
|
|
@@ -1357,7 +1385,7 @@ class PersistSignalUtils {
|
|
|
1357
1385
|
* @returns Promise that resolves when write is complete
|
|
1358
1386
|
*/
|
|
1359
1387
|
this.writeSignalData = async (signalRow, symbol, strategyName, exchangeName) => {
|
|
1360
|
-
LOGGER_SERVICE$
|
|
1388
|
+
LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1361
1389
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1362
1390
|
const isInitial = !this.getStorage.has(key);
|
|
1363
1391
|
const instance = this.getStorage(symbol, strategyName, exchangeName);
|
|
@@ -1372,7 +1400,7 @@ class PersistSignalUtils {
|
|
|
1372
1400
|
* @param Ctor - Custom IPersistSignalInstance constructor
|
|
1373
1401
|
*/
|
|
1374
1402
|
usePersistSignalAdapter(Ctor) {
|
|
1375
|
-
LOGGER_SERVICE$
|
|
1403
|
+
LOGGER_SERVICE$8.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_PERSIST_SIGNAL_ADAPTER);
|
|
1376
1404
|
this.PersistSignalInstanceCtor = Ctor;
|
|
1377
1405
|
this.getStorage.clear();
|
|
1378
1406
|
}
|
|
@@ -1381,21 +1409,21 @@ class PersistSignalUtils {
|
|
|
1381
1409
|
* Call when process.cwd() changes between strategy iterations.
|
|
1382
1410
|
*/
|
|
1383
1411
|
clear() {
|
|
1384
|
-
LOGGER_SERVICE$
|
|
1412
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_CLEAR);
|
|
1385
1413
|
this.getStorage.clear();
|
|
1386
1414
|
}
|
|
1387
1415
|
/**
|
|
1388
1416
|
* Switches to the default file-based PersistSignalInstance.
|
|
1389
1417
|
*/
|
|
1390
1418
|
useJson() {
|
|
1391
|
-
LOGGER_SERVICE$
|
|
1419
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
|
|
1392
1420
|
this.usePersistSignalAdapter(PersistSignalInstance);
|
|
1393
1421
|
}
|
|
1394
1422
|
/**
|
|
1395
1423
|
* Switches to PersistSignalDummyInstance (all operations are no-ops).
|
|
1396
1424
|
*/
|
|
1397
1425
|
useDummy() {
|
|
1398
|
-
LOGGER_SERVICE$
|
|
1426
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1399
1427
|
this.usePersistSignalAdapter(PersistSignalDummyInstance);
|
|
1400
1428
|
}
|
|
1401
1429
|
}
|
|
@@ -1535,7 +1563,7 @@ class PersistRiskUtils {
|
|
|
1535
1563
|
* @returns Promise resolving to position entries (empty array if none)
|
|
1536
1564
|
*/
|
|
1537
1565
|
this.readPositionData = async (riskName, exchangeName, when) => {
|
|
1538
|
-
LOGGER_SERVICE$
|
|
1566
|
+
LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
|
|
1539
1567
|
const key = `${riskName}:${exchangeName}`;
|
|
1540
1568
|
const isInitial = !this.getRiskStorage.has(key);
|
|
1541
1569
|
const instance = this.getRiskStorage(riskName, exchangeName);
|
|
@@ -1553,7 +1581,7 @@ class PersistRiskUtils {
|
|
|
1553
1581
|
* @returns Promise that resolves when write is complete
|
|
1554
1582
|
*/
|
|
1555
1583
|
this.writePositionData = async (riskRow, riskName, exchangeName, when) => {
|
|
1556
|
-
LOGGER_SERVICE$
|
|
1584
|
+
LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1557
1585
|
const key = `${riskName}:${exchangeName}`;
|
|
1558
1586
|
const isInitial = !this.getRiskStorage.has(key);
|
|
1559
1587
|
const instance = this.getRiskStorage(riskName, exchangeName);
|
|
@@ -1568,7 +1596,7 @@ class PersistRiskUtils {
|
|
|
1568
1596
|
* @param Ctor - Custom IPersistRiskInstance constructor
|
|
1569
1597
|
*/
|
|
1570
1598
|
usePersistRiskAdapter(Ctor) {
|
|
1571
|
-
LOGGER_SERVICE$
|
|
1599
|
+
LOGGER_SERVICE$8.info(PERSIST_RISK_UTILS_METHOD_NAME_USE_PERSIST_RISK_ADAPTER);
|
|
1572
1600
|
this.PersistRiskInstanceCtor = Ctor;
|
|
1573
1601
|
this.getRiskStorage.clear();
|
|
1574
1602
|
}
|
|
@@ -1577,21 +1605,21 @@ class PersistRiskUtils {
|
|
|
1577
1605
|
* Call when process.cwd() changes between strategy iterations.
|
|
1578
1606
|
*/
|
|
1579
1607
|
clear() {
|
|
1580
|
-
LOGGER_SERVICE$
|
|
1608
|
+
LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_CLEAR);
|
|
1581
1609
|
this.getRiskStorage.clear();
|
|
1582
1610
|
}
|
|
1583
1611
|
/**
|
|
1584
1612
|
* Switches to the default file-based PersistRiskInstance.
|
|
1585
1613
|
*/
|
|
1586
1614
|
useJson() {
|
|
1587
|
-
LOGGER_SERVICE$
|
|
1615
|
+
LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_JSON);
|
|
1588
1616
|
this.usePersistRiskAdapter(PersistRiskInstance);
|
|
1589
1617
|
}
|
|
1590
1618
|
/**
|
|
1591
1619
|
* Switches to PersistRiskDummyInstance (all operations are no-ops).
|
|
1592
1620
|
*/
|
|
1593
1621
|
useDummy() {
|
|
1594
|
-
LOGGER_SERVICE$
|
|
1622
|
+
LOGGER_SERVICE$8.log(PERSIST_RISK_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1595
1623
|
this.usePersistRiskAdapter(PersistRiskDummyInstance);
|
|
1596
1624
|
}
|
|
1597
1625
|
}
|
|
@@ -1730,7 +1758,7 @@ class PersistScheduleUtils {
|
|
|
1730
1758
|
* @returns Promise resolving to scheduled signal or null if none persisted
|
|
1731
1759
|
*/
|
|
1732
1760
|
this.readScheduleData = async (symbol, strategyName, exchangeName) => {
|
|
1733
|
-
LOGGER_SERVICE$
|
|
1761
|
+
LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
|
|
1734
1762
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1735
1763
|
const isInitial = !this.getScheduleStorage.has(key);
|
|
1736
1764
|
const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
|
|
@@ -1748,7 +1776,7 @@ class PersistScheduleUtils {
|
|
|
1748
1776
|
* @returns Promise that resolves when write is complete
|
|
1749
1777
|
*/
|
|
1750
1778
|
this.writeScheduleData = async (scheduledSignalRow, symbol, strategyName, exchangeName) => {
|
|
1751
|
-
LOGGER_SERVICE$
|
|
1779
|
+
LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1752
1780
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1753
1781
|
const isInitial = !this.getScheduleStorage.has(key);
|
|
1754
1782
|
const instance = this.getScheduleStorage(symbol, strategyName, exchangeName);
|
|
@@ -1763,7 +1791,7 @@ class PersistScheduleUtils {
|
|
|
1763
1791
|
* @param Ctor - Custom IPersistScheduleInstance constructor
|
|
1764
1792
|
*/
|
|
1765
1793
|
usePersistScheduleAdapter(Ctor) {
|
|
1766
|
-
LOGGER_SERVICE$
|
|
1794
|
+
LOGGER_SERVICE$8.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_PERSIST_SCHEDULE_ADAPTER);
|
|
1767
1795
|
this.PersistScheduleInstanceCtor = Ctor;
|
|
1768
1796
|
this.getScheduleStorage.clear();
|
|
1769
1797
|
}
|
|
@@ -1772,21 +1800,21 @@ class PersistScheduleUtils {
|
|
|
1772
1800
|
* Call when process.cwd() changes between strategy iterations.
|
|
1773
1801
|
*/
|
|
1774
1802
|
clear() {
|
|
1775
|
-
LOGGER_SERVICE$
|
|
1803
|
+
LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_CLEAR);
|
|
1776
1804
|
this.getScheduleStorage.clear();
|
|
1777
1805
|
}
|
|
1778
1806
|
/**
|
|
1779
1807
|
* Switches to the default file-based PersistScheduleInstance.
|
|
1780
1808
|
*/
|
|
1781
1809
|
useJson() {
|
|
1782
|
-
LOGGER_SERVICE$
|
|
1810
|
+
LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_JSON);
|
|
1783
1811
|
this.usePersistScheduleAdapter(PersistScheduleInstance);
|
|
1784
1812
|
}
|
|
1785
1813
|
/**
|
|
1786
1814
|
* Switches to PersistScheduleDummyInstance (all operations are no-ops).
|
|
1787
1815
|
*/
|
|
1788
1816
|
useDummy() {
|
|
1789
|
-
LOGGER_SERVICE$
|
|
1817
|
+
LOGGER_SERVICE$8.log(PERSIST_SCHEDULE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1790
1818
|
this.usePersistScheduleAdapter(PersistScheduleDummyInstance);
|
|
1791
1819
|
}
|
|
1792
1820
|
}
|
|
@@ -1931,7 +1959,7 @@ class PersistPartialUtils {
|
|
|
1931
1959
|
* @returns Promise resolving to partial data record (empty object if none)
|
|
1932
1960
|
*/
|
|
1933
1961
|
this.readPartialData = async (symbol, strategyName, signalId, exchangeName, when) => {
|
|
1934
|
-
LOGGER_SERVICE$
|
|
1962
|
+
LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_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);
|
|
@@ -1951,7 +1979,7 @@ class PersistPartialUtils {
|
|
|
1951
1979
|
* @returns Promise that resolves when write is complete
|
|
1952
1980
|
*/
|
|
1953
1981
|
this.writePartialData = async (partialData, symbol, strategyName, signalId, exchangeName, when) => {
|
|
1954
|
-
LOGGER_SERVICE$
|
|
1982
|
+
LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1955
1983
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1956
1984
|
const isInitial = !this.getPartialStorage.has(key);
|
|
1957
1985
|
const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
|
|
@@ -1966,7 +1994,7 @@ class PersistPartialUtils {
|
|
|
1966
1994
|
* @param Ctor - Custom IPersistPartialInstance constructor
|
|
1967
1995
|
*/
|
|
1968
1996
|
usePersistPartialAdapter(Ctor) {
|
|
1969
|
-
LOGGER_SERVICE$
|
|
1997
|
+
LOGGER_SERVICE$8.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_PERSIST_PARTIAL_ADAPTER);
|
|
1970
1998
|
this.PersistPartialInstanceCtor = Ctor;
|
|
1971
1999
|
this.getPartialStorage.clear();
|
|
1972
2000
|
}
|
|
@@ -1975,21 +2003,21 @@ class PersistPartialUtils {
|
|
|
1975
2003
|
* Call when process.cwd() changes between strategy iterations.
|
|
1976
2004
|
*/
|
|
1977
2005
|
clear() {
|
|
1978
|
-
LOGGER_SERVICE$
|
|
2006
|
+
LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_CLEAR);
|
|
1979
2007
|
this.getPartialStorage.clear();
|
|
1980
2008
|
}
|
|
1981
2009
|
/**
|
|
1982
2010
|
* Switches to the default file-based PersistPartialInstance.
|
|
1983
2011
|
*/
|
|
1984
2012
|
useJson() {
|
|
1985
|
-
LOGGER_SERVICE$
|
|
2013
|
+
LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_JSON);
|
|
1986
2014
|
this.usePersistPartialAdapter(PersistPartialInstance);
|
|
1987
2015
|
}
|
|
1988
2016
|
/**
|
|
1989
2017
|
* Switches to PersistPartialDummyInstance (all operations are no-ops).
|
|
1990
2018
|
*/
|
|
1991
2019
|
useDummy() {
|
|
1992
|
-
LOGGER_SERVICE$
|
|
2020
|
+
LOGGER_SERVICE$8.log(PERSIST_PARTIAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
1993
2021
|
this.usePersistPartialAdapter(PersistPartialDummyInstance);
|
|
1994
2022
|
}
|
|
1995
2023
|
}
|
|
@@ -2154,7 +2182,7 @@ class PersistBreakevenUtils {
|
|
|
2154
2182
|
* @returns Promise resolving to breakeven data record (empty object if none)
|
|
2155
2183
|
*/
|
|
2156
2184
|
this.readBreakevenData = async (symbol, strategyName, signalId, exchangeName, when) => {
|
|
2157
|
-
LOGGER_SERVICE$
|
|
2185
|
+
LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_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);
|
|
@@ -2174,7 +2202,7 @@ class PersistBreakevenUtils {
|
|
|
2174
2202
|
* @returns Promise that resolves when write is complete
|
|
2175
2203
|
*/
|
|
2176
2204
|
this.writeBreakevenData = async (breakevenData, symbol, strategyName, signalId, exchangeName, when) => {
|
|
2177
|
-
LOGGER_SERVICE$
|
|
2205
|
+
LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2178
2206
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
2179
2207
|
const isInitial = !this.getBreakevenStorage.has(key);
|
|
2180
2208
|
const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
|
|
@@ -2189,7 +2217,7 @@ class PersistBreakevenUtils {
|
|
|
2189
2217
|
* @param Ctor - Custom IPersistBreakevenInstance constructor
|
|
2190
2218
|
*/
|
|
2191
2219
|
usePersistBreakevenAdapter(Ctor) {
|
|
2192
|
-
LOGGER_SERVICE$
|
|
2220
|
+
LOGGER_SERVICE$8.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_PERSIST_BREAKEVEN_ADAPTER);
|
|
2193
2221
|
this.PersistBreakevenInstanceCtor = Ctor;
|
|
2194
2222
|
this.getBreakevenStorage.clear();
|
|
2195
2223
|
}
|
|
@@ -2198,21 +2226,21 @@ class PersistBreakevenUtils {
|
|
|
2198
2226
|
* Call when process.cwd() changes between strategy iterations.
|
|
2199
2227
|
*/
|
|
2200
2228
|
clear() {
|
|
2201
|
-
LOGGER_SERVICE$
|
|
2229
|
+
LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_CLEAR);
|
|
2202
2230
|
this.getBreakevenStorage.clear();
|
|
2203
2231
|
}
|
|
2204
2232
|
/**
|
|
2205
2233
|
* Switches to the default file-based PersistBreakevenInstance.
|
|
2206
2234
|
*/
|
|
2207
2235
|
useJson() {
|
|
2208
|
-
LOGGER_SERVICE$
|
|
2236
|
+
LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_JSON);
|
|
2209
2237
|
this.usePersistBreakevenAdapter(PersistBreakevenInstance);
|
|
2210
2238
|
}
|
|
2211
2239
|
/**
|
|
2212
2240
|
* Switches to PersistBreakevenDummyInstance (all operations are no-ops).
|
|
2213
2241
|
*/
|
|
2214
2242
|
useDummy() {
|
|
2215
|
-
LOGGER_SERVICE$
|
|
2243
|
+
LOGGER_SERVICE$8.log(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2216
2244
|
this.usePersistBreakevenAdapter(PersistBreakevenDummyInstance);
|
|
2217
2245
|
}
|
|
2218
2246
|
}
|
|
@@ -2303,7 +2331,7 @@ class PersistCandleInstance {
|
|
|
2303
2331
|
error: functoolsKit.errorData(error),
|
|
2304
2332
|
message: functoolsKit.getErrorMessage(error),
|
|
2305
2333
|
};
|
|
2306
|
-
LOGGER_SERVICE$
|
|
2334
|
+
LOGGER_SERVICE$8.warn(message, payload);
|
|
2307
2335
|
console.warn(message, payload);
|
|
2308
2336
|
errorEmitter.next(error);
|
|
2309
2337
|
return null;
|
|
@@ -2325,7 +2353,7 @@ class PersistCandleInstance {
|
|
|
2325
2353
|
for (const candle of candles) {
|
|
2326
2354
|
const candleCloseTime = candle.timestamp + stepMs;
|
|
2327
2355
|
if (candleCloseTime > now) {
|
|
2328
|
-
LOGGER_SERVICE$
|
|
2356
|
+
LOGGER_SERVICE$8.debug("PersistCandleInstance.writeCandlesData: skipping incomplete candle", {
|
|
2329
2357
|
symbol: this.symbol,
|
|
2330
2358
|
interval: this.interval,
|
|
2331
2359
|
exchangeName: this.exchangeName,
|
|
@@ -2402,7 +2430,7 @@ class PersistCandleUtils {
|
|
|
2402
2430
|
* @returns Promise resolving to candles in order, or null on cache miss
|
|
2403
2431
|
*/
|
|
2404
2432
|
this.readCandlesData = async (symbol, interval, exchangeName, limit, sinceTimestamp, untilTimestamp) => {
|
|
2405
|
-
LOGGER_SERVICE$
|
|
2433
|
+
LOGGER_SERVICE$8.info("PersistCandleUtils.readCandlesData", {
|
|
2406
2434
|
symbol,
|
|
2407
2435
|
interval,
|
|
2408
2436
|
exchangeName,
|
|
@@ -2426,7 +2454,7 @@ class PersistCandleUtils {
|
|
|
2426
2454
|
* @returns Promise that resolves when all writes are complete
|
|
2427
2455
|
*/
|
|
2428
2456
|
this.writeCandlesData = async (candles, symbol, interval, exchangeName) => {
|
|
2429
|
-
LOGGER_SERVICE$
|
|
2457
|
+
LOGGER_SERVICE$8.info("PersistCandleUtils.writeCandlesData", {
|
|
2430
2458
|
symbol,
|
|
2431
2459
|
interval,
|
|
2432
2460
|
exchangeName,
|
|
@@ -2446,7 +2474,7 @@ class PersistCandleUtils {
|
|
|
2446
2474
|
* @param Ctor - Custom IPersistCandleInstance constructor
|
|
2447
2475
|
*/
|
|
2448
2476
|
usePersistCandleAdapter(Ctor) {
|
|
2449
|
-
LOGGER_SERVICE$
|
|
2477
|
+
LOGGER_SERVICE$8.info("PersistCandleUtils.usePersistCandleAdapter");
|
|
2450
2478
|
this.PersistCandleInstanceCtor = Ctor;
|
|
2451
2479
|
this.getCandlesStorage.clear();
|
|
2452
2480
|
}
|
|
@@ -2455,21 +2483,21 @@ class PersistCandleUtils {
|
|
|
2455
2483
|
* Call when process.cwd() changes between strategy iterations.
|
|
2456
2484
|
*/
|
|
2457
2485
|
clear() {
|
|
2458
|
-
LOGGER_SERVICE$
|
|
2486
|
+
LOGGER_SERVICE$8.log(PERSIST_CANDLE_UTILS_METHOD_NAME_CLEAR);
|
|
2459
2487
|
this.getCandlesStorage.clear();
|
|
2460
2488
|
}
|
|
2461
2489
|
/**
|
|
2462
2490
|
* Switches to the default file-based PersistCandleInstance.
|
|
2463
2491
|
*/
|
|
2464
2492
|
useJson() {
|
|
2465
|
-
LOGGER_SERVICE$
|
|
2493
|
+
LOGGER_SERVICE$8.log("PersistCandleUtils.useJson");
|
|
2466
2494
|
this.usePersistCandleAdapter(PersistCandleInstance);
|
|
2467
2495
|
}
|
|
2468
2496
|
/**
|
|
2469
2497
|
* Switches to PersistCandleDummyInstance (always returns null on read, discards writes).
|
|
2470
2498
|
*/
|
|
2471
2499
|
useDummy() {
|
|
2472
|
-
LOGGER_SERVICE$
|
|
2500
|
+
LOGGER_SERVICE$8.log("PersistCandleUtils.useDummy");
|
|
2473
2501
|
this.usePersistCandleAdapter(PersistCandleDummyInstance);
|
|
2474
2502
|
}
|
|
2475
2503
|
}
|
|
@@ -2607,7 +2635,7 @@ class PersistStorageUtils {
|
|
|
2607
2635
|
* @returns Promise resolving to array of signal entries
|
|
2608
2636
|
*/
|
|
2609
2637
|
this.readStorageData = async (backtest) => {
|
|
2610
|
-
LOGGER_SERVICE$
|
|
2638
|
+
LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_READ_DATA);
|
|
2611
2639
|
const key = backtest ? `backtest` : `live`;
|
|
2612
2640
|
const isInitial = !this.getStorage.has(key);
|
|
2613
2641
|
const instance = this.getStorage(backtest);
|
|
@@ -2623,7 +2651,7 @@ class PersistStorageUtils {
|
|
|
2623
2651
|
* @returns Promise that resolves when write is complete
|
|
2624
2652
|
*/
|
|
2625
2653
|
this.writeStorageData = async (signalData, backtest) => {
|
|
2626
|
-
LOGGER_SERVICE$
|
|
2654
|
+
LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2627
2655
|
const key = backtest ? `backtest` : `live`;
|
|
2628
2656
|
const isInitial = !this.getStorage.has(key);
|
|
2629
2657
|
const instance = this.getStorage(backtest);
|
|
@@ -2638,7 +2666,7 @@ class PersistStorageUtils {
|
|
|
2638
2666
|
* @param Ctor - Custom IPersistStorageInstance constructor
|
|
2639
2667
|
*/
|
|
2640
2668
|
usePersistStorageAdapter(Ctor) {
|
|
2641
|
-
LOGGER_SERVICE$
|
|
2669
|
+
LOGGER_SERVICE$8.info(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_PERSIST_STORAGE_ADAPTER);
|
|
2642
2670
|
this.PersistStorageInstanceCtor = Ctor;
|
|
2643
2671
|
this.getStorage.clear();
|
|
2644
2672
|
}
|
|
@@ -2647,21 +2675,21 @@ class PersistStorageUtils {
|
|
|
2647
2675
|
* Call when process.cwd() changes between strategy iterations.
|
|
2648
2676
|
*/
|
|
2649
2677
|
clear() {
|
|
2650
|
-
LOGGER_SERVICE$
|
|
2678
|
+
LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_CLEAR);
|
|
2651
2679
|
this.getStorage.clear();
|
|
2652
2680
|
}
|
|
2653
2681
|
/**
|
|
2654
2682
|
* Switches to the default file-based PersistStorageInstance.
|
|
2655
2683
|
*/
|
|
2656
2684
|
useJson() {
|
|
2657
|
-
LOGGER_SERVICE$
|
|
2685
|
+
LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_JSON);
|
|
2658
2686
|
this.usePersistStorageAdapter(PersistStorageInstance);
|
|
2659
2687
|
}
|
|
2660
2688
|
/**
|
|
2661
2689
|
* Switches to PersistStorageDummyInstance (all operations are no-ops).
|
|
2662
2690
|
*/
|
|
2663
2691
|
useDummy() {
|
|
2664
|
-
LOGGER_SERVICE$
|
|
2692
|
+
LOGGER_SERVICE$8.log(PERSIST_STORAGE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2665
2693
|
this.usePersistStorageAdapter(PersistStorageDummyInstance);
|
|
2666
2694
|
}
|
|
2667
2695
|
}
|
|
@@ -2788,7 +2816,7 @@ class PersistNotificationUtils {
|
|
|
2788
2816
|
* @returns Promise resolving to array of notification entries
|
|
2789
2817
|
*/
|
|
2790
2818
|
this.readNotificationData = async (backtest) => {
|
|
2791
|
-
LOGGER_SERVICE$
|
|
2819
|
+
LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_READ_DATA);
|
|
2792
2820
|
const key = backtest ? `backtest` : `live`;
|
|
2793
2821
|
const isInitial = !this.getNotificationStorage.has(key);
|
|
2794
2822
|
const instance = this.getNotificationStorage(backtest);
|
|
@@ -2804,7 +2832,7 @@ class PersistNotificationUtils {
|
|
|
2804
2832
|
* @returns Promise that resolves when write is complete
|
|
2805
2833
|
*/
|
|
2806
2834
|
this.writeNotificationData = async (notificationData, backtest) => {
|
|
2807
|
-
LOGGER_SERVICE$
|
|
2835
|
+
LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2808
2836
|
const key = backtest ? `backtest` : `live`;
|
|
2809
2837
|
const isInitial = !this.getNotificationStorage.has(key);
|
|
2810
2838
|
const instance = this.getNotificationStorage(backtest);
|
|
@@ -2819,7 +2847,7 @@ class PersistNotificationUtils {
|
|
|
2819
2847
|
* @param Ctor - Custom IPersistNotificationInstance constructor
|
|
2820
2848
|
*/
|
|
2821
2849
|
usePersistNotificationAdapter(Ctor) {
|
|
2822
|
-
LOGGER_SERVICE$
|
|
2850
|
+
LOGGER_SERVICE$8.info(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER);
|
|
2823
2851
|
this.PersistNotificationInstanceCtor = Ctor;
|
|
2824
2852
|
this.getNotificationStorage.clear();
|
|
2825
2853
|
}
|
|
@@ -2829,21 +2857,21 @@ class PersistNotificationUtils {
|
|
|
2829
2857
|
* instances are created with the updated base path.
|
|
2830
2858
|
*/
|
|
2831
2859
|
clear() {
|
|
2832
|
-
LOGGER_SERVICE$
|
|
2860
|
+
LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_CLEAR);
|
|
2833
2861
|
this.getNotificationStorage.clear();
|
|
2834
2862
|
}
|
|
2835
2863
|
/**
|
|
2836
2864
|
* Switches to the default file-based PersistNotificationInstance.
|
|
2837
2865
|
*/
|
|
2838
2866
|
useJson() {
|
|
2839
|
-
LOGGER_SERVICE$
|
|
2867
|
+
LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON);
|
|
2840
2868
|
this.usePersistNotificationAdapter(PersistNotificationInstance);
|
|
2841
2869
|
}
|
|
2842
2870
|
/**
|
|
2843
2871
|
* Switches to PersistNotificationDummyInstance (all operations are no-ops).
|
|
2844
2872
|
*/
|
|
2845
2873
|
useDummy() {
|
|
2846
|
-
LOGGER_SERVICE$
|
|
2874
|
+
LOGGER_SERVICE$8.log(PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2847
2875
|
this.usePersistNotificationAdapter(PersistNotificationDummyInstance);
|
|
2848
2876
|
}
|
|
2849
2877
|
}
|
|
@@ -2967,7 +2995,7 @@ class PersistLogUtils {
|
|
|
2967
2995
|
* @returns Promise resolving to array of log entries
|
|
2968
2996
|
*/
|
|
2969
2997
|
this.readLogData = async () => {
|
|
2970
|
-
LOGGER_SERVICE$
|
|
2998
|
+
LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
|
|
2971
2999
|
const isInitial = !this._logInstance;
|
|
2972
3000
|
const instance = this.getLogInstance();
|
|
2973
3001
|
await instance.waitForInit(isInitial);
|
|
@@ -2981,7 +3009,7 @@ class PersistLogUtils {
|
|
|
2981
3009
|
* @returns Promise that resolves when write is complete
|
|
2982
3010
|
*/
|
|
2983
3011
|
this.writeLogData = async (logData) => {
|
|
2984
|
-
LOGGER_SERVICE$
|
|
3012
|
+
LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2985
3013
|
const isInitial = !this._logInstance;
|
|
2986
3014
|
const instance = this.getLogInstance();
|
|
2987
3015
|
await instance.waitForInit(isInitial);
|
|
@@ -3006,7 +3034,7 @@ class PersistLogUtils {
|
|
|
3006
3034
|
* @param Ctor - Custom IPersistLogInstance constructor
|
|
3007
3035
|
*/
|
|
3008
3036
|
usePersistLogAdapter(Ctor) {
|
|
3009
|
-
LOGGER_SERVICE$
|
|
3037
|
+
LOGGER_SERVICE$8.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
|
|
3010
3038
|
this.PersistLogInstanceCtor = Ctor;
|
|
3011
3039
|
this._logInstance = null;
|
|
3012
3040
|
}
|
|
@@ -3015,21 +3043,21 @@ class PersistLogUtils {
|
|
|
3015
3043
|
* Call when process.cwd() changes between strategy iterations.
|
|
3016
3044
|
*/
|
|
3017
3045
|
clear() {
|
|
3018
|
-
LOGGER_SERVICE$
|
|
3046
|
+
LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_CLEAR);
|
|
3019
3047
|
this._logInstance = null;
|
|
3020
3048
|
}
|
|
3021
3049
|
/**
|
|
3022
3050
|
* Switches to the default file-based PersistLogInstance.
|
|
3023
3051
|
*/
|
|
3024
3052
|
useJson() {
|
|
3025
|
-
LOGGER_SERVICE$
|
|
3053
|
+
LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
|
|
3026
3054
|
this.usePersistLogAdapter(PersistLogInstance);
|
|
3027
3055
|
}
|
|
3028
3056
|
/**
|
|
3029
3057
|
* Switches to PersistLogDummyInstance (all operations are no-ops).
|
|
3030
3058
|
*/
|
|
3031
3059
|
useDummy() {
|
|
3032
|
-
LOGGER_SERVICE$
|
|
3060
|
+
LOGGER_SERVICE$8.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3033
3061
|
this.usePersistLogAdapter(PersistLogDummyInstance);
|
|
3034
3062
|
}
|
|
3035
3063
|
}
|
|
@@ -3191,7 +3219,7 @@ class PersistMeasureUtils {
|
|
|
3191
3219
|
* @returns Promise resolving to cached value, or null if not found / soft-deleted
|
|
3192
3220
|
*/
|
|
3193
3221
|
this.readMeasureData = async (bucket, key) => {
|
|
3194
|
-
LOGGER_SERVICE$
|
|
3222
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
|
|
3195
3223
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3196
3224
|
const instance = this.getMeasureStorage(bucket);
|
|
3197
3225
|
await instance.waitForInit(isInitial);
|
|
@@ -3207,7 +3235,7 @@ class PersistMeasureUtils {
|
|
|
3207
3235
|
* @returns Promise that resolves when write is complete
|
|
3208
3236
|
*/
|
|
3209
3237
|
this.writeMeasureData = async (data, bucket, key, when) => {
|
|
3210
|
-
LOGGER_SERVICE$
|
|
3238
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
|
|
3211
3239
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3212
3240
|
const instance = this.getMeasureStorage(bucket);
|
|
3213
3241
|
await instance.waitForInit(isInitial);
|
|
@@ -3222,7 +3250,7 @@ class PersistMeasureUtils {
|
|
|
3222
3250
|
* @returns Promise that resolves when removal is complete
|
|
3223
3251
|
*/
|
|
3224
3252
|
this.removeMeasureData = async (bucket, key) => {
|
|
3225
|
-
LOGGER_SERVICE$
|
|
3253
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
|
|
3226
3254
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3227
3255
|
const instance = this.getMeasureStorage(bucket);
|
|
3228
3256
|
await instance.waitForInit(isInitial);
|
|
@@ -3236,7 +3264,7 @@ class PersistMeasureUtils {
|
|
|
3236
3264
|
* @param Ctor - Custom IPersistMeasureInstance constructor
|
|
3237
3265
|
*/
|
|
3238
3266
|
usePersistMeasureAdapter(Ctor) {
|
|
3239
|
-
LOGGER_SERVICE$
|
|
3267
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_PERSIST_MEASURE_ADAPTER);
|
|
3240
3268
|
this.PersistMeasureInstanceCtor = Ctor;
|
|
3241
3269
|
this.getMeasureStorage.clear();
|
|
3242
3270
|
}
|
|
@@ -3248,7 +3276,7 @@ class PersistMeasureUtils {
|
|
|
3248
3276
|
* @returns AsyncGenerator yielding entry keys
|
|
3249
3277
|
*/
|
|
3250
3278
|
async *listMeasureData(bucket) {
|
|
3251
|
-
LOGGER_SERVICE$
|
|
3279
|
+
LOGGER_SERVICE$8.info(PERSIST_MEASURE_UTILS_METHOD_NAME_LIST_DATA, { bucket });
|
|
3252
3280
|
const isInitial = !this.getMeasureStorage.has(bucket);
|
|
3253
3281
|
const instance = this.getMeasureStorage(bucket);
|
|
3254
3282
|
await instance.waitForInit(isInitial);
|
|
@@ -3259,21 +3287,21 @@ class PersistMeasureUtils {
|
|
|
3259
3287
|
* Call when process.cwd() changes between strategy iterations.
|
|
3260
3288
|
*/
|
|
3261
3289
|
clear() {
|
|
3262
|
-
LOGGER_SERVICE$
|
|
3290
|
+
LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_CLEAR);
|
|
3263
3291
|
this.getMeasureStorage.clear();
|
|
3264
3292
|
}
|
|
3265
3293
|
/**
|
|
3266
3294
|
* Switches to the default file-based PersistMeasureInstance.
|
|
3267
3295
|
*/
|
|
3268
3296
|
useJson() {
|
|
3269
|
-
LOGGER_SERVICE$
|
|
3297
|
+
LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_JSON);
|
|
3270
3298
|
this.usePersistMeasureAdapter(PersistMeasureInstance);
|
|
3271
3299
|
}
|
|
3272
3300
|
/**
|
|
3273
3301
|
* Switches to PersistMeasureDummyInstance (all operations are no-ops).
|
|
3274
3302
|
*/
|
|
3275
3303
|
useDummy() {
|
|
3276
|
-
LOGGER_SERVICE$
|
|
3304
|
+
LOGGER_SERVICE$8.log(PERSIST_MEASURE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3277
3305
|
this.usePersistMeasureAdapter(PersistMeasureDummyInstance);
|
|
3278
3306
|
}
|
|
3279
3307
|
}
|
|
@@ -3432,7 +3460,7 @@ class PersistIntervalUtils {
|
|
|
3432
3460
|
* @returns Promise resolving to marker data, or null if not found / soft-deleted
|
|
3433
3461
|
*/
|
|
3434
3462
|
this.readIntervalData = async (bucket, key) => {
|
|
3435
|
-
LOGGER_SERVICE$
|
|
3463
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_READ_DATA, { bucket, key });
|
|
3436
3464
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3437
3465
|
const instance = this.getIntervalStorage(bucket);
|
|
3438
3466
|
await instance.waitForInit(isInitial);
|
|
@@ -3448,7 +3476,7 @@ class PersistIntervalUtils {
|
|
|
3448
3476
|
* @returns Promise that resolves when write is complete
|
|
3449
3477
|
*/
|
|
3450
3478
|
this.writeIntervalData = async (data, bucket, key, when) => {
|
|
3451
|
-
LOGGER_SERVICE$
|
|
3479
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_WRITE_DATA, { bucket, key });
|
|
3452
3480
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3453
3481
|
const instance = this.getIntervalStorage(bucket);
|
|
3454
3482
|
await instance.waitForInit(isInitial);
|
|
@@ -3463,7 +3491,7 @@ class PersistIntervalUtils {
|
|
|
3463
3491
|
* @returns Promise that resolves when removal is complete
|
|
3464
3492
|
*/
|
|
3465
3493
|
this.removeIntervalData = async (bucket, key) => {
|
|
3466
|
-
LOGGER_SERVICE$
|
|
3494
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_REMOVE_DATA, { bucket, key });
|
|
3467
3495
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3468
3496
|
const instance = this.getIntervalStorage(bucket);
|
|
3469
3497
|
await instance.waitForInit(isInitial);
|
|
@@ -3477,7 +3505,7 @@ class PersistIntervalUtils {
|
|
|
3477
3505
|
* @param Ctor - Custom IPersistIntervalInstance constructor
|
|
3478
3506
|
*/
|
|
3479
3507
|
usePersistIntervalAdapter(Ctor) {
|
|
3480
|
-
LOGGER_SERVICE$
|
|
3508
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_PERSIST_INTERVAL_ADAPTER);
|
|
3481
3509
|
this.PersistIntervalInstanceCtor = Ctor;
|
|
3482
3510
|
this.getIntervalStorage.clear();
|
|
3483
3511
|
}
|
|
@@ -3489,7 +3517,7 @@ class PersistIntervalUtils {
|
|
|
3489
3517
|
* @returns AsyncGenerator yielding marker keys
|
|
3490
3518
|
*/
|
|
3491
3519
|
async *listIntervalData(bucket) {
|
|
3492
|
-
LOGGER_SERVICE$
|
|
3520
|
+
LOGGER_SERVICE$8.info(PERSIST_INTERVAL_UTILS_METHOD_NAME_LIST_DATA, { bucket });
|
|
3493
3521
|
const isInitial = !this.getIntervalStorage.has(bucket);
|
|
3494
3522
|
const instance = this.getIntervalStorage(bucket);
|
|
3495
3523
|
await instance.waitForInit(isInitial);
|
|
@@ -3500,21 +3528,21 @@ class PersistIntervalUtils {
|
|
|
3500
3528
|
* Call when process.cwd() changes between strategy iterations.
|
|
3501
3529
|
*/
|
|
3502
3530
|
clear() {
|
|
3503
|
-
LOGGER_SERVICE$
|
|
3531
|
+
LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_CLEAR);
|
|
3504
3532
|
this.getIntervalStorage.clear();
|
|
3505
3533
|
}
|
|
3506
3534
|
/**
|
|
3507
3535
|
* Switches to the default file-based PersistIntervalInstance.
|
|
3508
3536
|
*/
|
|
3509
3537
|
useJson() {
|
|
3510
|
-
LOGGER_SERVICE$
|
|
3538
|
+
LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_JSON);
|
|
3511
3539
|
this.usePersistIntervalAdapter(PersistIntervalInstance);
|
|
3512
3540
|
}
|
|
3513
3541
|
/**
|
|
3514
3542
|
* Switches to PersistIntervalDummyInstance (all operations are no-ops).
|
|
3515
3543
|
*/
|
|
3516
3544
|
useDummy() {
|
|
3517
|
-
LOGGER_SERVICE$
|
|
3545
|
+
LOGGER_SERVICE$8.log(PERSIST_INTERVAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3518
3546
|
this.usePersistIntervalAdapter(PersistIntervalDummyInstance);
|
|
3519
3547
|
}
|
|
3520
3548
|
}
|
|
@@ -3720,7 +3748,7 @@ class PersistMemoryUtils {
|
|
|
3720
3748
|
* @returns Promise resolving to entry data, or null if not found / soft-deleted
|
|
3721
3749
|
*/
|
|
3722
3750
|
this.readMemoryData = async (signalId, bucketName, memoryId) => {
|
|
3723
|
-
LOGGER_SERVICE$
|
|
3751
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName, memoryId });
|
|
3724
3752
|
const key = `${signalId}:${bucketName}`;
|
|
3725
3753
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3726
3754
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3737,7 +3765,7 @@ class PersistMemoryUtils {
|
|
|
3737
3765
|
* @returns Promise resolving to true if entry exists
|
|
3738
3766
|
*/
|
|
3739
3767
|
this.hasMemoryData = async (signalId, bucketName, memoryId) => {
|
|
3740
|
-
LOGGER_SERVICE$
|
|
3768
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA, { signalId, bucketName, memoryId });
|
|
3741
3769
|
const key = `${signalId}:${bucketName}`;
|
|
3742
3770
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3743
3771
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3756,7 +3784,7 @@ class PersistMemoryUtils {
|
|
|
3756
3784
|
* @returns Promise that resolves when write is complete
|
|
3757
3785
|
*/
|
|
3758
3786
|
this.writeMemoryData = async (data, signalId, bucketName, memoryId, when) => {
|
|
3759
|
-
LOGGER_SERVICE$
|
|
3787
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
|
|
3760
3788
|
const key = `${signalId}:${bucketName}`;
|
|
3761
3789
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3762
3790
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3773,7 +3801,7 @@ class PersistMemoryUtils {
|
|
|
3773
3801
|
* @returns Promise that resolves when removal is complete
|
|
3774
3802
|
*/
|
|
3775
3803
|
this.removeMemoryData = async (signalId, bucketName, memoryId) => {
|
|
3776
|
-
LOGGER_SERVICE$
|
|
3804
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_REMOVE_DATA, { signalId, bucketName, memoryId });
|
|
3777
3805
|
const key = `${signalId}:${bucketName}`;
|
|
3778
3806
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3779
3807
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3785,7 +3813,7 @@ class PersistMemoryUtils {
|
|
|
3785
3813
|
* Call when process.cwd() changes between strategy iterations.
|
|
3786
3814
|
*/
|
|
3787
3815
|
this.clear = () => {
|
|
3788
|
-
LOGGER_SERVICE$
|
|
3816
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR);
|
|
3789
3817
|
this.getMemoryStorage.clear();
|
|
3790
3818
|
};
|
|
3791
3819
|
/**
|
|
@@ -3796,7 +3824,7 @@ class PersistMemoryUtils {
|
|
|
3796
3824
|
* @param bucketName - Bucket name
|
|
3797
3825
|
*/
|
|
3798
3826
|
this.dispose = (signalId, bucketName) => {
|
|
3799
|
-
LOGGER_SERVICE$
|
|
3827
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE);
|
|
3800
3828
|
const key = `${signalId}:${bucketName}`;
|
|
3801
3829
|
this.getMemoryStorage.clear(key);
|
|
3802
3830
|
};
|
|
@@ -3808,7 +3836,7 @@ class PersistMemoryUtils {
|
|
|
3808
3836
|
* @param Ctor - Custom IPersistMemoryInstance constructor
|
|
3809
3837
|
*/
|
|
3810
3838
|
usePersistMemoryAdapter(Ctor) {
|
|
3811
|
-
LOGGER_SERVICE$
|
|
3839
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_USE_PERSIST_MEMORY_ADAPTER);
|
|
3812
3840
|
this.PersistMemoryInstanceCtor = Ctor;
|
|
3813
3841
|
this.getMemoryStorage.clear();
|
|
3814
3842
|
}
|
|
@@ -3822,7 +3850,7 @@ class PersistMemoryUtils {
|
|
|
3822
3850
|
* @returns AsyncGenerator yielding `{ memoryId, data }` tuples
|
|
3823
3851
|
*/
|
|
3824
3852
|
async *listMemoryData(signalId, bucketName) {
|
|
3825
|
-
LOGGER_SERVICE$
|
|
3853
|
+
LOGGER_SERVICE$8.info(PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA, { signalId, bucketName });
|
|
3826
3854
|
const key = `${signalId}:${bucketName}`;
|
|
3827
3855
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3828
3856
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
@@ -3833,14 +3861,14 @@ class PersistMemoryUtils {
|
|
|
3833
3861
|
* Switches to the default file-based PersistMemoryInstance.
|
|
3834
3862
|
*/
|
|
3835
3863
|
useJson() {
|
|
3836
|
-
LOGGER_SERVICE$
|
|
3864
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_JSON);
|
|
3837
3865
|
this.usePersistMemoryAdapter(PersistMemoryInstance);
|
|
3838
3866
|
}
|
|
3839
3867
|
/**
|
|
3840
3868
|
* Switches to PersistMemoryDummyInstance (all operations are no-ops).
|
|
3841
3869
|
*/
|
|
3842
3870
|
useDummy() {
|
|
3843
|
-
LOGGER_SERVICE$
|
|
3871
|
+
LOGGER_SERVICE$8.log(PERSIST_SIGNAL_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3844
3872
|
this.usePersistMemoryAdapter(PersistMemoryDummyInstance);
|
|
3845
3873
|
}
|
|
3846
3874
|
}
|
|
@@ -3989,7 +4017,7 @@ class PersistRecentUtils {
|
|
|
3989
4017
|
* @returns Promise resolving to recent signal or null if none persisted
|
|
3990
4018
|
*/
|
|
3991
4019
|
this.readRecentData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
3992
|
-
LOGGER_SERVICE$
|
|
4020
|
+
LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
|
|
3993
4021
|
const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
|
|
3994
4022
|
const isInitial = !this.getStorage.has(key);
|
|
3995
4023
|
const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
@@ -4010,7 +4038,7 @@ class PersistRecentUtils {
|
|
|
4010
4038
|
* @returns Promise that resolves when write is complete
|
|
4011
4039
|
*/
|
|
4012
4040
|
this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest, when) => {
|
|
4013
|
-
LOGGER_SERVICE$
|
|
4041
|
+
LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
|
|
4014
4042
|
const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
|
|
4015
4043
|
const isInitial = !this.getStorage.has(key);
|
|
4016
4044
|
const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
@@ -4043,7 +4071,7 @@ class PersistRecentUtils {
|
|
|
4043
4071
|
* @param Ctor - Custom IPersistRecentInstance constructor
|
|
4044
4072
|
*/
|
|
4045
4073
|
usePersistRecentAdapter(Ctor) {
|
|
4046
|
-
LOGGER_SERVICE$
|
|
4074
|
+
LOGGER_SERVICE$8.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
|
|
4047
4075
|
this.PersistRecentInstanceCtor = Ctor;
|
|
4048
4076
|
this.getStorage.clear();
|
|
4049
4077
|
}
|
|
@@ -4052,21 +4080,21 @@ class PersistRecentUtils {
|
|
|
4052
4080
|
* Call when process.cwd() changes between strategy iterations.
|
|
4053
4081
|
*/
|
|
4054
4082
|
clear() {
|
|
4055
|
-
LOGGER_SERVICE$
|
|
4083
|
+
LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
|
|
4056
4084
|
this.getStorage.clear();
|
|
4057
4085
|
}
|
|
4058
4086
|
/**
|
|
4059
4087
|
* Switches to the default file-based PersistRecentInstance.
|
|
4060
4088
|
*/
|
|
4061
4089
|
useJson() {
|
|
4062
|
-
LOGGER_SERVICE$
|
|
4090
|
+
LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
|
|
4063
4091
|
this.usePersistRecentAdapter(PersistRecentInstance);
|
|
4064
4092
|
}
|
|
4065
4093
|
/**
|
|
4066
4094
|
* Switches to PersistRecentDummyInstance (all operations are no-ops).
|
|
4067
4095
|
*/
|
|
4068
4096
|
useDummy() {
|
|
4069
|
-
LOGGER_SERVICE$
|
|
4097
|
+
LOGGER_SERVICE$8.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
|
|
4070
4098
|
this.usePersistRecentAdapter(PersistRecentDummyInstance);
|
|
4071
4099
|
}
|
|
4072
4100
|
}
|
|
@@ -4201,7 +4229,7 @@ class PersistStateUtils {
|
|
|
4201
4229
|
* @returns Promise that resolves when initialization is complete
|
|
4202
4230
|
*/
|
|
4203
4231
|
this.waitForInit = async (signalId, bucketName, initial) => {
|
|
4204
|
-
LOGGER_SERVICE$
|
|
4232
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT, { signalId, bucketName, initial });
|
|
4205
4233
|
const key = `${signalId}:${bucketName}`;
|
|
4206
4234
|
const isInitial = initial && !this.getStateStorage.has(key);
|
|
4207
4235
|
const instance = this.getStateStorage(signalId, bucketName);
|
|
@@ -4216,7 +4244,7 @@ class PersistStateUtils {
|
|
|
4216
4244
|
* @returns Promise resolving to state data or null if none persisted
|
|
4217
4245
|
*/
|
|
4218
4246
|
this.readStateData = async (signalId, bucketName) => {
|
|
4219
|
-
LOGGER_SERVICE$
|
|
4247
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_READ_DATA, { signalId, bucketName });
|
|
4220
4248
|
const key = `${signalId}:${bucketName}`;
|
|
4221
4249
|
const isInitial = !this.getStateStorage.has(key);
|
|
4222
4250
|
const instance = this.getStateStorage(signalId, bucketName);
|
|
@@ -4234,7 +4262,7 @@ class PersistStateUtils {
|
|
|
4234
4262
|
* @returns Promise that resolves when write is complete
|
|
4235
4263
|
*/
|
|
4236
4264
|
this.writeStateData = async (data, signalId, bucketName, when) => {
|
|
4237
|
-
LOGGER_SERVICE$
|
|
4265
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
|
|
4238
4266
|
const key = `${signalId}:${bucketName}`;
|
|
4239
4267
|
const isInitial = !this.getStateStorage.has(key);
|
|
4240
4268
|
const instance = this.getStateStorage(signalId, bucketName);
|
|
@@ -4245,14 +4273,14 @@ class PersistStateUtils {
|
|
|
4245
4273
|
* Switches to PersistStateDummyInstance (all operations are no-ops).
|
|
4246
4274
|
*/
|
|
4247
4275
|
this.useDummy = () => {
|
|
4248
|
-
LOGGER_SERVICE$
|
|
4276
|
+
LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
4249
4277
|
this.usePersistStateAdapter(PersistStateDummyInstance);
|
|
4250
4278
|
};
|
|
4251
4279
|
/**
|
|
4252
4280
|
* Switches to the default file-based PersistStateInstance.
|
|
4253
4281
|
*/
|
|
4254
4282
|
this.useJson = () => {
|
|
4255
|
-
LOGGER_SERVICE$
|
|
4283
|
+
LOGGER_SERVICE$8.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
|
|
4256
4284
|
this.usePersistStateAdapter(PersistStateInstance);
|
|
4257
4285
|
};
|
|
4258
4286
|
/**
|
|
@@ -4260,7 +4288,7 @@ class PersistStateUtils {
|
|
|
4260
4288
|
* Call when process.cwd() changes between strategy iterations.
|
|
4261
4289
|
*/
|
|
4262
4290
|
this.clear = () => {
|
|
4263
|
-
LOGGER_SERVICE$
|
|
4291
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_CLEAR);
|
|
4264
4292
|
this.getStateStorage.clear();
|
|
4265
4293
|
};
|
|
4266
4294
|
/**
|
|
@@ -4271,7 +4299,7 @@ class PersistStateUtils {
|
|
|
4271
4299
|
* @param bucketName - Bucket name
|
|
4272
4300
|
*/
|
|
4273
4301
|
this.dispose = (signalId, bucketName) => {
|
|
4274
|
-
LOGGER_SERVICE$
|
|
4302
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE);
|
|
4275
4303
|
const key = `${signalId}:${bucketName}`;
|
|
4276
4304
|
this.getStateStorage.clear(key);
|
|
4277
4305
|
};
|
|
@@ -4283,7 +4311,7 @@ class PersistStateUtils {
|
|
|
4283
4311
|
* @param Ctor - Custom IPersistStateInstance constructor
|
|
4284
4312
|
*/
|
|
4285
4313
|
usePersistStateAdapter(Ctor) {
|
|
4286
|
-
LOGGER_SERVICE$
|
|
4314
|
+
LOGGER_SERVICE$8.info(PERSIST_STATE_UTILS_METHOD_NAME_USE_PERSIST_STATE_ADAPTER);
|
|
4287
4315
|
this.PersistStateInstanceCtor = Ctor;
|
|
4288
4316
|
this.getStateStorage.clear();
|
|
4289
4317
|
}
|
|
@@ -4423,7 +4451,7 @@ class PersistSessionUtils {
|
|
|
4423
4451
|
* @returns Promise that resolves when initialization is complete
|
|
4424
4452
|
*/
|
|
4425
4453
|
this.waitForInit = async (strategyName, exchangeName, frameName, initial) => {
|
|
4426
|
-
LOGGER_SERVICE$
|
|
4454
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, { strategyName, exchangeName, frameName, initial });
|
|
4427
4455
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4428
4456
|
const isInitial = initial && !this.getSessionStorage.has(key);
|
|
4429
4457
|
const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
@@ -4439,7 +4467,7 @@ class PersistSessionUtils {
|
|
|
4439
4467
|
* @returns Promise resolving to session data or null if none persisted
|
|
4440
4468
|
*/
|
|
4441
4469
|
this.readSessionData = async (strategyName, exchangeName, frameName) => {
|
|
4442
|
-
LOGGER_SERVICE$
|
|
4470
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, { strategyName, exchangeName, frameName });
|
|
4443
4471
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4444
4472
|
const isInitial = !this.getSessionStorage.has(key);
|
|
4445
4473
|
const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
@@ -4458,7 +4486,7 @@ class PersistSessionUtils {
|
|
|
4458
4486
|
* @returns Promise that resolves when write is complete
|
|
4459
4487
|
*/
|
|
4460
4488
|
this.writeSessionData = async (data, strategyName, exchangeName, frameName, when) => {
|
|
4461
|
-
LOGGER_SERVICE$
|
|
4489
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
|
|
4462
4490
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4463
4491
|
const isInitial = !this.getSessionStorage.has(key);
|
|
4464
4492
|
const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
@@ -4469,14 +4497,14 @@ class PersistSessionUtils {
|
|
|
4469
4497
|
* Switches to PersistSessionDummyInstance (all operations are no-ops).
|
|
4470
4498
|
*/
|
|
4471
4499
|
this.useDummy = () => {
|
|
4472
|
-
LOGGER_SERVICE$
|
|
4500
|
+
LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
|
|
4473
4501
|
this.usePersistSessionAdapter(PersistSessionDummyInstance);
|
|
4474
4502
|
};
|
|
4475
4503
|
/**
|
|
4476
4504
|
* Switches to the default file-based PersistSessionInstance.
|
|
4477
4505
|
*/
|
|
4478
4506
|
this.useJson = () => {
|
|
4479
|
-
LOGGER_SERVICE$
|
|
4507
|
+
LOGGER_SERVICE$8.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
|
|
4480
4508
|
this.usePersistSessionAdapter(PersistSessionInstance);
|
|
4481
4509
|
};
|
|
4482
4510
|
/**
|
|
@@ -4484,7 +4512,7 @@ class PersistSessionUtils {
|
|
|
4484
4512
|
* Call when process.cwd() changes between strategy iterations.
|
|
4485
4513
|
*/
|
|
4486
4514
|
this.clear = () => {
|
|
4487
|
-
LOGGER_SERVICE$
|
|
4515
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
|
|
4488
4516
|
this.getSessionStorage.clear();
|
|
4489
4517
|
};
|
|
4490
4518
|
/**
|
|
@@ -4496,7 +4524,7 @@ class PersistSessionUtils {
|
|
|
4496
4524
|
* @param frameName - Frame identifier
|
|
4497
4525
|
*/
|
|
4498
4526
|
this.dispose = (strategyName, exchangeName, frameName) => {
|
|
4499
|
-
LOGGER_SERVICE$
|
|
4527
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
|
|
4500
4528
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4501
4529
|
this.getSessionStorage.clear(key);
|
|
4502
4530
|
};
|
|
@@ -4508,7 +4536,7 @@ class PersistSessionUtils {
|
|
|
4508
4536
|
* @param Ctor - Custom IPersistSessionInstance constructor
|
|
4509
4537
|
*/
|
|
4510
4538
|
usePersistSessionAdapter(Ctor) {
|
|
4511
|
-
LOGGER_SERVICE$
|
|
4539
|
+
LOGGER_SERVICE$8.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
|
|
4512
4540
|
this.PersistSessionInstanceCtor = Ctor;
|
|
4513
4541
|
this.getSessionStorage.clear();
|
|
4514
4542
|
}
|
|
@@ -4520,28 +4548,39 @@ class PersistSessionUtils {
|
|
|
4520
4548
|
const PersistSessionAdapter = new PersistSessionUtils();
|
|
4521
4549
|
|
|
4522
4550
|
var _a$2, _b$2;
|
|
4523
|
-
const BUSY_DELAY = 100;
|
|
4524
4551
|
const SET_BUSY_SYMBOL = Symbol("setBusy");
|
|
4525
4552
|
const GET_BUSY_SYMBOL = Symbol("getBusy");
|
|
4526
4553
|
const ACQUIRE_LOCK_SYMBOL = Symbol("acquireLock");
|
|
4527
4554
|
const RELEASE_LOCK_SYMBOL = Symbol("releaseLock");
|
|
4555
|
+
/**
|
|
4556
|
+
* Body of the queued acquire operation.
|
|
4557
|
+
*
|
|
4558
|
+
* Parks the caller on `self._tick` whenever the lock is already busy: each
|
|
4559
|
+
* `releaseLock` emits on `_tick`, waking exactly the next queued acquirer
|
|
4560
|
+
* instead of polling on a fixed delay. The busy counter is bumped only after
|
|
4561
|
+
* the loop exits, so re-entry checks remain coherent under contention.
|
|
4562
|
+
*
|
|
4563
|
+
* @param self - The owning {@link Lock} instance.
|
|
4564
|
+
*/
|
|
4528
4565
|
const ACQUIRE_LOCK_FN = async (self) => {
|
|
4529
4566
|
while (self[GET_BUSY_SYMBOL]()) {
|
|
4530
|
-
|
|
4567
|
+
// @ts-ignore
|
|
4568
|
+
await self._tick.toPromise();
|
|
4531
4569
|
}
|
|
4532
4570
|
self[SET_BUSY_SYMBOL](true);
|
|
4533
4571
|
};
|
|
4534
4572
|
/**
|
|
4535
4573
|
* Mutual exclusion primitive for async TypeScript code.
|
|
4536
4574
|
*
|
|
4537
|
-
* Provides a
|
|
4538
|
-
*
|
|
4539
|
-
*
|
|
4540
|
-
*
|
|
4575
|
+
* Provides a queued lock that serializes access to a critical section across
|
|
4576
|
+
* concurrent async callers. Wake-ups are event-driven (via an internal
|
|
4577
|
+
* `_tick` subject emitted on every `releaseLock`) rather than polling,
|
|
4578
|
+
* so contention does not incur a fixed delay.
|
|
4541
4579
|
*
|
|
4542
|
-
*
|
|
4580
|
+
* The busy counter detects mis-matched releases and throws immediately on
|
|
4581
|
+
* extra `releaseLock` calls.
|
|
4543
4582
|
*
|
|
4544
|
-
* **
|
|
4583
|
+
* **Usage**
|
|
4545
4584
|
* ```ts
|
|
4546
4585
|
* await lock.acquireLock();
|
|
4547
4586
|
* try {
|
|
@@ -4556,7 +4595,18 @@ const ACQUIRE_LOCK_FN = async (self) => {
|
|
|
4556
4595
|
*/
|
|
4557
4596
|
class Lock {
|
|
4558
4597
|
constructor() {
|
|
4598
|
+
/**
|
|
4599
|
+
* Outstanding acquires that have not yet been released.
|
|
4600
|
+
* Incremented in `[SET_BUSY_SYMBOL](true)`, decremented in `[SET_BUSY_SYMBOL](false)`.
|
|
4601
|
+
* A negative value indicates an extra `releaseLock` and throws on detection.
|
|
4602
|
+
*/
|
|
4559
4603
|
this._isBusy = 0;
|
|
4604
|
+
/**
|
|
4605
|
+
* Wake-up channel for {@link ACQUIRE_LOCK_FN}.
|
|
4606
|
+
* Every {@link releaseLock} emits a single tick that unblocks the next
|
|
4607
|
+
* queued acquirer parked on `toPromise()`.
|
|
4608
|
+
*/
|
|
4609
|
+
this._tick = new functoolsKit.Subject();
|
|
4560
4610
|
this[_a$2] = functoolsKit.queued(ACQUIRE_LOCK_FN);
|
|
4561
4611
|
this[_b$2] = () => this[SET_BUSY_SYMBOL](false);
|
|
4562
4612
|
/**
|
|
@@ -4577,16 +4627,19 @@ class Lock {
|
|
|
4577
4627
|
await this[ACQUIRE_LOCK_SYMBOL](this);
|
|
4578
4628
|
};
|
|
4579
4629
|
/**
|
|
4580
|
-
* Releases the lock previously acquired with {@link acquireLock}
|
|
4630
|
+
* Releases the lock previously acquired with {@link acquireLock} and emits
|
|
4631
|
+
* on the internal `_tick` subject to wake the next queued acquirer.
|
|
4632
|
+
*
|
|
4581
4633
|
* Must be called exactly once per successful {@link acquireLock} call,
|
|
4582
|
-
* typically inside a `finally` block. Throws if called more times
|
|
4583
|
-
*
|
|
4634
|
+
* typically inside a `finally` block. Throws if called more times than
|
|
4635
|
+
* the lock was acquired.
|
|
4584
4636
|
*
|
|
4585
4637
|
* @returns {Promise<void>} Resolves once the lock has been released.
|
|
4586
4638
|
* @throws {Error} If the lock is released more times than it was acquired.
|
|
4587
4639
|
*/
|
|
4588
4640
|
this.releaseLock = async () => {
|
|
4589
4641
|
await this[RELEASE_LOCK_SYMBOL]();
|
|
4642
|
+
await this._tick.next();
|
|
4590
4643
|
};
|
|
4591
4644
|
}
|
|
4592
4645
|
[SET_BUSY_SYMBOL](isBusy) {
|
|
@@ -4601,18 +4654,166 @@ class Lock {
|
|
|
4601
4654
|
}
|
|
4602
4655
|
_a$2 = ACQUIRE_LOCK_SYMBOL, _b$2 = RELEASE_LOCK_SYMBOL;
|
|
4603
4656
|
|
|
4657
|
+
const METHOD_NAME_ADD_ACTIVITY = "LookupUtils.addActivity";
|
|
4658
|
+
const METHOD_NAME_REMOVE_ACTIVITY = "LookupUtils.removeActivity";
|
|
4659
|
+
const METHOD_NAME_LIST_ACTIVITY = "LookupUtils.listActivity";
|
|
4660
|
+
/** Logger service injected as DI singleton */
|
|
4661
|
+
const LOGGER_SERVICE$7 = new LoggerService();
|
|
4662
|
+
/**
|
|
4663
|
+
* Builds the composite {@link Key} used to register an activity in `_lookupMap`.
|
|
4664
|
+
*
|
|
4665
|
+
* Mirrors the {@link Key} type construction: appends `frameName` only when provided
|
|
4666
|
+
* (typical for backtest), then a `"backtest"` / `"live"` discriminator suffix.
|
|
4667
|
+
*
|
|
4668
|
+
* @param symbol - Trading pair symbol.
|
|
4669
|
+
* @param strategyName - Strategy schema name.
|
|
4670
|
+
* @param exchangeName - Exchange schema name.
|
|
4671
|
+
* @param frameName - Frame schema name; omitted from the key when falsy.
|
|
4672
|
+
* @param backtest - `true` for backtest, `false` for live.
|
|
4673
|
+
* @returns Colon-joined composite key.
|
|
4674
|
+
*/
|
|
4675
|
+
const CREATE_KEY_FN$y = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
4676
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
4677
|
+
if (frameName)
|
|
4678
|
+
parts.push(frameName);
|
|
4679
|
+
parts.push(backtest ? "backtest" : "live");
|
|
4680
|
+
return parts.join(":");
|
|
4681
|
+
};
|
|
4682
|
+
/**
|
|
4683
|
+
* In-memory registry of currently running backtest and live activities.
|
|
4684
|
+
*
|
|
4685
|
+
* Purpose:
|
|
4686
|
+
* - Each `Backtest.run` / `Live.run` / per-strategy walker iteration registers an
|
|
4687
|
+
* {@link IActivityEntry} on start and removes it on completion.
|
|
4688
|
+
* - `Candle.spinLock` consults {@link isParallel} to decide whether the event-loop
|
|
4689
|
+
* hand-off (post-candle-fetch spin) is worth performing. With a single active
|
|
4690
|
+
* workload there is no peer to yield to, so the spin is skipped entirely.
|
|
4691
|
+
*
|
|
4692
|
+
* Exposed as the `Lookup` singleton; no constructor parameters.
|
|
4693
|
+
*
|
|
4694
|
+
* @example
|
|
4695
|
+
* ```typescript
|
|
4696
|
+
* Lookup.addActivity({ symbol: "BTCUSDT", context, backtest: true });
|
|
4697
|
+
* try {
|
|
4698
|
+
* for await (const _ of run(symbol, context)) { ... }
|
|
4699
|
+
* } finally {
|
|
4700
|
+
* Lookup.removeActivity({ symbol: "BTCUSDT", context, backtest: true });
|
|
4701
|
+
* }
|
|
4702
|
+
* ```
|
|
4703
|
+
*/
|
|
4704
|
+
class LookupUtils {
|
|
4705
|
+
constructor() {
|
|
4706
|
+
/** Active entries keyed by their composite {@link Key}. */
|
|
4707
|
+
this._lookupMap = new Map();
|
|
4708
|
+
/**
|
|
4709
|
+
* Registers a backtest or live activity in the lookup map.
|
|
4710
|
+
* Idempotent for identical keys — duplicate calls overwrite the existing entry.
|
|
4711
|
+
*
|
|
4712
|
+
* @param activity - Activity descriptor identifying the running workload.
|
|
4713
|
+
*/
|
|
4714
|
+
this.addActivity = (activity) => {
|
|
4715
|
+
LOGGER_SERVICE$7.info(METHOD_NAME_ADD_ACTIVITY, {
|
|
4716
|
+
activity,
|
|
4717
|
+
});
|
|
4718
|
+
const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
|
|
4719
|
+
this._lookupMap.set(key, activity);
|
|
4720
|
+
};
|
|
4721
|
+
/**
|
|
4722
|
+
* Removes a previously registered activity from the lookup map.
|
|
4723
|
+
* Must be paired with a prior {@link addActivity}, typically in a `finally` block,
|
|
4724
|
+
* so a thrown error in the underlying run does not leave a stale entry behind.
|
|
4725
|
+
*
|
|
4726
|
+
* @param activity - Activity descriptor matching the one passed to {@link addActivity}.
|
|
4727
|
+
*/
|
|
4728
|
+
this.removeActivity = (activity) => {
|
|
4729
|
+
LOGGER_SERVICE$7.info(METHOD_NAME_REMOVE_ACTIVITY, {
|
|
4730
|
+
activity,
|
|
4731
|
+
});
|
|
4732
|
+
const key = CREATE_KEY_FN$y(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
|
|
4733
|
+
this._lookupMap.delete(key);
|
|
4734
|
+
};
|
|
4735
|
+
/**
|
|
4736
|
+
* Returns a snapshot of currently active entries.
|
|
4737
|
+
*
|
|
4738
|
+
* @returns Array of all activities present in the lookup map at call time.
|
|
4739
|
+
*/
|
|
4740
|
+
this.listActivity = () => {
|
|
4741
|
+
LOGGER_SERVICE$7.info(METHOD_NAME_LIST_ACTIVITY);
|
|
4742
|
+
return Array.from(this._lookupMap.values());
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
/**
|
|
4746
|
+
* `true` when more than one activity is currently registered.
|
|
4747
|
+
* Used by `Candle.spinLock` to decide whether yielding the event loop is useful.
|
|
4748
|
+
*/
|
|
4749
|
+
get isParallel() {
|
|
4750
|
+
return this._lookupMap.size > 1;
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
/**
|
|
4754
|
+
* Process-wide singleton instance of {@link LookupUtils}.
|
|
4755
|
+
* Imported by `Backtest`, `Live`, `WalkerLogicPrivateService` (registration sites)
|
|
4756
|
+
* and by `Candle` (read-only consumer via `isParallel`).
|
|
4757
|
+
*/
|
|
4758
|
+
const Lookup = new LookupUtils();
|
|
4759
|
+
|
|
4604
4760
|
const METHOD_NAME_ACQUIRE_LOCK = "CandleUtils.acquireLock";
|
|
4605
4761
|
const METHOD_NAME_RELEASE_LOCK = "CandleUtils.releaseLock";
|
|
4762
|
+
const METHOD_NAME_SPIN_LOCK = "CandleUtils.spinLock";
|
|
4763
|
+
/**
|
|
4764
|
+
* Upper bound (ms) on how long `spinLock` may park before falling through.
|
|
4765
|
+
* If no peer backtest acquires the candle-fetch mutex within this window,
|
|
4766
|
+
* the spinner proceeds without further yielding.
|
|
4767
|
+
*/
|
|
4768
|
+
const ROTATE_DELAY = 50;
|
|
4606
4769
|
/** Logger service injected as DI singleton */
|
|
4607
4770
|
const LOGGER_SERVICE$6 = new LoggerService();
|
|
4771
|
+
/**
|
|
4772
|
+
* Process-wide coordinator for candle-fetch serialization and cooperative
|
|
4773
|
+
* yielding between parallel backtests.
|
|
4774
|
+
*
|
|
4775
|
+
* Two complementary primitives are exposed:
|
|
4776
|
+
* - **Mutex** via {@link acquireLock} / {@link releaseLock}: prevents concurrent
|
|
4777
|
+
* candle fetches from racing on the same exchange.
|
|
4778
|
+
* - **Spin hand-off** via {@link spinLock}: invoked after a fetch completes to
|
|
4779
|
+
* give peer backtests waiting on the mutex a chance to run, so multiple
|
|
4780
|
+
* `Backtest.run` workloads interleave instead of one monopolizing the loop.
|
|
4781
|
+
*
|
|
4782
|
+
* All three operations are no-ops when `CC_ENABLE_CANDLE_FETCH_MUTEX` is `false`.
|
|
4783
|
+
* The spin additionally requires `CC_ENABLE_BACKTEST_PARALLEL_SPIN` and at least
|
|
4784
|
+
* two registered activities in `Lookup` (see `Lookup.isParallel`).
|
|
4785
|
+
*
|
|
4786
|
+
* @example
|
|
4787
|
+
* ```typescript
|
|
4788
|
+
* await Candle.acquireLock("ClientExchange GET_CANDLES_FN");
|
|
4789
|
+
* try {
|
|
4790
|
+
* const candles = await fetchFromExchange(...);
|
|
4791
|
+
* return candles;
|
|
4792
|
+
* } finally {
|
|
4793
|
+
* await Candle.releaseLock("ClientExchange GET_CANDLES_FN");
|
|
4794
|
+
* }
|
|
4795
|
+
* // Elsewhere, after a fetch completes inside a backtest loop:
|
|
4796
|
+
* await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
|
|
4797
|
+
* ```
|
|
4798
|
+
*/
|
|
4608
4799
|
class CandleUtils {
|
|
4609
4800
|
constructor() {
|
|
4801
|
+
/** Underlying mutex serializing candle fetches across concurrent callers. */
|
|
4610
4802
|
this._lock = new Lock();
|
|
4611
4803
|
/**
|
|
4612
|
-
*
|
|
4804
|
+
* Emits whenever {@link acquireLock} successfully takes the mutex.
|
|
4805
|
+
* Awaited by {@link spinLock} to detect that a peer backtest has just
|
|
4806
|
+
* started its own fetch — the signal that yielding now will be productive.
|
|
4807
|
+
*/
|
|
4808
|
+
this._spin = new functoolsKit.Subject();
|
|
4809
|
+
/**
|
|
4810
|
+
* Acquires the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
|
|
4613
4811
|
* Prevents concurrent candle fetches from the same exchange.
|
|
4614
4812
|
*
|
|
4615
|
-
*
|
|
4813
|
+
* On successful acquisition, emits on the internal spin subject so any
|
|
4814
|
+
* peer parked inside {@link spinLock} can wake up and proceed.
|
|
4815
|
+
*
|
|
4816
|
+
* @param source - Caller identifier for logging.
|
|
4616
4817
|
*/
|
|
4617
4818
|
this.acquireLock = async (source) => {
|
|
4618
4819
|
LOGGER_SERVICE$6.info(METHOD_NAME_ACQUIRE_LOCK, {
|
|
@@ -4621,13 +4822,14 @@ class CandleUtils {
|
|
|
4621
4822
|
if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
|
|
4622
4823
|
return;
|
|
4623
4824
|
}
|
|
4624
|
-
|
|
4825
|
+
await this._lock.acquireLock();
|
|
4826
|
+
await this._spin.next();
|
|
4625
4827
|
};
|
|
4626
4828
|
/**
|
|
4627
|
-
* Releases the candle fetch mutex if CC_ENABLE_CANDLE_FETCH_MUTEX is enabled.
|
|
4628
|
-
* Must be called after acquireLock, typically in a finally block.
|
|
4829
|
+
* Releases the candle fetch mutex if `CC_ENABLE_CANDLE_FETCH_MUTEX` is enabled.
|
|
4830
|
+
* Must be called after {@link acquireLock}, typically in a `finally` block.
|
|
4629
4831
|
*
|
|
4630
|
-
* @param source - Caller identifier for logging
|
|
4832
|
+
* @param source - Caller identifier for logging.
|
|
4631
4833
|
*/
|
|
4632
4834
|
this.releaseLock = async (source) => {
|
|
4633
4835
|
LOGGER_SERVICE$6.info(METHOD_NAME_RELEASE_LOCK, {
|
|
@@ -4638,8 +4840,47 @@ class CandleUtils {
|
|
|
4638
4840
|
}
|
|
4639
4841
|
return await this._lock.releaseLock();
|
|
4640
4842
|
};
|
|
4843
|
+
/**
|
|
4844
|
+
* Cooperative event-loop hand-off invoked by `BacktestLogicPrivateService`
|
|
4845
|
+
* after a successful `getNextCandles`. Allows peer backtests waiting on the
|
|
4846
|
+
* candle-fetch mutex to run before the current backtest fetches the next chunk.
|
|
4847
|
+
*
|
|
4848
|
+
* Waits for one of:
|
|
4849
|
+
* - a peer calling {@link acquireLock} (signalled via the spin subject), or
|
|
4850
|
+
* - a `ROTATE_DELAY` ms timeout, so the caller never parks indefinitely.
|
|
4851
|
+
*
|
|
4852
|
+
* Returns immediately as a no-op when any of these is true:
|
|
4853
|
+
* - `CC_ENABLE_CANDLE_FETCH_MUTEX` is disabled (mutex is off entirely),
|
|
4854
|
+
* - `CC_ENABLE_BACKTEST_PARALLEL_SPIN` is disabled (cooperative yielding off),
|
|
4855
|
+
* - `Lookup.isParallel` is `false` (only one active workload — no peer to yield to).
|
|
4856
|
+
*
|
|
4857
|
+
* @param source - Caller identifier for logging.
|
|
4858
|
+
*/
|
|
4859
|
+
this.spinLock = async (source) => {
|
|
4860
|
+
LOGGER_SERVICE$6.info(METHOD_NAME_SPIN_LOCK, {
|
|
4861
|
+
source,
|
|
4862
|
+
});
|
|
4863
|
+
if (!GLOBAL_CONFIG.CC_ENABLE_CANDLE_FETCH_MUTEX) {
|
|
4864
|
+
return;
|
|
4865
|
+
}
|
|
4866
|
+
if (!GLOBAL_CONFIG.CC_ENABLE_BACKTEST_PARALLEL_SPIN) {
|
|
4867
|
+
return;
|
|
4868
|
+
}
|
|
4869
|
+
if (!Lookup.isParallel) {
|
|
4870
|
+
return;
|
|
4871
|
+
}
|
|
4872
|
+
await Promise.race([
|
|
4873
|
+
this._spin.toPromise(),
|
|
4874
|
+
functoolsKit.sleep(ROTATE_DELAY),
|
|
4875
|
+
]);
|
|
4876
|
+
};
|
|
4641
4877
|
}
|
|
4642
4878
|
}
|
|
4879
|
+
/**
|
|
4880
|
+
* Process-wide singleton instance of {@link CandleUtils}.
|
|
4881
|
+
* Imported by `ClientExchange` (mutex around exchange fetches) and by
|
|
4882
|
+
* `BacktestLogicPrivateService` (spin hand-off between parallel backtests).
|
|
4883
|
+
*/
|
|
4643
4884
|
const Candle = new CandleUtils();
|
|
4644
4885
|
|
|
4645
4886
|
const MS_PER_MINUTE$7 = 60000;
|
|
@@ -19173,9 +19414,28 @@ const TICK_FN = async (self, symbol, when) => {
|
|
|
19173
19414
|
return { type: "error", __error__: SYMBOL_FN_ERROR, reason: "TICK_FN", message: functoolsKit.getErrorMessage(error) };
|
|
19174
19415
|
}
|
|
19175
19416
|
};
|
|
19417
|
+
/**
|
|
19418
|
+
* Wraps `exchangeCoreService.getNextCandles` with error capture and a cooperative
|
|
19419
|
+
* event-loop hand-off after a successful fetch.
|
|
19420
|
+
*
|
|
19421
|
+
* Calls `Candle.spinLock(...)` on success: when multiple backtests run in parallel
|
|
19422
|
+
* (`Lookup.isParallel === true`), this yields the event loop so a peer waiting on
|
|
19423
|
+
* the candle-fetch mutex can take its turn, producing round-robin interleaving
|
|
19424
|
+
* instead of one backtest monopolizing the loop until completion. The spin is a
|
|
19425
|
+
* no-op for single-workload runs.
|
|
19426
|
+
*
|
|
19427
|
+
* @param self - Owning service instance, used for logging and exchange access.
|
|
19428
|
+
* @param symbol - Trading pair symbol.
|
|
19429
|
+
* @param candlesNeeded - Number of 1m candles to request.
|
|
19430
|
+
* @param bufferStartTime - Inclusive start time for the fetch window.
|
|
19431
|
+
* @param logMeta - Extra structured fields appended to the warn log on failure.
|
|
19432
|
+
* @returns Fetched candles, or a {@link TFnError} discriminated union on failure.
|
|
19433
|
+
*/
|
|
19176
19434
|
const GET_CANDLES_FN = async (self, symbol, candlesNeeded, bufferStartTime, logMeta) => {
|
|
19177
19435
|
try {
|
|
19178
|
-
|
|
19436
|
+
const result = await self.exchangeCoreService.getNextCandles(symbol, "1m", candlesNeeded, bufferStartTime, true);
|
|
19437
|
+
await Candle.spinLock("BacktestLogicPrivateService GET_CANDLES_FN");
|
|
19438
|
+
return result;
|
|
19179
19439
|
}
|
|
19180
19440
|
catch (error) {
|
|
19181
19441
|
console.error(`backtestLogicPrivateService getNextCandles failed symbol=${symbol} strategyName=${self.methodContextService.context.strategyName} exchangeName=${self.methodContextService.context.exchangeName}`);
|
|
@@ -20061,6 +20321,15 @@ class WalkerLogicPrivateService {
|
|
|
20061
20321
|
exchangeName: context.exchangeName,
|
|
20062
20322
|
frameName: context.frameName,
|
|
20063
20323
|
});
|
|
20324
|
+
Lookup.addActivity({
|
|
20325
|
+
symbol,
|
|
20326
|
+
context: {
|
|
20327
|
+
strategyName,
|
|
20328
|
+
exchangeName: context.exchangeName,
|
|
20329
|
+
frameName: context.frameName,
|
|
20330
|
+
},
|
|
20331
|
+
backtest: true,
|
|
20332
|
+
});
|
|
20064
20333
|
try {
|
|
20065
20334
|
await functoolsKit.resolveDocuments(iterator);
|
|
20066
20335
|
}
|
|
@@ -20076,6 +20345,17 @@ class WalkerLogicPrivateService {
|
|
|
20076
20345
|
await CALL_STRATEGY_ERROR_CALLBACKS_FN(this, walkerSchema, strategyName, symbol, error);
|
|
20077
20346
|
continue;
|
|
20078
20347
|
}
|
|
20348
|
+
finally {
|
|
20349
|
+
Lookup.removeActivity({
|
|
20350
|
+
symbol,
|
|
20351
|
+
context: {
|
|
20352
|
+
strategyName,
|
|
20353
|
+
exchangeName: context.exchangeName,
|
|
20354
|
+
frameName: context.frameName,
|
|
20355
|
+
},
|
|
20356
|
+
backtest: true,
|
|
20357
|
+
});
|
|
20358
|
+
}
|
|
20079
20359
|
this.loggerService.info("walkerLogicPrivateService backtest complete", {
|
|
20080
20360
|
strategyName,
|
|
20081
20361
|
symbol,
|
|
@@ -20152,6 +20432,110 @@ class WalkerLogicPrivateService {
|
|
|
20152
20432
|
}
|
|
20153
20433
|
}
|
|
20154
20434
|
|
|
20435
|
+
/**
|
|
20436
|
+
* Run iterator function for backtest logic.
|
|
20437
|
+
*
|
|
20438
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20439
|
+
* @param context - Execution context with strategy, exchange, and frame names
|
|
20440
|
+
* @param self - Instance of BacktestLogicPublicService
|
|
20441
|
+
* @returns Async iterator for backtest results
|
|
20442
|
+
*/
|
|
20443
|
+
const RUN_ITERATOR_FN$1 = (self, symbol, context) => {
|
|
20444
|
+
return MethodContextService.runAsyncIterator(self.backtestLogicPrivateService.run(symbol), {
|
|
20445
|
+
exchangeName: context.exchangeName,
|
|
20446
|
+
strategyName: context.strategyName,
|
|
20447
|
+
frameName: context.frameName,
|
|
20448
|
+
});
|
|
20449
|
+
};
|
|
20450
|
+
/**
|
|
20451
|
+
* Call before start execution for backtest logic.
|
|
20452
|
+
* This function is responsible for triggering the beforeStartSubject
|
|
20453
|
+
* with the appropriate context and symbol information.
|
|
20454
|
+
*/
|
|
20455
|
+
const CALL_BEFORE_START_FN$1 = functoolsKit.trycatch(async (self, symbol, context) => {
|
|
20456
|
+
const { startDate } = self.frameSchemaService.get(context.frameName);
|
|
20457
|
+
const when = alignToInterval(startDate, "1m");
|
|
20458
|
+
await MethodContextService.runInContext(async () => {
|
|
20459
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20460
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20461
|
+
await beforeStartSubject.next({
|
|
20462
|
+
symbol,
|
|
20463
|
+
exchangeName: context.exchangeName,
|
|
20464
|
+
strategyName: context.strategyName,
|
|
20465
|
+
frameName: context.frameName,
|
|
20466
|
+
backtest: true,
|
|
20467
|
+
when,
|
|
20468
|
+
timestamp: when.getTime(),
|
|
20469
|
+
currentPrice,
|
|
20470
|
+
});
|
|
20471
|
+
}, {
|
|
20472
|
+
symbol,
|
|
20473
|
+
when,
|
|
20474
|
+
backtest: true,
|
|
20475
|
+
});
|
|
20476
|
+
}, {
|
|
20477
|
+
exchangeName: context.exchangeName,
|
|
20478
|
+
strategyName: context.strategyName,
|
|
20479
|
+
frameName: context.frameName,
|
|
20480
|
+
});
|
|
20481
|
+
}, {
|
|
20482
|
+
fallback: (error, self) => {
|
|
20483
|
+
const message = "BacktestLogicPublicService CALL_BEFORE_START_FN thrown";
|
|
20484
|
+
const payload = {
|
|
20485
|
+
error: functoolsKit.errorData(error),
|
|
20486
|
+
message: functoolsKit.getErrorMessage(error),
|
|
20487
|
+
};
|
|
20488
|
+
self.loggerService.warn(message, payload);
|
|
20489
|
+
console.error(message, payload);
|
|
20490
|
+
errorEmitter.next(error);
|
|
20491
|
+
},
|
|
20492
|
+
});
|
|
20493
|
+
/**
|
|
20494
|
+
* Call after end execution for backtest logic.
|
|
20495
|
+
* This function is responsible for triggering the afterEndSubject
|
|
20496
|
+
* with the appropriate context and symbol information.
|
|
20497
|
+
*/
|
|
20498
|
+
const CALL_AFTER_END_FN$1 = functoolsKit.trycatch(async (self, symbol, context) => {
|
|
20499
|
+
const { startDate } = self.frameSchemaService.get(context.frameName);
|
|
20500
|
+
const timestamp = self.timeMetaService.hasTimestamp(symbol, context, true)
|
|
20501
|
+
? await self.timeMetaService.getTimestamp(symbol, context, true)
|
|
20502
|
+
: startDate.getTime();
|
|
20503
|
+
const when = new Date(timestamp);
|
|
20504
|
+
await MethodContextService.runInContext(async () => {
|
|
20505
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20506
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20507
|
+
await afterEndSubject.next({
|
|
20508
|
+
symbol,
|
|
20509
|
+
exchangeName: context.exchangeName,
|
|
20510
|
+
strategyName: context.strategyName,
|
|
20511
|
+
frameName: context.frameName,
|
|
20512
|
+
backtest: true,
|
|
20513
|
+
when,
|
|
20514
|
+
timestamp,
|
|
20515
|
+
currentPrice,
|
|
20516
|
+
});
|
|
20517
|
+
}, {
|
|
20518
|
+
symbol,
|
|
20519
|
+
when,
|
|
20520
|
+
backtest: true,
|
|
20521
|
+
});
|
|
20522
|
+
}, {
|
|
20523
|
+
exchangeName: context.exchangeName,
|
|
20524
|
+
strategyName: context.strategyName,
|
|
20525
|
+
frameName: context.frameName,
|
|
20526
|
+
});
|
|
20527
|
+
}, {
|
|
20528
|
+
fallback: (error, self) => {
|
|
20529
|
+
const message = "BacktestLogicPublicService CALL_AFTER_END_FN thrown";
|
|
20530
|
+
const payload = {
|
|
20531
|
+
error: functoolsKit.errorData(error),
|
|
20532
|
+
message: functoolsKit.getErrorMessage(error),
|
|
20533
|
+
};
|
|
20534
|
+
self.loggerService.warn(message, payload);
|
|
20535
|
+
console.error(message, payload);
|
|
20536
|
+
errorEmitter.next(error);
|
|
20537
|
+
},
|
|
20538
|
+
});
|
|
20155
20539
|
/**
|
|
20156
20540
|
* Public service for backtest orchestration with context management.
|
|
20157
20541
|
*
|
|
@@ -20180,30 +20564,134 @@ class BacktestLogicPublicService {
|
|
|
20180
20564
|
constructor() {
|
|
20181
20565
|
this.loggerService = inject(TYPES.loggerService);
|
|
20182
20566
|
this.backtestLogicPrivateService = inject(TYPES.backtestLogicPrivateService);
|
|
20183
|
-
|
|
20184
|
-
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20188
|
-
|
|
20189
|
-
|
|
20190
|
-
|
|
20191
|
-
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20567
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
20568
|
+
this.frameSchemaService = inject(TYPES.frameSchemaService);
|
|
20569
|
+
this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
|
|
20570
|
+
}
|
|
20571
|
+
/**
|
|
20572
|
+
* Runs backtest for a symbol with context propagation.
|
|
20573
|
+
*
|
|
20574
|
+
* Streams closed signals as async generator. Context is automatically
|
|
20575
|
+
* injected into all framework functions called during iteration.
|
|
20576
|
+
*
|
|
20577
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20578
|
+
* @param context - Execution context with strategy, exchange, and frame names
|
|
20579
|
+
* @returns Async generator yielding closed signals with PNL
|
|
20580
|
+
*/
|
|
20581
|
+
async *run(symbol, context) {
|
|
20582
|
+
this.loggerService.log("backtestLogicPublicService run", {
|
|
20583
|
+
symbol,
|
|
20584
|
+
context,
|
|
20585
|
+
});
|
|
20586
|
+
await CALL_BEFORE_START_FN$1(this, symbol, context);
|
|
20587
|
+
try {
|
|
20588
|
+
yield* RUN_ITERATOR_FN$1(this, symbol, context);
|
|
20589
|
+
}
|
|
20590
|
+
finally {
|
|
20591
|
+
await CALL_AFTER_END_FN$1(this, symbol, context);
|
|
20592
|
+
}
|
|
20593
|
+
}
|
|
20594
|
+
}
|
|
20595
|
+
|
|
20596
|
+
/**
|
|
20597
|
+
* Run iterator function for live logic.
|
|
20598
|
+
*
|
|
20599
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20600
|
+
* @param context - Execution context with strategy and exchange names
|
|
20601
|
+
* @param self - Instance of LiveLogicPublicService
|
|
20602
|
+
* @returns Async iterator for live trading results
|
|
20603
|
+
*/
|
|
20604
|
+
const RUN_ITERATOR_FN = (self, symbol, context) => {
|
|
20605
|
+
return MethodContextService.runAsyncIterator(self.liveLogicPrivateService.run(symbol), {
|
|
20606
|
+
exchangeName: context.exchangeName,
|
|
20607
|
+
strategyName: context.strategyName,
|
|
20608
|
+
frameName: "",
|
|
20609
|
+
});
|
|
20610
|
+
};
|
|
20611
|
+
/**
|
|
20612
|
+
* Call before start execution for live logic.
|
|
20613
|
+
* This function is responsible for triggering the beforeStartSubject
|
|
20614
|
+
* with the appropriate context and symbol information.
|
|
20615
|
+
*/
|
|
20616
|
+
const CALL_BEFORE_START_FN = functoolsKit.trycatch(async (self, symbol, context) => {
|
|
20617
|
+
const when = alignToInterval(new Date(), "1m");
|
|
20618
|
+
await MethodContextService.runInContext(async () => {
|
|
20619
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20620
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20621
|
+
await beforeStartSubject.next({
|
|
20195
20622
|
symbol,
|
|
20196
|
-
context,
|
|
20623
|
+
exchangeName: context.exchangeName,
|
|
20624
|
+
strategyName: context.strategyName,
|
|
20625
|
+
frameName: "",
|
|
20626
|
+
backtest: false,
|
|
20627
|
+
currentPrice,
|
|
20628
|
+
when,
|
|
20629
|
+
timestamp: when.getTime(),
|
|
20197
20630
|
});
|
|
20198
|
-
|
|
20631
|
+
}, {
|
|
20632
|
+
symbol,
|
|
20633
|
+
when,
|
|
20634
|
+
backtest: false,
|
|
20635
|
+
});
|
|
20636
|
+
}, {
|
|
20637
|
+
exchangeName: context.exchangeName,
|
|
20638
|
+
strategyName: context.strategyName,
|
|
20639
|
+
frameName: "",
|
|
20640
|
+
});
|
|
20641
|
+
}, {
|
|
20642
|
+
fallback: (error, self) => {
|
|
20643
|
+
const message = "LiveLogicPublicService CALL_BEFORE_START_FN thrown";
|
|
20644
|
+
const payload = {
|
|
20645
|
+
error: functoolsKit.errorData(error),
|
|
20646
|
+
message: functoolsKit.getErrorMessage(error),
|
|
20647
|
+
};
|
|
20648
|
+
self.loggerService.warn(message, payload);
|
|
20649
|
+
console.error(message, payload);
|
|
20650
|
+
errorEmitter.next(error);
|
|
20651
|
+
},
|
|
20652
|
+
});
|
|
20653
|
+
/**
|
|
20654
|
+
* Call after end execution for live logic.
|
|
20655
|
+
* This function is responsible for triggering the afterEndSubject
|
|
20656
|
+
* with the appropriate context and symbol information.
|
|
20657
|
+
*/
|
|
20658
|
+
const CALL_AFTER_END_FN = functoolsKit.trycatch(async (self, symbol, context) => {
|
|
20659
|
+
const when = alignToInterval(new Date(), "1m");
|
|
20660
|
+
await MethodContextService.runInContext(async () => {
|
|
20661
|
+
await ExecutionContextService.runInContext(async () => {
|
|
20662
|
+
const currentPrice = await self.exchangeConnectionService.getAveragePrice(symbol);
|
|
20663
|
+
await afterEndSubject.next({
|
|
20664
|
+
symbol,
|
|
20199
20665
|
exchangeName: context.exchangeName,
|
|
20200
20666
|
strategyName: context.strategyName,
|
|
20201
|
-
frameName:
|
|
20667
|
+
frameName: "",
|
|
20668
|
+
backtest: false,
|
|
20669
|
+
currentPrice,
|
|
20670
|
+
when,
|
|
20671
|
+
timestamp: when.getTime(),
|
|
20202
20672
|
});
|
|
20673
|
+
}, {
|
|
20674
|
+
symbol,
|
|
20675
|
+
when,
|
|
20676
|
+
backtest: false,
|
|
20677
|
+
});
|
|
20678
|
+
}, {
|
|
20679
|
+
exchangeName: context.exchangeName,
|
|
20680
|
+
strategyName: context.strategyName,
|
|
20681
|
+
frameName: "",
|
|
20682
|
+
});
|
|
20683
|
+
}, {
|
|
20684
|
+
fallback: (error, self) => {
|
|
20685
|
+
const message = "LiveLogicPublicService CALL_AFTER_END_FN thrown";
|
|
20686
|
+
const payload = {
|
|
20687
|
+
error: functoolsKit.errorData(error),
|
|
20688
|
+
message: functoolsKit.getErrorMessage(error),
|
|
20203
20689
|
};
|
|
20204
|
-
|
|
20205
|
-
|
|
20206
|
-
|
|
20690
|
+
self.loggerService.warn(message, payload);
|
|
20691
|
+
console.error(message, payload);
|
|
20692
|
+
errorEmitter.next(error);
|
|
20693
|
+
},
|
|
20694
|
+
});
|
|
20207
20695
|
/**
|
|
20208
20696
|
* Public service for live trading orchestration with context management.
|
|
20209
20697
|
*
|
|
@@ -20239,28 +20727,31 @@ class LiveLogicPublicService {
|
|
|
20239
20727
|
constructor() {
|
|
20240
20728
|
this.loggerService = inject(TYPES.loggerService);
|
|
20241
20729
|
this.liveLogicPrivateService = inject(TYPES.liveLogicPrivateService);
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
20252
|
-
|
|
20253
|
-
|
|
20254
|
-
|
|
20255
|
-
|
|
20256
|
-
|
|
20257
|
-
|
|
20258
|
-
|
|
20259
|
-
|
|
20260
|
-
|
|
20261
|
-
|
|
20262
|
-
|
|
20263
|
-
}
|
|
20730
|
+
this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
|
|
20731
|
+
}
|
|
20732
|
+
/**
|
|
20733
|
+
* Runs live trading for a symbol with context propagation.
|
|
20734
|
+
*
|
|
20735
|
+
* Streams opened and closed signals as infinite async generator.
|
|
20736
|
+
* Context is automatically injected into all framework functions.
|
|
20737
|
+
* Process can crash and restart - state will be recovered from disk.
|
|
20738
|
+
*
|
|
20739
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
20740
|
+
* @param context - Execution context with strategy and exchange names
|
|
20741
|
+
* @returns Infinite async generator yielding opened and closed signals
|
|
20742
|
+
*/
|
|
20743
|
+
async *run(symbol, context) {
|
|
20744
|
+
this.loggerService.log("liveLogicPublicService run", {
|
|
20745
|
+
symbol,
|
|
20746
|
+
context,
|
|
20747
|
+
});
|
|
20748
|
+
await CALL_BEFORE_START_FN(this, symbol, context);
|
|
20749
|
+
try {
|
|
20750
|
+
yield* RUN_ITERATOR_FN(this, symbol, context);
|
|
20751
|
+
}
|
|
20752
|
+
finally {
|
|
20753
|
+
await CALL_AFTER_END_FN(this, symbol, context);
|
|
20754
|
+
}
|
|
20264
20755
|
}
|
|
20265
20756
|
}
|
|
20266
20757
|
|
|
@@ -34464,6 +34955,21 @@ class TimeMetaService {
|
|
|
34464
34955
|
* Instances are cached until clear() is called.
|
|
34465
34956
|
*/
|
|
34466
34957
|
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
|
|
34958
|
+
/**
|
|
34959
|
+
* Checks if a timestamp exists for the given symbol and context.
|
|
34960
|
+
*
|
|
34961
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
34962
|
+
* @param context - Strategy, exchange, and frame identifiers
|
|
34963
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
34964
|
+
* @returns True if a timestamp is available, false otherwise
|
|
34965
|
+
*/
|
|
34966
|
+
this.hasTimestamp = (symbol, context, backtest) => {
|
|
34967
|
+
const key = CREATE_KEY_FN$a(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
34968
|
+
if (!this.getSource.has(key)) {
|
|
34969
|
+
return false;
|
|
34970
|
+
}
|
|
34971
|
+
return !!this.getSource.get(key)?.data;
|
|
34972
|
+
};
|
|
34467
34973
|
/**
|
|
34468
34974
|
* Returns the current candle timestamp (in milliseconds) for the given symbol and context.
|
|
34469
34975
|
*
|
|
@@ -36095,6 +36601,7 @@ const Exchange = new ExchangeUtils();
|
|
|
36095
36601
|
|
|
36096
36602
|
const WARM_CANDLES_METHOD_NAME = "cache.warmCandles";
|
|
36097
36603
|
const CHECK_CANDLES_METHOD_NAME = "cache.checkCandles";
|
|
36604
|
+
const CACHE_CANDLES_METHOD_NAME = "cache.cacheCandles";
|
|
36098
36605
|
const MS_PER_MINUTE$3 = 60000;
|
|
36099
36606
|
const INTERVAL_MINUTES$3 = {
|
|
36100
36607
|
"1m": 1,
|
|
@@ -36126,6 +36633,34 @@ const PRINT_PROGRESS_FN = (fetched, total, symbol, interval) => {
|
|
|
36126
36633
|
process.stdout.write("\n");
|
|
36127
36634
|
}
|
|
36128
36635
|
};
|
|
36636
|
+
/**
|
|
36637
|
+
* Retry-wrapped pipeline: validates the cache via `checkCandles` and, on miss,
|
|
36638
|
+
* fills it via `warmCandles` and rethrows to trigger a retry pass that
|
|
36639
|
+
* re-validates the freshly cached range. Limited to 2 attempts.
|
|
36640
|
+
*/
|
|
36641
|
+
const CACHE_CANDLES_FN = functoolsKit.retry(async (interval, dto, onWarmStart, onCheckStart) => {
|
|
36642
|
+
try {
|
|
36643
|
+
onCheckStart && onCheckStart(dto.symbol, interval, dto.from, dto.to);
|
|
36644
|
+
await checkCandles({
|
|
36645
|
+
exchangeName: dto.exchangeName,
|
|
36646
|
+
from: dto.from,
|
|
36647
|
+
to: dto.to,
|
|
36648
|
+
symbol: dto.symbol,
|
|
36649
|
+
interval: interval,
|
|
36650
|
+
});
|
|
36651
|
+
}
|
|
36652
|
+
catch (error) {
|
|
36653
|
+
onWarmStart && onWarmStart(dto.symbol, interval, dto.from, dto.to);
|
|
36654
|
+
await warmCandles({
|
|
36655
|
+
symbol: dto.symbol,
|
|
36656
|
+
exchangeName: dto.exchangeName,
|
|
36657
|
+
from: dto.from,
|
|
36658
|
+
to: dto.to,
|
|
36659
|
+
interval: interval,
|
|
36660
|
+
});
|
|
36661
|
+
throw error;
|
|
36662
|
+
}
|
|
36663
|
+
}, 2);
|
|
36129
36664
|
/**
|
|
36130
36665
|
* Checks cached candle presence via the persist adapter.
|
|
36131
36666
|
* Issues one ranged read; adapter-side `hasValue` covers each expected timestamp,
|
|
@@ -36201,6 +36736,34 @@ async function warmCandles(params) {
|
|
|
36201
36736
|
PRINT_PROGRESS_FN(fetched, totalCandles, symbol, interval);
|
|
36202
36737
|
}
|
|
36203
36738
|
}
|
|
36739
|
+
/**
|
|
36740
|
+
* Ensures candles for the given range are present in persist storage.
|
|
36741
|
+
* Runs a check-then-warm pipeline with one retry: validates the cache first
|
|
36742
|
+
* and, on a miss, downloads the missing data and re-validates.
|
|
36743
|
+
*
|
|
36744
|
+
* @param params - Combined cache parameters with optional lifecycle callbacks
|
|
36745
|
+
*/
|
|
36746
|
+
async function cacheCandles({ symbol, interval, from, to, exchangeName, onCheckStart = (symbol, interval, from, to) => {
|
|
36747
|
+
process.stdout.write("\n");
|
|
36748
|
+
process.stdout.write(`Checking candles cache for ${symbol} ${interval} from ${from} to ${to}\n`);
|
|
36749
|
+
}, onWarmStart = (symbol, interval, from, to) => {
|
|
36750
|
+
process.stdout.write("\n\n");
|
|
36751
|
+
process.stdout.write(`Caching candles for ${symbol} ${interval} from ${from} to ${to}\n`);
|
|
36752
|
+
}, }) {
|
|
36753
|
+
backtest.loggerService.info(CACHE_CANDLES_METHOD_NAME, {
|
|
36754
|
+
symbol,
|
|
36755
|
+
exchangeName,
|
|
36756
|
+
interval,
|
|
36757
|
+
from,
|
|
36758
|
+
to,
|
|
36759
|
+
});
|
|
36760
|
+
await CACHE_CANDLES_FN(interval, {
|
|
36761
|
+
exchangeName,
|
|
36762
|
+
from,
|
|
36763
|
+
to,
|
|
36764
|
+
symbol,
|
|
36765
|
+
}, onWarmStart, onCheckStart);
|
|
36766
|
+
}
|
|
36204
36767
|
|
|
36205
36768
|
const METHOD_NAME = "validate.validate";
|
|
36206
36769
|
/**
|
|
@@ -36620,11 +37183,6 @@ const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
|
36620
37183
|
const GET_CLOSE_PRICE_METHOD_NAME = "exchange.getClosePrice";
|
|
36621
37184
|
const FORMAT_PRICE_METHOD_NAME = "exchange.formatPrice";
|
|
36622
37185
|
const FORMAT_QUANTITY_METHOD_NAME = "exchange.formatQuantity";
|
|
36623
|
-
const GET_DATE_METHOD_NAME = "exchange.getDate";
|
|
36624
|
-
const GET_TIMESTAMP_METHOD_NAME = "exchange.getTimestamp";
|
|
36625
|
-
const GET_MODE_METHOD_NAME = "exchange.getMode";
|
|
36626
|
-
const GET_SYMBOL_METHOD_NAME = "exchange.getSymbol";
|
|
36627
|
-
const GET_CONTEXT_METHOD_NAME = "exchange.getContext";
|
|
36628
37186
|
const HAS_TRADE_CONTEXT_METHOD_NAME = "exchange.hasTradeContext";
|
|
36629
37187
|
const GET_ORDER_BOOK_METHOD_NAME = "exchange.getOrderBook";
|
|
36630
37188
|
const GET_RAW_CANDLES_METHOD_NAME = "exchange.getRawCandles";
|
|
@@ -36791,113 +37349,6 @@ async function formatQuantity(symbol, quantity) {
|
|
|
36791
37349
|
}
|
|
36792
37350
|
return await backtest.exchangeConnectionService.formatQuantity(symbol, quantity);
|
|
36793
37351
|
}
|
|
36794
|
-
/**
|
|
36795
|
-
* Gets the current date from execution context.
|
|
36796
|
-
*
|
|
36797
|
-
* In backtest mode: returns the current timeframe date being processed
|
|
36798
|
-
* In live mode: returns current real-time date
|
|
36799
|
-
*
|
|
36800
|
-
* @returns Promise resolving to current execution context date
|
|
36801
|
-
*
|
|
36802
|
-
* @example
|
|
36803
|
-
* ```typescript
|
|
36804
|
-
* const date = await getDate();
|
|
36805
|
-
* console.log(date); // 2024-01-01T12:00:00.000Z
|
|
36806
|
-
* ```
|
|
36807
|
-
*/
|
|
36808
|
-
async function getDate() {
|
|
36809
|
-
backtest.loggerService.info(GET_DATE_METHOD_NAME);
|
|
36810
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36811
|
-
throw new Error("getDate requires an execution context");
|
|
36812
|
-
}
|
|
36813
|
-
const { when } = backtest.executionContextService.context;
|
|
36814
|
-
return new Date(when.getTime());
|
|
36815
|
-
}
|
|
36816
|
-
/**
|
|
36817
|
-
* Gets the current timestamp from execution context.
|
|
36818
|
-
*
|
|
36819
|
-
* In backtest mode: returns the current timeframe timestamp being processed
|
|
36820
|
-
* In live mode: returns current real-time timestamp
|
|
36821
|
-
*
|
|
36822
|
-
* @returns Promise resolving to current execution context timestamp in milliseconds
|
|
36823
|
-
* @example
|
|
36824
|
-
* ```typescript
|
|
36825
|
-
* const timestamp = await getTimestamp();
|
|
36826
|
-
* console.log(timestamp); // 1700000000000
|
|
36827
|
-
* ```
|
|
36828
|
-
*/
|
|
36829
|
-
async function getTimestamp() {
|
|
36830
|
-
backtest.loggerService.info(GET_TIMESTAMP_METHOD_NAME);
|
|
36831
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36832
|
-
throw new Error("getTimestamp requires an execution context");
|
|
36833
|
-
}
|
|
36834
|
-
return getContextTimestamp();
|
|
36835
|
-
}
|
|
36836
|
-
/**
|
|
36837
|
-
* Gets the current execution mode.
|
|
36838
|
-
*
|
|
36839
|
-
* @returns Promise resolving to "backtest" or "live"
|
|
36840
|
-
*
|
|
36841
|
-
* @example
|
|
36842
|
-
* ```typescript
|
|
36843
|
-
* const mode = await getMode();
|
|
36844
|
-
* if (mode === "backtest") {
|
|
36845
|
-
* console.log("Running in backtest mode");
|
|
36846
|
-
* } else {
|
|
36847
|
-
* console.log("Running in live mode");
|
|
36848
|
-
* }
|
|
36849
|
-
* ```
|
|
36850
|
-
*/
|
|
36851
|
-
async function getMode() {
|
|
36852
|
-
backtest.loggerService.info(GET_MODE_METHOD_NAME);
|
|
36853
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36854
|
-
throw new Error("getMode requires an execution context");
|
|
36855
|
-
}
|
|
36856
|
-
const { backtest: bt } = backtest.executionContextService.context;
|
|
36857
|
-
return bt ? "backtest" : "live";
|
|
36858
|
-
}
|
|
36859
|
-
/**
|
|
36860
|
-
* Gets the current trading symbol from execution context.
|
|
36861
|
-
*
|
|
36862
|
-
* @returns Promise resolving to the current trading symbol (e.g., "BTCUSDT")
|
|
36863
|
-
* @throws Error if execution context is not active
|
|
36864
|
-
*
|
|
36865
|
-
* @example
|
|
36866
|
-
* ```typescript
|
|
36867
|
-
* const symbol = await getSymbol();
|
|
36868
|
-
* console.log(symbol); // "BTCUSDT"
|
|
36869
|
-
* ```
|
|
36870
|
-
*/
|
|
36871
|
-
async function getSymbol() {
|
|
36872
|
-
backtest.loggerService.info(GET_SYMBOL_METHOD_NAME);
|
|
36873
|
-
if (!ExecutionContextService.hasContext()) {
|
|
36874
|
-
throw new Error("getSymbol requires an execution context");
|
|
36875
|
-
}
|
|
36876
|
-
const { symbol } = backtest.executionContextService.context;
|
|
36877
|
-
return symbol;
|
|
36878
|
-
}
|
|
36879
|
-
/**
|
|
36880
|
-
* Gets the current method context.
|
|
36881
|
-
*
|
|
36882
|
-
* Returns the context object from the method context service, which contains
|
|
36883
|
-
* information about the current method execution environment.
|
|
36884
|
-
*
|
|
36885
|
-
* @returns Promise resolving to the current method context object
|
|
36886
|
-
* @throws Error if method context is not active
|
|
36887
|
-
*
|
|
36888
|
-
* @example
|
|
36889
|
-
* ```typescript
|
|
36890
|
-
* const context = await getContext();
|
|
36891
|
-
* console.log(context); // { ...method context data... }
|
|
36892
|
-
* ```
|
|
36893
|
-
*/
|
|
36894
|
-
async function getContext() {
|
|
36895
|
-
backtest.loggerService.info(GET_CONTEXT_METHOD_NAME);
|
|
36896
|
-
if (!MethodContextService.hasContext()) {
|
|
36897
|
-
throw new Error("getContext requires a method context");
|
|
36898
|
-
}
|
|
36899
|
-
return backtest.methodContextService.context;
|
|
36900
|
-
}
|
|
36901
37352
|
/**
|
|
36902
37353
|
* Fetches order book for a trading pair from the registered exchange.
|
|
36903
37354
|
*
|
|
@@ -40438,6 +40889,10 @@ const LISTEN_MAX_DRAWDOWN_METHOD_NAME = "event.listenMaxDrawdown";
|
|
|
40438
40889
|
const LISTEN_MAX_DRAWDOWN_ONCE_METHOD_NAME = "event.listenMaxDrawdownOnce";
|
|
40439
40890
|
const LISTEN_SIGNAL_NOTIFY_METHOD_NAME = "event.listenSignalNotify";
|
|
40440
40891
|
const LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME = "event.listenSignalNotifyOnce";
|
|
40892
|
+
const LISTEN_BEFORE_START_METHOD_NAME = "event.listenBeforeStart";
|
|
40893
|
+
const LISTEN_BEFORE_START_ONCE_METHOD_NAME = "event.listenBeforeStartOnce";
|
|
40894
|
+
const LISTEN_AFTER_END_METHOD_NAME = "event.listenAfterEnd";
|
|
40895
|
+
const LISTEN_AFTER_END_ONCE_METHOD_NAME = "event.listenAfterEndOnce";
|
|
40441
40896
|
/**
|
|
40442
40897
|
* Subscribes to all signal events with queued async processing.
|
|
40443
40898
|
*
|
|
@@ -41908,6 +42363,68 @@ function listenSignalNotifyOnce(filterFn, fn) {
|
|
|
41908
42363
|
};
|
|
41909
42364
|
return disposeFn = listenSignalNotify(wrappedFn);
|
|
41910
42365
|
}
|
|
42366
|
+
/**
|
|
42367
|
+
* Subscribes to before start events with queued async processing.
|
|
42368
|
+
* Emits when the engine is about to start a new strategy execution for a symbol.
|
|
42369
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
42370
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
42371
|
+
* @param fn - Callback function to handle before start events
|
|
42372
|
+
* @return Unsubscribe function to stop listening to events
|
|
42373
|
+
*/
|
|
42374
|
+
function listenBeforeStart(fn) {
|
|
42375
|
+
backtest.loggerService.log(LISTEN_BEFORE_START_METHOD_NAME);
|
|
42376
|
+
return beforeStartSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
42377
|
+
}
|
|
42378
|
+
/**
|
|
42379
|
+
* Subscribes to filtered before start events with one-time execution.
|
|
42380
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
42381
|
+
* and automatically unsubscribes.
|
|
42382
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
42383
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
42384
|
+
* @return Unsubscribe function to cancel the listener before it fires
|
|
42385
|
+
*/
|
|
42386
|
+
function listenBeforeStartOnce(filterFn, fn) {
|
|
42387
|
+
backtest.loggerService.log(LISTEN_BEFORE_START_ONCE_METHOD_NAME);
|
|
42388
|
+
let disposeFn;
|
|
42389
|
+
const wrappedFn = async (event) => {
|
|
42390
|
+
if (filterFn(event)) {
|
|
42391
|
+
await fn(event);
|
|
42392
|
+
disposeFn && disposeFn();
|
|
42393
|
+
}
|
|
42394
|
+
};
|
|
42395
|
+
return disposeFn = listenBeforeStart(wrappedFn);
|
|
42396
|
+
}
|
|
42397
|
+
/**
|
|
42398
|
+
* Subscribes to after end events with queued async processing.
|
|
42399
|
+
* Emits when the engine has completed processing a strategy execution for a symbol.
|
|
42400
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
42401
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
42402
|
+
* @param fn - Callback function to handle after end events
|
|
42403
|
+
* @return Unsubscribe function to stop listening to events
|
|
42404
|
+
*/
|
|
42405
|
+
function listenAfterEnd(fn) {
|
|
42406
|
+
backtest.loggerService.log(LISTEN_AFTER_END_METHOD_NAME);
|
|
42407
|
+
return afterEndSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
42408
|
+
}
|
|
42409
|
+
/**
|
|
42410
|
+
* Subscribes to filtered after end events with one-time execution.
|
|
42411
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
42412
|
+
* and automatically unsubscribes.
|
|
42413
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
42414
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
42415
|
+
* @return Unsubscribe function to cancel the listener before it fires
|
|
42416
|
+
*/
|
|
42417
|
+
function listenAfterEndOnce(filterFn, fn) {
|
|
42418
|
+
backtest.loggerService.log(LISTEN_AFTER_END_ONCE_METHOD_NAME);
|
|
42419
|
+
let disposeFn;
|
|
42420
|
+
const wrappedFn = async (event) => {
|
|
42421
|
+
if (filterFn(event)) {
|
|
42422
|
+
await fn(event);
|
|
42423
|
+
disposeFn && disposeFn();
|
|
42424
|
+
}
|
|
42425
|
+
};
|
|
42426
|
+
return disposeFn = listenAfterEnd(wrappedFn);
|
|
42427
|
+
}
|
|
41911
42428
|
|
|
41912
42429
|
const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
|
|
41913
42430
|
const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
|
|
@@ -41986,11 +42503,21 @@ const INSTANCE_TASK_FN$2 = async (symbol, context, self) => {
|
|
|
41986
42503
|
self._isStopped = false;
|
|
41987
42504
|
self._isDone = false;
|
|
41988
42505
|
}
|
|
42506
|
+
Lookup.addActivity({
|
|
42507
|
+
symbol,
|
|
42508
|
+
context,
|
|
42509
|
+
backtest: true,
|
|
42510
|
+
});
|
|
41989
42511
|
for await (const _ of self.run(symbol, context)) {
|
|
41990
42512
|
if (self._isStopped) {
|
|
41991
42513
|
break;
|
|
41992
42514
|
}
|
|
41993
42515
|
}
|
|
42516
|
+
Lookup.removeActivity({
|
|
42517
|
+
symbol,
|
|
42518
|
+
context,
|
|
42519
|
+
backtest: true,
|
|
42520
|
+
});
|
|
41994
42521
|
if (!self._isDone) {
|
|
41995
42522
|
await doneBacktestSubject.next({
|
|
41996
42523
|
exchangeName: context.exchangeName,
|
|
@@ -44637,11 +45164,21 @@ const INSTANCE_TASK_FN$1 = async (symbol, context, self) => {
|
|
|
44637
45164
|
self._isStopped = false;
|
|
44638
45165
|
self._isDone = false;
|
|
44639
45166
|
}
|
|
45167
|
+
Lookup.addActivity({
|
|
45168
|
+
symbol,
|
|
45169
|
+
context,
|
|
45170
|
+
backtest: false,
|
|
45171
|
+
});
|
|
44640
45172
|
for await (const signal of self.run(symbol, context)) {
|
|
44641
45173
|
if (signal?.action === "closed" && self._isStopped) {
|
|
44642
45174
|
break;
|
|
44643
45175
|
}
|
|
44644
45176
|
}
|
|
45177
|
+
Lookup.removeActivity({
|
|
45178
|
+
symbol,
|
|
45179
|
+
context,
|
|
45180
|
+
backtest: false,
|
|
45181
|
+
});
|
|
44645
45182
|
if (!self._isDone) {
|
|
44646
45183
|
await doneLiveSubject.next({
|
|
44647
45184
|
exchangeName: context.exchangeName,
|
|
@@ -48576,6 +49113,128 @@ async function listRiskSchema() {
|
|
|
48576
49113
|
return await backtest.riskValidationService.list();
|
|
48577
49114
|
}
|
|
48578
49115
|
|
|
49116
|
+
const GET_DATE_METHOD_NAME = "meta.getDate";
|
|
49117
|
+
const GET_TIMESTAMP_METHOD_NAME = "meta.getTimestamp";
|
|
49118
|
+
const GET_MODE_METHOD_NAME = "meta.getMode";
|
|
49119
|
+
const GET_SYMBOL_METHOD_NAME = "meta.getSymbol";
|
|
49120
|
+
const GET_CONTEXT_METHOD_NAME = "meta.getContext";
|
|
49121
|
+
/**
|
|
49122
|
+
* Gets the current date from execution context.
|
|
49123
|
+
*
|
|
49124
|
+
* In backtest mode: returns the current timeframe date being processed
|
|
49125
|
+
* In live mode: returns current real-time date
|
|
49126
|
+
*
|
|
49127
|
+
* @returns Promise resolving to current execution context date
|
|
49128
|
+
*
|
|
49129
|
+
* @example
|
|
49130
|
+
* ```typescript
|
|
49131
|
+
* const date = await getDate();
|
|
49132
|
+
* console.log(date); // 2024-01-01T12:00:00.000Z
|
|
49133
|
+
* ```
|
|
49134
|
+
*/
|
|
49135
|
+
async function getDate() {
|
|
49136
|
+
backtest.loggerService.info(GET_DATE_METHOD_NAME);
|
|
49137
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49138
|
+
throw new Error("getDate requires an execution context");
|
|
49139
|
+
}
|
|
49140
|
+
const { when } = backtest.executionContextService.context;
|
|
49141
|
+
return new Date(when.getTime());
|
|
49142
|
+
}
|
|
49143
|
+
/**
|
|
49144
|
+
* Gets the current timestamp from execution context.
|
|
49145
|
+
*
|
|
49146
|
+
* In backtest mode: returns the current timeframe timestamp being processed
|
|
49147
|
+
* In live mode: returns current real-time timestamp
|
|
49148
|
+
*
|
|
49149
|
+
* @returns Promise resolving to current execution context timestamp in milliseconds
|
|
49150
|
+
* @example
|
|
49151
|
+
* ```typescript
|
|
49152
|
+
* const timestamp = await getTimestamp();
|
|
49153
|
+
* console.log(timestamp); // 1700000000000
|
|
49154
|
+
* ```
|
|
49155
|
+
*/
|
|
49156
|
+
async function getTimestamp() {
|
|
49157
|
+
backtest.loggerService.info(GET_TIMESTAMP_METHOD_NAME);
|
|
49158
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49159
|
+
throw new Error("getTimestamp requires an execution context");
|
|
49160
|
+
}
|
|
49161
|
+
if (!MethodContextService.hasContext()) {
|
|
49162
|
+
throw new Error("getTimestamp requires a method context");
|
|
49163
|
+
}
|
|
49164
|
+
const { symbol, backtest: isBacktest } = backtest.executionContextService.context;
|
|
49165
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
49166
|
+
return backtest.timeMetaService.getTimestamp(symbol, {
|
|
49167
|
+
exchangeName,
|
|
49168
|
+
frameName,
|
|
49169
|
+
strategyName,
|
|
49170
|
+
}, isBacktest);
|
|
49171
|
+
}
|
|
49172
|
+
/**
|
|
49173
|
+
* Gets the current execution mode.
|
|
49174
|
+
*
|
|
49175
|
+
* @returns Promise resolving to "backtest" or "live"
|
|
49176
|
+
*
|
|
49177
|
+
* @example
|
|
49178
|
+
* ```typescript
|
|
49179
|
+
* const mode = await getMode();
|
|
49180
|
+
* if (mode === "backtest") {
|
|
49181
|
+
* console.log("Running in backtest mode");
|
|
49182
|
+
* } else {
|
|
49183
|
+
* console.log("Running in live mode");
|
|
49184
|
+
* }
|
|
49185
|
+
* ```
|
|
49186
|
+
*/
|
|
49187
|
+
async function getMode() {
|
|
49188
|
+
backtest.loggerService.info(GET_MODE_METHOD_NAME);
|
|
49189
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49190
|
+
throw new Error("getMode requires an execution context");
|
|
49191
|
+
}
|
|
49192
|
+
const { backtest: bt } = backtest.executionContextService.context;
|
|
49193
|
+
return bt ? "backtest" : "live";
|
|
49194
|
+
}
|
|
49195
|
+
/**
|
|
49196
|
+
* Gets the current trading symbol from execution context.
|
|
49197
|
+
*
|
|
49198
|
+
* @returns Promise resolving to the current trading symbol (e.g., "BTCUSDT")
|
|
49199
|
+
* @throws Error if execution context is not active
|
|
49200
|
+
*
|
|
49201
|
+
* @example
|
|
49202
|
+
* ```typescript
|
|
49203
|
+
* const symbol = await getSymbol();
|
|
49204
|
+
* console.log(symbol); // "BTCUSDT"
|
|
49205
|
+
* ```
|
|
49206
|
+
*/
|
|
49207
|
+
async function getSymbol() {
|
|
49208
|
+
backtest.loggerService.info(GET_SYMBOL_METHOD_NAME);
|
|
49209
|
+
if (!ExecutionContextService.hasContext()) {
|
|
49210
|
+
throw new Error("getSymbol requires an execution context");
|
|
49211
|
+
}
|
|
49212
|
+
const { symbol } = backtest.executionContextService.context;
|
|
49213
|
+
return symbol;
|
|
49214
|
+
}
|
|
49215
|
+
/**
|
|
49216
|
+
* Gets the current method context.
|
|
49217
|
+
*
|
|
49218
|
+
* Returns the context object from the method context service, which contains
|
|
49219
|
+
* information about the current method execution environment.
|
|
49220
|
+
*
|
|
49221
|
+
* @returns Promise resolving to the current method context object
|
|
49222
|
+
* @throws Error if method context is not active
|
|
49223
|
+
*
|
|
49224
|
+
* @example
|
|
49225
|
+
* ```typescript
|
|
49226
|
+
* const context = await getContext();
|
|
49227
|
+
* console.log(context); // { ...method context data... }
|
|
49228
|
+
* ```
|
|
49229
|
+
*/
|
|
49230
|
+
async function getContext() {
|
|
49231
|
+
backtest.loggerService.info(GET_CONTEXT_METHOD_NAME);
|
|
49232
|
+
if (!MethodContextService.hasContext()) {
|
|
49233
|
+
throw new Error("getContext requires a method context");
|
|
49234
|
+
}
|
|
49235
|
+
return backtest.methodContextService.context;
|
|
49236
|
+
}
|
|
49237
|
+
|
|
48579
49238
|
const RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistBacktestUtils.handleActivePing";
|
|
48580
49239
|
const RECENT_PERSIST_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL = "RecentPersistBacktestUtils.getLatestSignal";
|
|
48581
49240
|
const RECENT_PERSIST_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistLiveUtils.handleActivePing";
|
|
@@ -54620,6 +55279,8 @@ const SUBJECT_ISOLATION_LIST = [
|
|
|
54620
55279
|
syncSubject,
|
|
54621
55280
|
validationSubject,
|
|
54622
55281
|
signalNotifySubject,
|
|
55282
|
+
beforeStartSubject,
|
|
55283
|
+
afterEndSubject
|
|
54623
55284
|
];
|
|
54624
55285
|
/**
|
|
54625
55286
|
* Creates a snapshot function for a given subject by clearing its internal
|
|
@@ -63767,6 +64428,7 @@ exports.HighestProfit = HighestProfit;
|
|
|
63767
64428
|
exports.Interval = Interval;
|
|
63768
64429
|
exports.Live = Live;
|
|
63769
64430
|
exports.Log = Log;
|
|
64431
|
+
exports.Lookup = Lookup;
|
|
63770
64432
|
exports.Markdown = Markdown;
|
|
63771
64433
|
exports.MarkdownFileBase = MarkdownFileBase;
|
|
63772
64434
|
exports.MarkdownFolderBase = MarkdownFolderBase;
|
|
@@ -63848,6 +64510,7 @@ exports.addSizingSchema = addSizingSchema;
|
|
|
63848
64510
|
exports.addStrategySchema = addStrategySchema;
|
|
63849
64511
|
exports.addWalkerSchema = addWalkerSchema;
|
|
63850
64512
|
exports.alignToInterval = alignToInterval;
|
|
64513
|
+
exports.cacheCandles = cacheCandles;
|
|
63851
64514
|
exports.checkCandles = checkCandles;
|
|
63852
64515
|
exports.commitActivateScheduled = commitActivateScheduled;
|
|
63853
64516
|
exports.commitAverageBuy = commitAverageBuy;
|
|
@@ -63956,7 +64619,11 @@ exports.listStrategySchema = listStrategySchema;
|
|
|
63956
64619
|
exports.listWalkerSchema = listWalkerSchema;
|
|
63957
64620
|
exports.listenActivePing = listenActivePing;
|
|
63958
64621
|
exports.listenActivePingOnce = listenActivePingOnce;
|
|
64622
|
+
exports.listenAfterEnd = listenAfterEnd;
|
|
64623
|
+
exports.listenAfterEndOnce = listenAfterEndOnce;
|
|
63959
64624
|
exports.listenBacktestProgress = listenBacktestProgress;
|
|
64625
|
+
exports.listenBeforeStart = listenBeforeStart;
|
|
64626
|
+
exports.listenBeforeStartOnce = listenBeforeStartOnce;
|
|
63960
64627
|
exports.listenBreakevenAvailable = listenBreakevenAvailable;
|
|
63961
64628
|
exports.listenBreakevenAvailableOnce = listenBreakevenAvailableOnce;
|
|
63962
64629
|
exports.listenDoneBacktest = listenDoneBacktest;
|