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