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