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