backtest-kit 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.cjs +137 -21
- package/build/index.mjs +137 -21
- package/package.json +1 -1
- package/types.d.ts +37 -1
package/build/index.cjs
CHANGED
|
@@ -1430,6 +1430,11 @@ const walkerEmitter = new functoolsKit.Subject();
|
|
|
1430
1430
|
* Emits when all strategies have been tested and final results are available.
|
|
1431
1431
|
*/
|
|
1432
1432
|
const walkerCompleteSubject = new functoolsKit.Subject();
|
|
1433
|
+
/**
|
|
1434
|
+
* Walker stop emitter for walker cancellation events.
|
|
1435
|
+
* Emits when a walker comparison is stopped/cancelled.
|
|
1436
|
+
*/
|
|
1437
|
+
const walkerStopSubject = new functoolsKit.Subject();
|
|
1433
1438
|
/**
|
|
1434
1439
|
* Validation emitter for risk validation errors.
|
|
1435
1440
|
* Emits when risk validation functions throw errors during signal checking.
|
|
@@ -1449,7 +1454,8 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
1449
1454
|
signalLiveEmitter: signalLiveEmitter,
|
|
1450
1455
|
validationSubject: validationSubject,
|
|
1451
1456
|
walkerCompleteSubject: walkerCompleteSubject,
|
|
1452
|
-
walkerEmitter: walkerEmitter
|
|
1457
|
+
walkerEmitter: walkerEmitter,
|
|
1458
|
+
walkerStopSubject: walkerStopSubject
|
|
1453
1459
|
});
|
|
1454
1460
|
|
|
1455
1461
|
const INTERVAL_MINUTES$1 = {
|
|
@@ -1625,6 +1631,9 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
|
|
|
1625
1631
|
if (!signal) {
|
|
1626
1632
|
return null;
|
|
1627
1633
|
}
|
|
1634
|
+
if (self._isStopped) {
|
|
1635
|
+
return null;
|
|
1636
|
+
}
|
|
1628
1637
|
// Если priceOpen указан - проверяем нужно ли ждать активации или открыть сразу
|
|
1629
1638
|
if (signal.priceOpen !== undefined) {
|
|
1630
1639
|
// КРИТИЧЕСКАЯ ПРОВЕРКА: достигнут ли priceOpen?
|
|
@@ -2351,6 +2360,14 @@ class ClientStrategy {
|
|
|
2351
2360
|
}
|
|
2352
2361
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.strategyName, this.params.execution.context.symbol);
|
|
2353
2362
|
}
|
|
2363
|
+
/**
|
|
2364
|
+
* Retrieves the current pending signal.
|
|
2365
|
+
* If no signal is pending, returns null.
|
|
2366
|
+
* @returns Promise resolving to the pending signal or null.
|
|
2367
|
+
*/
|
|
2368
|
+
async getPendingSignal() {
|
|
2369
|
+
return this._pendingSignal;
|
|
2370
|
+
}
|
|
2354
2371
|
/**
|
|
2355
2372
|
* Performs a single tick of strategy execution.
|
|
2356
2373
|
*
|
|
@@ -2656,6 +2673,20 @@ class StrategyConnectionService {
|
|
|
2656
2673
|
callbacks,
|
|
2657
2674
|
});
|
|
2658
2675
|
});
|
|
2676
|
+
/**
|
|
2677
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
2678
|
+
* If no active signal exists, returns null.
|
|
2679
|
+
* Used internally for monitoring TP/SL and time expiration.
|
|
2680
|
+
*
|
|
2681
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
2682
|
+
*
|
|
2683
|
+
* @returns Promise resolving to pending signal or null
|
|
2684
|
+
*/
|
|
2685
|
+
this.getPendingSignal = async (strategyName) => {
|
|
2686
|
+
this.loggerService.log("strategyConnectionService getPendingSignal");
|
|
2687
|
+
const strategy = await this.getStrategy(strategyName);
|
|
2688
|
+
return await strategy.getPendingSignal();
|
|
2689
|
+
};
|
|
2659
2690
|
/**
|
|
2660
2691
|
* Executes live trading tick for current strategy.
|
|
2661
2692
|
*
|
|
@@ -3558,6 +3589,23 @@ class StrategyGlobalService {
|
|
|
3558
3589
|
riskName &&
|
|
3559
3590
|
this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
3560
3591
|
});
|
|
3592
|
+
/**
|
|
3593
|
+
* Retrieves the currently active pending signal for the symbol.
|
|
3594
|
+
* If no active signal exists, returns null.
|
|
3595
|
+
* Used internally for monitoring TP/SL and time expiration.
|
|
3596
|
+
*
|
|
3597
|
+
* @param symbol - Trading pair symbol
|
|
3598
|
+
* @param when - Timestamp for tick evaluation
|
|
3599
|
+
* @param backtest - Whether running in backtest mode
|
|
3600
|
+
* @returns Promise resolving to pending signal or null
|
|
3601
|
+
*/
|
|
3602
|
+
this.getPendingSignal = async (strategyName) => {
|
|
3603
|
+
this.loggerService.log("strategyGlobalService getPendingSignal", {
|
|
3604
|
+
strategyName,
|
|
3605
|
+
});
|
|
3606
|
+
await this.validate(this.methodContextService.context.strategyName);
|
|
3607
|
+
return await this.strategyConnectionService.getPendingSignal(strategyName);
|
|
3608
|
+
};
|
|
3561
3609
|
/**
|
|
3562
3610
|
* Checks signal status at a specific timestamp.
|
|
3563
3611
|
*
|
|
@@ -4560,6 +4608,7 @@ class LiveLogicPrivateService {
|
|
|
4560
4608
|
}
|
|
4561
4609
|
}
|
|
4562
4610
|
|
|
4611
|
+
const CANCEL_SYMBOL = Symbol("CANCEL_SYMBOL");
|
|
4563
4612
|
/**
|
|
4564
4613
|
* Private service for walker orchestration (strategy comparison).
|
|
4565
4614
|
*
|
|
@@ -4617,6 +4666,10 @@ class WalkerLogicPrivateService {
|
|
|
4617
4666
|
let strategiesTested = 0;
|
|
4618
4667
|
let bestMetric = null;
|
|
4619
4668
|
let bestStrategy = null;
|
|
4669
|
+
const listenStop = walkerStopSubject
|
|
4670
|
+
.filter((walkerName) => walkerName === context.walkerName)
|
|
4671
|
+
.map(() => CANCEL_SYMBOL)
|
|
4672
|
+
.toPromise();
|
|
4620
4673
|
// Run backtest for each strategy
|
|
4621
4674
|
for (const strategyName of strategies) {
|
|
4622
4675
|
// Call onStrategyStart callback if provided
|
|
@@ -4632,7 +4685,16 @@ class WalkerLogicPrivateService {
|
|
|
4632
4685
|
exchangeName: context.exchangeName,
|
|
4633
4686
|
frameName: context.frameName,
|
|
4634
4687
|
});
|
|
4635
|
-
await
|
|
4688
|
+
const result = await Promise.race([
|
|
4689
|
+
await functoolsKit.resolveDocuments(iterator),
|
|
4690
|
+
listenStop,
|
|
4691
|
+
]);
|
|
4692
|
+
if (result === CANCEL_SYMBOL) {
|
|
4693
|
+
this.loggerService.info("walkerLogicPrivateService received stop signal, cancelling walker", {
|
|
4694
|
+
context,
|
|
4695
|
+
});
|
|
4696
|
+
break;
|
|
4697
|
+
}
|
|
4636
4698
|
this.loggerService.info("walkerLogicPrivateService backtest complete", {
|
|
4637
4699
|
strategyName,
|
|
4638
4700
|
symbol,
|
|
@@ -9296,22 +9358,42 @@ class BacktestUtils {
|
|
|
9296
9358
|
context,
|
|
9297
9359
|
});
|
|
9298
9360
|
let isStopped = false;
|
|
9361
|
+
let isDone = false;
|
|
9299
9362
|
const task = async () => {
|
|
9300
9363
|
for await (const _ of this.run(symbol, context)) {
|
|
9301
9364
|
if (isStopped) {
|
|
9302
9365
|
break;
|
|
9303
9366
|
}
|
|
9304
9367
|
}
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9368
|
+
if (!isDone) {
|
|
9369
|
+
await doneBacktestSubject.next({
|
|
9370
|
+
exchangeName: context.exchangeName,
|
|
9371
|
+
strategyName: context.strategyName,
|
|
9372
|
+
backtest: true,
|
|
9373
|
+
symbol,
|
|
9374
|
+
});
|
|
9375
|
+
}
|
|
9376
|
+
isDone = true;
|
|
9311
9377
|
};
|
|
9312
9378
|
task().catch((error) => errorEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
9313
9379
|
return () => {
|
|
9314
9380
|
backtest$1.strategyGlobalService.stop(context.strategyName);
|
|
9381
|
+
backtest$1.strategyGlobalService
|
|
9382
|
+
.getPendingSignal(context.strategyName)
|
|
9383
|
+
.then(async (pendingSignal) => {
|
|
9384
|
+
if (pendingSignal) {
|
|
9385
|
+
return;
|
|
9386
|
+
}
|
|
9387
|
+
if (!isDone) {
|
|
9388
|
+
await doneBacktestSubject.next({
|
|
9389
|
+
exchangeName: context.exchangeName,
|
|
9390
|
+
strategyName: context.strategyName,
|
|
9391
|
+
backtest: true,
|
|
9392
|
+
symbol,
|
|
9393
|
+
});
|
|
9394
|
+
}
|
|
9395
|
+
isDone = true;
|
|
9396
|
+
});
|
|
9315
9397
|
isStopped = true;
|
|
9316
9398
|
};
|
|
9317
9399
|
};
|
|
@@ -9485,22 +9567,42 @@ class LiveUtils {
|
|
|
9485
9567
|
context,
|
|
9486
9568
|
});
|
|
9487
9569
|
let isStopped = false;
|
|
9570
|
+
let isDone = false;
|
|
9488
9571
|
const task = async () => {
|
|
9489
9572
|
for await (const signal of this.run(symbol, context)) {
|
|
9490
9573
|
if (signal?.action === "closed" && isStopped) {
|
|
9491
9574
|
break;
|
|
9492
9575
|
}
|
|
9493
9576
|
}
|
|
9494
|
-
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9577
|
+
if (!isDone) {
|
|
9578
|
+
await doneLiveSubject.next({
|
|
9579
|
+
exchangeName: context.exchangeName,
|
|
9580
|
+
strategyName: context.strategyName,
|
|
9581
|
+
backtest: false,
|
|
9582
|
+
symbol,
|
|
9583
|
+
});
|
|
9584
|
+
}
|
|
9585
|
+
isDone = true;
|
|
9500
9586
|
};
|
|
9501
9587
|
task().catch((error) => errorEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
9502
9588
|
return () => {
|
|
9503
9589
|
backtest$1.strategyGlobalService.stop(context.strategyName);
|
|
9590
|
+
backtest$1.strategyGlobalService
|
|
9591
|
+
.getPendingSignal(context.strategyName)
|
|
9592
|
+
.then(async (pendingSignal) => {
|
|
9593
|
+
if (pendingSignal) {
|
|
9594
|
+
return;
|
|
9595
|
+
}
|
|
9596
|
+
if (!isDone) {
|
|
9597
|
+
await doneLiveSubject.next({
|
|
9598
|
+
exchangeName: context.exchangeName,
|
|
9599
|
+
strategyName: context.strategyName,
|
|
9600
|
+
backtest: false,
|
|
9601
|
+
symbol,
|
|
9602
|
+
});
|
|
9603
|
+
}
|
|
9604
|
+
isDone = true;
|
|
9605
|
+
});
|
|
9504
9606
|
isStopped = true;
|
|
9505
9607
|
};
|
|
9506
9608
|
};
|
|
@@ -9926,25 +10028,39 @@ class WalkerUtils {
|
|
|
9926
10028
|
});
|
|
9927
10029
|
const walkerSchema = backtest$1.walkerSchemaService.get(context.walkerName);
|
|
9928
10030
|
let isStopped = false;
|
|
10031
|
+
let isDone = false;
|
|
9929
10032
|
const task = async () => {
|
|
9930
10033
|
for await (const _ of this.run(symbol, context)) {
|
|
9931
10034
|
if (isStopped) {
|
|
9932
10035
|
break;
|
|
9933
10036
|
}
|
|
9934
10037
|
}
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
10038
|
+
if (!isDone) {
|
|
10039
|
+
await doneWalkerSubject.next({
|
|
10040
|
+
exchangeName: walkerSchema.exchangeName,
|
|
10041
|
+
strategyName: context.walkerName,
|
|
10042
|
+
backtest: true,
|
|
10043
|
+
symbol,
|
|
10044
|
+
});
|
|
10045
|
+
}
|
|
10046
|
+
isDone = true;
|
|
9941
10047
|
};
|
|
9942
10048
|
task().catch((error) => errorEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
9943
10049
|
return () => {
|
|
9944
|
-
isStopped = true;
|
|
9945
10050
|
for (const strategyName of walkerSchema.strategies) {
|
|
9946
10051
|
backtest$1.strategyGlobalService.stop(strategyName);
|
|
9947
10052
|
}
|
|
10053
|
+
walkerStopSubject.next(context.walkerName);
|
|
10054
|
+
if (!isDone) {
|
|
10055
|
+
doneWalkerSubject.next({
|
|
10056
|
+
exchangeName: walkerSchema.exchangeName,
|
|
10057
|
+
strategyName: context.walkerName,
|
|
10058
|
+
backtest: true,
|
|
10059
|
+
symbol,
|
|
10060
|
+
});
|
|
10061
|
+
}
|
|
10062
|
+
isDone = true;
|
|
10063
|
+
isStopped = true;
|
|
9948
10064
|
};
|
|
9949
10065
|
};
|
|
9950
10066
|
/**
|
package/build/index.mjs
CHANGED
|
@@ -1428,6 +1428,11 @@ const walkerEmitter = new Subject();
|
|
|
1428
1428
|
* Emits when all strategies have been tested and final results are available.
|
|
1429
1429
|
*/
|
|
1430
1430
|
const walkerCompleteSubject = new Subject();
|
|
1431
|
+
/**
|
|
1432
|
+
* Walker stop emitter for walker cancellation events.
|
|
1433
|
+
* Emits when a walker comparison is stopped/cancelled.
|
|
1434
|
+
*/
|
|
1435
|
+
const walkerStopSubject = new Subject();
|
|
1431
1436
|
/**
|
|
1432
1437
|
* Validation emitter for risk validation errors.
|
|
1433
1438
|
* Emits when risk validation functions throw errors during signal checking.
|
|
@@ -1447,7 +1452,8 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
1447
1452
|
signalLiveEmitter: signalLiveEmitter,
|
|
1448
1453
|
validationSubject: validationSubject,
|
|
1449
1454
|
walkerCompleteSubject: walkerCompleteSubject,
|
|
1450
|
-
walkerEmitter: walkerEmitter
|
|
1455
|
+
walkerEmitter: walkerEmitter,
|
|
1456
|
+
walkerStopSubject: walkerStopSubject
|
|
1451
1457
|
});
|
|
1452
1458
|
|
|
1453
1459
|
const INTERVAL_MINUTES$1 = {
|
|
@@ -1623,6 +1629,9 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
|
|
|
1623
1629
|
if (!signal) {
|
|
1624
1630
|
return null;
|
|
1625
1631
|
}
|
|
1632
|
+
if (self._isStopped) {
|
|
1633
|
+
return null;
|
|
1634
|
+
}
|
|
1626
1635
|
// Если priceOpen указан - проверяем нужно ли ждать активации или открыть сразу
|
|
1627
1636
|
if (signal.priceOpen !== undefined) {
|
|
1628
1637
|
// КРИТИЧЕСКАЯ ПРОВЕРКА: достигнут ли priceOpen?
|
|
@@ -2349,6 +2358,14 @@ class ClientStrategy {
|
|
|
2349
2358
|
}
|
|
2350
2359
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.strategyName, this.params.execution.context.symbol);
|
|
2351
2360
|
}
|
|
2361
|
+
/**
|
|
2362
|
+
* Retrieves the current pending signal.
|
|
2363
|
+
* If no signal is pending, returns null.
|
|
2364
|
+
* @returns Promise resolving to the pending signal or null.
|
|
2365
|
+
*/
|
|
2366
|
+
async getPendingSignal() {
|
|
2367
|
+
return this._pendingSignal;
|
|
2368
|
+
}
|
|
2352
2369
|
/**
|
|
2353
2370
|
* Performs a single tick of strategy execution.
|
|
2354
2371
|
*
|
|
@@ -2654,6 +2671,20 @@ class StrategyConnectionService {
|
|
|
2654
2671
|
callbacks,
|
|
2655
2672
|
});
|
|
2656
2673
|
});
|
|
2674
|
+
/**
|
|
2675
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
2676
|
+
* If no active signal exists, returns null.
|
|
2677
|
+
* Used internally for monitoring TP/SL and time expiration.
|
|
2678
|
+
*
|
|
2679
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
2680
|
+
*
|
|
2681
|
+
* @returns Promise resolving to pending signal or null
|
|
2682
|
+
*/
|
|
2683
|
+
this.getPendingSignal = async (strategyName) => {
|
|
2684
|
+
this.loggerService.log("strategyConnectionService getPendingSignal");
|
|
2685
|
+
const strategy = await this.getStrategy(strategyName);
|
|
2686
|
+
return await strategy.getPendingSignal();
|
|
2687
|
+
};
|
|
2657
2688
|
/**
|
|
2658
2689
|
* Executes live trading tick for current strategy.
|
|
2659
2690
|
*
|
|
@@ -3556,6 +3587,23 @@ class StrategyGlobalService {
|
|
|
3556
3587
|
riskName &&
|
|
3557
3588
|
this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
3558
3589
|
});
|
|
3590
|
+
/**
|
|
3591
|
+
* Retrieves the currently active pending signal for the symbol.
|
|
3592
|
+
* If no active signal exists, returns null.
|
|
3593
|
+
* Used internally for monitoring TP/SL and time expiration.
|
|
3594
|
+
*
|
|
3595
|
+
* @param symbol - Trading pair symbol
|
|
3596
|
+
* @param when - Timestamp for tick evaluation
|
|
3597
|
+
* @param backtest - Whether running in backtest mode
|
|
3598
|
+
* @returns Promise resolving to pending signal or null
|
|
3599
|
+
*/
|
|
3600
|
+
this.getPendingSignal = async (strategyName) => {
|
|
3601
|
+
this.loggerService.log("strategyGlobalService getPendingSignal", {
|
|
3602
|
+
strategyName,
|
|
3603
|
+
});
|
|
3604
|
+
await this.validate(this.methodContextService.context.strategyName);
|
|
3605
|
+
return await this.strategyConnectionService.getPendingSignal(strategyName);
|
|
3606
|
+
};
|
|
3559
3607
|
/**
|
|
3560
3608
|
* Checks signal status at a specific timestamp.
|
|
3561
3609
|
*
|
|
@@ -4558,6 +4606,7 @@ class LiveLogicPrivateService {
|
|
|
4558
4606
|
}
|
|
4559
4607
|
}
|
|
4560
4608
|
|
|
4609
|
+
const CANCEL_SYMBOL = Symbol("CANCEL_SYMBOL");
|
|
4561
4610
|
/**
|
|
4562
4611
|
* Private service for walker orchestration (strategy comparison).
|
|
4563
4612
|
*
|
|
@@ -4615,6 +4664,10 @@ class WalkerLogicPrivateService {
|
|
|
4615
4664
|
let strategiesTested = 0;
|
|
4616
4665
|
let bestMetric = null;
|
|
4617
4666
|
let bestStrategy = null;
|
|
4667
|
+
const listenStop = walkerStopSubject
|
|
4668
|
+
.filter((walkerName) => walkerName === context.walkerName)
|
|
4669
|
+
.map(() => CANCEL_SYMBOL)
|
|
4670
|
+
.toPromise();
|
|
4618
4671
|
// Run backtest for each strategy
|
|
4619
4672
|
for (const strategyName of strategies) {
|
|
4620
4673
|
// Call onStrategyStart callback if provided
|
|
@@ -4630,7 +4683,16 @@ class WalkerLogicPrivateService {
|
|
|
4630
4683
|
exchangeName: context.exchangeName,
|
|
4631
4684
|
frameName: context.frameName,
|
|
4632
4685
|
});
|
|
4633
|
-
await
|
|
4686
|
+
const result = await Promise.race([
|
|
4687
|
+
await resolveDocuments(iterator),
|
|
4688
|
+
listenStop,
|
|
4689
|
+
]);
|
|
4690
|
+
if (result === CANCEL_SYMBOL) {
|
|
4691
|
+
this.loggerService.info("walkerLogicPrivateService received stop signal, cancelling walker", {
|
|
4692
|
+
context,
|
|
4693
|
+
});
|
|
4694
|
+
break;
|
|
4695
|
+
}
|
|
4634
4696
|
this.loggerService.info("walkerLogicPrivateService backtest complete", {
|
|
4635
4697
|
strategyName,
|
|
4636
4698
|
symbol,
|
|
@@ -9294,22 +9356,42 @@ class BacktestUtils {
|
|
|
9294
9356
|
context,
|
|
9295
9357
|
});
|
|
9296
9358
|
let isStopped = false;
|
|
9359
|
+
let isDone = false;
|
|
9297
9360
|
const task = async () => {
|
|
9298
9361
|
for await (const _ of this.run(symbol, context)) {
|
|
9299
9362
|
if (isStopped) {
|
|
9300
9363
|
break;
|
|
9301
9364
|
}
|
|
9302
9365
|
}
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9366
|
+
if (!isDone) {
|
|
9367
|
+
await doneBacktestSubject.next({
|
|
9368
|
+
exchangeName: context.exchangeName,
|
|
9369
|
+
strategyName: context.strategyName,
|
|
9370
|
+
backtest: true,
|
|
9371
|
+
symbol,
|
|
9372
|
+
});
|
|
9373
|
+
}
|
|
9374
|
+
isDone = true;
|
|
9309
9375
|
};
|
|
9310
9376
|
task().catch((error) => errorEmitter.next(new Error(getErrorMessage(error))));
|
|
9311
9377
|
return () => {
|
|
9312
9378
|
backtest$1.strategyGlobalService.stop(context.strategyName);
|
|
9379
|
+
backtest$1.strategyGlobalService
|
|
9380
|
+
.getPendingSignal(context.strategyName)
|
|
9381
|
+
.then(async (pendingSignal) => {
|
|
9382
|
+
if (pendingSignal) {
|
|
9383
|
+
return;
|
|
9384
|
+
}
|
|
9385
|
+
if (!isDone) {
|
|
9386
|
+
await doneBacktestSubject.next({
|
|
9387
|
+
exchangeName: context.exchangeName,
|
|
9388
|
+
strategyName: context.strategyName,
|
|
9389
|
+
backtest: true,
|
|
9390
|
+
symbol,
|
|
9391
|
+
});
|
|
9392
|
+
}
|
|
9393
|
+
isDone = true;
|
|
9394
|
+
});
|
|
9313
9395
|
isStopped = true;
|
|
9314
9396
|
};
|
|
9315
9397
|
};
|
|
@@ -9483,22 +9565,42 @@ class LiveUtils {
|
|
|
9483
9565
|
context,
|
|
9484
9566
|
});
|
|
9485
9567
|
let isStopped = false;
|
|
9568
|
+
let isDone = false;
|
|
9486
9569
|
const task = async () => {
|
|
9487
9570
|
for await (const signal of this.run(symbol, context)) {
|
|
9488
9571
|
if (signal?.action === "closed" && isStopped) {
|
|
9489
9572
|
break;
|
|
9490
9573
|
}
|
|
9491
9574
|
}
|
|
9492
|
-
|
|
9493
|
-
|
|
9494
|
-
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9575
|
+
if (!isDone) {
|
|
9576
|
+
await doneLiveSubject.next({
|
|
9577
|
+
exchangeName: context.exchangeName,
|
|
9578
|
+
strategyName: context.strategyName,
|
|
9579
|
+
backtest: false,
|
|
9580
|
+
symbol,
|
|
9581
|
+
});
|
|
9582
|
+
}
|
|
9583
|
+
isDone = true;
|
|
9498
9584
|
};
|
|
9499
9585
|
task().catch((error) => errorEmitter.next(new Error(getErrorMessage(error))));
|
|
9500
9586
|
return () => {
|
|
9501
9587
|
backtest$1.strategyGlobalService.stop(context.strategyName);
|
|
9588
|
+
backtest$1.strategyGlobalService
|
|
9589
|
+
.getPendingSignal(context.strategyName)
|
|
9590
|
+
.then(async (pendingSignal) => {
|
|
9591
|
+
if (pendingSignal) {
|
|
9592
|
+
return;
|
|
9593
|
+
}
|
|
9594
|
+
if (!isDone) {
|
|
9595
|
+
await doneLiveSubject.next({
|
|
9596
|
+
exchangeName: context.exchangeName,
|
|
9597
|
+
strategyName: context.strategyName,
|
|
9598
|
+
backtest: false,
|
|
9599
|
+
symbol,
|
|
9600
|
+
});
|
|
9601
|
+
}
|
|
9602
|
+
isDone = true;
|
|
9603
|
+
});
|
|
9502
9604
|
isStopped = true;
|
|
9503
9605
|
};
|
|
9504
9606
|
};
|
|
@@ -9924,25 +10026,39 @@ class WalkerUtils {
|
|
|
9924
10026
|
});
|
|
9925
10027
|
const walkerSchema = backtest$1.walkerSchemaService.get(context.walkerName);
|
|
9926
10028
|
let isStopped = false;
|
|
10029
|
+
let isDone = false;
|
|
9927
10030
|
const task = async () => {
|
|
9928
10031
|
for await (const _ of this.run(symbol, context)) {
|
|
9929
10032
|
if (isStopped) {
|
|
9930
10033
|
break;
|
|
9931
10034
|
}
|
|
9932
10035
|
}
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
10036
|
+
if (!isDone) {
|
|
10037
|
+
await doneWalkerSubject.next({
|
|
10038
|
+
exchangeName: walkerSchema.exchangeName,
|
|
10039
|
+
strategyName: context.walkerName,
|
|
10040
|
+
backtest: true,
|
|
10041
|
+
symbol,
|
|
10042
|
+
});
|
|
10043
|
+
}
|
|
10044
|
+
isDone = true;
|
|
9939
10045
|
};
|
|
9940
10046
|
task().catch((error) => errorEmitter.next(new Error(getErrorMessage(error))));
|
|
9941
10047
|
return () => {
|
|
9942
|
-
isStopped = true;
|
|
9943
10048
|
for (const strategyName of walkerSchema.strategies) {
|
|
9944
10049
|
backtest$1.strategyGlobalService.stop(strategyName);
|
|
9945
10050
|
}
|
|
10051
|
+
walkerStopSubject.next(context.walkerName);
|
|
10052
|
+
if (!isDone) {
|
|
10053
|
+
doneWalkerSubject.next({
|
|
10054
|
+
exchangeName: walkerSchema.exchangeName,
|
|
10055
|
+
strategyName: context.walkerName,
|
|
10056
|
+
backtest: true,
|
|
10057
|
+
symbol,
|
|
10058
|
+
});
|
|
10059
|
+
}
|
|
10060
|
+
isDone = true;
|
|
10061
|
+
isStopped = true;
|
|
9946
10062
|
};
|
|
9947
10063
|
};
|
|
9948
10064
|
/**
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -825,6 +825,15 @@ interface IStrategy {
|
|
|
825
825
|
* @returns Promise resolving to tick result (idle | opened | active | closed)
|
|
826
826
|
*/
|
|
827
827
|
tick: (symbol: string) => Promise<IStrategyTickResult>;
|
|
828
|
+
/**
|
|
829
|
+
* Retrieves the currently active pending signal for the symbol.
|
|
830
|
+
* If no active signal exists, returns null.
|
|
831
|
+
* Used internally for monitoring TP/SL and time expiration.
|
|
832
|
+
*
|
|
833
|
+
* @param symbol
|
|
834
|
+
* @returns
|
|
835
|
+
*/
|
|
836
|
+
getPendingSignal: (symbol: string) => Promise<ISignalRow | null>;
|
|
828
837
|
/**
|
|
829
838
|
* Fast backtest using historical candles.
|
|
830
839
|
* Iterates through candles, calculates VWAP, checks TP/SL on each candle.
|
|
@@ -4437,6 +4446,11 @@ declare const walkerEmitter: Subject<WalkerContract>;
|
|
|
4437
4446
|
* Emits when all strategies have been tested and final results are available.
|
|
4438
4447
|
*/
|
|
4439
4448
|
declare const walkerCompleteSubject: Subject<IWalkerResults>;
|
|
4449
|
+
/**
|
|
4450
|
+
* Walker stop emitter for walker cancellation events.
|
|
4451
|
+
* Emits when a walker comparison is stopped/cancelled.
|
|
4452
|
+
*/
|
|
4453
|
+
declare const walkerStopSubject: Subject<string>;
|
|
4440
4454
|
/**
|
|
4441
4455
|
* Validation emitter for risk validation errors.
|
|
4442
4456
|
* Emits when risk validation functions throw errors during signal checking.
|
|
@@ -4455,8 +4469,9 @@ declare const emitters_signalLiveEmitter: typeof signalLiveEmitter;
|
|
|
4455
4469
|
declare const emitters_validationSubject: typeof validationSubject;
|
|
4456
4470
|
declare const emitters_walkerCompleteSubject: typeof walkerCompleteSubject;
|
|
4457
4471
|
declare const emitters_walkerEmitter: typeof walkerEmitter;
|
|
4472
|
+
declare const emitters_walkerStopSubject: typeof walkerStopSubject;
|
|
4458
4473
|
declare namespace emitters {
|
|
4459
|
-
export { emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_performanceEmitter as performanceEmitter, emitters_progressEmitter as progressEmitter, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter };
|
|
4474
|
+
export { emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_performanceEmitter as performanceEmitter, emitters_progressEmitter as progressEmitter, 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 };
|
|
4460
4475
|
}
|
|
4461
4476
|
|
|
4462
4477
|
/**
|
|
@@ -4718,6 +4733,16 @@ declare class StrategyConnectionService implements IStrategy {
|
|
|
4718
4733
|
* @returns Configured ClientStrategy instance
|
|
4719
4734
|
*/
|
|
4720
4735
|
private getStrategy;
|
|
4736
|
+
/**
|
|
4737
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
4738
|
+
* If no active signal exists, returns null.
|
|
4739
|
+
* Used internally for monitoring TP/SL and time expiration.
|
|
4740
|
+
*
|
|
4741
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
4742
|
+
*
|
|
4743
|
+
* @returns Promise resolving to pending signal or null
|
|
4744
|
+
*/
|
|
4745
|
+
getPendingSignal: (strategyName: StrategyName) => Promise<ISignalRow | null>;
|
|
4721
4746
|
/**
|
|
4722
4747
|
* Executes live trading tick for current strategy.
|
|
4723
4748
|
*
|
|
@@ -5165,6 +5190,17 @@ declare class StrategyGlobalService {
|
|
|
5165
5190
|
* @returns Promise that resolves when validation is complete
|
|
5166
5191
|
*/
|
|
5167
5192
|
private validate;
|
|
5193
|
+
/**
|
|
5194
|
+
* Retrieves the currently active pending signal for the symbol.
|
|
5195
|
+
* If no active signal exists, returns null.
|
|
5196
|
+
* Used internally for monitoring TP/SL and time expiration.
|
|
5197
|
+
*
|
|
5198
|
+
* @param symbol - Trading pair symbol
|
|
5199
|
+
* @param when - Timestamp for tick evaluation
|
|
5200
|
+
* @param backtest - Whether running in backtest mode
|
|
5201
|
+
* @returns Promise resolving to pending signal or null
|
|
5202
|
+
*/
|
|
5203
|
+
getPendingSignal: (strategyName: StrategyName) => Promise<ISignalRow | null>;
|
|
5168
5204
|
/**
|
|
5169
5205
|
* Checks signal status at a specific timestamp.
|
|
5170
5206
|
*
|