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 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$w = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$w(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
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$w(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$v = (riskName, exchangeName, frameName, backtest) => {
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$v(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
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$v(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
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$u = (actionName, strategyName, exchangeName, frameName, backtest) => {
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$u(actionName, strategyName, exchangeName, frameName, backtest), (actionName, strategyName, exchangeName, frameName, backtest) => {
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$u(payload.actionName, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$t = (exchangeName) => {
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$t(exchangeName), async (exchangeName) => {
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$s = (context) => {
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$s(context), async (context) => {
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$r = (context) => {
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$r(context), async (context) => {
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$q = (context) => {
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$q(context), async (context) => {
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$p = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$p(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$a(symbol, strategyName, exchangeName, frameName));
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$p(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$o = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$o(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$9(symbol, strategyName, exchangeName, frameName));
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$o(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$n = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$n(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$8(symbol, strategyName, exchangeName, frameName));
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$n(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$m = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$m(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new PerformanceStorage(symbol, strategyName, exchangeName, frameName));
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$m(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$l = (exchangeName, frameName, backtest) => {
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$l(exchangeName, frameName, backtest), (exchangeName, frameName, backtest) => new HeatmapStorage(exchangeName, frameName, backtest));
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$l(payload.exchangeName, payload.frameName, payload.backtest);
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$k = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
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$k(signalId, backtest), (signalId, backtest) => {
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$k(data.id, backtest);
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$j = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$j(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$6(symbol, strategyName, exchangeName, frameName));
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$j(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$i = (context) => {
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$i(context), (context, methodName) => {
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$h = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
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$h(signalId, backtest), (signalId, backtest) => {
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$h(data.id, backtest);
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$g = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$g(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$5(symbol, strategyName, exchangeName, frameName));
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$g(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$f = (context) => {
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$f(context), (context, methodName) => {
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$e = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$e(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$4(symbol, strategyName, exchangeName, frameName));
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$e(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$d = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$d(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$3(symbol, strategyName, exchangeName, frameName));
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$d(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$c = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$c(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$2(symbol, strategyName, exchangeName, frameName, backtest));
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$c(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$b(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$1(symbol, strategyName, exchangeName, frameName));
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$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$a = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$a(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
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$a(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
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$a(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
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$a(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$9(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
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$9(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
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$9(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
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$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$8(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage(symbol, strategyName, exchangeName, frameName));
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$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
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$7 = (context) => {
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$7(context), async (context) => {
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$6 = (symbol, strategyName, exchangeName, frameName, backtest) => {
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$6(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
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$6(symbol, strategyName, exchangeName, frameName, backtest$1);
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$6(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
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$6(symbol, strategyName, exchangeName, frameName, backtest$1);
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$5 = (signalId, bucketName) => `${signalId}_${bucketName}`;
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$5(this.signalId, this.bucketName);
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$5(signalId, bucketName), (signalId, bucketName, initialValue) => Reflect.construct(this.StateFactory, [initialValue, signalId, bucketName]));
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$5(signalId, "");
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$5(dto.signalId, dto.bucketName);
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$5(dto.signalId, dto.bucketName);
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$5(signalId, bucketName), (signalId, bucketName, initialValue) => Reflect.construct(this.StateFactory, [initialValue, signalId, bucketName]));
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$5(signalId, "");
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$5(dto.signalId, dto.bucketName);
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$5(dto.signalId, dto.bucketName);
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, symbol } = backtest.executionContextService.context;
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, symbol } = backtest.executionContextService.context;
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, symbol } = backtest.executionContextService.context;
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, symbol } = backtest.executionContextService.context;
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 = "SessionUtils.createSnapshot";
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 SessionUtils {
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 Session = new SessionUtils();
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;