backtest-kit 1.4.6 → 1.4.8
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 +345 -245
- package/build/index.mjs +345 -245
- package/package.json +1 -1
- package/types.d.ts +175 -196
package/build/index.mjs
CHANGED
|
@@ -1214,24 +1214,25 @@ const PersistBase = makeExtendable(class {
|
|
|
1214
1214
|
class PersistSignalUtils {
|
|
1215
1215
|
constructor() {
|
|
1216
1216
|
this.PersistSignalFactory = PersistBase;
|
|
1217
|
-
this.getSignalStorage = memoize(([strategyName]) => `${strategyName}`, (strategyName) => Reflect.construct(this.PersistSignalFactory, [
|
|
1218
|
-
strategyName
|
|
1217
|
+
this.getSignalStorage = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => Reflect.construct(this.PersistSignalFactory, [
|
|
1218
|
+
`${symbol}_${strategyName}`,
|
|
1219
1219
|
`./dump/data/signal/`,
|
|
1220
1220
|
]));
|
|
1221
1221
|
/**
|
|
1222
|
-
* Reads persisted signal data for a
|
|
1222
|
+
* Reads persisted signal data for a symbol and strategy.
|
|
1223
1223
|
*
|
|
1224
1224
|
* Called by ClientStrategy.waitForInit() to restore state.
|
|
1225
1225
|
* Returns null if no signal exists.
|
|
1226
1226
|
*
|
|
1227
|
-
* @param strategyName - Strategy identifier
|
|
1228
1227
|
* @param symbol - Trading pair symbol
|
|
1228
|
+
* @param strategyName - Strategy identifier
|
|
1229
1229
|
* @returns Promise resolving to signal or null
|
|
1230
1230
|
*/
|
|
1231
|
-
this.readSignalData = async (
|
|
1231
|
+
this.readSignalData = async (symbol, strategyName) => {
|
|
1232
1232
|
backtest$1.loggerService.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_READ_DATA);
|
|
1233
|
-
const
|
|
1234
|
-
const
|
|
1233
|
+
const key = `${symbol}:${strategyName}`;
|
|
1234
|
+
const isInitial = !this.getSignalStorage.has(key);
|
|
1235
|
+
const stateStorage = this.getSignalStorage(symbol, strategyName);
|
|
1235
1236
|
await stateStorage.waitForInit(isInitial);
|
|
1236
1237
|
if (await stateStorage.hasValue(symbol)) {
|
|
1237
1238
|
return await stateStorage.readValue(symbol);
|
|
@@ -1245,14 +1246,15 @@ class PersistSignalUtils {
|
|
|
1245
1246
|
* Uses atomic writes to prevent corruption on crashes.
|
|
1246
1247
|
*
|
|
1247
1248
|
* @param signalRow - Signal data (null to clear)
|
|
1248
|
-
* @param strategyName - Strategy identifier
|
|
1249
1249
|
* @param symbol - Trading pair symbol
|
|
1250
|
+
* @param strategyName - Strategy identifier
|
|
1250
1251
|
* @returns Promise that resolves when write is complete
|
|
1251
1252
|
*/
|
|
1252
|
-
this.writeSignalData = async (signalRow,
|
|
1253
|
+
this.writeSignalData = async (signalRow, symbol, strategyName) => {
|
|
1253
1254
|
backtest$1.loggerService.info(PERSIST_SIGNAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1254
|
-
const
|
|
1255
|
-
const
|
|
1255
|
+
const key = `${symbol}:${strategyName}`;
|
|
1256
|
+
const isInitial = !this.getSignalStorage.has(key);
|
|
1257
|
+
const stateStorage = this.getSignalStorage(symbol, strategyName);
|
|
1256
1258
|
await stateStorage.waitForInit(isInitial);
|
|
1257
1259
|
await stateStorage.writeValue(symbol, signalRow);
|
|
1258
1260
|
};
|
|
@@ -1403,24 +1405,25 @@ const PersistRiskAdapter = new PersistRiskUtils();
|
|
|
1403
1405
|
class PersistScheduleUtils {
|
|
1404
1406
|
constructor() {
|
|
1405
1407
|
this.PersistScheduleFactory = PersistBase;
|
|
1406
|
-
this.getScheduleStorage = memoize(([strategyName]) => `${strategyName}`, (strategyName) => Reflect.construct(this.PersistScheduleFactory, [
|
|
1407
|
-
strategyName
|
|
1408
|
+
this.getScheduleStorage = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => Reflect.construct(this.PersistScheduleFactory, [
|
|
1409
|
+
`${symbol}_${strategyName}`,
|
|
1408
1410
|
`./dump/data/schedule/`,
|
|
1409
1411
|
]));
|
|
1410
1412
|
/**
|
|
1411
|
-
* Reads persisted scheduled signal data for a
|
|
1413
|
+
* Reads persisted scheduled signal data for a symbol and strategy.
|
|
1412
1414
|
*
|
|
1413
1415
|
* Called by ClientStrategy.waitForInit() to restore scheduled signal state.
|
|
1414
1416
|
* Returns null if no scheduled signal exists.
|
|
1415
1417
|
*
|
|
1416
|
-
* @param strategyName - Strategy identifier
|
|
1417
1418
|
* @param symbol - Trading pair symbol
|
|
1419
|
+
* @param strategyName - Strategy identifier
|
|
1418
1420
|
* @returns Promise resolving to scheduled signal or null
|
|
1419
1421
|
*/
|
|
1420
|
-
this.readScheduleData = async (
|
|
1422
|
+
this.readScheduleData = async (symbol, strategyName) => {
|
|
1421
1423
|
backtest$1.loggerService.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_READ_DATA);
|
|
1422
|
-
const
|
|
1423
|
-
const
|
|
1424
|
+
const key = `${symbol}:${strategyName}`;
|
|
1425
|
+
const isInitial = !this.getScheduleStorage.has(key);
|
|
1426
|
+
const stateStorage = this.getScheduleStorage(symbol, strategyName);
|
|
1424
1427
|
await stateStorage.waitForInit(isInitial);
|
|
1425
1428
|
if (await stateStorage.hasValue(symbol)) {
|
|
1426
1429
|
return await stateStorage.readValue(symbol);
|
|
@@ -1434,14 +1437,15 @@ class PersistScheduleUtils {
|
|
|
1434
1437
|
* Uses atomic writes to prevent corruption on crashes.
|
|
1435
1438
|
*
|
|
1436
1439
|
* @param scheduledSignalRow - Scheduled signal data (null to clear)
|
|
1437
|
-
* @param strategyName - Strategy identifier
|
|
1438
1440
|
* @param symbol - Trading pair symbol
|
|
1441
|
+
* @param strategyName - Strategy identifier
|
|
1439
1442
|
* @returns Promise that resolves when write is complete
|
|
1440
1443
|
*/
|
|
1441
|
-
this.writeScheduleData = async (scheduledSignalRow,
|
|
1444
|
+
this.writeScheduleData = async (scheduledSignalRow, symbol, strategyName) => {
|
|
1442
1445
|
backtest$1.loggerService.info(PERSIST_SCHEDULE_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1443
|
-
const
|
|
1444
|
-
const
|
|
1446
|
+
const key = `${symbol}:${strategyName}`;
|
|
1447
|
+
const isInitial = !this.getScheduleStorage.has(key);
|
|
1448
|
+
const stateStorage = this.getScheduleStorage(symbol, strategyName);
|
|
1445
1449
|
await stateStorage.waitForInit(isInitial);
|
|
1446
1450
|
await stateStorage.writeValue(symbol, scheduledSignalRow);
|
|
1447
1451
|
};
|
|
@@ -1825,6 +1829,9 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
|
|
|
1825
1829
|
if (signal.minuteEstimatedTime <= 0) {
|
|
1826
1830
|
errors.push(`minuteEstimatedTime must be positive, got ${signal.minuteEstimatedTime}`);
|
|
1827
1831
|
}
|
|
1832
|
+
if (!Number.isInteger(signal.minuteEstimatedTime)) {
|
|
1833
|
+
errors.push(`minuteEstimatedTime must be an integer (whole number), got ${signal.minuteEstimatedTime}`);
|
|
1834
|
+
}
|
|
1828
1835
|
// ЗАЩИТА ОТ ВЕЧНЫХ СИГНАЛОВ: ограничиваем максимальное время жизни сигнала
|
|
1829
1836
|
if (GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES && GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
|
|
1830
1837
|
if (signal.minuteEstimatedTime > GLOBAL_CONFIG.CC_MAX_SIGNAL_LIFETIME_MINUTES) {
|
|
@@ -1967,7 +1974,7 @@ const WAIT_FOR_INIT_FN$2 = async (self) => {
|
|
|
1967
1974
|
return;
|
|
1968
1975
|
}
|
|
1969
1976
|
// Restore pending signal
|
|
1970
|
-
const pendingSignal = await PersistSignalAdapter.readSignalData(self.params.
|
|
1977
|
+
const pendingSignal = await PersistSignalAdapter.readSignalData(self.params.execution.context.symbol, self.params.strategyName);
|
|
1971
1978
|
if (pendingSignal) {
|
|
1972
1979
|
if (pendingSignal.exchangeName !== self.params.method.context.exchangeName) {
|
|
1973
1980
|
return;
|
|
@@ -1983,7 +1990,7 @@ const WAIT_FOR_INIT_FN$2 = async (self) => {
|
|
|
1983
1990
|
}
|
|
1984
1991
|
}
|
|
1985
1992
|
// Restore scheduled signal
|
|
1986
|
-
const scheduledSignal = await PersistScheduleAdapter.readScheduleData(self.params.
|
|
1993
|
+
const scheduledSignal = await PersistScheduleAdapter.readScheduleData(self.params.execution.context.symbol, self.params.strategyName);
|
|
1987
1994
|
if (scheduledSignal) {
|
|
1988
1995
|
if (scheduledSignal.exchangeName !== self.params.method.context.exchangeName) {
|
|
1989
1996
|
return;
|
|
@@ -2677,7 +2684,7 @@ class ClientStrategy {
|
|
|
2677
2684
|
if (this.params.execution.context.backtest) {
|
|
2678
2685
|
return;
|
|
2679
2686
|
}
|
|
2680
|
-
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.
|
|
2687
|
+
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.execution.context.symbol, this.params.strategyName);
|
|
2681
2688
|
}
|
|
2682
2689
|
/**
|
|
2683
2690
|
* Updates scheduled signal and persists to disk in live mode.
|
|
@@ -2696,14 +2703,18 @@ class ClientStrategy {
|
|
|
2696
2703
|
if (this.params.execution.context.backtest) {
|
|
2697
2704
|
return;
|
|
2698
2705
|
}
|
|
2699
|
-
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, this.params.
|
|
2706
|
+
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, this.params.execution.context.symbol, this.params.strategyName);
|
|
2700
2707
|
}
|
|
2701
2708
|
/**
|
|
2702
2709
|
* Retrieves the current pending signal.
|
|
2703
2710
|
* If no signal is pending, returns null.
|
|
2704
2711
|
* @returns Promise resolving to the pending signal or null.
|
|
2705
2712
|
*/
|
|
2706
|
-
async getPendingSignal() {
|
|
2713
|
+
async getPendingSignal(symbol, strategyName) {
|
|
2714
|
+
this.params.logger.debug("ClientStrategy getPendingSignal", {
|
|
2715
|
+
symbol,
|
|
2716
|
+
strategyName,
|
|
2717
|
+
});
|
|
2707
2718
|
return this._pendingSignal;
|
|
2708
2719
|
}
|
|
2709
2720
|
/**
|
|
@@ -2736,8 +2747,11 @@ class ClientStrategy {
|
|
|
2736
2747
|
* }
|
|
2737
2748
|
* ```
|
|
2738
2749
|
*/
|
|
2739
|
-
async tick() {
|
|
2740
|
-
this.params.logger.debug("ClientStrategy tick"
|
|
2750
|
+
async tick(symbol, strategyName) {
|
|
2751
|
+
this.params.logger.debug("ClientStrategy tick", {
|
|
2752
|
+
symbol,
|
|
2753
|
+
strategyName,
|
|
2754
|
+
});
|
|
2741
2755
|
// Получаем текущее время в начале tick для консистентности
|
|
2742
2756
|
const currentTime = this.params.execution.context.when.getTime();
|
|
2743
2757
|
// Early return if strategy was stopped
|
|
@@ -2822,9 +2836,11 @@ class ClientStrategy {
|
|
|
2822
2836
|
* console.log(result.closeReason); // "take_profit" | "stop_loss" | "time_expired" | "cancelled"
|
|
2823
2837
|
* ```
|
|
2824
2838
|
*/
|
|
2825
|
-
async backtest(candles) {
|
|
2839
|
+
async backtest(symbol, strategyName, candles) {
|
|
2826
2840
|
this.params.logger.debug("ClientStrategy backtest", {
|
|
2827
|
-
symbol
|
|
2841
|
+
symbol,
|
|
2842
|
+
strategyName,
|
|
2843
|
+
contextSymbol: this.params.execution.context.symbol,
|
|
2828
2844
|
candlesCount: candles.length,
|
|
2829
2845
|
hasScheduled: !!this._scheduledSignal,
|
|
2830
2846
|
hasPending: !!this._pendingSignal,
|
|
@@ -2940,8 +2956,10 @@ class ClientStrategy {
|
|
|
2940
2956
|
* // Existing signal will continue until natural close
|
|
2941
2957
|
* ```
|
|
2942
2958
|
*/
|
|
2943
|
-
async stop() {
|
|
2959
|
+
async stop(symbol, strategyName) {
|
|
2944
2960
|
this.params.logger.debug("ClientStrategy stop", {
|
|
2961
|
+
symbol,
|
|
2962
|
+
strategyName,
|
|
2945
2963
|
hasPendingSignal: this._pendingSignal !== null,
|
|
2946
2964
|
hasScheduledSignal: this._scheduledSignal !== null,
|
|
2947
2965
|
});
|
|
@@ -2962,21 +2980,20 @@ const NOOP_RISK = {
|
|
|
2962
2980
|
* Connection service routing strategy operations to correct ClientStrategy instance.
|
|
2963
2981
|
*
|
|
2964
2982
|
* Routes all IStrategy method calls to the appropriate strategy implementation
|
|
2965
|
-
* based on
|
|
2983
|
+
* based on symbol-strategy pairs. Uses memoization to cache
|
|
2966
2984
|
* ClientStrategy instances for performance.
|
|
2967
2985
|
*
|
|
2968
2986
|
* Key features:
|
|
2969
|
-
* - Automatic strategy routing via
|
|
2970
|
-
* - Memoized ClientStrategy instances by strategyName
|
|
2971
|
-
* - Implements IStrategy interface
|
|
2987
|
+
* - Automatic strategy routing via symbol-strategy pairs
|
|
2988
|
+
* - Memoized ClientStrategy instances by symbol:strategyName
|
|
2972
2989
|
* - Ensures initialization with waitForInit() before operations
|
|
2973
2990
|
* - Handles both tick() (live) and backtest() operations
|
|
2974
2991
|
*
|
|
2975
2992
|
* @example
|
|
2976
2993
|
* ```typescript
|
|
2977
2994
|
* // Used internally by framework
|
|
2978
|
-
* const result = await strategyConnectionService.tick();
|
|
2979
|
-
* //
|
|
2995
|
+
* const result = await strategyConnectionService.tick(symbol, strategyName);
|
|
2996
|
+
* // Routes to correct strategy instance for symbol-strategy pair
|
|
2980
2997
|
* ```
|
|
2981
2998
|
*/
|
|
2982
2999
|
class StrategyConnectionService {
|
|
@@ -2989,17 +3006,19 @@ class StrategyConnectionService {
|
|
|
2989
3006
|
this.methodContextService = inject(TYPES.methodContextService);
|
|
2990
3007
|
this.partialConnectionService = inject(TYPES.partialConnectionService);
|
|
2991
3008
|
/**
|
|
2992
|
-
* Retrieves memoized ClientStrategy instance for given strategy
|
|
3009
|
+
* Retrieves memoized ClientStrategy instance for given symbol-strategy pair.
|
|
2993
3010
|
*
|
|
2994
3011
|
* Creates ClientStrategy on first call, returns cached instance on subsequent calls.
|
|
2995
|
-
* Cache key is strategyName string.
|
|
3012
|
+
* Cache key is symbol:strategyName string.
|
|
2996
3013
|
*
|
|
3014
|
+
* @param symbol - Trading pair symbol
|
|
2997
3015
|
* @param strategyName - Name of registered strategy schema
|
|
2998
3016
|
* @returns Configured ClientStrategy instance
|
|
2999
3017
|
*/
|
|
3000
|
-
this.getStrategy = memoize(([strategyName]) => `${strategyName}`, (strategyName) => {
|
|
3018
|
+
this.getStrategy = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, (symbol, strategyName) => {
|
|
3001
3019
|
const { riskName, getSignal, interval, callbacks } = this.strategySchemaService.get(strategyName);
|
|
3002
3020
|
return new ClientStrategy({
|
|
3021
|
+
symbol,
|
|
3003
3022
|
interval,
|
|
3004
3023
|
execution: this.executionContextService,
|
|
3005
3024
|
method: this.methodContextService,
|
|
@@ -3018,14 +3037,18 @@ class StrategyConnectionService {
|
|
|
3018
3037
|
* If no active signal exists, returns null.
|
|
3019
3038
|
* Used internally for monitoring TP/SL and time expiration.
|
|
3020
3039
|
*
|
|
3040
|
+
* @param symbol - Trading pair symbol
|
|
3021
3041
|
* @param strategyName - Name of strategy to get pending signal for
|
|
3022
3042
|
*
|
|
3023
3043
|
* @returns Promise resolving to pending signal or null
|
|
3024
3044
|
*/
|
|
3025
|
-
this.getPendingSignal = async (strategyName) => {
|
|
3026
|
-
this.loggerService.log("strategyConnectionService getPendingSignal"
|
|
3027
|
-
|
|
3028
|
-
|
|
3045
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
3046
|
+
this.loggerService.log("strategyConnectionService getPendingSignal", {
|
|
3047
|
+
symbol,
|
|
3048
|
+
strategyName,
|
|
3049
|
+
});
|
|
3050
|
+
const strategy = this.getStrategy(symbol, strategyName);
|
|
3051
|
+
return await strategy.getPendingSignal(symbol, strategyName);
|
|
3029
3052
|
};
|
|
3030
3053
|
/**
|
|
3031
3054
|
* Executes live trading tick for current strategy.
|
|
@@ -3033,13 +3056,18 @@ class StrategyConnectionService {
|
|
|
3033
3056
|
* Waits for strategy initialization before processing tick.
|
|
3034
3057
|
* Evaluates current market conditions and returns signal state.
|
|
3035
3058
|
*
|
|
3059
|
+
* @param symbol - Trading pair symbol
|
|
3060
|
+
* @param strategyName - Name of strategy to tick
|
|
3036
3061
|
* @returns Promise resolving to tick result (idle, opened, active, closed)
|
|
3037
3062
|
*/
|
|
3038
|
-
this.tick = async () => {
|
|
3039
|
-
this.loggerService.log("strategyConnectionService tick"
|
|
3040
|
-
|
|
3063
|
+
this.tick = async (symbol, strategyName) => {
|
|
3064
|
+
this.loggerService.log("strategyConnectionService tick", {
|
|
3065
|
+
symbol,
|
|
3066
|
+
strategyName,
|
|
3067
|
+
});
|
|
3068
|
+
const strategy = this.getStrategy(symbol, strategyName);
|
|
3041
3069
|
await strategy.waitForInit();
|
|
3042
|
-
const tick = await strategy.tick();
|
|
3070
|
+
const tick = await strategy.tick(symbol, strategyName);
|
|
3043
3071
|
{
|
|
3044
3072
|
if (this.executionContextService.context.backtest) {
|
|
3045
3073
|
await signalBacktestEmitter.next(tick);
|
|
@@ -3057,16 +3085,20 @@ class StrategyConnectionService {
|
|
|
3057
3085
|
* Waits for strategy initialization before processing candles.
|
|
3058
3086
|
* Evaluates strategy signals against historical data.
|
|
3059
3087
|
*
|
|
3088
|
+
* @param symbol - Trading pair symbol
|
|
3089
|
+
* @param strategyName - Name of strategy to backtest
|
|
3060
3090
|
* @param candles - Array of historical candle data to backtest
|
|
3061
3091
|
* @returns Promise resolving to backtest result (signal or idle)
|
|
3062
3092
|
*/
|
|
3063
|
-
this.backtest = async (candles) => {
|
|
3093
|
+
this.backtest = async (symbol, strategyName, candles) => {
|
|
3064
3094
|
this.loggerService.log("strategyConnectionService backtest", {
|
|
3095
|
+
symbol,
|
|
3096
|
+
strategyName,
|
|
3065
3097
|
candleCount: candles.length,
|
|
3066
3098
|
});
|
|
3067
|
-
const strategy =
|
|
3099
|
+
const strategy = this.getStrategy(symbol, strategyName);
|
|
3068
3100
|
await strategy.waitForInit();
|
|
3069
|
-
const tick = await strategy.backtest(candles);
|
|
3101
|
+
const tick = await strategy.backtest(symbol, strategyName, candles);
|
|
3070
3102
|
{
|
|
3071
3103
|
if (this.executionContextService.context.backtest) {
|
|
3072
3104
|
await signalBacktestEmitter.next(tick);
|
|
@@ -3081,15 +3113,17 @@ class StrategyConnectionService {
|
|
|
3081
3113
|
* Delegates to ClientStrategy.stop() which sets internal flag to prevent
|
|
3082
3114
|
* getSignal from being called on subsequent ticks.
|
|
3083
3115
|
*
|
|
3116
|
+
* @param symbol - Trading pair symbol
|
|
3084
3117
|
* @param strategyName - Name of strategy to stop
|
|
3085
3118
|
* @returns Promise that resolves when stop flag is set
|
|
3086
3119
|
*/
|
|
3087
|
-
this.stop = async (strategyName) => {
|
|
3120
|
+
this.stop = async (symbol, strategyName) => {
|
|
3088
3121
|
this.loggerService.log("strategyConnectionService stop", {
|
|
3122
|
+
symbol,
|
|
3089
3123
|
strategyName,
|
|
3090
3124
|
});
|
|
3091
|
-
const strategy = this.getStrategy(strategyName);
|
|
3092
|
-
await strategy.stop();
|
|
3125
|
+
const strategy = this.getStrategy(symbol, strategyName);
|
|
3126
|
+
await strategy.stop(symbol, strategyName);
|
|
3093
3127
|
};
|
|
3094
3128
|
/**
|
|
3095
3129
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -3097,13 +3131,19 @@ class StrategyConnectionService {
|
|
|
3097
3131
|
* Forces re-initialization of strategy on next getStrategy call.
|
|
3098
3132
|
* Useful for resetting strategy state or releasing resources.
|
|
3099
3133
|
*
|
|
3100
|
-
* @param
|
|
3134
|
+
* @param ctx - Optional context with symbol and strategyName (clears all if not provided)
|
|
3101
3135
|
*/
|
|
3102
|
-
this.clear = async (
|
|
3136
|
+
this.clear = async (ctx) => {
|
|
3103
3137
|
this.loggerService.log("strategyConnectionService clear", {
|
|
3104
|
-
|
|
3138
|
+
ctx,
|
|
3105
3139
|
});
|
|
3106
|
-
|
|
3140
|
+
if (ctx) {
|
|
3141
|
+
const key = `${ctx.symbol}:${ctx.strategyName}`;
|
|
3142
|
+
this.getStrategy.clear(key);
|
|
3143
|
+
}
|
|
3144
|
+
else {
|
|
3145
|
+
this.getStrategy.clear();
|
|
3146
|
+
}
|
|
3107
3147
|
};
|
|
3108
3148
|
}
|
|
3109
3149
|
}
|
|
@@ -3914,13 +3954,15 @@ class StrategyGlobalService {
|
|
|
3914
3954
|
/**
|
|
3915
3955
|
* Validates strategy and associated risk configuration.
|
|
3916
3956
|
*
|
|
3917
|
-
* Memoized to avoid redundant validations for the same strategy.
|
|
3957
|
+
* Memoized to avoid redundant validations for the same symbol-strategy pair.
|
|
3918
3958
|
* Logs validation activity.
|
|
3959
|
+
* @param symbol - Trading pair symbol
|
|
3919
3960
|
* @param strategyName - Name of the strategy to validate
|
|
3920
3961
|
* @returns Promise that resolves when validation is complete
|
|
3921
3962
|
*/
|
|
3922
|
-
this.validate = memoize(([strategyName]) => `${strategyName}`, async (strategyName) => {
|
|
3963
|
+
this.validate = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, async (symbol, strategyName) => {
|
|
3923
3964
|
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
3965
|
+
symbol,
|
|
3924
3966
|
strategyName,
|
|
3925
3967
|
});
|
|
3926
3968
|
const strategySchema = this.strategySchemaService.get(strategyName);
|
|
@@ -3935,16 +3977,16 @@ class StrategyGlobalService {
|
|
|
3935
3977
|
* Used internally for monitoring TP/SL and time expiration.
|
|
3936
3978
|
*
|
|
3937
3979
|
* @param symbol - Trading pair symbol
|
|
3938
|
-
* @param
|
|
3939
|
-
* @param backtest - Whether running in backtest mode
|
|
3980
|
+
* @param strategyName - Name of the strategy
|
|
3940
3981
|
* @returns Promise resolving to pending signal or null
|
|
3941
3982
|
*/
|
|
3942
|
-
this.getPendingSignal = async (strategyName) => {
|
|
3983
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
3943
3984
|
this.loggerService.log("strategyGlobalService getPendingSignal", {
|
|
3985
|
+
symbol,
|
|
3944
3986
|
strategyName,
|
|
3945
3987
|
});
|
|
3946
|
-
await this.validate(
|
|
3947
|
-
return await this.strategyConnectionService.getPendingSignal(strategyName);
|
|
3988
|
+
await this.validate(symbol, strategyName);
|
|
3989
|
+
return await this.strategyConnectionService.getPendingSignal(symbol, strategyName);
|
|
3948
3990
|
};
|
|
3949
3991
|
/**
|
|
3950
3992
|
* Checks signal status at a specific timestamp.
|
|
@@ -3963,9 +4005,10 @@ class StrategyGlobalService {
|
|
|
3963
4005
|
when,
|
|
3964
4006
|
backtest,
|
|
3965
4007
|
});
|
|
3966
|
-
|
|
4008
|
+
const strategyName = this.methodContextService.context.strategyName;
|
|
4009
|
+
await this.validate(symbol, strategyName);
|
|
3967
4010
|
return await ExecutionContextService.runInContext(async () => {
|
|
3968
|
-
return await this.strategyConnectionService.tick();
|
|
4011
|
+
return await this.strategyConnectionService.tick(symbol, strategyName);
|
|
3969
4012
|
}, {
|
|
3970
4013
|
symbol,
|
|
3971
4014
|
when,
|
|
@@ -3991,9 +4034,10 @@ class StrategyGlobalService {
|
|
|
3991
4034
|
when,
|
|
3992
4035
|
backtest,
|
|
3993
4036
|
});
|
|
3994
|
-
|
|
4037
|
+
const strategyName = this.methodContextService.context.strategyName;
|
|
4038
|
+
await this.validate(symbol, strategyName);
|
|
3995
4039
|
return await ExecutionContextService.runInContext(async () => {
|
|
3996
|
-
return await this.strategyConnectionService.backtest(candles);
|
|
4040
|
+
return await this.strategyConnectionService.backtest(symbol, strategyName, candles);
|
|
3997
4041
|
}, {
|
|
3998
4042
|
symbol,
|
|
3999
4043
|
when,
|
|
@@ -4006,15 +4050,17 @@ class StrategyGlobalService {
|
|
|
4006
4050
|
* Delegates to StrategyConnectionService.stop() to set internal flag.
|
|
4007
4051
|
* Does not require execution context.
|
|
4008
4052
|
*
|
|
4053
|
+
* @param symbol - Trading pair symbol
|
|
4009
4054
|
* @param strategyName - Name of strategy to stop
|
|
4010
4055
|
* @returns Promise that resolves when stop flag is set
|
|
4011
4056
|
*/
|
|
4012
|
-
this.stop = async (strategyName) => {
|
|
4057
|
+
this.stop = async (symbol, strategyName) => {
|
|
4013
4058
|
this.loggerService.log("strategyGlobalService stop", {
|
|
4059
|
+
symbol,
|
|
4014
4060
|
strategyName,
|
|
4015
4061
|
});
|
|
4016
|
-
await this.validate(strategyName);
|
|
4017
|
-
return await this.strategyConnectionService.stop(strategyName);
|
|
4062
|
+
await this.validate(symbol, strategyName);
|
|
4063
|
+
return await this.strategyConnectionService.stop(symbol, strategyName);
|
|
4018
4064
|
};
|
|
4019
4065
|
/**
|
|
4020
4066
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -4022,16 +4068,16 @@ class StrategyGlobalService {
|
|
|
4022
4068
|
* Delegates to StrategyConnectionService.clear() to remove strategy from cache.
|
|
4023
4069
|
* Forces re-initialization of strategy on next operation.
|
|
4024
4070
|
*
|
|
4025
|
-
* @param
|
|
4071
|
+
* @param ctx - Optional context with symbol and strategyName (clears all if not provided)
|
|
4026
4072
|
*/
|
|
4027
|
-
this.clear = async (
|
|
4073
|
+
this.clear = async (ctx) => {
|
|
4028
4074
|
this.loggerService.log("strategyGlobalService clear", {
|
|
4029
|
-
|
|
4075
|
+
ctx,
|
|
4030
4076
|
});
|
|
4031
|
-
if (
|
|
4032
|
-
await this.validate(strategyName);
|
|
4077
|
+
if (ctx) {
|
|
4078
|
+
await this.validate(ctx.symbol, ctx.strategyName);
|
|
4033
4079
|
}
|
|
4034
|
-
return await this.strategyConnectionService.clear(
|
|
4080
|
+
return await this.strategyConnectionService.clear(ctx);
|
|
4035
4081
|
};
|
|
4036
4082
|
}
|
|
4037
4083
|
}
|
|
@@ -5006,8 +5052,14 @@ class WalkerLogicPrivateService {
|
|
|
5006
5052
|
let strategiesTested = 0;
|
|
5007
5053
|
let bestMetric = null;
|
|
5008
5054
|
let bestStrategy = null;
|
|
5055
|
+
let pendingStrategy;
|
|
5009
5056
|
const listenStop = walkerStopSubject
|
|
5010
|
-
.filter((
|
|
5057
|
+
.filter((data) => {
|
|
5058
|
+
let isOk = true;
|
|
5059
|
+
isOk = isOk && data.symbol === symbol;
|
|
5060
|
+
isOk = isOk && data.strategyName === pendingStrategy;
|
|
5061
|
+
return isOk;
|
|
5062
|
+
})
|
|
5011
5063
|
.map(() => CANCEL_SYMBOL)
|
|
5012
5064
|
.toPromise();
|
|
5013
5065
|
// Run backtest for each strategy
|
|
@@ -5025,6 +5077,7 @@ class WalkerLogicPrivateService {
|
|
|
5025
5077
|
exchangeName: context.exchangeName,
|
|
5026
5078
|
frameName: context.frameName,
|
|
5027
5079
|
});
|
|
5080
|
+
pendingStrategy = strategyName;
|
|
5028
5081
|
const result = await Promise.race([
|
|
5029
5082
|
await resolveDocuments(iterator),
|
|
5030
5083
|
listenStop,
|
|
@@ -5040,7 +5093,7 @@ class WalkerLogicPrivateService {
|
|
|
5040
5093
|
symbol,
|
|
5041
5094
|
});
|
|
5042
5095
|
// Get statistics from BacktestMarkdownService
|
|
5043
|
-
const stats = await this.backtestMarkdownService.getData(strategyName);
|
|
5096
|
+
const stats = await this.backtestMarkdownService.getData(symbol, strategyName);
|
|
5044
5097
|
// Extract metric value
|
|
5045
5098
|
const value = stats[metric];
|
|
5046
5099
|
const metricValue = value !== null &&
|
|
@@ -5099,7 +5152,7 @@ class WalkerLogicPrivateService {
|
|
|
5099
5152
|
bestStrategy,
|
|
5100
5153
|
bestMetric,
|
|
5101
5154
|
bestStats: bestStrategy !== null
|
|
5102
|
-
? await this.backtestMarkdownService.getData(bestStrategy)
|
|
5155
|
+
? await this.backtestMarkdownService.getData(symbol, bestStrategy)
|
|
5103
5156
|
: null,
|
|
5104
5157
|
};
|
|
5105
5158
|
// Call onComplete callback if provided with final best results
|
|
@@ -5655,10 +5708,10 @@ class BacktestMarkdownService {
|
|
|
5655
5708
|
/** Logger service for debug output */
|
|
5656
5709
|
this.loggerService = inject(TYPES.loggerService);
|
|
5657
5710
|
/**
|
|
5658
|
-
* Memoized function to get or create ReportStorage for a strategy.
|
|
5659
|
-
* Each strategy gets its own isolated storage instance.
|
|
5711
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy pair.
|
|
5712
|
+
* Each symbol-strategy combination gets its own isolated storage instance.
|
|
5660
5713
|
*/
|
|
5661
|
-
this.getStorage = memoize(([strategyName]) => `${strategyName}`, () => new ReportStorage$4());
|
|
5714
|
+
this.getStorage = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, () => new ReportStorage$4());
|
|
5662
5715
|
/**
|
|
5663
5716
|
* Processes tick events and accumulates closed signals.
|
|
5664
5717
|
* Should be called from IStrategyCallbacks.onTick.
|
|
@@ -5685,56 +5738,61 @@ class BacktestMarkdownService {
|
|
|
5685
5738
|
if (data.action !== "closed") {
|
|
5686
5739
|
return;
|
|
5687
5740
|
}
|
|
5688
|
-
const storage = this.getStorage(data.strategyName);
|
|
5741
|
+
const storage = this.getStorage(data.symbol, data.strategyName);
|
|
5689
5742
|
storage.addSignal(data);
|
|
5690
5743
|
};
|
|
5691
5744
|
/**
|
|
5692
|
-
* Gets statistical data from all closed signals for a strategy.
|
|
5745
|
+
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
5693
5746
|
* Delegates to ReportStorage.getData().
|
|
5694
5747
|
*
|
|
5748
|
+
* @param symbol - Trading pair symbol
|
|
5695
5749
|
* @param strategyName - Strategy name to get data for
|
|
5696
5750
|
* @returns Statistical data object with all metrics
|
|
5697
5751
|
*
|
|
5698
5752
|
* @example
|
|
5699
5753
|
* ```typescript
|
|
5700
5754
|
* const service = new BacktestMarkdownService();
|
|
5701
|
-
* const stats = await service.getData("my-strategy");
|
|
5755
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy");
|
|
5702
5756
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
5703
5757
|
* ```
|
|
5704
5758
|
*/
|
|
5705
|
-
this.getData = async (strategyName) => {
|
|
5759
|
+
this.getData = async (symbol, strategyName) => {
|
|
5706
5760
|
this.loggerService.log("backtestMarkdownService getData", {
|
|
5761
|
+
symbol,
|
|
5707
5762
|
strategyName,
|
|
5708
5763
|
});
|
|
5709
|
-
const storage = this.getStorage(strategyName);
|
|
5764
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
5710
5765
|
return storage.getData();
|
|
5711
5766
|
};
|
|
5712
5767
|
/**
|
|
5713
|
-
* Generates markdown report with all closed signals for a strategy.
|
|
5768
|
+
* Generates markdown report with all closed signals for a symbol-strategy pair.
|
|
5714
5769
|
* Delegates to ReportStorage.generateReport().
|
|
5715
5770
|
*
|
|
5771
|
+
* @param symbol - Trading pair symbol
|
|
5716
5772
|
* @param strategyName - Strategy name to generate report for
|
|
5717
5773
|
* @returns Markdown formatted report string with table of all closed signals
|
|
5718
5774
|
*
|
|
5719
5775
|
* @example
|
|
5720
5776
|
* ```typescript
|
|
5721
5777
|
* const service = new BacktestMarkdownService();
|
|
5722
|
-
* const markdown = await service.getReport("my-strategy");
|
|
5778
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy");
|
|
5723
5779
|
* console.log(markdown);
|
|
5724
5780
|
* ```
|
|
5725
5781
|
*/
|
|
5726
|
-
this.getReport = async (strategyName) => {
|
|
5782
|
+
this.getReport = async (symbol, strategyName) => {
|
|
5727
5783
|
this.loggerService.log("backtestMarkdownService getReport", {
|
|
5784
|
+
symbol,
|
|
5728
5785
|
strategyName,
|
|
5729
5786
|
});
|
|
5730
|
-
const storage = this.getStorage(strategyName);
|
|
5787
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
5731
5788
|
return storage.getReport(strategyName);
|
|
5732
5789
|
};
|
|
5733
5790
|
/**
|
|
5734
|
-
* Saves strategy report to disk.
|
|
5791
|
+
* Saves symbol-strategy report to disk.
|
|
5735
5792
|
* Creates directory if it doesn't exist.
|
|
5736
5793
|
* Delegates to ReportStorage.dump().
|
|
5737
5794
|
*
|
|
5795
|
+
* @param symbol - Trading pair symbol
|
|
5738
5796
|
* @param strategyName - Strategy name to save report for
|
|
5739
5797
|
* @param path - Directory path to save report (default: "./dump/backtest")
|
|
5740
5798
|
*
|
|
@@ -5743,43 +5801,50 @@ class BacktestMarkdownService {
|
|
|
5743
5801
|
* const service = new BacktestMarkdownService();
|
|
5744
5802
|
*
|
|
5745
5803
|
* // Save to default path: ./dump/backtest/my-strategy.md
|
|
5746
|
-
* await service.dump("my-strategy");
|
|
5804
|
+
* await service.dump("BTCUSDT", "my-strategy");
|
|
5747
5805
|
*
|
|
5748
5806
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
5749
|
-
* await service.dump("my-strategy", "./custom/path");
|
|
5807
|
+
* await service.dump("BTCUSDT", "my-strategy", "./custom/path");
|
|
5750
5808
|
* ```
|
|
5751
5809
|
*/
|
|
5752
|
-
this.dump = async (strategyName, path = "./dump/backtest") => {
|
|
5810
|
+
this.dump = async (symbol, strategyName, path = "./dump/backtest") => {
|
|
5753
5811
|
this.loggerService.log("backtestMarkdownService dump", {
|
|
5812
|
+
symbol,
|
|
5754
5813
|
strategyName,
|
|
5755
5814
|
path,
|
|
5756
5815
|
});
|
|
5757
|
-
const storage = this.getStorage(strategyName);
|
|
5816
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
5758
5817
|
await storage.dump(strategyName, path);
|
|
5759
5818
|
};
|
|
5760
5819
|
/**
|
|
5761
5820
|
* Clears accumulated signal data from storage.
|
|
5762
|
-
* If
|
|
5763
|
-
* If
|
|
5821
|
+
* If ctx is provided, clears only that specific symbol-strategy pair's data.
|
|
5822
|
+
* If nothing is provided, clears all data.
|
|
5764
5823
|
*
|
|
5765
|
-
* @param
|
|
5824
|
+
* @param ctx - Optional context with symbol and strategyName
|
|
5766
5825
|
*
|
|
5767
5826
|
* @example
|
|
5768
5827
|
* ```typescript
|
|
5769
5828
|
* const service = new BacktestMarkdownService();
|
|
5770
5829
|
*
|
|
5771
|
-
* // Clear specific strategy
|
|
5772
|
-
* await service.clear("my-strategy");
|
|
5830
|
+
* // Clear specific symbol-strategy pair
|
|
5831
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy" });
|
|
5773
5832
|
*
|
|
5774
|
-
* // Clear all
|
|
5833
|
+
* // Clear all data
|
|
5775
5834
|
* await service.clear();
|
|
5776
5835
|
* ```
|
|
5777
5836
|
*/
|
|
5778
|
-
this.clear = async (
|
|
5837
|
+
this.clear = async (ctx) => {
|
|
5779
5838
|
this.loggerService.log("backtestMarkdownService clear", {
|
|
5780
|
-
|
|
5839
|
+
ctx,
|
|
5781
5840
|
});
|
|
5782
|
-
|
|
5841
|
+
if (ctx) {
|
|
5842
|
+
const key = `${ctx.symbol}:${ctx.strategyName}`;
|
|
5843
|
+
this.getStorage.clear(key);
|
|
5844
|
+
}
|
|
5845
|
+
else {
|
|
5846
|
+
this.getStorage.clear();
|
|
5847
|
+
}
|
|
5783
5848
|
};
|
|
5784
5849
|
/**
|
|
5785
5850
|
* Initializes the service by subscribing to backtest signal events.
|
|
@@ -6178,10 +6243,10 @@ class LiveMarkdownService {
|
|
|
6178
6243
|
/** Logger service for debug output */
|
|
6179
6244
|
this.loggerService = inject(TYPES.loggerService);
|
|
6180
6245
|
/**
|
|
6181
|
-
* Memoized function to get or create ReportStorage for a strategy.
|
|
6182
|
-
* Each strategy gets its own isolated storage instance.
|
|
6246
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy pair.
|
|
6247
|
+
* Each symbol-strategy combination gets its own isolated storage instance.
|
|
6183
6248
|
*/
|
|
6184
|
-
this.getStorage = memoize(([strategyName]) => `${strategyName}`, () => new ReportStorage$3());
|
|
6249
|
+
this.getStorage = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, () => new ReportStorage$3());
|
|
6185
6250
|
/**
|
|
6186
6251
|
* Processes tick events and accumulates all event types.
|
|
6187
6252
|
* Should be called from IStrategyCallbacks.onTick.
|
|
@@ -6207,7 +6272,7 @@ class LiveMarkdownService {
|
|
|
6207
6272
|
this.loggerService.log("liveMarkdownService tick", {
|
|
6208
6273
|
data,
|
|
6209
6274
|
});
|
|
6210
|
-
const storage = this.getStorage(data.strategyName);
|
|
6275
|
+
const storage = this.getStorage(data.symbol, data.strategyName);
|
|
6211
6276
|
if (data.action === "idle") {
|
|
6212
6277
|
storage.addIdleEvent(data.currentPrice);
|
|
6213
6278
|
}
|
|
@@ -6222,52 +6287,57 @@ class LiveMarkdownService {
|
|
|
6222
6287
|
}
|
|
6223
6288
|
};
|
|
6224
6289
|
/**
|
|
6225
|
-
* Gets statistical data from all live trading events for a strategy.
|
|
6290
|
+
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
6226
6291
|
* Delegates to ReportStorage.getData().
|
|
6227
6292
|
*
|
|
6293
|
+
* @param symbol - Trading pair symbol
|
|
6228
6294
|
* @param strategyName - Strategy name to get data for
|
|
6229
6295
|
* @returns Statistical data object with all metrics
|
|
6230
6296
|
*
|
|
6231
6297
|
* @example
|
|
6232
6298
|
* ```typescript
|
|
6233
6299
|
* const service = new LiveMarkdownService();
|
|
6234
|
-
* const stats = await service.getData("my-strategy");
|
|
6300
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy");
|
|
6235
6301
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
6236
6302
|
* ```
|
|
6237
6303
|
*/
|
|
6238
|
-
this.getData = async (strategyName) => {
|
|
6304
|
+
this.getData = async (symbol, strategyName) => {
|
|
6239
6305
|
this.loggerService.log("liveMarkdownService getData", {
|
|
6306
|
+
symbol,
|
|
6240
6307
|
strategyName,
|
|
6241
6308
|
});
|
|
6242
|
-
const storage = this.getStorage(strategyName);
|
|
6309
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6243
6310
|
return storage.getData();
|
|
6244
6311
|
};
|
|
6245
6312
|
/**
|
|
6246
|
-
* Generates markdown report with all events for a strategy.
|
|
6313
|
+
* Generates markdown report with all events for a symbol-strategy pair.
|
|
6247
6314
|
* Delegates to ReportStorage.getReport().
|
|
6248
6315
|
*
|
|
6316
|
+
* @param symbol - Trading pair symbol
|
|
6249
6317
|
* @param strategyName - Strategy name to generate report for
|
|
6250
6318
|
* @returns Markdown formatted report string with table of all events
|
|
6251
6319
|
*
|
|
6252
6320
|
* @example
|
|
6253
6321
|
* ```typescript
|
|
6254
6322
|
* const service = new LiveMarkdownService();
|
|
6255
|
-
* const markdown = await service.getReport("my-strategy");
|
|
6323
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy");
|
|
6256
6324
|
* console.log(markdown);
|
|
6257
6325
|
* ```
|
|
6258
6326
|
*/
|
|
6259
|
-
this.getReport = async (strategyName) => {
|
|
6327
|
+
this.getReport = async (symbol, strategyName) => {
|
|
6260
6328
|
this.loggerService.log("liveMarkdownService getReport", {
|
|
6329
|
+
symbol,
|
|
6261
6330
|
strategyName,
|
|
6262
6331
|
});
|
|
6263
|
-
const storage = this.getStorage(strategyName);
|
|
6332
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6264
6333
|
return storage.getReport(strategyName);
|
|
6265
6334
|
};
|
|
6266
6335
|
/**
|
|
6267
|
-
* Saves strategy report to disk.
|
|
6336
|
+
* Saves symbol-strategy report to disk.
|
|
6268
6337
|
* Creates directory if it doesn't exist.
|
|
6269
6338
|
* Delegates to ReportStorage.dump().
|
|
6270
6339
|
*
|
|
6340
|
+
* @param symbol - Trading pair symbol
|
|
6271
6341
|
* @param strategyName - Strategy name to save report for
|
|
6272
6342
|
* @param path - Directory path to save report (default: "./dump/live")
|
|
6273
6343
|
*
|
|
@@ -6276,43 +6346,50 @@ class LiveMarkdownService {
|
|
|
6276
6346
|
* const service = new LiveMarkdownService();
|
|
6277
6347
|
*
|
|
6278
6348
|
* // Save to default path: ./dump/live/my-strategy.md
|
|
6279
|
-
* await service.dump("my-strategy");
|
|
6349
|
+
* await service.dump("BTCUSDT", "my-strategy");
|
|
6280
6350
|
*
|
|
6281
6351
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
6282
|
-
* await service.dump("my-strategy", "./custom/path");
|
|
6352
|
+
* await service.dump("BTCUSDT", "my-strategy", "./custom/path");
|
|
6283
6353
|
* ```
|
|
6284
6354
|
*/
|
|
6285
|
-
this.dump = async (strategyName, path = "./dump/live") => {
|
|
6355
|
+
this.dump = async (symbol, strategyName, path = "./dump/live") => {
|
|
6286
6356
|
this.loggerService.log("liveMarkdownService dump", {
|
|
6357
|
+
symbol,
|
|
6287
6358
|
strategyName,
|
|
6288
6359
|
path,
|
|
6289
6360
|
});
|
|
6290
|
-
const storage = this.getStorage(strategyName);
|
|
6361
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6291
6362
|
await storage.dump(strategyName, path);
|
|
6292
6363
|
};
|
|
6293
6364
|
/**
|
|
6294
6365
|
* Clears accumulated event data from storage.
|
|
6295
|
-
* If
|
|
6296
|
-
* If
|
|
6366
|
+
* If ctx is provided, clears only that specific symbol-strategy pair's data.
|
|
6367
|
+
* If nothing is provided, clears all data.
|
|
6297
6368
|
*
|
|
6298
|
-
* @param
|
|
6369
|
+
* @param ctx - Optional context with symbol and strategyName
|
|
6299
6370
|
*
|
|
6300
6371
|
* @example
|
|
6301
6372
|
* ```typescript
|
|
6302
6373
|
* const service = new LiveMarkdownService();
|
|
6303
6374
|
*
|
|
6304
|
-
* // Clear specific strategy
|
|
6305
|
-
* await service.clear("my-strategy");
|
|
6375
|
+
* // Clear specific symbol-strategy pair
|
|
6376
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy" });
|
|
6306
6377
|
*
|
|
6307
|
-
* // Clear all
|
|
6378
|
+
* // Clear all data
|
|
6308
6379
|
* await service.clear();
|
|
6309
6380
|
* ```
|
|
6310
6381
|
*/
|
|
6311
|
-
this.clear = async (
|
|
6382
|
+
this.clear = async (ctx) => {
|
|
6312
6383
|
this.loggerService.log("liveMarkdownService clear", {
|
|
6313
|
-
|
|
6384
|
+
ctx,
|
|
6314
6385
|
});
|
|
6315
|
-
|
|
6386
|
+
if (ctx) {
|
|
6387
|
+
const key = `${ctx.symbol}:${ctx.strategyName}`;
|
|
6388
|
+
this.getStorage.clear(key);
|
|
6389
|
+
}
|
|
6390
|
+
else {
|
|
6391
|
+
this.getStorage.clear();
|
|
6392
|
+
}
|
|
6316
6393
|
};
|
|
6317
6394
|
/**
|
|
6318
6395
|
* Initializes the service by subscribing to live signal events.
|
|
@@ -6561,10 +6638,10 @@ class ScheduleMarkdownService {
|
|
|
6561
6638
|
/** Logger service for debug output */
|
|
6562
6639
|
this.loggerService = inject(TYPES.loggerService);
|
|
6563
6640
|
/**
|
|
6564
|
-
* Memoized function to get or create ReportStorage for a strategy.
|
|
6565
|
-
* Each strategy gets its own isolated storage instance.
|
|
6641
|
+
* Memoized function to get or create ReportStorage for a symbol-strategy pair.
|
|
6642
|
+
* Each symbol-strategy combination gets its own isolated storage instance.
|
|
6566
6643
|
*/
|
|
6567
|
-
this.getStorage = memoize(([strategyName]) => `${strategyName}`, () => new ReportStorage$2());
|
|
6644
|
+
this.getStorage = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, () => new ReportStorage$2());
|
|
6568
6645
|
/**
|
|
6569
6646
|
* Processes tick events and accumulates scheduled/cancelled events.
|
|
6570
6647
|
* Should be called from signalLiveEmitter subscription.
|
|
@@ -6583,7 +6660,7 @@ class ScheduleMarkdownService {
|
|
|
6583
6660
|
this.loggerService.log("scheduleMarkdownService tick", {
|
|
6584
6661
|
data,
|
|
6585
6662
|
});
|
|
6586
|
-
const storage = this.getStorage(data.strategyName);
|
|
6663
|
+
const storage = this.getStorage(data.symbol, data.strategyName);
|
|
6587
6664
|
if (data.action === "scheduled") {
|
|
6588
6665
|
storage.addScheduledEvent(data);
|
|
6589
6666
|
}
|
|
@@ -6592,52 +6669,57 @@ class ScheduleMarkdownService {
|
|
|
6592
6669
|
}
|
|
6593
6670
|
};
|
|
6594
6671
|
/**
|
|
6595
|
-
* Gets statistical data from all scheduled signal events for a strategy.
|
|
6672
|
+
* Gets statistical data from all scheduled signal events for a symbol-strategy pair.
|
|
6596
6673
|
* Delegates to ReportStorage.getData().
|
|
6597
6674
|
*
|
|
6675
|
+
* @param symbol - Trading pair symbol
|
|
6598
6676
|
* @param strategyName - Strategy name to get data for
|
|
6599
6677
|
* @returns Statistical data object with all metrics
|
|
6600
6678
|
*
|
|
6601
6679
|
* @example
|
|
6602
6680
|
* ```typescript
|
|
6603
6681
|
* const service = new ScheduleMarkdownService();
|
|
6604
|
-
* const stats = await service.getData("my-strategy");
|
|
6682
|
+
* const stats = await service.getData("BTCUSDT", "my-strategy");
|
|
6605
6683
|
* console.log(stats.cancellationRate, stats.avgWaitTime);
|
|
6606
6684
|
* ```
|
|
6607
6685
|
*/
|
|
6608
|
-
this.getData = async (strategyName) => {
|
|
6686
|
+
this.getData = async (symbol, strategyName) => {
|
|
6609
6687
|
this.loggerService.log("scheduleMarkdownService getData", {
|
|
6688
|
+
symbol,
|
|
6610
6689
|
strategyName,
|
|
6611
6690
|
});
|
|
6612
|
-
const storage = this.getStorage(strategyName);
|
|
6691
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6613
6692
|
return storage.getData();
|
|
6614
6693
|
};
|
|
6615
6694
|
/**
|
|
6616
|
-
* Generates markdown report with all scheduled events for a strategy.
|
|
6695
|
+
* Generates markdown report with all scheduled events for a symbol-strategy pair.
|
|
6617
6696
|
* Delegates to ReportStorage.getReport().
|
|
6618
6697
|
*
|
|
6698
|
+
* @param symbol - Trading pair symbol
|
|
6619
6699
|
* @param strategyName - Strategy name to generate report for
|
|
6620
6700
|
* @returns Markdown formatted report string with table of all events
|
|
6621
6701
|
*
|
|
6622
6702
|
* @example
|
|
6623
6703
|
* ```typescript
|
|
6624
6704
|
* const service = new ScheduleMarkdownService();
|
|
6625
|
-
* const markdown = await service.getReport("my-strategy");
|
|
6705
|
+
* const markdown = await service.getReport("BTCUSDT", "my-strategy");
|
|
6626
6706
|
* console.log(markdown);
|
|
6627
6707
|
* ```
|
|
6628
6708
|
*/
|
|
6629
|
-
this.getReport = async (strategyName) => {
|
|
6709
|
+
this.getReport = async (symbol, strategyName) => {
|
|
6630
6710
|
this.loggerService.log("scheduleMarkdownService getReport", {
|
|
6711
|
+
symbol,
|
|
6631
6712
|
strategyName,
|
|
6632
6713
|
});
|
|
6633
|
-
const storage = this.getStorage(strategyName);
|
|
6714
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6634
6715
|
return storage.getReport(strategyName);
|
|
6635
6716
|
};
|
|
6636
6717
|
/**
|
|
6637
|
-
* Saves strategy report to disk.
|
|
6718
|
+
* Saves symbol-strategy report to disk.
|
|
6638
6719
|
* Creates directory if it doesn't exist.
|
|
6639
6720
|
* Delegates to ReportStorage.dump().
|
|
6640
6721
|
*
|
|
6722
|
+
* @param symbol - Trading pair symbol
|
|
6641
6723
|
* @param strategyName - Strategy name to save report for
|
|
6642
6724
|
* @param path - Directory path to save report (default: "./dump/schedule")
|
|
6643
6725
|
*
|
|
@@ -6646,43 +6728,50 @@ class ScheduleMarkdownService {
|
|
|
6646
6728
|
* const service = new ScheduleMarkdownService();
|
|
6647
6729
|
*
|
|
6648
6730
|
* // Save to default path: ./dump/schedule/my-strategy.md
|
|
6649
|
-
* await service.dump("my-strategy");
|
|
6731
|
+
* await service.dump("BTCUSDT", "my-strategy");
|
|
6650
6732
|
*
|
|
6651
6733
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
6652
|
-
* await service.dump("my-strategy", "./custom/path");
|
|
6734
|
+
* await service.dump("BTCUSDT", "my-strategy", "./custom/path");
|
|
6653
6735
|
* ```
|
|
6654
6736
|
*/
|
|
6655
|
-
this.dump = async (strategyName, path = "./dump/schedule") => {
|
|
6737
|
+
this.dump = async (symbol, strategyName, path = "./dump/schedule") => {
|
|
6656
6738
|
this.loggerService.log("scheduleMarkdownService dump", {
|
|
6739
|
+
symbol,
|
|
6657
6740
|
strategyName,
|
|
6658
6741
|
path,
|
|
6659
6742
|
});
|
|
6660
|
-
const storage = this.getStorage(strategyName);
|
|
6743
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6661
6744
|
await storage.dump(strategyName, path);
|
|
6662
6745
|
};
|
|
6663
6746
|
/**
|
|
6664
6747
|
* Clears accumulated event data from storage.
|
|
6665
|
-
* If
|
|
6666
|
-
* If
|
|
6748
|
+
* If ctx is provided, clears only that specific symbol-strategy pair's data.
|
|
6749
|
+
* If nothing is provided, clears all data.
|
|
6667
6750
|
*
|
|
6668
|
-
* @param
|
|
6751
|
+
* @param ctx - Optional context with symbol and strategyName
|
|
6669
6752
|
*
|
|
6670
6753
|
* @example
|
|
6671
6754
|
* ```typescript
|
|
6672
6755
|
* const service = new ScheduleMarkdownService();
|
|
6673
6756
|
*
|
|
6674
|
-
* // Clear specific strategy
|
|
6675
|
-
* await service.clear("my-strategy");
|
|
6757
|
+
* // Clear specific symbol-strategy pair
|
|
6758
|
+
* await service.clear({ symbol: "BTCUSDT", strategyName: "my-strategy" });
|
|
6676
6759
|
*
|
|
6677
|
-
* // Clear all
|
|
6760
|
+
* // Clear all data
|
|
6678
6761
|
* await service.clear();
|
|
6679
6762
|
* ```
|
|
6680
6763
|
*/
|
|
6681
|
-
this.clear = async (
|
|
6764
|
+
this.clear = async (ctx) => {
|
|
6682
6765
|
this.loggerService.log("scheduleMarkdownService clear", {
|
|
6683
|
-
|
|
6766
|
+
ctx,
|
|
6684
6767
|
});
|
|
6685
|
-
|
|
6768
|
+
if (ctx) {
|
|
6769
|
+
const key = `${ctx.symbol}:${ctx.strategyName}`;
|
|
6770
|
+
this.getStorage.clear(key);
|
|
6771
|
+
}
|
|
6772
|
+
else {
|
|
6773
|
+
this.getStorage.clear();
|
|
6774
|
+
}
|
|
6686
6775
|
};
|
|
6687
6776
|
/**
|
|
6688
6777
|
* Initializes the service by subscribing to live signal events.
|
|
@@ -6916,10 +7005,10 @@ class PerformanceMarkdownService {
|
|
|
6916
7005
|
/** Logger service for debug output */
|
|
6917
7006
|
this.loggerService = inject(TYPES.loggerService);
|
|
6918
7007
|
/**
|
|
6919
|
-
* Memoized function to get or create PerformanceStorage for a strategy.
|
|
6920
|
-
* Each strategy gets its own isolated storage instance.
|
|
7008
|
+
* Memoized function to get or create PerformanceStorage for a symbol-strategy pair.
|
|
7009
|
+
* Each symbol-strategy combination gets its own isolated storage instance.
|
|
6921
7010
|
*/
|
|
6922
|
-
this.getStorage = memoize(([strategyName]) => `${strategyName}`, () => new PerformanceStorage());
|
|
7011
|
+
this.getStorage = memoize(([symbol, strategyName]) => `${symbol}:${strategyName}`, () => new PerformanceStorage());
|
|
6923
7012
|
/**
|
|
6924
7013
|
* Processes performance events and accumulates metrics.
|
|
6925
7014
|
* Should be called from performance tracking code.
|
|
@@ -6930,83 +7019,97 @@ class PerformanceMarkdownService {
|
|
|
6930
7019
|
this.loggerService.log("performanceMarkdownService track", {
|
|
6931
7020
|
event,
|
|
6932
7021
|
});
|
|
7022
|
+
const symbol = event.symbol || "global";
|
|
6933
7023
|
const strategyName = event.strategyName || "global";
|
|
6934
|
-
const storage = this.getStorage(strategyName);
|
|
7024
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6935
7025
|
storage.addEvent(event);
|
|
6936
7026
|
};
|
|
6937
7027
|
/**
|
|
6938
|
-
* Gets aggregated performance statistics for a strategy.
|
|
7028
|
+
* Gets aggregated performance statistics for a symbol-strategy pair.
|
|
6939
7029
|
*
|
|
7030
|
+
* @param symbol - Trading pair symbol
|
|
6940
7031
|
* @param strategyName - Strategy name to get data for
|
|
6941
7032
|
* @returns Performance statistics with aggregated metrics
|
|
6942
7033
|
*
|
|
6943
7034
|
* @example
|
|
6944
7035
|
* ```typescript
|
|
6945
|
-
* const stats = await performanceService.getData("my-strategy");
|
|
7036
|
+
* const stats = await performanceService.getData("BTCUSDT", "my-strategy");
|
|
6946
7037
|
* console.log("Total time:", stats.totalDuration);
|
|
6947
7038
|
* console.log("Slowest operation:", Object.values(stats.metricStats)
|
|
6948
7039
|
* .sort((a, b) => b.avgDuration - a.avgDuration)[0]);
|
|
6949
7040
|
* ```
|
|
6950
7041
|
*/
|
|
6951
|
-
this.getData = async (strategyName) => {
|
|
7042
|
+
this.getData = async (symbol, strategyName) => {
|
|
6952
7043
|
this.loggerService.log("performanceMarkdownService getData", {
|
|
7044
|
+
symbol,
|
|
6953
7045
|
strategyName,
|
|
6954
7046
|
});
|
|
6955
|
-
const storage = this.getStorage(strategyName);
|
|
7047
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6956
7048
|
return storage.getData(strategyName);
|
|
6957
7049
|
};
|
|
6958
7050
|
/**
|
|
6959
7051
|
* Generates markdown report with performance analysis.
|
|
6960
7052
|
*
|
|
7053
|
+
* @param symbol - Trading pair symbol
|
|
6961
7054
|
* @param strategyName - Strategy name to generate report for
|
|
6962
7055
|
* @returns Markdown formatted report string
|
|
6963
7056
|
*
|
|
6964
7057
|
* @example
|
|
6965
7058
|
* ```typescript
|
|
6966
|
-
* const markdown = await performanceService.getReport("my-strategy");
|
|
7059
|
+
* const markdown = await performanceService.getReport("BTCUSDT", "my-strategy");
|
|
6967
7060
|
* console.log(markdown);
|
|
6968
7061
|
* ```
|
|
6969
7062
|
*/
|
|
6970
|
-
this.getReport = async (strategyName) => {
|
|
7063
|
+
this.getReport = async (symbol, strategyName) => {
|
|
6971
7064
|
this.loggerService.log("performanceMarkdownService getReport", {
|
|
7065
|
+
symbol,
|
|
6972
7066
|
strategyName,
|
|
6973
7067
|
});
|
|
6974
|
-
const storage = this.getStorage(strategyName);
|
|
7068
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6975
7069
|
return storage.getReport(strategyName);
|
|
6976
7070
|
};
|
|
6977
7071
|
/**
|
|
6978
7072
|
* Saves performance report to disk.
|
|
6979
7073
|
*
|
|
7074
|
+
* @param symbol - Trading pair symbol
|
|
6980
7075
|
* @param strategyName - Strategy name to save report for
|
|
6981
7076
|
* @param path - Directory path to save report
|
|
6982
7077
|
*
|
|
6983
7078
|
* @example
|
|
6984
7079
|
* ```typescript
|
|
6985
7080
|
* // Save to default path: ./dump/performance/my-strategy.md
|
|
6986
|
-
* await performanceService.dump("my-strategy");
|
|
7081
|
+
* await performanceService.dump("BTCUSDT", "my-strategy");
|
|
6987
7082
|
*
|
|
6988
7083
|
* // Save to custom path
|
|
6989
|
-
* await performanceService.dump("my-strategy", "./custom/path");
|
|
7084
|
+
* await performanceService.dump("BTCUSDT", "my-strategy", "./custom/path");
|
|
6990
7085
|
* ```
|
|
6991
7086
|
*/
|
|
6992
|
-
this.dump = async (strategyName, path = "./dump/performance") => {
|
|
7087
|
+
this.dump = async (symbol, strategyName, path = "./dump/performance") => {
|
|
6993
7088
|
this.loggerService.log("performanceMarkdownService dump", {
|
|
7089
|
+
symbol,
|
|
6994
7090
|
strategyName,
|
|
6995
7091
|
path,
|
|
6996
7092
|
});
|
|
6997
|
-
const storage = this.getStorage(strategyName);
|
|
7093
|
+
const storage = this.getStorage(symbol, strategyName);
|
|
6998
7094
|
await storage.dump(strategyName, path);
|
|
6999
7095
|
};
|
|
7000
7096
|
/**
|
|
7001
7097
|
* Clears accumulated performance data from storage.
|
|
7002
7098
|
*
|
|
7003
|
-
* @param
|
|
7099
|
+
* @param symbol - Optional trading pair symbol
|
|
7100
|
+
* @param strategyName - Optional strategy name
|
|
7004
7101
|
*/
|
|
7005
|
-
this.clear = async (
|
|
7102
|
+
this.clear = async (ctx) => {
|
|
7006
7103
|
this.loggerService.log("performanceMarkdownService clear", {
|
|
7007
|
-
|
|
7104
|
+
ctx,
|
|
7008
7105
|
});
|
|
7009
|
-
|
|
7106
|
+
if (ctx) {
|
|
7107
|
+
const key = `${ctx.symbol}:${ctx.strategyName}`;
|
|
7108
|
+
this.getStorage.clear(key);
|
|
7109
|
+
}
|
|
7110
|
+
{
|
|
7111
|
+
this.getStorage.clear();
|
|
7112
|
+
}
|
|
7010
7113
|
};
|
|
7011
7114
|
/**
|
|
7012
7115
|
* Initializes the service by subscribing to performance events.
|
|
@@ -8700,7 +8803,7 @@ class OptimizerTemplateService {
|
|
|
8700
8803
|
};
|
|
8701
8804
|
/**
|
|
8702
8805
|
* Generates text() helper for LLM text generation.
|
|
8703
|
-
* Uses Ollama
|
|
8806
|
+
* Uses Ollama deepseek-v3.1:671b model for market analysis.
|
|
8704
8807
|
*
|
|
8705
8808
|
* @param symbol - Trading pair symbol (used in prompt)
|
|
8706
8809
|
* @returns Generated async text() function
|
|
@@ -8725,7 +8828,7 @@ class OptimizerTemplateService {
|
|
|
8725
8828
|
` });`,
|
|
8726
8829
|
``,
|
|
8727
8830
|
` const response = await ollama.chat({`,
|
|
8728
|
-
` model: "
|
|
8831
|
+
` model: "deepseek-v3.1:671b",`,
|
|
8729
8832
|
` messages: [`,
|
|
8730
8833
|
` {`,
|
|
8731
8834
|
` role: "system",`,
|
|
@@ -8790,7 +8893,7 @@ class OptimizerTemplateService {
|
|
|
8790
8893
|
` });`,
|
|
8791
8894
|
``,
|
|
8792
8895
|
` const response = await ollama.chat({`,
|
|
8793
|
-
` model: "
|
|
8896
|
+
` model: "deepseek-v3.1:671b",`,
|
|
8794
8897
|
` messages: [`,
|
|
8795
8898
|
` {`,
|
|
8796
8899
|
` role: "system",`,
|
|
@@ -12301,11 +12404,11 @@ class BacktestUtils {
|
|
|
12301
12404
|
context,
|
|
12302
12405
|
});
|
|
12303
12406
|
{
|
|
12304
|
-
backtest$1.backtestMarkdownService.clear(context.strategyName);
|
|
12305
|
-
backtest$1.scheduleMarkdownService.clear(context.strategyName);
|
|
12407
|
+
backtest$1.backtestMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
12408
|
+
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
12306
12409
|
}
|
|
12307
12410
|
{
|
|
12308
|
-
backtest$1.strategyGlobalService.clear(context.strategyName);
|
|
12411
|
+
backtest$1.strategyGlobalService.clear({ symbol, strategyName: context.strategyName });
|
|
12309
12412
|
}
|
|
12310
12413
|
{
|
|
12311
12414
|
const { riskName } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
@@ -12359,9 +12462,9 @@ class BacktestUtils {
|
|
|
12359
12462
|
};
|
|
12360
12463
|
task().catch((error) => errorEmitter.next(new Error(getErrorMessage(error))));
|
|
12361
12464
|
return () => {
|
|
12362
|
-
backtest$1.strategyGlobalService.stop(context.strategyName);
|
|
12465
|
+
backtest$1.strategyGlobalService.stop(symbol, context.strategyName);
|
|
12363
12466
|
backtest$1.strategyGlobalService
|
|
12364
|
-
.getPendingSignal(context.strategyName)
|
|
12467
|
+
.getPendingSignal(symbol, context.strategyName)
|
|
12365
12468
|
.then(async (pendingSignal) => {
|
|
12366
12469
|
if (pendingSignal) {
|
|
12367
12470
|
return;
|
|
@@ -12380,40 +12483,44 @@ class BacktestUtils {
|
|
|
12380
12483
|
};
|
|
12381
12484
|
};
|
|
12382
12485
|
/**
|
|
12383
|
-
* Gets statistical data from all closed signals for a strategy.
|
|
12486
|
+
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
12384
12487
|
*
|
|
12488
|
+
* @param symbol - Trading pair symbol
|
|
12385
12489
|
* @param strategyName - Strategy name to get data for
|
|
12386
12490
|
* @returns Promise resolving to statistical data object
|
|
12387
12491
|
*
|
|
12388
12492
|
* @example
|
|
12389
12493
|
* ```typescript
|
|
12390
|
-
* const stats = await Backtest.getData("my-strategy");
|
|
12494
|
+
* const stats = await Backtest.getData("BTCUSDT", "my-strategy");
|
|
12391
12495
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
12392
12496
|
* ```
|
|
12393
12497
|
*/
|
|
12394
|
-
this.getData = async (strategyName) => {
|
|
12498
|
+
this.getData = async (symbol, strategyName) => {
|
|
12395
12499
|
backtest$1.loggerService.info("BacktestUtils.getData", {
|
|
12500
|
+
symbol,
|
|
12396
12501
|
strategyName,
|
|
12397
12502
|
});
|
|
12398
|
-
return await backtest$1.backtestMarkdownService.getData(strategyName);
|
|
12503
|
+
return await backtest$1.backtestMarkdownService.getData(symbol, strategyName);
|
|
12399
12504
|
};
|
|
12400
12505
|
/**
|
|
12401
|
-
* Generates markdown report with all closed signals for a strategy.
|
|
12506
|
+
* Generates markdown report with all closed signals for a symbol-strategy pair.
|
|
12402
12507
|
*
|
|
12508
|
+
* @param symbol - Trading pair symbol
|
|
12403
12509
|
* @param strategyName - Strategy name to generate report for
|
|
12404
12510
|
* @returns Promise resolving to markdown formatted report string
|
|
12405
12511
|
*
|
|
12406
12512
|
* @example
|
|
12407
12513
|
* ```typescript
|
|
12408
|
-
* const markdown = await Backtest.getReport("my-strategy");
|
|
12514
|
+
* const markdown = await Backtest.getReport("BTCUSDT", "my-strategy");
|
|
12409
12515
|
* console.log(markdown);
|
|
12410
12516
|
* ```
|
|
12411
12517
|
*/
|
|
12412
|
-
this.getReport = async (strategyName) => {
|
|
12518
|
+
this.getReport = async (symbol, strategyName) => {
|
|
12413
12519
|
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_REPORT, {
|
|
12520
|
+
symbol,
|
|
12414
12521
|
strategyName,
|
|
12415
12522
|
});
|
|
12416
|
-
return await backtest$1.backtestMarkdownService.getReport(strategyName);
|
|
12523
|
+
return await backtest$1.backtestMarkdownService.getReport(symbol, strategyName);
|
|
12417
12524
|
};
|
|
12418
12525
|
/**
|
|
12419
12526
|
* Saves strategy report to disk.
|
|
@@ -12510,11 +12617,11 @@ class LiveUtils {
|
|
|
12510
12617
|
context,
|
|
12511
12618
|
});
|
|
12512
12619
|
{
|
|
12513
|
-
backtest$1.liveMarkdownService.clear(context.strategyName);
|
|
12514
|
-
backtest$1.scheduleMarkdownService.clear(context.strategyName);
|
|
12620
|
+
backtest$1.liveMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
12621
|
+
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName: context.strategyName });
|
|
12515
12622
|
}
|
|
12516
12623
|
{
|
|
12517
|
-
backtest$1.strategyGlobalService.clear(context.strategyName);
|
|
12624
|
+
backtest$1.strategyGlobalService.clear({ symbol, strategyName: context.strategyName });
|
|
12518
12625
|
}
|
|
12519
12626
|
{
|
|
12520
12627
|
const { riskName } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
@@ -12568,9 +12675,9 @@ class LiveUtils {
|
|
|
12568
12675
|
};
|
|
12569
12676
|
task().catch((error) => errorEmitter.next(new Error(getErrorMessage(error))));
|
|
12570
12677
|
return () => {
|
|
12571
|
-
backtest$1.strategyGlobalService.stop(context.strategyName);
|
|
12678
|
+
backtest$1.strategyGlobalService.stop(symbol, context.strategyName);
|
|
12572
12679
|
backtest$1.strategyGlobalService
|
|
12573
|
-
.getPendingSignal(context.strategyName)
|
|
12680
|
+
.getPendingSignal(symbol, context.strategyName)
|
|
12574
12681
|
.then(async (pendingSignal) => {
|
|
12575
12682
|
if (pendingSignal) {
|
|
12576
12683
|
return;
|
|
@@ -12589,40 +12696,44 @@ class LiveUtils {
|
|
|
12589
12696
|
};
|
|
12590
12697
|
};
|
|
12591
12698
|
/**
|
|
12592
|
-
* Gets statistical data from all live trading events for a strategy.
|
|
12699
|
+
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
12593
12700
|
*
|
|
12701
|
+
* @param symbol - Trading pair symbol
|
|
12594
12702
|
* @param strategyName - Strategy name to get data for
|
|
12595
12703
|
* @returns Promise resolving to statistical data object
|
|
12596
12704
|
*
|
|
12597
12705
|
* @example
|
|
12598
12706
|
* ```typescript
|
|
12599
|
-
* const stats = await Live.getData("my-strategy");
|
|
12707
|
+
* const stats = await Live.getData("BTCUSDT", "my-strategy");
|
|
12600
12708
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
12601
12709
|
* ```
|
|
12602
12710
|
*/
|
|
12603
|
-
this.getData = async (strategyName) => {
|
|
12711
|
+
this.getData = async (symbol, strategyName) => {
|
|
12604
12712
|
backtest$1.loggerService.info("LiveUtils.getData", {
|
|
12713
|
+
symbol,
|
|
12605
12714
|
strategyName,
|
|
12606
12715
|
});
|
|
12607
|
-
return await backtest$1.liveMarkdownService.getData(strategyName);
|
|
12716
|
+
return await backtest$1.liveMarkdownService.getData(symbol, strategyName);
|
|
12608
12717
|
};
|
|
12609
12718
|
/**
|
|
12610
|
-
* Generates markdown report with all events for a strategy.
|
|
12719
|
+
* Generates markdown report with all events for a symbol-strategy pair.
|
|
12611
12720
|
*
|
|
12721
|
+
* @param symbol - Trading pair symbol
|
|
12612
12722
|
* @param strategyName - Strategy name to generate report for
|
|
12613
12723
|
* @returns Promise resolving to markdown formatted report string
|
|
12614
12724
|
*
|
|
12615
12725
|
* @example
|
|
12616
12726
|
* ```typescript
|
|
12617
|
-
* const markdown = await Live.getReport("my-strategy");
|
|
12727
|
+
* const markdown = await Live.getReport("BTCUSDT", "my-strategy");
|
|
12618
12728
|
* console.log(markdown);
|
|
12619
12729
|
* ```
|
|
12620
12730
|
*/
|
|
12621
|
-
this.getReport = async (strategyName) => {
|
|
12731
|
+
this.getReport = async (symbol, strategyName) => {
|
|
12622
12732
|
backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_REPORT, {
|
|
12733
|
+
symbol,
|
|
12623
12734
|
strategyName,
|
|
12624
12735
|
});
|
|
12625
|
-
return await backtest$1.liveMarkdownService.getReport(strategyName);
|
|
12736
|
+
return await backtest$1.liveMarkdownService.getReport(symbol, strategyName);
|
|
12626
12737
|
};
|
|
12627
12738
|
/**
|
|
12628
12739
|
* Saves strategy report to disk.
|
|
@@ -12696,40 +12807,44 @@ const SCHEDULE_METHOD_NAME_DUMP = "ScheduleUtils.dump";
|
|
|
12696
12807
|
class ScheduleUtils {
|
|
12697
12808
|
constructor() {
|
|
12698
12809
|
/**
|
|
12699
|
-
* Gets statistical data from all scheduled signal events for a strategy.
|
|
12810
|
+
* Gets statistical data from all scheduled signal events for a symbol-strategy pair.
|
|
12700
12811
|
*
|
|
12812
|
+
* @param symbol - Trading pair symbol
|
|
12701
12813
|
* @param strategyName - Strategy name to get data for
|
|
12702
12814
|
* @returns Promise resolving to statistical data object
|
|
12703
12815
|
*
|
|
12704
12816
|
* @example
|
|
12705
12817
|
* ```typescript
|
|
12706
|
-
* const stats = await Schedule.getData("my-strategy");
|
|
12818
|
+
* const stats = await Schedule.getData("BTCUSDT", "my-strategy");
|
|
12707
12819
|
* console.log(stats.cancellationRate, stats.avgWaitTime);
|
|
12708
12820
|
* ```
|
|
12709
12821
|
*/
|
|
12710
|
-
this.getData = async (strategyName) => {
|
|
12822
|
+
this.getData = async (symbol, strategyName) => {
|
|
12711
12823
|
backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_DATA, {
|
|
12824
|
+
symbol,
|
|
12712
12825
|
strategyName,
|
|
12713
12826
|
});
|
|
12714
|
-
return await backtest$1.scheduleMarkdownService.getData(strategyName);
|
|
12827
|
+
return await backtest$1.scheduleMarkdownService.getData(symbol, strategyName);
|
|
12715
12828
|
};
|
|
12716
12829
|
/**
|
|
12717
|
-
* Generates markdown report with all scheduled events for a strategy.
|
|
12830
|
+
* Generates markdown report with all scheduled events for a symbol-strategy pair.
|
|
12718
12831
|
*
|
|
12832
|
+
* @param symbol - Trading pair symbol
|
|
12719
12833
|
* @param strategyName - Strategy name to generate report for
|
|
12720
12834
|
* @returns Promise resolving to markdown formatted report string
|
|
12721
12835
|
*
|
|
12722
12836
|
* @example
|
|
12723
12837
|
* ```typescript
|
|
12724
|
-
* const markdown = await Schedule.getReport("my-strategy");
|
|
12838
|
+
* const markdown = await Schedule.getReport("BTCUSDT", "my-strategy");
|
|
12725
12839
|
* console.log(markdown);
|
|
12726
12840
|
* ```
|
|
12727
12841
|
*/
|
|
12728
|
-
this.getReport = async (strategyName) => {
|
|
12842
|
+
this.getReport = async (symbol, strategyName) => {
|
|
12729
12843
|
backtest$1.loggerService.info(SCHEDULE_METHOD_NAME_GET_REPORT, {
|
|
12844
|
+
symbol,
|
|
12730
12845
|
strategyName,
|
|
12731
12846
|
});
|
|
12732
|
-
return await backtest$1.scheduleMarkdownService.getReport(strategyName);
|
|
12847
|
+
return await backtest$1.scheduleMarkdownService.getReport(symbol, strategyName);
|
|
12733
12848
|
};
|
|
12734
12849
|
/**
|
|
12735
12850
|
* Saves strategy report to disk.
|
|
@@ -12801,19 +12916,20 @@ const Schedule = new ScheduleUtils();
|
|
|
12801
12916
|
*/
|
|
12802
12917
|
class Performance {
|
|
12803
12918
|
/**
|
|
12804
|
-
* Gets aggregated performance statistics for a strategy.
|
|
12919
|
+
* Gets aggregated performance statistics for a symbol-strategy pair.
|
|
12805
12920
|
*
|
|
12806
12921
|
* Returns detailed metrics grouped by operation type:
|
|
12807
12922
|
* - Count, total duration, average, min, max
|
|
12808
12923
|
* - Standard deviation for volatility
|
|
12809
12924
|
* - Percentiles (median, P95, P99) for outlier detection
|
|
12810
12925
|
*
|
|
12926
|
+
* @param symbol - Trading pair symbol
|
|
12811
12927
|
* @param strategyName - Strategy name to analyze
|
|
12812
12928
|
* @returns Performance statistics with aggregated metrics
|
|
12813
12929
|
*
|
|
12814
12930
|
* @example
|
|
12815
12931
|
* ```typescript
|
|
12816
|
-
* const stats = await Performance.getData("my-strategy");
|
|
12932
|
+
* const stats = await Performance.getData("BTCUSDT", "my-strategy");
|
|
12817
12933
|
*
|
|
12818
12934
|
* // Find slowest operation type
|
|
12819
12935
|
* const slowest = Object.values(stats.metricStats)
|
|
@@ -12828,8 +12944,8 @@ class Performance {
|
|
|
12828
12944
|
* }
|
|
12829
12945
|
* ```
|
|
12830
12946
|
*/
|
|
12831
|
-
static async getData(strategyName) {
|
|
12832
|
-
return backtest$1.performanceMarkdownService.getData(strategyName);
|
|
12947
|
+
static async getData(symbol, strategyName) {
|
|
12948
|
+
return backtest$1.performanceMarkdownService.getData(symbol, strategyName);
|
|
12833
12949
|
}
|
|
12834
12950
|
/**
|
|
12835
12951
|
* Generates markdown report with performance analysis.
|
|
@@ -12839,12 +12955,13 @@ class Performance {
|
|
|
12839
12955
|
* - Detailed metrics table with statistics
|
|
12840
12956
|
* - Percentile analysis for bottleneck detection
|
|
12841
12957
|
*
|
|
12958
|
+
* @param symbol - Trading pair symbol
|
|
12842
12959
|
* @param strategyName - Strategy name to generate report for
|
|
12843
12960
|
* @returns Markdown formatted report string
|
|
12844
12961
|
*
|
|
12845
12962
|
* @example
|
|
12846
12963
|
* ```typescript
|
|
12847
|
-
* const markdown = await Performance.getReport("my-strategy");
|
|
12964
|
+
* const markdown = await Performance.getReport("BTCUSDT", "my-strategy");
|
|
12848
12965
|
* console.log(markdown);
|
|
12849
12966
|
*
|
|
12850
12967
|
* // Or save to file
|
|
@@ -12852,8 +12969,8 @@ class Performance {
|
|
|
12852
12969
|
* await fs.writeFile("performance-report.md", markdown);
|
|
12853
12970
|
* ```
|
|
12854
12971
|
*/
|
|
12855
|
-
static async getReport(strategyName) {
|
|
12856
|
-
return backtest$1.performanceMarkdownService.getReport(strategyName);
|
|
12972
|
+
static async getReport(symbol, strategyName) {
|
|
12973
|
+
return backtest$1.performanceMarkdownService.getReport(symbol, strategyName);
|
|
12857
12974
|
}
|
|
12858
12975
|
/**
|
|
12859
12976
|
* Saves performance report to disk.
|
|
@@ -12876,23 +12993,6 @@ class Performance {
|
|
|
12876
12993
|
static async dump(strategyName, path = "./dump/performance") {
|
|
12877
12994
|
return backtest$1.performanceMarkdownService.dump(strategyName, path);
|
|
12878
12995
|
}
|
|
12879
|
-
/**
|
|
12880
|
-
* Clears accumulated performance metrics from memory.
|
|
12881
|
-
*
|
|
12882
|
-
* @param strategyName - Optional strategy name to clear specific strategy's metrics
|
|
12883
|
-
*
|
|
12884
|
-
* @example
|
|
12885
|
-
* ```typescript
|
|
12886
|
-
* // Clear specific strategy metrics
|
|
12887
|
-
* await Performance.clear("my-strategy");
|
|
12888
|
-
*
|
|
12889
|
-
* // Clear all metrics for all strategies
|
|
12890
|
-
* await Performance.clear();
|
|
12891
|
-
* ```
|
|
12892
|
-
*/
|
|
12893
|
-
static async clear(strategyName) {
|
|
12894
|
-
return backtest$1.performanceMarkdownService.clear(strategyName);
|
|
12895
|
-
}
|
|
12896
12996
|
}
|
|
12897
12997
|
|
|
12898
12998
|
const WALKER_METHOD_NAME_RUN = "WalkerUtils.run";
|
|
@@ -12944,11 +13044,11 @@ class WalkerUtils {
|
|
|
12944
13044
|
// Clear backtest data for all strategies
|
|
12945
13045
|
for (const strategyName of walkerSchema.strategies) {
|
|
12946
13046
|
{
|
|
12947
|
-
backtest$1.backtestMarkdownService.clear(strategyName);
|
|
12948
|
-
backtest$1.scheduleMarkdownService.clear(strategyName);
|
|
13047
|
+
backtest$1.backtestMarkdownService.clear({ symbol, strategyName });
|
|
13048
|
+
backtest$1.scheduleMarkdownService.clear({ symbol, strategyName });
|
|
12949
13049
|
}
|
|
12950
13050
|
{
|
|
12951
|
-
backtest$1.strategyGlobalService.clear(strategyName);
|
|
13051
|
+
backtest$1.strategyGlobalService.clear({ symbol, strategyName });
|
|
12952
13052
|
}
|
|
12953
13053
|
{
|
|
12954
13054
|
const { riskName } = backtest$1.strategySchemaService.get(strategyName);
|
|
@@ -13007,9 +13107,9 @@ class WalkerUtils {
|
|
|
13007
13107
|
task().catch((error) => errorEmitter.next(new Error(getErrorMessage(error))));
|
|
13008
13108
|
return () => {
|
|
13009
13109
|
for (const strategyName of walkerSchema.strategies) {
|
|
13010
|
-
backtest$1.strategyGlobalService.stop(strategyName);
|
|
13110
|
+
backtest$1.strategyGlobalService.stop(symbol, strategyName);
|
|
13111
|
+
walkerStopSubject.next({ symbol, strategyName });
|
|
13011
13112
|
}
|
|
13012
|
-
walkerStopSubject.next(context.walkerName);
|
|
13013
13113
|
if (!isDone) {
|
|
13014
13114
|
doneWalkerSubject.next({
|
|
13015
13115
|
exchangeName: walkerSchema.exchangeName,
|