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