backtest-kit 1.6.9 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.cjs +1051 -602
- package/build/index.mjs +1051 -602
- package/package.json +1 -1
- package/types.d.ts +1034 -661
package/build/index.cjs
CHANGED
|
@@ -2095,6 +2095,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
|
|
|
2095
2095
|
symbol: self.params.execution.context.symbol,
|
|
2096
2096
|
strategyName: self.params.method.context.strategyName,
|
|
2097
2097
|
exchangeName: self.params.method.context.exchangeName,
|
|
2098
|
+
frameName: self.params.method.context.frameName,
|
|
2098
2099
|
currentPrice,
|
|
2099
2100
|
timestamp: currentTime,
|
|
2100
2101
|
}))) {
|
|
@@ -2121,6 +2122,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
|
|
|
2121
2122
|
symbol: self.params.execution.context.symbol,
|
|
2122
2123
|
exchangeName: self.params.method.context.exchangeName,
|
|
2123
2124
|
strategyName: self.params.method.context.strategyName,
|
|
2125
|
+
frameName: self.params.method.context.frameName,
|
|
2124
2126
|
scheduledAt: currentTime,
|
|
2125
2127
|
pendingAt: currentTime, // Для immediate signal оба времени одинаковые
|
|
2126
2128
|
_isScheduled: false,
|
|
@@ -2141,6 +2143,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
|
|
|
2141
2143
|
symbol: self.params.execution.context.symbol,
|
|
2142
2144
|
exchangeName: self.params.method.context.exchangeName,
|
|
2143
2145
|
strategyName: self.params.method.context.strategyName,
|
|
2146
|
+
frameName: self.params.method.context.frameName,
|
|
2144
2147
|
scheduledAt: currentTime,
|
|
2145
2148
|
pendingAt: currentTime, // Временно, обновится при активации
|
|
2146
2149
|
_isScheduled: true,
|
|
@@ -2157,6 +2160,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
|
|
|
2157
2160
|
symbol: self.params.execution.context.symbol,
|
|
2158
2161
|
exchangeName: self.params.method.context.exchangeName,
|
|
2159
2162
|
strategyName: self.params.method.context.strategyName,
|
|
2163
|
+
frameName: self.params.method.context.frameName,
|
|
2160
2164
|
scheduledAt: currentTime,
|
|
2161
2165
|
pendingAt: currentTime, // Для immediate signal оба времени одинаковые
|
|
2162
2166
|
_isScheduled: false,
|
|
@@ -2250,6 +2254,7 @@ const CHECK_SCHEDULED_SIGNAL_TIMEOUT_FN = async (self, scheduled, currentPrice)
|
|
|
2250
2254
|
closeTimestamp: currentTime,
|
|
2251
2255
|
strategyName: self.params.method.context.strategyName,
|
|
2252
2256
|
exchangeName: self.params.method.context.exchangeName,
|
|
2257
|
+
frameName: self.params.method.context.frameName,
|
|
2253
2258
|
symbol: self.params.execution.context.symbol,
|
|
2254
2259
|
backtest: self.params.execution.context.backtest,
|
|
2255
2260
|
reason: "timeout",
|
|
@@ -2307,6 +2312,7 @@ const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPr
|
|
|
2307
2312
|
closeTimestamp: self.params.execution.context.when.getTime(),
|
|
2308
2313
|
strategyName: self.params.method.context.strategyName,
|
|
2309
2314
|
exchangeName: self.params.method.context.exchangeName,
|
|
2315
|
+
frameName: self.params.method.context.frameName,
|
|
2310
2316
|
symbol: self.params.execution.context.symbol,
|
|
2311
2317
|
backtest: self.params.execution.context.backtest,
|
|
2312
2318
|
reason: "price_reject",
|
|
@@ -2345,6 +2351,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
2345
2351
|
pendingSignal: scheduled,
|
|
2346
2352
|
strategyName: self.params.method.context.strategyName,
|
|
2347
2353
|
exchangeName: self.params.method.context.exchangeName,
|
|
2354
|
+
frameName: self.params.method.context.frameName,
|
|
2348
2355
|
currentPrice: scheduled.priceOpen,
|
|
2349
2356
|
timestamp: activationTime,
|
|
2350
2357
|
}))) {
|
|
@@ -2366,6 +2373,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
2366
2373
|
await self.params.risk.addSignal(self.params.execution.context.symbol, {
|
|
2367
2374
|
strategyName: self.params.method.context.strategyName,
|
|
2368
2375
|
riskName: self.params.riskName,
|
|
2376
|
+
exchangeName: self.params.method.context.exchangeName,
|
|
2377
|
+
frameName: self.params.method.context.frameName,
|
|
2369
2378
|
});
|
|
2370
2379
|
if (self.params.callbacks?.onOpen) {
|
|
2371
2380
|
self.params.callbacks.onOpen(self.params.execution.context.symbol, self._pendingSignal, self._pendingSignal.priceOpen, self.params.execution.context.backtest);
|
|
@@ -2375,6 +2384,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
2375
2384
|
signal: self._pendingSignal,
|
|
2376
2385
|
strategyName: self.params.method.context.strategyName,
|
|
2377
2386
|
exchangeName: self.params.method.context.exchangeName,
|
|
2387
|
+
frameName: self.params.method.context.frameName,
|
|
2378
2388
|
symbol: self.params.execution.context.symbol,
|
|
2379
2389
|
currentPrice: self._pendingSignal.priceOpen,
|
|
2380
2390
|
backtest: self.params.execution.context.backtest,
|
|
@@ -2411,6 +2421,7 @@ const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice)
|
|
|
2411
2421
|
currentPrice: currentPrice,
|
|
2412
2422
|
strategyName: self.params.method.context.strategyName,
|
|
2413
2423
|
exchangeName: self.params.method.context.exchangeName,
|
|
2424
|
+
frameName: self.params.method.context.frameName,
|
|
2414
2425
|
symbol: self.params.execution.context.symbol,
|
|
2415
2426
|
percentTp: 0,
|
|
2416
2427
|
percentSl: 0,
|
|
@@ -2438,6 +2449,7 @@ const OPEN_NEW_SCHEDULED_SIGNAL_FN = async (self, signal) => {
|
|
|
2438
2449
|
signal: signal,
|
|
2439
2450
|
strategyName: self.params.method.context.strategyName,
|
|
2440
2451
|
exchangeName: self.params.method.context.exchangeName,
|
|
2452
|
+
frameName: self.params.method.context.frameName,
|
|
2441
2453
|
symbol: self.params.execution.context.symbol,
|
|
2442
2454
|
currentPrice: currentPrice,
|
|
2443
2455
|
backtest: self.params.execution.context.backtest,
|
|
@@ -2453,6 +2465,7 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
|
|
|
2453
2465
|
symbol: self.params.execution.context.symbol,
|
|
2454
2466
|
strategyName: self.params.method.context.strategyName,
|
|
2455
2467
|
exchangeName: self.params.method.context.exchangeName,
|
|
2468
|
+
frameName: self.params.method.context.frameName,
|
|
2456
2469
|
currentPrice: signal.priceOpen,
|
|
2457
2470
|
timestamp: self.params.execution.context.when.getTime(),
|
|
2458
2471
|
}))) {
|
|
@@ -2461,6 +2474,8 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
|
|
|
2461
2474
|
await self.params.risk.addSignal(self.params.execution.context.symbol, {
|
|
2462
2475
|
strategyName: self.params.method.context.strategyName,
|
|
2463
2476
|
riskName: self.params.riskName,
|
|
2477
|
+
exchangeName: self.params.method.context.exchangeName,
|
|
2478
|
+
frameName: self.params.method.context.frameName,
|
|
2464
2479
|
});
|
|
2465
2480
|
if (self.params.callbacks?.onOpen) {
|
|
2466
2481
|
self.params.callbacks.onOpen(self.params.execution.context.symbol, signal, signal.priceOpen, self.params.execution.context.backtest);
|
|
@@ -2470,6 +2485,7 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
|
|
|
2470
2485
|
signal: signal,
|
|
2471
2486
|
strategyName: self.params.method.context.strategyName,
|
|
2472
2487
|
exchangeName: self.params.method.context.exchangeName,
|
|
2488
|
+
frameName: self.params.method.context.frameName,
|
|
2473
2489
|
symbol: self.params.execution.context.symbol,
|
|
2474
2490
|
currentPrice: signal.priceOpen,
|
|
2475
2491
|
backtest: self.params.execution.context.backtest,
|
|
@@ -2525,6 +2541,8 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
|
|
|
2525
2541
|
await self.params.risk.removeSignal(self.params.execution.context.symbol, {
|
|
2526
2542
|
strategyName: self.params.method.context.strategyName,
|
|
2527
2543
|
riskName: self.params.riskName,
|
|
2544
|
+
exchangeName: self.params.method.context.exchangeName,
|
|
2545
|
+
frameName: self.params.method.context.frameName,
|
|
2528
2546
|
});
|
|
2529
2547
|
await self.setPendingSignal(null);
|
|
2530
2548
|
const result = {
|
|
@@ -2536,6 +2554,7 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
|
|
|
2536
2554
|
pnl: pnl,
|
|
2537
2555
|
strategyName: self.params.method.context.strategyName,
|
|
2538
2556
|
exchangeName: self.params.method.context.exchangeName,
|
|
2557
|
+
frameName: self.params.method.context.frameName,
|
|
2539
2558
|
symbol: self.params.execution.context.symbol,
|
|
2540
2559
|
backtest: self.params.execution.context.backtest,
|
|
2541
2560
|
};
|
|
@@ -2604,6 +2623,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice) => {
|
|
|
2604
2623
|
currentPrice: currentPrice,
|
|
2605
2624
|
strategyName: self.params.method.context.strategyName,
|
|
2606
2625
|
exchangeName: self.params.method.context.exchangeName,
|
|
2626
|
+
frameName: self.params.method.context.frameName,
|
|
2607
2627
|
symbol: self.params.execution.context.symbol,
|
|
2608
2628
|
percentTp,
|
|
2609
2629
|
percentSl,
|
|
@@ -2623,6 +2643,7 @@ const RETURN_IDLE_FN = async (self, currentPrice) => {
|
|
|
2623
2643
|
signal: null,
|
|
2624
2644
|
strategyName: self.params.method.context.strategyName,
|
|
2625
2645
|
exchangeName: self.params.method.context.exchangeName,
|
|
2646
|
+
frameName: self.params.method.context.frameName,
|
|
2626
2647
|
symbol: self.params.execution.context.symbol,
|
|
2627
2648
|
currentPrice: currentPrice,
|
|
2628
2649
|
backtest: self.params.execution.context.backtest,
|
|
@@ -2652,6 +2673,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
|
|
|
2652
2673
|
closeTimestamp: closeTimestamp,
|
|
2653
2674
|
strategyName: self.params.method.context.strategyName,
|
|
2654
2675
|
exchangeName: self.params.method.context.exchangeName,
|
|
2676
|
+
frameName: self.params.method.context.frameName,
|
|
2655
2677
|
symbol: self.params.execution.context.symbol,
|
|
2656
2678
|
backtest: self.params.execution.context.backtest,
|
|
2657
2679
|
reason,
|
|
@@ -2687,6 +2709,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
|
|
|
2687
2709
|
symbol: self.params.execution.context.symbol,
|
|
2688
2710
|
strategyName: self.params.method.context.strategyName,
|
|
2689
2711
|
exchangeName: self.params.method.context.exchangeName,
|
|
2712
|
+
frameName: self.params.method.context.frameName,
|
|
2690
2713
|
currentPrice: scheduled.priceOpen,
|
|
2691
2714
|
timestamp: activationTime,
|
|
2692
2715
|
}))) {
|
|
@@ -2708,6 +2731,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
|
|
|
2708
2731
|
await self.params.risk.addSignal(self.params.execution.context.symbol, {
|
|
2709
2732
|
strategyName: self.params.method.context.strategyName,
|
|
2710
2733
|
riskName: self.params.riskName,
|
|
2734
|
+
exchangeName: self.params.method.context.exchangeName,
|
|
2735
|
+
frameName: self.params.method.context.frameName,
|
|
2711
2736
|
});
|
|
2712
2737
|
if (self.params.callbacks?.onOpen) {
|
|
2713
2738
|
self.params.callbacks.onOpen(self.params.execution.context.symbol, activatedSignal, activatedSignal.priceOpen, self.params.execution.context.backtest);
|
|
@@ -2738,6 +2763,8 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
|
|
|
2738
2763
|
await self.params.risk.removeSignal(self.params.execution.context.symbol, {
|
|
2739
2764
|
strategyName: self.params.method.context.strategyName,
|
|
2740
2765
|
riskName: self.params.riskName,
|
|
2766
|
+
exchangeName: self.params.method.context.exchangeName,
|
|
2767
|
+
frameName: self.params.method.context.frameName,
|
|
2741
2768
|
});
|
|
2742
2769
|
await self.setPendingSignal(null);
|
|
2743
2770
|
const result = {
|
|
@@ -2749,6 +2776,7 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
|
|
|
2749
2776
|
pnl: pnl,
|
|
2750
2777
|
strategyName: self.params.method.context.strategyName,
|
|
2751
2778
|
exchangeName: self.params.method.context.exchangeName,
|
|
2779
|
+
frameName: self.params.method.context.frameName,
|
|
2752
2780
|
symbol: self.params.execution.context.symbol,
|
|
2753
2781
|
backtest: self.params.execution.context.backtest,
|
|
2754
2782
|
};
|
|
@@ -3045,10 +3073,9 @@ class ClientStrategy {
|
|
|
3045
3073
|
* If no signal is pending, returns null.
|
|
3046
3074
|
* @returns Promise resolving to the pending signal or null.
|
|
3047
3075
|
*/
|
|
3048
|
-
async getPendingSignal(symbol
|
|
3076
|
+
async getPendingSignal(symbol) {
|
|
3049
3077
|
this.params.logger.debug("ClientStrategy getPendingSignal", {
|
|
3050
3078
|
symbol,
|
|
3051
|
-
strategyName,
|
|
3052
3079
|
});
|
|
3053
3080
|
return this._pendingSignal;
|
|
3054
3081
|
}
|
|
@@ -3057,10 +3084,9 @@ class ClientStrategy {
|
|
|
3057
3084
|
* If no scheduled signal exists, returns null.
|
|
3058
3085
|
* @returns Promise resolving to the scheduled signal or null.
|
|
3059
3086
|
*/
|
|
3060
|
-
async getScheduledSignal(symbol
|
|
3087
|
+
async getScheduledSignal(symbol) {
|
|
3061
3088
|
this.params.logger.debug("ClientStrategy getScheduledSignal", {
|
|
3062
3089
|
symbol,
|
|
3063
|
-
strategyName,
|
|
3064
3090
|
});
|
|
3065
3091
|
return this._scheduledSignal;
|
|
3066
3092
|
}
|
|
@@ -3071,13 +3097,12 @@ class ClientStrategy {
|
|
|
3071
3097
|
* not continue processing new ticks or signals.
|
|
3072
3098
|
*
|
|
3073
3099
|
* @param symbol - Trading pair symbol
|
|
3074
|
-
* @param strategyName - Name of the strategy
|
|
3075
3100
|
* @returns Promise resolving to true if strategy is stopped, false otherwise
|
|
3076
3101
|
*/
|
|
3077
|
-
async getStopped(symbol
|
|
3102
|
+
async getStopped(symbol) {
|
|
3078
3103
|
this.params.logger.debug("ClientStrategy getStopped", {
|
|
3079
3104
|
symbol,
|
|
3080
|
-
strategyName,
|
|
3105
|
+
strategyName: this.params.method.context.strategyName,
|
|
3081
3106
|
});
|
|
3082
3107
|
return this._isStopped;
|
|
3083
3108
|
}
|
|
@@ -3143,6 +3168,7 @@ class ClientStrategy {
|
|
|
3143
3168
|
closeTimestamp: currentTime,
|
|
3144
3169
|
strategyName: this.params.method.context.strategyName,
|
|
3145
3170
|
exchangeName: this.params.method.context.exchangeName,
|
|
3171
|
+
frameName: this.params.method.context.frameName,
|
|
3146
3172
|
symbol: this.params.execution.context.symbol,
|
|
3147
3173
|
backtest: this.params.execution.context.backtest,
|
|
3148
3174
|
reason: "user",
|
|
@@ -3256,6 +3282,7 @@ class ClientStrategy {
|
|
|
3256
3282
|
closeTimestamp: this.params.execution.context.when.getTime(),
|
|
3257
3283
|
strategyName: this.params.method.context.strategyName,
|
|
3258
3284
|
exchangeName: this.params.method.context.exchangeName,
|
|
3285
|
+
frameName: this.params.method.context.frameName,
|
|
3259
3286
|
symbol: this.params.execution.context.symbol,
|
|
3260
3287
|
backtest: true,
|
|
3261
3288
|
reason: "user",
|
|
@@ -3318,6 +3345,7 @@ class ClientStrategy {
|
|
|
3318
3345
|
percentTp: 0,
|
|
3319
3346
|
strategyName: this.params.method.context.strategyName,
|
|
3320
3347
|
exchangeName: this.params.method.context.exchangeName,
|
|
3348
|
+
frameName: this.params.method.context.frameName,
|
|
3321
3349
|
symbol: this.params.execution.context.symbol,
|
|
3322
3350
|
backtest: this.params.execution.context.backtest,
|
|
3323
3351
|
};
|
|
@@ -3374,13 +3402,11 @@ class ClientStrategy {
|
|
|
3374
3402
|
* // Existing signal will continue until natural close
|
|
3375
3403
|
* ```
|
|
3376
3404
|
*/
|
|
3377
|
-
async stop(symbol,
|
|
3405
|
+
async stop(symbol, backtest) {
|
|
3378
3406
|
this.params.logger.debug("ClientStrategy stop", {
|
|
3379
3407
|
symbol,
|
|
3380
|
-
strategyName,
|
|
3381
3408
|
hasPendingSignal: this._pendingSignal !== null,
|
|
3382
3409
|
hasScheduledSignal: this._scheduledSignal !== null,
|
|
3383
|
-
backtest,
|
|
3384
3410
|
});
|
|
3385
3411
|
this._isStopped = true;
|
|
3386
3412
|
// Clear scheduled signal if exists
|
|
@@ -3391,7 +3417,7 @@ class ClientStrategy {
|
|
|
3391
3417
|
if (backtest) {
|
|
3392
3418
|
return;
|
|
3393
3419
|
}
|
|
3394
|
-
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
|
|
3420
|
+
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
|
|
3395
3421
|
}
|
|
3396
3422
|
/**
|
|
3397
3423
|
* Cancels the scheduled signal without stopping the strategy.
|
|
@@ -3414,12 +3440,10 @@ class ClientStrategy {
|
|
|
3414
3440
|
* // Strategy continues, can generate new signals
|
|
3415
3441
|
* ```
|
|
3416
3442
|
*/
|
|
3417
|
-
async cancel(symbol,
|
|
3443
|
+
async cancel(symbol, backtest, cancelId) {
|
|
3418
3444
|
this.params.logger.debug("ClientStrategy cancel", {
|
|
3419
3445
|
symbol,
|
|
3420
|
-
strategyName,
|
|
3421
3446
|
hasScheduledSignal: this._scheduledSignal !== null,
|
|
3422
|
-
backtest,
|
|
3423
3447
|
cancelId,
|
|
3424
3448
|
});
|
|
3425
3449
|
// Save cancelled signal for next tick to emit cancelled event
|
|
@@ -3432,7 +3456,7 @@ class ClientStrategy {
|
|
|
3432
3456
|
if (backtest) {
|
|
3433
3457
|
return;
|
|
3434
3458
|
}
|
|
3435
|
-
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
|
|
3459
|
+
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
|
|
3436
3460
|
}
|
|
3437
3461
|
}
|
|
3438
3462
|
|
|
@@ -3508,7 +3532,7 @@ class MergeRisk {
|
|
|
3508
3532
|
* Used to track active positions across all risk management systems.
|
|
3509
3533
|
*
|
|
3510
3534
|
* @param symbol - Trading pair symbol
|
|
3511
|
-
* @param context - Context with strategyName and
|
|
3535
|
+
* @param context - Context with strategyName, riskName, exchangeName and frameName
|
|
3512
3536
|
* @returns Promise that resolves when all risks have registered the signal
|
|
3513
3537
|
*/
|
|
3514
3538
|
async addSignal(symbol, context) {
|
|
@@ -3525,7 +3549,7 @@ class MergeRisk {
|
|
|
3525
3549
|
* Used to update risk state when a position closes.
|
|
3526
3550
|
*
|
|
3527
3551
|
* @param symbol - Trading pair symbol
|
|
3528
|
-
* @param context - Context with strategyName and
|
|
3552
|
+
* @param context - Context with strategyName, riskName, exchangeName and frameName
|
|
3529
3553
|
* @returns Promise that resolves when all risks have removed the signal
|
|
3530
3554
|
*/
|
|
3531
3555
|
async removeSignal(symbol, context) {
|
|
@@ -3597,20 +3621,20 @@ class RiskUtils {
|
|
|
3597
3621
|
* }
|
|
3598
3622
|
* ```
|
|
3599
3623
|
*/
|
|
3600
|
-
this.getData = async (symbol,
|
|
3624
|
+
this.getData = async (symbol, context, backtest = false) => {
|
|
3601
3625
|
backtest$1.loggerService.info(RISK_METHOD_NAME_GET_DATA, {
|
|
3602
3626
|
symbol,
|
|
3603
|
-
strategyName,
|
|
3627
|
+
strategyName: context.strategyName,
|
|
3604
3628
|
});
|
|
3605
|
-
backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_DATA);
|
|
3629
|
+
backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_DATA);
|
|
3606
3630
|
{
|
|
3607
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
3631
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
3608
3632
|
riskName &&
|
|
3609
3633
|
backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA);
|
|
3610
3634
|
riskList &&
|
|
3611
3635
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
|
|
3612
3636
|
}
|
|
3613
|
-
return await backtest$1.riskMarkdownService.getData(symbol, strategyName, backtest);
|
|
3637
|
+
return await backtest$1.riskMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
3614
3638
|
};
|
|
3615
3639
|
/**
|
|
3616
3640
|
* Generates markdown report with all risk rejection events for a symbol-strategy pair.
|
|
@@ -3653,20 +3677,20 @@ class RiskUtils {
|
|
|
3653
3677
|
* // - my-strategy: 1
|
|
3654
3678
|
* ```
|
|
3655
3679
|
*/
|
|
3656
|
-
this.getReport = async (symbol,
|
|
3680
|
+
this.getReport = async (symbol, context, backtest = false, columns) => {
|
|
3657
3681
|
backtest$1.loggerService.info(RISK_METHOD_NAME_GET_REPORT, {
|
|
3658
3682
|
symbol,
|
|
3659
|
-
strategyName,
|
|
3683
|
+
strategyName: context.strategyName,
|
|
3660
3684
|
});
|
|
3661
|
-
backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_GET_REPORT);
|
|
3685
|
+
backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_GET_REPORT);
|
|
3662
3686
|
{
|
|
3663
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
3687
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
3664
3688
|
riskName &&
|
|
3665
3689
|
backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT);
|
|
3666
3690
|
riskList &&
|
|
3667
3691
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
|
|
3668
3692
|
}
|
|
3669
|
-
return await backtest$1.riskMarkdownService.getReport(symbol, strategyName, backtest, columns);
|
|
3693
|
+
return await backtest$1.riskMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
3670
3694
|
};
|
|
3671
3695
|
/**
|
|
3672
3696
|
* Generates and saves markdown report to file.
|
|
@@ -3700,21 +3724,21 @@ class RiskUtils {
|
|
|
3700
3724
|
* }
|
|
3701
3725
|
* ```
|
|
3702
3726
|
*/
|
|
3703
|
-
this.dump = async (symbol,
|
|
3727
|
+
this.dump = async (symbol, context, backtest = false, path, columns) => {
|
|
3704
3728
|
backtest$1.loggerService.info(RISK_METHOD_NAME_DUMP, {
|
|
3705
3729
|
symbol,
|
|
3706
|
-
strategyName,
|
|
3730
|
+
strategyName: context.strategyName,
|
|
3707
3731
|
path,
|
|
3708
3732
|
});
|
|
3709
|
-
backtest$1.strategyValidationService.validate(strategyName, RISK_METHOD_NAME_DUMP);
|
|
3733
|
+
backtest$1.strategyValidationService.validate(context.strategyName, RISK_METHOD_NAME_DUMP);
|
|
3710
3734
|
{
|
|
3711
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
3735
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
3712
3736
|
riskName &&
|
|
3713
3737
|
backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP);
|
|
3714
3738
|
riskList &&
|
|
3715
3739
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
|
|
3716
3740
|
}
|
|
3717
|
-
await backtest$1.riskMarkdownService.dump(symbol, strategyName, backtest, path, columns);
|
|
3741
|
+
await backtest$1.riskMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
3718
3742
|
};
|
|
3719
3743
|
}
|
|
3720
3744
|
}
|
|
@@ -3747,10 +3771,12 @@ const NOOP_RISK = {
|
|
|
3747
3771
|
* Determines the appropriate IRisk instance based on provided riskName and riskList.
|
|
3748
3772
|
* @param dto - Object containing riskName and riskList
|
|
3749
3773
|
* @param backtest - Whether running in backtest mode
|
|
3774
|
+
* @param exchangeName - Exchange name for risk isolation
|
|
3775
|
+
* @param frameName - Frame name for risk isolation
|
|
3750
3776
|
* @param self - Reference to StrategyConnectionService instance
|
|
3751
3777
|
* @returns Configured IRisk instance (single or merged)
|
|
3752
3778
|
*/
|
|
3753
|
-
const GET_RISK_FN = (dto, backtest, self) => {
|
|
3779
|
+
const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
|
|
3754
3780
|
const hasRiskName = !!dto.riskName;
|
|
3755
3781
|
const hasRiskList = !!dto.riskList?.length;
|
|
3756
3782
|
// Нет ни riskName, ни riskList
|
|
@@ -3759,27 +3785,35 @@ const GET_RISK_FN = (dto, backtest, self) => {
|
|
|
3759
3785
|
}
|
|
3760
3786
|
// Есть только riskName (без riskList)
|
|
3761
3787
|
if (hasRiskName && !hasRiskList) {
|
|
3762
|
-
return self.riskConnectionService.getRisk(dto.riskName, backtest);
|
|
3788
|
+
return self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest);
|
|
3763
3789
|
}
|
|
3764
3790
|
// Есть только riskList (без riskName)
|
|
3765
3791
|
if (!hasRiskName && hasRiskList) {
|
|
3766
|
-
return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)));
|
|
3792
|
+
return new MergeRisk(dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)));
|
|
3767
3793
|
}
|
|
3768
3794
|
// Есть и riskName, и riskList - объединяем (riskName в начало)
|
|
3769
3795
|
return new MergeRisk([
|
|
3770
|
-
self.riskConnectionService.getRisk(dto.riskName, backtest),
|
|
3771
|
-
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
|
|
3796
|
+
self.riskConnectionService.getRisk(dto.riskName, exchangeName, frameName, backtest),
|
|
3797
|
+
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, exchangeName, frameName, backtest)),
|
|
3772
3798
|
]);
|
|
3773
3799
|
};
|
|
3774
3800
|
/**
|
|
3775
3801
|
* Creates a unique key for memoizing ClientStrategy instances.
|
|
3776
|
-
* Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
|
|
3802
|
+
* Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
|
|
3777
3803
|
* @param symbol - Trading pair symbol
|
|
3778
3804
|
* @param strategyName - Name of the strategy
|
|
3805
|
+
* @param exchangeName - Exchange name
|
|
3806
|
+
* @param frameName - Frame name (empty string for live)
|
|
3779
3807
|
* @param backtest - Whether running in backtest mode
|
|
3780
3808
|
* @returns Unique string key for memoization
|
|
3781
3809
|
*/
|
|
3782
|
-
const CREATE_KEY_FN$b = (symbol, strategyName, backtest) =>
|
|
3810
|
+
const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
3811
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
3812
|
+
if (frameName)
|
|
3813
|
+
parts.push(frameName);
|
|
3814
|
+
parts.push(backtest ? "backtest" : "live");
|
|
3815
|
+
return parts.join(":");
|
|
3816
|
+
};
|
|
3783
3817
|
/**
|
|
3784
3818
|
* Callback function for emitting ping events to pingSubject.
|
|
3785
3819
|
*
|
|
@@ -3828,32 +3862,34 @@ class StrategyConnectionService {
|
|
|
3828
3862
|
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
3829
3863
|
this.riskConnectionService = inject(TYPES.riskConnectionService);
|
|
3830
3864
|
this.exchangeConnectionService = inject(TYPES.exchangeConnectionService);
|
|
3831
|
-
this.methodContextService = inject(TYPES.methodContextService);
|
|
3832
3865
|
this.partialConnectionService = inject(TYPES.partialConnectionService);
|
|
3833
3866
|
/**
|
|
3834
|
-
* Retrieves memoized ClientStrategy instance for given symbol-strategy pair.
|
|
3867
|
+
* Retrieves memoized ClientStrategy instance for given symbol-strategy pair with exchange and frame isolation.
|
|
3835
3868
|
*
|
|
3836
3869
|
* Creates ClientStrategy on first call, returns cached instance on subsequent calls.
|
|
3837
|
-
* Cache key
|
|
3870
|
+
* Cache key includes exchangeName and frameName for proper isolation.
|
|
3838
3871
|
*
|
|
3839
3872
|
* @param symbol - Trading pair symbol
|
|
3840
3873
|
* @param strategyName - Name of registered strategy schema
|
|
3874
|
+
* @param exchangeName - Exchange name
|
|
3875
|
+
* @param frameName - Frame name (empty string for live)
|
|
3876
|
+
* @param backtest - Whether running in backtest mode
|
|
3841
3877
|
* @returns Configured ClientStrategy instance
|
|
3842
3878
|
*/
|
|
3843
|
-
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, backtest), (symbol, strategyName, backtest) => {
|
|
3879
|
+
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
3844
3880
|
const { riskName = "", riskList = [], getSignal, interval, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
3845
3881
|
return new ClientStrategy({
|
|
3846
3882
|
symbol,
|
|
3847
3883
|
interval,
|
|
3848
3884
|
execution: this.executionContextService,
|
|
3849
|
-
method:
|
|
3885
|
+
method: { context: { strategyName, exchangeName, frameName } },
|
|
3850
3886
|
logger: this.loggerService,
|
|
3851
3887
|
partial: this.partialConnectionService,
|
|
3852
3888
|
exchange: this.exchangeConnectionService,
|
|
3853
3889
|
risk: GET_RISK_FN({
|
|
3854
3890
|
riskName,
|
|
3855
3891
|
riskList,
|
|
3856
|
-
}, backtest, this),
|
|
3892
|
+
}, backtest, exchangeName, frameName, this),
|
|
3857
3893
|
riskName,
|
|
3858
3894
|
strategyName,
|
|
3859
3895
|
getSignal,
|
|
@@ -3866,38 +3902,40 @@ class StrategyConnectionService {
|
|
|
3866
3902
|
* If no active signal exists, returns null.
|
|
3867
3903
|
* Used internally for monitoring TP/SL and time expiration.
|
|
3868
3904
|
*
|
|
3905
|
+
* @param backtest - Whether running in backtest mode
|
|
3869
3906
|
* @param symbol - Trading pair symbol
|
|
3870
|
-
* @param
|
|
3907
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
3871
3908
|
*
|
|
3872
3909
|
* @returns Promise resolving to pending signal or null
|
|
3873
3910
|
*/
|
|
3874
|
-
this.getPendingSignal = async (backtest, symbol,
|
|
3911
|
+
this.getPendingSignal = async (backtest, symbol, context) => {
|
|
3875
3912
|
this.loggerService.log("strategyConnectionService getPendingSignal", {
|
|
3876
3913
|
symbol,
|
|
3877
|
-
|
|
3914
|
+
context,
|
|
3878
3915
|
backtest,
|
|
3879
3916
|
});
|
|
3880
|
-
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3881
|
-
return await strategy.getPendingSignal(symbol
|
|
3917
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
3918
|
+
return await strategy.getPendingSignal(symbol);
|
|
3882
3919
|
};
|
|
3883
3920
|
/**
|
|
3884
3921
|
* Retrieves the currently active scheduled signal for the strategy.
|
|
3885
3922
|
* If no scheduled signal exists, returns null.
|
|
3886
3923
|
* Used internally for monitoring scheduled signal activation.
|
|
3887
3924
|
*
|
|
3925
|
+
* @param backtest - Whether running in backtest mode
|
|
3888
3926
|
* @param symbol - Trading pair symbol
|
|
3889
|
-
* @param
|
|
3927
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
3890
3928
|
*
|
|
3891
3929
|
* @returns Promise resolving to scheduled signal or null
|
|
3892
3930
|
*/
|
|
3893
|
-
this.getScheduledSignal = async (backtest, symbol,
|
|
3931
|
+
this.getScheduledSignal = async (backtest, symbol, context) => {
|
|
3894
3932
|
this.loggerService.log("strategyConnectionService getScheduledSignal", {
|
|
3895
3933
|
symbol,
|
|
3896
|
-
|
|
3934
|
+
context,
|
|
3897
3935
|
backtest,
|
|
3898
3936
|
});
|
|
3899
|
-
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3900
|
-
return await strategy.getScheduledSignal(symbol
|
|
3937
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
3938
|
+
return await strategy.getScheduledSignal(symbol);
|
|
3901
3939
|
};
|
|
3902
3940
|
/**
|
|
3903
3941
|
* Retrieves the stopped state of the strategy.
|
|
@@ -3905,18 +3943,19 @@ class StrategyConnectionService {
|
|
|
3905
3943
|
* Delegates to the underlying strategy instance to check if it has been
|
|
3906
3944
|
* marked as stopped and should cease operation.
|
|
3907
3945
|
*
|
|
3946
|
+
* @param backtest - Whether running in backtest mode
|
|
3908
3947
|
* @param symbol - Trading pair symbol
|
|
3909
|
-
* @param
|
|
3948
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
3910
3949
|
* @returns Promise resolving to true if strategy is stopped, false otherwise
|
|
3911
3950
|
*/
|
|
3912
|
-
this.getStopped = async (backtest, symbol,
|
|
3951
|
+
this.getStopped = async (backtest, symbol, context) => {
|
|
3913
3952
|
this.loggerService.log("strategyConnectionService getStopped", {
|
|
3914
3953
|
symbol,
|
|
3915
|
-
|
|
3954
|
+
context,
|
|
3916
3955
|
backtest,
|
|
3917
3956
|
});
|
|
3918
|
-
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3919
|
-
return await strategy.getStopped(symbol
|
|
3957
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
3958
|
+
return await strategy.getStopped(symbol);
|
|
3920
3959
|
};
|
|
3921
3960
|
/**
|
|
3922
3961
|
* Executes live trading tick for current strategy.
|
|
@@ -3925,18 +3964,19 @@ class StrategyConnectionService {
|
|
|
3925
3964
|
* Evaluates current market conditions and returns signal state.
|
|
3926
3965
|
*
|
|
3927
3966
|
* @param symbol - Trading pair symbol
|
|
3928
|
-
* @param
|
|
3967
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
3929
3968
|
* @returns Promise resolving to tick result (idle, opened, active, closed)
|
|
3930
3969
|
*/
|
|
3931
|
-
this.tick = async (symbol,
|
|
3970
|
+
this.tick = async (symbol, context) => {
|
|
3971
|
+
const backtest = this.executionContextService.context.backtest;
|
|
3932
3972
|
this.loggerService.log("strategyConnectionService tick", {
|
|
3933
3973
|
symbol,
|
|
3934
|
-
|
|
3974
|
+
context,
|
|
3975
|
+
backtest,
|
|
3935
3976
|
});
|
|
3936
|
-
const
|
|
3937
|
-
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3977
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
3938
3978
|
await strategy.waitForInit();
|
|
3939
|
-
const tick = await strategy.tick(symbol, strategyName);
|
|
3979
|
+
const tick = await strategy.tick(symbol, context.strategyName);
|
|
3940
3980
|
{
|
|
3941
3981
|
if (this.executionContextService.context.backtest) {
|
|
3942
3982
|
await signalBacktestEmitter.next(tick);
|
|
@@ -3955,24 +3995,28 @@ class StrategyConnectionService {
|
|
|
3955
3995
|
* Evaluates strategy signals against historical data.
|
|
3956
3996
|
*
|
|
3957
3997
|
* @param symbol - Trading pair symbol
|
|
3958
|
-
* @param
|
|
3998
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
3959
3999
|
* @param candles - Array of historical candle data to backtest
|
|
3960
4000
|
* @returns Promise resolving to backtest result (signal or idle)
|
|
3961
4001
|
*/
|
|
3962
|
-
this.backtest = async (symbol,
|
|
4002
|
+
this.backtest = async (symbol, context, candles) => {
|
|
4003
|
+
const backtest = this.executionContextService.context.backtest;
|
|
3963
4004
|
this.loggerService.log("strategyConnectionService backtest", {
|
|
3964
4005
|
symbol,
|
|
3965
|
-
|
|
4006
|
+
context,
|
|
3966
4007
|
candleCount: candles.length,
|
|
4008
|
+
backtest,
|
|
3967
4009
|
});
|
|
3968
|
-
const
|
|
3969
|
-
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
4010
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
3970
4011
|
await strategy.waitForInit();
|
|
3971
|
-
const tick = await strategy.backtest(symbol, strategyName, candles);
|
|
4012
|
+
const tick = await strategy.backtest(symbol, context.strategyName, candles);
|
|
3972
4013
|
{
|
|
3973
4014
|
if (this.executionContextService.context.backtest) {
|
|
3974
4015
|
await signalBacktestEmitter.next(tick);
|
|
3975
4016
|
}
|
|
4017
|
+
if (!this.executionContextService.context.backtest) {
|
|
4018
|
+
await signalLiveEmitter.next(tick);
|
|
4019
|
+
}
|
|
3976
4020
|
await signalEmitter.next(tick);
|
|
3977
4021
|
}
|
|
3978
4022
|
return tick;
|
|
@@ -3983,16 +4027,18 @@ class StrategyConnectionService {
|
|
|
3983
4027
|
* Delegates to ClientStrategy.stop() which sets internal flag to prevent
|
|
3984
4028
|
* getSignal from being called on subsequent ticks.
|
|
3985
4029
|
*
|
|
4030
|
+
* @param backtest - Whether running in backtest mode
|
|
3986
4031
|
* @param symbol - Trading pair symbol
|
|
3987
|
-
* @param
|
|
4032
|
+
* @param ctx - Context with strategyName, exchangeName, frameName
|
|
3988
4033
|
* @returns Promise that resolves when stop flag is set
|
|
3989
4034
|
*/
|
|
3990
|
-
this.stop = async (backtest,
|
|
4035
|
+
this.stop = async (backtest, symbol, context) => {
|
|
3991
4036
|
this.loggerService.log("strategyConnectionService stop", {
|
|
3992
|
-
|
|
4037
|
+
symbol,
|
|
4038
|
+
context,
|
|
3993
4039
|
});
|
|
3994
|
-
const strategy = this.getStrategy(
|
|
3995
|
-
await strategy.stop(
|
|
4040
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
4041
|
+
await strategy.stop(symbol, backtest);
|
|
3996
4042
|
};
|
|
3997
4043
|
/**
|
|
3998
4044
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -4000,14 +4046,14 @@ class StrategyConnectionService {
|
|
|
4000
4046
|
* Forces re-initialization of strategy on next getStrategy call.
|
|
4001
4047
|
* Useful for resetting strategy state or releasing resources.
|
|
4002
4048
|
*
|
|
4003
|
-
* @param
|
|
4049
|
+
* @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
|
|
4004
4050
|
*/
|
|
4005
|
-
this.clear = async (
|
|
4051
|
+
this.clear = async (payload) => {
|
|
4006
4052
|
this.loggerService.log("strategyConnectionService clear", {
|
|
4007
|
-
|
|
4053
|
+
payload,
|
|
4008
4054
|
});
|
|
4009
|
-
if (
|
|
4010
|
-
const key = CREATE_KEY_FN$b(
|
|
4055
|
+
if (payload) {
|
|
4056
|
+
const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
4011
4057
|
this.getStrategy.clear(key);
|
|
4012
4058
|
}
|
|
4013
4059
|
else {
|
|
@@ -4024,17 +4070,19 @@ class StrategyConnectionService {
|
|
|
4024
4070
|
* detects the scheduled signal was cancelled.
|
|
4025
4071
|
*
|
|
4026
4072
|
* @param backtest - Whether running in backtest mode
|
|
4027
|
-
* @param
|
|
4073
|
+
* @param symbol - Trading pair symbol
|
|
4074
|
+
* @param ctx - Context with strategyName, exchangeName, frameName
|
|
4028
4075
|
* @param cancelId - Optional cancellation ID for user-initiated cancellations
|
|
4029
4076
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
4030
4077
|
*/
|
|
4031
|
-
this.cancel = async (backtest,
|
|
4078
|
+
this.cancel = async (backtest, symbol, context, cancelId) => {
|
|
4032
4079
|
this.loggerService.log("strategyConnectionService cancel", {
|
|
4033
|
-
|
|
4080
|
+
symbol,
|
|
4081
|
+
context,
|
|
4034
4082
|
cancelId,
|
|
4035
4083
|
});
|
|
4036
|
-
const strategy = this.getStrategy(
|
|
4037
|
-
await strategy.cancel(
|
|
4084
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
4085
|
+
await strategy.cancel(symbol, backtest, cancelId);
|
|
4038
4086
|
};
|
|
4039
4087
|
}
|
|
4040
4088
|
}
|
|
@@ -4420,7 +4468,7 @@ const get = (object, path) => {
|
|
|
4420
4468
|
/** Symbol indicating that positions need to be fetched from persistence */
|
|
4421
4469
|
const POSITION_NEED_FETCH = Symbol("risk-need-fetch");
|
|
4422
4470
|
/** Key generator for active position map */
|
|
4423
|
-
const
|
|
4471
|
+
const CREATE_NAME_FN = (strategyName, exchangeName, symbol) => `${strategyName}_${exchangeName}_${symbol}`;
|
|
4424
4472
|
/** Wrapper to execute risk validation function with error handling */
|
|
4425
4473
|
const DO_VALIDATION_FN = async (validation, params) => {
|
|
4426
4474
|
try {
|
|
@@ -4580,12 +4628,11 @@ class ClientRisk {
|
|
|
4580
4628
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
4581
4629
|
await this.waitForInit();
|
|
4582
4630
|
}
|
|
4583
|
-
const key =
|
|
4631
|
+
const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
|
|
4584
4632
|
const riskMap = this._activePositions;
|
|
4585
4633
|
riskMap.set(key, {
|
|
4586
|
-
signal: null, // Signal details not needed for position tracking
|
|
4587
4634
|
strategyName: context.strategyName,
|
|
4588
|
-
exchangeName:
|
|
4635
|
+
exchangeName: context.exchangeName,
|
|
4589
4636
|
openTimestamp: Date.now(),
|
|
4590
4637
|
});
|
|
4591
4638
|
await this._updatePositions();
|
|
@@ -4603,7 +4650,7 @@ class ClientRisk {
|
|
|
4603
4650
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
4604
4651
|
await this.waitForInit();
|
|
4605
4652
|
}
|
|
4606
|
-
const key =
|
|
4653
|
+
const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
|
|
4607
4654
|
const riskMap = this._activePositions;
|
|
4608
4655
|
riskMap.delete(key);
|
|
4609
4656
|
await this._updatePositions();
|
|
@@ -4612,12 +4659,20 @@ class ClientRisk {
|
|
|
4612
4659
|
|
|
4613
4660
|
/**
|
|
4614
4661
|
* Creates a unique key for memoizing ClientRisk instances.
|
|
4615
|
-
* Key format: "riskName:backtest" or "riskName:live"
|
|
4662
|
+
* Key format: "riskName:exchangeName:frameName:backtest" or "riskName:exchangeName:live"
|
|
4616
4663
|
* @param riskName - Name of the risk schema
|
|
4664
|
+
* @param exchangeName - Exchange name
|
|
4665
|
+
* @param frameName - Frame name (empty string for live)
|
|
4617
4666
|
* @param backtest - Whether running in backtest mode
|
|
4618
4667
|
* @returns Unique string key for memoization
|
|
4619
4668
|
*/
|
|
4620
|
-
const CREATE_KEY_FN$a = (riskName, backtest) =>
|
|
4669
|
+
const CREATE_KEY_FN$a = (riskName, exchangeName, frameName, backtest) => {
|
|
4670
|
+
const parts = [riskName, exchangeName];
|
|
4671
|
+
if (frameName)
|
|
4672
|
+
parts.push(frameName);
|
|
4673
|
+
parts.push(backtest ? "backtest" : "live");
|
|
4674
|
+
return parts.join(":");
|
|
4675
|
+
};
|
|
4621
4676
|
/**
|
|
4622
4677
|
* Callback function for emitting risk rejection events to riskSubject.
|
|
4623
4678
|
*
|
|
@@ -4630,16 +4685,19 @@ const CREATE_KEY_FN$a = (riskName, backtest) => `${riskName}:${backtest ? "backt
|
|
|
4630
4685
|
* @param rejectionResult - Rejection result with id and note
|
|
4631
4686
|
* @param timestamp - Event timestamp in milliseconds
|
|
4632
4687
|
* @param backtest - True if backtest mode, false if live mode
|
|
4688
|
+
* @param exchangeName - Exchange name
|
|
4689
|
+
* @param frameName - Frame name
|
|
4633
4690
|
*/
|
|
4634
|
-
const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => await riskSubject.next({
|
|
4691
|
+
const COMMIT_REJECTION_FN = async (symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName) => await riskSubject.next({
|
|
4635
4692
|
symbol,
|
|
4636
4693
|
pendingSignal: params.pendingSignal,
|
|
4637
4694
|
strategyName: params.strategyName,
|
|
4638
|
-
exchangeName
|
|
4695
|
+
exchangeName,
|
|
4639
4696
|
currentPrice: params.currentPrice,
|
|
4640
4697
|
activePositionCount,
|
|
4641
4698
|
rejectionId: rejectionResult.id,
|
|
4642
4699
|
rejectionNote: rejectionResult.note,
|
|
4700
|
+
frameName,
|
|
4643
4701
|
timestamp,
|
|
4644
4702
|
backtest,
|
|
4645
4703
|
});
|
|
@@ -4680,22 +4738,24 @@ class RiskConnectionService {
|
|
|
4680
4738
|
this.loggerService = inject(TYPES.loggerService);
|
|
4681
4739
|
this.riskSchemaService = inject(TYPES.riskSchemaService);
|
|
4682
4740
|
/**
|
|
4683
|
-
* Retrieves memoized ClientRisk instance for given risk name and backtest mode.
|
|
4741
|
+
* Retrieves memoized ClientRisk instance for given risk name, exchange, frame and backtest mode.
|
|
4684
4742
|
*
|
|
4685
4743
|
* Creates ClientRisk on first call, returns cached instance on subsequent calls.
|
|
4686
|
-
* Cache key
|
|
4744
|
+
* Cache key includes exchangeName and frameName to isolate risk per exchange+frame.
|
|
4687
4745
|
*
|
|
4688
4746
|
* @param riskName - Name of registered risk schema
|
|
4747
|
+
* @param exchangeName - Exchange name
|
|
4748
|
+
* @param frameName - Frame name (empty string for live)
|
|
4689
4749
|
* @param backtest - True if backtest mode, false if live mode
|
|
4690
4750
|
* @returns Configured ClientRisk instance
|
|
4691
4751
|
*/
|
|
4692
|
-
this.getRisk = functoolsKit.memoize(([riskName, backtest]) => CREATE_KEY_FN$a(riskName, backtest), (riskName, backtest) => {
|
|
4752
|
+
this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
|
|
4693
4753
|
const schema = this.riskSchemaService.get(riskName);
|
|
4694
4754
|
return new ClientRisk({
|
|
4695
4755
|
...schema,
|
|
4696
4756
|
logger: this.loggerService,
|
|
4697
4757
|
backtest,
|
|
4698
|
-
onRejected: COMMIT_REJECTION_FN,
|
|
4758
|
+
onRejected: (symbol, params, activePositionCount, rejectionResult, timestamp, backtest) => COMMIT_REJECTION_FN(symbol, params, activePositionCount, rejectionResult, timestamp, backtest, exchangeName, frameName),
|
|
4699
4759
|
});
|
|
4700
4760
|
});
|
|
4701
4761
|
/**
|
|
@@ -4706,57 +4766,55 @@ class RiskConnectionService {
|
|
|
4706
4766
|
* ClientRisk will emit riskSubject event via onRejected callback when signal is rejected.
|
|
4707
4767
|
*
|
|
4708
4768
|
* @param params - Risk check arguments (portfolio state, position details)
|
|
4709
|
-
* @param
|
|
4769
|
+
* @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
|
|
4710
4770
|
* @returns Promise resolving to risk check result
|
|
4711
4771
|
*/
|
|
4712
|
-
this.checkSignal = async (params,
|
|
4772
|
+
this.checkSignal = async (params, payload) => {
|
|
4713
4773
|
this.loggerService.log("riskConnectionService checkSignal", {
|
|
4714
4774
|
symbol: params.symbol,
|
|
4715
|
-
|
|
4775
|
+
payload,
|
|
4716
4776
|
});
|
|
4717
|
-
return await this.getRisk(
|
|
4777
|
+
return await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).checkSignal(params);
|
|
4718
4778
|
};
|
|
4719
4779
|
/**
|
|
4720
4780
|
* Registers an opened signal with the risk management system.
|
|
4721
4781
|
* Routes to appropriate ClientRisk instance.
|
|
4722
4782
|
*
|
|
4723
4783
|
* @param symbol - Trading pair symbol
|
|
4724
|
-
* @param
|
|
4784
|
+
* @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
|
|
4725
4785
|
*/
|
|
4726
|
-
this.addSignal = async (symbol,
|
|
4786
|
+
this.addSignal = async (symbol, payload) => {
|
|
4727
4787
|
this.loggerService.log("riskConnectionService addSignal", {
|
|
4728
4788
|
symbol,
|
|
4729
|
-
|
|
4789
|
+
payload,
|
|
4730
4790
|
});
|
|
4731
|
-
await this.getRisk(
|
|
4791
|
+
await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).addSignal(symbol, payload);
|
|
4732
4792
|
};
|
|
4733
4793
|
/**
|
|
4734
4794
|
* Removes a closed signal from the risk management system.
|
|
4735
4795
|
* Routes to appropriate ClientRisk instance.
|
|
4736
4796
|
*
|
|
4737
4797
|
* @param symbol - Trading pair symbol
|
|
4738
|
-
* @param
|
|
4798
|
+
* @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
|
|
4739
4799
|
*/
|
|
4740
|
-
this.removeSignal = async (symbol,
|
|
4800
|
+
this.removeSignal = async (symbol, payload) => {
|
|
4741
4801
|
this.loggerService.log("riskConnectionService removeSignal", {
|
|
4742
4802
|
symbol,
|
|
4743
|
-
|
|
4803
|
+
payload,
|
|
4744
4804
|
});
|
|
4745
|
-
await this.getRisk(
|
|
4805
|
+
await this.getRisk(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest).removeSignal(symbol, payload);
|
|
4746
4806
|
};
|
|
4747
4807
|
/**
|
|
4748
4808
|
* Clears the cached ClientRisk instance for the given risk name.
|
|
4749
4809
|
*
|
|
4750
|
-
* @param
|
|
4751
|
-
* @param ctx - Optional context with riskName (clears all if not provided)
|
|
4810
|
+
* @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
|
|
4752
4811
|
*/
|
|
4753
|
-
this.clear = async (
|
|
4812
|
+
this.clear = async (payload) => {
|
|
4754
4813
|
this.loggerService.log("riskConnectionService clear", {
|
|
4755
|
-
|
|
4756
|
-
backtest,
|
|
4814
|
+
payload,
|
|
4757
4815
|
});
|
|
4758
|
-
if (
|
|
4759
|
-
const key = CREATE_KEY_FN$a(
|
|
4816
|
+
if (payload) {
|
|
4817
|
+
const key = CREATE_KEY_FN$a(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
4760
4818
|
this.getRisk.clear(key);
|
|
4761
4819
|
}
|
|
4762
4820
|
else {
|
|
@@ -4955,23 +5013,22 @@ class StrategyCoreService {
|
|
|
4955
5013
|
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
4956
5014
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
4957
5015
|
this.strategyValidationService = inject(TYPES.strategyValidationService);
|
|
4958
|
-
this.methodContextService = inject(TYPES.methodContextService);
|
|
4959
5016
|
/**
|
|
4960
5017
|
* Validates strategy and associated risk configuration.
|
|
4961
5018
|
*
|
|
4962
|
-
* Memoized to avoid redundant validations for the same symbol-strategy
|
|
5019
|
+
* Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
|
|
4963
5020
|
* Logs validation activity.
|
|
4964
5021
|
* @param symbol - Trading pair symbol
|
|
4965
|
-
* @param
|
|
5022
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
4966
5023
|
* @returns Promise that resolves when validation is complete
|
|
4967
5024
|
*/
|
|
4968
|
-
this.validate = functoolsKit.memoize(([symbol,
|
|
5025
|
+
this.validate = functoolsKit.memoize(([symbol, context]) => `${symbol}:${context.strategyName}:${context.exchangeName}:${context.frameName}`, async (symbol, context) => {
|
|
4969
5026
|
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
4970
5027
|
symbol,
|
|
4971
|
-
|
|
5028
|
+
context,
|
|
4972
5029
|
});
|
|
4973
|
-
const { riskName, riskList } = this.strategySchemaService.get(strategyName);
|
|
4974
|
-
this.strategyValidationService.validate(strategyName, METHOD_NAME_VALIDATE);
|
|
5030
|
+
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
5031
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
4975
5032
|
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
4976
5033
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
4977
5034
|
});
|
|
@@ -4980,34 +5037,36 @@ class StrategyCoreService {
|
|
|
4980
5037
|
* If no active signal exists, returns null.
|
|
4981
5038
|
* Used internally for monitoring TP/SL and time expiration.
|
|
4982
5039
|
*
|
|
5040
|
+
* @param backtest - Whether running in backtest mode
|
|
4983
5041
|
* @param symbol - Trading pair symbol
|
|
4984
|
-
* @param
|
|
5042
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
4985
5043
|
* @returns Promise resolving to pending signal or null
|
|
4986
5044
|
*/
|
|
4987
|
-
this.getPendingSignal = async (backtest, symbol,
|
|
5045
|
+
this.getPendingSignal = async (backtest, symbol, context) => {
|
|
4988
5046
|
this.loggerService.log("strategyCoreService getPendingSignal", {
|
|
4989
5047
|
symbol,
|
|
4990
|
-
|
|
5048
|
+
context,
|
|
4991
5049
|
});
|
|
4992
|
-
await this.validate(symbol,
|
|
4993
|
-
return await this.strategyConnectionService.getPendingSignal(backtest, symbol,
|
|
5050
|
+
await this.validate(symbol, context);
|
|
5051
|
+
return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
|
|
4994
5052
|
};
|
|
4995
5053
|
/**
|
|
4996
5054
|
* Retrieves the currently active scheduled signal for the symbol.
|
|
4997
5055
|
* If no scheduled signal exists, returns null.
|
|
4998
5056
|
* Used internally for monitoring scheduled signal activation.
|
|
4999
5057
|
*
|
|
5058
|
+
* @param backtest - Whether running in backtest mode
|
|
5000
5059
|
* @param symbol - Trading pair symbol
|
|
5001
|
-
* @param
|
|
5060
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
5002
5061
|
* @returns Promise resolving to scheduled signal or null
|
|
5003
5062
|
*/
|
|
5004
|
-
this.getScheduledSignal = async (backtest, symbol,
|
|
5063
|
+
this.getScheduledSignal = async (backtest, symbol, context) => {
|
|
5005
5064
|
this.loggerService.log("strategyCoreService getScheduledSignal", {
|
|
5006
5065
|
symbol,
|
|
5007
|
-
|
|
5066
|
+
context,
|
|
5008
5067
|
});
|
|
5009
|
-
await this.validate(symbol,
|
|
5010
|
-
return await this.strategyConnectionService.getScheduledSignal(backtest, symbol,
|
|
5068
|
+
await this.validate(symbol, context);
|
|
5069
|
+
return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
|
|
5011
5070
|
};
|
|
5012
5071
|
/**
|
|
5013
5072
|
* Checks if the strategy has been stopped.
|
|
@@ -5015,18 +5074,19 @@ class StrategyCoreService {
|
|
|
5015
5074
|
* Validates strategy existence and delegates to connection service
|
|
5016
5075
|
* to retrieve the stopped state from the strategy instance.
|
|
5017
5076
|
*
|
|
5077
|
+
* @param backtest - Whether running in backtest mode
|
|
5018
5078
|
* @param symbol - Trading pair symbol
|
|
5019
|
-
* @param
|
|
5079
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
5020
5080
|
* @returns Promise resolving to true if strategy is stopped, false otherwise
|
|
5021
5081
|
*/
|
|
5022
|
-
this.getStopped = async (backtest, symbol,
|
|
5082
|
+
this.getStopped = async (backtest, symbol, context) => {
|
|
5023
5083
|
this.loggerService.log("strategyCoreService getStopped", {
|
|
5024
5084
|
symbol,
|
|
5025
|
-
|
|
5085
|
+
context,
|
|
5026
5086
|
backtest,
|
|
5027
5087
|
});
|
|
5028
|
-
await this.validate(symbol,
|
|
5029
|
-
return await this.strategyConnectionService.getStopped(backtest, symbol,
|
|
5088
|
+
await this.validate(symbol, context);
|
|
5089
|
+
return await this.strategyConnectionService.getStopped(backtest, symbol, context);
|
|
5030
5090
|
};
|
|
5031
5091
|
/**
|
|
5032
5092
|
* Checks signal status at a specific timestamp.
|
|
@@ -5037,21 +5097,19 @@ class StrategyCoreService {
|
|
|
5037
5097
|
* @param symbol - Trading pair symbol
|
|
5038
5098
|
* @param when - Timestamp for tick evaluation
|
|
5039
5099
|
* @param backtest - Whether running in backtest mode
|
|
5100
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
5040
5101
|
* @returns Discriminated union of tick result (idle, opened, active, closed)
|
|
5041
5102
|
*/
|
|
5042
|
-
this.tick = async (symbol, when, backtest) => {
|
|
5103
|
+
this.tick = async (symbol, when, backtest, context) => {
|
|
5043
5104
|
this.loggerService.log("strategyCoreService tick", {
|
|
5044
5105
|
symbol,
|
|
5045
5106
|
when,
|
|
5046
5107
|
backtest,
|
|
5108
|
+
context,
|
|
5047
5109
|
});
|
|
5048
|
-
|
|
5049
|
-
throw new Error("strategyCoreService tick requires a method context");
|
|
5050
|
-
}
|
|
5051
|
-
const strategyName = this.methodContextService.context.strategyName;
|
|
5052
|
-
await this.validate(symbol, strategyName);
|
|
5110
|
+
await this.validate(symbol, context);
|
|
5053
5111
|
return await ExecutionContextService.runInContext(async () => {
|
|
5054
|
-
return await this.strategyConnectionService.tick(symbol,
|
|
5112
|
+
return await this.strategyConnectionService.tick(symbol, context);
|
|
5055
5113
|
}, {
|
|
5056
5114
|
symbol,
|
|
5057
5115
|
when,
|
|
@@ -5068,22 +5126,20 @@ class StrategyCoreService {
|
|
|
5068
5126
|
* @param candles - Array of historical candles to test against
|
|
5069
5127
|
* @param when - Starting timestamp for backtest
|
|
5070
5128
|
* @param backtest - Whether running in backtest mode (typically true)
|
|
5129
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
5071
5130
|
* @returns Closed signal result with PNL
|
|
5072
5131
|
*/
|
|
5073
|
-
this.backtest = async (symbol, candles, when, backtest) => {
|
|
5132
|
+
this.backtest = async (symbol, candles, when, backtest, context) => {
|
|
5074
5133
|
this.loggerService.log("strategyCoreService backtest", {
|
|
5075
5134
|
symbol,
|
|
5076
5135
|
candleCount: candles.length,
|
|
5077
5136
|
when,
|
|
5078
5137
|
backtest,
|
|
5138
|
+
context,
|
|
5079
5139
|
});
|
|
5080
|
-
|
|
5081
|
-
throw new Error("strategyCoreService backtest requires a method context");
|
|
5082
|
-
}
|
|
5083
|
-
const strategyName = this.methodContextService.context.strategyName;
|
|
5084
|
-
await this.validate(symbol, strategyName);
|
|
5140
|
+
await this.validate(symbol, context);
|
|
5085
5141
|
return await ExecutionContextService.runInContext(async () => {
|
|
5086
|
-
return await this.strategyConnectionService.backtest(symbol,
|
|
5142
|
+
return await this.strategyConnectionService.backtest(symbol, context, candles);
|
|
5087
5143
|
}, {
|
|
5088
5144
|
symbol,
|
|
5089
5145
|
when,
|
|
@@ -5096,17 +5152,19 @@ class StrategyCoreService {
|
|
|
5096
5152
|
* Delegates to StrategyConnectionService.stop() to set internal flag.
|
|
5097
5153
|
* Does not require execution context.
|
|
5098
5154
|
*
|
|
5155
|
+
* @param backtest - Whether running in backtest mode
|
|
5099
5156
|
* @param symbol - Trading pair symbol
|
|
5100
|
-
* @param
|
|
5157
|
+
* @param ctx - Context with strategyName, exchangeName, frameName
|
|
5101
5158
|
* @returns Promise that resolves when stop flag is set
|
|
5102
5159
|
*/
|
|
5103
|
-
this.stop = async (backtest,
|
|
5160
|
+
this.stop = async (backtest, symbol, context) => {
|
|
5104
5161
|
this.loggerService.log("strategyCoreService stop", {
|
|
5105
|
-
|
|
5162
|
+
symbol,
|
|
5163
|
+
context,
|
|
5106
5164
|
backtest,
|
|
5107
5165
|
});
|
|
5108
|
-
await this.validate(
|
|
5109
|
-
return await this.strategyConnectionService.stop(backtest,
|
|
5166
|
+
await this.validate(symbol, context);
|
|
5167
|
+
return await this.strategyConnectionService.stop(backtest, symbol, context);
|
|
5110
5168
|
};
|
|
5111
5169
|
/**
|
|
5112
5170
|
* Cancels the scheduled signal without stopping the strategy.
|
|
@@ -5116,18 +5174,20 @@ class StrategyCoreService {
|
|
|
5116
5174
|
* Does not require execution context.
|
|
5117
5175
|
*
|
|
5118
5176
|
* @param backtest - Whether running in backtest mode
|
|
5119
|
-
* @param
|
|
5177
|
+
* @param symbol - Trading pair symbol
|
|
5178
|
+
* @param ctx - Context with strategyName, exchangeName, frameName
|
|
5120
5179
|
* @param cancelId - Optional cancellation ID for user-initiated cancellations
|
|
5121
5180
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
5122
5181
|
*/
|
|
5123
|
-
this.cancel = async (backtest,
|
|
5182
|
+
this.cancel = async (backtest, symbol, context, cancelId) => {
|
|
5124
5183
|
this.loggerService.log("strategyCoreService cancel", {
|
|
5125
|
-
|
|
5184
|
+
symbol,
|
|
5185
|
+
context,
|
|
5126
5186
|
backtest,
|
|
5127
5187
|
cancelId,
|
|
5128
5188
|
});
|
|
5129
|
-
await this.validate(
|
|
5130
|
-
return await this.strategyConnectionService.cancel(backtest,
|
|
5189
|
+
await this.validate(symbol, context);
|
|
5190
|
+
return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
|
|
5131
5191
|
};
|
|
5132
5192
|
/**
|
|
5133
5193
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -5135,16 +5195,20 @@ class StrategyCoreService {
|
|
|
5135
5195
|
* Delegates to StrategyConnectionService.clear() to remove strategy from cache.
|
|
5136
5196
|
* Forces re-initialization of strategy on next operation.
|
|
5137
5197
|
*
|
|
5138
|
-
* @param
|
|
5198
|
+
* @param payload - Optional payload with symbol, context and backtest flag (clears all if not provided)
|
|
5139
5199
|
*/
|
|
5140
|
-
this.clear = async (
|
|
5200
|
+
this.clear = async (payload) => {
|
|
5141
5201
|
this.loggerService.log("strategyCoreService clear", {
|
|
5142
|
-
|
|
5202
|
+
payload,
|
|
5143
5203
|
});
|
|
5144
|
-
if (
|
|
5145
|
-
await this.validate(
|
|
5204
|
+
if (payload) {
|
|
5205
|
+
await this.validate(payload.symbol, {
|
|
5206
|
+
strategyName: payload.strategyName,
|
|
5207
|
+
exchangeName: payload.exchangeName,
|
|
5208
|
+
frameName: payload.frameName
|
|
5209
|
+
});
|
|
5146
5210
|
}
|
|
5147
|
-
return await this.strategyConnectionService.clear(
|
|
5211
|
+
return await this.strategyConnectionService.clear(payload);
|
|
5148
5212
|
};
|
|
5149
5213
|
}
|
|
5150
5214
|
}
|
|
@@ -5225,76 +5289,74 @@ class RiskGlobalService {
|
|
|
5225
5289
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
5226
5290
|
/**
|
|
5227
5291
|
* Validates risk configuration.
|
|
5228
|
-
* Memoized to avoid redundant validations for the same risk
|
|
5292
|
+
* Memoized to avoid redundant validations for the same risk-exchange-frame combination.
|
|
5229
5293
|
* Logs validation activity.
|
|
5230
|
-
* @param
|
|
5294
|
+
* @param payload - Payload with riskName, exchangeName and frameName
|
|
5231
5295
|
* @returns Promise that resolves when validation is complete
|
|
5232
5296
|
*/
|
|
5233
|
-
this.validate = functoolsKit.memoize(([
|
|
5297
|
+
this.validate = functoolsKit.memoize(([payload]) => `${payload.riskName}:${payload.exchangeName}:${payload.frameName}`, async (payload) => {
|
|
5234
5298
|
this.loggerService.log("riskGlobalService validate", {
|
|
5235
|
-
|
|
5299
|
+
payload,
|
|
5236
5300
|
});
|
|
5237
|
-
this.riskValidationService.validate(riskName, "riskGlobalService validate");
|
|
5301
|
+
this.riskValidationService.validate(payload.riskName, "riskGlobalService validate");
|
|
5238
5302
|
});
|
|
5239
5303
|
/**
|
|
5240
5304
|
* Checks if a signal should be allowed based on risk limits.
|
|
5241
5305
|
*
|
|
5242
5306
|
* @param params - Risk check arguments (portfolio state, position details)
|
|
5243
|
-
* @param
|
|
5307
|
+
* @param payload - Execution payload with risk name, exchangeName, frameName and backtest mode
|
|
5244
5308
|
* @returns Promise resolving to risk check result
|
|
5245
5309
|
*/
|
|
5246
|
-
this.checkSignal = async (params,
|
|
5310
|
+
this.checkSignal = async (params, payload) => {
|
|
5247
5311
|
this.loggerService.log("riskGlobalService checkSignal", {
|
|
5248
5312
|
symbol: params.symbol,
|
|
5249
|
-
|
|
5313
|
+
payload,
|
|
5250
5314
|
});
|
|
5251
|
-
await this.validate(
|
|
5252
|
-
return await this.riskConnectionService.checkSignal(params,
|
|
5315
|
+
await this.validate(payload);
|
|
5316
|
+
return await this.riskConnectionService.checkSignal(params, payload);
|
|
5253
5317
|
};
|
|
5254
5318
|
/**
|
|
5255
5319
|
* Registers an opened signal with the risk management system.
|
|
5256
5320
|
*
|
|
5257
5321
|
* @param symbol - Trading pair symbol
|
|
5258
|
-
* @param
|
|
5322
|
+
* @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
|
|
5259
5323
|
*/
|
|
5260
|
-
this.addSignal = async (symbol,
|
|
5324
|
+
this.addSignal = async (symbol, payload) => {
|
|
5261
5325
|
this.loggerService.log("riskGlobalService addSignal", {
|
|
5262
5326
|
symbol,
|
|
5263
|
-
|
|
5327
|
+
payload,
|
|
5264
5328
|
});
|
|
5265
|
-
await this.validate(
|
|
5266
|
-
await this.riskConnectionService.addSignal(symbol,
|
|
5329
|
+
await this.validate(payload);
|
|
5330
|
+
await this.riskConnectionService.addSignal(symbol, payload);
|
|
5267
5331
|
};
|
|
5268
5332
|
/**
|
|
5269
5333
|
* Removes a closed signal from the risk management system.
|
|
5270
5334
|
*
|
|
5271
5335
|
* @param symbol - Trading pair symbol
|
|
5272
|
-
* @param
|
|
5336
|
+
* @param payload - Payload information (strategyName, riskName, exchangeName, frameName, backtest)
|
|
5273
5337
|
*/
|
|
5274
|
-
this.removeSignal = async (symbol,
|
|
5338
|
+
this.removeSignal = async (symbol, payload) => {
|
|
5275
5339
|
this.loggerService.log("riskGlobalService removeSignal", {
|
|
5276
5340
|
symbol,
|
|
5277
|
-
|
|
5341
|
+
payload,
|
|
5278
5342
|
});
|
|
5279
|
-
await this.validate(
|
|
5280
|
-
await this.riskConnectionService.removeSignal(symbol,
|
|
5343
|
+
await this.validate(payload);
|
|
5344
|
+
await this.riskConnectionService.removeSignal(symbol, payload);
|
|
5281
5345
|
};
|
|
5282
5346
|
/**
|
|
5283
5347
|
* Clears risk data.
|
|
5284
|
-
* If
|
|
5285
|
-
* If no
|
|
5286
|
-
* @param
|
|
5287
|
-
* @param ctx - Optional context with riskName (clears all if not provided)
|
|
5348
|
+
* If payload is provided, clears data for that specific risk instance.
|
|
5349
|
+
* If no payload is provided, clears all risk data.
|
|
5350
|
+
* @param payload - Optional payload with riskName, exchangeName, frameName, backtest (clears all if not provided)
|
|
5288
5351
|
*/
|
|
5289
|
-
this.clear = async (
|
|
5352
|
+
this.clear = async (payload) => {
|
|
5290
5353
|
this.loggerService.log("riskGlobalService clear", {
|
|
5291
|
-
|
|
5292
|
-
backtest,
|
|
5354
|
+
payload,
|
|
5293
5355
|
});
|
|
5294
|
-
if (
|
|
5295
|
-
await this.validate(
|
|
5356
|
+
if (payload) {
|
|
5357
|
+
await this.validate(payload);
|
|
5296
5358
|
}
|
|
5297
|
-
return await this.riskConnectionService.clear(
|
|
5359
|
+
return await this.riskConnectionService.clear(payload);
|
|
5298
5360
|
};
|
|
5299
5361
|
}
|
|
5300
5362
|
}
|
|
@@ -5845,7 +5907,11 @@ class BacktestLogicPrivateService {
|
|
|
5845
5907
|
});
|
|
5846
5908
|
}
|
|
5847
5909
|
// Check if strategy should stop before processing next frame
|
|
5848
|
-
if (await this.strategyCoreService.getStopped(true, symbol,
|
|
5910
|
+
if (await this.strategyCoreService.getStopped(true, symbol, {
|
|
5911
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
5912
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
5913
|
+
frameName: this.methodContextService.context.frameName,
|
|
5914
|
+
})) {
|
|
5849
5915
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (before tick)", {
|
|
5850
5916
|
symbol,
|
|
5851
5917
|
when: when.toISOString(),
|
|
@@ -5856,7 +5922,11 @@ class BacktestLogicPrivateService {
|
|
|
5856
5922
|
}
|
|
5857
5923
|
let result;
|
|
5858
5924
|
try {
|
|
5859
|
-
result = await this.strategyCoreService.tick(symbol, when, true
|
|
5925
|
+
result = await this.strategyCoreService.tick(symbol, when, true, {
|
|
5926
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
5927
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
5928
|
+
frameName: this.methodContextService.context.frameName,
|
|
5929
|
+
});
|
|
5860
5930
|
}
|
|
5861
5931
|
catch (error) {
|
|
5862
5932
|
console.warn(`backtestLogicPrivateService tick failed, skipping timeframe when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
@@ -5870,7 +5940,11 @@ class BacktestLogicPrivateService {
|
|
|
5870
5940
|
continue;
|
|
5871
5941
|
}
|
|
5872
5942
|
// Check if strategy should stop when idle (no active signal)
|
|
5873
|
-
if (await functoolsKit.and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol,
|
|
5943
|
+
if (await functoolsKit.and(Promise.resolve(result.action === "idle"), this.strategyCoreService.getStopped(true, symbol, {
|
|
5944
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
5945
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
5946
|
+
frameName: this.methodContextService.context.frameName,
|
|
5947
|
+
}))) {
|
|
5874
5948
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (idle state)", {
|
|
5875
5949
|
symbol,
|
|
5876
5950
|
when: when.toISOString(),
|
|
@@ -5929,7 +6003,11 @@ class BacktestLogicPrivateService {
|
|
|
5929
6003
|
// и если активируется - продолжит с TP/SL мониторингом
|
|
5930
6004
|
let backtestResult;
|
|
5931
6005
|
try {
|
|
5932
|
-
backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true
|
|
6006
|
+
backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
|
|
6007
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
6008
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
6009
|
+
frameName: this.methodContextService.context.frameName,
|
|
6010
|
+
});
|
|
5933
6011
|
}
|
|
5934
6012
|
catch (error) {
|
|
5935
6013
|
console.warn(`backtestLogicPrivateService backtest failed for scheduled signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
@@ -5961,6 +6039,7 @@ class BacktestLogicPrivateService {
|
|
|
5961
6039
|
duration: signalEndTime - signalStartTime,
|
|
5962
6040
|
strategyName: this.methodContextService.context.strategyName,
|
|
5963
6041
|
exchangeName: this.methodContextService.context.exchangeName,
|
|
6042
|
+
frameName: this.methodContextService.context.frameName,
|
|
5964
6043
|
symbol,
|
|
5965
6044
|
backtest: true,
|
|
5966
6045
|
});
|
|
@@ -5972,7 +6051,11 @@ class BacktestLogicPrivateService {
|
|
|
5972
6051
|
}
|
|
5973
6052
|
yield backtestResult;
|
|
5974
6053
|
// Check if strategy should stop after signal is closed
|
|
5975
|
-
if (await this.strategyCoreService.getStopped(true, symbol,
|
|
6054
|
+
if (await this.strategyCoreService.getStopped(true, symbol, {
|
|
6055
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
6056
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
6057
|
+
frameName: this.methodContextService.context.frameName,
|
|
6058
|
+
})) {
|
|
5976
6059
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (after scheduled signal closed)", {
|
|
5977
6060
|
symbol,
|
|
5978
6061
|
signalId: backtestResult.signal.id,
|
|
@@ -6026,7 +6109,11 @@ class BacktestLogicPrivateService {
|
|
|
6026
6109
|
// Вызываем backtest - всегда возвращает closed
|
|
6027
6110
|
let backtestResult;
|
|
6028
6111
|
try {
|
|
6029
|
-
backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true
|
|
6112
|
+
backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
|
|
6113
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
6114
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
6115
|
+
frameName: this.methodContextService.context.frameName,
|
|
6116
|
+
});
|
|
6030
6117
|
}
|
|
6031
6118
|
catch (error) {
|
|
6032
6119
|
console.warn(`backtestLogicPrivateService backtest failed for opened signal when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
@@ -6054,6 +6141,7 @@ class BacktestLogicPrivateService {
|
|
|
6054
6141
|
duration: signalEndTime - signalStartTime,
|
|
6055
6142
|
strategyName: this.methodContextService.context.strategyName,
|
|
6056
6143
|
exchangeName: this.methodContextService.context.exchangeName,
|
|
6144
|
+
frameName: this.methodContextService.context.frameName,
|
|
6057
6145
|
symbol,
|
|
6058
6146
|
backtest: true,
|
|
6059
6147
|
});
|
|
@@ -6065,7 +6153,11 @@ class BacktestLogicPrivateService {
|
|
|
6065
6153
|
}
|
|
6066
6154
|
yield backtestResult;
|
|
6067
6155
|
// Check if strategy should stop after signal is closed
|
|
6068
|
-
if (await this.strategyCoreService.getStopped(true, symbol,
|
|
6156
|
+
if (await this.strategyCoreService.getStopped(true, symbol, {
|
|
6157
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
6158
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
6159
|
+
frameName: this.methodContextService.context.frameName,
|
|
6160
|
+
})) {
|
|
6069
6161
|
this.loggerService.info("backtestLogicPrivateService stopped by user request (after signal closed)", {
|
|
6070
6162
|
symbol,
|
|
6071
6163
|
signalId: backtestResult.signal.id,
|
|
@@ -6085,6 +6177,7 @@ class BacktestLogicPrivateService {
|
|
|
6085
6177
|
duration: timeframeEndTime - timeframeStartTime,
|
|
6086
6178
|
strategyName: this.methodContextService.context.strategyName,
|
|
6087
6179
|
exchangeName: this.methodContextService.context.exchangeName,
|
|
6180
|
+
frameName: this.methodContextService.context.frameName,
|
|
6088
6181
|
symbol,
|
|
6089
6182
|
backtest: true,
|
|
6090
6183
|
});
|
|
@@ -6112,6 +6205,7 @@ class BacktestLogicPrivateService {
|
|
|
6112
6205
|
duration: backtestEndTime - backtestStartTime,
|
|
6113
6206
|
strategyName: this.methodContextService.context.strategyName,
|
|
6114
6207
|
exchangeName: this.methodContextService.context.exchangeName,
|
|
6208
|
+
frameName: this.methodContextService.context.frameName,
|
|
6115
6209
|
symbol,
|
|
6116
6210
|
backtest: true,
|
|
6117
6211
|
});
|
|
@@ -6174,7 +6268,11 @@ class LiveLogicPrivateService {
|
|
|
6174
6268
|
const when = new Date();
|
|
6175
6269
|
let result;
|
|
6176
6270
|
try {
|
|
6177
|
-
result = await this.strategyCoreService.tick(symbol, when, false
|
|
6271
|
+
result = await this.strategyCoreService.tick(symbol, when, false, {
|
|
6272
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
6273
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
6274
|
+
frameName: this.methodContextService.context.frameName,
|
|
6275
|
+
});
|
|
6178
6276
|
}
|
|
6179
6277
|
catch (error) {
|
|
6180
6278
|
console.warn(`backtestLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
@@ -6202,13 +6300,18 @@ class LiveLogicPrivateService {
|
|
|
6202
6300
|
duration: tickEndTime - tickStartTime,
|
|
6203
6301
|
strategyName: this.methodContextService.context.strategyName,
|
|
6204
6302
|
exchangeName: this.methodContextService.context.exchangeName,
|
|
6303
|
+
frameName: this.methodContextService.context.frameName,
|
|
6205
6304
|
symbol,
|
|
6206
6305
|
backtest: false,
|
|
6207
6306
|
});
|
|
6208
6307
|
previousEventTimestamp = currentTimestamp;
|
|
6209
6308
|
// Check if strategy should stop when idle (no active signal)
|
|
6210
6309
|
if (result.action === "idle") {
|
|
6211
|
-
if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol,
|
|
6310
|
+
if (await functoolsKit.and(Promise.resolve(true), this.strategyCoreService.getStopped(false, symbol, {
|
|
6311
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
6312
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
6313
|
+
frameName: this.methodContextService.context.frameName,
|
|
6314
|
+
}))) {
|
|
6212
6315
|
this.loggerService.info("liveLogicPrivateService stopped by user request (idle state)", {
|
|
6213
6316
|
symbol,
|
|
6214
6317
|
when: when.toISOString(),
|
|
@@ -6230,7 +6333,11 @@ class LiveLogicPrivateService {
|
|
|
6230
6333
|
yield result;
|
|
6231
6334
|
// Check if strategy should stop after signal is closed
|
|
6232
6335
|
if (result.action === "closed") {
|
|
6233
|
-
if (await this.strategyCoreService.getStopped(false, symbol,
|
|
6336
|
+
if (await this.strategyCoreService.getStopped(false, symbol, {
|
|
6337
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
6338
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
6339
|
+
frameName: this.methodContextService.context.frameName,
|
|
6340
|
+
})) {
|
|
6234
6341
|
this.loggerService.info("liveLogicPrivateService stopped by user request (after signal closed)", {
|
|
6235
6342
|
symbol,
|
|
6236
6343
|
signalId: result.signal.id,
|
|
@@ -6362,7 +6469,7 @@ class WalkerLogicPrivateService {
|
|
|
6362
6469
|
symbol,
|
|
6363
6470
|
});
|
|
6364
6471
|
// Get statistics from BacktestMarkdownService
|
|
6365
|
-
const stats = await this.backtestMarkdownService.getData(symbol, strategyName, true);
|
|
6472
|
+
const stats = await this.backtestMarkdownService.getData(symbol, strategyName, context.exchangeName, context.frameName, true);
|
|
6366
6473
|
// Extract metric value
|
|
6367
6474
|
const value = stats[metric];
|
|
6368
6475
|
const metricValue = value !== null &&
|
|
@@ -6426,7 +6533,7 @@ class WalkerLogicPrivateService {
|
|
|
6426
6533
|
bestStrategy,
|
|
6427
6534
|
bestMetric,
|
|
6428
6535
|
bestStats: bestStrategy !== null
|
|
6429
|
-
? await this.backtestMarkdownService.getData(symbol, bestStrategy, true)
|
|
6536
|
+
? await this.backtestMarkdownService.getData(symbol, bestStrategy, context.exchangeName, context.frameName, true)
|
|
6430
6537
|
: null,
|
|
6431
6538
|
};
|
|
6432
6539
|
// Call onComplete callback if provided with final best results
|
|
@@ -7789,13 +7896,21 @@ const DEFAULT_COLUMNS = Object.freeze({ ...COLUMN_CONFIG });
|
|
|
7789
7896
|
|
|
7790
7897
|
/**
|
|
7791
7898
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
7792
|
-
* Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
|
|
7899
|
+
* Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
|
|
7793
7900
|
* @param symbol - Trading pair symbol
|
|
7794
7901
|
* @param strategyName - Name of the strategy
|
|
7902
|
+
* @param exchangeName - Exchange name
|
|
7903
|
+
* @param frameName - Frame name
|
|
7795
7904
|
* @param backtest - Whether running in backtest mode
|
|
7796
7905
|
* @returns Unique string key for memoization
|
|
7797
7906
|
*/
|
|
7798
|
-
const CREATE_KEY_FN$9 = (symbol, strategyName, backtest) =>
|
|
7907
|
+
const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
7908
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
7909
|
+
if (frameName)
|
|
7910
|
+
parts.push(frameName);
|
|
7911
|
+
parts.push(backtest ? "backtest" : "live");
|
|
7912
|
+
return parts.join(":");
|
|
7913
|
+
};
|
|
7799
7914
|
/**
|
|
7800
7915
|
* Checks if a value is unsafe for display (not a number, NaN, or Infinity).
|
|
7801
7916
|
*
|
|
@@ -8001,17 +8116,17 @@ class BacktestMarkdownService {
|
|
|
8001
8116
|
/** Logger service for debug output */
|
|
8002
8117
|
this.loggerService = inject(TYPES.loggerService);
|
|
8003
8118
|
/**
|
|
8004
|
-
* Memoized function to get or create ReportStorage for a symbol-strategy-backtest
|
|
8005
|
-
* Each
|
|
8119
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
8120
|
+
* Each combination gets its own isolated storage instance.
|
|
8006
8121
|
*/
|
|
8007
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, backtest), () => new ReportStorage$5());
|
|
8122
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$5());
|
|
8008
8123
|
/**
|
|
8009
8124
|
* Processes tick events and accumulates closed signals.
|
|
8010
8125
|
* Should be called from IStrategyCallbacks.onTick.
|
|
8011
8126
|
*
|
|
8012
8127
|
* Only processes closed signals - opened signals are ignored.
|
|
8013
8128
|
*
|
|
8014
|
-
* @param data - Tick result from strategy execution (opened or closed)
|
|
8129
|
+
* @param data - Tick result from strategy execution (opened or closed) with frameName wrapper
|
|
8015
8130
|
*
|
|
8016
8131
|
* @example
|
|
8017
8132
|
* ```typescript
|
|
@@ -8031,7 +8146,7 @@ class BacktestMarkdownService {
|
|
|
8031
8146
|
if (data.action !== "closed") {
|
|
8032
8147
|
return;
|
|
8033
8148
|
}
|
|
8034
|
-
const storage = this.getStorage(data.symbol, data.strategyName, true);
|
|
8149
|
+
const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, true);
|
|
8035
8150
|
storage.addSignal(data);
|
|
8036
8151
|
};
|
|
8037
8152
|
/**
|
|
@@ -8040,23 +8155,27 @@ class BacktestMarkdownService {
|
|
|
8040
8155
|
*
|
|
8041
8156
|
* @param symbol - Trading pair symbol
|
|
8042
8157
|
* @param strategyName - Strategy name to get data for
|
|
8158
|
+
* @param exchangeName - Exchange name
|
|
8159
|
+
* @param frameName - Frame name
|
|
8043
8160
|
* @param backtest - True if backtest mode, false if live mode
|
|
8044
8161
|
* @returns Statistical data object with all metrics
|
|
8045
8162
|
*
|
|
8046
8163
|
* @example
|
|
8047
8164
|
* ```typescript
|
|
8048
8165
|
* const service = new BacktestMarkdownService();
|
|
8049
|
-
* const stats = await service.getData("BTCUSDT", "my-strategy", true);
|
|
8166
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", true);
|
|
8050
8167
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
8051
8168
|
* ```
|
|
8052
8169
|
*/
|
|
8053
|
-
this.getData = async (symbol, strategyName, backtest) => {
|
|
8170
|
+
this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
8054
8171
|
this.loggerService.log("backtestMarkdownService getData", {
|
|
8055
8172
|
symbol,
|
|
8056
8173
|
strategyName,
|
|
8174
|
+
exchangeName,
|
|
8175
|
+
frameName,
|
|
8057
8176
|
backtest,
|
|
8058
8177
|
});
|
|
8059
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
8178
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
8060
8179
|
return storage.getData();
|
|
8061
8180
|
};
|
|
8062
8181
|
/**
|
|
@@ -8065,6 +8184,8 @@ class BacktestMarkdownService {
|
|
|
8065
8184
|
*
|
|
8066
8185
|
* @param symbol - Trading pair symbol
|
|
8067
8186
|
* @param strategyName - Strategy name to generate report for
|
|
8187
|
+
* @param exchangeName - Exchange name
|
|
8188
|
+
* @param frameName - Frame name
|
|
8068
8189
|
* @param backtest - True if backtest mode, false if live mode
|
|
8069
8190
|
* @param columns - Column configuration for formatting the table
|
|
8070
8191
|
* @returns Markdown formatted report string with table of all closed signals
|
|
@@ -8072,17 +8193,19 @@ class BacktestMarkdownService {
|
|
|
8072
8193
|
* @example
|
|
8073
8194
|
* ```typescript
|
|
8074
8195
|
* const service = new BacktestMarkdownService();
|
|
8075
|
-
* const markdown = await service.getReport("BTCUSDT", "my-strategy", true);
|
|
8196
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", true);
|
|
8076
8197
|
* console.log(markdown);
|
|
8077
8198
|
* ```
|
|
8078
8199
|
*/
|
|
8079
|
-
this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
|
|
8200
|
+
this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.backtest_columns) => {
|
|
8080
8201
|
this.loggerService.log("backtestMarkdownService getReport", {
|
|
8081
8202
|
symbol,
|
|
8082
8203
|
strategyName,
|
|
8204
|
+
exchangeName,
|
|
8205
|
+
frameName,
|
|
8083
8206
|
backtest,
|
|
8084
8207
|
});
|
|
8085
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
8208
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
8086
8209
|
return storage.getReport(strategyName, columns);
|
|
8087
8210
|
};
|
|
8088
8211
|
/**
|
|
@@ -8092,6 +8215,8 @@ class BacktestMarkdownService {
|
|
|
8092
8215
|
*
|
|
8093
8216
|
* @param symbol - Trading pair symbol
|
|
8094
8217
|
* @param strategyName - Strategy name to save report for
|
|
8218
|
+
* @param exchangeName - Exchange name
|
|
8219
|
+
* @param frameName - Frame name
|
|
8095
8220
|
* @param backtest - True if backtest mode, false if live mode
|
|
8096
8221
|
* @param path - Directory path to save report (default: "./dump/backtest")
|
|
8097
8222
|
* @param columns - Column configuration for formatting the table
|
|
@@ -8101,48 +8226,48 @@ class BacktestMarkdownService {
|
|
|
8101
8226
|
* const service = new BacktestMarkdownService();
|
|
8102
8227
|
*
|
|
8103
8228
|
* // Save to default path: ./dump/backtest/my-strategy.md
|
|
8104
|
-
* await service.dump("BTCUSDT", "my-strategy", true);
|
|
8229
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true);
|
|
8105
8230
|
*
|
|
8106
8231
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
8107
|
-
* await service.dump("BTCUSDT", "my-strategy", true, "./custom/path");
|
|
8232
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", true, "./custom/path");
|
|
8108
8233
|
* ```
|
|
8109
8234
|
*/
|
|
8110
|
-
this.dump = async (symbol, strategyName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
|
|
8235
|
+
this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/backtest", columns = COLUMN_CONFIG.backtest_columns) => {
|
|
8111
8236
|
this.loggerService.log("backtestMarkdownService dump", {
|
|
8112
8237
|
symbol,
|
|
8113
8238
|
strategyName,
|
|
8239
|
+
exchangeName,
|
|
8240
|
+
frameName,
|
|
8114
8241
|
backtest,
|
|
8115
8242
|
path,
|
|
8116
8243
|
});
|
|
8117
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
8244
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
8118
8245
|
await storage.dump(strategyName, path, columns);
|
|
8119
8246
|
};
|
|
8120
8247
|
/**
|
|
8121
8248
|
* Clears accumulated signal data from storage.
|
|
8122
|
-
* If
|
|
8249
|
+
* If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
|
|
8123
8250
|
* If nothing is provided, clears all data.
|
|
8124
8251
|
*
|
|
8125
|
-
* @param
|
|
8126
|
-
* @param ctx - Optional context with symbol and strategyName
|
|
8252
|
+
* @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
|
|
8127
8253
|
*
|
|
8128
8254
|
* @example
|
|
8129
8255
|
* ```typescript
|
|
8130
8256
|
* const service = new BacktestMarkdownService();
|
|
8131
8257
|
*
|
|
8132
|
-
* // Clear specific
|
|
8133
|
-
* await service.clear(
|
|
8258
|
+
* // Clear specific combination
|
|
8259
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: true });
|
|
8134
8260
|
*
|
|
8135
8261
|
* // Clear all data
|
|
8136
8262
|
* await service.clear();
|
|
8137
8263
|
* ```
|
|
8138
8264
|
*/
|
|
8139
|
-
this.clear = async (
|
|
8265
|
+
this.clear = async (payload) => {
|
|
8140
8266
|
this.loggerService.log("backtestMarkdownService clear", {
|
|
8141
|
-
|
|
8142
|
-
ctx,
|
|
8267
|
+
payload,
|
|
8143
8268
|
});
|
|
8144
|
-
if (
|
|
8145
|
-
const key = CREATE_KEY_FN$9(
|
|
8269
|
+
if (payload) {
|
|
8270
|
+
const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
8146
8271
|
this.getStorage.clear(key);
|
|
8147
8272
|
}
|
|
8148
8273
|
else {
|
|
@@ -8169,13 +8294,21 @@ class BacktestMarkdownService {
|
|
|
8169
8294
|
|
|
8170
8295
|
/**
|
|
8171
8296
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
8172
|
-
* Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
|
|
8297
|
+
* Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
|
|
8173
8298
|
* @param symbol - Trading pair symbol
|
|
8174
8299
|
* @param strategyName - Name of the strategy
|
|
8300
|
+
* @param exchangeName - Exchange name
|
|
8301
|
+
* @param frameName - Frame name
|
|
8175
8302
|
* @param backtest - Whether running in backtest mode
|
|
8176
8303
|
* @returns Unique string key for memoization
|
|
8177
8304
|
*/
|
|
8178
|
-
const CREATE_KEY_FN$8 = (symbol, strategyName, backtest) =>
|
|
8305
|
+
const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
8306
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
8307
|
+
if (frameName)
|
|
8308
|
+
parts.push(frameName);
|
|
8309
|
+
parts.push(backtest ? "backtest" : "live");
|
|
8310
|
+
return parts.join(":");
|
|
8311
|
+
};
|
|
8179
8312
|
/**
|
|
8180
8313
|
* Checks if a value is unsafe for display (not a number, NaN, or Infinity).
|
|
8181
8314
|
*
|
|
@@ -8502,17 +8635,17 @@ class LiveMarkdownService {
|
|
|
8502
8635
|
/** Logger service for debug output */
|
|
8503
8636
|
this.loggerService = inject(TYPES.loggerService);
|
|
8504
8637
|
/**
|
|
8505
|
-
* Memoized function to get or create ReportStorage for a symbol-strategy-backtest
|
|
8506
|
-
* Each
|
|
8638
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
8639
|
+
* Each combination gets its own isolated storage instance.
|
|
8507
8640
|
*/
|
|
8508
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, backtest), () => new ReportStorage$4());
|
|
8641
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$4());
|
|
8509
8642
|
/**
|
|
8510
8643
|
* Processes tick events and accumulates all event types.
|
|
8511
8644
|
* Should be called from IStrategyCallbacks.onTick.
|
|
8512
8645
|
*
|
|
8513
8646
|
* Processes all event types: idle, opened, active, closed.
|
|
8514
8647
|
*
|
|
8515
|
-
* @param data - Tick result from strategy execution
|
|
8648
|
+
* @param data - Tick result from strategy execution with frameName wrapper
|
|
8516
8649
|
*
|
|
8517
8650
|
* @example
|
|
8518
8651
|
* ```typescript
|
|
@@ -8531,7 +8664,7 @@ class LiveMarkdownService {
|
|
|
8531
8664
|
this.loggerService.log("liveMarkdownService tick", {
|
|
8532
8665
|
data,
|
|
8533
8666
|
});
|
|
8534
|
-
const storage = this.getStorage(data.symbol, data.strategyName, false);
|
|
8667
|
+
const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, false);
|
|
8535
8668
|
if (data.action === "idle") {
|
|
8536
8669
|
storage.addIdleEvent(data.currentPrice);
|
|
8537
8670
|
}
|
|
@@ -8551,23 +8684,27 @@ class LiveMarkdownService {
|
|
|
8551
8684
|
*
|
|
8552
8685
|
* @param symbol - Trading pair symbol
|
|
8553
8686
|
* @param strategyName - Strategy name to get data for
|
|
8687
|
+
* @param exchangeName - Exchange name
|
|
8688
|
+
* @param frameName - Frame name
|
|
8554
8689
|
* @param backtest - True if backtest mode, false if live mode
|
|
8555
8690
|
* @returns Statistical data object with all metrics
|
|
8556
8691
|
*
|
|
8557
8692
|
* @example
|
|
8558
8693
|
* ```typescript
|
|
8559
8694
|
* const service = new LiveMarkdownService();
|
|
8560
|
-
* const stats = await service.getData("BTCUSDT", "my-strategy", false);
|
|
8695
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
8561
8696
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
8562
8697
|
* ```
|
|
8563
8698
|
*/
|
|
8564
|
-
this.getData = async (symbol, strategyName, backtest) => {
|
|
8699
|
+
this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
8565
8700
|
this.loggerService.log("liveMarkdownService getData", {
|
|
8566
8701
|
symbol,
|
|
8567
8702
|
strategyName,
|
|
8703
|
+
exchangeName,
|
|
8704
|
+
frameName,
|
|
8568
8705
|
backtest,
|
|
8569
8706
|
});
|
|
8570
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
8707
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
8571
8708
|
return storage.getData();
|
|
8572
8709
|
};
|
|
8573
8710
|
/**
|
|
@@ -8576,6 +8713,8 @@ class LiveMarkdownService {
|
|
|
8576
8713
|
*
|
|
8577
8714
|
* @param symbol - Trading pair symbol
|
|
8578
8715
|
* @param strategyName - Strategy name to generate report for
|
|
8716
|
+
* @param exchangeName - Exchange name
|
|
8717
|
+
* @param frameName - Frame name
|
|
8579
8718
|
* @param backtest - True if backtest mode, false if live mode
|
|
8580
8719
|
* @param columns - Column configuration for formatting the table
|
|
8581
8720
|
* @returns Markdown formatted report string with table of all events
|
|
@@ -8583,17 +8722,19 @@ class LiveMarkdownService {
|
|
|
8583
8722
|
* @example
|
|
8584
8723
|
* ```typescript
|
|
8585
8724
|
* const service = new LiveMarkdownService();
|
|
8586
|
-
* const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
|
|
8725
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
8587
8726
|
* console.log(markdown);
|
|
8588
8727
|
* ```
|
|
8589
8728
|
*/
|
|
8590
|
-
this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.live_columns) => {
|
|
8729
|
+
this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.live_columns) => {
|
|
8591
8730
|
this.loggerService.log("liveMarkdownService getReport", {
|
|
8592
8731
|
symbol,
|
|
8593
8732
|
strategyName,
|
|
8733
|
+
exchangeName,
|
|
8734
|
+
frameName,
|
|
8594
8735
|
backtest,
|
|
8595
8736
|
});
|
|
8596
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
8737
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
8597
8738
|
return storage.getReport(strategyName, columns);
|
|
8598
8739
|
};
|
|
8599
8740
|
/**
|
|
@@ -8603,6 +8744,8 @@ class LiveMarkdownService {
|
|
|
8603
8744
|
*
|
|
8604
8745
|
* @param symbol - Trading pair symbol
|
|
8605
8746
|
* @param strategyName - Strategy name to save report for
|
|
8747
|
+
* @param exchangeName - Exchange name
|
|
8748
|
+
* @param frameName - Frame name
|
|
8606
8749
|
* @param backtest - True if backtest mode, false if live mode
|
|
8607
8750
|
* @param path - Directory path to save report (default: "./dump/live")
|
|
8608
8751
|
* @param columns - Column configuration for formatting the table
|
|
@@ -8612,48 +8755,48 @@ class LiveMarkdownService {
|
|
|
8612
8755
|
* const service = new LiveMarkdownService();
|
|
8613
8756
|
*
|
|
8614
8757
|
* // Save to default path: ./dump/live/my-strategy.md
|
|
8615
|
-
* await service.dump("BTCUSDT", "my-strategy", false);
|
|
8758
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
8616
8759
|
*
|
|
8617
8760
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
8618
|
-
* await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
|
|
8761
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
|
|
8619
8762
|
* ```
|
|
8620
8763
|
*/
|
|
8621
|
-
this.dump = async (symbol, strategyName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
|
|
8764
|
+
this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/live", columns = COLUMN_CONFIG.live_columns) => {
|
|
8622
8765
|
this.loggerService.log("liveMarkdownService dump", {
|
|
8623
8766
|
symbol,
|
|
8624
8767
|
strategyName,
|
|
8768
|
+
exchangeName,
|
|
8769
|
+
frameName,
|
|
8625
8770
|
backtest,
|
|
8626
8771
|
path,
|
|
8627
8772
|
});
|
|
8628
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
8773
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
8629
8774
|
await storage.dump(strategyName, path, columns);
|
|
8630
8775
|
};
|
|
8631
8776
|
/**
|
|
8632
8777
|
* Clears accumulated event data from storage.
|
|
8633
|
-
* If
|
|
8778
|
+
* If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
|
|
8634
8779
|
* If nothing is provided, clears all data.
|
|
8635
8780
|
*
|
|
8636
|
-
* @param
|
|
8637
|
-
* @param ctx - Optional context with symbol and strategyName
|
|
8781
|
+
* @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
|
|
8638
8782
|
*
|
|
8639
8783
|
* @example
|
|
8640
8784
|
* ```typescript
|
|
8641
8785
|
* const service = new LiveMarkdownService();
|
|
8642
8786
|
*
|
|
8643
|
-
* // Clear specific
|
|
8644
|
-
* await service.clear(
|
|
8787
|
+
* // Clear specific combination
|
|
8788
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
|
|
8645
8789
|
*
|
|
8646
8790
|
* // Clear all data
|
|
8647
8791
|
* await service.clear();
|
|
8648
8792
|
* ```
|
|
8649
8793
|
*/
|
|
8650
|
-
this.clear = async (
|
|
8794
|
+
this.clear = async (payload) => {
|
|
8651
8795
|
this.loggerService.log("liveMarkdownService clear", {
|
|
8652
|
-
|
|
8653
|
-
ctx,
|
|
8796
|
+
payload,
|
|
8654
8797
|
});
|
|
8655
|
-
if (
|
|
8656
|
-
const key = CREATE_KEY_FN$8(
|
|
8798
|
+
if (payload) {
|
|
8799
|
+
const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
8657
8800
|
this.getStorage.clear(key);
|
|
8658
8801
|
}
|
|
8659
8802
|
else {
|
|
@@ -8680,13 +8823,21 @@ class LiveMarkdownService {
|
|
|
8680
8823
|
|
|
8681
8824
|
/**
|
|
8682
8825
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
8683
|
-
* Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
|
|
8826
|
+
* Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
|
|
8684
8827
|
* @param symbol - Trading pair symbol
|
|
8685
8828
|
* @param strategyName - Name of the strategy
|
|
8829
|
+
* @param exchangeName - Exchange name
|
|
8830
|
+
* @param frameName - Frame name
|
|
8686
8831
|
* @param backtest - Whether running in backtest mode
|
|
8687
8832
|
* @returns Unique string key for memoization
|
|
8688
8833
|
*/
|
|
8689
|
-
const CREATE_KEY_FN$7 = (symbol, strategyName, backtest) =>
|
|
8834
|
+
const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
8835
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
8836
|
+
if (frameName)
|
|
8837
|
+
parts.push(frameName);
|
|
8838
|
+
parts.push(backtest ? "backtest" : "live");
|
|
8839
|
+
return parts.join(":");
|
|
8840
|
+
};
|
|
8690
8841
|
/** Maximum number of events to store in schedule reports */
|
|
8691
8842
|
const MAX_EVENTS$4 = 250;
|
|
8692
8843
|
/**
|
|
@@ -8919,17 +9070,17 @@ class ScheduleMarkdownService {
|
|
|
8919
9070
|
/** Logger service for debug output */
|
|
8920
9071
|
this.loggerService = inject(TYPES.loggerService);
|
|
8921
9072
|
/**
|
|
8922
|
-
* Memoized function to get or create ReportStorage for a symbol-strategy-backtest
|
|
8923
|
-
* Each
|
|
9073
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
9074
|
+
* Each combination gets its own isolated storage instance.
|
|
8924
9075
|
*/
|
|
8925
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, backtest), () => new ReportStorage$3());
|
|
9076
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$3());
|
|
8926
9077
|
/**
|
|
8927
9078
|
* Processes tick events and accumulates scheduled/opened/cancelled events.
|
|
8928
9079
|
* Should be called from signalEmitter subscription.
|
|
8929
9080
|
*
|
|
8930
9081
|
* Processes only scheduled, opened and cancelled event types.
|
|
8931
9082
|
*
|
|
8932
|
-
* @param data - Tick result from strategy execution
|
|
9083
|
+
* @param data - Tick result from strategy execution with frameName wrapper
|
|
8933
9084
|
*
|
|
8934
9085
|
* @example
|
|
8935
9086
|
* ```typescript
|
|
@@ -8941,7 +9092,7 @@ class ScheduleMarkdownService {
|
|
|
8941
9092
|
this.loggerService.log("scheduleMarkdownService tick", {
|
|
8942
9093
|
data,
|
|
8943
9094
|
});
|
|
8944
|
-
const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
|
|
9095
|
+
const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
|
|
8945
9096
|
if (data.action === "scheduled") {
|
|
8946
9097
|
storage.addScheduledEvent(data);
|
|
8947
9098
|
}
|
|
@@ -8962,23 +9113,27 @@ class ScheduleMarkdownService {
|
|
|
8962
9113
|
*
|
|
8963
9114
|
* @param symbol - Trading pair symbol
|
|
8964
9115
|
* @param strategyName - Strategy name to get data for
|
|
9116
|
+
* @param exchangeName - Exchange name
|
|
9117
|
+
* @param frameName - Frame name
|
|
8965
9118
|
* @param backtest - True if backtest mode, false if live mode
|
|
8966
9119
|
* @returns Statistical data object with all metrics
|
|
8967
9120
|
*
|
|
8968
9121
|
* @example
|
|
8969
9122
|
* ```typescript
|
|
8970
9123
|
* const service = new ScheduleMarkdownService();
|
|
8971
|
-
* const stats = await service.getData("BTCUSDT", "my-strategy", false);
|
|
9124
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
8972
9125
|
* console.log(stats.cancellationRate, stats.avgWaitTime);
|
|
8973
9126
|
* ```
|
|
8974
9127
|
*/
|
|
8975
|
-
this.getData = async (symbol, strategyName, backtest) => {
|
|
9128
|
+
this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
8976
9129
|
this.loggerService.log("scheduleMarkdownService getData", {
|
|
8977
9130
|
symbol,
|
|
8978
9131
|
strategyName,
|
|
9132
|
+
exchangeName,
|
|
9133
|
+
frameName,
|
|
8979
9134
|
backtest,
|
|
8980
9135
|
});
|
|
8981
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
9136
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
8982
9137
|
return storage.getData();
|
|
8983
9138
|
};
|
|
8984
9139
|
/**
|
|
@@ -8987,6 +9142,8 @@ class ScheduleMarkdownService {
|
|
|
8987
9142
|
*
|
|
8988
9143
|
* @param symbol - Trading pair symbol
|
|
8989
9144
|
* @param strategyName - Strategy name to generate report for
|
|
9145
|
+
* @param exchangeName - Exchange name
|
|
9146
|
+
* @param frameName - Frame name
|
|
8990
9147
|
* @param backtest - True if backtest mode, false if live mode
|
|
8991
9148
|
* @param columns - Column configuration for formatting the table
|
|
8992
9149
|
* @returns Markdown formatted report string with table of all events
|
|
@@ -8994,17 +9151,19 @@ class ScheduleMarkdownService {
|
|
|
8994
9151
|
* @example
|
|
8995
9152
|
* ```typescript
|
|
8996
9153
|
* const service = new ScheduleMarkdownService();
|
|
8997
|
-
* const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
|
|
9154
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
8998
9155
|
* console.log(markdown);
|
|
8999
9156
|
* ```
|
|
9000
9157
|
*/
|
|
9001
|
-
this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
|
|
9158
|
+
this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.schedule_columns) => {
|
|
9002
9159
|
this.loggerService.log("scheduleMarkdownService getReport", {
|
|
9003
9160
|
symbol,
|
|
9004
9161
|
strategyName,
|
|
9162
|
+
exchangeName,
|
|
9163
|
+
frameName,
|
|
9005
9164
|
backtest,
|
|
9006
9165
|
});
|
|
9007
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
9166
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
9008
9167
|
return storage.getReport(strategyName, columns);
|
|
9009
9168
|
};
|
|
9010
9169
|
/**
|
|
@@ -9014,6 +9173,8 @@ class ScheduleMarkdownService {
|
|
|
9014
9173
|
*
|
|
9015
9174
|
* @param symbol - Trading pair symbol
|
|
9016
9175
|
* @param strategyName - Strategy name to save report for
|
|
9176
|
+
* @param exchangeName - Exchange name
|
|
9177
|
+
* @param frameName - Frame name
|
|
9017
9178
|
* @param backtest - True if backtest mode, false if live mode
|
|
9018
9179
|
* @param path - Directory path to save report (default: "./dump/schedule")
|
|
9019
9180
|
* @param columns - Column configuration for formatting the table
|
|
@@ -9023,48 +9184,48 @@ class ScheduleMarkdownService {
|
|
|
9023
9184
|
* const service = new ScheduleMarkdownService();
|
|
9024
9185
|
*
|
|
9025
9186
|
* // Save to default path: ./dump/schedule/my-strategy.md
|
|
9026
|
-
* await service.dump("BTCUSDT", "my-strategy", false);
|
|
9187
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
9027
9188
|
*
|
|
9028
9189
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
9029
|
-
* await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
|
|
9190
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
|
|
9030
9191
|
* ```
|
|
9031
9192
|
*/
|
|
9032
|
-
this.dump = async (symbol, strategyName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
|
|
9193
|
+
this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/schedule", columns = COLUMN_CONFIG.schedule_columns) => {
|
|
9033
9194
|
this.loggerService.log("scheduleMarkdownService dump", {
|
|
9034
9195
|
symbol,
|
|
9035
9196
|
strategyName,
|
|
9197
|
+
exchangeName,
|
|
9198
|
+
frameName,
|
|
9036
9199
|
backtest,
|
|
9037
9200
|
path,
|
|
9038
9201
|
});
|
|
9039
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
9202
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
9040
9203
|
await storage.dump(strategyName, path, columns);
|
|
9041
9204
|
};
|
|
9042
9205
|
/**
|
|
9043
9206
|
* Clears accumulated event data from storage.
|
|
9044
|
-
* If
|
|
9207
|
+
* If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
|
|
9045
9208
|
* If nothing is provided, clears all data.
|
|
9046
9209
|
*
|
|
9047
|
-
* @param
|
|
9048
|
-
* @param ctx - Optional context with symbol and strategyName
|
|
9210
|
+
* @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
|
|
9049
9211
|
*
|
|
9050
9212
|
* @example
|
|
9051
9213
|
* ```typescript
|
|
9052
9214
|
* const service = new ScheduleMarkdownService();
|
|
9053
9215
|
*
|
|
9054
|
-
* // Clear specific
|
|
9055
|
-
* await service.clear(
|
|
9216
|
+
* // Clear specific combination
|
|
9217
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
|
|
9056
9218
|
*
|
|
9057
9219
|
* // Clear all data
|
|
9058
9220
|
* await service.clear();
|
|
9059
9221
|
* ```
|
|
9060
9222
|
*/
|
|
9061
|
-
this.clear = async (
|
|
9223
|
+
this.clear = async (payload) => {
|
|
9062
9224
|
this.loggerService.log("scheduleMarkdownService clear", {
|
|
9063
|
-
|
|
9064
|
-
ctx,
|
|
9225
|
+
payload,
|
|
9065
9226
|
});
|
|
9066
|
-
if (
|
|
9067
|
-
const key = CREATE_KEY_FN$7(
|
|
9227
|
+
if (payload) {
|
|
9228
|
+
const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
9068
9229
|
this.getStorage.clear(key);
|
|
9069
9230
|
}
|
|
9070
9231
|
else {
|
|
@@ -9091,13 +9252,21 @@ class ScheduleMarkdownService {
|
|
|
9091
9252
|
|
|
9092
9253
|
/**
|
|
9093
9254
|
* Creates a unique key for memoizing PerformanceStorage instances.
|
|
9094
|
-
* Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
|
|
9255
|
+
* Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
|
|
9095
9256
|
* @param symbol - Trading pair symbol
|
|
9096
9257
|
* @param strategyName - Name of the strategy
|
|
9258
|
+
* @param exchangeName - Exchange name
|
|
9259
|
+
* @param frameName - Frame name
|
|
9097
9260
|
* @param backtest - Whether running in backtest mode
|
|
9098
9261
|
* @returns Unique string key for memoization
|
|
9099
9262
|
*/
|
|
9100
|
-
const CREATE_KEY_FN$6 = (symbol, strategyName, backtest) =>
|
|
9263
|
+
const CREATE_KEY_FN$6 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
9264
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
9265
|
+
if (frameName)
|
|
9266
|
+
parts.push(frameName);
|
|
9267
|
+
parts.push(backtest ? "backtest" : "live");
|
|
9268
|
+
return parts.join(":");
|
|
9269
|
+
};
|
|
9101
9270
|
/**
|
|
9102
9271
|
* Calculates percentile value from sorted array.
|
|
9103
9272
|
*/
|
|
@@ -9312,10 +9481,10 @@ class PerformanceMarkdownService {
|
|
|
9312
9481
|
/** Logger service for debug output */
|
|
9313
9482
|
this.loggerService = inject(TYPES.loggerService);
|
|
9314
9483
|
/**
|
|
9315
|
-
* Memoized function to get or create PerformanceStorage for a symbol-strategy-backtest
|
|
9316
|
-
* Each
|
|
9484
|
+
* Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
9485
|
+
* Each combination gets its own isolated storage instance.
|
|
9317
9486
|
*/
|
|
9318
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, backtest), () => new PerformanceStorage());
|
|
9487
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, exchangeName, frameName, backtest), () => new PerformanceStorage());
|
|
9319
9488
|
/**
|
|
9320
9489
|
* Processes performance events and accumulates metrics.
|
|
9321
9490
|
* Should be called from performance tracking code.
|
|
@@ -9328,7 +9497,8 @@ class PerformanceMarkdownService {
|
|
|
9328
9497
|
});
|
|
9329
9498
|
const symbol = event.symbol || "global";
|
|
9330
9499
|
const strategyName = event.strategyName || "global";
|
|
9331
|
-
const
|
|
9500
|
+
const exchangeName = event.exchangeName || "global";
|
|
9501
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, event.frameName, event.backtest);
|
|
9332
9502
|
storage.addEvent(event);
|
|
9333
9503
|
};
|
|
9334
9504
|
/**
|
|
@@ -9336,24 +9506,28 @@ class PerformanceMarkdownService {
|
|
|
9336
9506
|
*
|
|
9337
9507
|
* @param symbol - Trading pair symbol
|
|
9338
9508
|
* @param strategyName - Strategy name to get data for
|
|
9509
|
+
* @param exchangeName - Exchange name
|
|
9510
|
+
* @param frameName - Frame name
|
|
9339
9511
|
* @param backtest - True if backtest mode, false if live mode
|
|
9340
9512
|
* @returns Performance statistics with aggregated metrics
|
|
9341
9513
|
*
|
|
9342
9514
|
* @example
|
|
9343
9515
|
* ```typescript
|
|
9344
|
-
* const stats = await performanceService.getData("BTCUSDT", "my-strategy", false);
|
|
9516
|
+
* const stats = await performanceService.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
9345
9517
|
* console.log("Total time:", stats.totalDuration);
|
|
9346
9518
|
* console.log("Slowest operation:", Object.values(stats.metricStats)
|
|
9347
9519
|
* .sort((a, b) => b.avgDuration - a.avgDuration)[0]);
|
|
9348
9520
|
* ```
|
|
9349
9521
|
*/
|
|
9350
|
-
this.getData = async (symbol, strategyName, backtest) => {
|
|
9522
|
+
this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
9351
9523
|
this.loggerService.log("performanceMarkdownService getData", {
|
|
9352
9524
|
symbol,
|
|
9353
9525
|
strategyName,
|
|
9526
|
+
exchangeName,
|
|
9527
|
+
frameName,
|
|
9354
9528
|
backtest,
|
|
9355
9529
|
});
|
|
9356
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
9530
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
9357
9531
|
return storage.getData(strategyName);
|
|
9358
9532
|
};
|
|
9359
9533
|
/**
|
|
@@ -9361,23 +9535,27 @@ class PerformanceMarkdownService {
|
|
|
9361
9535
|
*
|
|
9362
9536
|
* @param symbol - Trading pair symbol
|
|
9363
9537
|
* @param strategyName - Strategy name to generate report for
|
|
9538
|
+
* @param exchangeName - Exchange name
|
|
9539
|
+
* @param frameName - Frame name
|
|
9364
9540
|
* @param backtest - True if backtest mode, false if live mode
|
|
9365
9541
|
* @param columns - Column configuration for formatting the table
|
|
9366
9542
|
* @returns Markdown formatted report string
|
|
9367
9543
|
*
|
|
9368
9544
|
* @example
|
|
9369
9545
|
* ```typescript
|
|
9370
|
-
* const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", false);
|
|
9546
|
+
* const markdown = await performanceService.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
9371
9547
|
* console.log(markdown);
|
|
9372
9548
|
* ```
|
|
9373
9549
|
*/
|
|
9374
|
-
this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
|
|
9550
|
+
this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.performance_columns) => {
|
|
9375
9551
|
this.loggerService.log("performanceMarkdownService getReport", {
|
|
9376
9552
|
symbol,
|
|
9377
9553
|
strategyName,
|
|
9554
|
+
exchangeName,
|
|
9555
|
+
frameName,
|
|
9378
9556
|
backtest,
|
|
9379
9557
|
});
|
|
9380
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
9558
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
9381
9559
|
return storage.getReport(strategyName, columns);
|
|
9382
9560
|
};
|
|
9383
9561
|
/**
|
|
@@ -9385,6 +9563,8 @@ class PerformanceMarkdownService {
|
|
|
9385
9563
|
*
|
|
9386
9564
|
* @param symbol - Trading pair symbol
|
|
9387
9565
|
* @param strategyName - Strategy name to save report for
|
|
9566
|
+
* @param exchangeName - Exchange name
|
|
9567
|
+
* @param frameName - Frame name
|
|
9388
9568
|
* @param backtest - True if backtest mode, false if live mode
|
|
9389
9569
|
* @param path - Directory path to save report
|
|
9390
9570
|
* @param columns - Column configuration for formatting the table
|
|
@@ -9392,35 +9572,35 @@ class PerformanceMarkdownService {
|
|
|
9392
9572
|
* @example
|
|
9393
9573
|
* ```typescript
|
|
9394
9574
|
* // Save to default path: ./dump/performance/my-strategy.md
|
|
9395
|
-
* await performanceService.dump("BTCUSDT", "my-strategy", false);
|
|
9575
|
+
* await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
9396
9576
|
*
|
|
9397
9577
|
* // Save to custom path
|
|
9398
|
-
* await performanceService.dump("BTCUSDT", "my-strategy", false, "./custom/path");
|
|
9578
|
+
* await performanceService.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
|
|
9399
9579
|
* ```
|
|
9400
9580
|
*/
|
|
9401
|
-
this.dump = async (symbol, strategyName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
|
|
9581
|
+
this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/performance", columns = COLUMN_CONFIG.performance_columns) => {
|
|
9402
9582
|
this.loggerService.log("performanceMarkdownService dump", {
|
|
9403
9583
|
symbol,
|
|
9404
9584
|
strategyName,
|
|
9585
|
+
exchangeName,
|
|
9586
|
+
frameName,
|
|
9405
9587
|
backtest,
|
|
9406
9588
|
path,
|
|
9407
9589
|
});
|
|
9408
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
9590
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
9409
9591
|
await storage.dump(strategyName, path, columns);
|
|
9410
9592
|
};
|
|
9411
9593
|
/**
|
|
9412
9594
|
* Clears accumulated performance data from storage.
|
|
9413
9595
|
*
|
|
9414
|
-
* @param
|
|
9415
|
-
* @param ctx - Optional context with symbol and strategyName
|
|
9596
|
+
* @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
|
|
9416
9597
|
*/
|
|
9417
|
-
this.clear = async (
|
|
9598
|
+
this.clear = async (payload) => {
|
|
9418
9599
|
this.loggerService.log("performanceMarkdownService clear", {
|
|
9419
|
-
|
|
9420
|
-
ctx,
|
|
9600
|
+
payload,
|
|
9421
9601
|
});
|
|
9422
|
-
if (
|
|
9423
|
-
const key = CREATE_KEY_FN$6(
|
|
9602
|
+
if (payload) {
|
|
9603
|
+
const key = CREATE_KEY_FN$6(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
9424
9604
|
this.getStorage.clear(key);
|
|
9425
9605
|
}
|
|
9426
9606
|
else {
|
|
@@ -9849,12 +10029,19 @@ class WalkerMarkdownService {
|
|
|
9849
10029
|
|
|
9850
10030
|
/**
|
|
9851
10031
|
* Creates a unique key for memoizing HeatmapStorage instances.
|
|
9852
|
-
* Key format: "
|
|
9853
|
-
* @param
|
|
10032
|
+
* Key format: "exchangeName:frameName:backtest" or "exchangeName:live"
|
|
10033
|
+
* @param exchangeName - Exchange name
|
|
10034
|
+
* @param frameName - Frame name
|
|
9854
10035
|
* @param backtest - Whether running in backtest mode
|
|
9855
10036
|
* @returns Unique string key for memoization
|
|
9856
10037
|
*/
|
|
9857
|
-
const CREATE_KEY_FN$5 = (
|
|
10038
|
+
const CREATE_KEY_FN$5 = (exchangeName, frameName, backtest) => {
|
|
10039
|
+
const parts = [exchangeName];
|
|
10040
|
+
if (frameName)
|
|
10041
|
+
parts.push(frameName);
|
|
10042
|
+
parts.push(backtest ? "backtest" : "live");
|
|
10043
|
+
return parts.join(":");
|
|
10044
|
+
};
|
|
9858
10045
|
const HEATMAP_METHOD_NAME_GET_DATA = "HeatMarkdownService.getData";
|
|
9859
10046
|
const HEATMAP_METHOD_NAME_GET_REPORT = "HeatMarkdownService.getReport";
|
|
9860
10047
|
const HEATMAP_METHOD_NAME_DUMP = "HeatMarkdownService.dump";
|
|
@@ -10195,10 +10382,10 @@ class HeatMarkdownService {
|
|
|
10195
10382
|
/** Logger service for debug output */
|
|
10196
10383
|
this.loggerService = inject(TYPES.loggerService);
|
|
10197
10384
|
/**
|
|
10198
|
-
* Memoized function to get or create HeatmapStorage for
|
|
10199
|
-
* Each
|
|
10385
|
+
* Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
|
|
10386
|
+
* Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
|
|
10200
10387
|
*/
|
|
10201
|
-
this.getStorage = functoolsKit.memoize(([
|
|
10388
|
+
this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$5(exchangeName, frameName, backtest), () => new HeatmapStorage());
|
|
10202
10389
|
/**
|
|
10203
10390
|
* Processes tick events and accumulates closed signals.
|
|
10204
10391
|
* Should be called from signal emitter subscription.
|
|
@@ -10214,20 +10401,21 @@ class HeatMarkdownService {
|
|
|
10214
10401
|
if (data.action !== "closed") {
|
|
10215
10402
|
return;
|
|
10216
10403
|
}
|
|
10217
|
-
const storage = this.getStorage(data.
|
|
10404
|
+
const storage = this.getStorage(data.exchangeName, data.frameName, data.backtest);
|
|
10218
10405
|
storage.addSignal(data);
|
|
10219
10406
|
};
|
|
10220
10407
|
/**
|
|
10221
|
-
* Gets aggregated portfolio heatmap statistics
|
|
10408
|
+
* Gets aggregated portfolio heatmap statistics.
|
|
10222
10409
|
*
|
|
10223
|
-
* @param
|
|
10410
|
+
* @param exchangeName - Exchange name
|
|
10411
|
+
* @param frameName - Frame name
|
|
10224
10412
|
* @param backtest - True if backtest mode, false if live mode
|
|
10225
10413
|
* @returns Promise resolving to heatmap statistics with per-symbol and portfolio-wide metrics
|
|
10226
10414
|
*
|
|
10227
10415
|
* @example
|
|
10228
10416
|
* ```typescript
|
|
10229
10417
|
* const service = new HeatMarkdownService();
|
|
10230
|
-
* const stats = await service.getData("
|
|
10418
|
+
* const stats = await service.getData("binance", "frame1", true);
|
|
10231
10419
|
*
|
|
10232
10420
|
* console.log(`Total symbols: ${stats.totalSymbols}`);
|
|
10233
10421
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
@@ -10237,18 +10425,21 @@ class HeatMarkdownService {
|
|
|
10237
10425
|
* });
|
|
10238
10426
|
* ```
|
|
10239
10427
|
*/
|
|
10240
|
-
this.getData = async (
|
|
10428
|
+
this.getData = async (exchangeName, frameName, backtest) => {
|
|
10241
10429
|
this.loggerService.log(HEATMAP_METHOD_NAME_GET_DATA, {
|
|
10242
|
-
|
|
10430
|
+
exchangeName,
|
|
10431
|
+
frameName,
|
|
10243
10432
|
backtest,
|
|
10244
10433
|
});
|
|
10245
|
-
const storage = this.getStorage(
|
|
10434
|
+
const storage = this.getStorage(exchangeName, frameName, backtest);
|
|
10246
10435
|
return storage.getData();
|
|
10247
10436
|
};
|
|
10248
10437
|
/**
|
|
10249
|
-
* Generates markdown report with portfolio heatmap table
|
|
10438
|
+
* Generates markdown report with portfolio heatmap table.
|
|
10250
10439
|
*
|
|
10251
|
-
* @param strategyName - Strategy name
|
|
10440
|
+
* @param strategyName - Strategy name for report title
|
|
10441
|
+
* @param exchangeName - Exchange name
|
|
10442
|
+
* @param frameName - Frame name
|
|
10252
10443
|
* @param backtest - True if backtest mode, false if live mode
|
|
10253
10444
|
* @param columns - Column configuration for formatting the table
|
|
10254
10445
|
* @returns Promise resolving to markdown formatted report string
|
|
@@ -10256,7 +10447,7 @@ class HeatMarkdownService {
|
|
|
10256
10447
|
* @example
|
|
10257
10448
|
* ```typescript
|
|
10258
10449
|
* const service = new HeatMarkdownService();
|
|
10259
|
-
* const markdown = await service.getReport("my-strategy", true);
|
|
10450
|
+
* const markdown = await service.getReport("my-strategy", "binance", "frame1", true);
|
|
10260
10451
|
* console.log(markdown);
|
|
10261
10452
|
* // Output:
|
|
10262
10453
|
* // # Portfolio Heatmap: my-strategy
|
|
@@ -10270,21 +10461,25 @@ class HeatMarkdownService {
|
|
|
10270
10461
|
* // ...
|
|
10271
10462
|
* ```
|
|
10272
10463
|
*/
|
|
10273
|
-
this.getReport = async (strategyName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
|
|
10464
|
+
this.getReport = async (strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.heat_columns) => {
|
|
10274
10465
|
this.loggerService.log(HEATMAP_METHOD_NAME_GET_REPORT, {
|
|
10275
10466
|
strategyName,
|
|
10467
|
+
exchangeName,
|
|
10468
|
+
frameName,
|
|
10276
10469
|
backtest,
|
|
10277
10470
|
});
|
|
10278
|
-
const storage = this.getStorage(
|
|
10471
|
+
const storage = this.getStorage(exchangeName, frameName, backtest);
|
|
10279
10472
|
return storage.getReport(strategyName, columns);
|
|
10280
10473
|
};
|
|
10281
10474
|
/**
|
|
10282
|
-
* Saves heatmap report to disk
|
|
10475
|
+
* Saves heatmap report to disk.
|
|
10283
10476
|
*
|
|
10284
10477
|
* Creates directory if it doesn't exist.
|
|
10285
10478
|
* Default filename: {strategyName}.md
|
|
10286
10479
|
*
|
|
10287
|
-
* @param strategyName - Strategy name
|
|
10480
|
+
* @param strategyName - Strategy name for report filename
|
|
10481
|
+
* @param exchangeName - Exchange name
|
|
10482
|
+
* @param frameName - Frame name
|
|
10288
10483
|
* @param backtest - True if backtest mode, false if live mode
|
|
10289
10484
|
* @param path - Optional directory path to save report (default: "./dump/heatmap")
|
|
10290
10485
|
* @param columns - Column configuration for formatting the table
|
|
@@ -10294,47 +10489,47 @@ class HeatMarkdownService {
|
|
|
10294
10489
|
* const service = new HeatMarkdownService();
|
|
10295
10490
|
*
|
|
10296
10491
|
* // Save to default path: ./dump/heatmap/my-strategy.md
|
|
10297
|
-
* await service.dump("my-strategy", true);
|
|
10492
|
+
* await service.dump("my-strategy", "binance", "frame1", true);
|
|
10298
10493
|
*
|
|
10299
10494
|
* // Save to custom path: ./reports/my-strategy.md
|
|
10300
|
-
* await service.dump("my-strategy", true, "./reports");
|
|
10495
|
+
* await service.dump("my-strategy", "binance", "frame1", true, "./reports");
|
|
10301
10496
|
* ```
|
|
10302
10497
|
*/
|
|
10303
|
-
this.dump = async (strategyName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
|
|
10498
|
+
this.dump = async (strategyName, exchangeName, frameName, backtest, path = "./dump/heatmap", columns = COLUMN_CONFIG.heat_columns) => {
|
|
10304
10499
|
this.loggerService.log(HEATMAP_METHOD_NAME_DUMP, {
|
|
10305
10500
|
strategyName,
|
|
10501
|
+
exchangeName,
|
|
10502
|
+
frameName,
|
|
10306
10503
|
backtest,
|
|
10307
10504
|
path,
|
|
10308
10505
|
});
|
|
10309
|
-
const storage = this.getStorage(
|
|
10506
|
+
const storage = this.getStorage(exchangeName, frameName, backtest);
|
|
10310
10507
|
await storage.dump(strategyName, path, columns);
|
|
10311
10508
|
};
|
|
10312
10509
|
/**
|
|
10313
10510
|
* Clears accumulated heatmap data from storage.
|
|
10314
|
-
* If
|
|
10315
|
-
* If
|
|
10511
|
+
* If payload is provided, clears only that exchangeName+frameName+backtest combination's data.
|
|
10512
|
+
* If payload is omitted, clears all data.
|
|
10316
10513
|
*
|
|
10317
|
-
* @param
|
|
10318
|
-
* @param ctx - Optional context with strategyName to clear specific data
|
|
10514
|
+
* @param payload - Optional payload with exchangeName, frameName, backtest to clear specific data
|
|
10319
10515
|
*
|
|
10320
10516
|
* @example
|
|
10321
10517
|
* ```typescript
|
|
10322
10518
|
* const service = new HeatMarkdownService();
|
|
10323
10519
|
*
|
|
10324
|
-
* // Clear specific
|
|
10325
|
-
* await service.clear(
|
|
10520
|
+
* // Clear specific exchange+frame+backtest data
|
|
10521
|
+
* await service.clear({ exchangeName: "binance", frameName: "frame1", backtest: true });
|
|
10326
10522
|
*
|
|
10327
10523
|
* // Clear all data
|
|
10328
10524
|
* await service.clear();
|
|
10329
10525
|
* ```
|
|
10330
10526
|
*/
|
|
10331
|
-
this.clear = async (
|
|
10527
|
+
this.clear = async (payload) => {
|
|
10332
10528
|
this.loggerService.log(HEATMAP_METHOD_NAME_CLEAR, {
|
|
10333
|
-
|
|
10334
|
-
ctx,
|
|
10529
|
+
payload,
|
|
10335
10530
|
});
|
|
10336
|
-
if (
|
|
10337
|
-
const key = CREATE_KEY_FN$5(
|
|
10531
|
+
if (payload) {
|
|
10532
|
+
const key = CREATE_KEY_FN$5(payload.exchangeName, payload.frameName, payload.backtest);
|
|
10338
10533
|
this.getStorage.clear(key);
|
|
10339
10534
|
}
|
|
10340
10535
|
else {
|
|
@@ -12192,7 +12387,7 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
|
|
|
12192
12387
|
revenuePercent,
|
|
12193
12388
|
backtest,
|
|
12194
12389
|
});
|
|
12195
|
-
await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
|
|
12390
|
+
await self.params.onProfit(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
|
|
12196
12391
|
}
|
|
12197
12392
|
}
|
|
12198
12393
|
if (shouldPersist) {
|
|
@@ -12242,7 +12437,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
12242
12437
|
lossPercent,
|
|
12243
12438
|
backtest,
|
|
12244
12439
|
});
|
|
12245
|
-
await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data, currentPrice, level, backtest, when.getTime());
|
|
12440
|
+
await self.params.onLoss(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, level, backtest, when.getTime());
|
|
12246
12441
|
}
|
|
12247
12442
|
}
|
|
12248
12443
|
if (shouldPersist) {
|
|
@@ -12568,10 +12763,11 @@ const CREATE_KEY_FN$4 = (signalId, backtest) => `${signalId}:${backtest ? "backt
|
|
|
12568
12763
|
* @param backtest - True if backtest mode
|
|
12569
12764
|
* @param timestamp - Event timestamp in milliseconds
|
|
12570
12765
|
*/
|
|
12571
|
-
const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
|
|
12766
|
+
const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialProfitSubject.next({
|
|
12572
12767
|
symbol,
|
|
12573
12768
|
strategyName,
|
|
12574
12769
|
exchangeName,
|
|
12770
|
+
frameName,
|
|
12575
12771
|
data,
|
|
12576
12772
|
currentPrice,
|
|
12577
12773
|
level,
|
|
@@ -12593,10 +12789,11 @@ const COMMIT_PROFIT_FN = async (symbol, strategyName, exchangeName, data, curren
|
|
|
12593
12789
|
* @param backtest - True if backtest mode
|
|
12594
12790
|
* @param timestamp - Event timestamp in milliseconds
|
|
12595
12791
|
*/
|
|
12596
|
-
const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
|
|
12792
|
+
const COMMIT_LOSS_FN = async (symbol, strategyName, exchangeName, frameName, data, currentPrice, level, backtest, timestamp) => await partialLossSubject.next({
|
|
12597
12793
|
symbol,
|
|
12598
12794
|
strategyName,
|
|
12599
12795
|
exchangeName,
|
|
12796
|
+
frameName,
|
|
12600
12797
|
data,
|
|
12601
12798
|
currentPrice,
|
|
12602
12799
|
level,
|
|
@@ -12748,11 +12945,21 @@ class PartialConnectionService {
|
|
|
12748
12945
|
|
|
12749
12946
|
/**
|
|
12750
12947
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
12751
|
-
* Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
|
|
12752
|
-
* @param
|
|
12948
|
+
* Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
|
|
12949
|
+
* @param symbol - Trading pair symbol
|
|
12950
|
+
* @param strategyName - Name of the strategy
|
|
12951
|
+
* @param exchangeName - Exchange name
|
|
12952
|
+
* @param frameName - Frame name
|
|
12953
|
+
* @param backtest - Whether running in backtest mode
|
|
12753
12954
|
* @returns Unique string key for memoization
|
|
12754
12955
|
*/
|
|
12755
|
-
const CREATE_KEY_FN$3 = (
|
|
12956
|
+
const CREATE_KEY_FN$3 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
12957
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
12958
|
+
if (frameName)
|
|
12959
|
+
parts.push(frameName);
|
|
12960
|
+
parts.push(backtest ? "backtest" : "live");
|
|
12961
|
+
return parts.join(":");
|
|
12962
|
+
};
|
|
12756
12963
|
/** Maximum number of events to store in partial reports */
|
|
12757
12964
|
const MAX_EVENTS$1 = 250;
|
|
12758
12965
|
/**
|
|
@@ -12924,15 +13131,15 @@ class PartialMarkdownService {
|
|
|
12924
13131
|
/** Logger service for debug output */
|
|
12925
13132
|
this.loggerService = inject(TYPES.loggerService);
|
|
12926
13133
|
/**
|
|
12927
|
-
* Memoized function to get or create ReportStorage for a symbol-strategy-backtest
|
|
12928
|
-
* Each
|
|
13134
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
13135
|
+
* Each combination gets its own isolated storage instance.
|
|
12929
13136
|
*/
|
|
12930
|
-
this.getStorage = functoolsKit.memoize(CREATE_KEY_FN$3, () => new ReportStorage$1());
|
|
13137
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$3(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage$1());
|
|
12931
13138
|
/**
|
|
12932
13139
|
* Processes profit events and accumulates them.
|
|
12933
13140
|
* Should be called from partialProfitSubject subscription.
|
|
12934
13141
|
*
|
|
12935
|
-
* @param data - Profit event data
|
|
13142
|
+
* @param data - Profit event data with frameName wrapper
|
|
12936
13143
|
*
|
|
12937
13144
|
* @example
|
|
12938
13145
|
* ```typescript
|
|
@@ -12944,14 +13151,14 @@ class PartialMarkdownService {
|
|
|
12944
13151
|
this.loggerService.log("partialMarkdownService tickProfit", {
|
|
12945
13152
|
data,
|
|
12946
13153
|
});
|
|
12947
|
-
const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
|
|
13154
|
+
const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
|
|
12948
13155
|
storage.addProfitEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
|
|
12949
13156
|
};
|
|
12950
13157
|
/**
|
|
12951
13158
|
* Processes loss events and accumulates them.
|
|
12952
13159
|
* Should be called from partialLossSubject subscription.
|
|
12953
13160
|
*
|
|
12954
|
-
* @param data - Loss event data
|
|
13161
|
+
* @param data - Loss event data with frameName wrapper
|
|
12955
13162
|
*
|
|
12956
13163
|
* @example
|
|
12957
13164
|
* ```typescript
|
|
@@ -12963,7 +13170,7 @@ class PartialMarkdownService {
|
|
|
12963
13170
|
this.loggerService.log("partialMarkdownService tickLoss", {
|
|
12964
13171
|
data,
|
|
12965
13172
|
});
|
|
12966
|
-
const storage = this.getStorage(data.symbol, data.data.strategyName, data.backtest);
|
|
13173
|
+
const storage = this.getStorage(data.symbol, data.data.strategyName, data.exchangeName, data.frameName, data.backtest);
|
|
12967
13174
|
storage.addLossEvent(data.data, data.currentPrice, data.level, data.backtest, data.timestamp);
|
|
12968
13175
|
};
|
|
12969
13176
|
/**
|
|
@@ -12972,23 +13179,27 @@ class PartialMarkdownService {
|
|
|
12972
13179
|
*
|
|
12973
13180
|
* @param symbol - Trading pair symbol to get data for
|
|
12974
13181
|
* @param strategyName - Strategy name to get data for
|
|
13182
|
+
* @param exchangeName - Exchange name
|
|
13183
|
+
* @param frameName - Frame name
|
|
12975
13184
|
* @param backtest - True if backtest mode, false if live mode
|
|
12976
13185
|
* @returns Statistical data object with all metrics
|
|
12977
13186
|
*
|
|
12978
13187
|
* @example
|
|
12979
13188
|
* ```typescript
|
|
12980
13189
|
* const service = new PartialMarkdownService();
|
|
12981
|
-
* const stats = await service.getData("BTCUSDT", "my-strategy", false);
|
|
13190
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
12982
13191
|
* console.log(stats.totalProfit, stats.totalLoss);
|
|
12983
13192
|
* ```
|
|
12984
13193
|
*/
|
|
12985
|
-
this.getData = async (symbol, strategyName, backtest) => {
|
|
13194
|
+
this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
12986
13195
|
this.loggerService.log("partialMarkdownService getData", {
|
|
12987
13196
|
symbol,
|
|
12988
13197
|
strategyName,
|
|
13198
|
+
exchangeName,
|
|
13199
|
+
frameName,
|
|
12989
13200
|
backtest,
|
|
12990
13201
|
});
|
|
12991
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
13202
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
12992
13203
|
return storage.getData();
|
|
12993
13204
|
};
|
|
12994
13205
|
/**
|
|
@@ -12997,6 +13208,8 @@ class PartialMarkdownService {
|
|
|
12997
13208
|
*
|
|
12998
13209
|
* @param symbol - Trading pair symbol to generate report for
|
|
12999
13210
|
* @param strategyName - Strategy name to generate report for
|
|
13211
|
+
* @param exchangeName - Exchange name
|
|
13212
|
+
* @param frameName - Frame name
|
|
13000
13213
|
* @param backtest - True if backtest mode, false if live mode
|
|
13001
13214
|
* @param columns - Column configuration for formatting the table
|
|
13002
13215
|
* @returns Markdown formatted report string with table of all events
|
|
@@ -13004,17 +13217,19 @@ class PartialMarkdownService {
|
|
|
13004
13217
|
* @example
|
|
13005
13218
|
* ```typescript
|
|
13006
13219
|
* const service = new PartialMarkdownService();
|
|
13007
|
-
* const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
|
|
13220
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
13008
13221
|
* console.log(markdown);
|
|
13009
13222
|
* ```
|
|
13010
13223
|
*/
|
|
13011
|
-
this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
|
|
13224
|
+
this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.partial_columns) => {
|
|
13012
13225
|
this.loggerService.log("partialMarkdownService getReport", {
|
|
13013
13226
|
symbol,
|
|
13014
13227
|
strategyName,
|
|
13228
|
+
exchangeName,
|
|
13229
|
+
frameName,
|
|
13015
13230
|
backtest,
|
|
13016
13231
|
});
|
|
13017
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
13232
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
13018
13233
|
return storage.getReport(symbol, strategyName, columns);
|
|
13019
13234
|
};
|
|
13020
13235
|
/**
|
|
@@ -13024,6 +13239,8 @@ class PartialMarkdownService {
|
|
|
13024
13239
|
*
|
|
13025
13240
|
* @param symbol - Trading pair symbol to save report for
|
|
13026
13241
|
* @param strategyName - Strategy name to save report for
|
|
13242
|
+
* @param exchangeName - Exchange name
|
|
13243
|
+
* @param frameName - Frame name
|
|
13027
13244
|
* @param backtest - True if backtest mode, false if live mode
|
|
13028
13245
|
* @param path - Directory path to save report (default: "./dump/partial")
|
|
13029
13246
|
* @param columns - Column configuration for formatting the table
|
|
@@ -13033,48 +13250,48 @@ class PartialMarkdownService {
|
|
|
13033
13250
|
* const service = new PartialMarkdownService();
|
|
13034
13251
|
*
|
|
13035
13252
|
* // Save to default path: ./dump/partial/BTCUSDT_my-strategy.md
|
|
13036
|
-
* await service.dump("BTCUSDT", "my-strategy", false);
|
|
13253
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
13037
13254
|
*
|
|
13038
13255
|
* // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
|
|
13039
|
-
* await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
|
|
13256
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
|
|
13040
13257
|
* ```
|
|
13041
13258
|
*/
|
|
13042
|
-
this.dump = async (symbol, strategyName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
|
|
13259
|
+
this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/partial", columns = COLUMN_CONFIG.partial_columns) => {
|
|
13043
13260
|
this.loggerService.log("partialMarkdownService dump", {
|
|
13044
13261
|
symbol,
|
|
13045
13262
|
strategyName,
|
|
13263
|
+
exchangeName,
|
|
13264
|
+
frameName,
|
|
13046
13265
|
backtest,
|
|
13047
13266
|
path,
|
|
13048
13267
|
});
|
|
13049
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
13268
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
13050
13269
|
await storage.dump(symbol, strategyName, path, columns);
|
|
13051
13270
|
};
|
|
13052
13271
|
/**
|
|
13053
13272
|
* Clears accumulated event data from storage.
|
|
13054
|
-
* If
|
|
13273
|
+
* If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
|
|
13055
13274
|
* If nothing is provided, clears all data.
|
|
13056
13275
|
*
|
|
13057
|
-
* @param
|
|
13058
|
-
* @param ctx - Optional context with symbol and strategyName
|
|
13276
|
+
* @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
|
|
13059
13277
|
*
|
|
13060
13278
|
* @example
|
|
13061
13279
|
* ```typescript
|
|
13062
13280
|
* const service = new PartialMarkdownService();
|
|
13063
13281
|
*
|
|
13064
|
-
* // Clear specific
|
|
13065
|
-
* await service.clear(
|
|
13282
|
+
* // Clear specific combination
|
|
13283
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
|
|
13066
13284
|
*
|
|
13067
13285
|
* // Clear all data
|
|
13068
13286
|
* await service.clear();
|
|
13069
13287
|
* ```
|
|
13070
13288
|
*/
|
|
13071
|
-
this.clear = async (
|
|
13289
|
+
this.clear = async (payload) => {
|
|
13072
13290
|
this.loggerService.log("partialMarkdownService clear", {
|
|
13073
|
-
|
|
13074
|
-
ctx,
|
|
13291
|
+
payload,
|
|
13075
13292
|
});
|
|
13076
|
-
if (
|
|
13077
|
-
const key = CREATE_KEY_FN$3(
|
|
13293
|
+
if (payload) {
|
|
13294
|
+
const key = CREATE_KEY_FN$3(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
13078
13295
|
this.getStorage.clear(key);
|
|
13079
13296
|
}
|
|
13080
13297
|
else {
|
|
@@ -13155,18 +13372,18 @@ class PartialGlobalService {
|
|
|
13155
13372
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
13156
13373
|
/**
|
|
13157
13374
|
* Validates strategy and associated risk configuration.
|
|
13158
|
-
* Memoized to avoid redundant validations for the same strategy.
|
|
13375
|
+
* Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
|
|
13159
13376
|
*
|
|
13160
|
-
* @param
|
|
13377
|
+
* @param context - Context with strategyName, exchangeName and frameName
|
|
13161
13378
|
* @param methodName - Name of the calling method for error tracking
|
|
13162
13379
|
*/
|
|
13163
|
-
this.validate = functoolsKit.memoize(([
|
|
13380
|
+
this.validate = functoolsKit.memoize(([context]) => `${context.strategyName}:${context.exchangeName}:${context.frameName}`, (context, methodName) => {
|
|
13164
13381
|
this.loggerService.log("partialGlobalService validate", {
|
|
13165
|
-
|
|
13382
|
+
context,
|
|
13166
13383
|
methodName,
|
|
13167
13384
|
});
|
|
13168
|
-
this.strategyValidationService.validate(strategyName, methodName);
|
|
13169
|
-
const { riskName, riskList } = this.strategySchemaService.get(strategyName);
|
|
13385
|
+
this.strategyValidationService.validate(context.strategyName, methodName);
|
|
13386
|
+
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
13170
13387
|
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
13171
13388
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
13172
13389
|
});
|
|
@@ -13192,7 +13409,11 @@ class PartialGlobalService {
|
|
|
13192
13409
|
backtest,
|
|
13193
13410
|
when,
|
|
13194
13411
|
});
|
|
13195
|
-
this.validate(
|
|
13412
|
+
this.validate({
|
|
13413
|
+
strategyName: data.strategyName,
|
|
13414
|
+
exchangeName: data.exchangeName,
|
|
13415
|
+
frameName: data.frameName
|
|
13416
|
+
}, "partialGlobalService profit");
|
|
13196
13417
|
return await this.partialConnectionService.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
|
|
13197
13418
|
};
|
|
13198
13419
|
/**
|
|
@@ -13217,7 +13438,11 @@ class PartialGlobalService {
|
|
|
13217
13438
|
backtest,
|
|
13218
13439
|
when,
|
|
13219
13440
|
});
|
|
13220
|
-
this.validate(
|
|
13441
|
+
this.validate({
|
|
13442
|
+
strategyName: data.strategyName,
|
|
13443
|
+
exchangeName: data.exchangeName,
|
|
13444
|
+
frameName: data.frameName
|
|
13445
|
+
}, "partialGlobalService loss");
|
|
13221
13446
|
return await this.partialConnectionService.loss(symbol, data, currentPrice, lossPercent, backtest, when);
|
|
13222
13447
|
};
|
|
13223
13448
|
/**
|
|
@@ -13237,7 +13462,11 @@ class PartialGlobalService {
|
|
|
13237
13462
|
priceClose,
|
|
13238
13463
|
backtest,
|
|
13239
13464
|
});
|
|
13240
|
-
this.validate(
|
|
13465
|
+
this.validate({
|
|
13466
|
+
strategyName: data.strategyName,
|
|
13467
|
+
exchangeName: data.exchangeName,
|
|
13468
|
+
frameName: data.frameName
|
|
13469
|
+
}, "partialGlobalService clear");
|
|
13241
13470
|
return await this.partialConnectionService.clear(symbol, data, priceClose, backtest);
|
|
13242
13471
|
};
|
|
13243
13472
|
}
|
|
@@ -13247,7 +13476,7 @@ class PartialGlobalService {
|
|
|
13247
13476
|
* Warning threshold for message size in kilobytes.
|
|
13248
13477
|
* Messages exceeding this size trigger console warnings.
|
|
13249
13478
|
*/
|
|
13250
|
-
const WARN_KB =
|
|
13479
|
+
const WARN_KB = 30;
|
|
13251
13480
|
/**
|
|
13252
13481
|
* Internal function for dumping signal data to markdown files.
|
|
13253
13482
|
* Creates a directory structure with system prompts, user messages, and LLM output.
|
|
@@ -13511,13 +13740,21 @@ class ConfigValidationService {
|
|
|
13511
13740
|
|
|
13512
13741
|
/**
|
|
13513
13742
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
13514
|
-
* Key format: "symbol:strategyName:backtest" or "symbol:strategyName:live"
|
|
13743
|
+
* Key format: "symbol:strategyName:exchangeName:frameName:backtest" or "symbol:strategyName:exchangeName:live"
|
|
13515
13744
|
* @param symbol - Trading pair symbol
|
|
13516
13745
|
* @param strategyName - Name of the strategy
|
|
13746
|
+
* @param exchangeName - Exchange name
|
|
13747
|
+
* @param frameName - Frame name
|
|
13517
13748
|
* @param backtest - Whether running in backtest mode
|
|
13518
13749
|
* @returns Unique string key for memoization
|
|
13519
13750
|
*/
|
|
13520
|
-
const CREATE_KEY_FN$2 = (symbol, strategyName, backtest) =>
|
|
13751
|
+
const CREATE_KEY_FN$2 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
13752
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
13753
|
+
if (frameName)
|
|
13754
|
+
parts.push(frameName);
|
|
13755
|
+
parts.push(backtest ? "backtest" : "live");
|
|
13756
|
+
return parts.join(":");
|
|
13757
|
+
};
|
|
13521
13758
|
/** Maximum number of events to store in risk reports */
|
|
13522
13759
|
const MAX_EVENTS = 250;
|
|
13523
13760
|
/**
|
|
@@ -13659,15 +13896,15 @@ class RiskMarkdownService {
|
|
|
13659
13896
|
/** Logger service for debug output */
|
|
13660
13897
|
this.loggerService = inject(TYPES.loggerService);
|
|
13661
13898
|
/**
|
|
13662
|
-
* Memoized function to get or create ReportStorage for a symbol-strategy-backtest
|
|
13663
|
-
* Each
|
|
13899
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
13900
|
+
* Each combination gets its own isolated storage instance.
|
|
13664
13901
|
*/
|
|
13665
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, backtest), () => new ReportStorage());
|
|
13902
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$2(symbol, strategyName, exchangeName, frameName, backtest), () => new ReportStorage());
|
|
13666
13903
|
/**
|
|
13667
13904
|
* Processes risk rejection events and accumulates them.
|
|
13668
13905
|
* Should be called from riskSubject subscription.
|
|
13669
13906
|
*
|
|
13670
|
-
* @param data - Risk rejection event data
|
|
13907
|
+
* @param data - Risk rejection event data with frameName wrapper
|
|
13671
13908
|
*
|
|
13672
13909
|
* @example
|
|
13673
13910
|
* ```typescript
|
|
@@ -13679,7 +13916,7 @@ class RiskMarkdownService {
|
|
|
13679
13916
|
this.loggerService.log("riskMarkdownService tickRejection", {
|
|
13680
13917
|
data,
|
|
13681
13918
|
});
|
|
13682
|
-
const storage = this.getStorage(data.symbol, data.strategyName, data.backtest);
|
|
13919
|
+
const storage = this.getStorage(data.symbol, data.strategyName, data.exchangeName, data.frameName, data.backtest);
|
|
13683
13920
|
storage.addRejectionEvent(data);
|
|
13684
13921
|
};
|
|
13685
13922
|
/**
|
|
@@ -13688,23 +13925,27 @@ class RiskMarkdownService {
|
|
|
13688
13925
|
*
|
|
13689
13926
|
* @param symbol - Trading pair symbol to get data for
|
|
13690
13927
|
* @param strategyName - Strategy name to get data for
|
|
13928
|
+
* @param exchangeName - Exchange name
|
|
13929
|
+
* @param frameName - Frame name
|
|
13691
13930
|
* @param backtest - True if backtest mode, false if live mode
|
|
13692
13931
|
* @returns Statistical data object with all metrics
|
|
13693
13932
|
*
|
|
13694
13933
|
* @example
|
|
13695
13934
|
* ```typescript
|
|
13696
13935
|
* const service = new RiskMarkdownService();
|
|
13697
|
-
* const stats = await service.getData("BTCUSDT", "my-strategy", false);
|
|
13936
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
13698
13937
|
* console.log(stats.totalRejections, stats.bySymbol);
|
|
13699
13938
|
* ```
|
|
13700
13939
|
*/
|
|
13701
|
-
this.getData = async (symbol, strategyName, backtest) => {
|
|
13940
|
+
this.getData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
13702
13941
|
this.loggerService.log("riskMarkdownService getData", {
|
|
13703
13942
|
symbol,
|
|
13704
13943
|
strategyName,
|
|
13944
|
+
exchangeName,
|
|
13945
|
+
frameName,
|
|
13705
13946
|
backtest,
|
|
13706
13947
|
});
|
|
13707
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
13948
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
13708
13949
|
return storage.getData();
|
|
13709
13950
|
};
|
|
13710
13951
|
/**
|
|
@@ -13713,6 +13954,8 @@ class RiskMarkdownService {
|
|
|
13713
13954
|
*
|
|
13714
13955
|
* @param symbol - Trading pair symbol to generate report for
|
|
13715
13956
|
* @param strategyName - Strategy name to generate report for
|
|
13957
|
+
* @param exchangeName - Exchange name
|
|
13958
|
+
* @param frameName - Frame name
|
|
13716
13959
|
* @param backtest - True if backtest mode, false if live mode
|
|
13717
13960
|
* @param columns - Column configuration for formatting the table
|
|
13718
13961
|
* @returns Markdown formatted report string with table of all events
|
|
@@ -13720,17 +13963,19 @@ class RiskMarkdownService {
|
|
|
13720
13963
|
* @example
|
|
13721
13964
|
* ```typescript
|
|
13722
13965
|
* const service = new RiskMarkdownService();
|
|
13723
|
-
* const markdown = await service.getReport("BTCUSDT", "my-strategy", false);
|
|
13966
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
13724
13967
|
* console.log(markdown);
|
|
13725
13968
|
* ```
|
|
13726
13969
|
*/
|
|
13727
|
-
this.getReport = async (symbol, strategyName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
|
|
13970
|
+
this.getReport = async (symbol, strategyName, exchangeName, frameName, backtest, columns = COLUMN_CONFIG.risk_columns) => {
|
|
13728
13971
|
this.loggerService.log("riskMarkdownService getReport", {
|
|
13729
13972
|
symbol,
|
|
13730
13973
|
strategyName,
|
|
13974
|
+
exchangeName,
|
|
13975
|
+
frameName,
|
|
13731
13976
|
backtest,
|
|
13732
13977
|
});
|
|
13733
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
13978
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
13734
13979
|
return storage.getReport(symbol, strategyName, columns);
|
|
13735
13980
|
};
|
|
13736
13981
|
/**
|
|
@@ -13740,6 +13985,8 @@ class RiskMarkdownService {
|
|
|
13740
13985
|
*
|
|
13741
13986
|
* @param symbol - Trading pair symbol to save report for
|
|
13742
13987
|
* @param strategyName - Strategy name to save report for
|
|
13988
|
+
* @param exchangeName - Exchange name
|
|
13989
|
+
* @param frameName - Frame name
|
|
13743
13990
|
* @param backtest - True if backtest mode, false if live mode
|
|
13744
13991
|
* @param path - Directory path to save report (default: "./dump/risk")
|
|
13745
13992
|
* @param columns - Column configuration for formatting the table
|
|
@@ -13749,48 +13996,48 @@ class RiskMarkdownService {
|
|
|
13749
13996
|
* const service = new RiskMarkdownService();
|
|
13750
13997
|
*
|
|
13751
13998
|
* // Save to default path: ./dump/risk/BTCUSDT_my-strategy.md
|
|
13752
|
-
* await service.dump("BTCUSDT", "my-strategy", false);
|
|
13999
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false);
|
|
13753
14000
|
*
|
|
13754
14001
|
* // Save to custom path: ./custom/path/BTCUSDT_my-strategy.md
|
|
13755
|
-
* await service.dump("BTCUSDT", "my-strategy", false, "./custom/path");
|
|
14002
|
+
* await service.dump("BTCUSDT", "my-strategy", "binance", "1h", false, "./custom/path");
|
|
13756
14003
|
* ```
|
|
13757
14004
|
*/
|
|
13758
|
-
this.dump = async (symbol, strategyName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
|
|
14005
|
+
this.dump = async (symbol, strategyName, exchangeName, frameName, backtest, path = "./dump/risk", columns = COLUMN_CONFIG.risk_columns) => {
|
|
13759
14006
|
this.loggerService.log("riskMarkdownService dump", {
|
|
13760
14007
|
symbol,
|
|
13761
14008
|
strategyName,
|
|
14009
|
+
exchangeName,
|
|
14010
|
+
frameName,
|
|
13762
14011
|
backtest,
|
|
13763
14012
|
path,
|
|
13764
14013
|
});
|
|
13765
|
-
const storage = this.getStorage(symbol, strategyName, backtest);
|
|
14014
|
+
const storage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
13766
14015
|
await storage.dump(symbol, strategyName, path, columns);
|
|
13767
14016
|
};
|
|
13768
14017
|
/**
|
|
13769
14018
|
* Clears accumulated event data from storage.
|
|
13770
|
-
* If
|
|
14019
|
+
* If payload is provided, clears only that specific symbol-strategy-exchange-frame-backtest combination's data.
|
|
13771
14020
|
* If nothing is provided, clears all data.
|
|
13772
14021
|
*
|
|
13773
|
-
* @param
|
|
13774
|
-
* @param ctx - Optional context with symbol and strategyName
|
|
14022
|
+
* @param payload - Optional payload with symbol, strategyName, exchangeName, frameName, backtest
|
|
13775
14023
|
*
|
|
13776
14024
|
* @example
|
|
13777
14025
|
* ```typescript
|
|
13778
14026
|
* const service = new RiskMarkdownService();
|
|
13779
14027
|
*
|
|
13780
|
-
* // Clear specific
|
|
13781
|
-
* await service.clear(
|
|
14028
|
+
* // Clear specific combination
|
|
14029
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy", exchangeName: "binance", frameName: "1h", backtest: false });
|
|
13782
14030
|
*
|
|
13783
14031
|
* // Clear all data
|
|
13784
14032
|
* await service.clear();
|
|
13785
14033
|
* ```
|
|
13786
14034
|
*/
|
|
13787
|
-
this.clear = async (
|
|
14035
|
+
this.clear = async (payload) => {
|
|
13788
14036
|
this.loggerService.log("riskMarkdownService clear", {
|
|
13789
|
-
|
|
13790
|
-
ctx,
|
|
14037
|
+
payload,
|
|
13791
14038
|
});
|
|
13792
|
-
if (
|
|
13793
|
-
const key = CREATE_KEY_FN$2(
|
|
14039
|
+
if (payload) {
|
|
14040
|
+
const key = CREATE_KEY_FN$2(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
13794
14041
|
this.getStorage.clear(key);
|
|
13795
14042
|
}
|
|
13796
14043
|
else {
|
|
@@ -14300,10 +14547,9 @@ const CANCEL_METHOD_NAME = "strategy.cancel";
|
|
|
14300
14547
|
* await stop("BTCUSDT", "my-strategy");
|
|
14301
14548
|
* ```
|
|
14302
14549
|
*/
|
|
14303
|
-
async function stop(symbol
|
|
14550
|
+
async function stop(symbol) {
|
|
14304
14551
|
backtest$1.loggerService.info(STOP_METHOD_NAME, {
|
|
14305
14552
|
symbol,
|
|
14306
|
-
strategyName,
|
|
14307
14553
|
});
|
|
14308
14554
|
if (!ExecutionContextService.hasContext()) {
|
|
14309
14555
|
throw new Error("stop requires an execution context");
|
|
@@ -14312,7 +14558,12 @@ async function stop(symbol, strategyName) {
|
|
|
14312
14558
|
throw new Error("stop requires a method context");
|
|
14313
14559
|
}
|
|
14314
14560
|
const { backtest: isBacktest } = backtest$1.executionContextService.context;
|
|
14315
|
-
|
|
14561
|
+
const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
|
|
14562
|
+
await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
|
|
14563
|
+
exchangeName,
|
|
14564
|
+
frameName,
|
|
14565
|
+
strategyName,
|
|
14566
|
+
});
|
|
14316
14567
|
}
|
|
14317
14568
|
/**
|
|
14318
14569
|
* Cancels the scheduled signal without stopping the strategy.
|
|
@@ -14336,10 +14587,9 @@ async function stop(symbol, strategyName) {
|
|
|
14336
14587
|
* await cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
14337
14588
|
* ```
|
|
14338
14589
|
*/
|
|
14339
|
-
async function cancel(symbol,
|
|
14590
|
+
async function cancel(symbol, cancelId) {
|
|
14340
14591
|
backtest$1.loggerService.info(CANCEL_METHOD_NAME, {
|
|
14341
14592
|
symbol,
|
|
14342
|
-
strategyName,
|
|
14343
14593
|
cancelId,
|
|
14344
14594
|
});
|
|
14345
14595
|
if (!ExecutionContextService.hasContext()) {
|
|
@@ -14349,7 +14599,8 @@ async function cancel(symbol, strategyName, cancelId) {
|
|
|
14349
14599
|
throw new Error("cancel requires a method context");
|
|
14350
14600
|
}
|
|
14351
14601
|
const { backtest: isBacktest } = backtest$1.executionContextService.context;
|
|
14352
|
-
|
|
14602
|
+
const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
|
|
14603
|
+
await backtest$1.strategyCoreService.cancel(isBacktest, symbol, { exchangeName, frameName, strategyName }, cancelId);
|
|
14353
14604
|
}
|
|
14354
14605
|
|
|
14355
14606
|
/**
|
|
@@ -16496,42 +16747,73 @@ class BacktestInstance {
|
|
|
16496
16747
|
context,
|
|
16497
16748
|
});
|
|
16498
16749
|
{
|
|
16499
|
-
backtest$1.backtestMarkdownService.clear(
|
|
16750
|
+
backtest$1.backtestMarkdownService.clear({
|
|
16500
16751
|
symbol,
|
|
16501
16752
|
strategyName: context.strategyName,
|
|
16753
|
+
exchangeName: context.exchangeName,
|
|
16754
|
+
frameName: context.frameName,
|
|
16755
|
+
backtest: true,
|
|
16502
16756
|
});
|
|
16503
|
-
backtest$1.liveMarkdownService.clear(
|
|
16757
|
+
backtest$1.liveMarkdownService.clear({
|
|
16504
16758
|
symbol,
|
|
16505
16759
|
strategyName: context.strategyName,
|
|
16760
|
+
exchangeName: context.exchangeName,
|
|
16761
|
+
frameName: context.frameName,
|
|
16762
|
+
backtest: true,
|
|
16506
16763
|
});
|
|
16507
|
-
backtest$1.scheduleMarkdownService.clear(
|
|
16764
|
+
backtest$1.scheduleMarkdownService.clear({
|
|
16508
16765
|
symbol,
|
|
16509
16766
|
strategyName: context.strategyName,
|
|
16767
|
+
exchangeName: context.exchangeName,
|
|
16768
|
+
frameName: context.frameName,
|
|
16769
|
+
backtest: true,
|
|
16510
16770
|
});
|
|
16511
|
-
backtest$1.performanceMarkdownService.clear(
|
|
16771
|
+
backtest$1.performanceMarkdownService.clear({
|
|
16512
16772
|
symbol,
|
|
16513
16773
|
strategyName: context.strategyName,
|
|
16774
|
+
exchangeName: context.exchangeName,
|
|
16775
|
+
frameName: context.frameName,
|
|
16776
|
+
backtest: true,
|
|
16514
16777
|
});
|
|
16515
|
-
backtest$1.partialMarkdownService.clear(
|
|
16778
|
+
backtest$1.partialMarkdownService.clear({
|
|
16516
16779
|
symbol,
|
|
16517
16780
|
strategyName: context.strategyName,
|
|
16781
|
+
exchangeName: context.exchangeName,
|
|
16782
|
+
frameName: context.frameName,
|
|
16783
|
+
backtest: true,
|
|
16518
16784
|
});
|
|
16519
|
-
backtest$1.riskMarkdownService.clear(
|
|
16785
|
+
backtest$1.riskMarkdownService.clear({
|
|
16520
16786
|
symbol,
|
|
16521
16787
|
strategyName: context.strategyName,
|
|
16788
|
+
exchangeName: context.exchangeName,
|
|
16789
|
+
frameName: context.frameName,
|
|
16790
|
+
backtest: true,
|
|
16522
16791
|
});
|
|
16523
16792
|
}
|
|
16524
16793
|
{
|
|
16525
|
-
backtest$1.strategyCoreService.clear(
|
|
16794
|
+
backtest$1.strategyCoreService.clear({
|
|
16526
16795
|
symbol,
|
|
16527
16796
|
strategyName: context.strategyName,
|
|
16797
|
+
exchangeName: context.exchangeName,
|
|
16798
|
+
frameName: context.frameName,
|
|
16799
|
+
backtest: true,
|
|
16528
16800
|
});
|
|
16529
16801
|
}
|
|
16530
16802
|
{
|
|
16531
16803
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16532
|
-
riskName && backtest$1.riskGlobalService.clear(
|
|
16804
|
+
riskName && backtest$1.riskGlobalService.clear({
|
|
16805
|
+
riskName,
|
|
16806
|
+
exchangeName: context.exchangeName,
|
|
16807
|
+
frameName: context.frameName,
|
|
16808
|
+
backtest: true,
|
|
16809
|
+
});
|
|
16533
16810
|
riskList &&
|
|
16534
|
-
riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(
|
|
16811
|
+
riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
|
|
16812
|
+
riskName,
|
|
16813
|
+
exchangeName: context.exchangeName,
|
|
16814
|
+
frameName: context.frameName,
|
|
16815
|
+
backtest: true,
|
|
16816
|
+
}));
|
|
16535
16817
|
}
|
|
16536
16818
|
return backtest$1.backtestCommandService.run(symbol, context);
|
|
16537
16819
|
};
|
|
@@ -16571,12 +16853,17 @@ class BacktestInstance {
|
|
|
16571
16853
|
}
|
|
16572
16854
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
16573
16855
|
return () => {
|
|
16574
|
-
backtest$1.strategyCoreService.stop(true, {
|
|
16575
|
-
symbol,
|
|
16856
|
+
backtest$1.strategyCoreService.stop(true, symbol, {
|
|
16576
16857
|
strategyName: context.strategyName,
|
|
16858
|
+
exchangeName: context.exchangeName,
|
|
16859
|
+
frameName: context.frameName,
|
|
16577
16860
|
});
|
|
16578
16861
|
backtest$1.strategyCoreService
|
|
16579
|
-
.getPendingSignal(true, symbol,
|
|
16862
|
+
.getPendingSignal(true, symbol, {
|
|
16863
|
+
strategyName: context.strategyName,
|
|
16864
|
+
exchangeName: context.exchangeName,
|
|
16865
|
+
frameName: context.frameName,
|
|
16866
|
+
})
|
|
16580
16867
|
.then(async (pendingSignal) => {
|
|
16581
16868
|
if (pendingSignal) {
|
|
16582
16869
|
return;
|
|
@@ -16696,16 +16983,16 @@ class BacktestUtils {
|
|
|
16696
16983
|
* }
|
|
16697
16984
|
* ```
|
|
16698
16985
|
*/
|
|
16699
|
-
this.getPendingSignal = async (symbol,
|
|
16700
|
-
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
16986
|
+
this.getPendingSignal = async (symbol, context) => {
|
|
16987
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
16701
16988
|
{
|
|
16702
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16989
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16703
16990
|
riskName &&
|
|
16704
16991
|
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
16705
16992
|
riskList &&
|
|
16706
16993
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL));
|
|
16707
16994
|
}
|
|
16708
|
-
return await backtest$1.strategyCoreService.getPendingSignal(true, symbol,
|
|
16995
|
+
return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, context);
|
|
16709
16996
|
};
|
|
16710
16997
|
/**
|
|
16711
16998
|
* Retrieves the currently active scheduled signal for the strategy.
|
|
@@ -16723,16 +17010,16 @@ class BacktestUtils {
|
|
|
16723
17010
|
* }
|
|
16724
17011
|
* ```
|
|
16725
17012
|
*/
|
|
16726
|
-
this.getScheduledSignal = async (symbol,
|
|
16727
|
-
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17013
|
+
this.getScheduledSignal = async (symbol, context) => {
|
|
17014
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
16728
17015
|
{
|
|
16729
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17016
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16730
17017
|
riskName &&
|
|
16731
17018
|
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
16732
17019
|
riskList &&
|
|
16733
17020
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL));
|
|
16734
17021
|
}
|
|
16735
|
-
return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol,
|
|
17022
|
+
return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, context);
|
|
16736
17023
|
};
|
|
16737
17024
|
/**
|
|
16738
17025
|
* Stops the strategy from generating new signals.
|
|
@@ -16743,24 +17030,29 @@ class BacktestUtils {
|
|
|
16743
17030
|
*
|
|
16744
17031
|
* @param symbol - Trading pair symbol
|
|
16745
17032
|
* @param strategyName - Strategy name to stop
|
|
17033
|
+
* @param context - Execution context with exchangeName and frameName
|
|
16746
17034
|
* @returns Promise that resolves when stop flag is set
|
|
16747
17035
|
*
|
|
16748
17036
|
* @example
|
|
16749
17037
|
* ```typescript
|
|
16750
17038
|
* // Stop strategy after some condition
|
|
16751
|
-
* await Backtest.stop("BTCUSDT", "my-strategy"
|
|
17039
|
+
* await Backtest.stop("BTCUSDT", "my-strategy", {
|
|
17040
|
+
* exchangeName: "binance",
|
|
17041
|
+
* frameName: "frame1",
|
|
17042
|
+
* strategyName: "my-strategy"
|
|
17043
|
+
* });
|
|
16752
17044
|
* ```
|
|
16753
17045
|
*/
|
|
16754
|
-
this.stop = async (symbol,
|
|
16755
|
-
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_STOP);
|
|
17046
|
+
this.stop = async (symbol, context) => {
|
|
17047
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_STOP);
|
|
16756
17048
|
{
|
|
16757
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17049
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16758
17050
|
riskName &&
|
|
16759
17051
|
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP);
|
|
16760
17052
|
riskList &&
|
|
16761
17053
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_STOP));
|
|
16762
17054
|
}
|
|
16763
|
-
await backtest$1.strategyCoreService.stop(true,
|
|
17055
|
+
await backtest$1.strategyCoreService.stop(true, symbol, context);
|
|
16764
17056
|
};
|
|
16765
17057
|
/**
|
|
16766
17058
|
* Cancels the scheduled signal without stopping the strategy.
|
|
@@ -16771,102 +17063,126 @@ class BacktestUtils {
|
|
|
16771
17063
|
*
|
|
16772
17064
|
* @param symbol - Trading pair symbol
|
|
16773
17065
|
* @param strategyName - Strategy name
|
|
17066
|
+
* @param context - Execution context with exchangeName and frameName
|
|
16774
17067
|
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
16775
17068
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
16776
17069
|
*
|
|
16777
17070
|
* @example
|
|
16778
17071
|
* ```typescript
|
|
16779
17072
|
* // Cancel scheduled signal with custom ID
|
|
16780
|
-
* await Backtest.cancel("BTCUSDT", "my-strategy",
|
|
17073
|
+
* await Backtest.cancel("BTCUSDT", "my-strategy", {
|
|
17074
|
+
* exchangeName: "binance",
|
|
17075
|
+
* frameName: "frame1",
|
|
17076
|
+
* strategyName: "my-strategy"
|
|
17077
|
+
* }, "manual-cancel-001");
|
|
16781
17078
|
* ```
|
|
16782
17079
|
*/
|
|
16783
|
-
this.cancel = async (symbol,
|
|
16784
|
-
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_CANCEL);
|
|
17080
|
+
this.cancel = async (symbol, context, cancelId) => {
|
|
17081
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_CANCEL);
|
|
16785
17082
|
{
|
|
16786
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17083
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16787
17084
|
riskName &&
|
|
16788
17085
|
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL);
|
|
16789
17086
|
riskList &&
|
|
16790
17087
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_CANCEL));
|
|
16791
17088
|
}
|
|
16792
|
-
await backtest$1.strategyCoreService.cancel(true,
|
|
17089
|
+
await backtest$1.strategyCoreService.cancel(true, symbol, context, cancelId);
|
|
16793
17090
|
};
|
|
16794
17091
|
/**
|
|
16795
17092
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
16796
17093
|
*
|
|
16797
17094
|
* @param symbol - Trading pair symbol
|
|
16798
17095
|
* @param strategyName - Strategy name to get data for
|
|
17096
|
+
* @param context - Execution context with exchangeName and frameName
|
|
16799
17097
|
* @returns Promise resolving to statistical data object
|
|
16800
17098
|
*
|
|
16801
17099
|
* @example
|
|
16802
17100
|
* ```typescript
|
|
16803
|
-
* const stats = await Backtest.getData("BTCUSDT", "my-strategy"
|
|
17101
|
+
* const stats = await Backtest.getData("BTCUSDT", "my-strategy", {
|
|
17102
|
+
* exchangeName: "binance",
|
|
17103
|
+
* frameName: "frame1",
|
|
17104
|
+
* strategyName: "my-strategy"
|
|
17105
|
+
* });
|
|
16804
17106
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
16805
17107
|
* ```
|
|
16806
17108
|
*/
|
|
16807
|
-
this.getData = async (symbol,
|
|
16808
|
-
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_DATA);
|
|
17109
|
+
this.getData = async (symbol, context) => {
|
|
17110
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_DATA);
|
|
16809
17111
|
{
|
|
16810
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17112
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16811
17113
|
riskName &&
|
|
16812
17114
|
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA);
|
|
16813
17115
|
riskList &&
|
|
16814
17116
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_DATA));
|
|
16815
17117
|
}
|
|
16816
|
-
return await backtest$1.backtestMarkdownService.getData(symbol, strategyName, true);
|
|
17118
|
+
return await backtest$1.backtestMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, true);
|
|
16817
17119
|
};
|
|
16818
17120
|
/**
|
|
16819
17121
|
* Generates markdown report with all closed signals for a symbol-strategy pair.
|
|
16820
17122
|
*
|
|
16821
17123
|
* @param symbol - Trading pair symbol
|
|
16822
17124
|
* @param strategyName - Strategy name to generate report for
|
|
17125
|
+
* @param context - Execution context with exchangeName and frameName
|
|
16823
17126
|
* @param columns - Optional columns configuration for the report
|
|
16824
17127
|
* @returns Promise resolving to markdown formatted report string
|
|
16825
17128
|
*
|
|
16826
17129
|
* @example
|
|
16827
17130
|
* ```typescript
|
|
16828
|
-
* const markdown = await Backtest.getReport("BTCUSDT", "my-strategy"
|
|
17131
|
+
* const markdown = await Backtest.getReport("BTCUSDT", "my-strategy", {
|
|
17132
|
+
* exchangeName: "binance",
|
|
17133
|
+
* frameName: "frame1",
|
|
17134
|
+
* strategyName: "my-strategy"
|
|
17135
|
+
* });
|
|
16829
17136
|
* console.log(markdown);
|
|
16830
17137
|
* ```
|
|
16831
17138
|
*/
|
|
16832
|
-
this.getReport = async (symbol,
|
|
16833
|
-
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
|
|
17139
|
+
this.getReport = async (symbol, context, columns) => {
|
|
17140
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_REPORT);
|
|
16834
17141
|
{
|
|
16835
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17142
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16836
17143
|
riskName &&
|
|
16837
17144
|
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT);
|
|
16838
17145
|
riskList &&
|
|
16839
17146
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_REPORT));
|
|
16840
17147
|
}
|
|
16841
|
-
return await backtest$1.backtestMarkdownService.getReport(symbol, strategyName, true, columns);
|
|
17148
|
+
return await backtest$1.backtestMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, true, columns);
|
|
16842
17149
|
};
|
|
16843
17150
|
/**
|
|
16844
17151
|
* Saves strategy report to disk.
|
|
16845
17152
|
*
|
|
16846
17153
|
* @param symbol - Trading pair symbol
|
|
16847
17154
|
* @param strategyName - Strategy name to save report for
|
|
17155
|
+
* @param context - Execution context with exchangeName and frameName
|
|
16848
17156
|
* @param path - Optional directory path to save report (default: "./dump/backtest")
|
|
16849
17157
|
* @param columns - Optional columns configuration for the report
|
|
16850
17158
|
*
|
|
16851
17159
|
* @example
|
|
16852
17160
|
* ```typescript
|
|
16853
17161
|
* // Save to default path: ./dump/backtest/my-strategy.md
|
|
16854
|
-
* await Backtest.dump("BTCUSDT", "my-strategy"
|
|
17162
|
+
* await Backtest.dump("BTCUSDT", "my-strategy", {
|
|
17163
|
+
* exchangeName: "binance",
|
|
17164
|
+
* frameName: "frame1",
|
|
17165
|
+
* strategyName: "my-strategy"
|
|
17166
|
+
* });
|
|
16855
17167
|
*
|
|
16856
17168
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
16857
|
-
* await Backtest.dump("BTCUSDT", "my-strategy",
|
|
17169
|
+
* await Backtest.dump("BTCUSDT", "my-strategy", {
|
|
17170
|
+
* exchangeName: "binance",
|
|
17171
|
+
* frameName: "frame1",
|
|
17172
|
+
* strategyName: "my-strategy"
|
|
17173
|
+
* }, "./custom/path");
|
|
16858
17174
|
* ```
|
|
16859
17175
|
*/
|
|
16860
|
-
this.dump = async (symbol,
|
|
16861
|
-
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_DUMP);
|
|
17176
|
+
this.dump = async (symbol, context, path, columns) => {
|
|
17177
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_DUMP);
|
|
16862
17178
|
{
|
|
16863
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17179
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
16864
17180
|
riskName &&
|
|
16865
17181
|
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP);
|
|
16866
17182
|
riskList &&
|
|
16867
17183
|
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_DUMP));
|
|
16868
17184
|
}
|
|
16869
|
-
await backtest$1.backtestMarkdownService.dump(symbol, strategyName, true, path, columns);
|
|
17185
|
+
await backtest$1.backtestMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, true, path, columns);
|
|
16870
17186
|
};
|
|
16871
17187
|
/**
|
|
16872
17188
|
* Lists all active backtest instances with their current status.
|
|
@@ -17041,20 +17357,36 @@ class LiveInstance {
|
|
|
17041
17357
|
context,
|
|
17042
17358
|
});
|
|
17043
17359
|
{
|
|
17044
|
-
backtest$1.backtestMarkdownService.clear(
|
|
17045
|
-
backtest$1.liveMarkdownService.clear(
|
|
17046
|
-
backtest$1.scheduleMarkdownService.clear(
|
|
17047
|
-
backtest$1.performanceMarkdownService.clear(
|
|
17048
|
-
backtest$1.partialMarkdownService.clear(
|
|
17049
|
-
backtest$1.riskMarkdownService.clear(
|
|
17360
|
+
backtest$1.backtestMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
|
|
17361
|
+
backtest$1.liveMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
|
|
17362
|
+
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
|
|
17363
|
+
backtest$1.performanceMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
|
|
17364
|
+
backtest$1.partialMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
|
|
17365
|
+
backtest$1.riskMarkdownService.clear({ symbol, strategyName: context.strategyName, exchangeName: context.exchangeName, frameName: "", backtest: false });
|
|
17050
17366
|
}
|
|
17051
17367
|
{
|
|
17052
|
-
backtest$1.strategyCoreService.clear(
|
|
17368
|
+
backtest$1.strategyCoreService.clear({
|
|
17369
|
+
symbol,
|
|
17370
|
+
strategyName: context.strategyName,
|
|
17371
|
+
exchangeName: context.exchangeName,
|
|
17372
|
+
frameName: "",
|
|
17373
|
+
backtest: false,
|
|
17374
|
+
});
|
|
17053
17375
|
}
|
|
17054
17376
|
{
|
|
17055
17377
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17056
|
-
riskName && backtest$1.riskGlobalService.clear(
|
|
17057
|
-
|
|
17378
|
+
riskName && backtest$1.riskGlobalService.clear({
|
|
17379
|
+
riskName,
|
|
17380
|
+
exchangeName: context.exchangeName,
|
|
17381
|
+
frameName: "",
|
|
17382
|
+
backtest: false
|
|
17383
|
+
});
|
|
17384
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
|
|
17385
|
+
riskName,
|
|
17386
|
+
exchangeName: context.exchangeName,
|
|
17387
|
+
frameName: "",
|
|
17388
|
+
backtest: false
|
|
17389
|
+
}));
|
|
17058
17390
|
}
|
|
17059
17391
|
return backtest$1.liveCommandService.run(symbol, context);
|
|
17060
17392
|
};
|
|
@@ -17094,9 +17426,17 @@ class LiveInstance {
|
|
|
17094
17426
|
}
|
|
17095
17427
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
17096
17428
|
return () => {
|
|
17097
|
-
backtest$1.strategyCoreService.stop(false,
|
|
17429
|
+
backtest$1.strategyCoreService.stop(false, symbol, {
|
|
17430
|
+
strategyName: context.strategyName,
|
|
17431
|
+
exchangeName: context.exchangeName,
|
|
17432
|
+
frameName: ""
|
|
17433
|
+
});
|
|
17098
17434
|
backtest$1.strategyCoreService
|
|
17099
|
-
.getPendingSignal(false, symbol,
|
|
17435
|
+
.getPendingSignal(false, symbol, {
|
|
17436
|
+
strategyName: context.strategyName,
|
|
17437
|
+
exchangeName: context.exchangeName,
|
|
17438
|
+
frameName: "",
|
|
17439
|
+
})
|
|
17100
17440
|
.then(async (pendingSignal) => {
|
|
17101
17441
|
if (pendingSignal) {
|
|
17102
17442
|
return;
|
|
@@ -17223,14 +17563,18 @@ class LiveUtils {
|
|
|
17223
17563
|
* }
|
|
17224
17564
|
* ```
|
|
17225
17565
|
*/
|
|
17226
|
-
this.getPendingSignal = async (symbol,
|
|
17227
|
-
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
17566
|
+
this.getPendingSignal = async (symbol, context) => {
|
|
17567
|
+
backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
17228
17568
|
{
|
|
17229
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17569
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17230
17570
|
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
17231
17571
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL));
|
|
17232
17572
|
}
|
|
17233
|
-
return await backtest$1.strategyCoreService.getPendingSignal(false, symbol,
|
|
17573
|
+
return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, {
|
|
17574
|
+
strategyName: context.strategyName,
|
|
17575
|
+
exchangeName: context.exchangeName,
|
|
17576
|
+
frameName: "",
|
|
17577
|
+
});
|
|
17234
17578
|
};
|
|
17235
17579
|
/**
|
|
17236
17580
|
* Retrieves the currently active scheduled signal for the strategy.
|
|
@@ -17248,14 +17592,18 @@ class LiveUtils {
|
|
|
17248
17592
|
* }
|
|
17249
17593
|
* ```
|
|
17250
17594
|
*/
|
|
17251
|
-
this.getScheduledSignal = async (symbol,
|
|
17252
|
-
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17595
|
+
this.getScheduledSignal = async (symbol, context) => {
|
|
17596
|
+
backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17253
17597
|
{
|
|
17254
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17598
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17255
17599
|
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17256
17600
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL));
|
|
17257
17601
|
}
|
|
17258
|
-
return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol,
|
|
17602
|
+
return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, {
|
|
17603
|
+
strategyName: context.strategyName,
|
|
17604
|
+
exchangeName: context.exchangeName,
|
|
17605
|
+
frameName: "",
|
|
17606
|
+
});
|
|
17259
17607
|
};
|
|
17260
17608
|
/**
|
|
17261
17609
|
* Stops the strategy from generating new signals.
|
|
@@ -17274,14 +17622,18 @@ class LiveUtils {
|
|
|
17274
17622
|
* await Live.stop("BTCUSDT", "my-strategy");
|
|
17275
17623
|
* ```
|
|
17276
17624
|
*/
|
|
17277
|
-
this.stop = async (symbol,
|
|
17278
|
-
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_STOP);
|
|
17625
|
+
this.stop = async (symbol, context) => {
|
|
17626
|
+
backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_STOP);
|
|
17279
17627
|
{
|
|
17280
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17628
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17281
17629
|
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP);
|
|
17282
17630
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_STOP));
|
|
17283
17631
|
}
|
|
17284
|
-
await backtest$1.strategyCoreService.stop(false,
|
|
17632
|
+
await backtest$1.strategyCoreService.stop(false, symbol, {
|
|
17633
|
+
strategyName: context.strategyName,
|
|
17634
|
+
exchangeName: context.exchangeName,
|
|
17635
|
+
frameName: "",
|
|
17636
|
+
});
|
|
17285
17637
|
};
|
|
17286
17638
|
/**
|
|
17287
17639
|
* Cancels the scheduled signal without stopping the strategy.
|
|
@@ -17292,94 +17644,122 @@ class LiveUtils {
|
|
|
17292
17644
|
*
|
|
17293
17645
|
* @param symbol - Trading pair symbol
|
|
17294
17646
|
* @param strategyName - Strategy name
|
|
17647
|
+
* @param context - Execution context with exchangeName and frameName
|
|
17295
17648
|
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
17296
17649
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
17297
17650
|
*
|
|
17298
17651
|
* @example
|
|
17299
17652
|
* ```typescript
|
|
17300
17653
|
* // Cancel scheduled signal in live trading with custom ID
|
|
17301
|
-
* await Live.cancel("BTCUSDT", "my-strategy",
|
|
17654
|
+
* await Live.cancel("BTCUSDT", "my-strategy", {
|
|
17655
|
+
* exchangeName: "binance",
|
|
17656
|
+
* frameName: "",
|
|
17657
|
+
* strategyName: "my-strategy"
|
|
17658
|
+
* }, "manual-cancel-001");
|
|
17302
17659
|
* ```
|
|
17303
17660
|
*/
|
|
17304
|
-
this.cancel = async (symbol,
|
|
17305
|
-
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_CANCEL);
|
|
17661
|
+
this.cancel = async (symbol, context, cancelId) => {
|
|
17662
|
+
backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_CANCEL);
|
|
17306
17663
|
{
|
|
17307
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17664
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17308
17665
|
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL);
|
|
17309
17666
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL));
|
|
17310
17667
|
}
|
|
17311
|
-
await backtest$1.strategyCoreService.cancel(false,
|
|
17668
|
+
await backtest$1.strategyCoreService.cancel(false, symbol, {
|
|
17669
|
+
strategyName: context.strategyName,
|
|
17670
|
+
exchangeName: context.exchangeName,
|
|
17671
|
+
frameName: "",
|
|
17672
|
+
}, cancelId);
|
|
17312
17673
|
};
|
|
17313
17674
|
/**
|
|
17314
17675
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
17315
17676
|
*
|
|
17316
17677
|
* @param symbol - Trading pair symbol
|
|
17317
17678
|
* @param strategyName - Strategy name to get data for
|
|
17679
|
+
* @param context - Execution context with exchangeName and frameName
|
|
17318
17680
|
* @returns Promise resolving to statistical data object
|
|
17319
17681
|
*
|
|
17320
17682
|
* @example
|
|
17321
17683
|
* ```typescript
|
|
17322
|
-
* const stats = await Live.getData("BTCUSDT", "my-strategy"
|
|
17684
|
+
* const stats = await Live.getData("BTCUSDT", "my-strategy", {
|
|
17685
|
+
* exchangeName: "binance",
|
|
17686
|
+
* frameName: "",
|
|
17687
|
+
* strategyName: "my-strategy"
|
|
17688
|
+
* });
|
|
17323
17689
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
17324
17690
|
* ```
|
|
17325
17691
|
*/
|
|
17326
|
-
this.getData = async (symbol,
|
|
17327
|
-
backtest$1.strategyValidationService.validate(strategyName, "LiveUtils.getData");
|
|
17692
|
+
this.getData = async (symbol, context) => {
|
|
17693
|
+
backtest$1.strategyValidationService.validate(context.strategyName, "LiveUtils.getData");
|
|
17328
17694
|
{
|
|
17329
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17695
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17330
17696
|
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA);
|
|
17331
17697
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_DATA));
|
|
17332
17698
|
}
|
|
17333
|
-
return await backtest$1.liveMarkdownService.getData(symbol, strategyName, false);
|
|
17699
|
+
return await backtest$1.liveMarkdownService.getData(symbol, context.strategyName, context.exchangeName, "", false);
|
|
17334
17700
|
};
|
|
17335
17701
|
/**
|
|
17336
17702
|
* Generates markdown report with all events for a symbol-strategy pair.
|
|
17337
17703
|
*
|
|
17338
17704
|
* @param symbol - Trading pair symbol
|
|
17339
17705
|
* @param strategyName - Strategy name to generate report for
|
|
17706
|
+
* @param context - Execution context with exchangeName and frameName
|
|
17340
17707
|
* @param columns - Optional columns configuration for the report
|
|
17341
17708
|
* @returns Promise resolving to markdown formatted report string
|
|
17342
17709
|
*
|
|
17343
17710
|
* @example
|
|
17344
17711
|
* ```typescript
|
|
17345
|
-
* const markdown = await Live.getReport("BTCUSDT", "my-strategy"
|
|
17712
|
+
* const markdown = await Live.getReport("BTCUSDT", "my-strategy", {
|
|
17713
|
+
* exchangeName: "binance",
|
|
17714
|
+
* frameName: "",
|
|
17715
|
+
* strategyName: "my-strategy"
|
|
17716
|
+
* });
|
|
17346
17717
|
* console.log(markdown);
|
|
17347
17718
|
* ```
|
|
17348
17719
|
*/
|
|
17349
|
-
this.getReport = async (symbol,
|
|
17350
|
-
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_REPORT);
|
|
17720
|
+
this.getReport = async (symbol, context, columns) => {
|
|
17721
|
+
backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_REPORT);
|
|
17351
17722
|
{
|
|
17352
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17723
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17353
17724
|
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT);
|
|
17354
17725
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_REPORT));
|
|
17355
17726
|
}
|
|
17356
|
-
return await backtest$1.liveMarkdownService.getReport(symbol, strategyName, false, columns);
|
|
17727
|
+
return await backtest$1.liveMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, "", false, columns);
|
|
17357
17728
|
};
|
|
17358
17729
|
/**
|
|
17359
17730
|
* Saves strategy report to disk.
|
|
17360
17731
|
*
|
|
17361
17732
|
* @param symbol - Trading pair symbol
|
|
17362
17733
|
* @param strategyName - Strategy name to save report for
|
|
17734
|
+
* @param context - Execution context with exchangeName and frameName
|
|
17363
17735
|
* @param path - Optional directory path to save report (default: "./dump/live")
|
|
17364
17736
|
* @param columns - Optional columns configuration for the report
|
|
17365
17737
|
*
|
|
17366
17738
|
* @example
|
|
17367
17739
|
* ```typescript
|
|
17368
17740
|
* // Save to default path: ./dump/live/my-strategy.md
|
|
17369
|
-
* await Live.dump("BTCUSDT", "my-strategy"
|
|
17741
|
+
* await Live.dump("BTCUSDT", "my-strategy", {
|
|
17742
|
+
* exchangeName: "binance",
|
|
17743
|
+
* frameName: "",
|
|
17744
|
+
* strategyName: "my-strategy"
|
|
17745
|
+
* });
|
|
17370
17746
|
*
|
|
17371
17747
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
17372
|
-
* await Live.dump("BTCUSDT", "my-strategy",
|
|
17748
|
+
* await Live.dump("BTCUSDT", "my-strategy", {
|
|
17749
|
+
* exchangeName: "binance",
|
|
17750
|
+
* frameName: "",
|
|
17751
|
+
* strategyName: "my-strategy"
|
|
17752
|
+
* }, "./custom/path");
|
|
17373
17753
|
* ```
|
|
17374
17754
|
*/
|
|
17375
|
-
this.dump = async (symbol,
|
|
17376
|
-
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_DUMP);
|
|
17755
|
+
this.dump = async (symbol, context, path, columns) => {
|
|
17756
|
+
backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_DUMP);
|
|
17377
17757
|
{
|
|
17378
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17758
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17379
17759
|
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP);
|
|
17380
17760
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_DUMP));
|
|
17381
17761
|
}
|
|
17382
|
-
await backtest$1.liveMarkdownService.dump(symbol, strategyName, false, path, columns);
|
|
17762
|
+
await backtest$1.liveMarkdownService.dump(symbol, context.strategyName, context.exchangeName, "", false, path, columns);
|
|
17383
17763
|
};
|
|
17384
17764
|
/**
|
|
17385
17765
|
* Lists all active live trading instances with their current status.
|
|
@@ -17460,19 +17840,19 @@ class ScheduleUtils {
|
|
|
17460
17840
|
* console.log(stats.cancellationRate, stats.avgWaitTime);
|
|
17461
17841
|
* ```
|
|
17462
17842
|
*/
|
|
17463
|
-
this.getData = async (symbol,
|
|
17843
|
+
this.getData = async (symbol, context, backtest = false) => {
|
|
17464
17844
|
backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_DATA, {
|
|
17465
17845
|
symbol,
|
|
17466
|
-
strategyName,
|
|
17846
|
+
strategyName: context.strategyName,
|
|
17467
17847
|
backtest,
|
|
17468
17848
|
});
|
|
17469
|
-
backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
|
|
17849
|
+
backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_DATA);
|
|
17470
17850
|
{
|
|
17471
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17851
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17472
17852
|
riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA);
|
|
17473
17853
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_DATA));
|
|
17474
17854
|
}
|
|
17475
|
-
return await backtest$1.scheduleMarkdownService.getData(symbol, strategyName, backtest);
|
|
17855
|
+
return await backtest$1.scheduleMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
17476
17856
|
};
|
|
17477
17857
|
/**
|
|
17478
17858
|
* Generates markdown report with all scheduled events for a symbol-strategy pair.
|
|
@@ -17488,19 +17868,19 @@ class ScheduleUtils {
|
|
|
17488
17868
|
* console.log(markdown);
|
|
17489
17869
|
* ```
|
|
17490
17870
|
*/
|
|
17491
|
-
this.getReport = async (symbol,
|
|
17871
|
+
this.getReport = async (symbol, context, backtest = false, columns) => {
|
|
17492
17872
|
backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_REPORT, {
|
|
17493
17873
|
symbol,
|
|
17494
|
-
strategyName,
|
|
17874
|
+
strategyName: context.strategyName,
|
|
17495
17875
|
backtest,
|
|
17496
17876
|
});
|
|
17497
|
-
backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
|
|
17877
|
+
backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_GET_REPORT);
|
|
17498
17878
|
{
|
|
17499
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17879
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17500
17880
|
riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT);
|
|
17501
17881
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_GET_REPORT));
|
|
17502
17882
|
}
|
|
17503
|
-
return await backtest$1.scheduleMarkdownService.getReport(symbol, strategyName, backtest, columns);
|
|
17883
|
+
return await backtest$1.scheduleMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
17504
17884
|
};
|
|
17505
17885
|
/**
|
|
17506
17886
|
* Saves strategy report to disk.
|
|
@@ -17519,20 +17899,20 @@ class ScheduleUtils {
|
|
|
17519
17899
|
* await Schedule.dump("BTCUSDT", "my-strategy", "./custom/path");
|
|
17520
17900
|
* ```
|
|
17521
17901
|
*/
|
|
17522
|
-
this.dump = async (symbol,
|
|
17902
|
+
this.dump = async (symbol, context, backtest = false, path, columns) => {
|
|
17523
17903
|
backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_DUMP, {
|
|
17524
17904
|
symbol,
|
|
17525
|
-
strategyName,
|
|
17905
|
+
strategyName: context.strategyName,
|
|
17526
17906
|
backtest,
|
|
17527
17907
|
path,
|
|
17528
17908
|
});
|
|
17529
|
-
backtest$1.strategyValidationService.validate(strategyName, SCHEDULE_METHOD_NAME_DUMP);
|
|
17909
|
+
backtest$1.strategyValidationService.validate(context.strategyName, SCHEDULE_METHOD_NAME_DUMP);
|
|
17530
17910
|
{
|
|
17531
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17911
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17532
17912
|
riskName && backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP);
|
|
17533
17913
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, SCHEDULE_METHOD_NAME_DUMP));
|
|
17534
17914
|
}
|
|
17535
|
-
await backtest$1.scheduleMarkdownService.dump(symbol, strategyName, backtest, path, columns);
|
|
17915
|
+
await backtest$1.scheduleMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
17536
17916
|
};
|
|
17537
17917
|
}
|
|
17538
17918
|
}
|
|
@@ -17613,14 +17993,14 @@ class Performance {
|
|
|
17613
17993
|
* }
|
|
17614
17994
|
* ```
|
|
17615
17995
|
*/
|
|
17616
|
-
static async getData(symbol,
|
|
17617
|
-
backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
|
|
17996
|
+
static async getData(symbol, context, backtest = false) {
|
|
17997
|
+
backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_DATA);
|
|
17618
17998
|
{
|
|
17619
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17999
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17620
18000
|
riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA);
|
|
17621
18001
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_DATA));
|
|
17622
18002
|
}
|
|
17623
|
-
return backtest$1.performanceMarkdownService.getData(symbol, strategyName, backtest);
|
|
18003
|
+
return backtest$1.performanceMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
17624
18004
|
}
|
|
17625
18005
|
/**
|
|
17626
18006
|
* Generates markdown report with performance analysis.
|
|
@@ -17645,14 +18025,14 @@ class Performance {
|
|
|
17645
18025
|
* await fs.writeFile("performance-report.md", markdown);
|
|
17646
18026
|
* ```
|
|
17647
18027
|
*/
|
|
17648
|
-
static async getReport(symbol,
|
|
17649
|
-
backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
|
|
18028
|
+
static async getReport(symbol, context, backtest = false, columns) {
|
|
18029
|
+
backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_GET_REPORT);
|
|
17650
18030
|
{
|
|
17651
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18031
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17652
18032
|
riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT);
|
|
17653
18033
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_GET_REPORT));
|
|
17654
18034
|
}
|
|
17655
|
-
return backtest$1.performanceMarkdownService.getReport(symbol, strategyName, backtest, columns);
|
|
18035
|
+
return backtest$1.performanceMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
17656
18036
|
}
|
|
17657
18037
|
/**
|
|
17658
18038
|
* Saves performance report to disk.
|
|
@@ -17674,14 +18054,14 @@ class Performance {
|
|
|
17674
18054
|
* await Performance.dump("BTCUSDT", "my-strategy", "./reports/perf");
|
|
17675
18055
|
* ```
|
|
17676
18056
|
*/
|
|
17677
|
-
static async dump(symbol,
|
|
17678
|
-
backtest$1.strategyValidationService.validate(strategyName, PERFORMANCE_METHOD_NAME_DUMP);
|
|
18057
|
+
static async dump(symbol, context, backtest = false, path = "./dump/performance", columns) {
|
|
18058
|
+
backtest$1.strategyValidationService.validate(context.strategyName, PERFORMANCE_METHOD_NAME_DUMP);
|
|
17679
18059
|
{
|
|
17680
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18060
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
17681
18061
|
riskName && backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP);
|
|
17682
18062
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PERFORMANCE_METHOD_NAME_DUMP));
|
|
17683
18063
|
}
|
|
17684
|
-
return backtest$1.performanceMarkdownService.dump(symbol, strategyName, backtest, path, columns);
|
|
18064
|
+
return backtest$1.performanceMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
17685
18065
|
}
|
|
17686
18066
|
}
|
|
17687
18067
|
|
|
@@ -17819,21 +18199,37 @@ class WalkerInstance {
|
|
|
17819
18199
|
// Clear backtest data for all strategies
|
|
17820
18200
|
for (const strategyName of walkerSchema.strategies) {
|
|
17821
18201
|
{
|
|
17822
|
-
backtest$1.backtestMarkdownService.clear(
|
|
17823
|
-
backtest$1.liveMarkdownService.clear(
|
|
17824
|
-
backtest$1.scheduleMarkdownService.clear(
|
|
17825
|
-
backtest$1.performanceMarkdownService.clear(
|
|
17826
|
-
backtest$1.partialMarkdownService.clear(
|
|
17827
|
-
backtest$1.riskMarkdownService.clear(
|
|
18202
|
+
backtest$1.backtestMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
|
|
18203
|
+
backtest$1.liveMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
|
|
18204
|
+
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
|
|
18205
|
+
backtest$1.performanceMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
|
|
18206
|
+
backtest$1.partialMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
|
|
18207
|
+
backtest$1.riskMarkdownService.clear({ symbol, strategyName, exchangeName: walkerSchema.exchangeName, frameName: walkerSchema.frameName, backtest: true });
|
|
17828
18208
|
}
|
|
17829
18209
|
{
|
|
17830
|
-
backtest$1.strategyCoreService.clear(
|
|
18210
|
+
backtest$1.strategyCoreService.clear({
|
|
18211
|
+
symbol,
|
|
18212
|
+
strategyName,
|
|
18213
|
+
exchangeName: walkerSchema.exchangeName,
|
|
18214
|
+
frameName: walkerSchema.frameName,
|
|
18215
|
+
backtest: true,
|
|
18216
|
+
});
|
|
17831
18217
|
}
|
|
17832
18218
|
{
|
|
17833
18219
|
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17834
|
-
riskName && backtest$1.riskGlobalService.clear(
|
|
18220
|
+
riskName && backtest$1.riskGlobalService.clear({
|
|
18221
|
+
riskName,
|
|
18222
|
+
exchangeName: walkerSchema.exchangeName,
|
|
18223
|
+
frameName: walkerSchema.frameName,
|
|
18224
|
+
backtest: true
|
|
18225
|
+
});
|
|
17835
18226
|
riskList &&
|
|
17836
|
-
riskList.forEach((riskName) => backtest$1.riskGlobalService.clear(
|
|
18227
|
+
riskList.forEach((riskName) => backtest$1.riskGlobalService.clear({
|
|
18228
|
+
riskName,
|
|
18229
|
+
exchangeName: walkerSchema.exchangeName,
|
|
18230
|
+
frameName: walkerSchema.frameName,
|
|
18231
|
+
backtest: true
|
|
18232
|
+
}));
|
|
17837
18233
|
}
|
|
17838
18234
|
}
|
|
17839
18235
|
return backtest$1.walkerCommandService.run(symbol, {
|
|
@@ -17878,7 +18274,11 @@ class WalkerInstance {
|
|
|
17878
18274
|
this.task(symbol, context).catch((error) => exitEmitter.next(new Error(functoolsKit.getErrorMessage(error))));
|
|
17879
18275
|
return () => {
|
|
17880
18276
|
for (const strategyName of walkerSchema.strategies) {
|
|
17881
|
-
backtest$1.strategyCoreService.stop(true,
|
|
18277
|
+
backtest$1.strategyCoreService.stop(true, symbol, {
|
|
18278
|
+
strategyName,
|
|
18279
|
+
exchangeName: walkerSchema.exchangeName,
|
|
18280
|
+
frameName: walkerSchema.frameName
|
|
18281
|
+
});
|
|
17882
18282
|
walkerStopSubject.next({
|
|
17883
18283
|
symbol,
|
|
17884
18284
|
strategyName,
|
|
@@ -18019,7 +18419,11 @@ class WalkerUtils {
|
|
|
18019
18419
|
}
|
|
18020
18420
|
for (const strategyName of walkerSchema.strategies) {
|
|
18021
18421
|
await walkerStopSubject.next({ symbol, strategyName, walkerName });
|
|
18022
|
-
await backtest$1.strategyCoreService.stop(true,
|
|
18422
|
+
await backtest$1.strategyCoreService.stop(true, symbol, {
|
|
18423
|
+
strategyName,
|
|
18424
|
+
exchangeName: walkerSchema.exchangeName,
|
|
18425
|
+
frameName: walkerSchema.frameName
|
|
18426
|
+
});
|
|
18023
18427
|
}
|
|
18024
18428
|
};
|
|
18025
18429
|
/**
|
|
@@ -18167,15 +18571,27 @@ const HEAT_METHOD_NAME_DUMP = "HeatUtils.dump";
|
|
|
18167
18571
|
* import { Heat } from "backtest-kit";
|
|
18168
18572
|
*
|
|
18169
18573
|
* // Get raw heatmap data for a strategy
|
|
18170
|
-
* const stats = await Heat.getData(
|
|
18574
|
+
* const stats = await Heat.getData({
|
|
18575
|
+
* strategyName: "my-strategy",
|
|
18576
|
+
* exchangeName: "binance",
|
|
18577
|
+
* frameName: "frame1"
|
|
18578
|
+
* });
|
|
18171
18579
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
18172
18580
|
*
|
|
18173
18581
|
* // Generate markdown report
|
|
18174
|
-
* const markdown = await Heat.getReport(
|
|
18582
|
+
* const markdown = await Heat.getReport({
|
|
18583
|
+
* strategyName: "my-strategy",
|
|
18584
|
+
* exchangeName: "binance",
|
|
18585
|
+
* frameName: "frame1"
|
|
18586
|
+
* });
|
|
18175
18587
|
* console.log(markdown);
|
|
18176
18588
|
*
|
|
18177
18589
|
* // Save to disk
|
|
18178
|
-
* await Heat.dump(
|
|
18590
|
+
* await Heat.dump({
|
|
18591
|
+
* strategyName: "my-strategy",
|
|
18592
|
+
* exchangeName: "binance",
|
|
18593
|
+
* frameName: "frame1"
|
|
18594
|
+
* }, false, "./reports");
|
|
18179
18595
|
* ```
|
|
18180
18596
|
*/
|
|
18181
18597
|
class HeatUtils {
|
|
@@ -18186,12 +18602,17 @@ class HeatUtils {
|
|
|
18186
18602
|
* Returns per-symbol breakdown and portfolio-wide metrics.
|
|
18187
18603
|
* Data is automatically collected from all closed signals for the strategy.
|
|
18188
18604
|
*
|
|
18189
|
-
* @param
|
|
18605
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18606
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18190
18607
|
* @returns Promise resolving to heatmap statistics object
|
|
18191
18608
|
*
|
|
18192
18609
|
* @example
|
|
18193
18610
|
* ```typescript
|
|
18194
|
-
* const stats = await Heat.getData(
|
|
18611
|
+
* const stats = await Heat.getData({
|
|
18612
|
+
* strategyName: "my-strategy",
|
|
18613
|
+
* exchangeName: "binance",
|
|
18614
|
+
* frameName: "frame1"
|
|
18615
|
+
* });
|
|
18195
18616
|
*
|
|
18196
18617
|
* console.log(`Total symbols: ${stats.totalSymbols}`);
|
|
18197
18618
|
* console.log(`Portfolio Total PNL: ${stats.portfolioTotalPnl}%`);
|
|
@@ -18203,15 +18624,15 @@ class HeatUtils {
|
|
|
18203
18624
|
* });
|
|
18204
18625
|
* ```
|
|
18205
18626
|
*/
|
|
18206
|
-
this.getData = async (
|
|
18207
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
|
|
18208
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_DATA);
|
|
18627
|
+
this.getData = async (context, backtest = false) => {
|
|
18628
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName: context.strategyName });
|
|
18629
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_DATA);
|
|
18209
18630
|
{
|
|
18210
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18631
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18211
18632
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
|
|
18212
18633
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
|
|
18213
18634
|
}
|
|
18214
|
-
return await backtest$1.heatMarkdownService.getData(
|
|
18635
|
+
return await backtest$1.heatMarkdownService.getData(context.exchangeName, context.frameName, backtest);
|
|
18215
18636
|
};
|
|
18216
18637
|
/**
|
|
18217
18638
|
* Generates markdown report with portfolio heatmap table for a strategy.
|
|
@@ -18219,13 +18640,18 @@ class HeatUtils {
|
|
|
18219
18640
|
* Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
|
|
18220
18641
|
* Symbols are sorted by Total PNL descending.
|
|
18221
18642
|
*
|
|
18222
|
-
* @param
|
|
18643
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18644
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18223
18645
|
* @param columns - Optional columns configuration for the report
|
|
18224
18646
|
* @returns Promise resolving to markdown formatted report string
|
|
18225
18647
|
*
|
|
18226
18648
|
* @example
|
|
18227
18649
|
* ```typescript
|
|
18228
|
-
* const markdown = await Heat.getReport(
|
|
18650
|
+
* const markdown = await Heat.getReport({
|
|
18651
|
+
* strategyName: "my-strategy",
|
|
18652
|
+
* exchangeName: "binance",
|
|
18653
|
+
* frameName: "frame1"
|
|
18654
|
+
* });
|
|
18229
18655
|
* console.log(markdown);
|
|
18230
18656
|
* // Output:
|
|
18231
18657
|
* // # Portfolio Heatmap: my-strategy
|
|
@@ -18239,15 +18665,15 @@ class HeatUtils {
|
|
|
18239
18665
|
* // ...
|
|
18240
18666
|
* ```
|
|
18241
18667
|
*/
|
|
18242
|
-
this.getReport = async (
|
|
18243
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
|
|
18244
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18668
|
+
this.getReport = async (context, backtest = false, columns) => {
|
|
18669
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName: context.strategyName });
|
|
18670
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18245
18671
|
{
|
|
18246
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18672
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18247
18673
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18248
18674
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
|
|
18249
18675
|
}
|
|
18250
|
-
return await backtest$1.heatMarkdownService.getReport(strategyName, backtest, columns);
|
|
18676
|
+
return await backtest$1.heatMarkdownService.getReport(context.strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
18251
18677
|
};
|
|
18252
18678
|
/**
|
|
18253
18679
|
* Saves heatmap report to disk for a strategy.
|
|
@@ -18255,28 +18681,37 @@ class HeatUtils {
|
|
|
18255
18681
|
* Creates directory if it doesn't exist.
|
|
18256
18682
|
* Default filename: {strategyName}.md
|
|
18257
18683
|
*
|
|
18258
|
-
* @param
|
|
18684
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18685
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18259
18686
|
* @param path - Optional directory path to save report (default: "./dump/heatmap")
|
|
18260
18687
|
* @param columns - Optional columns configuration for the report
|
|
18261
18688
|
*
|
|
18262
18689
|
* @example
|
|
18263
18690
|
* ```typescript
|
|
18264
18691
|
* // Save to default path: ./dump/heatmap/my-strategy.md
|
|
18265
|
-
* await Heat.dump(
|
|
18692
|
+
* await Heat.dump({
|
|
18693
|
+
* strategyName: "my-strategy",
|
|
18694
|
+
* exchangeName: "binance",
|
|
18695
|
+
* frameName: "frame1"
|
|
18696
|
+
* });
|
|
18266
18697
|
*
|
|
18267
18698
|
* // Save to custom path: ./reports/my-strategy.md
|
|
18268
|
-
* await Heat.dump(
|
|
18699
|
+
* await Heat.dump({
|
|
18700
|
+
* strategyName: "my-strategy",
|
|
18701
|
+
* exchangeName: "binance",
|
|
18702
|
+
* frameName: "frame1"
|
|
18703
|
+
* }, false, "./reports");
|
|
18269
18704
|
* ```
|
|
18270
18705
|
*/
|
|
18271
|
-
this.dump = async (
|
|
18272
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
|
|
18273
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_DUMP);
|
|
18706
|
+
this.dump = async (context, backtest = false, path, columns) => {
|
|
18707
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName: context.strategyName, path });
|
|
18708
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_DUMP);
|
|
18274
18709
|
{
|
|
18275
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18710
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18276
18711
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
|
|
18277
18712
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
|
|
18278
18713
|
}
|
|
18279
|
-
await backtest$1.heatMarkdownService.dump(strategyName, backtest, path, columns);
|
|
18714
|
+
await backtest$1.heatMarkdownService.dump(context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
18280
18715
|
};
|
|
18281
18716
|
}
|
|
18282
18717
|
}
|
|
@@ -18288,7 +18723,11 @@ class HeatUtils {
|
|
|
18288
18723
|
* import { Heat } from "backtest-kit";
|
|
18289
18724
|
*
|
|
18290
18725
|
* // Strategy-specific heatmap
|
|
18291
|
-
* const stats = await Heat.getData(
|
|
18726
|
+
* const stats = await Heat.getData({
|
|
18727
|
+
* strategyName: "my-strategy",
|
|
18728
|
+
* exchangeName: "binance",
|
|
18729
|
+
* frameName: "frame1"
|
|
18730
|
+
* });
|
|
18292
18731
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
18293
18732
|
* console.log(`Total Symbols: ${stats.totalSymbols}`);
|
|
18294
18733
|
*
|
|
@@ -18302,7 +18741,11 @@ class HeatUtils {
|
|
|
18302
18741
|
* });
|
|
18303
18742
|
*
|
|
18304
18743
|
* // Generate and save report
|
|
18305
|
-
* await Heat.dump(
|
|
18744
|
+
* await Heat.dump({
|
|
18745
|
+
* strategyName: "my-strategy",
|
|
18746
|
+
* exchangeName: "binance",
|
|
18747
|
+
* frameName: "frame1"
|
|
18748
|
+
* }, false, "./reports");
|
|
18306
18749
|
* ```
|
|
18307
18750
|
*/
|
|
18308
18751
|
const Heat = new HeatUtils();
|
|
@@ -18592,15 +19035,15 @@ class PartialUtils {
|
|
|
18592
19035
|
* }
|
|
18593
19036
|
* ```
|
|
18594
19037
|
*/
|
|
18595
|
-
this.getData = async (symbol,
|
|
18596
|
-
backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_DATA, { symbol, strategyName });
|
|
18597
|
-
backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_GET_DATA);
|
|
19038
|
+
this.getData = async (symbol, context, backtest = false) => {
|
|
19039
|
+
backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_DATA, { symbol, strategyName: context.strategyName });
|
|
19040
|
+
backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_DATA);
|
|
18598
19041
|
{
|
|
18599
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
19042
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18600
19043
|
riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA);
|
|
18601
19044
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_DATA));
|
|
18602
19045
|
}
|
|
18603
|
-
return await backtest$1.partialMarkdownService.getData(symbol, strategyName, backtest);
|
|
19046
|
+
return await backtest$1.partialMarkdownService.getData(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
18604
19047
|
};
|
|
18605
19048
|
/**
|
|
18606
19049
|
* Generates markdown report with all partial profit/loss events for a symbol-strategy pair.
|
|
@@ -18641,15 +19084,15 @@ class PartialUtils {
|
|
|
18641
19084
|
* // **Loss events:** 1
|
|
18642
19085
|
* ```
|
|
18643
19086
|
*/
|
|
18644
|
-
this.getReport = async (symbol,
|
|
18645
|
-
backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_REPORT, { symbol, strategyName });
|
|
18646
|
-
backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_GET_REPORT);
|
|
19087
|
+
this.getReport = async (symbol, context, backtest = false, columns) => {
|
|
19088
|
+
backtest$1.loggerService.info(PARTIAL_METHOD_NAME_GET_REPORT, { symbol, strategyName: context.strategyName });
|
|
19089
|
+
backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_GET_REPORT);
|
|
18647
19090
|
{
|
|
18648
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
19091
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18649
19092
|
riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT);
|
|
18650
19093
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_GET_REPORT));
|
|
18651
19094
|
}
|
|
18652
|
-
return await backtest$1.partialMarkdownService.getReport(symbol, strategyName, backtest, columns);
|
|
19095
|
+
return await backtest$1.partialMarkdownService.getReport(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
18653
19096
|
};
|
|
18654
19097
|
/**
|
|
18655
19098
|
* Generates and saves markdown report to file.
|
|
@@ -18683,15 +19126,15 @@ class PartialUtils {
|
|
|
18683
19126
|
* }
|
|
18684
19127
|
* ```
|
|
18685
19128
|
*/
|
|
18686
|
-
this.dump = async (symbol,
|
|
18687
|
-
backtest$1.loggerService.info(PARTIAL_METHOD_NAME_DUMP, { symbol, strategyName, path });
|
|
18688
|
-
backtest$1.strategyValidationService.validate(strategyName, PARTIAL_METHOD_NAME_DUMP);
|
|
19129
|
+
this.dump = async (symbol, context, backtest = false, path, columns) => {
|
|
19130
|
+
backtest$1.loggerService.info(PARTIAL_METHOD_NAME_DUMP, { symbol, strategyName: context.strategyName, path });
|
|
19131
|
+
backtest$1.strategyValidationService.validate(context.strategyName, PARTIAL_METHOD_NAME_DUMP);
|
|
18689
19132
|
{
|
|
18690
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
19133
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18691
19134
|
riskName && backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP);
|
|
18692
19135
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, PARTIAL_METHOD_NAME_DUMP));
|
|
18693
19136
|
}
|
|
18694
|
-
await backtest$1.partialMarkdownService.dump(symbol, strategyName, backtest, path, columns);
|
|
19137
|
+
await backtest$1.partialMarkdownService.dump(symbol, context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
18695
19138
|
};
|
|
18696
19139
|
}
|
|
18697
19140
|
}
|
|
@@ -19104,7 +19547,13 @@ const INTERVAL_MINUTES = {
|
|
|
19104
19547
|
* @param backtest - Whether running in backtest mode
|
|
19105
19548
|
* @returns Cache key string
|
|
19106
19549
|
*/
|
|
19107
|
-
const CREATE_KEY_FN$1 = (strategyName, exchangeName, backtest) =>
|
|
19550
|
+
const CREATE_KEY_FN$1 = (strategyName, exchangeName, frameName, backtest) => {
|
|
19551
|
+
const parts = [strategyName, exchangeName];
|
|
19552
|
+
if (frameName)
|
|
19553
|
+
parts.push(frameName);
|
|
19554
|
+
parts.push(backtest ? "backtest" : "live");
|
|
19555
|
+
return parts.join(":");
|
|
19556
|
+
};
|
|
19108
19557
|
/**
|
|
19109
19558
|
* Instance class for caching function results with timeframe-based invalidation.
|
|
19110
19559
|
*
|
|
@@ -19180,7 +19629,7 @@ class CacheInstance {
|
|
|
19180
19629
|
throw new Error(`CacheInstance unknown cache ttl interval=${this.interval}`);
|
|
19181
19630
|
}
|
|
19182
19631
|
}
|
|
19183
|
-
const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
|
|
19632
|
+
const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.methodContextService.context.frameName, backtest$1.executionContextService.context.backtest);
|
|
19184
19633
|
const currentWhen = backtest$1.executionContextService.context.when;
|
|
19185
19634
|
const cached = this._cacheMap.get(key);
|
|
19186
19635
|
if (cached) {
|
|
@@ -19218,7 +19667,7 @@ class CacheInstance {
|
|
|
19218
19667
|
* ```
|
|
19219
19668
|
*/
|
|
19220
19669
|
this.clear = () => {
|
|
19221
|
-
const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.executionContextService.context.backtest);
|
|
19670
|
+
const key = CREATE_KEY_FN$1(backtest$1.methodContextService.context.strategyName, backtest$1.methodContextService.context.exchangeName, backtest$1.methodContextService.context.frameName, backtest$1.executionContextService.context.backtest);
|
|
19222
19671
|
this._cacheMap.delete(key);
|
|
19223
19672
|
};
|
|
19224
19673
|
}
|