backtest-kit 1.4.7 → 1.4.9
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/build/index.cjs +165 -18
- package/build/index.mjs +165 -19
- package/package.json +1 -1
- package/types.d.ts +48 -13
package/build/index.cjs
CHANGED
|
@@ -399,10 +399,12 @@ const GET_CANDLES_FN = async (dto, since, self) => {
|
|
|
399
399
|
return result;
|
|
400
400
|
}
|
|
401
401
|
catch (err) {
|
|
402
|
-
|
|
402
|
+
const message = `ClientExchange GET_CANDLES_FN: attempt ${i + 1} failed for symbol=${dto.symbol}, interval=${dto.interval}, since=${since.toISOString()}, limit=${dto.limit}}`;
|
|
403
|
+
self.params.logger.warn(message, {
|
|
403
404
|
error: functoolsKit.errorData(err),
|
|
404
405
|
message: functoolsKit.getErrorMessage(err),
|
|
405
406
|
});
|
|
407
|
+
console.warn(message);
|
|
406
408
|
lastError = err;
|
|
407
409
|
await functoolsKit.sleep(GLOBAL_CONFIG.CC_GET_CANDLES_RETRY_DELAY_MS);
|
|
408
410
|
}
|
|
@@ -1602,6 +1604,12 @@ const signalBacktestEmitter = new functoolsKit.Subject();
|
|
|
1602
1604
|
* Emits errors caught in background tasks (Live.background, Backtest.background).
|
|
1603
1605
|
*/
|
|
1604
1606
|
const errorEmitter = new functoolsKit.Subject();
|
|
1607
|
+
/**
|
|
1608
|
+
* Exit emitter for critical errors that require process termination.
|
|
1609
|
+
* Emits errors that should terminate the current execution (Backtest, Live, Walker).
|
|
1610
|
+
* Unlike errorEmitter (for recoverable errors), exitEmitter signals fatal errors.
|
|
1611
|
+
*/
|
|
1612
|
+
const exitEmitter = new functoolsKit.Subject();
|
|
1605
1613
|
/**
|
|
1606
1614
|
* Done emitter for live background execution completion.
|
|
1607
1615
|
* Emits when live background tasks complete (Live.background).
|
|
@@ -1674,6 +1682,7 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
1674
1682
|
doneLiveSubject: doneLiveSubject,
|
|
1675
1683
|
doneWalkerSubject: doneWalkerSubject,
|
|
1676
1684
|
errorEmitter: errorEmitter,
|
|
1685
|
+
exitEmitter: exitEmitter,
|
|
1677
1686
|
partialLossSubject: partialLossSubject,
|
|
1678
1687
|
partialProfitSubject: partialProfitSubject,
|
|
1679
1688
|
performanceEmitter: performanceEmitter,
|
|
@@ -1831,6 +1840,9 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
|
|
|
1831
1840
|
if (signal.minuteEstimatedTime <= 0) {
|
|
1832
1841
|
errors.push(`minuteEstimatedTime must be positive, got ${signal.minuteEstimatedTime}`);
|
|
1833
1842
|
}
|
|
1843
|
+
if (!Number.isInteger(signal.minuteEstimatedTime)) {
|
|
1844
|
+
errors.push(`minuteEstimatedTime must be an integer (whole number), got ${signal.minuteEstimatedTime}`);
|
|
1845
|
+
}
|
|
1834
1846
|
// ЗАЩИТА ОТ ВЕЧНЫХ СИГНАЛОВ: ограничиваем максимальное время жизни сигнала
|
|
1835
1847
|
if (GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES && GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
|
|
1836
1848
|
if (signal.minuteEstimatedTime > GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
|
|
@@ -3017,6 +3029,7 @@ class StrategyConnectionService {
|
|
|
3017
3029
|
this.getStrategy = functoolsKit.memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => {
|
|
3018
3030
|
const { riskName, getSignal, interval, callbacks } = this.strategySchemaService.get(strategyName);
|
|
3019
3031
|
return new ClientStrategy({
|
|
3032
|
+
symbol,
|
|
3020
3033
|
interval,
|
|
3021
3034
|
execution: this.executionContextService,
|
|
3022
3035
|
method: this.methodContextService,
|
|
@@ -4750,7 +4763,21 @@ class BacktestLogicPrivateService {
|
|
|
4750
4763
|
progress: totalFrames > 0 ? i / totalFrames : 0,
|
|
4751
4764
|
});
|
|
4752
4765
|
}
|
|
4753
|
-
|
|
4766
|
+
let result;
|
|
4767
|
+
try {
|
|
4768
|
+
result = await this.strategyGlobalService.tick(symbol, when, true);
|
|
4769
|
+
}
|
|
4770
|
+
catch (error) {
|
|
4771
|
+
console.warn(`backtestLogicPrivateService tick failed, skipping timeframe when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4772
|
+
this.loggerService.warn("backtestLogicPrivateService tick failed, skipping timeframe", {
|
|
4773
|
+
symbol,
|
|
4774
|
+
when: when.toISOString(),
|
|
4775
|
+
error: functoolsKit.errorData(error), message: functoolsKit.getErrorMessage(error),
|
|
4776
|
+
});
|
|
4777
|
+
await errorEmitter.next(error);
|
|
4778
|
+
i++;
|
|
4779
|
+
continue;
|
|
4780
|
+
}
|
|
4754
4781
|
// Если scheduled signal создан - обрабатываем через backtest()
|
|
4755
4782
|
if (result.action === "scheduled") {
|
|
4756
4783
|
const signalStartTime = performance.now();
|
|
@@ -4766,7 +4793,22 @@ class BacktestLogicPrivateService {
|
|
|
4766
4793
|
// + minuteEstimatedTime для работы сигнала ПОСЛЕ активации
|
|
4767
4794
|
// +1 потому что when включается как первая свеча (timestamp начинается с when, а не after when)
|
|
4768
4795
|
const candlesNeeded = GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES + signal.minuteEstimatedTime + 1;
|
|
4769
|
-
|
|
4796
|
+
let candles;
|
|
4797
|
+
try {
|
|
4798
|
+
candles = await this.exchangeGlobalService.getNextCandles(symbol, "1m", candlesNeeded, when, true);
|
|
4799
|
+
}
|
|
4800
|
+
catch (error) {
|
|
4801
|
+
console.warn(`backtestLogicPrivateService getNextCandles failed for scheduled signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4802
|
+
this.loggerService.warn("backtestLogicPrivateService getNextCandles failed for scheduled signal", {
|
|
4803
|
+
symbol,
|
|
4804
|
+
signalId: signal.id,
|
|
4805
|
+
candlesNeeded,
|
|
4806
|
+
error: functoolsKit.errorData(error), message: functoolsKit.getErrorMessage(error),
|
|
4807
|
+
});
|
|
4808
|
+
await errorEmitter.next(error);
|
|
4809
|
+
i++;
|
|
4810
|
+
continue;
|
|
4811
|
+
}
|
|
4770
4812
|
if (!candles.length) {
|
|
4771
4813
|
i++;
|
|
4772
4814
|
continue;
|
|
@@ -4779,7 +4821,21 @@ class BacktestLogicPrivateService {
|
|
|
4779
4821
|
});
|
|
4780
4822
|
// backtest() сам обработает scheduled signal: найдет активацию/отмену
|
|
4781
4823
|
// и если активируется - продолжит с TP/SL мониторингом
|
|
4782
|
-
|
|
4824
|
+
let backtestResult;
|
|
4825
|
+
try {
|
|
4826
|
+
backtestResult = await this.strategyGlobalService.backtest(symbol, candles, when, true);
|
|
4827
|
+
}
|
|
4828
|
+
catch (error) {
|
|
4829
|
+
console.warn(`backtestLogicPrivateService backtest failed for scheduled signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4830
|
+
this.loggerService.warn("backtestLogicPrivateService backtest failed for scheduled signal", {
|
|
4831
|
+
symbol,
|
|
4832
|
+
signalId: signal.id,
|
|
4833
|
+
error: functoolsKit.errorData(error), message: functoolsKit.getErrorMessage(error),
|
|
4834
|
+
});
|
|
4835
|
+
await errorEmitter.next(error);
|
|
4836
|
+
i++;
|
|
4837
|
+
continue;
|
|
4838
|
+
}
|
|
4783
4839
|
this.loggerService.info("backtestLogicPrivateService scheduled signal closed", {
|
|
4784
4840
|
symbol,
|
|
4785
4841
|
signalId: backtestResult.signal.id,
|
|
@@ -4820,9 +4876,24 @@ class BacktestLogicPrivateService {
|
|
|
4820
4876
|
minuteEstimatedTime: signal.minuteEstimatedTime,
|
|
4821
4877
|
});
|
|
4822
4878
|
// Получаем свечи для бектеста
|
|
4823
|
-
|
|
4879
|
+
let candles;
|
|
4880
|
+
try {
|
|
4881
|
+
candles = await this.exchangeGlobalService.getNextCandles(symbol, "1m", signal.minuteEstimatedTime, when, true);
|
|
4882
|
+
}
|
|
4883
|
+
catch (error) {
|
|
4884
|
+
console.warn(`backtestLogicPrivateService getNextCandles failed for opened signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4885
|
+
this.loggerService.warn("backtestLogicPrivateService getNextCandles failed for opened signal", {
|
|
4886
|
+
symbol,
|
|
4887
|
+
signalId: signal.id,
|
|
4888
|
+
error: functoolsKit.errorData(error), message: functoolsKit.getErrorMessage(error),
|
|
4889
|
+
});
|
|
4890
|
+
await errorEmitter.next(error);
|
|
4891
|
+
i++;
|
|
4892
|
+
continue;
|
|
4893
|
+
}
|
|
4824
4894
|
if (!candles.length) {
|
|
4825
|
-
|
|
4895
|
+
i++;
|
|
4896
|
+
continue;
|
|
4826
4897
|
}
|
|
4827
4898
|
this.loggerService.info("backtestLogicPrivateService candles fetched", {
|
|
4828
4899
|
symbol,
|
|
@@ -4830,7 +4901,21 @@ class BacktestLogicPrivateService {
|
|
|
4830
4901
|
candlesCount: candles.length,
|
|
4831
4902
|
});
|
|
4832
4903
|
// Вызываем backtest - всегда возвращает closed
|
|
4833
|
-
|
|
4904
|
+
let backtestResult;
|
|
4905
|
+
try {
|
|
4906
|
+
backtestResult = await this.strategyGlobalService.backtest(symbol, candles, when, true);
|
|
4907
|
+
}
|
|
4908
|
+
catch (error) {
|
|
4909
|
+
console.warn(`backtestLogicPrivateService backtest failed for opened signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4910
|
+
this.loggerService.warn("backtestLogicPrivateService backtest failed for opened signal", {
|
|
4911
|
+
symbol,
|
|
4912
|
+
signalId: signal.id,
|
|
4913
|
+
error: functoolsKit.errorData(error), message: functoolsKit.getErrorMessage(error),
|
|
4914
|
+
});
|
|
4915
|
+
await errorEmitter.next(error);
|
|
4916
|
+
i++;
|
|
4917
|
+
continue;
|
|
4918
|
+
}
|
|
4834
4919
|
this.loggerService.info("backtestLogicPrivateService signal closed", {
|
|
4835
4920
|
symbol,
|
|
4836
4921
|
signalId: backtestResult.signal.id,
|
|
@@ -4954,7 +5039,21 @@ class LiveLogicPrivateService {
|
|
|
4954
5039
|
while (true) {
|
|
4955
5040
|
const tickStartTime = performance.now();
|
|
4956
5041
|
const when = new Date();
|
|
4957
|
-
|
|
5042
|
+
let result;
|
|
5043
|
+
try {
|
|
5044
|
+
result = await this.strategyGlobalService.tick(symbol, when, false);
|
|
5045
|
+
}
|
|
5046
|
+
catch (error) {
|
|
5047
|
+
console.warn(`backtestLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
5048
|
+
this.loggerService.warn("liveLogicPrivateService tick failed, retrying after sleep", {
|
|
5049
|
+
symbol,
|
|
5050
|
+
when: when.toISOString(),
|
|
5051
|
+
error: functoolsKit.errorData(error), message: functoolsKit.getErrorMessage(error),
|
|
5052
|
+
});
|
|
5053
|
+
await errorEmitter.next(error);
|
|
5054
|
+
await functoolsKit.sleep(TICK_TTL);
|
|
5055
|
+
continue;
|
|
5056
|
+
}
|
|
4958
5057
|
this.loggerService.info("liveLogicPrivateService tick result", {
|
|
4959
5058
|
symbol,
|
|
4960
5059
|
action: result.action,
|
|
@@ -5076,10 +5175,27 @@ class WalkerLogicPrivateService {
|
|
|
5076
5175
|
frameName: context.frameName,
|
|
5077
5176
|
});
|
|
5078
5177
|
pendingStrategy = strategyName;
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5178
|
+
let result;
|
|
5179
|
+
try {
|
|
5180
|
+
result = await Promise.race([
|
|
5181
|
+
await functoolsKit.resolveDocuments(iterator),
|
|
5182
|
+
listenStop,
|
|
5183
|
+
]);
|
|
5184
|
+
}
|
|
5185
|
+
catch (error) {
|
|
5186
|
+
console.warn(`walkerLogicPrivateService backtest failed symbol=${symbol} strategyName=${strategyName} exchangeName=${context.exchangeName}`);
|
|
5187
|
+
this.loggerService.warn("walkerLogicPrivateService backtest failed for strategy, skipping", {
|
|
5188
|
+
strategyName,
|
|
5189
|
+
symbol,
|
|
5190
|
+
error: functoolsKit.errorData(error), message: functoolsKit.getErrorMessage(error),
|
|
5191
|
+
});
|
|
5192
|
+
await errorEmitter.next(error);
|
|
5193
|
+
// Call onStrategyError callback if provided
|
|
5194
|
+
if (walkerSchema.callbacks?.onStrategyError) {
|
|
5195
|
+
walkerSchema.callbacks.onStrategyError(strategyName, symbol, error);
|
|
5196
|
+
}
|
|
5197
|
+
continue;
|
|
5198
|
+
}
|
|
5083
5199
|
if (result === CANCEL_SYMBOL) {
|
|
5084
5200
|
this.loggerService.info("walkerLogicPrivateService received stop signal, cancelling walker", {
|
|
5085
5201
|
context,
|
|
@@ -11437,6 +11553,7 @@ const LISTEN_SIGNAL_LIVE_ONCE_METHOD_NAME = "event.listenSignalLiveOnce";
|
|
|
11437
11553
|
const LISTEN_SIGNAL_BACKTEST_METHOD_NAME = "event.listenSignalBacktest";
|
|
11438
11554
|
const LISTEN_SIGNAL_BACKTEST_ONCE_METHOD_NAME = "event.listenSignalBacktestOnce";
|
|
11439
11555
|
const LISTEN_ERROR_METHOD_NAME = "event.listenError";
|
|
11556
|
+
const LISTEN_EXIT_METHOD_NAME = "event.listenExit";
|
|
11440
11557
|
const LISTEN_DONE_LIVE_METHOD_NAME = "event.listenDoneLive";
|
|
11441
11558
|
const LISTEN_DONE_LIVE_ONCE_METHOD_NAME = "event.listenDoneLiveOnce";
|
|
11442
11559
|
const LISTEN_DONE_BACKTEST_METHOD_NAME = "event.listenDoneBacktest";
|
|
@@ -11619,9 +11736,10 @@ function listenSignalBacktestOnce(filterFn, fn) {
|
|
|
11619
11736
|
return signalBacktestEmitter.filter(filterFn).once(fn);
|
|
11620
11737
|
}
|
|
11621
11738
|
/**
|
|
11622
|
-
* Subscribes to
|
|
11739
|
+
* Subscribes to recoverable execution errors with queued async processing.
|
|
11623
11740
|
*
|
|
11624
|
-
* Listens to errors
|
|
11741
|
+
* Listens to recoverable errors during strategy execution (e.g., failed API calls).
|
|
11742
|
+
* These errors are caught and handled gracefully - execution continues.
|
|
11625
11743
|
* Events are processed sequentially in order received, even if callback is async.
|
|
11626
11744
|
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
11627
11745
|
*
|
|
@@ -11633,7 +11751,7 @@ function listenSignalBacktestOnce(filterFn, fn) {
|
|
|
11633
11751
|
* import { listenError } from "./function/event";
|
|
11634
11752
|
*
|
|
11635
11753
|
* const unsubscribe = listenError((error) => {
|
|
11636
|
-
* console.error("
|
|
11754
|
+
* console.error("Recoverable error (execution continues):", error.message);
|
|
11637
11755
|
* // Log to monitoring service, send alerts, etc.
|
|
11638
11756
|
* });
|
|
11639
11757
|
*
|
|
@@ -11645,6 +11763,34 @@ function listenError(fn) {
|
|
|
11645
11763
|
backtest$1.loggerService.log(LISTEN_ERROR_METHOD_NAME);
|
|
11646
11764
|
return errorEmitter.subscribe(functoolsKit.queued(async (error) => fn(error)));
|
|
11647
11765
|
}
|
|
11766
|
+
/**
|
|
11767
|
+
* Subscribes to fatal execution errors with queued async processing.
|
|
11768
|
+
*
|
|
11769
|
+
* Listens to critical errors that terminate execution (Live.background, Backtest.background, Walker.background).
|
|
11770
|
+
* Unlike listenError (recoverable errors), these errors stop the current process.
|
|
11771
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
11772
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
11773
|
+
*
|
|
11774
|
+
* @param fn - Callback function to handle fatal error events
|
|
11775
|
+
* @returns Unsubscribe function to stop listening
|
|
11776
|
+
*
|
|
11777
|
+
* @example
|
|
11778
|
+
* ```typescript
|
|
11779
|
+
* import { listenExit } from "./function/event";
|
|
11780
|
+
*
|
|
11781
|
+
* const unsubscribe = listenExit((error) => {
|
|
11782
|
+
* console.error("Fatal error (execution terminated):", error.message);
|
|
11783
|
+
* // Log to monitoring, send alerts, restart process, etc.
|
|
11784
|
+
* });
|
|
11785
|
+
*
|
|
11786
|
+
* // Later: stop listening
|
|
11787
|
+
* unsubscribe();
|
|
11788
|
+
* ```
|
|
11789
|
+
*/
|
|
11790
|
+
function listenExit(fn) {
|
|
11791
|
+
backtest$1.loggerService.log(LISTEN_EXIT_METHOD_NAME);
|
|
11792
|
+
return exitEmitter.subscribe(functoolsKit.queued(async (error) => fn(error)));
|
|
11793
|
+
}
|
|
11648
11794
|
/**
|
|
11649
11795
|
* Subscribes to live background execution completion events with queued async processing.
|
|
11650
11796
|
*
|
|
@@ -12458,7 +12604,7 @@ class BacktestUtils {
|
|
|
12458
12604
|
}
|
|
12459
12605
|
isDone = true;
|
|
12460
12606
|
};
|
|
12461
|
-
task().catch((error) =>
|
|
12607
|
+
task().catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
12462
12608
|
return () => {
|
|
12463
12609
|
backtest$1.strategyGlobalService.stop(symbol, context.strategyName);
|
|
12464
12610
|
backtest$1.strategyGlobalService
|
|
@@ -12671,7 +12817,7 @@ class LiveUtils {
|
|
|
12671
12817
|
}
|
|
12672
12818
|
isDone = true;
|
|
12673
12819
|
};
|
|
12674
|
-
task().catch((error) =>
|
|
12820
|
+
task().catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
12675
12821
|
return () => {
|
|
12676
12822
|
backtest$1.strategyGlobalService.stop(symbol, context.strategyName);
|
|
12677
12823
|
backtest$1.strategyGlobalService
|
|
@@ -13102,7 +13248,7 @@ class WalkerUtils {
|
|
|
13102
13248
|
}
|
|
13103
13249
|
isDone = true;
|
|
13104
13250
|
};
|
|
13105
|
-
task().catch((error) =>
|
|
13251
|
+
task().catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
13106
13252
|
return () => {
|
|
13107
13253
|
for (const strategyName of walkerSchema.strategies) {
|
|
13108
13254
|
backtest$1.strategyGlobalService.stop(symbol, strategyName);
|
|
@@ -13855,6 +14001,7 @@ exports.listenDoneLiveOnce = listenDoneLiveOnce;
|
|
|
13855
14001
|
exports.listenDoneWalker = listenDoneWalker;
|
|
13856
14002
|
exports.listenDoneWalkerOnce = listenDoneWalkerOnce;
|
|
13857
14003
|
exports.listenError = listenError;
|
|
14004
|
+
exports.listenExit = listenExit;
|
|
13858
14005
|
exports.listenOptimizerProgress = listenOptimizerProgress;
|
|
13859
14006
|
exports.listenPartialLoss = listenPartialLoss;
|
|
13860
14007
|
exports.listenPartialLossOnce = listenPartialLossOnce;
|
package/build/index.mjs
CHANGED
|
@@ -397,10 +397,12 @@ const GET_CANDLES_FN = async (dto, since, self) => {
|
|
|
397
397
|
return result;
|
|
398
398
|
}
|
|
399
399
|
catch (err) {
|
|
400
|
-
|
|
400
|
+
const message = `ClientExchange GET_CANDLES_FN: attempt ${i + 1} failed for symbol=${dto.symbol}, interval=${dto.interval}, since=${since.toISOString()}, limit=${dto.limit}}`;
|
|
401
|
+
self.params.logger.warn(message, {
|
|
401
402
|
error: errorData(err),
|
|
402
403
|
message: getErrorMessage(err),
|
|
403
404
|
});
|
|
405
|
+
console.warn(message);
|
|
404
406
|
lastError = err;
|
|
405
407
|
await sleep(GLOBAL_CONFIG.CC_GET_CANDLES_RETRY_DELAY_MS);
|
|
406
408
|
}
|
|
@@ -1600,6 +1602,12 @@ const signalBacktestEmitter = new Subject();
|
|
|
1600
1602
|
* Emits errors caught in background tasks (Live.background, Backtest.background).
|
|
1601
1603
|
*/
|
|
1602
1604
|
const errorEmitter = new Subject();
|
|
1605
|
+
/**
|
|
1606
|
+
* Exit emitter for critical errors that require process termination.
|
|
1607
|
+
* Emits errors that should terminate the current execution (Backtest, Live, Walker).
|
|
1608
|
+
* Unlike errorEmitter (for recoverable errors), exitEmitter signals fatal errors.
|
|
1609
|
+
*/
|
|
1610
|
+
const exitEmitter = new Subject();
|
|
1603
1611
|
/**
|
|
1604
1612
|
* Done emitter for live background execution completion.
|
|
1605
1613
|
* Emits when live background tasks complete (Live.background).
|
|
@@ -1672,6 +1680,7 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
1672
1680
|
doneLiveSubject: doneLiveSubject,
|
|
1673
1681
|
doneWalkerSubject: doneWalkerSubject,
|
|
1674
1682
|
errorEmitter: errorEmitter,
|
|
1683
|
+
exitEmitter: exitEmitter,
|
|
1675
1684
|
partialLossSubject: partialLossSubject,
|
|
1676
1685
|
partialProfitSubject: partialProfitSubject,
|
|
1677
1686
|
performanceEmitter: performanceEmitter,
|
|
@@ -1829,6 +1838,9 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
|
|
|
1829
1838
|
if (signal.minuteEstimatedTime <= 0) {
|
|
1830
1839
|
errors.push(`minuteEstimatedTime must be positive, got ${signal.minuteEstimatedTime}`);
|
|
1831
1840
|
}
|
|
1841
|
+
if (!Number.isInteger(signal.minuteEstimatedTime)) {
|
|
1842
|
+
errors.push(`minuteEstimatedTime must be an integer (whole number), got ${signal.minuteEstimatedTime}`);
|
|
1843
|
+
}
|
|
1832
1844
|
// ЗАЩИТА ОТ ВЕЧНЫХ СИГНАЛОВ: ограничиваем максимальное время жизни сигнала
|
|
1833
1845
|
if (GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES && GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
|
|
1834
1846
|
if (signal.minuteEstimatedTime > GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
|
|
@@ -3015,6 +3027,7 @@ class StrategyConnectionService {
|
|
|
3015
3027
|
this.getStrategy = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => {
|
|
3016
3028
|
const { riskName, getSignal, interval, callbacks } = this.strategySchemaService.get(strategyName);
|
|
3017
3029
|
return new ClientStrategy({
|
|
3030
|
+
symbol,
|
|
3018
3031
|
interval,
|
|
3019
3032
|
execution: this.executionContextService,
|
|
3020
3033
|
method: this.methodContextService,
|
|
@@ -4748,7 +4761,21 @@ class BacktestLogicPrivateService {
|
|
|
4748
4761
|
progress: totalFrames > 0 ? i / totalFrames : 0,
|
|
4749
4762
|
});
|
|
4750
4763
|
}
|
|
4751
|
-
|
|
4764
|
+
let result;
|
|
4765
|
+
try {
|
|
4766
|
+
result = await this.strategyGlobalService.tick(symbol, when, true);
|
|
4767
|
+
}
|
|
4768
|
+
catch (error) {
|
|
4769
|
+
console.warn(`backtestLogicPrivateService tick failed, skipping timeframe when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4770
|
+
this.loggerService.warn("backtestLogicPrivateService tick failed, skipping timeframe", {
|
|
4771
|
+
symbol,
|
|
4772
|
+
when: when.toISOString(),
|
|
4773
|
+
error: errorData(error), message: getErrorMessage(error),
|
|
4774
|
+
});
|
|
4775
|
+
await errorEmitter.next(error);
|
|
4776
|
+
i++;
|
|
4777
|
+
continue;
|
|
4778
|
+
}
|
|
4752
4779
|
// Если scheduled signal создан - обрабатываем через backtest()
|
|
4753
4780
|
if (result.action === "scheduled") {
|
|
4754
4781
|
const signalStartTime = performance.now();
|
|
@@ -4764,7 +4791,22 @@ class BacktestLogicPrivateService {
|
|
|
4764
4791
|
// + minuteEstimatedTime для работы сигнала ПОСЛЕ активации
|
|
4765
4792
|
// +1 потому что when включается как первая свеча (timestamp начинается с when, а не after when)
|
|
4766
4793
|
const candlesNeeded = GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES + signal.minuteEstimatedTime + 1;
|
|
4767
|
-
|
|
4794
|
+
let candles;
|
|
4795
|
+
try {
|
|
4796
|
+
candles = await this.exchangeGlobalService.getNextCandles(symbol, "1m", candlesNeeded, when, true);
|
|
4797
|
+
}
|
|
4798
|
+
catch (error) {
|
|
4799
|
+
console.warn(`backtestLogicPrivateService getNextCandles failed for scheduled signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4800
|
+
this.loggerService.warn("backtestLogicPrivateService getNextCandles failed for scheduled signal", {
|
|
4801
|
+
symbol,
|
|
4802
|
+
signalId: signal.id,
|
|
4803
|
+
candlesNeeded,
|
|
4804
|
+
error: errorData(error), message: getErrorMessage(error),
|
|
4805
|
+
});
|
|
4806
|
+
await errorEmitter.next(error);
|
|
4807
|
+
i++;
|
|
4808
|
+
continue;
|
|
4809
|
+
}
|
|
4768
4810
|
if (!candles.length) {
|
|
4769
4811
|
i++;
|
|
4770
4812
|
continue;
|
|
@@ -4777,7 +4819,21 @@ class BacktestLogicPrivateService {
|
|
|
4777
4819
|
});
|
|
4778
4820
|
// backtest() сам обработает scheduled signal: найдет активацию/отмену
|
|
4779
4821
|
// и если активируется - продолжит с TP/SL мониторингом
|
|
4780
|
-
|
|
4822
|
+
let backtestResult;
|
|
4823
|
+
try {
|
|
4824
|
+
backtestResult = await this.strategyGlobalService.backtest(symbol, candles, when, true);
|
|
4825
|
+
}
|
|
4826
|
+
catch (error) {
|
|
4827
|
+
console.warn(`backtestLogicPrivateService backtest failed for scheduled signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4828
|
+
this.loggerService.warn("backtestLogicPrivateService backtest failed for scheduled signal", {
|
|
4829
|
+
symbol,
|
|
4830
|
+
signalId: signal.id,
|
|
4831
|
+
error: errorData(error), message: getErrorMessage(error),
|
|
4832
|
+
});
|
|
4833
|
+
await errorEmitter.next(error);
|
|
4834
|
+
i++;
|
|
4835
|
+
continue;
|
|
4836
|
+
}
|
|
4781
4837
|
this.loggerService.info("backtestLogicPrivateService scheduled signal closed", {
|
|
4782
4838
|
symbol,
|
|
4783
4839
|
signalId: backtestResult.signal.id,
|
|
@@ -4818,9 +4874,24 @@ class BacktestLogicPrivateService {
|
|
|
4818
4874
|
minuteEstimatedTime: signal.minuteEstimatedTime,
|
|
4819
4875
|
});
|
|
4820
4876
|
// Получаем свечи для бектеста
|
|
4821
|
-
|
|
4877
|
+
let candles;
|
|
4878
|
+
try {
|
|
4879
|
+
candles = await this.exchangeGlobalService.getNextCandles(symbol, "1m", signal.minuteEstimatedTime, when, true);
|
|
4880
|
+
}
|
|
4881
|
+
catch (error) {
|
|
4882
|
+
console.warn(`backtestLogicPrivateService getNextCandles failed for opened signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4883
|
+
this.loggerService.warn("backtestLogicPrivateService getNextCandles failed for opened signal", {
|
|
4884
|
+
symbol,
|
|
4885
|
+
signalId: signal.id,
|
|
4886
|
+
error: errorData(error), message: getErrorMessage(error),
|
|
4887
|
+
});
|
|
4888
|
+
await errorEmitter.next(error);
|
|
4889
|
+
i++;
|
|
4890
|
+
continue;
|
|
4891
|
+
}
|
|
4822
4892
|
if (!candles.length) {
|
|
4823
|
-
|
|
4893
|
+
i++;
|
|
4894
|
+
continue;
|
|
4824
4895
|
}
|
|
4825
4896
|
this.loggerService.info("backtestLogicPrivateService candles fetched", {
|
|
4826
4897
|
symbol,
|
|
@@ -4828,7 +4899,21 @@ class BacktestLogicPrivateService {
|
|
|
4828
4899
|
candlesCount: candles.length,
|
|
4829
4900
|
});
|
|
4830
4901
|
// Вызываем backtest - всегда возвращает closed
|
|
4831
|
-
|
|
4902
|
+
let backtestResult;
|
|
4903
|
+
try {
|
|
4904
|
+
backtestResult = await this.strategyGlobalService.backtest(symbol, candles, when, true);
|
|
4905
|
+
}
|
|
4906
|
+
catch (error) {
|
|
4907
|
+
console.warn(`backtestLogicPrivateService backtest failed for opened signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
4908
|
+
this.loggerService.warn("backtestLogicPrivateService backtest failed for opened signal", {
|
|
4909
|
+
symbol,
|
|
4910
|
+
signalId: signal.id,
|
|
4911
|
+
error: errorData(error), message: getErrorMessage(error),
|
|
4912
|
+
});
|
|
4913
|
+
await errorEmitter.next(error);
|
|
4914
|
+
i++;
|
|
4915
|
+
continue;
|
|
4916
|
+
}
|
|
4832
4917
|
this.loggerService.info("backtestLogicPrivateService signal closed", {
|
|
4833
4918
|
symbol,
|
|
4834
4919
|
signalId: backtestResult.signal.id,
|
|
@@ -4952,7 +5037,21 @@ class LiveLogicPrivateService {
|
|
|
4952
5037
|
while (true) {
|
|
4953
5038
|
const tickStartTime = performance.now();
|
|
4954
5039
|
const when = new Date();
|
|
4955
|
-
|
|
5040
|
+
let result;
|
|
5041
|
+
try {
|
|
5042
|
+
result = await this.strategyGlobalService.tick(symbol, when, false);
|
|
5043
|
+
}
|
|
5044
|
+
catch (error) {
|
|
5045
|
+
console.warn(`backtestLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
5046
|
+
this.loggerService.warn("liveLogicPrivateService tick failed, retrying after sleep", {
|
|
5047
|
+
symbol,
|
|
5048
|
+
when: when.toISOString(),
|
|
5049
|
+
error: errorData(error), message: getErrorMessage(error),
|
|
5050
|
+
});
|
|
5051
|
+
await errorEmitter.next(error);
|
|
5052
|
+
await sleep(TICK_TTL);
|
|
5053
|
+
continue;
|
|
5054
|
+
}
|
|
4956
5055
|
this.loggerService.info("liveLogicPrivateService tick result", {
|
|
4957
5056
|
symbol,
|
|
4958
5057
|
action: result.action,
|
|
@@ -5074,10 +5173,27 @@ class WalkerLogicPrivateService {
|
|
|
5074
5173
|
frameName: context.frameName,
|
|
5075
5174
|
});
|
|
5076
5175
|
pendingStrategy = strategyName;
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5176
|
+
let result;
|
|
5177
|
+
try {
|
|
5178
|
+
result = await Promise.race([
|
|
5179
|
+
await resolveDocuments(iterator),
|
|
5180
|
+
listenStop,
|
|
5181
|
+
]);
|
|
5182
|
+
}
|
|
5183
|
+
catch (error) {
|
|
5184
|
+
console.warn(`walkerLogicPrivateService backtest failed symbol=${symbol} strategyName=${strategyName} exchangeName=${context.exchangeName}`);
|
|
5185
|
+
this.loggerService.warn("walkerLogicPrivateService backtest failed for strategy, skipping", {
|
|
5186
|
+
strategyName,
|
|
5187
|
+
symbol,
|
|
5188
|
+
error: errorData(error), message: getErrorMessage(error),
|
|
5189
|
+
});
|
|
5190
|
+
await errorEmitter.next(error);
|
|
5191
|
+
// Call onStrategyError callback if provided
|
|
5192
|
+
if (walkerSchema.callbacks?.onStrategyError) {
|
|
5193
|
+
walkerSchema.callbacks.onStrategyError(strategyName, symbol, error);
|
|
5194
|
+
}
|
|
5195
|
+
continue;
|
|
5196
|
+
}
|
|
5081
5197
|
if (result === CANCEL_SYMBOL) {
|
|
5082
5198
|
this.loggerService.info("walkerLogicPrivateService received stop signal, cancelling walker", {
|
|
5083
5199
|
context,
|
|
@@ -11435,6 +11551,7 @@ const LISTEN_SIGNAL_LIVE_ONCE_METHOD_NAME = "event.listenSignalLiveOnce";
|
|
|
11435
11551
|
const LISTEN_SIGNAL_BACKTEST_METHOD_NAME = "event.listenSignalBacktest";
|
|
11436
11552
|
const LISTEN_SIGNAL_BACKTEST_ONCE_METHOD_NAME = "event.listenSignalBacktestOnce";
|
|
11437
11553
|
const LISTEN_ERROR_METHOD_NAME = "event.listenError";
|
|
11554
|
+
const LISTEN_EXIT_METHOD_NAME = "event.listenExit";
|
|
11438
11555
|
const LISTEN_DONE_LIVE_METHOD_NAME = "event.listenDoneLive";
|
|
11439
11556
|
const LISTEN_DONE_LIVE_ONCE_METHOD_NAME = "event.listenDoneLiveOnce";
|
|
11440
11557
|
const LISTEN_DONE_BACKTEST_METHOD_NAME = "event.listenDoneBacktest";
|
|
@@ -11617,9 +11734,10 @@ function listenSignalBacktestOnce(filterFn, fn) {
|
|
|
11617
11734
|
return signalBacktestEmitter.filter(filterFn).once(fn);
|
|
11618
11735
|
}
|
|
11619
11736
|
/**
|
|
11620
|
-
* Subscribes to
|
|
11737
|
+
* Subscribes to recoverable execution errors with queued async processing.
|
|
11621
11738
|
*
|
|
11622
|
-
* Listens to errors
|
|
11739
|
+
* Listens to recoverable errors during strategy execution (e.g., failed API calls).
|
|
11740
|
+
* These errors are caught and handled gracefully - execution continues.
|
|
11623
11741
|
* Events are processed sequentially in order received, even if callback is async.
|
|
11624
11742
|
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
11625
11743
|
*
|
|
@@ -11631,7 +11749,7 @@ function listenSignalBacktestOnce(filterFn, fn) {
|
|
|
11631
11749
|
* import { listenError } from "./function/event";
|
|
11632
11750
|
*
|
|
11633
11751
|
* const unsubscribe = listenError((error) => {
|
|
11634
|
-
* console.error("
|
|
11752
|
+
* console.error("Recoverable error (execution continues):", error.message);
|
|
11635
11753
|
* // Log to monitoring service, send alerts, etc.
|
|
11636
11754
|
* });
|
|
11637
11755
|
*
|
|
@@ -11643,6 +11761,34 @@ function listenError(fn) {
|
|
|
11643
11761
|
backtest$1.loggerService.log(LISTEN_ERROR_METHOD_NAME);
|
|
11644
11762
|
return errorEmitter.subscribe(queued(async (error) => fn(error)));
|
|
11645
11763
|
}
|
|
11764
|
+
/**
|
|
11765
|
+
* Subscribes to fatal execution errors with queued async processing.
|
|
11766
|
+
*
|
|
11767
|
+
* Listens to critical errors that terminate execution (Live.background, Backtest.background, Walker.background).
|
|
11768
|
+
* Unlike listenError (recoverable errors), these errors stop the current process.
|
|
11769
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
11770
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
11771
|
+
*
|
|
11772
|
+
* @param fn - Callback function to handle fatal error events
|
|
11773
|
+
* @returns Unsubscribe function to stop listening
|
|
11774
|
+
*
|
|
11775
|
+
* @example
|
|
11776
|
+
* ```typescript
|
|
11777
|
+
* import { listenExit } from "./function/event";
|
|
11778
|
+
*
|
|
11779
|
+
* const unsubscribe = listenExit((error) => {
|
|
11780
|
+
* console.error("Fatal error (execution terminated):", error.message);
|
|
11781
|
+
* // Log to monitoring, send alerts, restart process, etc.
|
|
11782
|
+
* });
|
|
11783
|
+
*
|
|
11784
|
+
* // Later: stop listening
|
|
11785
|
+
* unsubscribe();
|
|
11786
|
+
* ```
|
|
11787
|
+
*/
|
|
11788
|
+
function listenExit(fn) {
|
|
11789
|
+
backtest$1.loggerService.log(LISTEN_EXIT_METHOD_NAME);
|
|
11790
|
+
return exitEmitter.subscribe(queued(async (error) => fn(error)));
|
|
11791
|
+
}
|
|
11646
11792
|
/**
|
|
11647
11793
|
* Subscribes to live background execution completion events with queued async processing.
|
|
11648
11794
|
*
|
|
@@ -12456,7 +12602,7 @@ class BacktestUtils {
|
|
|
12456
12602
|
}
|
|
12457
12603
|
isDone = true;
|
|
12458
12604
|
};
|
|
12459
|
-
task().catch((error) =>
|
|
12605
|
+
task().catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
|
|
12460
12606
|
return () => {
|
|
12461
12607
|
backtest$1.strategyGlobalService.stop(symbol, context.strategyName);
|
|
12462
12608
|
backtest$1.strategyGlobalService
|
|
@@ -12669,7 +12815,7 @@ class LiveUtils {
|
|
|
12669
12815
|
}
|
|
12670
12816
|
isDone = true;
|
|
12671
12817
|
};
|
|
12672
|
-
task().catch((error) =>
|
|
12818
|
+
task().catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
|
|
12673
12819
|
return () => {
|
|
12674
12820
|
backtest$1.strategyGlobalService.stop(symbol, context.strategyName);
|
|
12675
12821
|
backtest$1.strategyGlobalService
|
|
@@ -13100,7 +13246,7 @@ class WalkerUtils {
|
|
|
13100
13246
|
}
|
|
13101
13247
|
isDone = true;
|
|
13102
13248
|
};
|
|
13103
|
-
task().catch((error) =>
|
|
13249
|
+
task().catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
|
|
13104
13250
|
return () => {
|
|
13105
13251
|
for (const strategyName of walkerSchema.strategies) {
|
|
13106
13252
|
backtest$1.strategyGlobalService.stop(symbol, strategyName);
|
|
@@ -13806,4 +13952,4 @@ class ConstantUtils {
|
|
|
13806
13952
|
*/
|
|
13807
13953
|
const Constant = new ConstantUtils();
|
|
13808
13954
|
|
|
13809
|
-
export { Backtest, Constant, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|
|
13955
|
+
export { Backtest, Constant, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -1201,6 +1201,8 @@ interface IWalkerCallbacks {
|
|
|
1201
1201
|
onStrategyStart: (strategyName: StrategyName, symbol: string) => void;
|
|
1202
1202
|
/** Called when a strategy backtest completes */
|
|
1203
1203
|
onStrategyComplete: (strategyName: StrategyName, symbol: string, stats: BacktestStatistics, metric: number | null) => void;
|
|
1204
|
+
/** Called when a strategy backtest fails with an error */
|
|
1205
|
+
onStrategyError: (strategyName: StrategyName, symbol: string, error: Error | unknown) => void;
|
|
1204
1206
|
/** Called when all strategies have been tested */
|
|
1205
1207
|
onComplete: (results: IWalkerResults) => void;
|
|
1206
1208
|
}
|
|
@@ -2938,9 +2940,10 @@ declare function listenSignalBacktest(fn: (event: IStrategyTickResult) => void):
|
|
|
2938
2940
|
*/
|
|
2939
2941
|
declare function listenSignalBacktestOnce(filterFn: (event: IStrategyTickResult) => boolean, fn: (event: IStrategyTickResult) => void): () => void;
|
|
2940
2942
|
/**
|
|
2941
|
-
* Subscribes to
|
|
2943
|
+
* Subscribes to recoverable execution errors with queued async processing.
|
|
2942
2944
|
*
|
|
2943
|
-
* Listens to errors
|
|
2945
|
+
* Listens to recoverable errors during strategy execution (e.g., failed API calls).
|
|
2946
|
+
* These errors are caught and handled gracefully - execution continues.
|
|
2944
2947
|
* Events are processed sequentially in order received, even if callback is async.
|
|
2945
2948
|
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
2946
2949
|
*
|
|
@@ -2952,7 +2955,7 @@ declare function listenSignalBacktestOnce(filterFn: (event: IStrategyTickResult)
|
|
|
2952
2955
|
* import { listenError } from "./function/event";
|
|
2953
2956
|
*
|
|
2954
2957
|
* const unsubscribe = listenError((error) => {
|
|
2955
|
-
* console.error("
|
|
2958
|
+
* console.error("Recoverable error (execution continues):", error.message);
|
|
2956
2959
|
* // Log to monitoring service, send alerts, etc.
|
|
2957
2960
|
* });
|
|
2958
2961
|
*
|
|
@@ -2961,6 +2964,31 @@ declare function listenSignalBacktestOnce(filterFn: (event: IStrategyTickResult)
|
|
|
2961
2964
|
* ```
|
|
2962
2965
|
*/
|
|
2963
2966
|
declare function listenError(fn: (error: Error) => void): () => void;
|
|
2967
|
+
/**
|
|
2968
|
+
* Subscribes to fatal execution errors with queued async processing.
|
|
2969
|
+
*
|
|
2970
|
+
* Listens to critical errors that terminate execution (Live.background, Backtest.background, Walker.background).
|
|
2971
|
+
* Unlike listenError (recoverable errors), these errors stop the current process.
|
|
2972
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
2973
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
2974
|
+
*
|
|
2975
|
+
* @param fn - Callback function to handle fatal error events
|
|
2976
|
+
* @returns Unsubscribe function to stop listening
|
|
2977
|
+
*
|
|
2978
|
+
* @example
|
|
2979
|
+
* ```typescript
|
|
2980
|
+
* import { listenExit } from "./function/event";
|
|
2981
|
+
*
|
|
2982
|
+
* const unsubscribe = listenExit((error) => {
|
|
2983
|
+
* console.error("Fatal error (execution terminated):", error.message);
|
|
2984
|
+
* // Log to monitoring, send alerts, restart process, etc.
|
|
2985
|
+
* });
|
|
2986
|
+
*
|
|
2987
|
+
* // Later: stop listening
|
|
2988
|
+
* unsubscribe();
|
|
2989
|
+
* ```
|
|
2990
|
+
*/
|
|
2991
|
+
declare function listenExit(fn: (error: Error) => void): () => void;
|
|
2964
2992
|
/**
|
|
2965
2993
|
* Subscribes to live background execution completion events with queued async processing.
|
|
2966
2994
|
*
|
|
@@ -5035,7 +5063,7 @@ declare class BacktestUtils {
|
|
|
5035
5063
|
strategyName: string;
|
|
5036
5064
|
exchangeName: string;
|
|
5037
5065
|
frameName: string;
|
|
5038
|
-
}) => AsyncGenerator<
|
|
5066
|
+
}) => AsyncGenerator<any, void, unknown>;
|
|
5039
5067
|
/**
|
|
5040
5068
|
* Runs backtest in background without yielding results.
|
|
5041
5069
|
*
|
|
@@ -5170,7 +5198,7 @@ declare class LiveUtils {
|
|
|
5170
5198
|
run: (symbol: string, context: {
|
|
5171
5199
|
strategyName: string;
|
|
5172
5200
|
exchangeName: string;
|
|
5173
|
-
}) => AsyncGenerator<
|
|
5201
|
+
}) => AsyncGenerator<any, void, unknown>;
|
|
5174
5202
|
/**
|
|
5175
5203
|
* Runs live trading in background without yielding results.
|
|
5176
5204
|
*
|
|
@@ -6091,6 +6119,12 @@ declare const signalBacktestEmitter: Subject<IStrategyTickResult>;
|
|
|
6091
6119
|
* Emits errors caught in background tasks (Live.background, Backtest.background).
|
|
6092
6120
|
*/
|
|
6093
6121
|
declare const errorEmitter: Subject<Error>;
|
|
6122
|
+
/**
|
|
6123
|
+
* Exit emitter for critical errors that require process termination.
|
|
6124
|
+
* Emits errors that should terminate the current execution (Backtest, Live, Walker).
|
|
6125
|
+
* Unlike errorEmitter (for recoverable errors), exitEmitter signals fatal errors.
|
|
6126
|
+
*/
|
|
6127
|
+
declare const exitEmitter: Subject<Error>;
|
|
6094
6128
|
/**
|
|
6095
6129
|
* Done emitter for live background execution completion.
|
|
6096
6130
|
* Emits when live background tasks complete (Live.background).
|
|
@@ -6164,6 +6198,7 @@ declare const emitters_doneBacktestSubject: typeof doneBacktestSubject;
|
|
|
6164
6198
|
declare const emitters_doneLiveSubject: typeof doneLiveSubject;
|
|
6165
6199
|
declare const emitters_doneWalkerSubject: typeof doneWalkerSubject;
|
|
6166
6200
|
declare const emitters_errorEmitter: typeof errorEmitter;
|
|
6201
|
+
declare const emitters_exitEmitter: typeof exitEmitter;
|
|
6167
6202
|
declare const emitters_partialLossSubject: typeof partialLossSubject;
|
|
6168
6203
|
declare const emitters_partialProfitSubject: typeof partialProfitSubject;
|
|
6169
6204
|
declare const emitters_performanceEmitter: typeof performanceEmitter;
|
|
@@ -6178,7 +6213,7 @@ declare const emitters_walkerCompleteSubject: typeof walkerCompleteSubject;
|
|
|
6178
6213
|
declare const emitters_walkerEmitter: typeof walkerEmitter;
|
|
6179
6214
|
declare const emitters_walkerStopSubject: typeof walkerStopSubject;
|
|
6180
6215
|
declare namespace emitters {
|
|
6181
|
-
export { emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_partialLossSubject as partialLossSubject, emitters_partialProfitSubject as partialProfitSubject, emitters_performanceEmitter as performanceEmitter, emitters_progressBacktestEmitter as progressBacktestEmitter, emitters_progressOptimizerEmitter as progressOptimizerEmitter, emitters_progressWalkerEmitter as progressWalkerEmitter, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter, emitters_walkerStopSubject as walkerStopSubject };
|
|
6216
|
+
export { emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_exitEmitter as exitEmitter, emitters_partialLossSubject as partialLossSubject, emitters_partialProfitSubject as partialProfitSubject, emitters_performanceEmitter as performanceEmitter, emitters_progressBacktestEmitter as progressBacktestEmitter, emitters_progressOptimizerEmitter as progressOptimizerEmitter, emitters_progressWalkerEmitter as progressWalkerEmitter, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter, emitters_walkerStopSubject as walkerStopSubject };
|
|
6182
6217
|
}
|
|
6183
6218
|
|
|
6184
6219
|
/**
|
|
@@ -7416,7 +7451,7 @@ declare class BacktestLogicPrivateService {
|
|
|
7416
7451
|
* }
|
|
7417
7452
|
* ```
|
|
7418
7453
|
*/
|
|
7419
|
-
run(symbol: string): AsyncGenerator<
|
|
7454
|
+
run(symbol: string): AsyncGenerator<any, void, unknown>;
|
|
7420
7455
|
}
|
|
7421
7456
|
|
|
7422
7457
|
/**
|
|
@@ -7461,7 +7496,7 @@ declare class LiveLogicPrivateService {
|
|
|
7461
7496
|
* }
|
|
7462
7497
|
* ```
|
|
7463
7498
|
*/
|
|
7464
|
-
run(symbol: string): AsyncGenerator<
|
|
7499
|
+
run(symbol: string): AsyncGenerator<any, void, unknown>;
|
|
7465
7500
|
}
|
|
7466
7501
|
|
|
7467
7502
|
/**
|
|
@@ -7555,7 +7590,7 @@ declare class BacktestLogicPublicService {
|
|
|
7555
7590
|
strategyName: string;
|
|
7556
7591
|
exchangeName: string;
|
|
7557
7592
|
frameName: string;
|
|
7558
|
-
}) => AsyncGenerator<
|
|
7593
|
+
}) => AsyncGenerator<any, void, unknown>;
|
|
7559
7594
|
}
|
|
7560
7595
|
|
|
7561
7596
|
/**
|
|
@@ -7606,7 +7641,7 @@ declare class LiveLogicPublicService {
|
|
|
7606
7641
|
run: (symbol: string, context: {
|
|
7607
7642
|
strategyName: string;
|
|
7608
7643
|
exchangeName: string;
|
|
7609
|
-
}) => AsyncGenerator<
|
|
7644
|
+
}) => AsyncGenerator<any, void, unknown>;
|
|
7610
7645
|
}
|
|
7611
7646
|
|
|
7612
7647
|
/**
|
|
@@ -7674,7 +7709,7 @@ declare class LiveCommandService {
|
|
|
7674
7709
|
run: (symbol: string, context: {
|
|
7675
7710
|
strategyName: string;
|
|
7676
7711
|
exchangeName: string;
|
|
7677
|
-
}) => AsyncGenerator<
|
|
7712
|
+
}) => AsyncGenerator<any, void, unknown>;
|
|
7678
7713
|
}
|
|
7679
7714
|
|
|
7680
7715
|
/**
|
|
@@ -7702,7 +7737,7 @@ declare class BacktestCommandService {
|
|
|
7702
7737
|
strategyName: string;
|
|
7703
7738
|
exchangeName: string;
|
|
7704
7739
|
frameName: string;
|
|
7705
|
-
}) => AsyncGenerator<
|
|
7740
|
+
}) => AsyncGenerator<any, void, unknown>;
|
|
7706
7741
|
}
|
|
7707
7742
|
|
|
7708
7743
|
/**
|
|
@@ -8659,4 +8694,4 @@ declare const backtest: {
|
|
|
8659
8694
|
loggerService: LoggerService;
|
|
8660
8695
|
};
|
|
8661
8696
|
|
|
8662
|
-
export { Backtest, type BacktestStatistics, type CandleInterval, Constant, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IHeatmapStatistics, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatistics, type MessageModel, type MessageRole, MethodContextService, Optimizer, Partial$1 as Partial, type PartialData, type PartialLossContract, type PartialProfitContract, type PartialStatistics, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressOptimizerContract, type ProgressWalkerContract, type RiskData, Schedule, type ScheduleData, type ScheduleStatistics, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, Walker, type WalkerContract, type WalkerMetric, type WalkerStatistics, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|
|
8697
|
+
export { Backtest, type BacktestStatistics, type CandleInterval, Constant, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IHeatmapStatistics, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatistics, type MessageModel, type MessageRole, MethodContextService, Optimizer, Partial$1 as Partial, type PartialData, type PartialLossContract, type PartialProfitContract, type PartialStatistics, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressOptimizerContract, type ProgressWalkerContract, type RiskData, Schedule, type ScheduleData, type ScheduleStatistics, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, Walker, type WalkerContract, type WalkerMetric, type WalkerStatistics, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|