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