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.mjs
CHANGED
|
@@ -2626,7 +2626,7 @@ const PersistScheduleAdapter = new PersistScheduleUtils();
|
|
|
2626
2626
|
* Utility class for managing partial profit/loss levels persistence.
|
|
2627
2627
|
*
|
|
2628
2628
|
* Features:
|
|
2629
|
-
* - Memoized storage instances per symbol
|
|
2629
|
+
* - Memoized storage instances per symbol:strategyName
|
|
2630
2630
|
* - Custom adapter support
|
|
2631
2631
|
* - Atomic read/write operations for partial data
|
|
2632
2632
|
* - Crash-safe partial state management
|
|
@@ -2636,23 +2636,25 @@ const PersistScheduleAdapter = new PersistScheduleUtils();
|
|
|
2636
2636
|
class PersistPartialUtils {
|
|
2637
2637
|
constructor() {
|
|
2638
2638
|
this.PersistPartialFactory = PersistBase;
|
|
2639
|
-
this.getPartialStorage = memoize(([symbol]) => `${symbol}`, (symbol) => Reflect.construct(this.PersistPartialFactory, [
|
|
2640
|
-
symbol
|
|
2639
|
+
this.getPartialStorage = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => Reflect.construct(this.PersistPartialFactory, [
|
|
2640
|
+
`${symbol}_${strategyName}`,
|
|
2641
2641
|
`./dump/data/partial/`,
|
|
2642
2642
|
]));
|
|
2643
2643
|
/**
|
|
2644
|
-
* Reads persisted partial data for a symbol.
|
|
2644
|
+
* Reads persisted partial data for a symbol and strategy.
|
|
2645
2645
|
*
|
|
2646
2646
|
* Called by ClientPartial.waitForInit() to restore state.
|
|
2647
2647
|
* Returns empty object if no partial data exists.
|
|
2648
2648
|
*
|
|
2649
2649
|
* @param symbol - Trading pair symbol
|
|
2650
|
+
* @param strategyName - Strategy identifier
|
|
2650
2651
|
* @returns Promise resolving to partial data record
|
|
2651
2652
|
*/
|
|
2652
|
-
this.readPartialData = async (symbol) => {
|
|
2653
|
+
this.readPartialData = async (symbol, strategyName) => {
|
|
2653
2654
|
backtest$1.loggerService.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
|
|
2654
|
-
const
|
|
2655
|
-
const
|
|
2655
|
+
const key = `${symbol}:${strategyName}`;
|
|
2656
|
+
const isInitial = !this.getPartialStorage.has(key);
|
|
2657
|
+
const stateStorage = this.getPartialStorage(symbol, strategyName);
|
|
2656
2658
|
await stateStorage.waitForInit(isInitial);
|
|
2657
2659
|
const PARTIAL_STORAGE_KEY = "levels";
|
|
2658
2660
|
if (await stateStorage.hasValue(PARTIAL_STORAGE_KEY)) {
|
|
@@ -2668,12 +2670,14 @@ class PersistPartialUtils {
|
|
|
2668
2670
|
*
|
|
2669
2671
|
* @param partialData - Record of signal IDs to partial data
|
|
2670
2672
|
* @param symbol - Trading pair symbol
|
|
2673
|
+
* @param strategyName - Strategy identifier
|
|
2671
2674
|
* @returns Promise that resolves when write is complete
|
|
2672
2675
|
*/
|
|
2673
|
-
this.writePartialData = async (partialData, symbol) => {
|
|
2676
|
+
this.writePartialData = async (partialData, symbol, strategyName) => {
|
|
2674
2677
|
backtest$1.loggerService.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2675
|
-
const
|
|
2676
|
-
const
|
|
2678
|
+
const key = `${symbol}:${strategyName}`;
|
|
2679
|
+
const isInitial = !this.getPartialStorage.has(key);
|
|
2680
|
+
const stateStorage = this.getPartialStorage(symbol, strategyName);
|
|
2677
2681
|
await stateStorage.waitForInit(isInitial);
|
|
2678
2682
|
const PARTIAL_STORAGE_KEY = "levels";
|
|
2679
2683
|
await stateStorage.writeValue(PARTIAL_STORAGE_KEY, partialData);
|
|
@@ -2708,10 +2712,10 @@ class PersistPartialUtils {
|
|
|
2708
2712
|
* PersistPartialAdapter.usePersistPartialAdapter(RedisPersist);
|
|
2709
2713
|
*
|
|
2710
2714
|
* // Read partial data
|
|
2711
|
-
* const partialData = await PersistPartialAdapter.readPartialData("BTCUSDT");
|
|
2715
|
+
* const partialData = await PersistPartialAdapter.readPartialData("BTCUSDT", "my-strategy");
|
|
2712
2716
|
*
|
|
2713
2717
|
* // Write partial data
|
|
2714
|
-
* await PersistPartialAdapter.writePartialData(partialData, "BTCUSDT");
|
|
2718
|
+
* await PersistPartialAdapter.writePartialData(partialData, "BTCUSDT", "my-strategy");
|
|
2715
2719
|
* ```
|
|
2716
2720
|
*/
|
|
2717
2721
|
const PersistPartialAdapter = new PersistPartialUtils();
|
|
@@ -4572,25 +4576,25 @@ const NOOP_RISK = {
|
|
|
4572
4576
|
addSignal: () => Promise.resolve(),
|
|
4573
4577
|
removeSignal: () => Promise.resolve(),
|
|
4574
4578
|
};
|
|
4575
|
-
const GET_RISK_FN = (dto, self) => {
|
|
4579
|
+
const GET_RISK_FN = (dto, backtest, self) => {
|
|
4576
4580
|
const hasRiskName = !!dto.riskName;
|
|
4577
|
-
const hasRiskList = !!
|
|
4581
|
+
const hasRiskList = !!dto.riskList?.length;
|
|
4578
4582
|
// Нет ни riskName, ни riskList
|
|
4579
4583
|
if (!hasRiskName && !hasRiskList) {
|
|
4580
4584
|
return NOOP_RISK;
|
|
4581
4585
|
}
|
|
4582
4586
|
// Есть только riskName (без riskList)
|
|
4583
4587
|
if (hasRiskName && !hasRiskList) {
|
|
4584
|
-
return self.riskConnectionService.getRisk(dto.riskName);
|
|
4588
|
+
return self.riskConnectionService.getRisk(dto.riskName, backtest);
|
|
4585
4589
|
}
|
|
4586
4590
|
// Есть только riskList (без riskName)
|
|
4587
4591
|
if (!hasRiskName && hasRiskList) {
|
|
4588
|
-
return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName)));
|
|
4592
|
+
return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)));
|
|
4589
4593
|
}
|
|
4590
4594
|
// Есть и riskName, и riskList - объединяем (riskName в начало)
|
|
4591
4595
|
return new MergeRisk([
|
|
4592
|
-
self.riskConnectionService.getRisk(dto.riskName),
|
|
4593
|
-
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName))
|
|
4596
|
+
self.riskConnectionService.getRisk(dto.riskName, backtest),
|
|
4597
|
+
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
|
|
4594
4598
|
]);
|
|
4595
4599
|
};
|
|
4596
4600
|
/**
|
|
@@ -4632,7 +4636,7 @@ class StrategyConnectionService {
|
|
|
4632
4636
|
* @param strategyName - Name of registered strategy schema
|
|
4633
4637
|
* @returns Configured ClientStrategy instance
|
|
4634
4638
|
*/
|
|
4635
|
-
this.getStrategy = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => {
|
|
4639
|
+
this.getStrategy = memoize(([symbol, strategyName, backtest]) => `${symbol}:${strategyName}:${backtest ? "backtest" : "live"}`, (symbol, strategyName, backtest) => {
|
|
4636
4640
|
const { riskName = "", riskList = [], getSignal, interval, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
4637
4641
|
return new ClientStrategy({
|
|
4638
4642
|
symbol,
|
|
@@ -4645,7 +4649,7 @@ class StrategyConnectionService {
|
|
|
4645
4649
|
risk: GET_RISK_FN({
|
|
4646
4650
|
riskName,
|
|
4647
4651
|
riskList,
|
|
4648
|
-
}, this),
|
|
4652
|
+
}, backtest, this),
|
|
4649
4653
|
riskName,
|
|
4650
4654
|
strategyName,
|
|
4651
4655
|
getSignal,
|
|
@@ -4662,12 +4666,13 @@ class StrategyConnectionService {
|
|
|
4662
4666
|
*
|
|
4663
4667
|
* @returns Promise resolving to pending signal or null
|
|
4664
4668
|
*/
|
|
4665
|
-
this.getPendingSignal = async (symbol, strategyName) => {
|
|
4669
|
+
this.getPendingSignal = async (backtest, symbol, strategyName) => {
|
|
4666
4670
|
this.loggerService.log("strategyConnectionService getPendingSignal", {
|
|
4667
4671
|
symbol,
|
|
4668
4672
|
strategyName,
|
|
4673
|
+
backtest,
|
|
4669
4674
|
});
|
|
4670
|
-
const strategy = this.getStrategy(symbol, strategyName);
|
|
4675
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4671
4676
|
return await strategy.getPendingSignal(symbol, strategyName);
|
|
4672
4677
|
};
|
|
4673
4678
|
/**
|
|
@@ -4680,12 +4685,13 @@ class StrategyConnectionService {
|
|
|
4680
4685
|
* @param strategyName - Name of the strategy
|
|
4681
4686
|
* @returns Promise resolving to true if strategy is stopped, false otherwise
|
|
4682
4687
|
*/
|
|
4683
|
-
this.getStopped = async (symbol, strategyName) => {
|
|
4688
|
+
this.getStopped = async (backtest, symbol, strategyName) => {
|
|
4684
4689
|
this.loggerService.log("strategyConnectionService getStopped", {
|
|
4685
4690
|
symbol,
|
|
4686
4691
|
strategyName,
|
|
4692
|
+
backtest,
|
|
4687
4693
|
});
|
|
4688
|
-
const strategy = this.getStrategy(symbol, strategyName);
|
|
4694
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4689
4695
|
return await strategy.getStopped(symbol, strategyName);
|
|
4690
4696
|
};
|
|
4691
4697
|
/**
|
|
@@ -4703,7 +4709,8 @@ class StrategyConnectionService {
|
|
|
4703
4709
|
symbol,
|
|
4704
4710
|
strategyName,
|
|
4705
4711
|
});
|
|
4706
|
-
const
|
|
4712
|
+
const backtest = this.executionContextService.context.backtest;
|
|
4713
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4707
4714
|
await strategy.waitForInit();
|
|
4708
4715
|
const tick = await strategy.tick(symbol, strategyName);
|
|
4709
4716
|
{
|
|
@@ -4734,7 +4741,8 @@ class StrategyConnectionService {
|
|
|
4734
4741
|
strategyName,
|
|
4735
4742
|
candleCount: candles.length,
|
|
4736
4743
|
});
|
|
4737
|
-
const
|
|
4744
|
+
const backtest = this.executionContextService.context.backtest;
|
|
4745
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4738
4746
|
await strategy.waitForInit();
|
|
4739
4747
|
const tick = await strategy.backtest(symbol, strategyName, candles);
|
|
4740
4748
|
{
|
|
@@ -4755,11 +4763,11 @@ class StrategyConnectionService {
|
|
|
4755
4763
|
* @param strategyName - Name of strategy to stop
|
|
4756
4764
|
* @returns Promise that resolves when stop flag is set
|
|
4757
4765
|
*/
|
|
4758
|
-
this.stop = async (
|
|
4766
|
+
this.stop = async (backtest, ctx) => {
|
|
4759
4767
|
this.loggerService.log("strategyConnectionService stop", {
|
|
4760
4768
|
ctx,
|
|
4761
4769
|
});
|
|
4762
|
-
const strategy = this.getStrategy(ctx.symbol, ctx.strategyName);
|
|
4770
|
+
const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
|
|
4763
4771
|
await strategy.stop(ctx.symbol, ctx.strategyName, backtest);
|
|
4764
4772
|
};
|
|
4765
4773
|
/**
|
|
@@ -4770,12 +4778,12 @@ class StrategyConnectionService {
|
|
|
4770
4778
|
*
|
|
4771
4779
|
* @param ctx - Optional context with symbol and strategyName (clears all if not provided)
|
|
4772
4780
|
*/
|
|
4773
|
-
this.clear = async (ctx) => {
|
|
4781
|
+
this.clear = async (backtest, ctx) => {
|
|
4774
4782
|
this.loggerService.log("strategyConnectionService clear", {
|
|
4775
4783
|
ctx,
|
|
4776
4784
|
});
|
|
4777
4785
|
if (ctx) {
|
|
4778
|
-
const key = `${ctx.symbol}:${ctx.strategyName}`;
|
|
4786
|
+
const key = `${ctx.symbol}:${ctx.strategyName}:${backtest ? "backtest" : "live"}`;
|
|
4779
4787
|
this.getStrategy.clear(key);
|
|
4780
4788
|
}
|
|
4781
4789
|
else {
|
|
@@ -5170,9 +5178,15 @@ const DO_VALIDATION_FN = trycatch(async (validation, params) => {
|
|
|
5170
5178
|
* Initializes active positions by reading from persistence.
|
|
5171
5179
|
* Uses singleshot pattern to ensure it only runs once.
|
|
5172
5180
|
* This function is exported for use in tests or other modules.
|
|
5181
|
+
*
|
|
5182
|
+
* In backtest mode, initializes with empty Map. In live mode, reads from persist storage.
|
|
5173
5183
|
*/
|
|
5174
5184
|
const WAIT_FOR_INIT_FN$1 = async (self) => {
|
|
5175
|
-
self.params.logger.debug("ClientRisk waitForInit");
|
|
5185
|
+
self.params.logger.debug("ClientRisk waitForInit", { backtest: self.params.backtest });
|
|
5186
|
+
if (self.params.backtest) {
|
|
5187
|
+
self._activePositions = new Map();
|
|
5188
|
+
return;
|
|
5189
|
+
}
|
|
5176
5190
|
const persistedPositions = await PersistRiskAdapter.readPositionData(self.params.riskName);
|
|
5177
5191
|
self._activePositions = new Map(persistedPositions);
|
|
5178
5192
|
};
|
|
@@ -5220,6 +5234,7 @@ class ClientRisk {
|
|
|
5220
5234
|
this.params.logger.debug("ClientRisk checkSignal", {
|
|
5221
5235
|
symbol: params.symbol,
|
|
5222
5236
|
strategyName: params.strategyName,
|
|
5237
|
+
backtest: this.params.backtest,
|
|
5223
5238
|
});
|
|
5224
5239
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5225
5240
|
await this.waitForInit();
|
|
@@ -5265,8 +5280,12 @@ class ClientRisk {
|
|
|
5265
5280
|
}
|
|
5266
5281
|
/**
|
|
5267
5282
|
* Persists current active positions to disk.
|
|
5283
|
+
* Skips in backtest mode.
|
|
5268
5284
|
*/
|
|
5269
5285
|
async _updatePositions() {
|
|
5286
|
+
if (this.params.backtest) {
|
|
5287
|
+
return;
|
|
5288
|
+
}
|
|
5270
5289
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5271
5290
|
await this.waitForInit();
|
|
5272
5291
|
}
|
|
@@ -5280,6 +5299,7 @@ class ClientRisk {
|
|
|
5280
5299
|
this.params.logger.debug("ClientRisk addSignal", {
|
|
5281
5300
|
symbol,
|
|
5282
5301
|
context,
|
|
5302
|
+
backtest: this.params.backtest,
|
|
5283
5303
|
});
|
|
5284
5304
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5285
5305
|
await this.waitForInit();
|
|
@@ -5302,6 +5322,7 @@ class ClientRisk {
|
|
|
5302
5322
|
this.params.logger.debug("ClientRisk removeSignal", {
|
|
5303
5323
|
symbol,
|
|
5304
5324
|
context,
|
|
5325
|
+
backtest: this.params.backtest,
|
|
5305
5326
|
});
|
|
5306
5327
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
5307
5328
|
await this.waitForInit();
|
|
@@ -5372,19 +5393,21 @@ class RiskConnectionService {
|
|
|
5372
5393
|
this.loggerService = inject(TYPES.loggerService);
|
|
5373
5394
|
this.riskSchemaService = inject(TYPES.riskSchemaService);
|
|
5374
5395
|
/**
|
|
5375
|
-
* Retrieves memoized ClientRisk instance for given risk name.
|
|
5396
|
+
* Retrieves memoized ClientRisk instance for given risk name and backtest mode.
|
|
5376
5397
|
*
|
|
5377
5398
|
* Creates ClientRisk on first call, returns cached instance on subsequent calls.
|
|
5378
|
-
* Cache key is riskName string.
|
|
5399
|
+
* Cache key is "riskName:backtest" string to separate live and backtest instances.
|
|
5379
5400
|
*
|
|
5380
5401
|
* @param riskName - Name of registered risk schema
|
|
5402
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
5381
5403
|
* @returns Configured ClientRisk instance
|
|
5382
5404
|
*/
|
|
5383
|
-
this.getRisk = memoize(([riskName]) => `${riskName}`, (riskName) => {
|
|
5405
|
+
this.getRisk = memoize(([riskName, backtest]) => `${riskName}:${backtest ? "backtest" : "live"}`, (riskName, backtest) => {
|
|
5384
5406
|
const schema = this.riskSchemaService.get(riskName);
|
|
5385
5407
|
return new ClientRisk({
|
|
5386
5408
|
...schema,
|
|
5387
5409
|
logger: this.loggerService,
|
|
5410
|
+
backtest,
|
|
5388
5411
|
onRejected: COMMIT_REJECTION_FN,
|
|
5389
5412
|
});
|
|
5390
5413
|
});
|
|
@@ -5396,7 +5419,7 @@ class RiskConnectionService {
|
|
|
5396
5419
|
* ClientRisk will emit riskSubject event via onRejected callback when signal is rejected.
|
|
5397
5420
|
*
|
|
5398
5421
|
* @param params - Risk check arguments (portfolio state, position details)
|
|
5399
|
-
* @param context - Execution context with risk name
|
|
5422
|
+
* @param context - Execution context with risk name and backtest mode
|
|
5400
5423
|
* @returns Promise resolving to risk check result
|
|
5401
5424
|
*/
|
|
5402
5425
|
this.checkSignal = async (params, context) => {
|
|
@@ -5404,46 +5427,48 @@ class RiskConnectionService {
|
|
|
5404
5427
|
symbol: params.symbol,
|
|
5405
5428
|
context,
|
|
5406
5429
|
});
|
|
5407
|
-
return await this.getRisk(context.riskName).checkSignal(params);
|
|
5430
|
+
return await this.getRisk(context.riskName, context.backtest).checkSignal(params);
|
|
5408
5431
|
};
|
|
5409
5432
|
/**
|
|
5410
5433
|
* Registers an opened signal with the risk management system.
|
|
5411
5434
|
* Routes to appropriate ClientRisk instance.
|
|
5412
5435
|
*
|
|
5413
5436
|
* @param symbol - Trading pair symbol
|
|
5414
|
-
* @param context - Context information (strategyName, riskName)
|
|
5437
|
+
* @param context - Context information (strategyName, riskName, backtest)
|
|
5415
5438
|
*/
|
|
5416
5439
|
this.addSignal = async (symbol, context) => {
|
|
5417
5440
|
this.loggerService.log("riskConnectionService addSignal", {
|
|
5418
5441
|
symbol,
|
|
5419
5442
|
context,
|
|
5420
5443
|
});
|
|
5421
|
-
await this.getRisk(context.riskName).addSignal(symbol, context);
|
|
5444
|
+
await this.getRisk(context.riskName, context.backtest).addSignal(symbol, context);
|
|
5422
5445
|
};
|
|
5423
5446
|
/**
|
|
5424
5447
|
* Removes a closed signal from the risk management system.
|
|
5425
5448
|
* Routes to appropriate ClientRisk instance.
|
|
5426
5449
|
*
|
|
5427
5450
|
* @param symbol - Trading pair symbol
|
|
5428
|
-
* @param context - Context information (strategyName, riskName)
|
|
5451
|
+
* @param context - Context information (strategyName, riskName, backtest)
|
|
5429
5452
|
*/
|
|
5430
5453
|
this.removeSignal = async (symbol, context) => {
|
|
5431
5454
|
this.loggerService.log("riskConnectionService removeSignal", {
|
|
5432
5455
|
symbol,
|
|
5433
5456
|
context,
|
|
5434
5457
|
});
|
|
5435
|
-
await this.getRisk(context.riskName).removeSignal(symbol, context);
|
|
5458
|
+
await this.getRisk(context.riskName, context.backtest).removeSignal(symbol, context);
|
|
5436
5459
|
};
|
|
5437
5460
|
/**
|
|
5438
5461
|
* Clears the cached ClientRisk instance for the given risk name.
|
|
5439
5462
|
*
|
|
5440
5463
|
* @param riskName - Name of the risk schema to clear from cache
|
|
5441
5464
|
*/
|
|
5442
|
-
this.clear = async (riskName) => {
|
|
5465
|
+
this.clear = async (backtest, riskName) => {
|
|
5443
5466
|
this.loggerService.log("riskConnectionService clear", {
|
|
5444
5467
|
riskName,
|
|
5468
|
+
backtest,
|
|
5445
5469
|
});
|
|
5446
|
-
|
|
5470
|
+
const key = `${riskName}:${backtest ? "backtest" : "live"}`;
|
|
5471
|
+
this.getRisk.clear(key);
|
|
5447
5472
|
};
|
|
5448
5473
|
}
|
|
5449
5474
|
}
|
|
@@ -5666,7 +5691,7 @@ class StrategyCoreService {
|
|
|
5666
5691
|
* @param strategyName - Name of the strategy
|
|
5667
5692
|
* @returns Promise resolving to pending signal or null
|
|
5668
5693
|
*/
|
|
5669
|
-
this.getPendingSignal = async (symbol, strategyName) => {
|
|
5694
|
+
this.getPendingSignal = async (backtest, symbol, strategyName) => {
|
|
5670
5695
|
this.loggerService.log("strategyCoreService getPendingSignal", {
|
|
5671
5696
|
symbol,
|
|
5672
5697
|
strategyName,
|
|
@@ -5675,7 +5700,7 @@ class StrategyCoreService {
|
|
|
5675
5700
|
throw new Error("strategyCoreService getPendingSignal requires a method context");
|
|
5676
5701
|
}
|
|
5677
5702
|
await this.validate(symbol, strategyName);
|
|
5678
|
-
return await this.strategyConnectionService.getPendingSignal(symbol, strategyName);
|
|
5703
|
+
return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
|
|
5679
5704
|
};
|
|
5680
5705
|
/**
|
|
5681
5706
|
* Checks if the strategy has been stopped.
|
|
@@ -5687,16 +5712,17 @@ class StrategyCoreService {
|
|
|
5687
5712
|
* @param strategyName - Name of the strategy
|
|
5688
5713
|
* @returns Promise resolving to true if strategy is stopped, false otherwise
|
|
5689
5714
|
*/
|
|
5690
|
-
this.getStopped = async (symbol, strategyName) => {
|
|
5715
|
+
this.getStopped = async (backtest, symbol, strategyName) => {
|
|
5691
5716
|
this.loggerService.log("strategyCoreService getStopped", {
|
|
5692
5717
|
symbol,
|
|
5693
5718
|
strategyName,
|
|
5719
|
+
backtest,
|
|
5694
5720
|
});
|
|
5695
5721
|
if (!MethodContextService.hasContext()) {
|
|
5696
5722
|
throw new Error("strategyCoreService getStopped requires a method context");
|
|
5697
5723
|
}
|
|
5698
5724
|
await this.validate(symbol, strategyName);
|
|
5699
|
-
return await this.strategyConnectionService.getStopped(symbol, strategyName);
|
|
5725
|
+
return await this.strategyConnectionService.getStopped(backtest, symbol, strategyName);
|
|
5700
5726
|
};
|
|
5701
5727
|
/**
|
|
5702
5728
|
* Checks signal status at a specific timestamp.
|
|
@@ -5770,13 +5796,13 @@ class StrategyCoreService {
|
|
|
5770
5796
|
* @param strategyName - Name of strategy to stop
|
|
5771
5797
|
* @returns Promise that resolves when stop flag is set
|
|
5772
5798
|
*/
|
|
5773
|
-
this.stop = async (
|
|
5799
|
+
this.stop = async (backtest, ctx) => {
|
|
5774
5800
|
this.loggerService.log("strategyCoreService stop", {
|
|
5775
5801
|
ctx,
|
|
5776
5802
|
backtest,
|
|
5777
5803
|
});
|
|
5778
5804
|
await this.validate(ctx.symbol, ctx.strategyName);
|
|
5779
|
-
return await this.strategyConnectionService.stop(
|
|
5805
|
+
return await this.strategyConnectionService.stop(backtest, ctx);
|
|
5780
5806
|
};
|
|
5781
5807
|
/**
|
|
5782
5808
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -5786,14 +5812,14 @@ class StrategyCoreService {
|
|
|
5786
5812
|
*
|
|
5787
5813
|
* @param ctx - Optional context with symbol and strategyName (clears all if not provided)
|
|
5788
5814
|
*/
|
|
5789
|
-
this.clear = async (ctx) => {
|
|
5815
|
+
this.clear = async (backtest, ctx) => {
|
|
5790
5816
|
this.loggerService.log("strategyCoreService clear", {
|
|
5791
5817
|
ctx,
|
|
5792
5818
|
});
|
|
5793
5819
|
if (ctx) {
|
|
5794
5820
|
await this.validate(ctx.symbol, ctx.strategyName);
|
|
5795
5821
|
}
|
|
5796
|
-
return await this.strategyConnectionService.clear(ctx);
|
|
5822
|
+
return await this.strategyConnectionService.clear(backtest, ctx);
|
|
5797
5823
|
};
|
|
5798
5824
|
}
|
|
5799
5825
|
}
|
|
@@ -5934,14 +5960,15 @@ class RiskGlobalService {
|
|
|
5934
5960
|
* If no riskName is provided, clears all risk data.
|
|
5935
5961
|
* @param riskName - Optional name of the risk instance to clear
|
|
5936
5962
|
*/
|
|
5937
|
-
this.clear = async (riskName) => {
|
|
5963
|
+
this.clear = async (backtest, riskName) => {
|
|
5938
5964
|
this.loggerService.log("riskGlobalService clear", {
|
|
5939
5965
|
riskName,
|
|
5966
|
+
backtest,
|
|
5940
5967
|
});
|
|
5941
5968
|
if (riskName) {
|
|
5942
5969
|
await this.validate(riskName);
|
|
5943
5970
|
}
|
|
5944
|
-
return await this.riskConnectionService.clear(riskName);
|
|
5971
|
+
return await this.riskConnectionService.clear(backtest, riskName);
|
|
5945
5972
|
};
|
|
5946
5973
|
}
|
|
5947
5974
|
}
|
|
@@ -6485,7 +6512,7 @@ class BacktestLogicPrivateService {
|
|
|
6485
6512
|
});
|
|
6486
6513
|
}
|
|
6487
6514
|
// Check if strategy should stop before processing next frame
|
|
6488
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6515
|
+
if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
|
|
6489
6516
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (before tick)", {
|
|
6490
6517
|
symbol,
|
|
6491
6518
|
when: when.toISOString(),
|
|
@@ -6510,7 +6537,7 @@ class BacktestLogicPrivateService {
|
|
|
6510
6537
|
continue;
|
|
6511
6538
|
}
|
|
6512
6539
|
// Check if strategy should stop when idle (no active signal)
|
|
6513
|
-
if (await and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName))) {
|
|
6540
|
+
if (await and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName))) {
|
|
6514
6541
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (idle state)", {
|
|
6515
6542
|
symbol,
|
|
6516
6543
|
when: when.toISOString(),
|
|
@@ -6612,7 +6639,7 @@ class BacktestLogicPrivateService {
|
|
|
6612
6639
|
}
|
|
6613
6640
|
yield backtestResult;
|
|
6614
6641
|
// Check if strategy should stop after signal is closed
|
|
6615
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6642
|
+
if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
|
|
6616
6643
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (after scheduled signal closed)", {
|
|
6617
6644
|
symbol,
|
|
6618
6645
|
signalId: backtestResult.signal.id,
|
|
@@ -6705,7 +6732,7 @@ class BacktestLogicPrivateService {
|
|
|
6705
6732
|
}
|
|
6706
6733
|
yield backtestResult;
|
|
6707
6734
|
// Check if strategy should stop after signal is closed
|
|
6708
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6735
|
+
if (await this.strategyCoreService.getStopped(true, symbol, this.methodContextService.context.strategyName)) {
|
|
6709
6736
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (after signal closed)", {
|
|
6710
6737
|
symbol,
|
|
6711
6738
|
signalId: backtestResult.signal.id,
|
|
@@ -6848,7 +6875,7 @@ class LiveLogicPrivateService {
|
|
|
6848
6875
|
previousEventTimestamp = currentTimestamp;
|
|
6849
6876
|
// Check if strategy should stop when idle (no active signal)
|
|
6850
6877
|
if (result.action === "idle") {
|
|
6851
|
-
if (await and(Promise.resolve(true), this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName))) {
|
|
6878
|
+
if (await and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName))) {
|
|
6852
6879
|
this.loggerService.info("liveLogicPrivateService stopped by user request (idle state)", {
|
|
6853
6880
|
symbol,
|
|
6854
6881
|
when: when.toISOString(),
|
|
@@ -6870,7 +6897,7 @@ class LiveLogicPrivateService {
|
|
|
6870
6897
|
yield result;
|
|
6871
6898
|
// Check if strategy should stop after signal is closed
|
|
6872
6899
|
if (result.action === "closed") {
|
|
6873
|
-
if (await this.strategyCoreService.getStopped(symbol, this.methodContextService.context.strategyName)) {
|
|
6900
|
+
if (await this.strategyCoreService.getStopped(false, symbol, this.methodContextService.context.strategyName)) {
|
|
6874
6901
|
this.loggerService.info("liveLogicPrivateService stopped by user request (after signal closed)", {
|
|
6875
6902
|
symbol,
|
|
6876
6903
|
signalId: result.signal.id,
|
|
@@ -11665,6 +11692,9 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
|
|
|
11665
11692
|
if (self._states === NEED_FETCH) {
|
|
11666
11693
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
11667
11694
|
}
|
|
11695
|
+
if (data.id !== self.params.signalId) {
|
|
11696
|
+
throw new Error(`Signal ID mismatch: expected ${self.params.signalId}, got ${data.id}`);
|
|
11697
|
+
}
|
|
11668
11698
|
let state = self._states.get(data.id);
|
|
11669
11699
|
if (!state) {
|
|
11670
11700
|
state = {
|
|
@@ -11689,7 +11719,7 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
|
|
|
11689
11719
|
}
|
|
11690
11720
|
}
|
|
11691
11721
|
if (shouldPersist) {
|
|
11692
|
-
await self._persistState(symbol,
|
|
11722
|
+
await self._persistState(symbol, data.strategyName);
|
|
11693
11723
|
}
|
|
11694
11724
|
};
|
|
11695
11725
|
/**
|
|
@@ -11711,6 +11741,9 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
11711
11741
|
if (self._states === NEED_FETCH) {
|
|
11712
11742
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
11713
11743
|
}
|
|
11744
|
+
if (data.id !== self.params.signalId) {
|
|
11745
|
+
throw new Error(`Signal ID mismatch: expected ${self.params.signalId}, got ${data.id}`);
|
|
11746
|
+
}
|
|
11714
11747
|
let state = self._states.get(data.id);
|
|
11715
11748
|
if (!state) {
|
|
11716
11749
|
state = {
|
|
@@ -11736,7 +11769,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
11736
11769
|
}
|
|
11737
11770
|
}
|
|
11738
11771
|
if (shouldPersist) {
|
|
11739
|
-
await self._persistState(symbol,
|
|
11772
|
+
await self._persistState(symbol, data.strategyName);
|
|
11740
11773
|
}
|
|
11741
11774
|
};
|
|
11742
11775
|
/**
|
|
@@ -11745,15 +11778,29 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
11745
11778
|
* Loads persisted partial state from disk and restores in-memory Maps.
|
|
11746
11779
|
* Converts serialized arrays back to Sets for O(1) lookups.
|
|
11747
11780
|
*
|
|
11781
|
+
* ONLY runs in LIVE mode (backtest=false). In backtest mode, state is not persisted.
|
|
11782
|
+
*
|
|
11748
11783
|
* @param symbol - Trading pair symbol
|
|
11784
|
+
* @param strategyName - Strategy identifier
|
|
11785
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
11749
11786
|
* @param self - ClientPartial instance reference
|
|
11750
11787
|
*/
|
|
11751
|
-
const WAIT_FOR_INIT_FN = async (symbol, self) => {
|
|
11752
|
-
self.params.logger.debug("ClientPartial waitForInit", {
|
|
11753
|
-
|
|
11754
|
-
|
|
11788
|
+
const WAIT_FOR_INIT_FN = async (symbol, strategyName, self) => {
|
|
11789
|
+
self.params.logger.debug("ClientPartial waitForInit", {
|
|
11790
|
+
symbol,
|
|
11791
|
+
strategyName,
|
|
11792
|
+
backtest: self.params.backtest
|
|
11793
|
+
});
|
|
11794
|
+
if (self._states !== NEED_FETCH) {
|
|
11795
|
+
throw new Error("ClientPartial WAIT_FOR_INIT_FN should be called once!");
|
|
11796
|
+
}
|
|
11797
|
+
self._states = new Map();
|
|
11798
|
+
// Skip persistence in backtest mode
|
|
11799
|
+
if (self.params.backtest) {
|
|
11800
|
+
self.params.logger.debug("ClientPartial waitForInit: skipping persist read in backtest mode");
|
|
11801
|
+
return;
|
|
11755
11802
|
}
|
|
11756
|
-
const partialData = await PersistPartialAdapter.readPartialData(symbol);
|
|
11803
|
+
const partialData = await PersistPartialAdapter.readPartialData(symbol, strategyName);
|
|
11757
11804
|
for (const [signalId, data] of Object.entries(partialData)) {
|
|
11758
11805
|
const state = {
|
|
11759
11806
|
profitLevels: new Set(data.profitLevels),
|
|
@@ -11763,6 +11810,7 @@ const WAIT_FOR_INIT_FN = async (symbol, self) => {
|
|
|
11763
11810
|
}
|
|
11764
11811
|
self.params.logger.info("ClientPartial restored state", {
|
|
11765
11812
|
symbol,
|
|
11813
|
+
strategyName,
|
|
11766
11814
|
signalCount: Object.keys(partialData).length,
|
|
11767
11815
|
});
|
|
11768
11816
|
};
|
|
@@ -11841,23 +11889,24 @@ class ClientPartial {
|
|
|
11841
11889
|
/**
|
|
11842
11890
|
* Initializes partial state by loading from disk.
|
|
11843
11891
|
*
|
|
11844
|
-
* Uses singleshot pattern to ensure initialization happens exactly once per symbol.
|
|
11892
|
+
* Uses singleshot pattern to ensure initialization happens exactly once per symbol:strategyName.
|
|
11845
11893
|
* Reads persisted state from PersistPartialAdapter and restores to _states Map.
|
|
11846
11894
|
*
|
|
11847
11895
|
* Must be called before profit()/loss()/clear() methods.
|
|
11848
11896
|
*
|
|
11849
11897
|
* @param symbol - Trading pair symbol
|
|
11898
|
+
* @param strategyName - Strategy identifier
|
|
11899
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
11850
11900
|
* @returns Promise that resolves when initialization is complete
|
|
11851
11901
|
*
|
|
11852
11902
|
* @example
|
|
11853
11903
|
* ```typescript
|
|
11854
11904
|
* const partial = new ClientPartial(params);
|
|
11855
|
-
* await partial.waitForInit("BTCUSDT"); // Load persisted state
|
|
11905
|
+
* await partial.waitForInit("BTCUSDT", "my-strategy", false); // Load persisted state (live mode)
|
|
11856
11906
|
* // Now profit()/loss() can be called
|
|
11857
11907
|
* ```
|
|
11858
11908
|
*/
|
|
11859
|
-
this.waitForInit = singleshot(async (symbol) => await WAIT_FOR_INIT_FN(symbol, this));
|
|
11860
|
-
this._states = new Map();
|
|
11909
|
+
this.waitForInit = singleshot(async (symbol, strategyName) => await WAIT_FOR_INIT_FN(symbol, strategyName, this));
|
|
11861
11910
|
}
|
|
11862
11911
|
/**
|
|
11863
11912
|
* Persists current partial state to disk.
|
|
@@ -11870,13 +11919,15 @@ class ClientPartial {
|
|
|
11870
11919
|
* Uses atomic file writes via PersistPartialAdapter.
|
|
11871
11920
|
*
|
|
11872
11921
|
* @param symbol - Trading pair symbol
|
|
11922
|
+
* @param strategyName - Strategy identifier
|
|
11923
|
+
* @param backtest - True if backtest mode
|
|
11873
11924
|
* @returns Promise that resolves when persistence is complete
|
|
11874
11925
|
*/
|
|
11875
|
-
async _persistState(symbol,
|
|
11876
|
-
if (backtest) {
|
|
11926
|
+
async _persistState(symbol, strategyName) {
|
|
11927
|
+
if (this.params.backtest) {
|
|
11877
11928
|
return;
|
|
11878
11929
|
}
|
|
11879
|
-
this.params.logger.debug("ClientPartial persistState", { symbol });
|
|
11930
|
+
this.params.logger.debug("ClientPartial persistState", { symbol, strategyName });
|
|
11880
11931
|
if (this._states === NEED_FETCH) {
|
|
11881
11932
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
11882
11933
|
}
|
|
@@ -11887,7 +11938,7 @@ class ClientPartial {
|
|
|
11887
11938
|
lossLevels: Array.from(state.lossLevels),
|
|
11888
11939
|
};
|
|
11889
11940
|
}
|
|
11890
|
-
await PersistPartialAdapter.writePartialData(partialData, symbol);
|
|
11941
|
+
await PersistPartialAdapter.writePartialData(partialData, symbol, strategyName);
|
|
11891
11942
|
}
|
|
11892
11943
|
/**
|
|
11893
11944
|
* Processes profit state and emits events for newly reached profit levels.
|
|
@@ -12008,8 +12059,11 @@ class ClientPartial {
|
|
|
12008
12059
|
if (this._states === NEED_FETCH) {
|
|
12009
12060
|
throw new Error("ClientPartial not initialized. Call waitForInit() before using.");
|
|
12010
12061
|
}
|
|
12062
|
+
if (data.id !== this.params.signalId) {
|
|
12063
|
+
throw new Error(`Signal ID mismatch: expected ${this.params.signalId}, got ${data.id}`);
|
|
12064
|
+
}
|
|
12011
12065
|
this._states.delete(data.id);
|
|
12012
|
-
await this._persistState(symbol,
|
|
12066
|
+
await this._persistState(symbol, data.strategyName);
|
|
12013
12067
|
}
|
|
12014
12068
|
}
|
|
12015
12069
|
|
|
@@ -12104,15 +12158,17 @@ class PartialConnectionService {
|
|
|
12104
12158
|
/**
|
|
12105
12159
|
* Memoized factory function for ClientPartial instances.
|
|
12106
12160
|
*
|
|
12107
|
-
* Creates one ClientPartial per signal ID with configured callbacks.
|
|
12161
|
+
* Creates one ClientPartial per signal ID and backtest mode with configured callbacks.
|
|
12108
12162
|
* Instances are cached until clear() is called.
|
|
12109
12163
|
*
|
|
12110
|
-
* Key format: signalId
|
|
12164
|
+
* Key format: "signalId:backtest" or "signalId:live"
|
|
12111
12165
|
* Value: ClientPartial instance with logger and event emitters
|
|
12112
12166
|
*/
|
|
12113
|
-
this.getPartial = memoize(([signalId]) => `${signalId}`, () => {
|
|
12167
|
+
this.getPartial = memoize(([signalId, backtest]) => `${signalId}:${backtest ? "backtest" : "live"}`, (signalId, backtest) => {
|
|
12114
12168
|
return new ClientPartial({
|
|
12169
|
+
signalId,
|
|
12115
12170
|
logger: this.loggerService,
|
|
12171
|
+
backtest,
|
|
12116
12172
|
onProfit: COMMIT_PROFIT_FN,
|
|
12117
12173
|
onLoss: COMMIT_LOSS_FN,
|
|
12118
12174
|
});
|
|
@@ -12140,8 +12196,8 @@ class PartialConnectionService {
|
|
|
12140
12196
|
backtest,
|
|
12141
12197
|
when,
|
|
12142
12198
|
});
|
|
12143
|
-
const partial = this.getPartial(data.id);
|
|
12144
|
-
await partial.waitForInit(symbol);
|
|
12199
|
+
const partial = this.getPartial(data.id, backtest);
|
|
12200
|
+
await partial.waitForInit(symbol, data.strategyName);
|
|
12145
12201
|
return await partial.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
|
|
12146
12202
|
};
|
|
12147
12203
|
/**
|
|
@@ -12167,8 +12223,8 @@ class PartialConnectionService {
|
|
|
12167
12223
|
backtest,
|
|
12168
12224
|
when,
|
|
12169
12225
|
});
|
|
12170
|
-
const partial = this.getPartial(data.id);
|
|
12171
|
-
await partial.waitForInit(symbol);
|
|
12226
|
+
const partial = this.getPartial(data.id, backtest);
|
|
12227
|
+
await partial.waitForInit(symbol, data.strategyName);
|
|
12172
12228
|
return await partial.loss(symbol, data, currentPrice, lossPercent, backtest, when);
|
|
12173
12229
|
};
|
|
12174
12230
|
/**
|
|
@@ -12189,15 +12245,17 @@ class PartialConnectionService {
|
|
|
12189
12245
|
* @returns Promise that resolves when clear is complete
|
|
12190
12246
|
*/
|
|
12191
12247
|
this.clear = async (symbol, data, priceClose, backtest) => {
|
|
12192
|
-
this.loggerService.log("partialConnectionService
|
|
12248
|
+
this.loggerService.log("partialConnectionService clear", {
|
|
12193
12249
|
symbol,
|
|
12194
12250
|
data,
|
|
12195
12251
|
priceClose,
|
|
12252
|
+
backtest,
|
|
12196
12253
|
});
|
|
12197
|
-
const partial = this.getPartial(data.id);
|
|
12198
|
-
await partial.waitForInit(symbol);
|
|
12254
|
+
const partial = this.getPartial(data.id, backtest);
|
|
12255
|
+
await partial.waitForInit(symbol, data.strategyName);
|
|
12199
12256
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
12200
|
-
|
|
12257
|
+
const key = `${data.id}:${backtest ? "backtest" : "live"}`;
|
|
12258
|
+
this.getPartial.clear(key);
|
|
12201
12259
|
};
|
|
12202
12260
|
}
|
|
12203
12261
|
}
|
|
@@ -15549,12 +15607,12 @@ class BacktestInstance {
|
|
|
15549
15607
|
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
15550
15608
|
}
|
|
15551
15609
|
{
|
|
15552
|
-
backtest$1.strategyCoreService.clear({ symbol, strategyName: context.strategyName });
|
|
15610
|
+
backtest$1.strategyCoreService.clear(true, { symbol, strategyName: context.strategyName });
|
|
15553
15611
|
}
|
|
15554
15612
|
{
|
|
15555
15613
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
15556
|
-
riskName && backtest$1.riskGlobalService.clear(riskName);
|
|
15557
|
-
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(riskName));
|
|
15614
|
+
riskName && backtest$1.riskGlobalService.clear(true, riskName);
|
|
15615
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, riskName));
|
|
15558
15616
|
}
|
|
15559
15617
|
return backtest$1.backtestCommandService.run(symbol, context);
|
|
15560
15618
|
};
|
|
@@ -15585,9 +15643,9 @@ class BacktestInstance {
|
|
|
15585
15643
|
});
|
|
15586
15644
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
|
|
15587
15645
|
return () => {
|
|
15588
|
-
backtest$1.strategyCoreService.stop({ symbol, strategyName: context.strategyName }
|
|
15646
|
+
backtest$1.strategyCoreService.stop(true, { symbol, strategyName: context.strategyName });
|
|
15589
15647
|
backtest$1.strategyCoreService
|
|
15590
|
-
.getPendingSignal(symbol, context.strategyName)
|
|
15648
|
+
.getPendingSignal(true, symbol, context.strategyName)
|
|
15591
15649
|
.then(async (pendingSignal) => {
|
|
15592
15650
|
if (pendingSignal) {
|
|
15593
15651
|
return;
|
|
@@ -15627,7 +15685,7 @@ class BacktestInstance {
|
|
|
15627
15685
|
symbol,
|
|
15628
15686
|
strategyName,
|
|
15629
15687
|
});
|
|
15630
|
-
await backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
15688
|
+
await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
15631
15689
|
};
|
|
15632
15690
|
/**
|
|
15633
15691
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
@@ -16053,12 +16111,12 @@ class LiveInstance {
|
|
|
16053
16111
|
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
16054
16112
|
}
|
|
16055
16113
|
{
|
|
16056
|
-
backtest$1.strategyCoreService.clear({ symbol, strategyName: context.strategyName });
|
|
16114
|
+
backtest$1.strategyCoreService.clear(false, { symbol, strategyName: context.strategyName });
|
|
16057
16115
|
}
|
|
16058
16116
|
{
|
|
16059
16117
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16060
|
-
riskName && backtest$1.riskGlobalService.clear(riskName);
|
|
16061
|
-
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(riskName));
|
|
16118
|
+
riskName && backtest$1.riskGlobalService.clear(false, riskName);
|
|
16119
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(false, riskName));
|
|
16062
16120
|
}
|
|
16063
16121
|
return backtest$1.liveCommandService.run(symbol, context);
|
|
16064
16122
|
};
|
|
@@ -16089,9 +16147,9 @@ class LiveInstance {
|
|
|
16089
16147
|
});
|
|
16090
16148
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
|
|
16091
16149
|
return () => {
|
|
16092
|
-
backtest$1.strategyCoreService.stop({ symbol, strategyName: context.strategyName }
|
|
16150
|
+
backtest$1.strategyCoreService.stop(false, { symbol, strategyName: context.strategyName });
|
|
16093
16151
|
backtest$1.strategyCoreService
|
|
16094
|
-
.getPendingSignal(symbol, context.strategyName)
|
|
16152
|
+
.getPendingSignal(false, symbol, context.strategyName)
|
|
16095
16153
|
.then(async (pendingSignal) => {
|
|
16096
16154
|
if (pendingSignal) {
|
|
16097
16155
|
return;
|
|
@@ -16131,7 +16189,7 @@ class LiveInstance {
|
|
|
16131
16189
|
symbol,
|
|
16132
16190
|
strategyName,
|
|
16133
16191
|
});
|
|
16134
|
-
await backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
16192
|
+
await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
|
|
16135
16193
|
};
|
|
16136
16194
|
/**
|
|
16137
16195
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
@@ -16835,12 +16893,13 @@ class WalkerInstance {
|
|
|
16835
16893
|
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName });
|
|
16836
16894
|
}
|
|
16837
16895
|
{
|
|
16838
|
-
backtest$1.strategyCoreService.clear({ symbol, strategyName });
|
|
16896
|
+
backtest$1.strategyCoreService.clear(true, { symbol, strategyName });
|
|
16839
16897
|
}
|
|
16840
16898
|
{
|
|
16841
16899
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16842
|
-
riskName && backtest$1.riskGlobalService.clear(riskName);
|
|
16843
|
-
riskList &&
|
|
16900
|
+
riskName && backtest$1.riskGlobalService.clear(true, riskName);
|
|
16901
|
+
riskList &&
|
|
16902
|
+
riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(true, riskName));
|
|
16844
16903
|
}
|
|
16845
16904
|
}
|
|
16846
16905
|
return backtest$1.walkerCommandService.run(symbol, {
|
|
@@ -16876,8 +16935,12 @@ class WalkerInstance {
|
|
|
16876
16935
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(getErrorMessage(error))));
|
|
16877
16936
|
return () => {
|
|
16878
16937
|
for (const strategyName of walkerSchema.strategies) {
|
|
16879
|
-
backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
16880
|
-
walkerStopSubject.next({
|
|
16938
|
+
backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
16939
|
+
walkerStopSubject.next({
|
|
16940
|
+
symbol,
|
|
16941
|
+
strategyName,
|
|
16942
|
+
walkerName: context.walkerName,
|
|
16943
|
+
});
|
|
16881
16944
|
}
|
|
16882
16945
|
if (!this._isDone) {
|
|
16883
16946
|
doneWalkerSubject.next({
|
|
@@ -16922,7 +16985,7 @@ class WalkerInstance {
|
|
|
16922
16985
|
const walkerSchema = backtest$1.walkerSchemaService.get(walkerName);
|
|
16923
16986
|
for (const strategyName of walkerSchema.strategies) {
|
|
16924
16987
|
await walkerStopSubject.next({ symbol, strategyName, walkerName });
|
|
16925
|
-
await backtest$1.strategyCoreService.stop({ symbol, strategyName }
|
|
16988
|
+
await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
16926
16989
|
}
|
|
16927
16990
|
};
|
|
16928
16991
|
/**
|
|
@@ -17051,8 +17114,10 @@ class WalkerUtils {
|
|
|
17051
17114
|
for (const strategyName of walkerSchema.strategies) {
|
|
17052
17115
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_RUN);
|
|
17053
17116
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17054
|
-
riskName &&
|
|
17055
|
-
|
|
17117
|
+
riskName &&
|
|
17118
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_RUN);
|
|
17119
|
+
riskList &&
|
|
17120
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_RUN));
|
|
17056
17121
|
}
|
|
17057
17122
|
const instance = this._getInstance(symbol, context.walkerName);
|
|
17058
17123
|
return instance.run(symbol, context);
|
|
@@ -17084,8 +17149,10 @@ class WalkerUtils {
|
|
|
17084
17149
|
for (const strategyName of walkerSchema.strategies) {
|
|
17085
17150
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_BACKGROUND);
|
|
17086
17151
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17087
|
-
riskName &&
|
|
17088
|
-
|
|
17152
|
+
riskName &&
|
|
17153
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_BACKGROUND);
|
|
17154
|
+
riskList &&
|
|
17155
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_BACKGROUND));
|
|
17089
17156
|
}
|
|
17090
17157
|
const instance = this._getInstance(symbol, context.walkerName);
|
|
17091
17158
|
return instance.background(symbol, context);
|
|
@@ -17119,8 +17186,10 @@ class WalkerUtils {
|
|
|
17119
17186
|
for (const strategyName of walkerSchema.strategies) {
|
|
17120
17187
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_STOP);
|
|
17121
17188
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17122
|
-
riskName &&
|
|
17123
|
-
|
|
17189
|
+
riskName &&
|
|
17190
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_STOP);
|
|
17191
|
+
riskList &&
|
|
17192
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_STOP));
|
|
17124
17193
|
}
|
|
17125
17194
|
const instance = this._getInstance(symbol, walkerName);
|
|
17126
17195
|
return await instance.stop(symbol, walkerName);
|
|
@@ -17144,8 +17213,10 @@ class WalkerUtils {
|
|
|
17144
17213
|
for (const strategyName of walkerSchema.strategies) {
|
|
17145
17214
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_GET_DATA);
|
|
17146
17215
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17147
|
-
riskName &&
|
|
17148
|
-
|
|
17216
|
+
riskName &&
|
|
17217
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_DATA);
|
|
17218
|
+
riskList &&
|
|
17219
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_DATA));
|
|
17149
17220
|
}
|
|
17150
17221
|
const instance = this._getInstance(symbol, walkerName);
|
|
17151
17222
|
return await instance.getData(symbol, walkerName);
|
|
@@ -17171,8 +17242,10 @@ class WalkerUtils {
|
|
|
17171
17242
|
for (const strategyName of walkerSchema.strategies) {
|
|
17172
17243
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_GET_REPORT);
|
|
17173
17244
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17174
|
-
riskName &&
|
|
17175
|
-
|
|
17245
|
+
riskName &&
|
|
17246
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_REPORT);
|
|
17247
|
+
riskList &&
|
|
17248
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_GET_REPORT));
|
|
17176
17249
|
}
|
|
17177
17250
|
const instance = this._getInstance(symbol, walkerName);
|
|
17178
17251
|
return await instance.getReport(symbol, walkerName, strategyColumns, pnlColumns);
|
|
@@ -17201,8 +17274,10 @@ class WalkerUtils {
|
|
|
17201
17274
|
for (const strategyName of walkerSchema.strategies) {
|
|
17202
17275
|
backtest$1.strategyValidationService.validate(strategyName, WALKER_METHOD_NAME_DUMP);
|
|
17203
17276
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17204
|
-
riskName &&
|
|
17205
|
-
|
|
17277
|
+
riskName &&
|
|
17278
|
+
backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_DUMP);
|
|
17279
|
+
riskList &&
|
|
17280
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, WALKER_METHOD_NAME_DUMP));
|
|
17206
17281
|
}
|
|
17207
17282
|
const instance = this._getInstance(symbol, walkerName);
|
|
17208
17283
|
return await instance.dump(symbol, walkerName, path, strategyColumns, pnlColumns);
|