backtest-kit 7.5.0 → 7.7.0
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 +797 -102
- package/build/index.mjs +792 -103
- package/package.json +1 -1
- package/types.d.ts +380 -7
package/build/index.cjs
CHANGED
|
@@ -1024,6 +1024,15 @@ const PERSIST_STATE_UTILS_METHOD_NAME_CLEAR = "PersistStateUtils.clear";
|
|
|
1024
1024
|
const PERSIST_STATE_UTILS_METHOD_NAME_DISPOSE = "PersistStateUtils.dispose";
|
|
1025
1025
|
const PERSIST_STATE_UTILS_METHOD_NAME_WAIT_FOR_INIT = "PersistStateUtils.waitForInit";
|
|
1026
1026
|
const PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY = "PersistStateUtils.useDummy";
|
|
1027
|
+
const PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON = "PersistStateUtils.useJson";
|
|
1028
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER = "PersistSessionUtils.usePersistSessionAdapter";
|
|
1029
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA = "PersistSessionUtils.readSessionData";
|
|
1030
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA = "PersistSessionUtils.writeSessionData";
|
|
1031
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR = "PersistSessionUtils.clear";
|
|
1032
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE = "PersistSessionUtils.dispose";
|
|
1033
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT = "PersistSessionUtils.waitForInit";
|
|
1034
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY = "PersistSessionUtils.useDummy";
|
|
1035
|
+
const PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON = "PersistSessionUtils.useJson";
|
|
1027
1036
|
const PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER = "PersistRecentUtils.usePersistRecentAdapter";
|
|
1028
1037
|
const PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA = "PersistRecentUtils.readRecentData";
|
|
1029
1038
|
const PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA = "PersistRecentUtils.writeRecentData";
|
|
@@ -3069,6 +3078,14 @@ class PersistStateUtils {
|
|
|
3069
3078
|
LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3070
3079
|
this.usePersistStateAdapter(PersistDummy);
|
|
3071
3080
|
};
|
|
3081
|
+
/**
|
|
3082
|
+
* Switches to the default JSON persist adapter.
|
|
3083
|
+
* All future persistence writes will use JSON storage.
|
|
3084
|
+
*/
|
|
3085
|
+
this.useJson = () => {
|
|
3086
|
+
LOGGER_SERVICE$7.log(PERSIST_STATE_UTILS_METHOD_NAME_USE_JSON);
|
|
3087
|
+
this.usePersistStateAdapter(PersistBase);
|
|
3088
|
+
};
|
|
3072
3089
|
/**
|
|
3073
3090
|
* Clears the memoized storage cache.
|
|
3074
3091
|
* Call this when process.cwd() changes between strategy iterations
|
|
@@ -3106,6 +3123,142 @@ class PersistStateUtils {
|
|
|
3106
3123
|
* Used by StatePersistInstance for crash-safe state persistence.
|
|
3107
3124
|
*/
|
|
3108
3125
|
const PersistStateAdapter = new PersistStateUtils();
|
|
3126
|
+
/**
|
|
3127
|
+
* Utility class for managing session persistence.
|
|
3128
|
+
*
|
|
3129
|
+
* Features:
|
|
3130
|
+
* - Memoized storage instances per (strategyName, exchangeName, frameName) key
|
|
3131
|
+
* - Custom adapter support
|
|
3132
|
+
* - Atomic read/write operations
|
|
3133
|
+
*
|
|
3134
|
+
* Storage layout: ./dump/session/<strategyName>/<exchangeName>/<frameName>.json
|
|
3135
|
+
*
|
|
3136
|
+
* Used by SessionPersistInstance for crash-safe session persistence.
|
|
3137
|
+
*/
|
|
3138
|
+
class PersistSessionUtils {
|
|
3139
|
+
constructor() {
|
|
3140
|
+
this.PersistSessionFactory = PersistBase;
|
|
3141
|
+
this.getSessionStorage = functoolsKit.memoize(([strategyName, exchangeName, frameName]) => `${strategyName}:${exchangeName}:${frameName}`, (strategyName, exchangeName, frameName) => Reflect.construct(this.PersistSessionFactory, [
|
|
3142
|
+
frameName,
|
|
3143
|
+
`./dump/session/${strategyName}/${exchangeName}/`,
|
|
3144
|
+
]));
|
|
3145
|
+
/**
|
|
3146
|
+
* Initializes the storage for a given (strategyName, exchangeName, frameName) triple.
|
|
3147
|
+
*
|
|
3148
|
+
* @param strategyName - Strategy identifier
|
|
3149
|
+
* @param exchangeName - Exchange identifier
|
|
3150
|
+
* @param frameName - Frame identifier
|
|
3151
|
+
* @param initial - Whether this is the first initialization
|
|
3152
|
+
*/
|
|
3153
|
+
this.waitForInit = async (strategyName, exchangeName, frameName, initial) => {
|
|
3154
|
+
LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WAIT_FOR_INIT, {
|
|
3155
|
+
strategyName,
|
|
3156
|
+
exchangeName,
|
|
3157
|
+
frameName,
|
|
3158
|
+
initial,
|
|
3159
|
+
});
|
|
3160
|
+
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
3161
|
+
const isInitial = initial && !this.getSessionStorage.has(key);
|
|
3162
|
+
const sessionStorage = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
3163
|
+
await sessionStorage.waitForInit(isInitial);
|
|
3164
|
+
};
|
|
3165
|
+
/**
|
|
3166
|
+
* Reads a session entry from persistence storage.
|
|
3167
|
+
*
|
|
3168
|
+
* @param strategyName - Strategy identifier
|
|
3169
|
+
* @param exchangeName - Exchange identifier
|
|
3170
|
+
* @param frameName - Frame identifier
|
|
3171
|
+
* @returns Promise resolving to entry data or null if not found
|
|
3172
|
+
*/
|
|
3173
|
+
this.readSessionData = async (strategyName, exchangeName, frameName) => {
|
|
3174
|
+
LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_READ_DATA, {
|
|
3175
|
+
strategyName,
|
|
3176
|
+
exchangeName,
|
|
3177
|
+
frameName,
|
|
3178
|
+
});
|
|
3179
|
+
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
3180
|
+
const isInitial = !this.getSessionStorage.has(key);
|
|
3181
|
+
const sessionStorage = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
3182
|
+
await sessionStorage.waitForInit(isInitial);
|
|
3183
|
+
if (await sessionStorage.hasValue(frameName)) {
|
|
3184
|
+
return await sessionStorage.readValue(frameName);
|
|
3185
|
+
}
|
|
3186
|
+
return null;
|
|
3187
|
+
};
|
|
3188
|
+
/**
|
|
3189
|
+
* Writes a session entry to disk with atomic file writes.
|
|
3190
|
+
*
|
|
3191
|
+
* @param data - Entry data to persist
|
|
3192
|
+
* @param strategyName - Strategy identifier
|
|
3193
|
+
* @param exchangeName - Exchange identifier
|
|
3194
|
+
* @param frameName - Frame identifier
|
|
3195
|
+
*/
|
|
3196
|
+
this.writeSessionData = async (data, strategyName, exchangeName, frameName) => {
|
|
3197
|
+
LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, {
|
|
3198
|
+
strategyName,
|
|
3199
|
+
exchangeName,
|
|
3200
|
+
frameName,
|
|
3201
|
+
});
|
|
3202
|
+
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
3203
|
+
const isInitial = !this.getSessionStorage.has(key);
|
|
3204
|
+
const sessionStorage = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
3205
|
+
await sessionStorage.waitForInit(isInitial);
|
|
3206
|
+
await sessionStorage.writeValue(frameName, data);
|
|
3207
|
+
};
|
|
3208
|
+
/**
|
|
3209
|
+
* Switches to a dummy persist adapter that discards all writes.
|
|
3210
|
+
* All future persistence writes will be no-ops.
|
|
3211
|
+
*/
|
|
3212
|
+
this.useDummy = () => {
|
|
3213
|
+
LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_DUMMY);
|
|
3214
|
+
this.usePersistSessionAdapter(PersistDummy);
|
|
3215
|
+
};
|
|
3216
|
+
/**
|
|
3217
|
+
* Switches to the default JSON persist adapter.
|
|
3218
|
+
* All future persistence writes will use JSON storage.
|
|
3219
|
+
*/
|
|
3220
|
+
this.useJson = () => {
|
|
3221
|
+
LOGGER_SERVICE$7.log(PERSIST_SESSION_UTILS_METHOD_NAME_USE_JSON);
|
|
3222
|
+
this.usePersistSessionAdapter(PersistBase);
|
|
3223
|
+
};
|
|
3224
|
+
/**
|
|
3225
|
+
* Clears the memoized storage cache.
|
|
3226
|
+
* Call this when process.cwd() changes between strategy iterations
|
|
3227
|
+
* so new storage instances are created with the updated base path.
|
|
3228
|
+
*/
|
|
3229
|
+
this.clear = () => {
|
|
3230
|
+
LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_CLEAR);
|
|
3231
|
+
this.getSessionStorage.clear();
|
|
3232
|
+
};
|
|
3233
|
+
/**
|
|
3234
|
+
* Disposes of the session adapter and releases any resources.
|
|
3235
|
+
* Call this when a session is removed to clean up its associated storage.
|
|
3236
|
+
*
|
|
3237
|
+
* @param strategyName - Strategy identifier
|
|
3238
|
+
* @param exchangeName - Exchange identifier
|
|
3239
|
+
* @param frameName - Frame identifier
|
|
3240
|
+
*/
|
|
3241
|
+
this.dispose = (strategyName, exchangeName, frameName) => {
|
|
3242
|
+
LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_DISPOSE);
|
|
3243
|
+
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
3244
|
+
this.getSessionStorage.clear(key);
|
|
3245
|
+
};
|
|
3246
|
+
}
|
|
3247
|
+
/**
|
|
3248
|
+
* Registers a custom persistence adapter.
|
|
3249
|
+
*
|
|
3250
|
+
* @param Ctor - Custom PersistBase constructor
|
|
3251
|
+
*/
|
|
3252
|
+
usePersistSessionAdapter(Ctor) {
|
|
3253
|
+
LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_USE_PERSIST_SESSION_ADAPTER);
|
|
3254
|
+
this.PersistSessionFactory = Ctor;
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
/**
|
|
3258
|
+
* Global singleton instance of PersistSessionUtils.
|
|
3259
|
+
* Used by SessionPersistInstance for crash-safe session persistence.
|
|
3260
|
+
*/
|
|
3261
|
+
const PersistSessionAdapter = new PersistSessionUtils();
|
|
3109
3262
|
|
|
3110
3263
|
var _a$2, _b$2;
|
|
3111
3264
|
const BUSY_DELAY = 100;
|
|
@@ -10571,7 +10724,7 @@ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
|
|
|
10571
10724
|
* @param backtest - Whether running in backtest mode
|
|
10572
10725
|
* @returns Unique string key for memoization
|
|
10573
10726
|
*/
|
|
10574
|
-
const CREATE_KEY_FN$
|
|
10727
|
+
const CREATE_KEY_FN$x = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10575
10728
|
const parts = [symbol, strategyName, exchangeName];
|
|
10576
10729
|
if (frameName)
|
|
10577
10730
|
parts.push(frameName);
|
|
@@ -10871,7 +11024,7 @@ class StrategyConnectionService {
|
|
|
10871
11024
|
* @param backtest - Whether running in backtest mode
|
|
10872
11025
|
* @returns Configured ClientStrategy instance
|
|
10873
11026
|
*/
|
|
10874
|
-
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
11027
|
+
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$x(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10875
11028
|
const { riskName = "", riskList = [], getSignal, interval = STRATEGY_DEFAULT_INTERVAL, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
10876
11029
|
return new ClientStrategy({
|
|
10877
11030
|
symbol,
|
|
@@ -11833,7 +11986,7 @@ class StrategyConnectionService {
|
|
|
11833
11986
|
}
|
|
11834
11987
|
return;
|
|
11835
11988
|
}
|
|
11836
|
-
const key = CREATE_KEY_FN$
|
|
11989
|
+
const key = CREATE_KEY_FN$x(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
11837
11990
|
if (!this.getStrategy.has(key)) {
|
|
11838
11991
|
return;
|
|
11839
11992
|
}
|
|
@@ -13007,7 +13160,7 @@ class ClientRisk {
|
|
|
13007
13160
|
* @param backtest - Whether running in backtest mode
|
|
13008
13161
|
* @returns Unique string key for memoization
|
|
13009
13162
|
*/
|
|
13010
|
-
const CREATE_KEY_FN$
|
|
13163
|
+
const CREATE_KEY_FN$w = (riskName, exchangeName, frameName, backtest) => {
|
|
13011
13164
|
const parts = [riskName, exchangeName];
|
|
13012
13165
|
if (frameName)
|
|
13013
13166
|
parts.push(frameName);
|
|
@@ -13107,7 +13260,7 @@ class RiskConnectionService {
|
|
|
13107
13260
|
* @param backtest - True if backtest mode, false if live mode
|
|
13108
13261
|
* @returns Configured ClientRisk instance
|
|
13109
13262
|
*/
|
|
13110
|
-
this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
13263
|
+
this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$w(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
|
|
13111
13264
|
const schema = this.riskSchemaService.get(riskName);
|
|
13112
13265
|
return new ClientRisk({
|
|
13113
13266
|
...schema,
|
|
@@ -13176,7 +13329,7 @@ class RiskConnectionService {
|
|
|
13176
13329
|
payload,
|
|
13177
13330
|
});
|
|
13178
13331
|
if (payload) {
|
|
13179
|
-
const key = CREATE_KEY_FN$
|
|
13332
|
+
const key = CREATE_KEY_FN$w(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
13180
13333
|
this.getRisk.clear(key);
|
|
13181
13334
|
}
|
|
13182
13335
|
else {
|
|
@@ -14295,7 +14448,7 @@ class ClientAction {
|
|
|
14295
14448
|
* @param backtest - Whether running in backtest mode
|
|
14296
14449
|
* @returns Unique string key for memoization
|
|
14297
14450
|
*/
|
|
14298
|
-
const CREATE_KEY_FN$
|
|
14451
|
+
const CREATE_KEY_FN$v = (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
14299
14452
|
const parts = [actionName, strategyName, exchangeName];
|
|
14300
14453
|
if (frameName)
|
|
14301
14454
|
parts.push(frameName);
|
|
@@ -14347,7 +14500,7 @@ class ActionConnectionService {
|
|
|
14347
14500
|
* @param backtest - True if backtest mode, false if live mode
|
|
14348
14501
|
* @returns Configured ClientAction instance
|
|
14349
14502
|
*/
|
|
14350
|
-
this.getAction = functoolsKit.memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
14503
|
+
this.getAction = functoolsKit.memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$v(actionName, strategyName, exchangeName, frameName, backtest), (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
14351
14504
|
const schema = this.actionSchemaService.get(actionName);
|
|
14352
14505
|
return new ClientAction({
|
|
14353
14506
|
...schema,
|
|
@@ -14573,7 +14726,7 @@ class ActionConnectionService {
|
|
|
14573
14726
|
await Promise.all(actions.map(async (action) => await action.dispose()));
|
|
14574
14727
|
return;
|
|
14575
14728
|
}
|
|
14576
|
-
const key = CREATE_KEY_FN$
|
|
14729
|
+
const key = CREATE_KEY_FN$v(payload.actionName, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
14577
14730
|
if (!this.getAction.has(key)) {
|
|
14578
14731
|
return;
|
|
14579
14732
|
}
|
|
@@ -14591,7 +14744,7 @@ const METHOD_NAME_VALIDATE$3 = "exchangeCoreService validate";
|
|
|
14591
14744
|
* @param exchangeName - Exchange name
|
|
14592
14745
|
* @returns Unique string key for memoization
|
|
14593
14746
|
*/
|
|
14594
|
-
const CREATE_KEY_FN$
|
|
14747
|
+
const CREATE_KEY_FN$u = (exchangeName) => {
|
|
14595
14748
|
return exchangeName;
|
|
14596
14749
|
};
|
|
14597
14750
|
/**
|
|
@@ -14615,7 +14768,7 @@ class ExchangeCoreService {
|
|
|
14615
14768
|
* @param exchangeName - Name of the exchange to validate
|
|
14616
14769
|
* @returns Promise that resolves when validation is complete
|
|
14617
14770
|
*/
|
|
14618
|
-
this.validate = functoolsKit.memoize(([exchangeName]) => CREATE_KEY_FN$
|
|
14771
|
+
this.validate = functoolsKit.memoize(([exchangeName]) => CREATE_KEY_FN$u(exchangeName), async (exchangeName) => {
|
|
14619
14772
|
this.loggerService.log(METHOD_NAME_VALIDATE$3, {
|
|
14620
14773
|
exchangeName,
|
|
14621
14774
|
});
|
|
@@ -14867,7 +15020,7 @@ const METHOD_NAME_VALIDATE$2 = "strategyCoreService validate";
|
|
|
14867
15020
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14868
15021
|
* @returns Unique string key for memoization
|
|
14869
15022
|
*/
|
|
14870
|
-
const CREATE_KEY_FN$
|
|
15023
|
+
const CREATE_KEY_FN$t = (context) => {
|
|
14871
15024
|
const parts = [context.strategyName, context.exchangeName];
|
|
14872
15025
|
if (context.frameName)
|
|
14873
15026
|
parts.push(context.frameName);
|
|
@@ -14899,7 +15052,7 @@ class StrategyCoreService {
|
|
|
14899
15052
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14900
15053
|
* @returns Promise that resolves when validation is complete
|
|
14901
15054
|
*/
|
|
14902
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
15055
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$t(context), async (context) => {
|
|
14903
15056
|
this.loggerService.log(METHOD_NAME_VALIDATE$2, {
|
|
14904
15057
|
context,
|
|
14905
15058
|
});
|
|
@@ -16269,7 +16422,7 @@ class SizingGlobalService {
|
|
|
16269
16422
|
* @param context - Context with riskName, exchangeName, frameName
|
|
16270
16423
|
* @returns Unique string key for memoization
|
|
16271
16424
|
*/
|
|
16272
|
-
const CREATE_KEY_FN$
|
|
16425
|
+
const CREATE_KEY_FN$s = (context) => {
|
|
16273
16426
|
const parts = [context.riskName, context.exchangeName];
|
|
16274
16427
|
if (context.frameName)
|
|
16275
16428
|
parts.push(context.frameName);
|
|
@@ -16295,7 +16448,7 @@ class RiskGlobalService {
|
|
|
16295
16448
|
* @param payload - Payload with riskName, exchangeName and frameName
|
|
16296
16449
|
* @returns Promise that resolves when validation is complete
|
|
16297
16450
|
*/
|
|
16298
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
16451
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$s(context), async (context) => {
|
|
16299
16452
|
this.loggerService.log("riskGlobalService validate", {
|
|
16300
16453
|
context,
|
|
16301
16454
|
});
|
|
@@ -16373,7 +16526,7 @@ const METHOD_NAME_VALIDATE$1 = "actionCoreService validate";
|
|
|
16373
16526
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
16374
16527
|
* @returns Unique string key for memoization
|
|
16375
16528
|
*/
|
|
16376
|
-
const CREATE_KEY_FN$
|
|
16529
|
+
const CREATE_KEY_FN$r = (context) => {
|
|
16377
16530
|
const parts = [context.strategyName, context.exchangeName];
|
|
16378
16531
|
if (context.frameName)
|
|
16379
16532
|
parts.push(context.frameName);
|
|
@@ -16417,7 +16570,7 @@ class ActionCoreService {
|
|
|
16417
16570
|
* @param context - Strategy execution context with strategyName, exchangeName and frameName
|
|
16418
16571
|
* @returns Promise that resolves when all validations complete
|
|
16419
16572
|
*/
|
|
16420
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
16573
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$r(context), async (context) => {
|
|
16421
16574
|
this.loggerService.log(METHOD_NAME_VALIDATE$1, {
|
|
16422
16575
|
context,
|
|
16423
16576
|
});
|
|
@@ -21487,7 +21640,7 @@ const ReportWriter = new ReportWriterAdapter();
|
|
|
21487
21640
|
* @param backtest - Whether running in backtest mode
|
|
21488
21641
|
* @returns Unique string key for memoization
|
|
21489
21642
|
*/
|
|
21490
|
-
const CREATE_KEY_FN$
|
|
21643
|
+
const CREATE_KEY_FN$q = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
21491
21644
|
const parts = [symbol, strategyName, exchangeName];
|
|
21492
21645
|
if (frameName)
|
|
21493
21646
|
parts.push(frameName);
|
|
@@ -21733,7 +21886,7 @@ class BacktestMarkdownService {
|
|
|
21733
21886
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21734
21887
|
* Each combination gets its own isolated storage instance.
|
|
21735
21888
|
*/
|
|
21736
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
21889
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$q(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$a(symbol, strategyName, exchangeName, frameName));
|
|
21737
21890
|
/**
|
|
21738
21891
|
* Processes tick events and accumulates closed signals.
|
|
21739
21892
|
* Should be called from IStrategyCallbacks.onTick.
|
|
@@ -21890,7 +22043,7 @@ class BacktestMarkdownService {
|
|
|
21890
22043
|
payload,
|
|
21891
22044
|
});
|
|
21892
22045
|
if (payload) {
|
|
21893
|
-
const key = CREATE_KEY_FN$
|
|
22046
|
+
const key = CREATE_KEY_FN$q(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
21894
22047
|
this.getStorage.clear(key);
|
|
21895
22048
|
}
|
|
21896
22049
|
else {
|
|
@@ -21952,7 +22105,7 @@ class BacktestMarkdownService {
|
|
|
21952
22105
|
* @param backtest - Whether running in backtest mode
|
|
21953
22106
|
* @returns Unique string key for memoization
|
|
21954
22107
|
*/
|
|
21955
|
-
const CREATE_KEY_FN$
|
|
22108
|
+
const CREATE_KEY_FN$p = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
21956
22109
|
const parts = [symbol, strategyName, exchangeName];
|
|
21957
22110
|
if (frameName)
|
|
21958
22111
|
parts.push(frameName);
|
|
@@ -22447,7 +22600,7 @@ class LiveMarkdownService {
|
|
|
22447
22600
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22448
22601
|
* Each combination gets its own isolated storage instance.
|
|
22449
22602
|
*/
|
|
22450
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22603
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$p(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$9(symbol, strategyName, exchangeName, frameName));
|
|
22451
22604
|
/**
|
|
22452
22605
|
* Subscribes to live signal emitter to receive tick events.
|
|
22453
22606
|
* Protected against multiple subscriptions.
|
|
@@ -22665,7 +22818,7 @@ class LiveMarkdownService {
|
|
|
22665
22818
|
payload,
|
|
22666
22819
|
});
|
|
22667
22820
|
if (payload) {
|
|
22668
|
-
const key = CREATE_KEY_FN$
|
|
22821
|
+
const key = CREATE_KEY_FN$p(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22669
22822
|
this.getStorage.clear(key);
|
|
22670
22823
|
}
|
|
22671
22824
|
else {
|
|
@@ -22685,7 +22838,7 @@ class LiveMarkdownService {
|
|
|
22685
22838
|
* @param backtest - Whether running in backtest mode
|
|
22686
22839
|
* @returns Unique string key for memoization
|
|
22687
22840
|
*/
|
|
22688
|
-
const CREATE_KEY_FN$
|
|
22841
|
+
const CREATE_KEY_FN$o = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22689
22842
|
const parts = [symbol, strategyName, exchangeName];
|
|
22690
22843
|
if (frameName)
|
|
22691
22844
|
parts.push(frameName);
|
|
@@ -22974,7 +23127,7 @@ class ScheduleMarkdownService {
|
|
|
22974
23127
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22975
23128
|
* Each combination gets its own isolated storage instance.
|
|
22976
23129
|
*/
|
|
22977
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
23130
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$o(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$8(symbol, strategyName, exchangeName, frameName));
|
|
22978
23131
|
/**
|
|
22979
23132
|
* Subscribes to signal emitter to receive scheduled signal events.
|
|
22980
23133
|
* Protected against multiple subscriptions.
|
|
@@ -23177,7 +23330,7 @@ class ScheduleMarkdownService {
|
|
|
23177
23330
|
payload,
|
|
23178
23331
|
});
|
|
23179
23332
|
if (payload) {
|
|
23180
|
-
const key = CREATE_KEY_FN$
|
|
23333
|
+
const key = CREATE_KEY_FN$o(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
23181
23334
|
this.getStorage.clear(key);
|
|
23182
23335
|
}
|
|
23183
23336
|
else {
|
|
@@ -23197,7 +23350,7 @@ class ScheduleMarkdownService {
|
|
|
23197
23350
|
* @param backtest - Whether running in backtest mode
|
|
23198
23351
|
* @returns Unique string key for memoization
|
|
23199
23352
|
*/
|
|
23200
|
-
const CREATE_KEY_FN$
|
|
23353
|
+
const CREATE_KEY_FN$n = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
23201
23354
|
const parts = [symbol, strategyName, exchangeName];
|
|
23202
23355
|
if (frameName)
|
|
23203
23356
|
parts.push(frameName);
|
|
@@ -23442,7 +23595,7 @@ class PerformanceMarkdownService {
|
|
|
23442
23595
|
* Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
23443
23596
|
* Each combination gets its own isolated storage instance.
|
|
23444
23597
|
*/
|
|
23445
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
23598
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$n(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new PerformanceStorage(symbol, strategyName, exchangeName, frameName));
|
|
23446
23599
|
/**
|
|
23447
23600
|
* Subscribes to performance emitter to receive performance events.
|
|
23448
23601
|
* Protected against multiple subscriptions.
|
|
@@ -23609,7 +23762,7 @@ class PerformanceMarkdownService {
|
|
|
23609
23762
|
payload,
|
|
23610
23763
|
});
|
|
23611
23764
|
if (payload) {
|
|
23612
|
-
const key = CREATE_KEY_FN$
|
|
23765
|
+
const key = CREATE_KEY_FN$n(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
23613
23766
|
this.getStorage.clear(key);
|
|
23614
23767
|
}
|
|
23615
23768
|
else {
|
|
@@ -24088,7 +24241,7 @@ class WalkerMarkdownService {
|
|
|
24088
24241
|
* @param backtest - Whether running in backtest mode
|
|
24089
24242
|
* @returns Unique string key for memoization
|
|
24090
24243
|
*/
|
|
24091
|
-
const CREATE_KEY_FN$
|
|
24244
|
+
const CREATE_KEY_FN$m = (exchangeName, frameName, backtest) => {
|
|
24092
24245
|
const parts = [exchangeName];
|
|
24093
24246
|
if (frameName)
|
|
24094
24247
|
parts.push(frameName);
|
|
@@ -24535,7 +24688,7 @@ class HeatMarkdownService {
|
|
|
24535
24688
|
* Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
|
|
24536
24689
|
* Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
|
|
24537
24690
|
*/
|
|
24538
|
-
this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
24691
|
+
this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$m(exchangeName, frameName, backtest), (exchangeName, frameName, backtest) => new HeatmapStorage(exchangeName, frameName, backtest));
|
|
24539
24692
|
/**
|
|
24540
24693
|
* Subscribes to signal emitter to receive tick events.
|
|
24541
24694
|
* Protected against multiple subscriptions.
|
|
@@ -24753,7 +24906,7 @@ class HeatMarkdownService {
|
|
|
24753
24906
|
payload,
|
|
24754
24907
|
});
|
|
24755
24908
|
if (payload) {
|
|
24756
|
-
const key = CREATE_KEY_FN$
|
|
24909
|
+
const key = CREATE_KEY_FN$m(payload.exchangeName, payload.frameName, payload.backtest);
|
|
24757
24910
|
this.getStorage.clear(key);
|
|
24758
24911
|
}
|
|
24759
24912
|
else {
|
|
@@ -25784,7 +25937,7 @@ class ClientPartial {
|
|
|
25784
25937
|
* @param backtest - Whether running in backtest mode
|
|
25785
25938
|
* @returns Unique string key for memoization
|
|
25786
25939
|
*/
|
|
25787
|
-
const CREATE_KEY_FN$
|
|
25940
|
+
const CREATE_KEY_FN$l = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
25788
25941
|
/**
|
|
25789
25942
|
* Creates a callback function for emitting profit events to partialProfitSubject.
|
|
25790
25943
|
*
|
|
@@ -25906,7 +26059,7 @@ class PartialConnectionService {
|
|
|
25906
26059
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
25907
26060
|
* Value: ClientPartial instance with logger and event emitters
|
|
25908
26061
|
*/
|
|
25909
|
-
this.getPartial = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
26062
|
+
this.getPartial = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$l(signalId, backtest), (signalId, backtest) => {
|
|
25910
26063
|
return new ClientPartial({
|
|
25911
26064
|
signalId,
|
|
25912
26065
|
logger: this.loggerService,
|
|
@@ -25996,7 +26149,7 @@ class PartialConnectionService {
|
|
|
25996
26149
|
const partial = this.getPartial(data.id, backtest);
|
|
25997
26150
|
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
25998
26151
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
25999
|
-
const key = CREATE_KEY_FN$
|
|
26152
|
+
const key = CREATE_KEY_FN$l(data.id, backtest);
|
|
26000
26153
|
this.getPartial.clear(key);
|
|
26001
26154
|
};
|
|
26002
26155
|
}
|
|
@@ -26012,7 +26165,7 @@ class PartialConnectionService {
|
|
|
26012
26165
|
* @param backtest - Whether running in backtest mode
|
|
26013
26166
|
* @returns Unique string key for memoization
|
|
26014
26167
|
*/
|
|
26015
|
-
const CREATE_KEY_FN$
|
|
26168
|
+
const CREATE_KEY_FN$k = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
26016
26169
|
const parts = [symbol, strategyName, exchangeName];
|
|
26017
26170
|
if (frameName)
|
|
26018
26171
|
parts.push(frameName);
|
|
@@ -26235,7 +26388,7 @@ class PartialMarkdownService {
|
|
|
26235
26388
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
26236
26389
|
* Each combination gets its own isolated storage instance.
|
|
26237
26390
|
*/
|
|
26238
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
26391
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$k(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$6(symbol, strategyName, exchangeName, frameName));
|
|
26239
26392
|
/**
|
|
26240
26393
|
* Subscribes to partial profit/loss signal emitters to receive events.
|
|
26241
26394
|
* Protected against multiple subscriptions.
|
|
@@ -26445,7 +26598,7 @@ class PartialMarkdownService {
|
|
|
26445
26598
|
payload,
|
|
26446
26599
|
});
|
|
26447
26600
|
if (payload) {
|
|
26448
|
-
const key = CREATE_KEY_FN$
|
|
26601
|
+
const key = CREATE_KEY_FN$k(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
26449
26602
|
this.getStorage.clear(key);
|
|
26450
26603
|
}
|
|
26451
26604
|
else {
|
|
@@ -26461,7 +26614,7 @@ class PartialMarkdownService {
|
|
|
26461
26614
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
26462
26615
|
* @returns Unique string key for memoization
|
|
26463
26616
|
*/
|
|
26464
|
-
const CREATE_KEY_FN$
|
|
26617
|
+
const CREATE_KEY_FN$j = (context) => {
|
|
26465
26618
|
const parts = [context.strategyName, context.exchangeName];
|
|
26466
26619
|
if (context.frameName)
|
|
26467
26620
|
parts.push(context.frameName);
|
|
@@ -26535,7 +26688,7 @@ class PartialGlobalService {
|
|
|
26535
26688
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
26536
26689
|
* @param methodName - Name of the calling method for error tracking
|
|
26537
26690
|
*/
|
|
26538
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
26691
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$j(context), (context, methodName) => {
|
|
26539
26692
|
this.loggerService.log("partialGlobalService validate", {
|
|
26540
26693
|
context,
|
|
26541
26694
|
methodName,
|
|
@@ -26990,7 +27143,7 @@ class ClientBreakeven {
|
|
|
26990
27143
|
* @param backtest - Whether running in backtest mode
|
|
26991
27144
|
* @returns Unique string key for memoization
|
|
26992
27145
|
*/
|
|
26993
|
-
const CREATE_KEY_FN$
|
|
27146
|
+
const CREATE_KEY_FN$i = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
26994
27147
|
/**
|
|
26995
27148
|
* Creates a callback function for emitting breakeven events to breakevenSubject.
|
|
26996
27149
|
*
|
|
@@ -27076,7 +27229,7 @@ class BreakevenConnectionService {
|
|
|
27076
27229
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
27077
27230
|
* Value: ClientBreakeven instance with logger and event emitter
|
|
27078
27231
|
*/
|
|
27079
|
-
this.getBreakeven = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
27232
|
+
this.getBreakeven = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$i(signalId, backtest), (signalId, backtest) => {
|
|
27080
27233
|
return new ClientBreakeven({
|
|
27081
27234
|
signalId,
|
|
27082
27235
|
logger: this.loggerService,
|
|
@@ -27137,7 +27290,7 @@ class BreakevenConnectionService {
|
|
|
27137
27290
|
const breakeven = this.getBreakeven(data.id, backtest);
|
|
27138
27291
|
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
27139
27292
|
await breakeven.clear(symbol, data, priceClose, backtest);
|
|
27140
|
-
const key = CREATE_KEY_FN$
|
|
27293
|
+
const key = CREATE_KEY_FN$i(data.id, backtest);
|
|
27141
27294
|
this.getBreakeven.clear(key);
|
|
27142
27295
|
};
|
|
27143
27296
|
}
|
|
@@ -27153,7 +27306,7 @@ class BreakevenConnectionService {
|
|
|
27153
27306
|
* @param backtest - Whether running in backtest mode
|
|
27154
27307
|
* @returns Unique string key for memoization
|
|
27155
27308
|
*/
|
|
27156
|
-
const CREATE_KEY_FN$
|
|
27309
|
+
const CREATE_KEY_FN$h = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
27157
27310
|
const parts = [symbol, strategyName, exchangeName];
|
|
27158
27311
|
if (frameName)
|
|
27159
27312
|
parts.push(frameName);
|
|
@@ -27328,7 +27481,7 @@ class BreakevenMarkdownService {
|
|
|
27328
27481
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
27329
27482
|
* Each combination gets its own isolated storage instance.
|
|
27330
27483
|
*/
|
|
27331
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
27484
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$h(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$5(symbol, strategyName, exchangeName, frameName));
|
|
27332
27485
|
/**
|
|
27333
27486
|
* Subscribes to breakeven signal emitter to receive events.
|
|
27334
27487
|
* Protected against multiple subscriptions.
|
|
@@ -27517,7 +27670,7 @@ class BreakevenMarkdownService {
|
|
|
27517
27670
|
payload,
|
|
27518
27671
|
});
|
|
27519
27672
|
if (payload) {
|
|
27520
|
-
const key = CREATE_KEY_FN$
|
|
27673
|
+
const key = CREATE_KEY_FN$h(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
27521
27674
|
this.getStorage.clear(key);
|
|
27522
27675
|
}
|
|
27523
27676
|
else {
|
|
@@ -27533,7 +27686,7 @@ class BreakevenMarkdownService {
|
|
|
27533
27686
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
27534
27687
|
* @returns Unique string key for memoization
|
|
27535
27688
|
*/
|
|
27536
|
-
const CREATE_KEY_FN$
|
|
27689
|
+
const CREATE_KEY_FN$g = (context) => {
|
|
27537
27690
|
const parts = [context.strategyName, context.exchangeName];
|
|
27538
27691
|
if (context.frameName)
|
|
27539
27692
|
parts.push(context.frameName);
|
|
@@ -27607,7 +27760,7 @@ class BreakevenGlobalService {
|
|
|
27607
27760
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
27608
27761
|
* @param methodName - Name of the calling method for error tracking
|
|
27609
27762
|
*/
|
|
27610
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
27763
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$g(context), (context, methodName) => {
|
|
27611
27764
|
this.loggerService.log("breakevenGlobalService validate", {
|
|
27612
27765
|
context,
|
|
27613
27766
|
methodName,
|
|
@@ -27828,7 +27981,7 @@ class ConfigValidationService {
|
|
|
27828
27981
|
* @param backtest - Whether running in backtest mode
|
|
27829
27982
|
* @returns Unique string key for memoization
|
|
27830
27983
|
*/
|
|
27831
|
-
const CREATE_KEY_FN$
|
|
27984
|
+
const CREATE_KEY_FN$f = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
27832
27985
|
const parts = [symbol, strategyName, exchangeName];
|
|
27833
27986
|
if (frameName)
|
|
27834
27987
|
parts.push(frameName);
|
|
@@ -27995,7 +28148,7 @@ class RiskMarkdownService {
|
|
|
27995
28148
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
27996
28149
|
* Each combination gets its own isolated storage instance.
|
|
27997
28150
|
*/
|
|
27998
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
28151
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$f(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$4(symbol, strategyName, exchangeName, frameName));
|
|
27999
28152
|
/**
|
|
28000
28153
|
* Subscribes to risk rejection emitter to receive rejection events.
|
|
28001
28154
|
* Protected against multiple subscriptions.
|
|
@@ -28184,7 +28337,7 @@ class RiskMarkdownService {
|
|
|
28184
28337
|
payload,
|
|
28185
28338
|
});
|
|
28186
28339
|
if (payload) {
|
|
28187
|
-
const key = CREATE_KEY_FN$
|
|
28340
|
+
const key = CREATE_KEY_FN$f(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
28188
28341
|
this.getStorage.clear(key);
|
|
28189
28342
|
}
|
|
28190
28343
|
else {
|
|
@@ -30764,7 +30917,7 @@ class HighestProfitReportService {
|
|
|
30764
30917
|
* @returns Colon-separated key string for memoization
|
|
30765
30918
|
* @internal
|
|
30766
30919
|
*/
|
|
30767
|
-
const CREATE_KEY_FN$
|
|
30920
|
+
const CREATE_KEY_FN$e = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
30768
30921
|
const parts = [symbol, strategyName, exchangeName];
|
|
30769
30922
|
if (frameName)
|
|
30770
30923
|
parts.push(frameName);
|
|
@@ -31006,7 +31159,7 @@ class StrategyMarkdownService {
|
|
|
31006
31159
|
*
|
|
31007
31160
|
* @internal
|
|
31008
31161
|
*/
|
|
31009
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31162
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$e(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$3(symbol, strategyName, exchangeName, frameName));
|
|
31010
31163
|
/**
|
|
31011
31164
|
* Records a cancel-scheduled event when a scheduled signal is cancelled.
|
|
31012
31165
|
*
|
|
@@ -31580,7 +31733,7 @@ class StrategyMarkdownService {
|
|
|
31580
31733
|
this.clear = async (payload) => {
|
|
31581
31734
|
this.loggerService.log("strategyMarkdownService clear", { payload });
|
|
31582
31735
|
if (payload) {
|
|
31583
|
-
const key = CREATE_KEY_FN$
|
|
31736
|
+
const key = CREATE_KEY_FN$e(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31584
31737
|
this.getStorage.clear(key);
|
|
31585
31738
|
}
|
|
31586
31739
|
else {
|
|
@@ -31688,7 +31841,7 @@ class StrategyMarkdownService {
|
|
|
31688
31841
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
31689
31842
|
* Key format: "symbol:strategyName:exchangeName[:frameName]:backtest|live"
|
|
31690
31843
|
*/
|
|
31691
|
-
const CREATE_KEY_FN$
|
|
31844
|
+
const CREATE_KEY_FN$d = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31692
31845
|
const parts = [symbol, strategyName, exchangeName];
|
|
31693
31846
|
if (frameName)
|
|
31694
31847
|
parts.push(frameName);
|
|
@@ -31881,7 +32034,7 @@ let ReportStorage$2 = class ReportStorage {
|
|
|
31881
32034
|
class SyncMarkdownService {
|
|
31882
32035
|
constructor() {
|
|
31883
32036
|
this.loggerService = inject(TYPES.loggerService);
|
|
31884
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32037
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$d(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$2(symbol, strategyName, exchangeName, frameName, backtest));
|
|
31885
32038
|
/**
|
|
31886
32039
|
* Subscribes to `syncSubject` to start receiving `SignalSyncContract` events.
|
|
31887
32040
|
* Protected against multiple subscriptions via `singleshot` — subsequent calls
|
|
@@ -32079,7 +32232,7 @@ class SyncMarkdownService {
|
|
|
32079
32232
|
this.clear = async (payload) => {
|
|
32080
32233
|
this.loggerService.log("syncMarkdownService clear", { payload });
|
|
32081
32234
|
if (payload) {
|
|
32082
|
-
const key = CREATE_KEY_FN$
|
|
32235
|
+
const key = CREATE_KEY_FN$d(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32083
32236
|
this.getStorage.clear(key);
|
|
32084
32237
|
}
|
|
32085
32238
|
else {
|
|
@@ -32092,7 +32245,7 @@ class SyncMarkdownService {
|
|
|
32092
32245
|
/**
|
|
32093
32246
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
32094
32247
|
*/
|
|
32095
|
-
const CREATE_KEY_FN$
|
|
32248
|
+
const CREATE_KEY_FN$c = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
32096
32249
|
const parts = [symbol, strategyName, exchangeName];
|
|
32097
32250
|
if (frameName)
|
|
32098
32251
|
parts.push(frameName);
|
|
@@ -32270,7 +32423,7 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
32270
32423
|
class HighestProfitMarkdownService {
|
|
32271
32424
|
constructor() {
|
|
32272
32425
|
this.loggerService = inject(TYPES.loggerService);
|
|
32273
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32426
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$c(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$1(symbol, strategyName, exchangeName, frameName));
|
|
32274
32427
|
/**
|
|
32275
32428
|
* Subscribes to `highestProfitSubject` to start receiving `HighestProfitContract`
|
|
32276
32429
|
* events. Protected against multiple subscriptions via `singleshot` — subsequent
|
|
@@ -32436,7 +32589,7 @@ class HighestProfitMarkdownService {
|
|
|
32436
32589
|
this.clear = async (payload) => {
|
|
32437
32590
|
this.loggerService.log("highestProfitMarkdownService clear", { payload });
|
|
32438
32591
|
if (payload) {
|
|
32439
|
-
const key = CREATE_KEY_FN$
|
|
32592
|
+
const key = CREATE_KEY_FN$c(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32440
32593
|
this.getStorage.clear(key);
|
|
32441
32594
|
}
|
|
32442
32595
|
else {
|
|
@@ -32458,7 +32611,7 @@ const LISTEN_TIMEOUT$1 = 120000;
|
|
|
32458
32611
|
* @param backtest - Whether running in backtest mode
|
|
32459
32612
|
* @returns Unique string key for memoization
|
|
32460
32613
|
*/
|
|
32461
|
-
const CREATE_KEY_FN$
|
|
32614
|
+
const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
32462
32615
|
const parts = [symbol, strategyName, exchangeName];
|
|
32463
32616
|
if (frameName)
|
|
32464
32617
|
parts.push(frameName);
|
|
@@ -32501,7 +32654,7 @@ class PriceMetaService {
|
|
|
32501
32654
|
* Each subject holds the latest currentPrice emitted by the strategy iterator for that key.
|
|
32502
32655
|
* Instances are cached until clear() is called.
|
|
32503
32656
|
*/
|
|
32504
|
-
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32657
|
+
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
|
|
32505
32658
|
/**
|
|
32506
32659
|
* Returns the current market price for the given symbol and context.
|
|
32507
32660
|
*
|
|
@@ -32530,10 +32683,10 @@ class PriceMetaService {
|
|
|
32530
32683
|
if (source.data) {
|
|
32531
32684
|
return source.data;
|
|
32532
32685
|
}
|
|
32533
|
-
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$
|
|
32686
|
+
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$b(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
|
|
32534
32687
|
const currentPrice = await functoolsKit.waitForNext(source, (data) => !!data, LISTEN_TIMEOUT$1);
|
|
32535
32688
|
if (typeof currentPrice === "symbol") {
|
|
32536
|
-
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$
|
|
32689
|
+
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$b(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
32537
32690
|
}
|
|
32538
32691
|
return currentPrice;
|
|
32539
32692
|
};
|
|
@@ -32575,7 +32728,7 @@ class PriceMetaService {
|
|
|
32575
32728
|
this.getSource.clear();
|
|
32576
32729
|
return;
|
|
32577
32730
|
}
|
|
32578
|
-
const key = CREATE_KEY_FN$
|
|
32731
|
+
const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32579
32732
|
this.getSource.clear(key);
|
|
32580
32733
|
};
|
|
32581
32734
|
}
|
|
@@ -32593,7 +32746,7 @@ const LISTEN_TIMEOUT = 120000;
|
|
|
32593
32746
|
* @param backtest - Whether running in backtest mode
|
|
32594
32747
|
* @returns Unique string key for memoization
|
|
32595
32748
|
*/
|
|
32596
|
-
const CREATE_KEY_FN$
|
|
32749
|
+
const CREATE_KEY_FN$a = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
32597
32750
|
const parts = [symbol, strategyName, exchangeName];
|
|
32598
32751
|
if (frameName)
|
|
32599
32752
|
parts.push(frameName);
|
|
@@ -32636,7 +32789,7 @@ class TimeMetaService {
|
|
|
32636
32789
|
* Each subject holds the latest createdAt timestamp emitted by the strategy iterator for that key.
|
|
32637
32790
|
* Instances are cached until clear() is called.
|
|
32638
32791
|
*/
|
|
32639
|
-
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32792
|
+
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
|
|
32640
32793
|
/**
|
|
32641
32794
|
* Returns the current candle timestamp (in milliseconds) for the given symbol and context.
|
|
32642
32795
|
*
|
|
@@ -32664,10 +32817,10 @@ class TimeMetaService {
|
|
|
32664
32817
|
if (source.data) {
|
|
32665
32818
|
return source.data;
|
|
32666
32819
|
}
|
|
32667
|
-
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$
|
|
32820
|
+
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$a(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
|
|
32668
32821
|
const timestamp = await functoolsKit.waitForNext(source, (data) => !!data, LISTEN_TIMEOUT);
|
|
32669
32822
|
if (typeof timestamp === "symbol") {
|
|
32670
|
-
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$
|
|
32823
|
+
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$a(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
32671
32824
|
}
|
|
32672
32825
|
return timestamp;
|
|
32673
32826
|
};
|
|
@@ -32709,7 +32862,7 @@ class TimeMetaService {
|
|
|
32709
32862
|
this.getSource.clear();
|
|
32710
32863
|
return;
|
|
32711
32864
|
}
|
|
32712
|
-
const key = CREATE_KEY_FN$
|
|
32865
|
+
const key = CREATE_KEY_FN$a(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32713
32866
|
this.getSource.clear(key);
|
|
32714
32867
|
};
|
|
32715
32868
|
}
|
|
@@ -32815,7 +32968,7 @@ class MaxDrawdownReportService {
|
|
|
32815
32968
|
/**
|
|
32816
32969
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
32817
32970
|
*/
|
|
32818
|
-
const CREATE_KEY_FN$
|
|
32971
|
+
const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
32819
32972
|
const parts = [symbol, strategyName, exchangeName];
|
|
32820
32973
|
if (frameName)
|
|
32821
32974
|
parts.push(frameName);
|
|
@@ -32941,7 +33094,7 @@ class ReportStorage {
|
|
|
32941
33094
|
class MaxDrawdownMarkdownService {
|
|
32942
33095
|
constructor() {
|
|
32943
33096
|
this.loggerService = inject(TYPES.loggerService);
|
|
32944
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
33097
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage(symbol, strategyName, exchangeName, frameName));
|
|
32945
33098
|
/**
|
|
32946
33099
|
* Subscribes to `maxDrawdownSubject` to start receiving `MaxDrawdownContract`
|
|
32947
33100
|
* events. Protected against multiple subscriptions via `singleshot`.
|
|
@@ -33020,7 +33173,7 @@ class MaxDrawdownMarkdownService {
|
|
|
33020
33173
|
this.clear = async (payload) => {
|
|
33021
33174
|
this.loggerService.log("maxDrawdownMarkdownService clear", { payload });
|
|
33022
33175
|
if (payload) {
|
|
33023
|
-
const key = CREATE_KEY_FN$
|
|
33176
|
+
const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
33024
33177
|
this.getStorage.clear(key);
|
|
33025
33178
|
}
|
|
33026
33179
|
else {
|
|
@@ -33038,7 +33191,7 @@ const METHOD_NAME_VALIDATE = "notificationHelperService.validate";
|
|
|
33038
33191
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
33039
33192
|
* @returns Unique string key for memoization
|
|
33040
33193
|
*/
|
|
33041
|
-
const CREATE_KEY_FN$
|
|
33194
|
+
const CREATE_KEY_FN$8 = (context) => {
|
|
33042
33195
|
const parts = [context.strategyName, context.exchangeName];
|
|
33043
33196
|
if (context.frameName)
|
|
33044
33197
|
parts.push(context.frameName);
|
|
@@ -33071,7 +33224,7 @@ class NotificationHelperService {
|
|
|
33071
33224
|
* @param context - Routing context: strategyName, exchangeName, frameName
|
|
33072
33225
|
* @throws {Error} If any registered schema fails validation
|
|
33073
33226
|
*/
|
|
33074
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
33227
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$8(context), async (context) => {
|
|
33075
33228
|
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
33076
33229
|
context,
|
|
33077
33230
|
});
|
|
@@ -46615,7 +46768,7 @@ const RECENT_ADAPTER_METHOD_NAME_GET_MINUTES_SINCE_LATEST_SIGNAL = "RecentAdapte
|
|
|
46615
46768
|
* @param backtest - Flag indicating if the context is backtest or live
|
|
46616
46769
|
* @returns Composite key string
|
|
46617
46770
|
*/
|
|
46618
|
-
const CREATE_KEY_FN$
|
|
46771
|
+
const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
46619
46772
|
const parts = [symbol, strategyName, exchangeName];
|
|
46620
46773
|
if (frameName)
|
|
46621
46774
|
parts.push(frameName);
|
|
@@ -46705,7 +46858,7 @@ class RecentMemoryBacktestUtils {
|
|
|
46705
46858
|
backtest.loggerService.info(RECENT_MEMORY_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
46706
46859
|
signalId: event.data.id,
|
|
46707
46860
|
});
|
|
46708
|
-
const key = CREATE_KEY_FN$
|
|
46861
|
+
const key = CREATE_KEY_FN$7(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
46709
46862
|
this._signals.set(key, event.data);
|
|
46710
46863
|
};
|
|
46711
46864
|
/**
|
|
@@ -46718,7 +46871,7 @@ class RecentMemoryBacktestUtils {
|
|
|
46718
46871
|
* @returns The latest signal or null if not found
|
|
46719
46872
|
*/
|
|
46720
46873
|
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
46721
|
-
const key = CREATE_KEY_FN$
|
|
46874
|
+
const key = CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
46722
46875
|
backtest.loggerService.info(RECENT_MEMORY_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL, { key });
|
|
46723
46876
|
return this._signals.get(key) ?? null;
|
|
46724
46877
|
};
|
|
@@ -46824,7 +46977,7 @@ class RecentMemoryLiveUtils {
|
|
|
46824
46977
|
backtest.loggerService.info(RECENT_MEMORY_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
46825
46978
|
signalId: event.data.id,
|
|
46826
46979
|
});
|
|
46827
|
-
const key = CREATE_KEY_FN$
|
|
46980
|
+
const key = CREATE_KEY_FN$7(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
46828
46981
|
this._signals.set(key, event.data);
|
|
46829
46982
|
};
|
|
46830
46983
|
/**
|
|
@@ -46837,7 +46990,7 @@ class RecentMemoryLiveUtils {
|
|
|
46837
46990
|
* @returns The latest signal or null if not found
|
|
46838
46991
|
*/
|
|
46839
46992
|
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
46840
|
-
const key = CREATE_KEY_FN$
|
|
46993
|
+
const key = CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
46841
46994
|
backtest.loggerService.info(RECENT_MEMORY_LIVE_METHOD_NAME_GET_LATEST_SIGNAL, { key });
|
|
46842
46995
|
return this._signals.get(key) ?? null;
|
|
46843
46996
|
};
|
|
@@ -47188,7 +47341,7 @@ const RecentLive = new RecentLiveAdapter();
|
|
|
47188
47341
|
*/
|
|
47189
47342
|
const RecentBacktest = new RecentBacktestAdapter();
|
|
47190
47343
|
|
|
47191
|
-
const CREATE_KEY_FN$
|
|
47344
|
+
const CREATE_KEY_FN$6 = (signalId, bucketName) => `${signalId}_${bucketName}`;
|
|
47192
47345
|
const STATE_LOCAL_INSTANCE_METHOD_NAME_GET = "StateLocalInstance.getState";
|
|
47193
47346
|
const STATE_LOCAL_INSTANCE_METHOD_NAME_SET = "StateLocalInstance.setState";
|
|
47194
47347
|
const STATE_PERSIST_INSTANCE_METHOD_NAME_WAIT_FOR_INIT = "StatePersistInstance.waitForInit";
|
|
@@ -47366,7 +47519,7 @@ class StatePersistInstance {
|
|
|
47366
47519
|
else {
|
|
47367
47520
|
this._value = dispatch;
|
|
47368
47521
|
}
|
|
47369
|
-
const id = CREATE_KEY_FN$
|
|
47522
|
+
const id = CREATE_KEY_FN$6(this.signalId, this.bucketName);
|
|
47370
47523
|
await PersistStateAdapter.writeStateData({ id, data: this._value }, this.signalId, this.bucketName);
|
|
47371
47524
|
return this._value;
|
|
47372
47525
|
});
|
|
@@ -47411,14 +47564,14 @@ class StatePersistInstance {
|
|
|
47411
47564
|
class StateBacktestAdapter {
|
|
47412
47565
|
constructor() {
|
|
47413
47566
|
this.StateFactory = StateLocalInstance;
|
|
47414
|
-
this.getInstance = functoolsKit.memoize(([signalId, bucketName]) => CREATE_KEY_FN$
|
|
47567
|
+
this.getInstance = functoolsKit.memoize(([signalId, bucketName]) => CREATE_KEY_FN$6(signalId, bucketName), (signalId, bucketName, initialValue) => Reflect.construct(this.StateFactory, [initialValue, signalId, bucketName]));
|
|
47415
47568
|
/**
|
|
47416
47569
|
* Disposes all memoized instances for the given signalId.
|
|
47417
47570
|
* Called by StateAdapter when a signal is cancelled or closed.
|
|
47418
47571
|
* @param signalId - Signal identifier to dispose
|
|
47419
47572
|
*/
|
|
47420
47573
|
this.disposeSignal = (signalId) => {
|
|
47421
|
-
const prefix = CREATE_KEY_FN$
|
|
47574
|
+
const prefix = CREATE_KEY_FN$6(signalId, "");
|
|
47422
47575
|
for (const key of this.getInstance.keys()) {
|
|
47423
47576
|
if (key.startsWith(prefix)) {
|
|
47424
47577
|
const instance = this.getInstance.get(key);
|
|
@@ -47439,7 +47592,7 @@ class StateBacktestAdapter {
|
|
|
47439
47592
|
signalId: dto.signalId,
|
|
47440
47593
|
bucketName: dto.bucketName,
|
|
47441
47594
|
});
|
|
47442
|
-
const key = CREATE_KEY_FN$
|
|
47595
|
+
const key = CREATE_KEY_FN$6(dto.signalId, dto.bucketName);
|
|
47443
47596
|
const isInitial = !this.getInstance.has(key);
|
|
47444
47597
|
const instance = this.getInstance(dto.signalId, dto.bucketName, dto.initialValue);
|
|
47445
47598
|
await instance.waitForInit(isInitial);
|
|
@@ -47458,7 +47611,7 @@ class StateBacktestAdapter {
|
|
|
47458
47611
|
signalId: dto.signalId,
|
|
47459
47612
|
bucketName: dto.bucketName,
|
|
47460
47613
|
});
|
|
47461
|
-
const key = CREATE_KEY_FN$
|
|
47614
|
+
const key = CREATE_KEY_FN$6(dto.signalId, dto.bucketName);
|
|
47462
47615
|
const isInitial = !this.getInstance.has(key);
|
|
47463
47616
|
const instance = this.getInstance(dto.signalId, dto.bucketName, dto.initialValue);
|
|
47464
47617
|
await instance.waitForInit(isInitial);
|
|
@@ -47526,14 +47679,14 @@ class StateBacktestAdapter {
|
|
|
47526
47679
|
class StateLiveAdapter {
|
|
47527
47680
|
constructor() {
|
|
47528
47681
|
this.StateFactory = StatePersistInstance;
|
|
47529
|
-
this.getInstance = functoolsKit.memoize(([signalId, bucketName]) => CREATE_KEY_FN$
|
|
47682
|
+
this.getInstance = functoolsKit.memoize(([signalId, bucketName]) => CREATE_KEY_FN$6(signalId, bucketName), (signalId, bucketName, initialValue) => Reflect.construct(this.StateFactory, [initialValue, signalId, bucketName]));
|
|
47530
47683
|
/**
|
|
47531
47684
|
* Disposes all memoized instances for the given signalId.
|
|
47532
47685
|
* Called by StateAdapter when a signal is cancelled or closed.
|
|
47533
47686
|
* @param signalId - Signal identifier to dispose
|
|
47534
47687
|
*/
|
|
47535
47688
|
this.disposeSignal = (signalId) => {
|
|
47536
|
-
const prefix = CREATE_KEY_FN$
|
|
47689
|
+
const prefix = CREATE_KEY_FN$6(signalId, "");
|
|
47537
47690
|
for (const key of this.getInstance.keys()) {
|
|
47538
47691
|
if (key.startsWith(prefix)) {
|
|
47539
47692
|
const instance = this.getInstance.get(key);
|
|
@@ -47554,7 +47707,7 @@ class StateLiveAdapter {
|
|
|
47554
47707
|
signalId: dto.signalId,
|
|
47555
47708
|
bucketName: dto.bucketName,
|
|
47556
47709
|
});
|
|
47557
|
-
const key = CREATE_KEY_FN$
|
|
47710
|
+
const key = CREATE_KEY_FN$6(dto.signalId, dto.bucketName);
|
|
47558
47711
|
const isInitial = !this.getInstance.has(key);
|
|
47559
47712
|
const instance = this.getInstance(dto.signalId, dto.bucketName, dto.initialValue);
|
|
47560
47713
|
await instance.waitForInit(isInitial);
|
|
@@ -47573,7 +47726,7 @@ class StateLiveAdapter {
|
|
|
47573
47726
|
signalId: dto.signalId,
|
|
47574
47727
|
bucketName: dto.bucketName,
|
|
47575
47728
|
});
|
|
47576
|
-
const key = CREATE_KEY_FN$
|
|
47729
|
+
const key = CREATE_KEY_FN$6(dto.signalId, dto.bucketName);
|
|
47577
47730
|
const isInitial = !this.getInstance.has(key);
|
|
47578
47731
|
const instance = this.getInstance(dto.signalId, dto.bucketName, dto.initialValue);
|
|
47579
47732
|
await instance.waitForInit(isInitial);
|
|
@@ -47825,6 +47978,7 @@ async function getMinutesSinceLatestSignalCreated(symbol) {
|
|
|
47825
47978
|
* SL trades show peak < 0.15% (Feb08, Feb13) or never go positive (Feb25).
|
|
47826
47979
|
* Rule: if minutesOpen >= N and peakPercent < threshold (e.g. 0.3%) — exit.
|
|
47827
47980
|
*
|
|
47981
|
+
* @param symbol - Trading pair symbol
|
|
47828
47982
|
* @param dto.bucketName - State bucket name
|
|
47829
47983
|
* @param dto.initialValue - Default value when no persisted state exists
|
|
47830
47984
|
* @returns Promise resolving to current state value, or initialValue if no signal
|
|
@@ -47844,16 +47998,16 @@ async function getMinutesSinceLatestSignalCreated(symbol) {
|
|
|
47844
47998
|
* }
|
|
47845
47999
|
* ```
|
|
47846
48000
|
*/
|
|
47847
|
-
async function getSignalState(dto) {
|
|
48001
|
+
async function getSignalState(symbol, dto) {
|
|
47848
48002
|
const { bucketName, initialValue } = dto;
|
|
47849
|
-
backtest.loggerService.info(GET_SIGNAL_STATE_METHOD_NAME, { bucketName });
|
|
48003
|
+
backtest.loggerService.info(GET_SIGNAL_STATE_METHOD_NAME, { symbol, bucketName });
|
|
47850
48004
|
if (!ExecutionContextService.hasContext()) {
|
|
47851
48005
|
throw new Error("getSignalState requires an execution context");
|
|
47852
48006
|
}
|
|
47853
48007
|
if (!MethodContextService.hasContext()) {
|
|
47854
48008
|
throw new Error("getSignalState requires a method context");
|
|
47855
48009
|
}
|
|
47856
|
-
const { backtest: isBacktest
|
|
48010
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
47857
48011
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
47858
48012
|
const currentPrice = await backtest.exchangeConnectionService.getAveragePrice(symbol);
|
|
47859
48013
|
let signal;
|
|
@@ -47889,6 +48043,7 @@ async function getSignalState(dto) {
|
|
|
47889
48043
|
* SL trades show peak < 0.15% (Feb08, Feb13) or never go positive (Feb25).
|
|
47890
48044
|
* Rule: if minutesOpen >= N and peakPercent < threshold (e.g. 0.3%) — exit.
|
|
47891
48045
|
*
|
|
48046
|
+
* @param symbol - Trading pair symbol
|
|
47892
48047
|
* @param dto.bucketName - State bucket name
|
|
47893
48048
|
* @param dto.initialValue - Default value when no persisted state exists
|
|
47894
48049
|
* @param dto.dispatch - New value or updater function receiving current value
|
|
@@ -47912,7 +48067,7 @@ async function getSignalState(dto) {
|
|
|
47912
48067
|
* );
|
|
47913
48068
|
* ```
|
|
47914
48069
|
*/
|
|
47915
|
-
async function setSignalState(dispatch, dto) {
|
|
48070
|
+
async function setSignalState(symbol, dispatch, dto) {
|
|
47916
48071
|
const { bucketName, initialValue } = dto;
|
|
47917
48072
|
backtest.loggerService.info(SET_SIGNAL_STATE_METHOD_NAME, { bucketName });
|
|
47918
48073
|
if (!ExecutionContextService.hasContext()) {
|
|
@@ -47921,7 +48076,7 @@ async function setSignalState(dispatch, dto) {
|
|
|
47921
48076
|
if (!MethodContextService.hasContext()) {
|
|
47922
48077
|
throw new Error("setSignalState requires a method context");
|
|
47923
48078
|
}
|
|
47924
|
-
const { backtest: isBacktest
|
|
48079
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
47925
48080
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
47926
48081
|
const currentPrice = await backtest.exchangeConnectionService.getAveragePrice(symbol);
|
|
47927
48082
|
let signal;
|
|
@@ -47944,15 +48099,549 @@ async function setSignalState(dispatch, dto) {
|
|
|
47944
48099
|
throw new Error(`setSignalState requires a pending or scheduled signal for symbol=${symbol} bucketName=${bucketName}`);
|
|
47945
48100
|
}
|
|
47946
48101
|
|
|
48102
|
+
const CREATE_KEY_FN$5 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
48103
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
48104
|
+
if (frameName)
|
|
48105
|
+
parts.push(frameName);
|
|
48106
|
+
parts.push(backtest ? "backtest" : "live");
|
|
48107
|
+
return parts.join(":");
|
|
48108
|
+
};
|
|
48109
|
+
const SESSION_LOCAL_INSTANCE_METHOD_NAME_GET = "SessionLocalInstance.getData";
|
|
48110
|
+
const SESSION_LOCAL_INSTANCE_METHOD_NAME_SET = "SessionLocalInstance.setData";
|
|
48111
|
+
const SESSION_PERSIST_INSTANCE_METHOD_NAME_WAIT_FOR_INIT = "SessionPersistInstance.waitForInit";
|
|
48112
|
+
const SESSION_PERSIST_INSTANCE_METHOD_NAME_GET = "SessionPersistInstance.getData";
|
|
48113
|
+
const SESSION_PERSIST_INSTANCE_METHOD_NAME_SET = "SessionPersistInstance.setData";
|
|
48114
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_DISPOSE = "SessionBacktestAdapter.dispose";
|
|
48115
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_GET = "SessionBacktestAdapter.getData";
|
|
48116
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_SET = "SessionBacktestAdapter.setData";
|
|
48117
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_LOCAL = "SessionBacktestAdapter.useLocal";
|
|
48118
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST = "SessionBacktestAdapter.usePersist";
|
|
48119
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY = "SessionBacktestAdapter.useDummy";
|
|
48120
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_SESSION_ADAPTER = "SessionBacktestAdapter.useSessionAdapter";
|
|
48121
|
+
const SESSION_BACKTEST_ADAPTER_METHOD_NAME_CLEAR = "SessionBacktestAdapter.clear";
|
|
48122
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_DISPOSE = "SessionLiveAdapter.dispose";
|
|
48123
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_GET = "SessionLiveAdapter.getData";
|
|
48124
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_SET = "SessionLiveAdapter.setData";
|
|
48125
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_USE_LOCAL = "SessionLiveAdapter.useLocal";
|
|
48126
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST = "SessionLiveAdapter.usePersist";
|
|
48127
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY = "SessionLiveAdapter.useDummy";
|
|
48128
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_USE_SESSION_ADAPTER = "SessionLiveAdapter.useSessionAdapter";
|
|
48129
|
+
const SESSION_LIVE_ADAPTER_METHOD_NAME_CLEAR = "SessionLiveAdapter.clear";
|
|
48130
|
+
const SESSION_ADAPTER_METHOD_NAME_GET = "SessionAdapter.getData";
|
|
48131
|
+
const SESSION_ADAPTER_METHOD_NAME_SET = "SessionAdapter.setData";
|
|
48132
|
+
/**
|
|
48133
|
+
* In-process session instance backed by a plain object reference.
|
|
48134
|
+
* All data lives in process memory only — no disk persistence.
|
|
48135
|
+
*
|
|
48136
|
+
* Features:
|
|
48137
|
+
* - Mutable in-memory session data
|
|
48138
|
+
* - Scoped per (symbol, strategyName, exchangeName, frameName) tuple
|
|
48139
|
+
*
|
|
48140
|
+
* Use for backtesting and unit tests where persistence between runs is not needed.
|
|
48141
|
+
*/
|
|
48142
|
+
class SessionLocalInstance {
|
|
48143
|
+
constructor(symbol, strategyName, exchangeName, frameName, backtest$1) {
|
|
48144
|
+
this.symbol = symbol;
|
|
48145
|
+
this.strategyName = strategyName;
|
|
48146
|
+
this.exchangeName = exchangeName;
|
|
48147
|
+
this.frameName = frameName;
|
|
48148
|
+
this.backtest = backtest$1;
|
|
48149
|
+
this._data = null;
|
|
48150
|
+
/**
|
|
48151
|
+
* Initializes _data to null — local session needs no async setup.
|
|
48152
|
+
* @returns Promise that resolves immediately
|
|
48153
|
+
*/
|
|
48154
|
+
this.waitForInit = functoolsKit.singleshot(async (_initial) => {
|
|
48155
|
+
this._data = null;
|
|
48156
|
+
});
|
|
48157
|
+
/**
|
|
48158
|
+
* Read the current in-memory session value.
|
|
48159
|
+
* @returns Current session value, or null if not set
|
|
48160
|
+
*/
|
|
48161
|
+
this.getData = async () => {
|
|
48162
|
+
backtest.loggerService.debug(SESSION_LOCAL_INSTANCE_METHOD_NAME_GET, {
|
|
48163
|
+
strategyName: this.strategyName,
|
|
48164
|
+
exchangeName: this.exchangeName,
|
|
48165
|
+
frameName: this.frameName,
|
|
48166
|
+
});
|
|
48167
|
+
return this._data;
|
|
48168
|
+
};
|
|
48169
|
+
/**
|
|
48170
|
+
* Update the in-memory session value.
|
|
48171
|
+
* @param value - New value or null to clear
|
|
48172
|
+
*/
|
|
48173
|
+
this.setData = async (value) => {
|
|
48174
|
+
backtest.loggerService.debug(SESSION_LOCAL_INSTANCE_METHOD_NAME_SET, {
|
|
48175
|
+
strategyName: this.strategyName,
|
|
48176
|
+
exchangeName: this.exchangeName,
|
|
48177
|
+
frameName: this.frameName,
|
|
48178
|
+
});
|
|
48179
|
+
this._data = value;
|
|
48180
|
+
};
|
|
48181
|
+
}
|
|
48182
|
+
/** Releases resources held by this instance. */
|
|
48183
|
+
async dispose() {
|
|
48184
|
+
backtest.loggerService.debug(SESSION_BACKTEST_ADAPTER_METHOD_NAME_DISPOSE, {
|
|
48185
|
+
strategyName: this.strategyName,
|
|
48186
|
+
exchangeName: this.exchangeName,
|
|
48187
|
+
frameName: this.frameName,
|
|
48188
|
+
});
|
|
48189
|
+
}
|
|
48190
|
+
}
|
|
48191
|
+
/**
|
|
48192
|
+
* No-op session instance that discards all writes.
|
|
48193
|
+
* Used for disabling session storage in tests or dry-run scenarios.
|
|
48194
|
+
*
|
|
48195
|
+
* Useful when replaying historical candles without needing to accumulate
|
|
48196
|
+
* cross-candle session state — getData always returns null.
|
|
48197
|
+
*/
|
|
48198
|
+
class SessionDummyInstance {
|
|
48199
|
+
constructor(symbol, strategyName, exchangeName, frameName, backtest) {
|
|
48200
|
+
this.symbol = symbol;
|
|
48201
|
+
this.strategyName = strategyName;
|
|
48202
|
+
this.exchangeName = exchangeName;
|
|
48203
|
+
this.frameName = frameName;
|
|
48204
|
+
this.backtest = backtest;
|
|
48205
|
+
/**
|
|
48206
|
+
* No-op initialization.
|
|
48207
|
+
* @returns Promise that resolves immediately
|
|
48208
|
+
*/
|
|
48209
|
+
this.waitForInit = functoolsKit.singleshot(async (_initial) => {
|
|
48210
|
+
});
|
|
48211
|
+
/**
|
|
48212
|
+
* No-op read — always returns null.
|
|
48213
|
+
* @returns null
|
|
48214
|
+
*/
|
|
48215
|
+
this.getData = async () => {
|
|
48216
|
+
return null;
|
|
48217
|
+
};
|
|
48218
|
+
/**
|
|
48219
|
+
* No-op write — discards the value.
|
|
48220
|
+
*/
|
|
48221
|
+
this.setData = async (_value) => {
|
|
48222
|
+
};
|
|
48223
|
+
}
|
|
48224
|
+
/** No-op. */
|
|
48225
|
+
async dispose() {
|
|
48226
|
+
}
|
|
48227
|
+
}
|
|
48228
|
+
/**
|
|
48229
|
+
* File-system backed session instance.
|
|
48230
|
+
* Data is persisted atomically to disk via PersistSessionAdapter.
|
|
48231
|
+
* Session is restored from disk on waitForInit.
|
|
48232
|
+
*
|
|
48233
|
+
* Features:
|
|
48234
|
+
* - Crash-safe atomic file writes
|
|
48235
|
+
* - Scoped per (symbol, strategyName, exchangeName, frameName) tuple
|
|
48236
|
+
*
|
|
48237
|
+
* Use in live trading to survive process restarts mid-session.
|
|
48238
|
+
*/
|
|
48239
|
+
class SessionPersistInstance {
|
|
48240
|
+
constructor(symbol, strategyName, exchangeName, frameName, backtest$1) {
|
|
48241
|
+
this.symbol = symbol;
|
|
48242
|
+
this.strategyName = strategyName;
|
|
48243
|
+
this.exchangeName = exchangeName;
|
|
48244
|
+
this.frameName = frameName;
|
|
48245
|
+
this.backtest = backtest$1;
|
|
48246
|
+
this._data = null;
|
|
48247
|
+
/**
|
|
48248
|
+
* Initialize persistence storage and restore session from disk.
|
|
48249
|
+
* @param initial - Whether this is the first initialization
|
|
48250
|
+
*/
|
|
48251
|
+
this.waitForInit = functoolsKit.singleshot(async (initial) => {
|
|
48252
|
+
backtest.loggerService.debug(SESSION_PERSIST_INSTANCE_METHOD_NAME_WAIT_FOR_INIT, {
|
|
48253
|
+
strategyName: this.strategyName,
|
|
48254
|
+
exchangeName: this.exchangeName,
|
|
48255
|
+
frameName: this.frameName,
|
|
48256
|
+
initial,
|
|
48257
|
+
});
|
|
48258
|
+
await PersistSessionAdapter.waitForInit(this.strategyName, this.exchangeName, this.frameName, initial);
|
|
48259
|
+
const data = await PersistSessionAdapter.readSessionData(this.strategyName, this.exchangeName, this.frameName);
|
|
48260
|
+
if (data) {
|
|
48261
|
+
this._data = data.data;
|
|
48262
|
+
return;
|
|
48263
|
+
}
|
|
48264
|
+
this._data = null;
|
|
48265
|
+
});
|
|
48266
|
+
/**
|
|
48267
|
+
* Read the current persisted session value.
|
|
48268
|
+
* @returns Current session value, or null if not set
|
|
48269
|
+
*/
|
|
48270
|
+
this.getData = async () => {
|
|
48271
|
+
backtest.loggerService.debug(SESSION_PERSIST_INSTANCE_METHOD_NAME_GET, {
|
|
48272
|
+
strategyName: this.strategyName,
|
|
48273
|
+
exchangeName: this.exchangeName,
|
|
48274
|
+
frameName: this.frameName,
|
|
48275
|
+
});
|
|
48276
|
+
return this._data;
|
|
48277
|
+
};
|
|
48278
|
+
/**
|
|
48279
|
+
* Update session value and persist to disk atomically.
|
|
48280
|
+
* @param value - New value or null to clear
|
|
48281
|
+
*/
|
|
48282
|
+
this.setData = async (value) => {
|
|
48283
|
+
backtest.loggerService.debug(SESSION_PERSIST_INSTANCE_METHOD_NAME_SET, {
|
|
48284
|
+
strategyName: this.strategyName,
|
|
48285
|
+
exchangeName: this.exchangeName,
|
|
48286
|
+
frameName: this.frameName,
|
|
48287
|
+
});
|
|
48288
|
+
this._data = value;
|
|
48289
|
+
const id = CREATE_KEY_FN$5(this.symbol, this.strategyName, this.exchangeName, this.frameName, this.backtest);
|
|
48290
|
+
await PersistSessionAdapter.writeSessionData({ id, data: value }, this.strategyName, this.exchangeName, this.frameName);
|
|
48291
|
+
};
|
|
48292
|
+
}
|
|
48293
|
+
/** Releases resources held by this instance. */
|
|
48294
|
+
async dispose() {
|
|
48295
|
+
backtest.loggerService.debug(SESSION_LIVE_ADAPTER_METHOD_NAME_DISPOSE, {
|
|
48296
|
+
strategyName: this.strategyName,
|
|
48297
|
+
exchangeName: this.exchangeName,
|
|
48298
|
+
frameName: this.frameName,
|
|
48299
|
+
});
|
|
48300
|
+
await PersistSessionAdapter.dispose(this.strategyName, this.exchangeName, this.frameName);
|
|
48301
|
+
}
|
|
48302
|
+
}
|
|
48303
|
+
/**
|
|
48304
|
+
* Backtest session adapter with pluggable storage backend.
|
|
48305
|
+
*
|
|
48306
|
+
* Features:
|
|
48307
|
+
* - Adapter pattern for swappable session instance implementations
|
|
48308
|
+
* - Default backend: SessionLocalInstance (in-memory, no disk persistence)
|
|
48309
|
+
* - Alternative backends: SessionPersistInstance, SessionDummyInstance
|
|
48310
|
+
* - Convenience methods: useLocal(), usePersist(), useDummy(), useSessionAdapter()
|
|
48311
|
+
* - Memoized instances per (symbol, strategyName, exchangeName, frameName) tuple
|
|
48312
|
+
*/
|
|
48313
|
+
class SessionBacktestAdapter {
|
|
48314
|
+
constructor() {
|
|
48315
|
+
this.SessionFactory = SessionLocalInstance;
|
|
48316
|
+
this.getInstance = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$5(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => Reflect.construct(this.SessionFactory, [symbol, strategyName, exchangeName, frameName, backtest]));
|
|
48317
|
+
/**
|
|
48318
|
+
* Read the current session value for a backtest run.
|
|
48319
|
+
* @param symbol - Trading pair symbol
|
|
48320
|
+
* @param context.strategyName - Strategy identifier
|
|
48321
|
+
* @param context.exchangeName - Exchange identifier
|
|
48322
|
+
* @param context.frameName - Frame identifier
|
|
48323
|
+
* @returns Current session value, or null if not set
|
|
48324
|
+
*/
|
|
48325
|
+
this.getData = async (symbol, context) => {
|
|
48326
|
+
backtest.loggerService.debug(SESSION_BACKTEST_ADAPTER_METHOD_NAME_GET, {
|
|
48327
|
+
strategyName: context.strategyName,
|
|
48328
|
+
exchangeName: context.exchangeName,
|
|
48329
|
+
frameName: context.frameName,
|
|
48330
|
+
});
|
|
48331
|
+
const key = CREATE_KEY_FN$5(symbol, context.strategyName, context.exchangeName, context.frameName, true);
|
|
48332
|
+
const isInitial = !this.getInstance.has(key);
|
|
48333
|
+
const instance = this.getInstance(symbol, context.strategyName, context.exchangeName, context.frameName, true);
|
|
48334
|
+
await instance.waitForInit(isInitial);
|
|
48335
|
+
return await instance.getData();
|
|
48336
|
+
};
|
|
48337
|
+
/**
|
|
48338
|
+
* Update the session value for a backtest run.
|
|
48339
|
+
* @param symbol - Trading pair symbol
|
|
48340
|
+
* @param value - New value or null to clear
|
|
48341
|
+
* @param context.strategyName - Strategy identifier
|
|
48342
|
+
* @param context.exchangeName - Exchange identifier
|
|
48343
|
+
* @param context.frameName - Frame identifier
|
|
48344
|
+
*/
|
|
48345
|
+
this.setData = async (symbol, value, context) => {
|
|
48346
|
+
backtest.loggerService.debug(SESSION_BACKTEST_ADAPTER_METHOD_NAME_SET, {
|
|
48347
|
+
strategyName: context.strategyName,
|
|
48348
|
+
exchangeName: context.exchangeName,
|
|
48349
|
+
frameName: context.frameName,
|
|
48350
|
+
});
|
|
48351
|
+
const key = CREATE_KEY_FN$5(symbol, context.strategyName, context.exchangeName, context.frameName, true);
|
|
48352
|
+
const isInitial = !this.getInstance.has(key);
|
|
48353
|
+
const instance = this.getInstance(symbol, context.strategyName, context.exchangeName, context.frameName, true);
|
|
48354
|
+
await instance.waitForInit(isInitial);
|
|
48355
|
+
return await instance.setData(value);
|
|
48356
|
+
};
|
|
48357
|
+
/**
|
|
48358
|
+
* Switches to in-memory adapter (default).
|
|
48359
|
+
* All data lives in process memory only.
|
|
48360
|
+
*/
|
|
48361
|
+
this.useLocal = () => {
|
|
48362
|
+
backtest.loggerService.info(SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_LOCAL);
|
|
48363
|
+
this.SessionFactory = SessionLocalInstance;
|
|
48364
|
+
};
|
|
48365
|
+
/**
|
|
48366
|
+
* Switches to file-system backed adapter.
|
|
48367
|
+
* Data is persisted to disk via PersistSessionAdapter.
|
|
48368
|
+
*/
|
|
48369
|
+
this.usePersist = () => {
|
|
48370
|
+
backtest.loggerService.info(SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
|
|
48371
|
+
this.SessionFactory = SessionPersistInstance;
|
|
48372
|
+
};
|
|
48373
|
+
/**
|
|
48374
|
+
* Switches to dummy adapter that discards all writes.
|
|
48375
|
+
*/
|
|
48376
|
+
this.useDummy = () => {
|
|
48377
|
+
backtest.loggerService.info(SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
|
|
48378
|
+
this.SessionFactory = SessionDummyInstance;
|
|
48379
|
+
};
|
|
48380
|
+
/**
|
|
48381
|
+
* Switches to a custom session adapter implementation.
|
|
48382
|
+
* @param Ctor - Constructor for the custom session instance
|
|
48383
|
+
*/
|
|
48384
|
+
this.useSessionAdapter = (Ctor) => {
|
|
48385
|
+
backtest.loggerService.info(SESSION_BACKTEST_ADAPTER_METHOD_NAME_USE_SESSION_ADAPTER);
|
|
48386
|
+
this.SessionFactory = Ctor;
|
|
48387
|
+
};
|
|
48388
|
+
/**
|
|
48389
|
+
* Clears the memoized instance cache.
|
|
48390
|
+
* Call this when process.cwd() changes between strategy iterations
|
|
48391
|
+
* so new instances are created with the updated base path.
|
|
48392
|
+
*/
|
|
48393
|
+
this.clear = () => {
|
|
48394
|
+
backtest.loggerService.info(SESSION_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
|
|
48395
|
+
this.getInstance.clear();
|
|
48396
|
+
};
|
|
48397
|
+
}
|
|
48398
|
+
}
|
|
48399
|
+
/**
|
|
48400
|
+
* Live trading session adapter with pluggable storage backend.
|
|
48401
|
+
*
|
|
48402
|
+
* Features:
|
|
48403
|
+
* - Adapter pattern for swappable session instance implementations
|
|
48404
|
+
* - Default backend: SessionPersistInstance (file-system backed, survives restarts)
|
|
48405
|
+
* - Alternative backends: SessionLocalInstance, SessionDummyInstance
|
|
48406
|
+
* - Convenience methods: useLocal(), usePersist(), useDummy(), useSessionAdapter()
|
|
48407
|
+
* - Memoized instances per (symbol, strategyName, exchangeName, frameName) tuple
|
|
48408
|
+
*/
|
|
48409
|
+
class SessionLiveAdapter {
|
|
48410
|
+
constructor() {
|
|
48411
|
+
this.SessionFactory = SessionPersistInstance;
|
|
48412
|
+
this.getInstance = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$5(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => Reflect.construct(this.SessionFactory, [symbol, strategyName, exchangeName, frameName, backtest]));
|
|
48413
|
+
/**
|
|
48414
|
+
* Read the current session value for a live run.
|
|
48415
|
+
* @param symbol - Trading pair symbol
|
|
48416
|
+
* @param context.strategyName - Strategy identifier
|
|
48417
|
+
* @param context.exchangeName - Exchange identifier
|
|
48418
|
+
* @param context.frameName - Frame identifier
|
|
48419
|
+
* @returns Current session value, or null if not set
|
|
48420
|
+
*/
|
|
48421
|
+
this.getData = async (symbol, context) => {
|
|
48422
|
+
backtest.loggerService.debug(SESSION_LIVE_ADAPTER_METHOD_NAME_GET, {
|
|
48423
|
+
strategyName: context.strategyName,
|
|
48424
|
+
exchangeName: context.exchangeName,
|
|
48425
|
+
frameName: context.frameName,
|
|
48426
|
+
});
|
|
48427
|
+
const key = CREATE_KEY_FN$5(symbol, context.strategyName, context.exchangeName, context.frameName, false);
|
|
48428
|
+
const isInitial = !this.getInstance.has(key);
|
|
48429
|
+
const instance = this.getInstance(symbol, context.strategyName, context.exchangeName, context.frameName, false);
|
|
48430
|
+
await instance.waitForInit(isInitial);
|
|
48431
|
+
return await instance.getData();
|
|
48432
|
+
};
|
|
48433
|
+
/**
|
|
48434
|
+
* Update the session value for a live run.
|
|
48435
|
+
* @param symbol - Trading pair symbol
|
|
48436
|
+
* @param value - New value or null to clear
|
|
48437
|
+
* @param context.strategyName - Strategy identifier
|
|
48438
|
+
* @param context.exchangeName - Exchange identifier
|
|
48439
|
+
* @param context.frameName - Frame identifier
|
|
48440
|
+
*/
|
|
48441
|
+
this.setData = async (symbol, value, context) => {
|
|
48442
|
+
backtest.loggerService.debug(SESSION_LIVE_ADAPTER_METHOD_NAME_SET, {
|
|
48443
|
+
strategyName: context.strategyName,
|
|
48444
|
+
exchangeName: context.exchangeName,
|
|
48445
|
+
frameName: context.frameName,
|
|
48446
|
+
});
|
|
48447
|
+
const key = CREATE_KEY_FN$5(symbol, context.strategyName, context.exchangeName, context.frameName, false);
|
|
48448
|
+
const isInitial = !this.getInstance.has(key);
|
|
48449
|
+
const instance = this.getInstance(symbol, context.strategyName, context.exchangeName, context.frameName, false);
|
|
48450
|
+
await instance.waitForInit(isInitial);
|
|
48451
|
+
return await instance.setData(value);
|
|
48452
|
+
};
|
|
48453
|
+
/**
|
|
48454
|
+
* Switches to in-memory adapter.
|
|
48455
|
+
* All data lives in process memory only.
|
|
48456
|
+
*/
|
|
48457
|
+
this.useLocal = () => {
|
|
48458
|
+
backtest.loggerService.info(SESSION_LIVE_ADAPTER_METHOD_NAME_USE_LOCAL);
|
|
48459
|
+
this.SessionFactory = SessionLocalInstance;
|
|
48460
|
+
};
|
|
48461
|
+
/**
|
|
48462
|
+
* Switches to file-system backed adapter (default).
|
|
48463
|
+
* Data is persisted to disk via PersistSessionAdapter.
|
|
48464
|
+
*/
|
|
48465
|
+
this.usePersist = () => {
|
|
48466
|
+
backtest.loggerService.info(SESSION_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
|
|
48467
|
+
this.SessionFactory = SessionPersistInstance;
|
|
48468
|
+
};
|
|
48469
|
+
/**
|
|
48470
|
+
* Switches to dummy adapter that discards all writes.
|
|
48471
|
+
*/
|
|
48472
|
+
this.useDummy = () => {
|
|
48473
|
+
backtest.loggerService.info(SESSION_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
|
|
48474
|
+
this.SessionFactory = SessionDummyInstance;
|
|
48475
|
+
};
|
|
48476
|
+
/**
|
|
48477
|
+
* Switches to a custom session adapter implementation.
|
|
48478
|
+
* @param Ctor - Constructor for the custom session instance
|
|
48479
|
+
*/
|
|
48480
|
+
this.useSessionAdapter = (Ctor) => {
|
|
48481
|
+
backtest.loggerService.info(SESSION_LIVE_ADAPTER_METHOD_NAME_USE_SESSION_ADAPTER);
|
|
48482
|
+
this.SessionFactory = Ctor;
|
|
48483
|
+
};
|
|
48484
|
+
/**
|
|
48485
|
+
* Clears the memoized instance cache.
|
|
48486
|
+
* Call this when process.cwd() changes between strategy iterations
|
|
48487
|
+
* so new instances are created with the updated base path.
|
|
48488
|
+
*/
|
|
48489
|
+
this.clear = () => {
|
|
48490
|
+
backtest.loggerService.info(SESSION_LIVE_ADAPTER_METHOD_NAME_CLEAR);
|
|
48491
|
+
this.getInstance.clear();
|
|
48492
|
+
};
|
|
48493
|
+
}
|
|
48494
|
+
}
|
|
48495
|
+
/**
|
|
48496
|
+
* Main session adapter that manages both backtest and live session storage.
|
|
48497
|
+
*
|
|
48498
|
+
* Features:
|
|
48499
|
+
* - Routes all operations to SessionBacktest or SessionLive based on the backtest flag
|
|
48500
|
+
*/
|
|
48501
|
+
class SessionAdapter {
|
|
48502
|
+
constructor() {
|
|
48503
|
+
/**
|
|
48504
|
+
* Read the current session value for a signal.
|
|
48505
|
+
* Routes to SessionBacktest or SessionLive based on backtest.
|
|
48506
|
+
* @param symbol - Trading pair symbol
|
|
48507
|
+
* @param context.strategyName - Strategy identifier
|
|
48508
|
+
* @param context.exchangeName - Exchange identifier
|
|
48509
|
+
* @param context.frameName - Frame identifier
|
|
48510
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
48511
|
+
* @returns Current session value, or null if not set
|
|
48512
|
+
*/
|
|
48513
|
+
this.getData = async (symbol, context, backtest$1) => {
|
|
48514
|
+
backtest.loggerService.debug(SESSION_ADAPTER_METHOD_NAME_GET, {
|
|
48515
|
+
strategyName: context.strategyName,
|
|
48516
|
+
exchangeName: context.exchangeName,
|
|
48517
|
+
frameName: context.frameName,
|
|
48518
|
+
backtest: backtest$1,
|
|
48519
|
+
});
|
|
48520
|
+
if (backtest$1) {
|
|
48521
|
+
return await SessionBacktest.getData(symbol, context);
|
|
48522
|
+
}
|
|
48523
|
+
return await SessionLive.getData(symbol, context);
|
|
48524
|
+
};
|
|
48525
|
+
/**
|
|
48526
|
+
* Update the session value for a signal.
|
|
48527
|
+
* Routes to SessionBacktest or SessionLive based on backtest.
|
|
48528
|
+
* @param symbol - Trading pair symbol
|
|
48529
|
+
* @param value - New value or null to clear
|
|
48530
|
+
* @param context.strategyName - Strategy identifier
|
|
48531
|
+
* @param context.exchangeName - Exchange identifier
|
|
48532
|
+
* @param context.frameName - Frame identifier
|
|
48533
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
48534
|
+
*/
|
|
48535
|
+
this.setData = async (symbol, value, context, backtest$1) => {
|
|
48536
|
+
backtest.loggerService.debug(SESSION_ADAPTER_METHOD_NAME_SET, {
|
|
48537
|
+
strategyName: context.strategyName,
|
|
48538
|
+
exchangeName: context.exchangeName,
|
|
48539
|
+
frameName: context.frameName,
|
|
48540
|
+
backtest: backtest$1,
|
|
48541
|
+
});
|
|
48542
|
+
if (backtest$1) {
|
|
48543
|
+
return await SessionBacktest.setData(symbol, value, context);
|
|
48544
|
+
}
|
|
48545
|
+
return await SessionLive.setData(symbol, value, context);
|
|
48546
|
+
};
|
|
48547
|
+
}
|
|
48548
|
+
}
|
|
48549
|
+
/**
|
|
48550
|
+
* Global singleton instance of SessionAdapter.
|
|
48551
|
+
* Provides unified session management for backtest and live trading.
|
|
48552
|
+
*/
|
|
48553
|
+
const Session = new SessionAdapter();
|
|
48554
|
+
/**
|
|
48555
|
+
* Global singleton instance of SessionLiveAdapter.
|
|
48556
|
+
* Provides live trading session storage with pluggable backends.
|
|
48557
|
+
*/
|
|
48558
|
+
const SessionLive = new SessionLiveAdapter();
|
|
48559
|
+
/**
|
|
48560
|
+
* Global singleton instance of SessionBacktestAdapter.
|
|
48561
|
+
* Provides backtest session storage with pluggable backends.
|
|
48562
|
+
*/
|
|
48563
|
+
const SessionBacktest = new SessionBacktestAdapter();
|
|
48564
|
+
|
|
48565
|
+
const GET_SESSION_METHOD_NAME = "session.getSession";
|
|
48566
|
+
const SET_SESSION_METHOD_NAME = "session.setSession";
|
|
48567
|
+
/**
|
|
48568
|
+
* Reads the session value scoped to the current (symbol, strategy, exchange, frame) context.
|
|
48569
|
+
*
|
|
48570
|
+
* Session data persists across candles within a single run and can survive process
|
|
48571
|
+
* restarts in live mode — useful for caching LLM inference results, intermediate
|
|
48572
|
+
* indicator state, or any cross-candle accumulator that is not tied to a specific signal.
|
|
48573
|
+
*
|
|
48574
|
+
* Automatically detects backtest/live mode from execution context.
|
|
48575
|
+
*
|
|
48576
|
+
* @param symbol - Trading pair symbol
|
|
48577
|
+
* @returns Promise resolving to current session value, or null if not set
|
|
48578
|
+
*
|
|
48579
|
+
* @example
|
|
48580
|
+
* ```typescript
|
|
48581
|
+
* import { getSession } from "backtest-kit";
|
|
48582
|
+
*
|
|
48583
|
+
* const session = await getSession<{ lastLlmSignal: string }>("BTCUSDT");
|
|
48584
|
+
* if (session?.lastLlmSignal === "buy") {
|
|
48585
|
+
* // reuse cached LLM result instead of calling the model again
|
|
48586
|
+
* }
|
|
48587
|
+
* ```
|
|
48588
|
+
*/
|
|
48589
|
+
async function getSessionData(symbol) {
|
|
48590
|
+
backtest.loggerService.info(GET_SESSION_METHOD_NAME, { symbol });
|
|
48591
|
+
if (!ExecutionContextService.hasContext()) {
|
|
48592
|
+
throw new Error("getSession requires an execution context");
|
|
48593
|
+
}
|
|
48594
|
+
if (!MethodContextService.hasContext()) {
|
|
48595
|
+
throw new Error("getSession requires a method context");
|
|
48596
|
+
}
|
|
48597
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
48598
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
48599
|
+
return await Session.getData(symbol, { exchangeName, frameName, strategyName }, isBacktest);
|
|
48600
|
+
}
|
|
48601
|
+
/**
|
|
48602
|
+
* Writes a session value scoped to the current (symbol, strategy, exchange, frame) context.
|
|
48603
|
+
*
|
|
48604
|
+
* Session data persists across candles within a single run and can survive process
|
|
48605
|
+
* restarts in live mode — useful for caching LLM inference results, intermediate
|
|
48606
|
+
* indicator state, or any cross-candle accumulator that is not tied to a specific signal.
|
|
48607
|
+
*
|
|
48608
|
+
* Pass null to clear the session.
|
|
48609
|
+
*
|
|
48610
|
+
* Automatically detects backtest/live mode from execution context.
|
|
48611
|
+
*
|
|
48612
|
+
* @param symbol - Trading pair symbol
|
|
48613
|
+
* @param value - New value or null to clear
|
|
48614
|
+
* @returns Promise that resolves when the session has been written
|
|
48615
|
+
*
|
|
48616
|
+
* @example
|
|
48617
|
+
* ```typescript
|
|
48618
|
+
* import { setSession } from "backtest-kit";
|
|
48619
|
+
*
|
|
48620
|
+
* await setSession("BTCUSDT", { lastLlmSignal: "buy" });
|
|
48621
|
+
* ```
|
|
48622
|
+
*/
|
|
48623
|
+
async function setSessionData(symbol, value) {
|
|
48624
|
+
backtest.loggerService.info(SET_SESSION_METHOD_NAME, { symbol });
|
|
48625
|
+
if (!ExecutionContextService.hasContext()) {
|
|
48626
|
+
throw new Error("setSession requires an execution context");
|
|
48627
|
+
}
|
|
48628
|
+
if (!MethodContextService.hasContext()) {
|
|
48629
|
+
throw new Error("setSession requires a method context");
|
|
48630
|
+
}
|
|
48631
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
48632
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
48633
|
+
await Session.setData(symbol, value, { exchangeName, frameName, strategyName }, isBacktest);
|
|
48634
|
+
}
|
|
48635
|
+
|
|
47947
48636
|
const CREATE_SIGNAL_STATE_METHOD_NAME = "state.createSignalState";
|
|
47948
|
-
const CREATE_SET_STATE_FN = (params) => async (dispatch) => {
|
|
48637
|
+
const CREATE_SET_STATE_FN = (params) => async (symbol, dispatch) => {
|
|
47949
48638
|
if (!ExecutionContextService.hasContext()) {
|
|
47950
48639
|
throw new Error("createSignalState requires an execution context");
|
|
47951
48640
|
}
|
|
47952
48641
|
if (!MethodContextService.hasContext()) {
|
|
47953
48642
|
throw new Error("createSignalState requires a method context");
|
|
47954
48643
|
}
|
|
47955
|
-
const { backtest: isBacktest
|
|
48644
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
47956
48645
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
47957
48646
|
const currentPrice = await backtest.exchangeConnectionService.getAveragePrice(symbol);
|
|
47958
48647
|
let signal;
|
|
@@ -47974,14 +48663,14 @@ const CREATE_SET_STATE_FN = (params) => async (dispatch) => {
|
|
|
47974
48663
|
}
|
|
47975
48664
|
throw new Error(`createSignalState requires a pending or scheduled signal for symbol=${symbol} bucketName=${params.bucketName}`);
|
|
47976
48665
|
};
|
|
47977
|
-
const CREATE_GET_STATE_FN = (params) => async () => {
|
|
48666
|
+
const CREATE_GET_STATE_FN = (params) => async (symbol) => {
|
|
47978
48667
|
if (!ExecutionContextService.hasContext()) {
|
|
47979
48668
|
throw new Error("createSignalState requires an execution context");
|
|
47980
48669
|
}
|
|
47981
48670
|
if (!MethodContextService.hasContext()) {
|
|
47982
48671
|
throw new Error("createSignalState requires a method context");
|
|
47983
48672
|
}
|
|
47984
|
-
const { backtest: isBacktest
|
|
48673
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
47985
48674
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
47986
48675
|
const currentPrice = await backtest.exchangeConnectionService.getAveragePrice(symbol);
|
|
47987
48676
|
let signal;
|
|
@@ -51802,7 +52491,7 @@ class LogAdapter {
|
|
|
51802
52491
|
*/
|
|
51803
52492
|
const Log = new LogAdapter();
|
|
51804
52493
|
|
|
51805
|
-
const METHOD_NAME_CREATE_SNAPSHOT = "
|
|
52494
|
+
const METHOD_NAME_CREATE_SNAPSHOT = "SystemUtils.createSnapshot";
|
|
51806
52495
|
/** List of all global subjects whose listeners should be snapshotted for session isolation */
|
|
51807
52496
|
const SUBJECT_ISOLATION_LIST = [
|
|
51808
52497
|
activePingSubject,
|
|
@@ -51849,7 +52538,7 @@ const CREATE_SUBJECT_SNAPSHOT_FN = (subject) => {
|
|
|
51849
52538
|
* Allows temporarily detaching all subject subscriptions so that one session
|
|
51850
52539
|
* does not interfere with another, then restoring them afterwards.
|
|
51851
52540
|
*/
|
|
51852
|
-
class
|
|
52541
|
+
class SystemUtils {
|
|
51853
52542
|
constructor() {
|
|
51854
52543
|
/**
|
|
51855
52544
|
* Snapshots the current listener state of every global subject by replacing
|
|
@@ -51863,7 +52552,7 @@ class SessionUtils {
|
|
|
51863
52552
|
};
|
|
51864
52553
|
}
|
|
51865
52554
|
}
|
|
51866
|
-
const
|
|
52555
|
+
const System = new SystemUtils();
|
|
51867
52556
|
|
|
51868
52557
|
const SCHEDULE_METHOD_NAME_GET_DATA = "ScheduleUtils.getData";
|
|
51869
52558
|
const SCHEDULE_METHOD_NAME_GET_REPORT = "ScheduleUtils.getReport";
|
|
@@ -60931,6 +61620,7 @@ exports.PersistPartialAdapter = PersistPartialAdapter;
|
|
|
60931
61620
|
exports.PersistRecentAdapter = PersistRecentAdapter;
|
|
60932
61621
|
exports.PersistRiskAdapter = PersistRiskAdapter;
|
|
60933
61622
|
exports.PersistScheduleAdapter = PersistScheduleAdapter;
|
|
61623
|
+
exports.PersistSessionAdapter = PersistSessionAdapter;
|
|
60934
61624
|
exports.PersistSignalAdapter = PersistSignalAdapter;
|
|
60935
61625
|
exports.PersistStateAdapter = PersistStateAdapter;
|
|
60936
61626
|
exports.PersistStorageAdapter = PersistStorageAdapter;
|
|
@@ -60946,6 +61636,8 @@ exports.ReportWriter = ReportWriter;
|
|
|
60946
61636
|
exports.Risk = Risk;
|
|
60947
61637
|
exports.Schedule = Schedule;
|
|
60948
61638
|
exports.Session = Session;
|
|
61639
|
+
exports.SessionBacktest = SessionBacktest;
|
|
61640
|
+
exports.SessionLive = SessionLive;
|
|
60949
61641
|
exports.State = State;
|
|
60950
61642
|
exports.StateBacktest = StateBacktest;
|
|
60951
61643
|
exports.StateBacktestAdapter = StateBacktestAdapter;
|
|
@@ -60956,6 +61648,7 @@ exports.StorageBacktest = StorageBacktest;
|
|
|
60956
61648
|
exports.StorageLive = StorageLive;
|
|
60957
61649
|
exports.Strategy = Strategy;
|
|
60958
61650
|
exports.Sync = Sync;
|
|
61651
|
+
exports.System = System;
|
|
60959
61652
|
exports.Walker = Walker;
|
|
60960
61653
|
exports.addActionSchema = addActionSchema;
|
|
60961
61654
|
exports.addExchangeSchema = addExchangeSchema;
|
|
@@ -61047,6 +61740,7 @@ exports.getPositionWaitingMinutes = getPositionWaitingMinutes;
|
|
|
61047
61740
|
exports.getRawCandles = getRawCandles;
|
|
61048
61741
|
exports.getRiskSchema = getRiskSchema;
|
|
61049
61742
|
exports.getScheduledSignal = getScheduledSignal;
|
|
61743
|
+
exports.getSessionData = getSessionData;
|
|
61050
61744
|
exports.getSignalState = getSignalState;
|
|
61051
61745
|
exports.getSizingSchema = getSizingSchema;
|
|
61052
61746
|
exports.getStrategySchema = getStrategySchema;
|
|
@@ -61133,6 +61827,7 @@ exports.set = set;
|
|
|
61133
61827
|
exports.setColumns = setColumns;
|
|
61134
61828
|
exports.setConfig = setConfig;
|
|
61135
61829
|
exports.setLogger = setLogger;
|
|
61830
|
+
exports.setSessionData = setSessionData;
|
|
61136
61831
|
exports.setSignalState = setSignalState;
|
|
61137
61832
|
exports.shutdown = shutdown;
|
|
61138
61833
|
exports.slPercentShiftToPrice = slPercentShiftToPrice;
|