backtest-kit 1.5.26 → 1.5.27
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 +190 -115
- package/build/index.mjs +190 -115
- package/package.json +1 -1
- package/types.d.ts +38 -26
package/build/index.cjs
CHANGED
|
@@ -2628,7 +2628,7 @@ const PersistScheduleAdapter = new PersistScheduleUtils();
|
|
|
2628
2628
|
* Utility class for managing partial profit/loss levels persistence.
|
|
2629
2629
|
*
|
|
2630
2630
|
* Features:
|
|
2631
|
-
* - Memoized storage instances per symbol
|
|
2631
|
+
* - Memoized storage instances per symbol:strategyName
|
|
2632
2632
|
* - Custom adapter support
|
|
2633
2633
|
* - Atomic read/write operations for partial data
|
|
2634
2634
|
* - Crash-safe partial state management
|
|
@@ -2638,23 +2638,25 @@ const PersistScheduleAdapter = new PersistScheduleUtils();
|
|
|
2638
2638
|
class PersistPartialUtils {
|
|
2639
2639
|
constructor() {
|
|
2640
2640
|
this.PersistPartialFactory = PersistBase;
|
|
2641
|
-
this.getPartialStorage = functoolsKit.memoize(([symbol]) => `${symbol}`, (symbol) => Reflect.construct(this.PersistPartialFactory, [
|
|
2642
|
-
symbol
|
|
2641
|
+
this.getPartialStorage = functoolsKit.memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => Reflect.construct(this.PersistPartialFactory, [
|
|
2642
|
+
`${symbol}_${strategyName}`,
|
|
2643
2643
|
`./dump/data/partial/`,
|
|
2644
2644
|
]));
|
|
2645
2645
|
/**
|
|
2646
|
-
* Reads persisted partial data for a symbol.
|
|
2646
|
+
* Reads persisted partial data for a symbol and strategy.
|
|
2647
2647
|
*
|
|
2648
2648
|
* Called by ClientPartial.waitForInit() to restore state.
|
|
2649
2649
|
* Returns empty object if no partial data exists.
|
|
2650
2650
|
*
|
|
2651
2651
|
* @param symbol - Trading pair symbol
|
|
2652
|
+
* @param strategyName - Strategy identifier
|
|
2652
2653
|
* @returns Promise resolving to partial data record
|
|
2653
2654
|
*/
|
|
2654
|
-
this.readPartialData = async (symbol) => {
|
|
2655
|
+
this.readPartialData = async (symbol, strategyName) => {
|
|
2655
2656
|
backtest$1.loggerService.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
|
|
2656
|
-
const
|
|
2657
|
-
const
|
|
2657
|
+
const key = `${symbol}:${strategyName}`;
|
|
2658
|
+
const isInitial = !this.getPartialStorage.has(key);
|
|
2659
|
+
const stateStorage = this.getPartialStorage(symbol, strategyName);
|
|
2658
2660
|
await stateStorage.waitForInit(isInitial);
|
|
2659
2661
|
const PARTIAL_STORAGE_KEY = "levels";
|
|
2660
2662
|
if (await stateStorage.hasValue(PARTIAL_STORAGE_KEY)) {
|
|
@@ -2670,12 +2672,14 @@ class PersistPartialUtils {
|
|
|
2670
2672
|
*
|
|
2671
2673
|
* @param partialData - Record of signal IDs to partial data
|
|
2672
2674
|
* @param symbol - Trading pair symbol
|
|
2675
|
+
* @param strategyName - Strategy identifier
|
|
2673
2676
|
* @returns Promise that resolves when write is complete
|
|
2674
2677
|
*/
|
|
2675
|
-
this.writePartialData = async (partialData, symbol) => {
|
|
2678
|
+
this.writePartialData = async (partialData, symbol, strategyName) => {
|
|
2676
2679
|
backtest$1.loggerService.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2677
|
-
const
|
|
2678
|
-
const
|
|
2680
|
+
const key = `${symbol}:${strategyName}`;
|
|
2681
|
+
const isInitial = !this.getPartialStorage.has(key);
|
|
2682
|
+
const stateStorage = this.getPartialStorage(symbol, strategyName);
|
|
2679
2683
|
await stateStorage.waitForInit(isInitial);
|
|
2680
2684
|
const PARTIAL_STORAGE_KEY = "levels";
|
|
2681
2685
|
await stateStorage.writeValue(PARTIAL_STORAGE_KEY, partialData);
|
|
@@ -2710,10 +2714,10 @@ class PersistPartialUtils {
|
|
|
2710
2714
|
* PersistPartialAdapter.usePersistPartialAdapter(RedisPersist);
|
|
2711
2715
|
*
|
|
2712
2716
|
* // Read partial data
|
|
2713
|
-
* const partialData = await PersistPartialAdapter.readPartialData("BTCUSDT");
|
|
2717
|
+
* const partialData = await PersistPartialAdapter.readPartialData("BTCUSDT", "my-strategy");
|
|
2714
2718
|
*
|
|
2715
2719
|
* // Write partial data
|
|
2716
|
-
* await PersistPartialAdapter.writePartialData(partialData, "BTCUSDT");
|
|
2720
|
+
* await PersistPartialAdapter.writePartialData(partialData, "BTCUSDT", "my-strategy");
|
|
2717
2721
|
* ```
|
|
2718
2722
|
*/
|
|
2719
2723
|
const PersistPartialAdapter = new PersistPartialUtils();
|
|
@@ -4574,25 +4578,25 @@ const NOOP_RISK = {
|
|
|
4574
4578
|
addSignal: () => Promise.resolve(),
|
|
4575
4579
|
removeSignal: () => Promise.resolve(),
|
|
4576
4580
|
};
|
|
4577
|
-
const GET_RISK_FN = (dto, self) => {
|
|
4581
|
+
const GET_RISK_FN = (dto, backtest, self) => {
|
|
4578
4582
|
const hasRiskName = !!dto.riskName;
|
|
4579
|
-
const hasRiskList = !!
|
|
4583
|
+
const hasRiskList = !!dto.riskList?.length;
|
|
4580
4584
|
// Нет ни riskName, ни riskList
|
|
4581
4585
|
if (!hasRiskName && !hasRiskList) {
|
|
4582
4586
|
return NOOP_RISK;
|
|
4583
4587
|
}
|
|
4584
4588
|
// Есть только riskName (без riskList)
|
|
4585
4589
|
if (hasRiskName && !hasRiskList) {
|
|
4586
|
-
return self.riskConnectionService.getRisk(dto.riskName);
|
|
4590
|
+
return self.riskConnectionService.getRisk(dto.riskName, backtest);
|
|
4587
4591
|
}
|
|
4588
4592
|
// Есть только riskList (без riskName)
|
|
4589
4593
|
if (!hasRiskName && hasRiskList) {
|
|
4590
|
-
return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName)));
|
|
4594
|
+
return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)));
|
|
4591
4595
|
}
|
|
4592
4596
|
// Есть и riskName, и riskList - объединяем (riskName в начало)
|
|
4593
4597
|
return new MergeRisk([
|
|
4594
|
-
self.riskConnectionService.getRisk(dto.riskName),
|
|
4595
|
-
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName))
|
|
4598
|
+
self.riskConnectionService.getRisk(dto.riskName, backtest),
|
|
4599
|
+
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
|
|
4596
4600
|
]);
|
|
4597
4601
|
};
|
|
4598
4602
|
/**
|
|
@@ -4634,7 +4638,7 @@ class StrategyConnectionService {
|
|
|
4634
4638
|
* @param strategyName - Name of registered strategy schema
|
|
4635
4639
|
* @returns Configured ClientStrategy instance
|
|
4636
4640
|
*/
|
|
4637
|
-
this.getStrategy = functoolsKit.memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => {
|
|
4641
|
+
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, backtest]) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`, (symbol, strategyName, backtest) => {
|
|
4638
4642
|
const { riskName = "", riskList = [], getSignal, interval, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
4639
4643
|
return new ClientStrategy({
|
|
4640
4644
|
symbol,
|
|
@@ -4647,7 +4651,7 @@ class StrategyConnectionService {
|
|
|
4647
4651
|
risk: GET_RISK_FN({
|
|
4648
4652
|
riskName,
|
|
4649
4653
|
riskList,
|
|
4650
|
-
}, this),
|
|
4654
|
+
}, backtest, this),
|
|
4651
4655
|
riskName,
|
|
4652
4656
|
strategyName,
|
|
4653
4657
|
getSignal,
|
|
@@ -4664,12 +4668,13 @@ class StrategyConnectionService {
|
|
|
4664
4668
|
*
|
|
4665
4669
|
* @returns Promise resolving to pending signal or null
|
|
4666
4670
|
*/
|
|
4667
|
-
this.getPendingSignal = async (symbol, strategyName) => {
|
|
4671
|
+
this.getPendingSignal = async (backtest, symbol, strategyName) => {
|
|
4668
4672
|
this.loggerService.log("strategyConnectionService getPendingSignal", {
|
|
4669
4673
|
symbol,
|
|
4670
4674
|
strategyName,
|
|
4675
|
+
backtest,
|
|
4671
4676
|
});
|
|
4672
|
-
const strategy = this.getStrategy(symbol, strategyName);
|
|
4677
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4673
4678
|
return await strategy.getPendingSignal(symbol, strategyName);
|
|
4674
4679
|
};
|
|
4675
4680
|
/**
|
|
@@ -4682,12 +4687,13 @@ class StrategyConnectionService {
|
|
|
4682
4687
|
* @param strategyName - Name of the strategy
|
|
4683
4688
|
* @returns Promise resolving to true if strategy is stopped, false otherwise
|
|
4684
4689
|
*/
|
|
4685
|
-
this.getStopped = async (symbol, strategyName) => {
|
|
4690
|
+
this.getStopped = async (backtest, symbol, strategyName) => {
|
|
4686
4691
|
this.loggerService.log("strategyConnectionService getStopped", {
|
|
4687
4692
|
symbol,
|
|
4688
4693
|
strategyName,
|
|
4694
|
+
backtest,
|
|
4689
4695
|
});
|
|
4690
|
-
const strategy = this.getStrategy(symbol, strategyName);
|
|
4696
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4691
4697
|
return await strategy.getStopped(symbol, strategyName);
|
|
4692
4698
|
};
|
|
4693
4699
|
/**
|
|
@@ -4705,7 +4711,8 @@ class StrategyConnectionService {
|
|
|
4705
4711
|
symbol,
|
|
4706
4712
|
strategyName,
|
|
4707
4713
|
});
|
|
4708
|
-
const
|
|
4714
|
+
const backtest = this.executionContextService.context.backtest;
|
|
4715
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4709
4716
|
await strategy.waitForInit();
|
|
4710
4717
|
const tick = await strategy.tick(symbol, strategyName);
|
|
4711
4718
|
{
|
|
@@ -4736,7 +4743,8 @@ class StrategyConnectionService {
|
|
|
4736
4743
|
strategyName,
|
|
4737
4744
|
candleCount: candles.length,
|
|
4738
4745
|
});
|
|
4739
|
-
const
|
|
4746
|
+
const backtest = this.executionContextService.context.backtest;
|
|
4747
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4740
4748
|
await strategy.waitForInit();
|
|
4741
4749
|
const tick = await strategy.backtest(symbol, strategyName, candles);
|
|
4742
4750
|
{
|
|
@@ -4757,11 +4765,11 @@ class StrategyConnectionService {
|
|
|
4757
4765
|
* @param strategyName - Name of strategy to stop
|
|
4758
4766
|
* @returns Promise that resolves when stop flag is set
|
|
4759
4767
|
*/
|
|
4760
|
-
this.stop = async (
|
|
4768
|
+
this.stop = async (backtest, ctx) => {
|
|
4761
4769
|
this.loggerService.log("strategyConnectionService stop", {
|
|
4762
4770
|
ctx,
|
|
4763
4771
|
});
|
|
4764
|
-
const strategy = this.getStrategy(ctx.symbol, ctx.strategyName);
|
|
4772
|
+
const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
|
|
4765
4773
|
await strategy.stop(ctx.symbol, ctx.strategyName, backtest);
|
|
4766
4774
|
};
|
|
4767
4775
|
/**
|
|
@@ -4772,12 +4780,12 @@ class StrategyConnectionService {
|
|
|
4772
4780
|
*
|
|
4773
4781
|
* @param ctx - Optional context with symbol and strategyName (clears all if not provided)
|
|
4774
4782
|
*/
|
|
4775
|
-
this.clear = async (ctx) => {
|
|
4783
|
+
this.clear = async (backtest, ctx) => {
|
|
4776
4784
|
this.loggerService.log("strategyConnectionService clear", {
|
|
4777
4785
|
ctx,
|
|
4778
4786
|
});
|
|
4779
4787
|
if (ctx) {
|
|
4780
|
-
const key = `${ctx.symbol}:${ctx.strategyName}`;
|
|
4788
|
+
const key = `${ctx.symbol}:${ctx.strategyName}:${backtest ? "backtest" : "live"}`;
|
|
4781
4789
|
this.getStrategy.clear(key);
|
|
4782
4790
|
}
|
|
4783
4791
|
else {
|
|
@@ -5172,9 +5180,15 @@ const DO_VALIDATION_FN = functoolsKit.trycatch(async (validation, params) => {
|
|
|
5172
5180
|
* Initializes active positions by reading from persistence.
|
|
5173
5181
|
* Uses singleshot pattern to ensure it only runs once.
|
|
5174
5182
|
* This function is exported for use in tests or other modules.
|
|
5183
|
+
*
|
|
5184
|
+
* In backtest mode, initializes with empty Map. In live mode, reads from persist storage.
|
|
5175
5185
|
*/
|
|
5176
5186
|
const WAIT_FOR_INIT_FN$1 = async (self) => {
|
|
5177
|
-
self.params.logger.debug("ClientRisk waitForInit");
|
|
5187
|
+
self.params.logger.debug("ClientRisk waitForInit", { backtest: self.params.backtest });
|
|
5188
|
+
if (self.params.backtest) {
|
|
5189
|
+
self._activePositions = new Map();
|
|
5190
|
+
return;
|
|
5191
|
+
}
|
|
5178
5192
|
const persistedPositions = await PersistRiskAdapter.readPositionData(self.params.riskName);
|
|
5179
5193
|
self._activePositions = new Map(persistedPositions);
|
|
5180
5194
|
};
|
|
@@ -5222,6 +5236,7 @@ class ClientRisk {
|
|
|
5222
5236
|
this.params.logger.debug("ClientRisk checkSignal", {
|
|
5223
5237
|
symbol: params.symbol,
|
|
5224
5238
|
strategyName: params.strategyName,
|
|
5239
|
+
backtest: this.params.backtest,
|
|
5225
5240
|
});
|
|
5226
5241
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5227
5242
|
await this.waitForInit();
|
|
@@ -5267,8 +5282,12 @@ class ClientRisk {
|
|
|
5267
5282
|
}
|
|
5268
5283
|
/**
|
|
5269
5284
|
* Persists current active positions to disk.
|
|
5285
|
+
* Skips in backtest mode.
|
|
5270
5286
|
*/
|
|
5271
5287
|
async _updatePositions() {
|
|
5288
|
+
if (this.params.backtest) {
|
|
5289
|
+
return;
|
|
5290
|
+
}
|
|
5272
5291
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5273
5292
|
await this.waitForInit();
|
|
5274
5293
|
}
|
|
@@ -5282,6 +5301,7 @@ class ClientRisk {
|
|
|
5282
5301
|
this.params.logger.debug("ClientRisk addSignal", {
|
|
5283
5302
|
symbol,
|
|
5284
5303
|
context,
|
|
5304
|
+
backtest: this.params.backtest,
|
|
5285
5305
|
});
|
|
5286
5306
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5287
5307
|
await this.waitForInit();
|
|
@@ -5304,6 +5324,7 @@ class ClientRisk {
|
|
|
5304
5324
|
this.params.logger.debug("ClientRisk removeSignal", {
|
|
5305
5325
|
symbol,
|
|
5306
5326
|
context,
|
|
5327
|
+
backtest: this.params.backtest,
|
|
5307
5328
|
});
|
|
5308
5329
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5309
5330
|
await this.waitForInit();
|
|
@@ -5374,19 +5395,21 @@ class RiskConnectionService {
|
|
|
5374
5395
|
this.loggerService = inject(TYPES.loggerService);
|
|
5375
5396
|
this.riskSchemaService = inject(TYPES.riskSchemaService);
|
|
5376
5397
|
/**
|
|
5377
|
-
* Retrieves memoized ClientRisk instance for given risk name.
|
|
5398
|
+
* Retrieves memoized ClientRisk instance for given risk name and backtest mode.
|
|
5378
5399
|
*
|
|
5379
5400
|
* Creates ClientRisk on first call, returns cached instance on subsequent calls.
|
|
5380
|
-
* Cache key is riskName string.
|
|
5401
|
+
* Cache key is "riskName:backtest" string to separate live and backtest instances.
|
|
5381
5402
|
*
|
|
5382
5403
|
* @param riskName - Name of registered risk schema
|
|
5404
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
5383
5405
|
* @returns Configured ClientRisk instance
|
|
5384
5406
|
*/
|
|
5385
|
-
this.getRisk = functoolsKit.memoize(([riskName]) => `${riskName}`, (riskName) => {
|
|
5407
|
+
this.getRisk = functoolsKit.memoize(([riskName, backtest]) => `${riskName}:${backtest ? "backtest" : "live"}`, (riskName, backtest) => {
|
|
5386
5408
|
const schema = this.riskSchemaService.get(riskName);
|
|
5387
5409
|
return new ClientRisk({
|
|
5388
5410
|
...schema,
|
|
5389
5411
|
logger: this.loggerService,
|
|
5412
|
+
backtest,
|
|
5390
5413
|
onRejected: COMMIT_REJECTION_FN,
|
|
5391
5414
|
});
|
|
5392
5415
|
});
|
|
@@ -5398,7 +5421,7 @@ class RiskConnectionService {
|
|
|
5398
5421
|
* ClientRisk will emit riskSubject event via onRejected callback when signal is rejected.
|
|
5399
5422
|
*
|
|
5400
5423
|
* @param params - Risk check arguments (portfolio state, position details)
|
|
5401
|
-
* @param context - Execution context with risk name
|
|
5424
|
+
* @param context - Execution context with risk name and backtest mode
|
|
5402
5425
|
* @returns Promise resolving to risk check result
|
|
5403
5426
|
*/
|
|
5404
5427
|
this.checkSignal = async (params, context) => {
|
|
@@ -5406,46 +5429,48 @@ class RiskConnectionService {
|
|
|
5406
5429
|
symbol: params.symbol,
|
|
5407
5430
|
context,
|
|
5408
5431
|
});
|
|
5409
|
-
return await this.getRisk(context.riskName).checkSignal(params);
|
|
5432
|
+
return await this.getRisk(context.riskName, context.backtest).checkSignal(params);
|
|
5410
5433
|
};
|
|
5411
5434
|
/**
|
|
5412
5435
|
* Registers an opened signal with the risk management system.
|
|
5413
5436
|
* Routes to appropriate ClientRisk instance.
|
|
5414
5437
|
*
|
|
5415
5438
|
* @param symbol - Trading pair symbol
|
|
5416
|
-
* @param context - Context information (strategyName, riskName)
|
|
5439
|
+
* @param context - Context information (strategyName, riskName, backtest)
|
|
5417
5440
|
*/
|
|
5418
5441
|
this.addSignal = async (symbol, context) => {
|
|
5419
5442
|
this.loggerService.log("riskConnectionService addSignal", {
|
|
5420
5443
|
symbol,
|
|
5421
5444
|
context,
|
|
5422
5445
|
});
|
|
5423
|
-
await this.getRisk(context.riskName).addSignal(symbol, context);
|
|
5446
|
+
await this.getRisk(context.riskName, context.backtest).addSignal(symbol, context);
|
|
5424
5447
|
};
|
|
5425
5448
|
/**
|
|
5426
5449
|
* Removes a closed signal from the risk management system.
|
|
5427
5450
|
* Routes to appropriate ClientRisk instance.
|
|
5428
5451
|
*
|
|
5429
5452
|
* @param symbol - Trading pair symbol
|
|
5430
|
-
* @param context - Context information (strategyName, riskName)
|
|
5453
|
+
* @param context - Context information (strategyName, riskName, backtest)
|
|
5431
5454
|
*/
|
|
5432
5455
|
this.removeSignal = async (symbol, context) => {
|
|
5433
5456
|
this.loggerService.log("riskConnectionService removeSignal", {
|
|
5434
5457
|
symbol,
|
|
5435
5458
|
context,
|
|
5436
5459
|
});
|
|
5437
|
-
await this.getRisk(context.riskName).removeSignal(symbol, context);
|
|
5460
|
+
await this.getRisk(context.riskName, context.backtest).removeSignal(symbol, context);
|
|
5438
5461
|
};
|
|
5439
5462
|
/**
|
|
5440
5463
|
* Clears the cached ClientRisk instance for the given risk name.
|
|
5441
5464
|
*
|
|
5442
5465
|
* @param riskName - Name of the risk schema to clear from cache
|
|
5443
5466
|
*/
|
|
5444
|
-
this.clear = async (riskName) => {
|
|
5467
|
+
this.clear = async (backtest, riskName) => {
|
|
5445
5468
|
this.loggerService.log("riskConnectionService clear", {
|
|
5446
5469
|
riskName,
|
|
5470
|
+
backtest,
|
|
5447
5471
|
});
|
|
5448
|
-
|
|
5472
|
+
const key = `${riskName}:${backtest ? "backtest" : "live"}`;
|
|
5473
|
+
this.getRisk.clear(key);
|
|
5449
5474
|
};
|
|
5450
5475
|
}
|
|
5451
5476
|
}
|
|
@@ -5668,7 +5693,7 @@ class StrategyCoreService {
|
|
|
5668
5693
|
* @param strategyName - Name of the strategy
|
|
5669
5694
|
* @returns Promise resolving to pending signal or null
|
|
5670
5695
|
*/
|
|
5671
|
-
this.getPendingSignal = async (symbol, strategyName) => {
|
|
5696
|
+
this.getPendingSignal = async (backtest, symbol, strategyName) => {
|
|
5672
5697
|
this.loggerService.log("strategyCoreService getPendingSignal", {
|
|
5673
5698
|
symbol,
|
|
5674
5699
|
strategyName,
|
|
@@ -5677,7 +5702,7 @@ class StrategyCoreService {
|
|
|
5677
5702
|
throw new Error("strategyCoreService getPendingSignal requires a method context");
|
|
5678
5703
|
}
|
|
5679
5704
|
await this.validate(symbol, strategyName);
|
|
5680
|
-
return await this.strategyConnectionService.getPendingSignal(symbol, strategyName);
|
|
5705
|
+
return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
|
|
5681
5706
|
};
|
|
5682
5707
|
/**
|
|
5683
5708
|
* Checks if the strategy has been stopped.
|
|
@@ -5689,16 +5714,17 @@ class StrategyCoreService {
|
|
|
5689
5714
|
* @param strategyName - Name of the strategy
|
|
5690
5715
|
* @returns Promise resolving to true if strategy is stopped, false otherwise
|
|
5691
5716
|
*/
|
|
5692
|
-
this.getStopped = async (symbol, strategyName) => {
|
|
5717
|
+
this.getStopped = async (backtest, symbol, strategyName) => {
|
|
5693
5718
|
this.loggerService.log("strategyCoreService getStopped", {
|
|
5694
5719
|
symbol,
|
|
5695
5720
|
strategyName,
|
|
5721
|
+
backtest,
|
|
5696
5722
|
});
|
|
5697
5723
|
if (!MethodContextService.hasContext()) {
|
|
5698
5724
|
throw new Error("strategyCoreService getStopped requires a method context");
|
|
5699
5725
|
}
|
|
5700
5726
|
await this.validate(symbol, strategyName);
|
|
5701
|
-
return await this.strategyConnectionService.getStopped(symbol, strategyName);
|
|
5727
|
+
return await this.strategyConnectionService.getStopped(backtest, symbol, strategyName);
|
|
5702
5728
|
};
|
|
5703
5729
|
/**
|
|
5704
5730
|
* Checks signal status at a specific timestamp.
|
|
@@ -5772,13 +5798,13 @@ class StrategyCoreService {
|
|
|
5772
5798
|
* @param strategyName - Name of strategy to stop
|
|
5773
5799
|
* @returns Promise that resolves when stop flag is set
|
|
5774
5800
|
*/
|
|
5775
|
-
this.stop = async (
|
|
5801
|
+
this.stop = async (backtest, ctx) => {
|
|
5776
5802
|
this.loggerService.log("strategyCoreService stop", {
|
|
5777
5803
|
ctx,
|
|
5778
5804
|
backtest,
|
|
5779
5805
|
});
|
|
5780
5806
|
await this.validate(ctx.symbol, ctx.strategyName);
|
|
5781
|
-
return await this.strategyConnectionService.stop(
|
|
5807
|
+
return await this.strategyConnectionService.stop(backtest, ctx);
|
|
5782
5808
|
};
|
|
5783
5809
|
/**
|
|
5784
5810
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -5788,14 +5814,14 @@ class StrategyCoreService {
|
|
|
5788
5814
|
*
|
|
5789
5815
|
* @param ctx - Optional context with symbol and strategyName (clears all if not provided)
|
|
5790
5816
|
*/
|
|
5791
|
-
this.clear = async (ctx) => {
|
|
5817
|
+
this.clear = async (backtest, ctx) => {
|
|
5792
5818
|
this.loggerService.log("strategyCoreService clear", {
|
|
5793
5819
|
ctx,
|
|
5794
5820
|
});
|
|
5795
5821
|
if (ctx) {
|
|
5796
5822
|
await this.validate(ctx.symbol, ctx.strategyName);
|
|
5797
5823
|
}
|
|
5798
|
-
return await this.strategyConnectionService.clear(ctx);
|
|
5824
|
+
return await this.strategyConnectionService.clear(backtest, ctx);
|
|
5799
5825
|
};
|
|
5800
5826
|
}
|
|
5801
5827
|
}
|
|
@@ -5936,14 +5962,15 @@ class RiskGlobalService {
|
|
|
5936
5962
|
* If no riskName is provided, clears all risk data.
|
|
5937
5963
|
* @param riskName - Optional name of the risk instance to clear
|
|
5938
5964
|
*/
|
|
5939
|
-
this.clear = async (riskName) => {
|
|
5965
|
+
this.clear = async (backtest, riskName) => {
|
|
5940
5966
|
this.loggerService.log("riskGlobalService clear", {
|
|
5941
5967
|
riskName,
|
|
5968
|
+
backtest,
|
|
5942
5969
|
});
|
|
5943
5970
|
if (riskName) {
|
|
5944
5971
|
await this.validate(riskName);
|
|
5945
5972
|
}
|
|
5946
|
-
return await this.riskConnectionService.clear(riskName);
|
|
5973
|
+
return await this.riskConnectionService.clear(backtest, riskName);
|
|
5947
5974
|
};
|
|
5948
5975
|
}
|
|
5949
5976
|
}
|
|
@@ -6487,7 +6514,7 @@ class BacktestLogicPrivateService {
|
|
|
6487
6514
|
});
|
|
6488
6515
|
}
|
|
6489
6516
|
// Check if strategy should stop before processing next frame
|
|
6490
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6517
|
+
if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
|
|
6491
6518
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (before tick)", {
|
|
6492
6519
|
symbol,
|
|
6493
6520
|
when: when.toISOString(),
|
|
@@ -6512,7 +6539,7 @@ class BacktestLogicPrivateService {
|
|
|
6512
6539
|
continue;
|
|
6513
6540
|
}
|
|
6514
6541
|
// Check if strategy should stop when idle (no active signal)
|
|
6515
|
-
if (await functoolsKit.and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName))) {
|
|
6542
|
+
if (await functoolsKit.and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName))) {
|
|
6516
6543
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (idle state)", {
|
|
6517
6544
|
symbol,
|
|
6518
6545
|
when: when.toISOString(),
|
|
@@ -6614,7 +6641,7 @@ class BacktestLogicPrivateService {
|
|
|
6614
6641
|
}
|
|
6615
6642
|
yield backtestResult;
|
|
6616
6643
|
// Check if strategy should stop after signal is closed
|
|
6617
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6644
|
+
if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
|
|
6618
6645
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (after scheduled signal closed)", {
|
|
6619
6646
|
symbol,
|
|
6620
6647
|
signalId: backtestResult.signal.id,
|
|
@@ -6707,7 +6734,7 @@ class BacktestLogicPrivateService {
|
|
|
6707
6734
|
}
|
|
6708
6735
|
yield backtestResult;
|
|
6709
6736
|
// Check if strategy should stop after signal is closed
|
|
6710
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6737
|
+
if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
|
|
6711
6738
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (after signal closed)", {
|
|
6712
6739
|
symbol,
|
|
6713
6740
|
signalId: backtestResult.signal.id,
|
|
@@ -6850,7 +6877,7 @@ class LiveLogicPrivateService {
|
|
|
6850
6877
|
previousEventTimestamp = currentTimestamp;
|
|
6851
6878
|
// Check if strategy should stop when idle (no active signal)
|
|
6852
6879
|
if (result.action === "idle") {
|
|
6853
|
-
if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName))) {
|
|
6880
|
+
if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName))) {
|
|
6854
6881
|
this.loggerService.info("liveLogicPrivateService stopped by user request (idle state)", {
|
|
6855
6882
|
symbol,
|
|
6856
6883
|
when: when.toISOString(),
|
|
@@ -6872,7 +6899,7 @@ class LiveLogicPrivateService {
|
|
|
6872
6899
|
yield result;
|
|
6873
6900
|
// Check if strategy should stop after signal is closed
|
|
6874
6901
|
if (result.action === "closed") {
|
|
6875
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6902
|
+
if (await this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName)) {
|
|
6876
6903
|
this.loggerService.info("liveLogicPrivateService stopped by user request (after signal closed)", {
|
|
6877
6904
|
symbol,
|
|
6878
6905
|
signalId: result.signal.id,
|
|
@@ -11667,6 +11694,9 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
|
|
|
11667
11694
|
if (self._states === NEED_FETCH) {
|
|
11668
11695
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
11669
11696
|
}
|
|
11697
|
+
if (data.id !== self.params.signalId) {
|
|
11698
|
+
throw new Error(`Signal ID mismatch: expected ${self.params.signalId}, got ${data.id}`);
|
|
11699
|
+
}
|
|
11670
11700
|
let state = self._states.get(data.id);
|
|
11671
11701
|
if (!state) {
|
|
11672
11702
|
state = {
|
|
@@ -11691,7 +11721,7 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
|
|
|
11691
11721
|
}
|
|
11692
11722
|
}
|
|
11693
11723
|
if (shouldPersist) {
|
|
11694
|
-
await self._persistState(symbol,
|
|
11724
|
+
await self._persistState(symbol, data.strategyName);
|
|
11695
11725
|
}
|
|
11696
11726
|
};
|
|
11697
11727
|
/**
|
|
@@ -11713,6 +11743,9 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
11713
11743
|
if (self._states === NEED_FETCH) {
|
|
11714
11744
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
11715
11745
|
}
|
|
11746
|
+
if (data.id !== self.params.signalId) {
|
|
11747
|
+
throw new Error(`Signal ID mismatch: expected ${self.params.signalId}, got ${data.id}`);
|
|
11748
|
+
}
|
|
11716
11749
|
let state = self._states.get(data.id);
|
|
11717
11750
|
if (!state) {
|
|
11718
11751
|
state = {
|
|
@@ -11738,7 +11771,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
11738
11771
|
}
|
|
11739
11772
|
}
|
|
11740
11773
|
if (shouldPersist) {
|
|
11741
|
-
await self._persistState(symbol,
|
|
11774
|
+
await self._persistState(symbol, data.strategyName);
|
|
11742
11775
|
}
|
|
11743
11776
|
};
|
|
11744
11777
|
/**
|
|
@@ -11747,15 +11780,29 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
11747
11780
|
* Loads persisted partial state from disk and restores in-memory Maps.
|
|
11748
11781
|
* Converts serialized arrays back to Sets for O(1) lookups.
|
|
11749
11782
|
*
|
|
11783
|
+
* ONLY runs in LIVE mode (backtest=false). In backtest mode, state is not persisted.
|
|
11784
|
+
*
|
|
11750
11785
|
* @param symbol - Trading pair symbol
|
|
11786
|
+
* @param strategyName - Strategy identifier
|
|
11787
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
11751
11788
|
* @param self - ClientPartial instance reference
|
|
11752
11789
|
*/
|
|
11753
|
-
const WAIT_FOR_INIT_FN = async (symbol, self) => {
|
|
11754
|
-
self.params.logger.debug("ClientPartial waitForInit", {
|
|
11755
|
-
|
|
11756
|
-
|
|
11790
|
+
const WAIT_FOR_INIT_FN = async (symbol, strategyName, self) => {
|
|
11791
|
+
self.params.logger.debug("ClientPartial waitForInit", {
|
|
11792
|
+
symbol,
|
|
11793
|
+
strategyName,
|
|
11794
|
+
backtest: self.params.backtest
|
|
11795
|
+
});
|
|
11796
|
+
if (self._states !== NEED_FETCH) {
|
|
11797
|
+
throw new Error("ClientPartial WAIT_FOR_INIT_FN should be called once!");
|
|
11798
|
+
}
|
|
11799
|
+
self._states = new Map();
|
|
11800
|
+
// Skip persistence in backtest mode
|
|
11801
|
+
if (self.params.backtest) {
|
|
11802
|
+
self.params.logger.debug("ClientPartial waitForInit: skipping persist read in backtest mode");
|
|
11803
|
+
return;
|
|
11757
11804
|
}
|
|
11758
|
-
const partialData = await PersistPartialAdapter.readPartialData(symbol);
|
|
11805
|
+
const partialData = await PersistPartialAdapter.readPartialData(symbol, strategyName);
|
|
11759
11806
|
for (const [signalId, data] of Object.entries(partialData)) {
|
|
11760
11807
|
const state = {
|
|
11761
11808
|
profitLevels: new Set(data.profitLevels),
|
|
@@ -11765,6 +11812,7 @@ const WAIT_FOR_INIT_FN = async (symbol, self) => {
|
|
|
11765
11812
|
}
|
|
11766
11813
|
self.params.logger.info("ClientPartial restored state", {
|
|
11767
11814
|
symbol,
|
|
11815
|
+
strategyName,
|
|
11768
11816
|
signalCount: Object.keys(partialData).length,
|
|
11769
11817
|
});
|
|
11770
11818
|
};
|
|
@@ -11843,23 +11891,24 @@ class ClientPartial {
|
|
|
11843
11891
|
/**
|
|
11844
11892
|
* Initializes partial state by loading from disk.
|
|
11845
11893
|
*
|
|
11846
|
-
* Uses singleshot pattern to ensure initialization happens exactly once per symbol.
|
|
11894
|
+
* Uses singleshot pattern to ensure initialization happens exactly once per symbol:strategyName.
|
|
11847
11895
|
* Reads persisted state from PersistPartialAdapter and restores to _states Map.
|
|
11848
11896
|
*
|
|
11849
11897
|
* Must be called before profit()/loss()/clear() methods.
|
|
11850
11898
|
*
|
|
11851
11899
|
* @param symbol - Trading pair symbol
|
|
11900
|
+
* @param strategyName - Strategy identifier
|
|
11901
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
11852
11902
|
* @returns Promise that resolves when initialization is complete
|
|
11853
11903
|
*
|
|
11854
11904
|
* @example
|
|
11855
11905
|
* ```typescript
|
|
11856
11906
|
* const partial = new ClientPartial(params);
|
|
11857
|
-
* await partial.waitForInit("BTCUSDT"); // Load persisted state
|
|
11907
|
+
* await partial.waitForInit("BTCUSDT", "my-strategy", false); // Load persisted state (live mode)
|
|
11858
11908
|
* // Now profit()/loss() can be called
|
|
11859
11909
|
* ```
|
|
11860
11910
|
*/
|
|
11861
|
-
this.waitForInit = functoolsKit.singleshot(async (symbol) => await WAIT_FOR_INIT_FN(symbol, this));
|
|
11862
|
-
this._states = new Map();
|
|
11911
|
+
this.waitForInit = functoolsKit.singleshot(async (symbol, strategyName) => await WAIT_FOR_INIT_FN(symbol, strategyName, this));
|
|
11863
11912
|
}
|
|
11864
11913
|
/**
|
|
11865
11914
|
* Persists current partial state to disk.
|
|
@@ -11872,13 +11921,15 @@ class ClientPartial {
|
|
|
11872
11921
|
* Uses atomic file writes via PersistPartialAdapter.
|
|
11873
11922
|
*
|
|
11874
11923
|
* @param symbol - Trading pair symbol
|
|
11924
|
+
* @param strategyName - Strategy identifier
|
|
11925
|
+
* @param backtest - True if backtest mode
|
|
11875
11926
|
* @returns Promise that resolves when persistence is complete
|
|
11876
11927
|
*/
|
|
11877
|
-
async _persistState(symbol,
|
|
11878
|
-
if (backtest) {
|
|
11928
|
+
async _persistState(symbol, strategyName) {
|
|
11929
|
+
if (this.params.backtest) {
|
|
11879
11930
|
return;
|
|
11880
11931
|
}
|
|
11881
|
-
this.params.logger.debug("ClientPartial persistState", { symbol });
|
|
11932
|
+
this.params.logger.debug("ClientPartial persistState", { symbol, strategyName });
|
|
11882
11933
|
if (this._states === NEED_FETCH) {
|
|
11883
11934
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
11884
11935
|
}
|
|
@@ -11889,7 +11940,7 @@ class ClientPartial {
|
|
|
11889
11940
|
lossLevels: Array.from(state.lossLevels),
|
|
11890
11941
|
};
|
|
11891
11942
|
}
|
|
11892
|
-
await PersistPartialAdapter.writePartialData(partialData, symbol);
|
|
11943
|
+
await PersistPartialAdapter.writePartialData(partialData, symbol, strategyName);
|
|
11893
11944
|
}
|
|
11894
11945
|
/**
|
|
11895
11946
|
* Processes profit state and emits events for newly reached profit levels.
|
|
@@ -12010,8 +12061,11 @@ class ClientPartial {
|
|
|
12010
12061
|
if (this._states === NEED_FETCH) {
|
|
12011
12062
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
12012
12063
|
}
|
|
12064
|
+
if (data.id !== this.params.signalId) {
|
|
12065
|
+
throw new Error(`Signal ID mismatch: expected ${this.params.signalId}, got ${data.id}`);
|
|
12066
|
+
}
|
|
12013
12067
|
this._states.delete(data.id);
|
|
12014
|
-
await this._persistState(symbol,
|
|
12068
|
+
await this._persistState(symbol, data.strategyName);
|
|
12015
12069
|
}
|
|
12016
12070
|
}
|
|
12017
12071
|
|
|
@@ -12106,15 +12160,17 @@ class PartialConnectionService {
|
|
|
12106
12160
|
/**
|
|
12107
12161
|
* Memoized factory function for ClientPartial instances.
|
|
12108
12162
|
*
|
|
12109
|
-
* Creates one ClientPartial per signal ID with configured callbacks.
|
|
12163
|
+
* Creates one ClientPartial per signal ID and backtest mode with configured callbacks.
|
|
12110
12164
|
* Instances are cached until clear() is called.
|
|
12111
12165
|
*
|
|
12112
|
-
* Key format: signalId
|
|
12166
|
+
* Key format: "signalId:backtest" or "signalId:live"
|
|
12113
12167
|
* Value: ClientPartial instance with logger and event emitters
|
|
12114
12168
|
*/
|
|
12115
|
-
this.getPartial = functoolsKit.memoize(([signalId]) => `${signalId}`, () => {
|
|
12169
|
+
this.getPartial = functoolsKit.memoize(([signalId, backtest]) => `${signalId}:${backtest ? "backtest" : "live"}`, (signalId, backtest) => {
|
|
12116
12170
|
return new ClientPartial({
|
|
12171
|
+
signalId,
|
|
12117
12172
|
logger: this.loggerService,
|
|
12173
|
+
backtest,
|
|
12118
12174
|
onProfit: COMMIT_PROFIT_FN,
|
|
12119
12175
|
onLoss: COMMIT_LOSS_FN,
|
|
12120
12176
|
});
|
|
@@ -12142,8 +12198,8 @@ class PartialConnectionService {
|
|
|
12142
12198
|
backtest,
|
|
12143
12199
|
when,
|
|
12144
12200
|
});
|
|
12145
|
-
const partial = this.getPartial(data.id);
|
|
12146
|
-
await partial.waitForInit(symbol);
|
|
12201
|
+
const partial = this.getPartial(data.id, backtest);
|
|
12202
|
+
await partial.waitForInit(symbol, data.strategyName);
|
|
12147
12203
|
return await partial.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
|
|
12148
12204
|
};
|
|
12149
12205
|
/**
|
|
@@ -12169,8 +12225,8 @@ class PartialConnectionService {
|
|
|
12169
12225
|
backtest,
|
|
12170
12226
|
when,
|
|
12171
12227
|
});
|
|
12172
|
-
const partial = this.getPartial(data.id);
|
|
12173
|
-
await partial.waitForInit(symbol);
|
|
12228
|
+
const partial = this.getPartial(data.id, backtest);
|
|
12229
|
+
await partial.waitForInit(symbol, data.strategyName);
|
|
12174
12230
|
return await partial.loss(symbol, data, currentPrice, lossPercent, backtest, when);
|
|
12175
12231
|
};
|
|
12176
12232
|
/**
|
|
@@ -12191,15 +12247,17 @@ class PartialConnectionService {
|
|
|
12191
12247
|
* @returns Promise that resolves when clear is complete
|
|
12192
12248
|
*/
|
|
12193
12249
|
this.clear = async (symbol, data, priceClose, backtest) => {
|
|
12194
|
-
this.loggerService.log("partialConnectionService
|
|
12250
|
+
this.loggerService.log("partialConnectionService clear", {
|
|
12195
12251
|
symbol,
|
|
12196
12252
|
data,
|
|
12197
12253
|
priceClose,
|
|
12254
|
+
backtest,
|
|
12198
12255
|
});
|
|
12199
|
-
const partial = this.getPartial(data.id);
|
|
12200
|
-
await partial.waitForInit(symbol);
|
|
12256
|
+
const partial = this.getPartial(data.id, backtest);
|
|
12257
|
+
await partial.waitForInit(symbol, data.strategyName);
|
|
12201
12258
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
12202
|
-
|
|
12259
|
+
const key = `${data.id}:${backtest ? "backtest" : "live"}`;
|
|
12260
|
+
this.getPartial.clear(key);
|
|
12203
12261
|
};
|
|
12204
12262
|
}
|
|
12205
12263
|
}
|
|
@@ -15551,12 +15609,12 @@ class BacktestInstance {
|
|
|
15551
15609
|
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
15552
15610
|
}
|
|
15553
15611
|
{
|
|
15554
|
-
backtest$1.strategyCoreService.clear({ symbol, strategyName: context.strategyName });
|
|
15612
|
+
backtest$1.strategyCoreService.clear(true, { symbol, strategyName: context.strategyName });
|
|
15555
15613
|
}
|
|
15556
15614
|
{
|
|
15557
15615
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
15558
|
-
riskName && backtest$1.riskGlobalService.clear(riskName);
|
|
15559
|
-
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(riskName));
|
|
15616
|
+
riskName && backtest$1.riskGlobalService.clear(true, riskName);
|
|
15617
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, riskName));
|
|
15560
15618
|
}
|
|
15561
15619
|
return backtest$1.backtestCommandService.run(symbol, context);
|
|
15562
15620
|
};
|
|
@@ -15587,9 +15645,9 @@ class BacktestInstance {
|
|
|
15587
15645
|
});
|
|
15588
15646
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
15589
15647
|
return () => {
|
|
15590
|
-
backtest$1.strategyCoreService.stop({ symbol, strategyName: context.strategyName }
|
|
15648
|
+
backtest$1.strategyCoreService.stop(true, { symbol, strategyName: context.strategyName });
|
|
15591
15649
|
backtest$1.strategyCoreService
|
|
15592
|
-
.getPendingSignal(symbol, context.strategyName)
|
|
15650
|
+
.getPendingSignal(true, symbol, context.strategyName)
|
|
15593
15651
|
.then(async (pendingSignal) => {
|
|
15594
15652
|
if (pendingSignal) {
|
|
15595
15653
|
return;
|
|
@@ -15629,7 +15687,7 @@ class BacktestInstance {
|
|
|
15629
15687
|
symbol,
|
|
15630
15688
|
strategyName,
|
|
15631
15689
|
});
|
|
15632
|
-
await backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
15690
|
+
await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
15633
15691
|
};
|
|
15634
15692
|
/**
|
|
15635
15693
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
@@ -16055,12 +16113,12 @@ class LiveInstance {
|
|
|
16055
16113
|
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
16056
16114
|
}
|
|
16057
16115
|
{
|
|
16058
|
-
backtest$1.strategyCoreService.clear({ symbol, strategyName: context.strategyName });
|
|
16116
|
+
backtest$1.strategyCoreService.clear(false, { symbol, strategyName: context.strategyName });
|
|
16059
16117
|
}
|
|
16060
16118
|
{
|
|
16061
16119
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16062
|
-
riskName && backtest$1.riskGlobalService.clear(riskName);
|
|
16063
|
-
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(riskName));
|
|
16120
|
+
riskName && backtest$1.riskGlobalService.clear(false, riskName);
|
|
16121
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(false, riskName));
|
|
16064
16122
|
}
|
|
16065
16123
|
return backtest$1.liveCommandService.run(symbol, context);
|
|
16066
16124
|
};
|
|
@@ -16091,9 +16149,9 @@ class LiveInstance {
|
|
|
16091
16149
|
});
|
|
16092
16150
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
16093
16151
|
return () => {
|
|
16094
|
-
backtest$1.strategyCoreService.stop({ symbol, strategyName: context.strategyName }
|
|
16152
|
+
backtest$1.strategyCoreService.stop(false, { symbol, strategyName: context.strategyName });
|
|
16095
16153
|
backtest$1.strategyCoreService
|
|
16096
|
-
.getPendingSignal(symbol, context.strategyName)
|
|
16154
|
+
.getPendingSignal(false, symbol, context.strategyName)
|
|
16097
16155
|
.then(async (pendingSignal) => {
|
|
16098
16156
|
if (pendingSignal) {
|
|
16099
16157
|
return;
|
|
@@ -16133,7 +16191,7 @@ class LiveInstance {
|
|
|
16133
16191
|
symbol,
|
|
16134
16192
|
strategyName,
|
|
16135
16193
|
});
|
|
16136
|
-
await backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
16194
|
+
await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
|
|
16137
16195
|
};
|
|
16138
16196
|
/**
|
|
16139
16197
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
@@ -16837,12 +16895,13 @@ class WalkerInstance {
|
|
|
16837
16895
|
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName });
|
|
16838
16896
|
}
|
|
16839
16897
|
{
|
|
16840
|
-
backtest$1.strategyCoreService.clear({ symbol, strategyName });
|
|
16898
|
+
backtest$1.strategyCoreService.clear(true, { symbol, strategyName });
|
|
16841
16899
|
}
|
|
16842
16900
|
{
|
|
16843
16901
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16844
|
-
riskName && backtest$1.riskGlobalService.clear(riskName);
|
|
16845
|
-
riskList &&
|
|
16902
|
+
riskName && backtest$1.riskGlobalService.clear(true, riskName);
|
|
16903
|
+
riskList &&
|
|
16904
|
+
riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, riskName));
|
|
16846
16905
|
}
|
|
16847
16906
|
}
|
|
16848
16907
|
return backtest$1.walkerCommandService.run(symbol, {
|
|
@@ -16878,8 +16937,12 @@ class WalkerInstance {
|
|
|
16878
16937
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
16879
16938
|
return () => {
|
|
16880
16939
|
for (const strategyName of walkerSchema.strategies) {
|
|
16881
|
-
backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
16882
|
-
walkerStopSubject.next({
|
|
16940
|
+
backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
16941
|
+
walkerStopSubject.next({
|
|
16942
|
+
symbol,
|
|
16943
|
+
strategyName,
|
|
16944
|
+
walkerName: context.walkerName,
|
|
16945
|
+
});
|
|
16883
16946
|
}
|
|
16884
16947
|
if (!this._isDone) {
|
|
16885
16948
|
doneWalkerSubject.next({
|
|
@@ -16924,7 +16987,7 @@ class WalkerInstance {
|
|
|
16924
16987
|
const walkerSchema = backtest$1.walkerSchemaService.get(walkerName);
|
|
16925
16988
|
for (const strategyName of walkerSchema.strategies) {
|
|
16926
16989
|
await walkerStopSubject.next({ symbol, strategyName, walkerName });
|
|
16927
|
-
await backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
16990
|
+
await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
16928
16991
|
}
|
|
16929
16992
|
};
|
|
16930
16993
|
/**
|
|
@@ -17053,8 +17116,10 @@ class WalkerUtils {
|
|
|
17053
17116
|
for (const strategyName of walkerSchema.strategies) {
|
|
17054
17117
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_RUN);
|
|
17055
17118
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17056
|
-
riskName &&
|
|
17057
|
-
|
|
17119
|
+
riskName &&
|
|
17120
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_RUN);
|
|
17121
|
+
riskList &&
|
|
17122
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_RUN));
|
|
17058
17123
|
}
|
|
17059
17124
|
const instance = this._getInstance(symbol, context.walkerName);
|
|
17060
17125
|
return instance.run(symbol, context);
|
|
@@ -17086,8 +17151,10 @@ class WalkerUtils {
|
|
|
17086
17151
|
for (const strategyName of walkerSchema.strategies) {
|
|
17087
17152
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_BACKGROUND);
|
|
17088
17153
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17089
|
-
riskName &&
|
|
17090
|
-
|
|
17154
|
+
riskName &&
|
|
17155
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_BACKGROUND);
|
|
17156
|
+
riskList &&
|
|
17157
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_BACKGROUND));
|
|
17091
17158
|
}
|
|
17092
17159
|
const instance = this._getInstance(symbol, context.walkerName);
|
|
17093
17160
|
return instance.background(symbol, context);
|
|
@@ -17121,8 +17188,10 @@ class WalkerUtils {
|
|
|
17121
17188
|
for (const strategyName of walkerSchema.strategies) {
|
|
17122
17189
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_STOP);
|
|
17123
17190
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17124
|
-
riskName &&
|
|
17125
|
-
|
|
17191
|
+
riskName &&
|
|
17192
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_STOP);
|
|
17193
|
+
riskList &&
|
|
17194
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_STOP));
|
|
17126
17195
|
}
|
|
17127
17196
|
const instance = this._getInstance(symbol, walkerName);
|
|
17128
17197
|
return await instance.stop(symbol, walkerName);
|
|
@@ -17146,8 +17215,10 @@ class WalkerUtils {
|
|
|
17146
17215
|
for (const strategyName of walkerSchema.strategies) {
|
|
17147
17216
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_GET_DATA);
|
|
17148
17217
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17149
|
-
riskName &&
|
|
17150
|
-
|
|
17218
|
+
riskName &&
|
|
17219
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_DATA);
|
|
17220
|
+
riskList &&
|
|
17221
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_DATA));
|
|
17151
17222
|
}
|
|
17152
17223
|
const instance = this._getInstance(symbol, walkerName);
|
|
17153
17224
|
return await instance.getData(symbol, walkerName);
|
|
@@ -17173,8 +17244,10 @@ class WalkerUtils {
|
|
|
17173
17244
|
for (const strategyName of walkerSchema.strategies) {
|
|
17174
17245
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_GET_REPORT);
|
|
17175
17246
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17176
|
-
riskName &&
|
|
17177
|
-
|
|
17247
|
+
riskName &&
|
|
17248
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_REPORT);
|
|
17249
|
+
riskList &&
|
|
17250
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_REPORT));
|
|
17178
17251
|
}
|
|
17179
17252
|
const instance = this._getInstance(symbol, walkerName);
|
|
17180
17253
|
return await instance.getReport(symbol, walkerName, strategyColumns, pnlColumns);
|
|
@@ -17203,8 +17276,10 @@ class WalkerUtils {
|
|
|
17203
17276
|
for (const strategyName of walkerSchema.strategies) {
|
|
17204
17277
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_DUMP);
|
|
17205
17278
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17206
|
-
riskName &&
|
|
17207
|
-
|
|
17279
|
+
riskName &&
|
|
17280
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_DUMP);
|
|
17281
|
+
riskList &&
|
|
17282
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_DUMP));
|
|
17208
17283
|
}
|
|
17209
17284
|
const instance = this._getInstance(symbol, walkerName);
|
|
17210
17285
|
return await instance.dump(symbol, walkerName, path, strategyColumns, pnlColumns);
|