backtest-kit 2.2.17 → 2.2.19

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.
Files changed (4) hide show
  1. package/build/index.cjs +1042 -242
  2. package/build/index.mjs +1041 -243
  3. package/package.json +1 -1
  4. package/types.d.ts +434 -143
package/build/index.cjs CHANGED
@@ -2828,6 +2828,11 @@ const INTERVAL_MINUTES$3 = {
2828
2828
  "30m": 30,
2829
2829
  "1h": 60,
2830
2830
  };
2831
+ /**
2832
+ * Mock value for scheduled signal pendingAt timestamp.
2833
+ * Used to indicate that the actual pendingAt will be set upon activation.
2834
+ */
2835
+ const SCHEDULED_SIGNAL_PENDING_MOCK = 0;
2831
2836
  const TIMEOUT_SYMBOL = Symbol('timeout');
2832
2837
  /**
2833
2838
  * Calls onCommit callback with strategy commit event.
@@ -2867,73 +2872,123 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, timestamp) => {
2867
2872
  return;
2868
2873
  }
2869
2874
  const queue = self._commitQueue;
2870
- self._commitQueue = [];
2875
+ {
2876
+ self._commitQueue = [];
2877
+ }
2878
+ if (!self._pendingSignal) {
2879
+ return;
2880
+ }
2881
+ // Get public signal data for commit events (contains effective and original SL/TP)
2882
+ const publicSignal = TO_PUBLIC_SIGNAL(self._pendingSignal);
2871
2883
  for (const commit of queue) {
2872
- switch (commit.action) {
2873
- case "partial-profit":
2874
- await CALL_COMMIT_FN(self, {
2875
- action: "partial-profit",
2876
- symbol: commit.symbol,
2877
- strategyName: self.params.strategyName,
2878
- exchangeName: self.params.exchangeName,
2879
- frameName: self.params.frameName,
2880
- backtest: commit.backtest,
2881
- percentToClose: commit.percentToClose,
2882
- currentPrice: commit.currentPrice,
2883
- timestamp,
2884
- });
2885
- break;
2886
- case "partial-loss":
2887
- await CALL_COMMIT_FN(self, {
2888
- action: "partial-loss",
2889
- symbol: commit.symbol,
2890
- strategyName: self.params.strategyName,
2891
- exchangeName: self.params.exchangeName,
2892
- frameName: self.params.frameName,
2893
- backtest: commit.backtest,
2894
- percentToClose: commit.percentToClose,
2895
- currentPrice: commit.currentPrice,
2896
- timestamp,
2897
- });
2898
- break;
2899
- case "breakeven":
2900
- await CALL_COMMIT_FN(self, {
2901
- action: "breakeven",
2902
- symbol: commit.symbol,
2903
- strategyName: self.params.strategyName,
2904
- exchangeName: self.params.exchangeName,
2905
- frameName: self.params.frameName,
2906
- backtest: commit.backtest,
2907
- currentPrice: commit.currentPrice,
2908
- timestamp,
2909
- });
2910
- break;
2911
- case "trailing-stop":
2912
- await CALL_COMMIT_FN(self, {
2913
- action: "trailing-stop",
2914
- symbol: commit.symbol,
2915
- strategyName: self.params.strategyName,
2916
- exchangeName: self.params.exchangeName,
2917
- frameName: self.params.frameName,
2918
- backtest: commit.backtest,
2919
- percentShift: commit.percentShift,
2920
- currentPrice: commit.currentPrice,
2921
- timestamp,
2922
- });
2923
- break;
2924
- case "trailing-take":
2925
- await CALL_COMMIT_FN(self, {
2926
- action: "trailing-take",
2927
- symbol: commit.symbol,
2928
- strategyName: self.params.strategyName,
2929
- exchangeName: self.params.exchangeName,
2930
- frameName: self.params.frameName,
2931
- backtest: commit.backtest,
2932
- percentShift: commit.percentShift,
2933
- currentPrice: commit.currentPrice,
2934
- timestamp,
2935
- });
2936
- break;
2884
+ if (commit.action === "partial-profit") {
2885
+ await CALL_COMMIT_FN(self, {
2886
+ action: "partial-profit",
2887
+ symbol: commit.symbol,
2888
+ strategyName: self.params.strategyName,
2889
+ exchangeName: self.params.exchangeName,
2890
+ frameName: self.params.frameName,
2891
+ backtest: commit.backtest,
2892
+ percentToClose: commit.percentToClose,
2893
+ currentPrice: commit.currentPrice,
2894
+ timestamp,
2895
+ position: publicSignal.position,
2896
+ priceOpen: publicSignal.priceOpen,
2897
+ priceTakeProfit: publicSignal.priceTakeProfit,
2898
+ priceStopLoss: publicSignal.priceStopLoss,
2899
+ originalPriceTakeProfit: publicSignal.originalPriceTakeProfit,
2900
+ originalPriceStopLoss: publicSignal.originalPriceStopLoss,
2901
+ scheduledAt: publicSignal.scheduledAt,
2902
+ pendingAt: publicSignal.pendingAt,
2903
+ });
2904
+ continue;
2905
+ }
2906
+ if (commit.action === "partial-loss") {
2907
+ await CALL_COMMIT_FN(self, {
2908
+ action: "partial-loss",
2909
+ symbol: commit.symbol,
2910
+ strategyName: self.params.strategyName,
2911
+ exchangeName: self.params.exchangeName,
2912
+ frameName: self.params.frameName,
2913
+ backtest: commit.backtest,
2914
+ percentToClose: commit.percentToClose,
2915
+ currentPrice: commit.currentPrice,
2916
+ timestamp,
2917
+ position: publicSignal.position,
2918
+ priceOpen: publicSignal.priceOpen,
2919
+ priceTakeProfit: publicSignal.priceTakeProfit,
2920
+ priceStopLoss: publicSignal.priceStopLoss,
2921
+ originalPriceTakeProfit: publicSignal.originalPriceTakeProfit,
2922
+ originalPriceStopLoss: publicSignal.originalPriceStopLoss,
2923
+ scheduledAt: publicSignal.scheduledAt,
2924
+ pendingAt: publicSignal.pendingAt,
2925
+ });
2926
+ continue;
2927
+ }
2928
+ if (commit.action === "breakeven") {
2929
+ await CALL_COMMIT_FN(self, {
2930
+ action: "breakeven",
2931
+ symbol: commit.symbol,
2932
+ strategyName: self.params.strategyName,
2933
+ exchangeName: self.params.exchangeName,
2934
+ frameName: self.params.frameName,
2935
+ backtest: commit.backtest,
2936
+ currentPrice: commit.currentPrice,
2937
+ timestamp,
2938
+ position: publicSignal.position,
2939
+ priceOpen: publicSignal.priceOpen,
2940
+ priceTakeProfit: publicSignal.priceTakeProfit,
2941
+ priceStopLoss: publicSignal.priceStopLoss,
2942
+ originalPriceTakeProfit: publicSignal.originalPriceTakeProfit,
2943
+ originalPriceStopLoss: publicSignal.originalPriceStopLoss,
2944
+ scheduledAt: publicSignal.scheduledAt,
2945
+ pendingAt: publicSignal.pendingAt,
2946
+ });
2947
+ continue;
2948
+ }
2949
+ if (commit.action === "trailing-stop") {
2950
+ await CALL_COMMIT_FN(self, {
2951
+ action: "trailing-stop",
2952
+ symbol: commit.symbol,
2953
+ strategyName: self.params.strategyName,
2954
+ exchangeName: self.params.exchangeName,
2955
+ frameName: self.params.frameName,
2956
+ backtest: commit.backtest,
2957
+ percentShift: commit.percentShift,
2958
+ currentPrice: commit.currentPrice,
2959
+ timestamp,
2960
+ position: publicSignal.position,
2961
+ priceOpen: publicSignal.priceOpen,
2962
+ priceTakeProfit: publicSignal.priceTakeProfit,
2963
+ priceStopLoss: publicSignal.priceStopLoss,
2964
+ originalPriceTakeProfit: publicSignal.originalPriceTakeProfit,
2965
+ originalPriceStopLoss: publicSignal.originalPriceStopLoss,
2966
+ scheduledAt: publicSignal.scheduledAt,
2967
+ pendingAt: publicSignal.pendingAt,
2968
+ });
2969
+ continue;
2970
+ }
2971
+ if (commit.action === "trailing-take") {
2972
+ await CALL_COMMIT_FN(self, {
2973
+ action: "trailing-take",
2974
+ symbol: commit.symbol,
2975
+ strategyName: self.params.strategyName,
2976
+ exchangeName: self.params.exchangeName,
2977
+ frameName: self.params.frameName,
2978
+ backtest: commit.backtest,
2979
+ percentShift: commit.percentShift,
2980
+ currentPrice: commit.currentPrice,
2981
+ timestamp,
2982
+ position: publicSignal.position,
2983
+ priceOpen: publicSignal.priceOpen,
2984
+ priceTakeProfit: publicSignal.priceTakeProfit,
2985
+ priceStopLoss: publicSignal.priceStopLoss,
2986
+ originalPriceTakeProfit: publicSignal.originalPriceTakeProfit,
2987
+ originalPriceStopLoss: publicSignal.originalPriceStopLoss,
2988
+ scheduledAt: publicSignal.scheduledAt,
2989
+ pendingAt: publicSignal.pendingAt,
2990
+ });
2991
+ continue;
2937
2992
  }
2938
2993
  }
2939
2994
  };
@@ -3258,7 +3313,7 @@ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
3258
3313
  if (typeof signal.pendingAt !== "number") {
3259
3314
  errors.push(`pendingAt must be a number type, got ${signal.pendingAt} (${typeof signal.pendingAt})`);
3260
3315
  }
3261
- if (signal.pendingAt <= 0) {
3316
+ if (signal.pendingAt <= 0 && !isScheduled) {
3262
3317
  errors.push(`pendingAt must be positive, got ${signal.pendingAt}`);
3263
3318
  }
3264
3319
  }
@@ -3344,7 +3399,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
3344
3399
  strategyName: self.params.method.context.strategyName,
3345
3400
  frameName: self.params.method.context.frameName,
3346
3401
  scheduledAt: currentTime,
3347
- pendingAt: currentTime, // Временно, обновится при активации
3402
+ pendingAt: SCHEDULED_SIGNAL_PENDING_MOCK, // Временно, обновится при активации
3348
3403
  _isScheduled: true,
3349
3404
  };
3350
3405
  // Валидируем сигнал перед возвратом
@@ -13488,6 +13543,8 @@ const backtest_columns = [
13488
13543
  key: "duration",
13489
13544
  label: "Duration (min)",
13490
13545
  format: (data) => {
13546
+ if (!data.closeTimestamp || !data.signal.pendingAt)
13547
+ return "N/A";
13491
13548
  const durationMs = data.closeTimestamp - data.signal.pendingAt;
13492
13549
  const durationMin = Math.round(durationMs / 60000);
13493
13550
  return `${durationMin}`;
@@ -13497,7 +13554,7 @@ const backtest_columns = [
13497
13554
  {
13498
13555
  key: "openTimestamp",
13499
13556
  label: "Open Time",
13500
- format: (data) => new Date(data.signal.pendingAt).toISOString(),
13557
+ format: (data) => data.signal.pendingAt ? new Date(data.signal.pendingAt).toISOString() : "N/A",
13501
13558
  isVisible: () => true,
13502
13559
  },
13503
13560
  {
@@ -23626,7 +23683,7 @@ class RiskReportService {
23626
23683
  strategyName: data.strategyName,
23627
23684
  exchangeName: data.exchangeName,
23628
23685
  frameName: data.frameName,
23629
- signalId: "",
23686
+ signalId: data.pendingSignal?.id || "",
23630
23687
  walkerName: "",
23631
23688
  });
23632
23689
  };
@@ -23791,8 +23848,16 @@ class StrategyReportService {
23791
23848
  * @param isBacktest - Whether this is a backtest or live trading event
23792
23849
  * @param context - Strategy context with strategyName, exchangeName, frameName
23793
23850
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
23794
- */
23795
- this.partialProfit = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp) => {
23851
+ * @param position - Trade direction: "long" or "short"
23852
+ * @param priceOpen - Entry price for the position
23853
+ * @param priceTakeProfit - Effective take profit price
23854
+ * @param priceStopLoss - Effective stop loss price
23855
+ * @param originalPriceTakeProfit - Original take profit before trailing
23856
+ * @param originalPriceStopLoss - Original stop loss before trailing
23857
+ * @param scheduledAt - Signal creation timestamp in milliseconds
23858
+ * @param pendingAt - Pending timestamp in milliseconds
23859
+ */
23860
+ this.partialProfit = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
23796
23861
  this.loggerService.log("strategyReportService partialProfit", {
23797
23862
  symbol,
23798
23863
  percentToClose,
@@ -23818,6 +23883,14 @@ class StrategyReportService {
23818
23883
  symbol,
23819
23884
  timestamp,
23820
23885
  createdAt,
23886
+ position,
23887
+ priceOpen,
23888
+ priceTakeProfit,
23889
+ priceStopLoss,
23890
+ originalPriceTakeProfit,
23891
+ originalPriceStopLoss,
23892
+ scheduledAt,
23893
+ pendingAt,
23821
23894
  }, {
23822
23895
  signalId: pendingRow.id,
23823
23896
  exchangeName: context.exchangeName,
@@ -23836,8 +23909,16 @@ class StrategyReportService {
23836
23909
  * @param isBacktest - Whether this is a backtest or live trading event
23837
23910
  * @param context - Strategy context with strategyName, exchangeName, frameName
23838
23911
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
23839
- */
23840
- this.partialLoss = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp) => {
23912
+ * @param position - Trade direction: "long" or "short"
23913
+ * @param priceOpen - Entry price for the position
23914
+ * @param priceTakeProfit - Effective take profit price
23915
+ * @param priceStopLoss - Effective stop loss price
23916
+ * @param originalPriceTakeProfit - Original take profit before trailing
23917
+ * @param originalPriceStopLoss - Original stop loss before trailing
23918
+ * @param scheduledAt - Signal creation timestamp in milliseconds
23919
+ * @param pendingAt - Pending timestamp in milliseconds
23920
+ */
23921
+ this.partialLoss = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
23841
23922
  this.loggerService.log("strategyReportService partialLoss", {
23842
23923
  symbol,
23843
23924
  percentToClose,
@@ -23863,6 +23944,14 @@ class StrategyReportService {
23863
23944
  symbol,
23864
23945
  timestamp,
23865
23946
  createdAt,
23947
+ position,
23948
+ priceOpen,
23949
+ priceTakeProfit,
23950
+ priceStopLoss,
23951
+ originalPriceTakeProfit,
23952
+ originalPriceStopLoss,
23953
+ scheduledAt,
23954
+ pendingAt,
23866
23955
  }, {
23867
23956
  signalId: pendingRow.id,
23868
23957
  exchangeName: context.exchangeName,
@@ -23881,8 +23970,16 @@ class StrategyReportService {
23881
23970
  * @param isBacktest - Whether this is a backtest or live trading event
23882
23971
  * @param context - Strategy context with strategyName, exchangeName, frameName
23883
23972
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
23884
- */
23885
- this.trailingStop = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp) => {
23973
+ * @param position - Trade direction: "long" or "short"
23974
+ * @param priceOpen - Entry price for the position
23975
+ * @param priceTakeProfit - Effective take profit price
23976
+ * @param priceStopLoss - Effective stop loss price
23977
+ * @param originalPriceTakeProfit - Original take profit before trailing
23978
+ * @param originalPriceStopLoss - Original stop loss before trailing
23979
+ * @param scheduledAt - Signal creation timestamp in milliseconds
23980
+ * @param pendingAt - Pending timestamp in milliseconds
23981
+ */
23982
+ this.trailingStop = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
23886
23983
  this.loggerService.log("strategyReportService trailingStop", {
23887
23984
  symbol,
23888
23985
  percentShift,
@@ -23908,6 +24005,14 @@ class StrategyReportService {
23908
24005
  symbol,
23909
24006
  timestamp,
23910
24007
  createdAt,
24008
+ position,
24009
+ priceOpen,
24010
+ priceTakeProfit,
24011
+ priceStopLoss,
24012
+ originalPriceTakeProfit,
24013
+ originalPriceStopLoss,
24014
+ scheduledAt,
24015
+ pendingAt,
23911
24016
  }, {
23912
24017
  signalId: pendingRow.id,
23913
24018
  exchangeName: context.exchangeName,
@@ -23926,8 +24031,16 @@ class StrategyReportService {
23926
24031
  * @param isBacktest - Whether this is a backtest or live trading event
23927
24032
  * @param context - Strategy context with strategyName, exchangeName, frameName
23928
24033
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
23929
- */
23930
- this.trailingTake = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp) => {
24034
+ * @param position - Trade direction: "long" or "short"
24035
+ * @param priceOpen - Entry price for the position
24036
+ * @param priceTakeProfit - Effective take profit price
24037
+ * @param priceStopLoss - Effective stop loss price
24038
+ * @param originalPriceTakeProfit - Original take profit before trailing
24039
+ * @param originalPriceStopLoss - Original stop loss before trailing
24040
+ * @param scheduledAt - Signal creation timestamp in milliseconds
24041
+ * @param pendingAt - Pending timestamp in milliseconds
24042
+ */
24043
+ this.trailingTake = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
23931
24044
  this.loggerService.log("strategyReportService trailingTake", {
23932
24045
  symbol,
23933
24046
  percentShift,
@@ -23953,6 +24066,14 @@ class StrategyReportService {
23953
24066
  symbol,
23954
24067
  timestamp,
23955
24068
  createdAt,
24069
+ position,
24070
+ priceOpen,
24071
+ priceTakeProfit,
24072
+ priceStopLoss,
24073
+ originalPriceTakeProfit,
24074
+ originalPriceStopLoss,
24075
+ scheduledAt,
24076
+ pendingAt,
23956
24077
  }, {
23957
24078
  signalId: pendingRow.id,
23958
24079
  exchangeName: context.exchangeName,
@@ -23970,8 +24091,16 @@ class StrategyReportService {
23970
24091
  * @param isBacktest - Whether this is a backtest or live trading event
23971
24092
  * @param context - Strategy context with strategyName, exchangeName, frameName
23972
24093
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
23973
- */
23974
- this.breakeven = async (symbol, currentPrice, isBacktest, context, timestamp) => {
24094
+ * @param position - Trade direction: "long" or "short"
24095
+ * @param priceOpen - Entry price for the position
24096
+ * @param priceTakeProfit - Effective take profit price
24097
+ * @param priceStopLoss - Effective stop loss price
24098
+ * @param originalPriceTakeProfit - Original take profit before trailing
24099
+ * @param originalPriceStopLoss - Original stop loss before trailing
24100
+ * @param scheduledAt - Signal creation timestamp in milliseconds
24101
+ * @param pendingAt - Pending timestamp in milliseconds
24102
+ */
24103
+ this.breakeven = async (symbol, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
23975
24104
  this.loggerService.log("strategyReportService breakeven", {
23976
24105
  symbol,
23977
24106
  currentPrice,
@@ -23995,6 +24124,14 @@ class StrategyReportService {
23995
24124
  symbol,
23996
24125
  timestamp,
23997
24126
  createdAt,
24127
+ position,
24128
+ priceOpen,
24129
+ priceTakeProfit,
24130
+ priceStopLoss,
24131
+ originalPriceTakeProfit,
24132
+ originalPriceStopLoss,
24133
+ scheduledAt,
24134
+ pendingAt,
23998
24135
  }, {
23999
24136
  signalId: pendingRow.id,
24000
24137
  exchangeName: context.exchangeName,
@@ -24034,35 +24171,35 @@ class StrategyReportService {
24034
24171
  exchangeName: event.exchangeName,
24035
24172
  frameName: event.frameName,
24036
24173
  strategyName: event.strategyName,
24037
- }, event.timestamp));
24174
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24038
24175
  const unPartialLoss = strategyCommitSubject
24039
24176
  .filter(({ action }) => action === "partial-loss")
24040
24177
  .connect(async (event) => await this.partialLoss(event.symbol, event.percentToClose, event.currentPrice, event.backtest, {
24041
24178
  exchangeName: event.exchangeName,
24042
24179
  frameName: event.frameName,
24043
24180
  strategyName: event.strategyName,
24044
- }, event.timestamp));
24181
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24045
24182
  const unTrailingStop = strategyCommitSubject
24046
24183
  .filter(({ action }) => action === "trailing-stop")
24047
24184
  .connect(async (event) => await this.trailingStop(event.symbol, event.percentShift, event.currentPrice, event.backtest, {
24048
24185
  exchangeName: event.exchangeName,
24049
24186
  frameName: event.frameName,
24050
24187
  strategyName: event.strategyName,
24051
- }, event.timestamp));
24188
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24052
24189
  const unTrailingTake = strategyCommitSubject
24053
24190
  .filter(({ action }) => action === "trailing-take")
24054
24191
  .connect(async (event) => await this.trailingTake(event.symbol, event.percentShift, event.currentPrice, event.backtest, {
24055
24192
  exchangeName: event.exchangeName,
24056
24193
  frameName: event.frameName,
24057
24194
  strategyName: event.strategyName,
24058
- }, event.timestamp));
24195
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24059
24196
  const unBreakeven = strategyCommitSubject
24060
24197
  .filter(({ action }) => action === "breakeven")
24061
24198
  .connect(async (event) => await this.breakeven(event.symbol, event.currentPrice, event.backtest, {
24062
24199
  exchangeName: event.exchangeName,
24063
24200
  frameName: event.frameName,
24064
24201
  strategyName: event.strategyName,
24065
- }, event.timestamp));
24202
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24066
24203
  const disposeFn = functoolsKit.compose(() => unCancelSchedule(), () => unClosePending(), () => unPartialProfit(), () => unPartialLoss(), () => unTrailingStop(), () => unTrailingTake(), () => unBreakeven());
24067
24204
  return () => {
24068
24205
  disposeFn();
@@ -24432,8 +24569,16 @@ class StrategyMarkdownService {
24432
24569
  * @param isBacktest - Whether this is a backtest or live trading event
24433
24570
  * @param context - Strategy context with strategyName, exchangeName, frameName
24434
24571
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
24435
- */
24436
- this.partialProfit = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp) => {
24572
+ * @param position - Trade direction: "long" or "short"
24573
+ * @param priceOpen - Entry price for the position
24574
+ * @param priceTakeProfit - Effective take profit price
24575
+ * @param priceStopLoss - Effective stop loss price
24576
+ * @param originalPriceTakeProfit - Original take profit before trailing
24577
+ * @param originalPriceStopLoss - Original stop loss before trailing
24578
+ * @param scheduledAt - Signal creation timestamp in milliseconds
24579
+ * @param pendingAt - Pending timestamp in milliseconds
24580
+ */
24581
+ this.partialProfit = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
24437
24582
  this.loggerService.log("strategyMarkdownService partialProfit", {
24438
24583
  symbol,
24439
24584
  percentToClose,
@@ -24465,6 +24610,14 @@ class StrategyMarkdownService {
24465
24610
  currentPrice,
24466
24611
  createdAt,
24467
24612
  backtest: isBacktest,
24613
+ position,
24614
+ priceOpen,
24615
+ priceTakeProfit,
24616
+ priceStopLoss,
24617
+ originalPriceTakeProfit,
24618
+ originalPriceStopLoss,
24619
+ scheduledAt,
24620
+ pendingAt,
24468
24621
  });
24469
24622
  };
24470
24623
  /**
@@ -24476,8 +24629,16 @@ class StrategyMarkdownService {
24476
24629
  * @param isBacktest - Whether this is a backtest or live trading event
24477
24630
  * @param context - Strategy context with strategyName, exchangeName, frameName
24478
24631
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
24479
- */
24480
- this.partialLoss = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp) => {
24632
+ * @param position - Trade direction: "long" or "short"
24633
+ * @param priceOpen - Entry price for the position
24634
+ * @param priceTakeProfit - Effective take profit price
24635
+ * @param priceStopLoss - Effective stop loss price
24636
+ * @param originalPriceTakeProfit - Original take profit before trailing
24637
+ * @param originalPriceStopLoss - Original stop loss before trailing
24638
+ * @param scheduledAt - Signal creation timestamp in milliseconds
24639
+ * @param pendingAt - Pending timestamp in milliseconds
24640
+ */
24641
+ this.partialLoss = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
24481
24642
  this.loggerService.log("strategyMarkdownService partialLoss", {
24482
24643
  symbol,
24483
24644
  percentToClose,
@@ -24509,6 +24670,14 @@ class StrategyMarkdownService {
24509
24670
  currentPrice,
24510
24671
  createdAt,
24511
24672
  backtest: isBacktest,
24673
+ position,
24674
+ priceOpen,
24675
+ priceTakeProfit,
24676
+ priceStopLoss,
24677
+ originalPriceTakeProfit,
24678
+ originalPriceStopLoss,
24679
+ scheduledAt,
24680
+ pendingAt,
24512
24681
  });
24513
24682
  };
24514
24683
  /**
@@ -24520,8 +24689,16 @@ class StrategyMarkdownService {
24520
24689
  * @param isBacktest - Whether this is a backtest or live trading event
24521
24690
  * @param context - Strategy context with strategyName, exchangeName, frameName
24522
24691
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
24523
- */
24524
- this.trailingStop = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp) => {
24692
+ * @param position - Trade direction: "long" or "short"
24693
+ * @param priceOpen - Entry price for the position
24694
+ * @param priceTakeProfit - Effective take profit price
24695
+ * @param priceStopLoss - Effective stop loss price
24696
+ * @param originalPriceTakeProfit - Original take profit before trailing
24697
+ * @param originalPriceStopLoss - Original stop loss before trailing
24698
+ * @param scheduledAt - Signal creation timestamp in milliseconds
24699
+ * @param pendingAt - Pending timestamp in milliseconds
24700
+ */
24701
+ this.trailingStop = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
24525
24702
  this.loggerService.log("strategyMarkdownService trailingStop", {
24526
24703
  symbol,
24527
24704
  percentShift,
@@ -24553,6 +24730,14 @@ class StrategyMarkdownService {
24553
24730
  currentPrice,
24554
24731
  createdAt,
24555
24732
  backtest: isBacktest,
24733
+ position,
24734
+ priceOpen,
24735
+ priceTakeProfit,
24736
+ priceStopLoss,
24737
+ originalPriceTakeProfit,
24738
+ originalPriceStopLoss,
24739
+ scheduledAt,
24740
+ pendingAt,
24556
24741
  });
24557
24742
  };
24558
24743
  /**
@@ -24564,8 +24749,16 @@ class StrategyMarkdownService {
24564
24749
  * @param isBacktest - Whether this is a backtest or live trading event
24565
24750
  * @param context - Strategy context with strategyName, exchangeName, frameName
24566
24751
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
24567
- */
24568
- this.trailingTake = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp) => {
24752
+ * @param position - Trade direction: "long" or "short"
24753
+ * @param priceOpen - Entry price for the position
24754
+ * @param priceTakeProfit - Effective take profit price
24755
+ * @param priceStopLoss - Effective stop loss price
24756
+ * @param originalPriceTakeProfit - Original take profit before trailing
24757
+ * @param originalPriceStopLoss - Original stop loss before trailing
24758
+ * @param scheduledAt - Signal creation timestamp in milliseconds
24759
+ * @param pendingAt - Pending timestamp in milliseconds
24760
+ */
24761
+ this.trailingTake = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
24569
24762
  this.loggerService.log("strategyMarkdownService trailingTake", {
24570
24763
  symbol,
24571
24764
  percentShift,
@@ -24597,6 +24790,14 @@ class StrategyMarkdownService {
24597
24790
  currentPrice,
24598
24791
  createdAt,
24599
24792
  backtest: isBacktest,
24793
+ position,
24794
+ priceOpen,
24795
+ priceTakeProfit,
24796
+ priceStopLoss,
24797
+ originalPriceTakeProfit,
24798
+ originalPriceStopLoss,
24799
+ scheduledAt,
24800
+ pendingAt,
24600
24801
  });
24601
24802
  };
24602
24803
  /**
@@ -24607,8 +24808,16 @@ class StrategyMarkdownService {
24607
24808
  * @param isBacktest - Whether this is a backtest or live trading event
24608
24809
  * @param context - Strategy context with strategyName, exchangeName, frameName
24609
24810
  * @param timestamp - Timestamp from StrategyCommitContract (execution context time)
24610
- */
24611
- this.breakeven = async (symbol, currentPrice, isBacktest, context, timestamp) => {
24811
+ * @param position - Trade direction: "long" or "short"
24812
+ * @param priceOpen - Entry price for the position
24813
+ * @param priceTakeProfit - Effective take profit price
24814
+ * @param priceStopLoss - Effective stop loss price
24815
+ * @param originalPriceTakeProfit - Original take profit before trailing
24816
+ * @param originalPriceStopLoss - Original stop loss before trailing
24817
+ * @param scheduledAt - Signal creation timestamp in milliseconds
24818
+ * @param pendingAt - Pending timestamp in milliseconds
24819
+ */
24820
+ this.breakeven = async (symbol, currentPrice, isBacktest, context, timestamp, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt) => {
24612
24821
  this.loggerService.log("strategyMarkdownService breakeven", {
24613
24822
  symbol,
24614
24823
  currentPrice,
@@ -24638,6 +24847,14 @@ class StrategyMarkdownService {
24638
24847
  currentPrice,
24639
24848
  createdAt,
24640
24849
  backtest: isBacktest,
24850
+ position,
24851
+ priceOpen,
24852
+ priceTakeProfit,
24853
+ priceStopLoss,
24854
+ originalPriceTakeProfit,
24855
+ originalPriceStopLoss,
24856
+ scheduledAt,
24857
+ pendingAt,
24641
24858
  });
24642
24859
  };
24643
24860
  /**
@@ -24784,35 +25001,35 @@ class StrategyMarkdownService {
24784
25001
  exchangeName: event.exchangeName,
24785
25002
  frameName: event.frameName,
24786
25003
  strategyName: event.strategyName,
24787
- }, event.timestamp));
25004
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24788
25005
  const unPartialLoss = strategyCommitSubject
24789
25006
  .filter(({ action }) => action === "partial-loss")
24790
25007
  .connect(async (event) => await this.partialLoss(event.symbol, event.percentToClose, event.currentPrice, event.backtest, {
24791
25008
  exchangeName: event.exchangeName,
24792
25009
  frameName: event.frameName,
24793
25010
  strategyName: event.strategyName,
24794
- }, event.timestamp));
25011
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24795
25012
  const unTrailingStop = strategyCommitSubject
24796
25013
  .filter(({ action }) => action === "trailing-stop")
24797
25014
  .connect(async (event) => await this.trailingStop(event.symbol, event.percentShift, event.currentPrice, event.backtest, {
24798
25015
  exchangeName: event.exchangeName,
24799
25016
  frameName: event.frameName,
24800
25017
  strategyName: event.strategyName,
24801
- }, event.timestamp));
25018
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24802
25019
  const unTrailingTake = strategyCommitSubject
24803
25020
  .filter(({ action }) => action === "trailing-take")
24804
25021
  .connect(async (event) => await this.trailingTake(event.symbol, event.percentShift, event.currentPrice, event.backtest, {
24805
25022
  exchangeName: event.exchangeName,
24806
25023
  frameName: event.frameName,
24807
25024
  strategyName: event.strategyName,
24808
- }, event.timestamp));
25025
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24809
25026
  const unBreakeven = strategyCommitSubject
24810
25027
  .filter(({ action }) => action === "breakeven")
24811
25028
  .connect(async (event) => await this.breakeven(event.symbol, event.currentPrice, event.backtest, {
24812
25029
  exchangeName: event.exchangeName,
24813
25030
  frameName: event.frameName,
24814
25031
  strategyName: event.strategyName,
24815
- }, event.timestamp));
25032
+ }, event.timestamp, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt));
24816
25033
  const disposeFn = functoolsKit.compose(() => unCancelSchedule(), () => unClosePending(), () => unPartialProfit(), () => unPartialLoss(), () => unTrailingStop(), () => unTrailingTake(), () => unBreakeven());
24817
25034
  return () => {
24818
25035
  disposeFn();
@@ -31617,53 +31834,64 @@ class ConstantUtils {
31617
31834
  const Constant = new ConstantUtils();
31618
31835
 
31619
31836
  const MAX_SIGNALS = 25;
31620
- const STORAGE_BACKTEST_METHOD_NAME_WAIT_FOR_INIT = "StorageBacktestUtils.waitForInit";
31621
- const STORAGE_BACKTEST_METHOD_NAME_UPDATE_STORAGE = "StorageBacktestUtils._updateStorage";
31622
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_OPENED = "StorageBacktestUtils.handleOpened";
31623
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CLOSED = "StorageBacktestUtils.handleClosed";
31624
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED = "StorageBacktestUtils.handleScheduled";
31625
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CANCELLED = "StorageBacktestUtils.handleCancelled";
31626
- const STORAGE_BACKTEST_METHOD_NAME_FIND_BY_ID = "StorageBacktestUtils.findById";
31627
- const STORAGE_BACKTEST_METHOD_NAME_LIST = "StorageBacktestUtils.list";
31628
- const STORAGE_LIVE_METHOD_NAME_WAIT_FOR_INIT = "StorageLiveUtils.waitForInit";
31629
- const STORAGE_LIVE_METHOD_NAME_UPDATE_STORAGE = "StorageLiveUtils._updateStorage";
31630
- const STORAGE_LIVE_METHOD_NAME_HANDLE_OPENED = "StorageLiveUtils.handleOpened";
31631
- const STORAGE_LIVE_METHOD_NAME_HANDLE_CLOSED = "StorageLiveUtils.handleClosed";
31632
- const STORAGE_LIVE_METHOD_NAME_HANDLE_SCHEDULED = "StorageLiveUtils.handleScheduled";
31633
- const STORAGE_LIVE_METHOD_NAME_HANDLE_CANCELLED = "StorageLiveUtils.handleCancelled";
31634
- const STORAGE_LIVE_METHOD_NAME_FIND_BY_ID = "StorageLiveUtils.findById";
31635
- const STORAGE_LIVE_METHOD_NAME_LIST = "StorageLiveUtils.list";
31837
+ const STORAGE_BACKTEST_METHOD_NAME_WAIT_FOR_INIT = "StoragePersistBacktestUtils.waitForInit";
31838
+ const STORAGE_BACKTEST_METHOD_NAME_UPDATE_STORAGE = "StoragePersistBacktestUtils._updateStorage";
31839
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_OPENED = "StoragePersistBacktestUtils.handleOpened";
31840
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CLOSED = "StoragePersistBacktestUtils.handleClosed";
31841
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED = "StoragePersistBacktestUtils.handleScheduled";
31842
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CANCELLED = "StoragePersistBacktestUtils.handleCancelled";
31843
+ const STORAGE_BACKTEST_METHOD_NAME_FIND_BY_ID = "StoragePersistBacktestUtils.findById";
31844
+ const STORAGE_BACKTEST_METHOD_NAME_LIST = "StoragePersistBacktestUtils.list";
31845
+ const STORAGE_LIVE_METHOD_NAME_WAIT_FOR_INIT = "StoragePersistLiveUtils.waitForInit";
31846
+ const STORAGE_LIVE_METHOD_NAME_UPDATE_STORAGE = "StoragePersistLiveUtils._updateStorage";
31847
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_OPENED = "StoragePersistLiveUtils.handleOpened";
31848
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_CLOSED = "StoragePersistLiveUtils.handleClosed";
31849
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_SCHEDULED = "StoragePersistLiveUtils.handleScheduled";
31850
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_CANCELLED = "StoragePersistLiveUtils.handleCancelled";
31851
+ const STORAGE_LIVE_METHOD_NAME_FIND_BY_ID = "StoragePersistLiveUtils.findById";
31852
+ const STORAGE_LIVE_METHOD_NAME_LIST = "StoragePersistLiveUtils.list";
31853
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_OPENED = "StorageMemoryBacktestUtils.handleOpened";
31854
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CLOSED = "StorageMemoryBacktestUtils.handleClosed";
31855
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED = "StorageMemoryBacktestUtils.handleScheduled";
31856
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CANCELLED = "StorageMemoryBacktestUtils.handleCancelled";
31857
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_FIND_BY_ID = "StorageMemoryBacktestUtils.findById";
31858
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_LIST = "StorageMemoryBacktestUtils.list";
31859
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_OPENED = "StorageMemoryLiveUtils.handleOpened";
31860
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CLOSED = "StorageMemoryLiveUtils.handleClosed";
31861
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_SCHEDULED = "StorageMemoryLiveUtils.handleScheduled";
31862
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CANCELLED = "StorageMemoryLiveUtils.handleCancelled";
31863
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_FIND_BY_ID = "StorageMemoryLiveUtils.findById";
31864
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_LIST = "StorageMemoryLiveUtils.list";
31636
31865
  const STORAGE_ADAPTER_METHOD_NAME_ENABLE = "StorageAdapter.enable";
31637
31866
  const STORAGE_ADAPTER_METHOD_NAME_DISABLE = "StorageAdapter.disable";
31638
31867
  const STORAGE_ADAPTER_METHOD_NAME_FIND_SIGNAL_BY_ID = "StorageAdapter.findSignalById";
31639
31868
  const STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_BACKTEST = "StorageAdapter.listSignalBacktest";
31640
31869
  const STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_LIVE = "StorageAdapter.listSignalLive";
31870
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER = "StorageBacktestAdapter.useStorageAdapter";
31871
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY = "StorageBacktestAdapter.useDummy";
31872
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST = "StorageBacktestAdapter.usePersist";
31873
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY = "StorageBacktestAdapter.useMemory";
31874
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER = "StorageLiveAdapter.useStorageAdapter";
31875
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY = "StorageLiveAdapter.useDummy";
31876
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST = "StorageLiveAdapter.usePersist";
31877
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY = "StorageLiveAdapter.useMemory";
31641
31878
  /**
31642
- * Utility class for managing backtest signal history.
31643
- *
31644
- * Stores trading signal history for admin dashboard display during backtesting
31645
- * with automatic initialization, deduplication, and storage limits.
31646
- *
31647
- * @example
31648
- * ```typescript
31649
- * import { StorageBacktestUtils } from "./classes/Storage";
31879
+ * Persistent storage adapter for backtest signals.
31650
31880
  *
31651
- * const storage = new StorageBacktestUtils();
31652
- *
31653
- * // Handle signal events
31654
- * await storage.handleOpened(tickResult);
31655
- * await storage.handleClosed(tickResult);
31881
+ * Features:
31882
+ * - Persists signals to disk using PersistStorageAdapter
31883
+ * - Lazy initialization with singleshot pattern
31884
+ * - Maintains up to MAX_SIGNALS (25) most recent signals
31885
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
31886
+ * - Prevents duplicate updates based on timestamp comparison
31656
31887
  *
31657
- * // Query signals
31658
- * const signal = await storage.findById("signal-123");
31659
- * const allSignals = await storage.list();
31660
- * ```
31888
+ * Use this adapter (default) for backtest signal persistence across sessions.
31661
31889
  */
31662
- class StorageBacktestUtils {
31890
+ class StoragePersistBacktestUtils {
31663
31891
  constructor() {
31664
31892
  /**
31665
- * Initializes storage by loading existing signal history from persist layer.
31666
- * Uses singleshot to ensure initialization happens only once.
31893
+ * Singleshot initialization function that loads signals from disk.
31894
+ * Protected by singleshot to ensure one-time execution.
31667
31895
  */
31668
31896
  this.waitForInit = functoolsKit.singleshot(async () => {
31669
31897
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_WAIT_FOR_INIT);
@@ -31675,9 +31903,8 @@ class StorageBacktestUtils {
31675
31903
  });
31676
31904
  /**
31677
31905
  * Handles signal opened event.
31678
- *
31679
- * @param tick - Tick result containing opened signal data
31680
- * @returns Promise resolving when storage is updated
31906
+ * Updates storage with opened status if not stale.
31907
+ * @param tick - The opened signal tick data
31681
31908
  */
31682
31909
  this.handleOpened = async (tick) => {
31683
31910
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_OPENED, {
@@ -31699,9 +31926,8 @@ class StorageBacktestUtils {
31699
31926
  };
31700
31927
  /**
31701
31928
  * Handles signal closed event.
31702
- *
31703
- * @param tick - Tick result containing closed signal data
31704
- * @returns Promise resolving when storage is updated
31929
+ * Updates storage with closed status and PnL if not stale.
31930
+ * @param tick - The closed signal tick data
31705
31931
  */
31706
31932
  this.handleClosed = async (tick) => {
31707
31933
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_CLOSED, {
@@ -31724,9 +31950,8 @@ class StorageBacktestUtils {
31724
31950
  };
31725
31951
  /**
31726
31952
  * Handles signal scheduled event.
31727
- *
31728
- * @param tick - Tick result containing scheduled signal data
31729
- * @returns Promise resolving when storage is updated
31953
+ * Updates storage with scheduled status if not stale.
31954
+ * @param tick - The scheduled signal tick data
31730
31955
  */
31731
31956
  this.handleScheduled = async (tick) => {
31732
31957
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED, {
@@ -31748,9 +31973,8 @@ class StorageBacktestUtils {
31748
31973
  };
31749
31974
  /**
31750
31975
  * Handles signal cancelled event.
31751
- *
31752
- * @param tick - Tick result containing cancelled signal data
31753
- * @returns Promise resolving when storage is updated
31976
+ * Updates storage with cancelled status if not stale.
31977
+ * @param tick - The cancelled signal tick data
31754
31978
  */
31755
31979
  this.handleCancelled = async (tick) => {
31756
31980
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_CANCELLED, {
@@ -31771,10 +31995,9 @@ class StorageBacktestUtils {
31771
31995
  await this._updateStorage();
31772
31996
  };
31773
31997
  /**
31774
- * Finds a signal by its unique identifier.
31775
- *
31776
- * @param id - Signal identifier
31777
- * @returns Promise resolving to signal row or null if not found
31998
+ * Finds a signal by its ID.
31999
+ * @param id - The signal ID to search for
32000
+ * @returns The signal row or null if not found
31778
32001
  */
31779
32002
  this.findById = async (id) => {
31780
32003
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_FIND_BY_ID, { id });
@@ -31782,9 +32005,8 @@ class StorageBacktestUtils {
31782
32005
  return this._signals.get(id) ?? null;
31783
32006
  };
31784
32007
  /**
31785
- * Lists all stored backtest signals.
31786
- *
31787
- * @returns Promise resolving to array of signal rows
32008
+ * Lists all stored signals.
32009
+ * @returns Array of all signal rows
31788
32010
  */
31789
32011
  this.list = async () => {
31790
32012
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_LIST);
@@ -31793,15 +32015,14 @@ class StorageBacktestUtils {
31793
32015
  };
31794
32016
  }
31795
32017
  /**
31796
- * Persists current signal history to storage.
31797
- * Sorts by priority and limits to MAX_SIGNALS entries.
31798
- *
31799
- * @throws Error if storage not initialized
32018
+ * Persists the current signal map to disk storage.
32019
+ * Sorts signals by priority and keeps only the most recent MAX_SIGNALS.
32020
+ * @throws Error if not initialized
31800
32021
  */
31801
32022
  async _updateStorage() {
31802
32023
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_UPDATE_STORAGE);
31803
32024
  if (!this._signals) {
31804
- throw new Error("StorageBacktestUtils not initialized. Call waitForInit first.");
32025
+ throw new Error("StoragePersistBacktestUtils not initialized. Call waitForInit first.");
31805
32026
  }
31806
32027
  const signalList = Array.from(this._signals.values());
31807
32028
  signalList.sort((a, b) => a.priority - b.priority);
@@ -31809,31 +32030,190 @@ class StorageBacktestUtils {
31809
32030
  }
31810
32031
  }
31811
32032
  /**
31812
- * Utility class for managing live trading signal history.
32033
+ * In-memory storage adapter for backtest signals.
31813
32034
  *
31814
- * Stores trading signal history for admin dashboard display during live trading
31815
- * with automatic initialization, deduplication, and storage limits.
32035
+ * Features:
32036
+ * - Stores signals in memory only (no persistence)
32037
+ * - Fast read/write operations
32038
+ * - Data is lost when application restarts
32039
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
32040
+ * - Prevents duplicate updates based on timestamp comparison
31816
32041
  *
31817
- * @example
31818
- * ```typescript
31819
- * import { StorageLiveUtils } from "./classes/Storage";
32042
+ * Use this adapter for testing or when persistence is not required.
32043
+ */
32044
+ class StorageMemoryBacktestUtils {
32045
+ constructor() {
32046
+ /** Map of signal IDs to signal rows */
32047
+ this._signals = new Map();
32048
+ /**
32049
+ * Handles signal opened event.
32050
+ * Updates in-memory storage with opened status if not stale.
32051
+ * @param tick - The opened signal tick data
32052
+ */
32053
+ this.handleOpened = async (tick) => {
32054
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_OPENED, {
32055
+ signalId: tick.signal.id,
32056
+ });
32057
+ const lastStorage = this._signals.get(tick.signal.id);
32058
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32059
+ return;
32060
+ }
32061
+ this._signals.set(tick.signal.id, {
32062
+ ...tick.signal,
32063
+ status: "opened",
32064
+ priority: Date.now(),
32065
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32066
+ updatedAt: tick.createdAt,
32067
+ });
32068
+ };
32069
+ /**
32070
+ * Handles signal closed event.
32071
+ * Updates in-memory storage with closed status and PnL if not stale.
32072
+ * @param tick - The closed signal tick data
32073
+ */
32074
+ this.handleClosed = async (tick) => {
32075
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CLOSED, {
32076
+ signalId: tick.signal.id,
32077
+ });
32078
+ const lastStorage = this._signals.get(tick.signal.id);
32079
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32080
+ return;
32081
+ }
32082
+ this._signals.set(tick.signal.id, {
32083
+ ...tick.signal,
32084
+ status: "closed",
32085
+ priority: Date.now(),
32086
+ pnl: tick.pnl,
32087
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32088
+ updatedAt: tick.createdAt,
32089
+ });
32090
+ };
32091
+ /**
32092
+ * Handles signal scheduled event.
32093
+ * Updates in-memory storage with scheduled status if not stale.
32094
+ * @param tick - The scheduled signal tick data
32095
+ */
32096
+ this.handleScheduled = async (tick) => {
32097
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED, {
32098
+ signalId: tick.signal.id,
32099
+ });
32100
+ const lastStorage = this._signals.get(tick.signal.id);
32101
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32102
+ return;
32103
+ }
32104
+ this._signals.set(tick.signal.id, {
32105
+ ...tick.signal,
32106
+ status: "scheduled",
32107
+ priority: Date.now(),
32108
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32109
+ updatedAt: tick.createdAt,
32110
+ });
32111
+ };
32112
+ /**
32113
+ * Handles signal cancelled event.
32114
+ * Updates in-memory storage with cancelled status if not stale.
32115
+ * @param tick - The cancelled signal tick data
32116
+ */
32117
+ this.handleCancelled = async (tick) => {
32118
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CANCELLED, {
32119
+ signalId: tick.signal.id,
32120
+ });
32121
+ const lastStorage = this._signals.get(tick.signal.id);
32122
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32123
+ return;
32124
+ }
32125
+ this._signals.set(tick.signal.id, {
32126
+ ...tick.signal,
32127
+ status: "cancelled",
32128
+ priority: Date.now(),
32129
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32130
+ updatedAt: tick.createdAt,
32131
+ });
32132
+ };
32133
+ /**
32134
+ * Finds a signal by its ID.
32135
+ * @param id - The signal ID to search for
32136
+ * @returns The signal row or null if not found
32137
+ */
32138
+ this.findById = async (id) => {
32139
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_FIND_BY_ID, { id });
32140
+ return this._signals.get(id) ?? null;
32141
+ };
32142
+ /**
32143
+ * Lists all stored signals.
32144
+ * @returns Array of all signal rows
32145
+ */
32146
+ this.list = async () => {
32147
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_LIST);
32148
+ return Array.from(this._signals.values());
32149
+ };
32150
+ }
32151
+ }
32152
+ /**
32153
+ * Dummy storage adapter for backtest signals that discards all writes.
32154
+ *
32155
+ * Features:
32156
+ * - No-op implementation for all methods
32157
+ * - findById always returns null
32158
+ * - list always returns empty array
31820
32159
  *
31821
- * const storage = new StorageLiveUtils();
32160
+ * Use this adapter to disable backtest signal storage completely.
32161
+ */
32162
+ class StorageDummyBacktestUtils {
32163
+ constructor() {
32164
+ /**
32165
+ * No-op handler for signal opened event.
32166
+ */
32167
+ this.handleOpened = async () => {
32168
+ };
32169
+ /**
32170
+ * No-op handler for signal closed event.
32171
+ */
32172
+ this.handleClosed = async () => {
32173
+ };
32174
+ /**
32175
+ * No-op handler for signal scheduled event.
32176
+ */
32177
+ this.handleScheduled = async () => {
32178
+ };
32179
+ /**
32180
+ * No-op handler for signal cancelled event.
32181
+ */
32182
+ this.handleCancelled = async () => {
32183
+ };
32184
+ /**
32185
+ * Always returns null (no storage).
32186
+ * @returns null
32187
+ */
32188
+ this.findById = async () => {
32189
+ return null;
32190
+ };
32191
+ /**
32192
+ * Always returns empty array (no storage).
32193
+ * @returns Empty array
32194
+ */
32195
+ this.list = async () => {
32196
+ return [];
32197
+ };
32198
+ }
32199
+ }
32200
+ /**
32201
+ * Persistent storage adapter for live trading signals.
31822
32202
  *
31823
- * // Handle signal events
31824
- * await storage.handleOpened(tickResult);
31825
- * await storage.handleClosed(tickResult);
32203
+ * Features:
32204
+ * - Persists signals to disk using PersistStorageAdapter
32205
+ * - Lazy initialization with singleshot pattern
32206
+ * - Maintains up to MAX_SIGNALS (25) most recent signals
32207
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
32208
+ * - Prevents duplicate updates based on timestamp comparison
31826
32209
  *
31827
- * // Query signals
31828
- * const signal = await storage.findById("signal-123");
31829
- * const allSignals = await storage.list();
31830
- * ```
32210
+ * Use this adapter (default) for live signal persistence across sessions.
31831
32211
  */
31832
- class StorageLiveUtils {
32212
+ class StoragePersistLiveUtils {
31833
32213
  constructor() {
31834
32214
  /**
31835
- * Initializes storage by loading existing signal history from persist layer.
31836
- * Uses singleshot to ensure initialization happens only once.
32215
+ * Singleshot initialization function that loads signals from disk.
32216
+ * Protected by singleshot to ensure one-time execution.
31837
32217
  */
31838
32218
  this.waitForInit = functoolsKit.singleshot(async () => {
31839
32219
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_WAIT_FOR_INIT);
@@ -31845,9 +32225,8 @@ class StorageLiveUtils {
31845
32225
  });
31846
32226
  /**
31847
32227
  * Handles signal opened event.
31848
- *
31849
- * @param tick - Tick result containing opened signal data
31850
- * @returns Promise resolving when history is updated
32228
+ * Updates storage with opened status if not stale.
32229
+ * @param tick - The opened signal tick data
31851
32230
  */
31852
32231
  this.handleOpened = async (tick) => {
31853
32232
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_OPENED, {
@@ -31869,9 +32248,8 @@ class StorageLiveUtils {
31869
32248
  };
31870
32249
  /**
31871
32250
  * Handles signal closed event.
31872
- *
31873
- * @param tick - Tick result containing closed signal data
31874
- * @returns Promise resolving when history is updated
32251
+ * Updates storage with closed status and PnL if not stale.
32252
+ * @param tick - The closed signal tick data
31875
32253
  */
31876
32254
  this.handleClosed = async (tick) => {
31877
32255
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_CLOSED, {
@@ -31894,9 +32272,8 @@ class StorageLiveUtils {
31894
32272
  };
31895
32273
  /**
31896
32274
  * Handles signal scheduled event.
31897
- *
31898
- * @param tick - Tick result containing scheduled signal data
31899
- * @returns Promise resolving when history is updated
32275
+ * Updates storage with scheduled status if not stale.
32276
+ * @param tick - The scheduled signal tick data
31900
32277
  */
31901
32278
  this.handleScheduled = async (tick) => {
31902
32279
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_SCHEDULED, {
@@ -31918,9 +32295,8 @@ class StorageLiveUtils {
31918
32295
  };
31919
32296
  /**
31920
32297
  * Handles signal cancelled event.
31921
- *
31922
- * @param tick - Tick result containing cancelled signal data
31923
- * @returns Promise resolving when history is updated
32298
+ * Updates storage with cancelled status if not stale.
32299
+ * @param tick - The cancelled signal tick data
31924
32300
  */
31925
32301
  this.handleCancelled = async (tick) => {
31926
32302
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_CANCELLED, {
@@ -31941,10 +32317,9 @@ class StorageLiveUtils {
31941
32317
  await this._updateStorage();
31942
32318
  };
31943
32319
  /**
31944
- * Finds a signal by its unique identifier.
31945
- *
31946
- * @param id - Signal identifier
31947
- * @returns Promise resolving to signal row or null if not found
32320
+ * Finds a signal by its ID.
32321
+ * @param id - The signal ID to search for
32322
+ * @returns The signal row or null if not found
31948
32323
  */
31949
32324
  this.findById = async (id) => {
31950
32325
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_FIND_BY_ID, { id });
@@ -31952,9 +32327,8 @@ class StorageLiveUtils {
31952
32327
  return this._signals.get(id) ?? null;
31953
32328
  };
31954
32329
  /**
31955
- * Lists all stored live signals.
31956
- *
31957
- * @returns Promise resolving to array of signal rows
32330
+ * Lists all stored signals.
32331
+ * @returns Array of all signal rows
31958
32332
  */
31959
32333
  this.list = async () => {
31960
32334
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_LIST);
@@ -31963,15 +32337,14 @@ class StorageLiveUtils {
31963
32337
  };
31964
32338
  }
31965
32339
  /**
31966
- * Persists current signal history to storage.
31967
- * Sorts by priority and limits to MAX_SIGNALS entries.
31968
- *
31969
- * @throws Error if storage not initialized
32340
+ * Persists the current signal map to disk storage.
32341
+ * Sorts signals by priority and keeps only the most recent MAX_SIGNALS.
32342
+ * @throws Error if not initialized
31970
32343
  */
31971
32344
  async _updateStorage() {
31972
32345
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_UPDATE_STORAGE);
31973
32346
  if (!this._signals) {
31974
- throw new Error("StorageLiveUtils not initialized. Call waitForInit first.");
32347
+ throw new Error("StoragePersistLiveUtils not initialized. Call waitForInit first.");
31975
32348
  }
31976
32349
  const signalList = Array.from(this._signals.values());
31977
32350
  signalList.sort((a, b) => a.priority - b.priority);
@@ -31979,36 +32352,385 @@ class StorageLiveUtils {
31979
32352
  }
31980
32353
  }
31981
32354
  /**
31982
- * Main storage adapter for signal history management.
32355
+ * In-memory storage adapter for live trading signals.
31983
32356
  *
31984
- * Provides unified interface for accessing backtest and live signal history
31985
- * for admin dashboard. Subscribes to signal emitters and automatically
31986
- * updates history on signal events.
32357
+ * Features:
32358
+ * - Stores signals in memory only (no persistence)
32359
+ * - Fast read/write operations
32360
+ * - Data is lost when application restarts
32361
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
32362
+ * - Prevents duplicate updates based on timestamp comparison
31987
32363
  *
31988
- * @example
31989
- * ```typescript
31990
- * import { Storage } from "./classes/Storage";
32364
+ * Use this adapter for testing or when persistence is not required.
32365
+ */
32366
+ class StorageMemoryLiveUtils {
32367
+ constructor() {
32368
+ /** Map of signal IDs to signal rows */
32369
+ this._signals = new Map();
32370
+ /**
32371
+ * Handles signal opened event.
32372
+ * Updates in-memory storage with opened status if not stale.
32373
+ * @param tick - The opened signal tick data
32374
+ */
32375
+ this.handleOpened = async (tick) => {
32376
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_OPENED, {
32377
+ signalId: tick.signal.id,
32378
+ });
32379
+ const lastStorage = this._signals.get(tick.signal.id);
32380
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32381
+ return;
32382
+ }
32383
+ this._signals.set(tick.signal.id, {
32384
+ ...tick.signal,
32385
+ status: "opened",
32386
+ priority: Date.now(),
32387
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32388
+ updatedAt: tick.createdAt,
32389
+ });
32390
+ };
32391
+ /**
32392
+ * Handles signal closed event.
32393
+ * Updates in-memory storage with closed status and PnL if not stale.
32394
+ * @param tick - The closed signal tick data
32395
+ */
32396
+ this.handleClosed = async (tick) => {
32397
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CLOSED, {
32398
+ signalId: tick.signal.id,
32399
+ });
32400
+ const lastStorage = this._signals.get(tick.signal.id);
32401
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32402
+ return;
32403
+ }
32404
+ this._signals.set(tick.signal.id, {
32405
+ ...tick.signal,
32406
+ status: "closed",
32407
+ priority: Date.now(),
32408
+ pnl: tick.pnl,
32409
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32410
+ updatedAt: tick.createdAt,
32411
+ });
32412
+ };
32413
+ /**
32414
+ * Handles signal scheduled event.
32415
+ * Updates in-memory storage with scheduled status if not stale.
32416
+ * @param tick - The scheduled signal tick data
32417
+ */
32418
+ this.handleScheduled = async (tick) => {
32419
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_SCHEDULED, {
32420
+ signalId: tick.signal.id,
32421
+ });
32422
+ const lastStorage = this._signals.get(tick.signal.id);
32423
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32424
+ return;
32425
+ }
32426
+ this._signals.set(tick.signal.id, {
32427
+ ...tick.signal,
32428
+ status: "scheduled",
32429
+ priority: Date.now(),
32430
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32431
+ updatedAt: tick.createdAt,
32432
+ });
32433
+ };
32434
+ /**
32435
+ * Handles signal cancelled event.
32436
+ * Updates in-memory storage with cancelled status if not stale.
32437
+ * @param tick - The cancelled signal tick data
32438
+ */
32439
+ this.handleCancelled = async (tick) => {
32440
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CANCELLED, {
32441
+ signalId: tick.signal.id,
32442
+ });
32443
+ const lastStorage = this._signals.get(tick.signal.id);
32444
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32445
+ return;
32446
+ }
32447
+ this._signals.set(tick.signal.id, {
32448
+ ...tick.signal,
32449
+ status: "cancelled",
32450
+ priority: Date.now(),
32451
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32452
+ updatedAt: tick.createdAt,
32453
+ });
32454
+ };
32455
+ /**
32456
+ * Finds a signal by its ID.
32457
+ * @param id - The signal ID to search for
32458
+ * @returns The signal row or null if not found
32459
+ */
32460
+ this.findById = async (id) => {
32461
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_FIND_BY_ID, { id });
32462
+ return this._signals.get(id) ?? null;
32463
+ };
32464
+ /**
32465
+ * Lists all stored signals.
32466
+ * @returns Array of all signal rows
32467
+ */
32468
+ this.list = async () => {
32469
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_LIST);
32470
+ return Array.from(this._signals.values());
32471
+ };
32472
+ }
32473
+ }
32474
+ /**
32475
+ * Dummy storage adapter for live trading signals that discards all writes.
31991
32476
  *
31992
- * // Enable signal history tracking
31993
- * const unsubscribe = Storage.enable();
32477
+ * Features:
32478
+ * - No-op implementation for all methods
32479
+ * - findById always returns null
32480
+ * - list always returns empty array
31994
32481
  *
31995
- * // Query signals
31996
- * const backtestSignals = await Storage.listSignalBacktest();
31997
- * const liveSignals = await Storage.listSignalLive();
31998
- * const signal = await Storage.findSignalById("signal-123");
32482
+ * Use this adapter to disable live signal storage completely.
32483
+ */
32484
+ class StorageDummyLiveUtils {
32485
+ constructor() {
32486
+ /**
32487
+ * No-op handler for signal opened event.
32488
+ */
32489
+ this.handleOpened = async () => {
32490
+ };
32491
+ /**
32492
+ * No-op handler for signal closed event.
32493
+ */
32494
+ this.handleClosed = async () => {
32495
+ };
32496
+ /**
32497
+ * No-op handler for signal scheduled event.
32498
+ */
32499
+ this.handleScheduled = async () => {
32500
+ };
32501
+ /**
32502
+ * No-op handler for signal cancelled event.
32503
+ */
32504
+ this.handleCancelled = async () => {
32505
+ };
32506
+ /**
32507
+ * Always returns null (no storage).
32508
+ * @returns null
32509
+ */
32510
+ this.findById = async () => {
32511
+ return null;
32512
+ };
32513
+ /**
32514
+ * Always returns empty array (no storage).
32515
+ * @returns Empty array
32516
+ */
32517
+ this.list = async () => {
32518
+ return [];
32519
+ };
32520
+ }
32521
+ }
32522
+ /**
32523
+ * Backtest storage adapter with pluggable storage backend.
31999
32524
  *
32000
- * // Disable tracking
32001
- * Storage.disable();
32002
- * ```
32525
+ * Features:
32526
+ * - Adapter pattern for swappable storage implementations
32527
+ * - Default adapter: StoragePersistBacktestUtils (persistent storage)
32528
+ * - Alternative adapters: StorageMemoryBacktestUtils, StorageDummyBacktestUtils
32529
+ * - Convenience methods: usePersist(), useMemory(), useDummy()
32530
+ */
32531
+ class StorageBacktestAdapter {
32532
+ constructor() {
32533
+ /** Internal storage utils instance */
32534
+ this._signalBacktestUtils = new StorageMemoryBacktestUtils();
32535
+ /**
32536
+ * Handles signal opened event.
32537
+ * Proxies call to the underlying storage adapter.
32538
+ * @param tick - The opened signal tick data
32539
+ */
32540
+ this.handleOpened = async (tick) => {
32541
+ return await this._signalBacktestUtils.handleOpened(tick);
32542
+ };
32543
+ /**
32544
+ * Handles signal closed event.
32545
+ * Proxies call to the underlying storage adapter.
32546
+ * @param tick - The closed signal tick data
32547
+ */
32548
+ this.handleClosed = async (tick) => {
32549
+ return await this._signalBacktestUtils.handleClosed(tick);
32550
+ };
32551
+ /**
32552
+ * Handles signal scheduled event.
32553
+ * Proxies call to the underlying storage adapter.
32554
+ * @param tick - The scheduled signal tick data
32555
+ */
32556
+ this.handleScheduled = async (tick) => {
32557
+ return await this._signalBacktestUtils.handleScheduled(tick);
32558
+ };
32559
+ /**
32560
+ * Handles signal cancelled event.
32561
+ * Proxies call to the underlying storage adapter.
32562
+ * @param tick - The cancelled signal tick data
32563
+ */
32564
+ this.handleCancelled = async (tick) => {
32565
+ return await this._signalBacktestUtils.handleCancelled(tick);
32566
+ };
32567
+ /**
32568
+ * Finds a signal by its ID.
32569
+ * Proxies call to the underlying storage adapter.
32570
+ * @param id - The signal ID to search for
32571
+ * @returns The signal row or null if not found
32572
+ */
32573
+ this.findById = async (id) => {
32574
+ return await this._signalBacktestUtils.findById(id);
32575
+ };
32576
+ /**
32577
+ * Lists all stored signals.
32578
+ * Proxies call to the underlying storage adapter.
32579
+ * @returns Array of all signal rows
32580
+ */
32581
+ this.list = async () => {
32582
+ return await this._signalBacktestUtils.list();
32583
+ };
32584
+ /**
32585
+ * Sets the storage adapter constructor.
32586
+ * All future storage operations will use this adapter.
32587
+ *
32588
+ * @param Ctor - Constructor for storage adapter
32589
+ */
32590
+ this.useStorageAdapter = (Ctor) => {
32591
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
32592
+ this._signalBacktestUtils = Reflect.construct(Ctor, []);
32593
+ };
32594
+ /**
32595
+ * Switches to dummy storage adapter.
32596
+ * All future storage writes will be no-ops.
32597
+ */
32598
+ this.useDummy = () => {
32599
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
32600
+ this._signalBacktestUtils = new StorageDummyBacktestUtils();
32601
+ };
32602
+ /**
32603
+ * Switches to persistent storage adapter (default).
32604
+ * Signals will be persisted to disk.
32605
+ */
32606
+ this.usePersist = () => {
32607
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
32608
+ this._signalBacktestUtils = new StoragePersistBacktestUtils();
32609
+ };
32610
+ /**
32611
+ * Switches to in-memory storage adapter.
32612
+ * Signals will be stored in memory only.
32613
+ */
32614
+ this.useMemory = () => {
32615
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
32616
+ this._signalBacktestUtils = new StorageMemoryBacktestUtils();
32617
+ };
32618
+ }
32619
+ }
32620
+ /**
32621
+ * Live trading storage adapter with pluggable storage backend.
32622
+ *
32623
+ * Features:
32624
+ * - Adapter pattern for swappable storage implementations
32625
+ * - Default adapter: StoragePersistLiveUtils (persistent storage)
32626
+ * - Alternative adapters: StorageMemoryLiveUtils, StorageDummyLiveUtils
32627
+ * - Convenience methods: usePersist(), useMemory(), useDummy()
32628
+ */
32629
+ class StorageLiveAdapter {
32630
+ constructor() {
32631
+ /** Internal storage utils instance */
32632
+ this._signalLiveUtils = new StoragePersistLiveUtils();
32633
+ /**
32634
+ * Handles signal opened event.
32635
+ * Proxies call to the underlying storage adapter.
32636
+ * @param tick - The opened signal tick data
32637
+ */
32638
+ this.handleOpened = async (tick) => {
32639
+ return await this._signalLiveUtils.handleOpened(tick);
32640
+ };
32641
+ /**
32642
+ * Handles signal closed event.
32643
+ * Proxies call to the underlying storage adapter.
32644
+ * @param tick - The closed signal tick data
32645
+ */
32646
+ this.handleClosed = async (tick) => {
32647
+ return await this._signalLiveUtils.handleClosed(tick);
32648
+ };
32649
+ /**
32650
+ * Handles signal scheduled event.
32651
+ * Proxies call to the underlying storage adapter.
32652
+ * @param tick - The scheduled signal tick data
32653
+ */
32654
+ this.handleScheduled = async (tick) => {
32655
+ return await this._signalLiveUtils.handleScheduled(tick);
32656
+ };
32657
+ /**
32658
+ * Handles signal cancelled event.
32659
+ * Proxies call to the underlying storage adapter.
32660
+ * @param tick - The cancelled signal tick data
32661
+ */
32662
+ this.handleCancelled = async (tick) => {
32663
+ return await this._signalLiveUtils.handleCancelled(tick);
32664
+ };
32665
+ /**
32666
+ * Finds a signal by its ID.
32667
+ * Proxies call to the underlying storage adapter.
32668
+ * @param id - The signal ID to search for
32669
+ * @returns The signal row or null if not found
32670
+ */
32671
+ this.findById = async (id) => {
32672
+ return await this._signalLiveUtils.findById(id);
32673
+ };
32674
+ /**
32675
+ * Lists all stored signals.
32676
+ * Proxies call to the underlying storage adapter.
32677
+ * @returns Array of all signal rows
32678
+ */
32679
+ this.list = async () => {
32680
+ return await this._signalLiveUtils.list();
32681
+ };
32682
+ /**
32683
+ * Sets the storage adapter constructor.
32684
+ * All future storage operations will use this adapter.
32685
+ *
32686
+ * @param Ctor - Constructor for storage adapter
32687
+ */
32688
+ this.useStorageAdapter = (Ctor) => {
32689
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
32690
+ this._signalLiveUtils = Reflect.construct(Ctor, []);
32691
+ };
32692
+ /**
32693
+ * Switches to dummy storage adapter.
32694
+ * All future storage writes will be no-ops.
32695
+ */
32696
+ this.useDummy = () => {
32697
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
32698
+ this._signalLiveUtils = new StorageDummyLiveUtils();
32699
+ };
32700
+ /**
32701
+ * Switches to persistent storage adapter (default).
32702
+ * Signals will be persisted to disk.
32703
+ */
32704
+ this.usePersist = () => {
32705
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
32706
+ this._signalLiveUtils = new StoragePersistLiveUtils();
32707
+ };
32708
+ /**
32709
+ * Switches to in-memory storage adapter.
32710
+ * Signals will be stored in memory only.
32711
+ */
32712
+ this.useMemory = () => {
32713
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
32714
+ this._signalLiveUtils = new StorageMemoryLiveUtils();
32715
+ };
32716
+ }
32717
+ }
32718
+ /**
32719
+ * Main storage adapter that manages both backtest and live signal storage.
32720
+ *
32721
+ * Features:
32722
+ * - Subscribes to signal emitters for automatic storage updates
32723
+ * - Provides unified access to both backtest and live signals
32724
+ * - Singleshot enable pattern prevents duplicate subscriptions
32725
+ * - Cleanup function for proper unsubscription
32003
32726
  */
32004
32727
  class StorageAdapter {
32005
32728
  constructor() {
32006
- this._signalLiveUtils = new StorageLiveUtils();
32007
- this._signalBacktestUtils = new StorageBacktestUtils();
32008
32729
  /**
32009
- * Enables signal history tracking by subscribing to emitters.
32730
+ * Enables signal storage by subscribing to signal emitters.
32731
+ * Uses singleshot to ensure one-time subscription.
32010
32732
  *
32011
- * @returns Cleanup function to unsubscribe from all emitters
32733
+ * @returns Cleanup function that unsubscribes from all emitters
32012
32734
  */
32013
32735
  this.enable = functoolsKit.singleshot(() => {
32014
32736
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_ENABLE);
@@ -32017,31 +32739,31 @@ class StorageAdapter {
32017
32739
  {
32018
32740
  const unBacktestOpen = signalBacktestEmitter
32019
32741
  .filter(({ action }) => action === "opened")
32020
- .connect((tick) => this._signalBacktestUtils.handleOpened(tick));
32742
+ .connect((tick) => StorageBacktest.handleOpened(tick));
32021
32743
  const unBacktestClose = signalBacktestEmitter
32022
32744
  .filter(({ action }) => action === "closed")
32023
- .connect((tick) => this._signalBacktestUtils.handleClosed(tick));
32745
+ .connect((tick) => StorageBacktest.handleClosed(tick));
32024
32746
  const unBacktestScheduled = signalBacktestEmitter
32025
32747
  .filter(({ action }) => action === "scheduled")
32026
- .connect((tick) => this._signalBacktestUtils.handleScheduled(tick));
32748
+ .connect((tick) => StorageBacktest.handleScheduled(tick));
32027
32749
  const unBacktestCancelled = signalBacktestEmitter
32028
32750
  .filter(({ action }) => action === "cancelled")
32029
- .connect((tick) => this._signalBacktestUtils.handleCancelled(tick));
32751
+ .connect((tick) => StorageBacktest.handleCancelled(tick));
32030
32752
  unBacktest = functoolsKit.compose(() => unBacktestOpen(), () => unBacktestClose(), () => unBacktestScheduled(), () => unBacktestCancelled());
32031
32753
  }
32032
32754
  {
32033
32755
  const unLiveOpen = signalLiveEmitter
32034
32756
  .filter(({ action }) => action === "opened")
32035
- .connect((tick) => this._signalLiveUtils.handleOpened(tick));
32757
+ .connect((tick) => StorageLive.handleOpened(tick));
32036
32758
  const unLiveClose = signalLiveEmitter
32037
32759
  .filter(({ action }) => action === "closed")
32038
- .connect((tick) => this._signalLiveUtils.handleClosed(tick));
32760
+ .connect((tick) => StorageLive.handleClosed(tick));
32039
32761
  const unLiveScheduled = signalLiveEmitter
32040
32762
  .filter(({ action }) => action === "scheduled")
32041
- .connect((tick) => this._signalLiveUtils.handleScheduled(tick));
32763
+ .connect((tick) => StorageLive.handleScheduled(tick));
32042
32764
  const unLiveCancelled = signalLiveEmitter
32043
32765
  .filter(({ action }) => action === "cancelled")
32044
- .connect((tick) => this._signalLiveUtils.handleCancelled(tick));
32766
+ .connect((tick) => StorageLive.handleCancelled(tick));
32045
32767
  unLive = functoolsKit.compose(() => unLiveOpen(), () => unLiveClose(), () => unLiveScheduled(), () => unLiveCancelled());
32046
32768
  }
32047
32769
  return () => {
@@ -32051,7 +32773,8 @@ class StorageAdapter {
32051
32773
  };
32052
32774
  });
32053
32775
  /**
32054
- * Disables signal history tracking by unsubscribing from emitters.
32776
+ * Disables signal storage by unsubscribing from all emitters.
32777
+ * Safe to call multiple times.
32055
32778
  */
32056
32779
  this.disable = () => {
32057
32780
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_DISABLE);
@@ -32061,11 +32784,12 @@ class StorageAdapter {
32061
32784
  }
32062
32785
  };
32063
32786
  /**
32064
- * Finds a signal by ID across both backtest and live history.
32787
+ * Finds a signal by ID across both backtest and live storage.
32065
32788
  *
32066
- * @param id - Signal identifier
32067
- * @returns Promise resolving to signal row
32068
- * @throws Error if signal not found in either storage
32789
+ * @param id - The signal ID to search for
32790
+ * @returns The signal row or throws if not found
32791
+ * @throws Error if StorageAdapter is not enabled
32792
+ * @throws Error if signal is not found in either storage
32069
32793
  */
32070
32794
  this.findSignalById = async (id) => {
32071
32795
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_FIND_SIGNAL_BY_ID, { id });
@@ -32073,41 +32797,57 @@ class StorageAdapter {
32073
32797
  throw new Error("StorageAdapter is not enabled. Call enable() first.");
32074
32798
  }
32075
32799
  let result = null;
32076
- if ((result = await this._signalBacktestUtils.findById(id))) {
32800
+ if ((result = await StorageBacktest.findById(id))) {
32077
32801
  return result;
32078
32802
  }
32079
- if ((result = await this._signalLiveUtils.findById(id))) {
32803
+ if ((result = await StorageLive.findById(id))) {
32080
32804
  return result;
32081
32805
  }
32082
32806
  throw new Error(`Storage signal with id ${id} not found`);
32083
32807
  };
32084
32808
  /**
32085
- * Lists all backtest signal history.
32809
+ * Lists all backtest signals from storage.
32086
32810
  *
32087
- * @returns Promise resolving to array of backtest signal rows
32811
+ * @returns Array of all backtest signal rows
32812
+ * @throws Error if StorageAdapter is not enabled
32088
32813
  */
32089
32814
  this.listSignalBacktest = async () => {
32090
32815
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_BACKTEST);
32091
32816
  if (!this.enable.hasValue()) {
32092
32817
  throw new Error("StorageAdapter is not enabled. Call enable() first.");
32093
32818
  }
32094
- return await this._signalBacktestUtils.list();
32819
+ return await StorageBacktest.list();
32095
32820
  };
32096
32821
  /**
32097
- * Lists all live signal history.
32822
+ * Lists all live signals from storage.
32098
32823
  *
32099
- * @returns Promise resolving to array of live signal rows
32824
+ * @returns Array of all live signal rows
32825
+ * @throws Error if StorageAdapter is not enabled
32100
32826
  */
32101
32827
  this.listSignalLive = async () => {
32102
32828
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_LIVE);
32103
32829
  if (!this.enable.hasValue()) {
32104
32830
  throw new Error("StorageAdapter is not enabled. Call enable() first.");
32105
32831
  }
32106
- return await this._signalLiveUtils.list();
32832
+ return await StorageLive.list();
32107
32833
  };
32108
32834
  }
32109
32835
  }
32836
+ /**
32837
+ * Global singleton instance of StorageAdapter.
32838
+ * Provides unified signal storage management for backtest and live trading.
32839
+ */
32110
32840
  const Storage = new StorageAdapter();
32841
+ /**
32842
+ * Global singleton instance of StorageLiveAdapter.
32843
+ * Provides live trading signal storage with pluggable backends.
32844
+ */
32845
+ const StorageLive = new StorageLiveAdapter();
32846
+ /**
32847
+ * Global singleton instance of StorageBacktestAdapter.
32848
+ * Provides backtest signal storage with pluggable backends.
32849
+ */
32850
+ const StorageBacktest = new StorageBacktestAdapter();
32111
32851
 
32112
32852
  const EXCHANGE_METHOD_NAME_GET_CANDLES = "ExchangeUtils.getCandles";
32113
32853
  const EXCHANGE_METHOD_NAME_GET_AVERAGE_PRICE = "ExchangeUtils.getAveragePrice";
@@ -33201,6 +33941,12 @@ class NotificationInstance {
33201
33941
  currentPrice: data.currentPrice,
33202
33942
  priceOpen: data.data.priceOpen,
33203
33943
  position: data.data.position,
33944
+ priceTakeProfit: data.data.priceTakeProfit,
33945
+ priceStopLoss: data.data.priceStopLoss,
33946
+ originalPriceTakeProfit: data.data.originalPriceTakeProfit,
33947
+ originalPriceStopLoss: data.data.originalPriceStopLoss,
33948
+ scheduledAt: data.data.scheduledAt,
33949
+ pendingAt: data.data.pendingAt,
33204
33950
  createdAt: data.timestamp,
33205
33951
  });
33206
33952
  };
@@ -33221,6 +33967,12 @@ class NotificationInstance {
33221
33967
  currentPrice: data.currentPrice,
33222
33968
  priceOpen: data.data.priceOpen,
33223
33969
  position: data.data.position,
33970
+ priceTakeProfit: data.data.priceTakeProfit,
33971
+ priceStopLoss: data.data.priceStopLoss,
33972
+ originalPriceTakeProfit: data.data.originalPriceTakeProfit,
33973
+ originalPriceStopLoss: data.data.originalPriceStopLoss,
33974
+ scheduledAt: data.data.scheduledAt,
33975
+ pendingAt: data.data.pendingAt,
33224
33976
  createdAt: data.timestamp,
33225
33977
  });
33226
33978
  };
@@ -33240,6 +33992,12 @@ class NotificationInstance {
33240
33992
  currentPrice: data.currentPrice,
33241
33993
  priceOpen: data.data.priceOpen,
33242
33994
  position: data.data.position,
33995
+ priceTakeProfit: data.data.priceTakeProfit,
33996
+ priceStopLoss: data.data.priceStopLoss,
33997
+ originalPriceTakeProfit: data.data.originalPriceTakeProfit,
33998
+ originalPriceStopLoss: data.data.originalPriceStopLoss,
33999
+ scheduledAt: data.data.scheduledAt,
34000
+ pendingAt: data.data.pendingAt,
33243
34001
  createdAt: data.timestamp,
33244
34002
  });
33245
34003
  };
@@ -33258,6 +34016,14 @@ class NotificationInstance {
33258
34016
  exchangeName: data.exchangeName,
33259
34017
  percentToClose: data.percentToClose,
33260
34018
  currentPrice: data.currentPrice,
34019
+ position: data.position,
34020
+ priceOpen: data.priceOpen,
34021
+ priceTakeProfit: data.priceTakeProfit,
34022
+ priceStopLoss: data.priceStopLoss,
34023
+ originalPriceTakeProfit: data.originalPriceTakeProfit,
34024
+ originalPriceStopLoss: data.originalPriceStopLoss,
34025
+ scheduledAt: data.scheduledAt,
34026
+ pendingAt: data.pendingAt,
33261
34027
  createdAt: data.timestamp,
33262
34028
  });
33263
34029
  }
@@ -33272,6 +34038,14 @@ class NotificationInstance {
33272
34038
  exchangeName: data.exchangeName,
33273
34039
  percentToClose: data.percentToClose,
33274
34040
  currentPrice: data.currentPrice,
34041
+ position: data.position,
34042
+ priceOpen: data.priceOpen,
34043
+ priceTakeProfit: data.priceTakeProfit,
34044
+ priceStopLoss: data.priceStopLoss,
34045
+ originalPriceTakeProfit: data.originalPriceTakeProfit,
34046
+ originalPriceStopLoss: data.originalPriceStopLoss,
34047
+ scheduledAt: data.scheduledAt,
34048
+ pendingAt: data.pendingAt,
33275
34049
  createdAt: data.timestamp,
33276
34050
  });
33277
34051
  }
@@ -33285,6 +34059,14 @@ class NotificationInstance {
33285
34059
  strategyName: data.strategyName,
33286
34060
  exchangeName: data.exchangeName,
33287
34061
  currentPrice: data.currentPrice,
34062
+ position: data.position,
34063
+ priceOpen: data.priceOpen,
34064
+ priceTakeProfit: data.priceTakeProfit,
34065
+ priceStopLoss: data.priceStopLoss,
34066
+ originalPriceTakeProfit: data.originalPriceTakeProfit,
34067
+ originalPriceStopLoss: data.originalPriceStopLoss,
34068
+ scheduledAt: data.scheduledAt,
34069
+ pendingAt: data.pendingAt,
33288
34070
  createdAt: data.timestamp,
33289
34071
  });
33290
34072
  }
@@ -33299,6 +34081,14 @@ class NotificationInstance {
33299
34081
  exchangeName: data.exchangeName,
33300
34082
  percentShift: data.percentShift,
33301
34083
  currentPrice: data.currentPrice,
34084
+ position: data.position,
34085
+ priceOpen: data.priceOpen,
34086
+ priceTakeProfit: data.priceTakeProfit,
34087
+ priceStopLoss: data.priceStopLoss,
34088
+ originalPriceTakeProfit: data.originalPriceTakeProfit,
34089
+ originalPriceStopLoss: data.originalPriceStopLoss,
34090
+ scheduledAt: data.scheduledAt,
34091
+ pendingAt: data.pendingAt,
33302
34092
  createdAt: data.timestamp,
33303
34093
  });
33304
34094
  }
@@ -33313,6 +34103,14 @@ class NotificationInstance {
33313
34103
  exchangeName: data.exchangeName,
33314
34104
  percentShift: data.percentShift,
33315
34105
  currentPrice: data.currentPrice,
34106
+ position: data.position,
34107
+ priceOpen: data.priceOpen,
34108
+ priceTakeProfit: data.priceTakeProfit,
34109
+ priceStopLoss: data.priceStopLoss,
34110
+ originalPriceTakeProfit: data.originalPriceTakeProfit,
34111
+ originalPriceStopLoss: data.originalPriceStopLoss,
34112
+ scheduledAt: data.scheduledAt,
34113
+ pendingAt: data.pendingAt,
33316
34114
  createdAt: data.timestamp,
33317
34115
  });
33318
34116
  }
@@ -34144,6 +34942,8 @@ exports.ReportBase = ReportBase;
34144
34942
  exports.Risk = Risk;
34145
34943
  exports.Schedule = Schedule;
34146
34944
  exports.Storage = Storage;
34945
+ exports.StorageBacktest = StorageBacktest;
34946
+ exports.StorageLive = StorageLive;
34147
34947
  exports.Strategy = Strategy;
34148
34948
  exports.Walker = Walker;
34149
34949
  exports.addActionSchema = addActionSchema;