backtest-kit 7.1.0 → 7.3.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
@@ -4770,8 +4770,7 @@ const TIMEOUT_SYMBOL = Symbol('timeout');
4770
4770
  * The framework will retry on the next tick.
4771
4771
  */
4772
4772
  const CALL_SIGNAL_SYNC_OPEN_FN = functoolsKit.trycatch(async (timestamp, currentPrice, pendingSignal, self) => {
4773
- const publicSignal = TO_PUBLIC_SIGNAL(pendingSignal, currentPrice);
4774
- const pnl = toProfitLossDto(pendingSignal, currentPrice);
4773
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", pendingSignal, currentPrice);
4775
4774
  return await self.params.onSignalSync({
4776
4775
  action: "signal-open",
4777
4776
  symbol: self.params.execution.context.symbol,
@@ -4782,10 +4781,12 @@ const CALL_SIGNAL_SYNC_OPEN_FN = functoolsKit.trycatch(async (timestamp, current
4782
4781
  signalId: pendingSignal.id,
4783
4782
  timestamp,
4784
4783
  signal: publicSignal,
4784
+ maxDrawdown: publicSignal.maxDrawdown,
4785
+ peakProfit: publicSignal.peakProfit,
4785
4786
  cost: pendingSignal.cost,
4786
4787
  currentPrice,
4787
4788
  position: publicSignal.position,
4788
- pnl,
4789
+ pnl: publicSignal.pnl,
4789
4790
  priceOpen: publicSignal.priceOpen,
4790
4791
  priceTakeProfit: publicSignal.priceTakeProfit,
4791
4792
  priceStopLoss: publicSignal.priceStopLoss,
@@ -4809,8 +4810,7 @@ const CALL_SIGNAL_SYNC_OPEN_FN = functoolsKit.trycatch(async (timestamp, current
4809
4810
  * strategy state is NOT mutated. The framework will retry on the next tick.
4810
4811
  */
4811
4812
  const CALL_SIGNAL_SYNC_CLOSE_FN = functoolsKit.trycatch(async (timestamp, currentPrice, closeReason, signal, self) => {
4812
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
4813
- const pnl = toProfitLossDto(signal, currentPrice);
4813
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
4814
4814
  return await self.params.onSignalSync({
4815
4815
  action: "signal-close",
4816
4816
  symbol: self.params.execution.context.symbol,
@@ -4821,8 +4821,10 @@ const CALL_SIGNAL_SYNC_CLOSE_FN = functoolsKit.trycatch(async (timestamp, curren
4821
4821
  signalId: signal.id,
4822
4822
  timestamp,
4823
4823
  signal: publicSignal,
4824
+ maxDrawdown: publicSignal.maxDrawdown,
4825
+ peakProfit: publicSignal.peakProfit,
4824
4826
  currentPrice,
4825
- pnl,
4827
+ pnl: publicSignal.pnl,
4826
4828
  position: publicSignal.position,
4827
4829
  priceOpen: publicSignal.priceOpen,
4828
4830
  priceTakeProfit: publicSignal.priceTakeProfit,
@@ -4883,10 +4885,9 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4883
4885
  if (!self._pendingSignal) {
4884
4886
  return;
4885
4887
  }
4886
- // Get public signal data for commit events (contains effective and original SL/TP)
4887
- const publicSignal = TO_PUBLIC_SIGNAL(self._pendingSignal, currentPrice);
4888
4888
  for (const commit of queue) {
4889
4889
  if (commit.action === "partial-profit") {
4890
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", self._pendingSignal, commit.currentPrice);
4890
4891
  await CALL_COMMIT_FN(self, {
4891
4892
  action: "partial-profit",
4892
4893
  symbol: commit.symbol,
@@ -4896,7 +4897,10 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4896
4897
  backtest: commit.backtest,
4897
4898
  percentToClose: commit.percentToClose,
4898
4899
  currentPrice: commit.currentPrice,
4899
- pnl: toProfitLossDto(self._pendingSignal, commit.currentPrice),
4900
+ pnl: publicSignal.pnl,
4901
+ maxDrawdown: publicSignal.maxDrawdown,
4902
+ peakProfit: publicSignal.peakProfit,
4903
+ signal: publicSignal,
4900
4904
  timestamp,
4901
4905
  totalEntries: publicSignal.totalEntries,
4902
4906
  totalPartials: publicSignal.totalPartials,
@@ -4915,6 +4919,7 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4915
4919
  continue;
4916
4920
  }
4917
4921
  if (commit.action === "partial-loss") {
4922
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", self._pendingSignal, commit.currentPrice);
4918
4923
  await CALL_COMMIT_FN(self, {
4919
4924
  action: "partial-loss",
4920
4925
  symbol: commit.symbol,
@@ -4924,7 +4929,10 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4924
4929
  backtest: commit.backtest,
4925
4930
  percentToClose: commit.percentToClose,
4926
4931
  currentPrice: commit.currentPrice,
4927
- pnl: toProfitLossDto(self._pendingSignal, commit.currentPrice),
4932
+ pnl: publicSignal.pnl,
4933
+ maxDrawdown: publicSignal.maxDrawdown,
4934
+ peakProfit: publicSignal.peakProfit,
4935
+ signal: publicSignal,
4928
4936
  timestamp,
4929
4937
  totalEntries: publicSignal.totalEntries,
4930
4938
  totalPartials: publicSignal.totalPartials,
@@ -4943,6 +4951,7 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4943
4951
  continue;
4944
4952
  }
4945
4953
  if (commit.action === "breakeven") {
4954
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", self._pendingSignal, commit.currentPrice);
4946
4955
  await CALL_COMMIT_FN(self, {
4947
4956
  action: "breakeven",
4948
4957
  symbol: commit.symbol,
@@ -4951,7 +4960,10 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4951
4960
  frameName: self.params.frameName,
4952
4961
  backtest: commit.backtest,
4953
4962
  currentPrice: commit.currentPrice,
4954
- pnl: toProfitLossDto(self._pendingSignal, commit.currentPrice),
4963
+ pnl: publicSignal.pnl,
4964
+ maxDrawdown: publicSignal.maxDrawdown,
4965
+ peakProfit: publicSignal.peakProfit,
4966
+ signal: publicSignal,
4955
4967
  timestamp,
4956
4968
  totalEntries: publicSignal.totalEntries,
4957
4969
  totalPartials: publicSignal.totalPartials,
@@ -4970,6 +4982,7 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4970
4982
  continue;
4971
4983
  }
4972
4984
  if (commit.action === "trailing-stop") {
4985
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", self._pendingSignal, commit.currentPrice);
4973
4986
  await CALL_COMMIT_FN(self, {
4974
4987
  action: "trailing-stop",
4975
4988
  symbol: commit.symbol,
@@ -4979,7 +4992,10 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4979
4992
  backtest: commit.backtest,
4980
4993
  percentShift: commit.percentShift,
4981
4994
  currentPrice: commit.currentPrice,
4982
- pnl: toProfitLossDto(self._pendingSignal, commit.currentPrice),
4995
+ pnl: publicSignal.pnl,
4996
+ maxDrawdown: publicSignal.maxDrawdown,
4997
+ peakProfit: publicSignal.peakProfit,
4998
+ signal: publicSignal,
4983
4999
  timestamp,
4984
5000
  totalEntries: publicSignal.totalEntries,
4985
5001
  totalPartials: publicSignal.totalPartials,
@@ -4998,6 +5014,7 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
4998
5014
  continue;
4999
5015
  }
5000
5016
  if (commit.action === "trailing-take") {
5017
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", self._pendingSignal, commit.currentPrice);
5001
5018
  await CALL_COMMIT_FN(self, {
5002
5019
  action: "trailing-take",
5003
5020
  symbol: commit.symbol,
@@ -5007,7 +5024,10 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
5007
5024
  backtest: commit.backtest,
5008
5025
  percentShift: commit.percentShift,
5009
5026
  currentPrice: commit.currentPrice,
5010
- pnl: toProfitLossDto(self._pendingSignal, commit.currentPrice),
5027
+ pnl: publicSignal.pnl,
5028
+ maxDrawdown: publicSignal.maxDrawdown,
5029
+ peakProfit: publicSignal.peakProfit,
5030
+ signal: publicSignal,
5011
5031
  timestamp,
5012
5032
  totalEntries: publicSignal.totalEntries,
5013
5033
  totalPartials: publicSignal.totalPartials,
@@ -5026,6 +5046,7 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
5026
5046
  continue;
5027
5047
  }
5028
5048
  if (commit.action === "average-buy") {
5049
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", self._pendingSignal, commit.currentPrice);
5029
5050
  const effectivePriceOpen = getEffectivePriceOpen(self._pendingSignal);
5030
5051
  await CALL_COMMIT_FN(self, {
5031
5052
  action: "average-buy",
@@ -5037,7 +5058,10 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
5037
5058
  currentPrice: commit.currentPrice,
5038
5059
  cost: commit.cost,
5039
5060
  effectivePriceOpen,
5040
- pnl: toProfitLossDto(self._pendingSignal, commit.currentPrice),
5061
+ pnl: publicSignal.pnl,
5062
+ maxDrawdown: publicSignal.maxDrawdown,
5063
+ peakProfit: publicSignal.peakProfit,
5064
+ signal: publicSignal,
5041
5065
  timestamp,
5042
5066
  totalEntries: publicSignal.totalEntries,
5043
5067
  totalPartials: publicSignal.totalPartials,
@@ -5057,6 +5081,8 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
5057
5081
  }
5058
5082
  }
5059
5083
  };
5084
+ /** Zero PNL constant for scheduled signals (which don't have priceOpen or PNL yet) */
5085
+ const ZERO_PNL$1 = { pnlPercentage: 0, priceOpen: 0, priceClose: 0, pnlCost: 0, pnlEntries: 0 };
5060
5086
  /**
5061
5087
  * Converts internal signal to public API format.
5062
5088
  *
@@ -5104,7 +5130,7 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, currentPrice, timestamp) => {
5104
5130
  * // publicSignal._trailingPriceTakeProfit = undefined (hidden from external API)
5105
5131
  * ```
5106
5132
  */
5107
- const TO_PUBLIC_SIGNAL = (signal, currentPrice) => {
5133
+ const TO_PUBLIC_SIGNAL = (type, signal, currentPrice) => {
5108
5134
  const hasTrailingSL = "_trailingPriceStopLoss" in signal && signal._trailingPriceStopLoss !== undefined;
5109
5135
  const hasTrailingTP = "_trailingPriceTakeProfit" in signal && signal._trailingPriceTakeProfit !== undefined;
5110
5136
  const partialExecuted = "_partial" in signal
@@ -5112,11 +5138,14 @@ const TO_PUBLIC_SIGNAL = (signal, currentPrice) => {
5112
5138
  : 0;
5113
5139
  const totalEntries = ("_entry" in signal && Array.isArray(signal._entry))
5114
5140
  ? signal._entry.length
5115
- : 1;
5141
+ : type === "scheduled" ? 0 : 1;
5116
5142
  const totalPartials = ("_partial" in signal && Array.isArray(signal._partial))
5117
5143
  ? signal._partial.length
5118
5144
  : 0;
5119
- const effectivePriceOpen = "_entry" in signal ? getEffectivePriceOpen(signal) : signal.priceOpen;
5145
+ const pnl = type === "scheduled" ? ZERO_PNL$1 : toProfitLossDto(signal, currentPrice);
5146
+ const maxDrawdown = type === "scheduled" ? ZERO_PNL$1 : ("_fall" in signal ? !!signal["_fall"] ? ({ ...signal._fall }) : ZERO_PNL$1 : ZERO_PNL$1);
5147
+ const peakProfit = type === "scheduled" ? ZERO_PNL$1 : ("_peak" in signal ? signal["_peak"] ? ({ ...signal._peak }) : ZERO_PNL$1 : ZERO_PNL$1);
5148
+ const effectivePriceOpen = type === "scheduled" ? signal.priceOpen : "_entry" in signal ? signal["_entry"] ? getEffectivePriceOpen(signal) : signal.priceOpen : signal.priceOpen;
5120
5149
  return {
5121
5150
  ...structuredClone(signal),
5122
5151
  priceOpen: effectivePriceOpen,
@@ -5125,10 +5154,12 @@ const TO_PUBLIC_SIGNAL = (signal, currentPrice) => {
5125
5154
  originalPriceOpen: signal.priceOpen,
5126
5155
  originalPriceStopLoss: signal.priceStopLoss,
5127
5156
  originalPriceTakeProfit: signal.priceTakeProfit,
5157
+ maxDrawdown,
5158
+ peakProfit,
5128
5159
  partialExecuted,
5129
5160
  totalEntries,
5130
5161
  totalPartials,
5131
- pnl: toProfitLossDto(signal, currentPrice),
5162
+ pnl,
5132
5163
  };
5133
5164
  };
5134
5165
  const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
@@ -5193,8 +5224,8 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
5193
5224
  timestamp: currentTime,
5194
5225
  _isScheduled: false,
5195
5226
  _entry: [{ price: signal.priceOpen, cost: signal.cost ?? GLOBAL_CONFIG.CC_POSITION_ENTRY_COST, timestamp: currentTime }],
5196
- _peak: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
5197
- _fall: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
5227
+ _peak: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
5228
+ _fall: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
5198
5229
  };
5199
5230
  // Валидируем сигнал перед возвратом
5200
5231
  validatePendingSignal(signalRow, currentPrice);
@@ -5219,8 +5250,8 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
5219
5250
  timestamp: currentTime,
5220
5251
  _isScheduled: true,
5221
5252
  _entry: [{ price: signal.priceOpen, cost: signal.cost ?? GLOBAL_CONFIG.CC_POSITION_ENTRY_COST, timestamp: currentTime }],
5222
- _peak: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
5223
- _fall: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
5253
+ _peak: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
5254
+ _fall: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
5224
5255
  };
5225
5256
  // Валидируем сигнал перед возвратом
5226
5257
  validateScheduledSignal(scheduledSignalRow, currentPrice);
@@ -5242,8 +5273,8 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
5242
5273
  timestamp: currentTime,
5243
5274
  _isScheduled: false,
5244
5275
  _entry: [{ price: currentPrice, cost: signal.cost ?? GLOBAL_CONFIG.CC_POSITION_ENTRY_COST, timestamp: currentTime }],
5245
- _peak: { price: currentPrice, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
5246
- _fall: { price: currentPrice, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
5276
+ _peak: { price: currentPrice, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
5277
+ _fall: { price: currentPrice, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
5247
5278
  };
5248
5279
  // Валидируем сигнал перед возвратом
5249
5280
  validatePendingSignal(signalRow, currentPrice);
@@ -5847,7 +5878,7 @@ const CHECK_SCHEDULED_SIGNAL_TIMEOUT_FN = async (self, scheduled, currentPrice)
5847
5878
  await CALL_CANCEL_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentPrice, currentTime, self.params.execution.context.backtest);
5848
5879
  const result = {
5849
5880
  action: "cancelled",
5850
- signal: TO_PUBLIC_SIGNAL(scheduled, currentPrice),
5881
+ signal: TO_PUBLIC_SIGNAL("scheduled", scheduled, currentPrice),
5851
5882
  currentPrice: currentPrice,
5852
5883
  closeTimestamp: currentTime,
5853
5884
  strategyName: self.params.method.context.strategyName,
@@ -5903,7 +5934,7 @@ const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPr
5903
5934
  await CALL_CANCEL_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentPrice, currentTime, self.params.execution.context.backtest);
5904
5935
  const result = {
5905
5936
  action: "cancelled",
5906
- signal: TO_PUBLIC_SIGNAL(scheduled, currentPrice),
5937
+ signal: TO_PUBLIC_SIGNAL("scheduled", scheduled, currentPrice),
5907
5938
  currentPrice: currentPrice,
5908
5939
  closeTimestamp: currentTime,
5909
5940
  strategyName: self.params.method.context.strategyName,
@@ -5954,8 +5985,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
5954
5985
  ...scheduled,
5955
5986
  pendingAt: activationTime,
5956
5987
  _isScheduled: false,
5957
- _peak: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0 },
5958
- _fall: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0 },
5988
+ _peak: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
5989
+ _fall: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
5959
5990
  };
5960
5991
  // Sync open: if external system rejects — cancel scheduled signal instead of opening
5961
5992
  const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(activationTime, activatedSignal.priceOpen, activatedSignal, self);
@@ -5965,6 +5996,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
5965
5996
  signalId: scheduled.id,
5966
5997
  });
5967
5998
  await self.setScheduledSignal(null);
5999
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", scheduled, scheduled.priceOpen);
5968
6000
  await CALL_COMMIT_FN(self, {
5969
6001
  action: "cancel-scheduled",
5970
6002
  symbol: self.params.execution.context.symbol,
@@ -5977,7 +6009,10 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
5977
6009
  totalEntries: scheduled._entry?.length ?? 1,
5978
6010
  totalPartials: scheduled._partial?.length ?? 0,
5979
6011
  originalPriceOpen: scheduled.priceOpen,
5980
- pnl: toProfitLossDto(scheduled, scheduled.priceOpen),
6012
+ pnl: publicSignal.pnl,
6013
+ maxDrawdown: publicSignal.maxDrawdown,
6014
+ peakProfit: publicSignal.peakProfit,
6015
+ signal: publicSignal,
5981
6016
  note: scheduled.note,
5982
6017
  });
5983
6018
  return null;
@@ -5988,7 +6023,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
5988
6023
  await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, self._pendingSignal, self._pendingSignal.priceOpen, activationTime, self.params.execution.context.backtest);
5989
6024
  const result = {
5990
6025
  action: "opened",
5991
- signal: TO_PUBLIC_SIGNAL(self._pendingSignal, self._pendingSignal.priceOpen),
6026
+ signal: TO_PUBLIC_SIGNAL("pending", self._pendingSignal, self._pendingSignal.priceOpen),
5992
6027
  strategyName: self.params.method.context.strategyName,
5993
6028
  exchangeName: self.params.method.context.exchangeName,
5994
6029
  frameName: self.params.method.context.frameName,
@@ -6002,7 +6037,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
6002
6037
  };
6003
6038
  const CALL_SCHEDULE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, scheduled, timestamp, backtest, currentPrice) => {
6004
6039
  await ExecutionContextService.runInContext(async () => {
6005
- const publicSignal = TO_PUBLIC_SIGNAL(scheduled, currentPrice);
6040
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", scheduled, currentPrice);
6006
6041
  // Call system onSchedulePing callback first (emits to pingSubject)
6007
6042
  await self.params.onSchedulePing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, publicSignal, currentPrice, self.params.execution.context.backtest, timestamp);
6008
6043
  // Call user onSchedulePing callback only if signal is still active (not cancelled, not activated)
@@ -6028,7 +6063,7 @@ const CALL_SCHEDULE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (s
6028
6063
  });
6029
6064
  const CALL_ACTIVE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, pending, timestamp, backtest, currentPrice) => {
6030
6065
  await ExecutionContextService.runInContext(async () => {
6031
- const publicSignal = TO_PUBLIC_SIGNAL(pending, currentPrice);
6066
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", pending, currentPrice);
6032
6067
  // Call system onActivePing callback first (emits to activePingSubject)
6033
6068
  await self.params.onActivePing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, publicSignal, currentPrice, self.params.execution.context.backtest, timestamp);
6034
6069
  // Call user onActivePing callback only if signal is still active (not closed)
@@ -6076,7 +6111,7 @@ const CALL_IDLE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self,
6076
6111
  const CALL_ACTIVE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, timestamp, backtest) => {
6077
6112
  await ExecutionContextService.runInContext(async () => {
6078
6113
  if (self.params.callbacks?.onActive) {
6079
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6114
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6080
6115
  await self.params.callbacks.onActive(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
6081
6116
  }
6082
6117
  }, {
@@ -6099,7 +6134,7 @@ const CALL_ACTIVE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, sy
6099
6134
  const CALL_SCHEDULE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, timestamp, backtest) => {
6100
6135
  await ExecutionContextService.runInContext(async () => {
6101
6136
  if (self.params.callbacks?.onSchedule) {
6102
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6137
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", signal, currentPrice);
6103
6138
  await self.params.callbacks.onSchedule(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
6104
6139
  }
6105
6140
  }, {
@@ -6122,7 +6157,7 @@ const CALL_SCHEDULE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self,
6122
6157
  const CALL_CANCEL_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, timestamp, backtest) => {
6123
6158
  await ExecutionContextService.runInContext(async () => {
6124
6159
  if (self.params.callbacks?.onCancel) {
6125
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6160
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", signal, currentPrice);
6126
6161
  await self.params.callbacks.onCancel(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
6127
6162
  }
6128
6163
  }, {
@@ -6145,7 +6180,7 @@ const CALL_CANCEL_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, sy
6145
6180
  const CALL_OPEN_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, priceOpen, timestamp, backtest) => {
6146
6181
  await ExecutionContextService.runInContext(async () => {
6147
6182
  if (self.params.callbacks?.onOpen) {
6148
- const publicSignal = TO_PUBLIC_SIGNAL(signal, priceOpen);
6183
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, priceOpen);
6149
6184
  await self.params.callbacks.onOpen(self.params.execution.context.symbol, publicSignal, priceOpen, self.params.execution.context.backtest);
6150
6185
  }
6151
6186
  }, {
@@ -6168,7 +6203,7 @@ const CALL_OPEN_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symb
6168
6203
  const CALL_CLOSE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, timestamp, backtest) => {
6169
6204
  await ExecutionContextService.runInContext(async () => {
6170
6205
  if (self.params.callbacks?.onClose) {
6171
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6206
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6172
6207
  await self.params.callbacks.onClose(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
6173
6208
  }
6174
6209
  }, {
@@ -6291,7 +6326,7 @@ const CALL_RISK_REMOVE_SIGNAL_FN = functoolsKit.trycatch(beginTime(async (self,
6291
6326
  });
6292
6327
  const CALL_PARTIAL_CLEAR_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, timestamp, backtest) => {
6293
6328
  await ExecutionContextService.runInContext(async () => {
6294
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6329
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6295
6330
  await self.params.partial.clear(symbol, publicSignal, currentPrice, backtest);
6296
6331
  }, {
6297
6332
  when: new Date(timestamp),
@@ -6313,7 +6348,7 @@ const CALL_PARTIAL_CLEAR_FN = functoolsKit.trycatch(beginTime(async (self, symbo
6313
6348
  const CALL_RISK_CHECK_SIGNAL_FN = functoolsKit.trycatch(beginTime(async (self, symbol, pendingSignal, currentPrice, timestamp, backtest) => {
6314
6349
  return await ExecutionContextService.runInContext(async () => {
6315
6350
  return await self.params.risk.checkSignal({
6316
- currentSignal: TO_PUBLIC_SIGNAL(pendingSignal, currentPrice),
6351
+ currentSignal: TO_PUBLIC_SIGNAL("scheduled", pendingSignal, currentPrice),
6317
6352
  symbol: symbol,
6318
6353
  strategyName: self.params.method.context.strategyName,
6319
6354
  exchangeName: self.params.method.context.exchangeName,
@@ -6342,7 +6377,7 @@ const CALL_RISK_CHECK_SIGNAL_FN = functoolsKit.trycatch(beginTime(async (self, s
6342
6377
  });
6343
6378
  const CALL_PARTIAL_PROFIT_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, percentTp, timestamp, backtest) => {
6344
6379
  await ExecutionContextService.runInContext(async () => {
6345
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6380
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6346
6381
  await self.params.partial.profit(symbol, publicSignal, currentPrice, percentTp, backtest, new Date(timestamp));
6347
6382
  if (self.params.callbacks?.onPartialProfit) {
6348
6383
  await self.params.callbacks.onPartialProfit(symbol, publicSignal, currentPrice, percentTp, backtest);
@@ -6366,7 +6401,7 @@ const CALL_PARTIAL_PROFIT_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (
6366
6401
  });
6367
6402
  const CALL_PARTIAL_LOSS_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, percentSl, timestamp, backtest) => {
6368
6403
  await ExecutionContextService.runInContext(async () => {
6369
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6404
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6370
6405
  await self.params.partial.loss(symbol, publicSignal, currentPrice, percentSl, backtest, new Date(timestamp));
6371
6406
  if (self.params.callbacks?.onPartialLoss) {
6372
6407
  await self.params.callbacks.onPartialLoss(symbol, publicSignal, currentPrice, percentSl, backtest);
@@ -6390,7 +6425,7 @@ const CALL_PARTIAL_LOSS_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (se
6390
6425
  });
6391
6426
  const CALL_BREAKEVEN_CHECK_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, timestamp, backtest) => {
6392
6427
  await ExecutionContextService.runInContext(async () => {
6393
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6428
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6394
6429
  const isBreakeven = await self.params.breakeven.check(symbol, publicSignal, currentPrice, backtest, new Date(timestamp));
6395
6430
  if (self.params.callbacks?.onBreakeven) {
6396
6431
  isBreakeven && await self.params.callbacks.onBreakeven(symbol, publicSignal, currentPrice, backtest);
@@ -6414,7 +6449,7 @@ const CALL_BREAKEVEN_CHECK_FN = functoolsKit.trycatch(beginTime(async (self, sym
6414
6449
  });
6415
6450
  const CALL_BREAKEVEN_CLEAR_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, currentPrice, timestamp, backtest) => {
6416
6451
  await ExecutionContextService.runInContext(async () => {
6417
- const publicSignal = TO_PUBLIC_SIGNAL(signal, currentPrice);
6452
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6418
6453
  await self.params.breakeven.clear(symbol, publicSignal, currentPrice, backtest);
6419
6454
  }, {
6420
6455
  when: new Date(timestamp),
@@ -6437,7 +6472,7 @@ const CALL_BACKTEST_SCHEDULE_OPEN_FN = functoolsKit.trycatch(beginTime(async (se
6437
6472
  await ExecutionContextService.runInContext(async () => {
6438
6473
  backtestScheduleOpenSubject.next({
6439
6474
  action: "opened",
6440
- signal: TO_PUBLIC_SIGNAL(signal, signal.priceOpen),
6475
+ signal: TO_PUBLIC_SIGNAL("pending", signal, signal.priceOpen),
6441
6476
  strategyName: self.params.method.context.strategyName,
6442
6477
  exchangeName: self.params.method.context.exchangeName,
6443
6478
  frameName: self.params.method.context.frameName,
@@ -6466,10 +6501,10 @@ const CALL_BACKTEST_SCHEDULE_OPEN_FN = functoolsKit.trycatch(beginTime(async (se
6466
6501
  const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
6467
6502
  const currentTime = self.params.execution.context.when.getTime();
6468
6503
  await CALL_SCHEDULE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentTime, self.params.execution.context.backtest, currentPrice);
6469
- const pnl = toProfitLossDto(scheduled, currentPrice);
6504
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", scheduled, currentPrice);
6470
6505
  const result = {
6471
6506
  action: "waiting",
6472
- signal: TO_PUBLIC_SIGNAL(scheduled, currentPrice),
6507
+ signal: publicSignal,
6473
6508
  currentPrice: currentPrice,
6474
6509
  strategyName: self.params.method.context.strategyName,
6475
6510
  exchangeName: self.params.method.context.exchangeName,
@@ -6477,7 +6512,7 @@ const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice)
6477
6512
  symbol: self.params.execution.context.symbol,
6478
6513
  percentTp: 0,
6479
6514
  percentSl: 0,
6480
- pnl,
6515
+ pnl: publicSignal.pnl,
6481
6516
  backtest: self.params.execution.context.backtest,
6482
6517
  createdAt: currentTime,
6483
6518
  };
@@ -6497,7 +6532,7 @@ const OPEN_NEW_SCHEDULED_SIGNAL_FN = async (self, signal) => {
6497
6532
  await CALL_SCHEDULE_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
6498
6533
  const result = {
6499
6534
  action: "scheduled",
6500
- signal: TO_PUBLIC_SIGNAL(signal, currentPrice),
6535
+ signal: TO_PUBLIC_SIGNAL("scheduled", signal, currentPrice),
6501
6536
  strategyName: self.params.method.context.strategyName,
6502
6537
  exchangeName: self.params.method.context.exchangeName,
6503
6538
  frameName: self.params.method.context.frameName,
@@ -6527,7 +6562,7 @@ const OPEN_NEW_PENDING_SIGNAL_FN = async (self, signal) => {
6527
6562
  await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, signal.priceOpen, currentTime, self.params.execution.context.backtest);
6528
6563
  const result = {
6529
6564
  action: "opened",
6530
- signal: TO_PUBLIC_SIGNAL(signal, signal.priceOpen),
6565
+ signal: TO_PUBLIC_SIGNAL("pending", signal, signal.priceOpen),
6531
6566
  strategyName: self.params.method.context.strategyName,
6532
6567
  exchangeName: self.params.method.context.exchangeName,
6533
6568
  frameName: self.params.method.context.frameName,
@@ -6582,13 +6617,13 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
6582
6617
  });
6583
6618
  return null;
6584
6619
  }
6585
- const pnl = toProfitLossDto(signal, currentPrice);
6620
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6586
6621
  self.params.logger.info(`ClientStrategy signal ${closeReason}`, {
6587
6622
  symbol: self.params.execution.context.symbol,
6588
6623
  signalId: signal.id,
6589
6624
  closeReason,
6590
6625
  priceClose: currentPrice,
6591
- pnlPercentage: pnl.pnlPercentage,
6626
+ pnlPercentage: publicSignal.pnl.pnlPercentage,
6592
6627
  });
6593
6628
  await CALL_CLOSE_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
6594
6629
  // КРИТИЧНО: Очищаем состояние ClientPartial при закрытии позиции
@@ -6599,11 +6634,11 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
6599
6634
  await self.setPendingSignal(null);
6600
6635
  const result = {
6601
6636
  action: "closed",
6602
- signal: TO_PUBLIC_SIGNAL(signal, currentPrice),
6637
+ signal: publicSignal,
6603
6638
  currentPrice: currentPrice,
6604
6639
  closeReason: closeReason,
6605
6640
  closeTimestamp: currentTime,
6606
- pnl: pnl,
6641
+ pnl: publicSignal.pnl,
6607
6642
  strategyName: self.params.method.context.strategyName,
6608
6643
  exchangeName: self.params.method.context.exchangeName,
6609
6644
  frameName: self.params.method.context.frameName,
@@ -6618,17 +6653,12 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
6618
6653
  let percentTp = 0;
6619
6654
  let percentSl = 0;
6620
6655
  const currentTime = self.params.execution.context.when.getTime();
6621
- await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest, currentPrice);
6622
6656
  // Calculate percentage of path to TP/SL for partial fill/loss callbacks
6623
6657
  {
6624
6658
  const effectivePriceOpen = getEffectivePriceOpen(signal);
6625
6659
  if (signal.position === "long") {
6626
6660
  // For long: calculate progress towards TP or SL
6627
6661
  const currentDistance = currentPrice - effectivePriceOpen;
6628
- if (currentDistance > 0) {
6629
- // Check if breakeven should be triggered
6630
- await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
6631
- }
6632
6662
  if (currentDistance > 0) {
6633
6663
  // Moving towards TP (use trailing TP if set)
6634
6664
  const effectiveTakeProfit = signal._trailingPriceTakeProfit ?? signal.priceTakeProfit;
@@ -6636,14 +6666,17 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
6636
6666
  const progressPercent = (currentDistance / tpDistance) * 100;
6637
6667
  percentTp = Math.min(progressPercent, 100);
6638
6668
  if (currentPrice > signal._peak.price) {
6639
- const { pnl } = TO_PUBLIC_SIGNAL(signal, currentPrice);
6640
- signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
6669
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6670
+ signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
6641
6671
  if (self.params.callbacks?.onWrite) {
6642
6672
  self.params.callbacks.onWrite(signal.symbol, signal, backtest);
6643
6673
  }
6644
6674
  !backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
6645
- await self.params.onHighestProfit(TO_PUBLIC_SIGNAL(signal, currentPrice), currentPrice, currentTime);
6675
+ await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
6646
6676
  }
6677
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest, currentPrice);
6678
+ // Check if breakeven should be triggered
6679
+ await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
6647
6680
  await CALL_PARTIAL_PROFIT_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentPrice, percentTp, currentTime, self.params.execution.context.backtest);
6648
6681
  }
6649
6682
  else if (currentDistance < 0) {
@@ -6653,24 +6686,24 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
6653
6686
  const progressPercent = (Math.abs(currentDistance) / slDistance) * 100;
6654
6687
  percentSl = Math.min(progressPercent, 100);
6655
6688
  if (currentPrice < signal._fall.price) {
6656
- const { pnl } = TO_PUBLIC_SIGNAL(signal, currentPrice);
6657
- signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
6689
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6690
+ signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
6658
6691
  if (self.params.callbacks?.onWrite) {
6659
6692
  self.params.callbacks.onWrite(signal.symbol, signal, backtest);
6660
6693
  }
6661
6694
  !backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
6662
- await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL(signal, currentPrice), currentPrice, currentTime);
6695
+ await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
6663
6696
  }
6697
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest, currentPrice);
6664
6698
  await CALL_PARTIAL_LOSS_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentPrice, percentSl, currentTime, self.params.execution.context.backtest);
6665
6699
  }
6700
+ else {
6701
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest, currentPrice);
6702
+ }
6666
6703
  }
6667
6704
  else if (signal.position === "short") {
6668
6705
  // For short: calculate progress towards TP or SL
6669
6706
  const currentDistance = effectivePriceOpen - currentPrice;
6670
- if (currentDistance > 0) {
6671
- // Check if breakeven should be triggered
6672
- await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
6673
- }
6674
6707
  if (currentDistance > 0) {
6675
6708
  // Moving towards TP (use trailing TP if set)
6676
6709
  const effectiveTakeProfit = signal._trailingPriceTakeProfit ?? signal.priceTakeProfit;
@@ -6678,39 +6711,46 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
6678
6711
  const progressPercent = (currentDistance / tpDistance) * 100;
6679
6712
  percentTp = Math.min(progressPercent, 100);
6680
6713
  if (currentPrice < signal._peak.price) {
6681
- const { pnl } = TO_PUBLIC_SIGNAL(signal, currentPrice);
6682
- signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
6714
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6715
+ signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
6683
6716
  if (self.params.callbacks?.onWrite) {
6684
6717
  self.params.callbacks.onWrite(signal.symbol, signal, backtest);
6685
6718
  }
6686
6719
  !backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
6687
- await self.params.onHighestProfit(TO_PUBLIC_SIGNAL(signal, currentPrice), currentPrice, currentTime);
6720
+ await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
6688
6721
  }
6722
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest, currentPrice);
6723
+ // Check if breakeven should be triggered
6724
+ await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
6689
6725
  await CALL_PARTIAL_PROFIT_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentPrice, percentTp, currentTime, self.params.execution.context.backtest);
6690
6726
  }
6691
- if (currentDistance < 0) {
6727
+ else if (currentDistance < 0) {
6692
6728
  // Moving towards SL (use trailing SL if set)
6693
6729
  const effectiveStopLoss = signal._trailingPriceStopLoss ?? signal.priceStopLoss;
6694
6730
  const slDistance = effectiveStopLoss - effectivePriceOpen;
6695
6731
  const progressPercent = (Math.abs(currentDistance) / slDistance) * 100;
6696
6732
  percentSl = Math.min(progressPercent, 100);
6697
6733
  if (currentPrice > signal._fall.price) {
6698
- const { pnl } = TO_PUBLIC_SIGNAL(signal, currentPrice);
6699
- signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
6734
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6735
+ signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
6700
6736
  if (self.params.callbacks?.onWrite) {
6701
6737
  self.params.callbacks.onWrite(signal.symbol, signal, backtest);
6702
6738
  }
6703
6739
  !backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
6704
- await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL(signal, currentPrice), currentPrice, currentTime);
6740
+ await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
6705
6741
  }
6742
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest, currentPrice);
6706
6743
  await CALL_PARTIAL_LOSS_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentPrice, percentSl, currentTime, self.params.execution.context.backtest);
6707
6744
  }
6745
+ else {
6746
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest, currentPrice);
6747
+ }
6708
6748
  }
6709
6749
  }
6710
- const pnl = toProfitLossDto(signal, currentPrice);
6750
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
6711
6751
  const result = {
6712
6752
  action: "active",
6713
- signal: TO_PUBLIC_SIGNAL(signal, currentPrice),
6753
+ signal: publicSignal,
6714
6754
  currentPrice: currentPrice,
6715
6755
  strategyName: self.params.method.context.strategyName,
6716
6756
  exchangeName: self.params.method.context.exchangeName,
@@ -6718,7 +6758,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
6718
6758
  symbol: self.params.execution.context.symbol,
6719
6759
  percentTp,
6720
6760
  percentSl,
6721
- pnl,
6761
+ pnl: publicSignal.pnl,
6722
6762
  backtest: self.params.execution.context.backtest,
6723
6763
  createdAt: currentTime,
6724
6764
  _backtestLastTimestamp: currentTime,
@@ -6754,6 +6794,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
6754
6794
  reason,
6755
6795
  });
6756
6796
  await self.setScheduledSignal(null);
6797
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", scheduled, averagePrice);
6757
6798
  if (reason === "user") {
6758
6799
  await CALL_COMMIT_FN(self, {
6759
6800
  action: "cancel-scheduled",
@@ -6768,14 +6809,17 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
6768
6809
  totalEntries: scheduled._entry?.length ?? 1,
6769
6810
  totalPartials: scheduled._partial?.length ?? 0,
6770
6811
  originalPriceOpen: scheduled.priceOpen,
6771
- pnl: toProfitLossDto(scheduled, averagePrice),
6812
+ pnl: publicSignal.pnl,
6813
+ maxDrawdown: publicSignal.maxDrawdown,
6814
+ peakProfit: publicSignal.peakProfit,
6815
+ signal: publicSignal,
6772
6816
  note: cancelNote ?? scheduled.note,
6773
6817
  });
6774
6818
  }
6775
6819
  await CALL_CANCEL_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, averagePrice, closeTimestamp, self.params.execution.context.backtest);
6776
6820
  const result = {
6777
6821
  action: "cancelled",
6778
- signal: TO_PUBLIC_SIGNAL(scheduled, averagePrice),
6822
+ signal: publicSignal,
6779
6823
  currentPrice: averagePrice,
6780
6824
  closeTimestamp: closeTimestamp,
6781
6825
  strategyName: self.params.method.context.strategyName,
@@ -6824,8 +6868,8 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
6824
6868
  ...scheduled,
6825
6869
  pendingAt: activationTime,
6826
6870
  _isScheduled: false,
6827
- _peak: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0 },
6828
- _fall: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0 },
6871
+ _peak: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
6872
+ _fall: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
6829
6873
  };
6830
6874
  // Sync open: if external system rejects — cancel scheduled signal instead of opening
6831
6875
  const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(activationTime, activatedSignal.priceOpen, activatedSignal, self);
@@ -6835,6 +6879,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
6835
6879
  signalId: scheduled.id,
6836
6880
  });
6837
6881
  await self.setScheduledSignal(null);
6882
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", scheduled, scheduled.priceOpen);
6838
6883
  await CALL_COMMIT_FN(self, {
6839
6884
  action: "cancel-scheduled",
6840
6885
  symbol: self.params.execution.context.symbol,
@@ -6847,7 +6892,10 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
6847
6892
  totalEntries: scheduled._entry?.length ?? 1,
6848
6893
  totalPartials: scheduled._partial?.length ?? 0,
6849
6894
  originalPriceOpen: scheduled.priceOpen,
6850
- pnl: toProfitLossDto(scheduled, scheduled.priceOpen),
6895
+ pnl: publicSignal.pnl,
6896
+ maxDrawdown: publicSignal.maxDrawdown,
6897
+ peakProfit: publicSignal.peakProfit,
6898
+ signal: publicSignal,
6851
6899
  note: scheduled.note,
6852
6900
  });
6853
6901
  return false;
@@ -6870,20 +6918,20 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
6870
6918
  });
6871
6919
  return null;
6872
6920
  }
6873
- const pnl = toProfitLossDto(signal, averagePrice);
6921
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
6874
6922
  self.params.logger.debug(`ClientStrategy backtest ${closeReason}`, {
6875
6923
  symbol: self.params.execution.context.symbol,
6876
6924
  signalId: signal.id,
6877
6925
  reason: closeReason,
6878
6926
  priceClose: averagePrice,
6879
6927
  closeTimestamp,
6880
- pnlPercentage: pnl.pnlPercentage,
6928
+ pnlPercentage: publicSignal.pnl.pnlPercentage,
6881
6929
  });
6882
6930
  if (closeReason === "stop_loss") {
6883
- self.params.logger.warn(`ClientStrategy backtest: Signal closed with loss (stop_loss), PNL: ${pnl.pnlPercentage.toFixed(2)}%`);
6931
+ self.params.logger.warn(`ClientStrategy backtest: Signal closed with loss (stop_loss), PNL: ${publicSignal.pnl.pnlPercentage.toFixed(2)}%`);
6884
6932
  }
6885
- if (closeReason === "time_expired" && pnl.pnlPercentage < 0) {
6886
- self.params.logger.warn(`ClientStrategy backtest: Signal closed with loss (time_expired), PNL: ${pnl.pnlPercentage.toFixed(2)}%`);
6933
+ if (closeReason === "time_expired" && publicSignal.pnl.pnlPercentage < 0) {
6934
+ self.params.logger.warn(`ClientStrategy backtest: Signal closed with loss (time_expired), PNL: ${publicSignal.pnl.pnlPercentage.toFixed(2)}%`);
6887
6935
  }
6888
6936
  await CALL_CLOSE_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
6889
6937
  // КРИТИЧНО: Очищаем состояние ClientPartial при закрытии позиции
@@ -6894,11 +6942,11 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
6894
6942
  await self.setPendingSignal(null);
6895
6943
  const result = {
6896
6944
  action: "closed",
6897
- signal: TO_PUBLIC_SIGNAL(signal, averagePrice),
6945
+ signal: publicSignal,
6898
6946
  currentPrice: averagePrice,
6899
6947
  closeReason: closeReason,
6900
6948
  closeTimestamp: closeTimestamp,
6901
- pnl: pnl,
6949
+ pnl: publicSignal.pnl,
6902
6950
  strategyName: self.params.method.context.strategyName,
6903
6951
  exchangeName: self.params.method.context.exchangeName,
6904
6952
  frameName: self.params.method.context.frameName,
@@ -6922,6 +6970,7 @@ const CLOSE_USER_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, closedSignal, aver
6922
6970
  `Retry backtest() with new candle data.`);
6923
6971
  }
6924
6972
  self._closedSignal = null;
6973
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", closedSignal, averagePrice);
6925
6974
  await CALL_COMMIT_FN(self, {
6926
6975
  action: "close-pending",
6927
6976
  symbol: self.params.execution.context.symbol,
@@ -6935,21 +6984,23 @@ const CLOSE_USER_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, closedSignal, aver
6935
6984
  totalEntries: closedSignal._entry?.length ?? 1,
6936
6985
  totalPartials: closedSignal._partial?.length ?? 0,
6937
6986
  originalPriceOpen: closedSignal.priceOpen,
6938
- pnl: toProfitLossDto(closedSignal, averagePrice),
6987
+ pnl: publicSignal.pnl,
6988
+ maxDrawdown: publicSignal.maxDrawdown,
6989
+ peakProfit: publicSignal.peakProfit,
6990
+ signal: publicSignal,
6939
6991
  note: closedSignal.closeNote ?? closedSignal.note,
6940
6992
  });
6941
6993
  await CALL_CLOSE_CALLBACKS_FN(self, self.params.execution.context.symbol, closedSignal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
6942
6994
  await CALL_PARTIAL_CLEAR_FN(self, self.params.execution.context.symbol, closedSignal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
6943
6995
  await CALL_BREAKEVEN_CLEAR_FN(self, self.params.execution.context.symbol, closedSignal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
6944
6996
  await CALL_RISK_REMOVE_SIGNAL_FN(self, self.params.execution.context.symbol, closeTimestamp, self.params.execution.context.backtest);
6945
- const pnl = toProfitLossDto(closedSignal, averagePrice);
6946
6997
  const result = {
6947
6998
  action: "closed",
6948
- signal: TO_PUBLIC_SIGNAL(closedSignal, averagePrice),
6999
+ signal: publicSignal,
6949
7000
  currentPrice: averagePrice,
6950
7001
  closeReason: "closed",
6951
7002
  closeTimestamp,
6952
- pnl,
7003
+ pnl: publicSignal.pnl,
6953
7004
  strategyName: self.params.method.context.strategyName,
6954
7005
  exchangeName: self.params.method.context.exchangeName,
6955
7006
  frameName: self.params.method.context.frameName,
@@ -7014,8 +7065,8 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
7014
7065
  ...activatedSignal,
7015
7066
  pendingAt: candle.timestamp,
7016
7067
  _isScheduled: false,
7017
- _peak: { price: activatedSignal.priceOpen, timestamp: candle.timestamp, pnlPercentage: 0, pnlCost: 0 },
7018
- _fall: { price: activatedSignal.priceOpen, timestamp: candle.timestamp, pnlPercentage: 0, pnlCost: 0 },
7068
+ _peak: { price: activatedSignal.priceOpen, timestamp: candle.timestamp, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
7069
+ _fall: { price: activatedSignal.priceOpen, timestamp: candle.timestamp, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
7019
7070
  };
7020
7071
  // Sync open: if external system rejects — cancel scheduled signal instead of opening
7021
7072
  const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(candle.timestamp, pendingSignal.priceOpen, pendingSignal, self);
@@ -7025,6 +7076,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
7025
7076
  signalId: activatedSignal.id,
7026
7077
  });
7027
7078
  await self.setScheduledSignal(null);
7079
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", activatedSignal, averagePrice);
7028
7080
  await CALL_COMMIT_FN(self, {
7029
7081
  action: "cancel-scheduled",
7030
7082
  symbol: self.params.execution.context.symbol,
@@ -7037,7 +7089,10 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
7037
7089
  totalEntries: activatedSignal._entry?.length ?? 1,
7038
7090
  totalPartials: activatedSignal._partial?.length ?? 0,
7039
7091
  originalPriceOpen: activatedSignal.priceOpen,
7040
- pnl: toProfitLossDto(activatedSignal, averagePrice),
7092
+ pnl: publicSignal.pnl,
7093
+ maxDrawdown: publicSignal.maxDrawdown,
7094
+ peakProfit: publicSignal.peakProfit,
7095
+ signal: publicSignal,
7041
7096
  note: activatedSignal.activateNote ?? activatedSignal.note,
7042
7097
  });
7043
7098
  return { outcome: "pending" };
@@ -7046,7 +7101,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
7046
7101
  await self.setPendingSignal(pendingSignal);
7047
7102
  await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, pendingSignal, candle.timestamp, self.params.execution.context.backtest);
7048
7103
  // Emit commit AFTER successful risk check
7049
- const publicSignalForCommit = TO_PUBLIC_SIGNAL(pendingSignal, averagePrice);
7104
+ const publicSignalForCommit = TO_PUBLIC_SIGNAL("pending", pendingSignal, averagePrice);
7050
7105
  await CALL_COMMIT_FN(self, {
7051
7106
  action: "activate-scheduled",
7052
7107
  symbol: self.params.execution.context.symbol,
@@ -7058,7 +7113,10 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
7058
7113
  activateId: activatedSignal.activateId,
7059
7114
  timestamp: candle.timestamp,
7060
7115
  currentPrice: averagePrice,
7061
- pnl: toProfitLossDto(pendingSignal, averagePrice),
7116
+ pnl: publicSignalForCommit.pnl,
7117
+ maxDrawdown: publicSignalForCommit.maxDrawdown,
7118
+ peakProfit: publicSignalForCommit.peakProfit,
7119
+ signal: publicSignalForCommit,
7062
7120
  position: publicSignalForCommit.position,
7063
7121
  priceOpen: publicSignalForCommit.priceOpen,
7064
7122
  priceTakeProfit: publicSignalForCommit.priceTakeProfit,
@@ -7159,7 +7217,6 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
7159
7217
  if (self._closedSignal) {
7160
7218
  return await CLOSE_USER_PENDING_SIGNAL_IN_BACKTEST_FN(self, self._closedSignal, averagePrice, currentCandleTimestamp);
7161
7219
  }
7162
- await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true, averagePrice);
7163
7220
  let shouldClose = false;
7164
7221
  let closeReason;
7165
7222
  // Check time expiration FIRST (КРИТИЧНО!)
@@ -7218,23 +7275,21 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
7218
7275
  if (signal.position === "long") {
7219
7276
  // For long: calculate progress towards TP or SL
7220
7277
  const currentDistance = averagePrice - effectivePriceOpen;
7221
- if (currentDistance > 0) {
7222
- // Check if breakeven should be triggered
7223
- await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, averagePrice, currentCandleTimestamp, self.params.execution.context.backtest);
7224
- }
7225
7278
  if (currentDistance > 0) {
7226
7279
  // Moving towards TP (use trailing TP if set)
7227
7280
  const effectiveTakeProfit = signal._trailingPriceTakeProfit ?? signal.priceTakeProfit;
7228
7281
  const tpDistance = effectiveTakeProfit - effectivePriceOpen;
7229
7282
  const progressPercent = (currentDistance / tpDistance) * 100;
7230
7283
  if (averagePrice > signal._peak.price) {
7231
- const { pnl } = TO_PUBLIC_SIGNAL(signal, averagePrice);
7232
- signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
7284
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
7285
+ signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
7233
7286
  if (self.params.callbacks?.onWrite) {
7234
7287
  self.params.callbacks.onWrite(signal.symbol, signal, true);
7235
7288
  }
7236
- await self.params.onHighestProfit(TO_PUBLIC_SIGNAL(signal, averagePrice), averagePrice, currentCandleTimestamp);
7289
+ await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
7237
7290
  }
7291
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true, averagePrice);
7292
+ await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, averagePrice, currentCandleTimestamp, self.params.execution.context.backtest);
7238
7293
  await CALL_PARTIAL_PROFIT_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, averagePrice, Math.min(progressPercent, 100), currentCandleTimestamp, self.params.execution.context.backtest);
7239
7294
  }
7240
7295
  else if (currentDistance < 0) {
@@ -7243,53 +7298,59 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
7243
7298
  const slDistance = effectivePriceOpen - effectiveStopLoss;
7244
7299
  const progressPercent = (Math.abs(currentDistance) / slDistance) * 100;
7245
7300
  if (averagePrice < signal._fall.price) {
7246
- const { pnl } = TO_PUBLIC_SIGNAL(signal, averagePrice);
7247
- signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
7301
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
7302
+ signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
7248
7303
  if (self.params.callbacks?.onWrite) {
7249
7304
  self.params.callbacks.onWrite(signal.symbol, signal, true);
7250
7305
  }
7251
- await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL(signal, averagePrice), averagePrice, currentCandleTimestamp);
7306
+ await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
7252
7307
  }
7308
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true, averagePrice);
7253
7309
  await CALL_PARTIAL_LOSS_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, averagePrice, Math.min(progressPercent, 100), currentCandleTimestamp, self.params.execution.context.backtest);
7254
7310
  }
7311
+ else {
7312
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true, averagePrice);
7313
+ }
7255
7314
  }
7256
7315
  else if (signal.position === "short") {
7257
7316
  // For short: calculate progress towards TP or SL
7258
7317
  const currentDistance = effectivePriceOpen - averagePrice;
7259
- if (currentDistance > 0) {
7260
- // Check if breakeven should be triggered
7261
- await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, averagePrice, currentCandleTimestamp, self.params.execution.context.backtest);
7262
- }
7263
7318
  if (currentDistance > 0) {
7264
7319
  // Moving towards TP (use trailing TP if set)
7265
7320
  const effectiveTakeProfit = signal._trailingPriceTakeProfit ?? signal.priceTakeProfit;
7266
7321
  const tpDistance = effectivePriceOpen - effectiveTakeProfit;
7267
7322
  const progressPercent = (currentDistance / tpDistance) * 100;
7268
7323
  if (averagePrice < signal._peak.price) {
7269
- const { pnl } = TO_PUBLIC_SIGNAL(signal, averagePrice);
7270
- signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
7324
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
7325
+ signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
7271
7326
  if (self.params.callbacks?.onWrite) {
7272
7327
  self.params.callbacks.onWrite(signal.symbol, signal, true);
7273
7328
  }
7274
- await self.params.onHighestProfit(TO_PUBLIC_SIGNAL(signal, averagePrice), averagePrice, currentCandleTimestamp);
7329
+ await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
7275
7330
  }
7331
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true, averagePrice);
7332
+ await CALL_BREAKEVEN_CHECK_FN(self, self.params.execution.context.symbol, signal, averagePrice, currentCandleTimestamp, self.params.execution.context.backtest);
7276
7333
  await CALL_PARTIAL_PROFIT_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, averagePrice, Math.min(progressPercent, 100), currentCandleTimestamp, self.params.execution.context.backtest);
7277
7334
  }
7278
- if (currentDistance < 0) {
7335
+ else if (currentDistance < 0) {
7279
7336
  // Moving towards SL (use trailing SL if set)
7280
7337
  const effectiveStopLoss = signal._trailingPriceStopLoss ?? signal.priceStopLoss;
7281
7338
  const slDistance = effectiveStopLoss - effectivePriceOpen;
7282
7339
  const progressPercent = (Math.abs(currentDistance) / slDistance) * 100;
7283
7340
  if (averagePrice > signal._fall.price) {
7284
- const { pnl } = TO_PUBLIC_SIGNAL(signal, averagePrice);
7285
- signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage };
7341
+ const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
7342
+ signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
7286
7343
  if (self.params.callbacks?.onWrite) {
7287
7344
  self.params.callbacks.onWrite(signal.symbol, signal, true);
7288
7345
  }
7289
- await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL(signal, averagePrice), averagePrice, currentCandleTimestamp);
7346
+ await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
7290
7347
  }
7348
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true, averagePrice);
7291
7349
  await CALL_PARTIAL_LOSS_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, averagePrice, Math.min(progressPercent, 100), currentCandleTimestamp, self.params.execution.context.backtest);
7292
7350
  }
7351
+ else {
7352
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true, averagePrice);
7353
+ }
7293
7354
  }
7294
7355
  }
7295
7356
  // Process queued commit events with candle timestamp
@@ -7300,9 +7361,10 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
7300
7361
  const lastPrice = GET_AVG_PRICE_FN(lastCandles);
7301
7362
  const closeTimestamp = lastCandles[lastCandles.length - 1].timestamp;
7302
7363
  if (signal.minuteEstimatedTime === Infinity) {
7364
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, lastPrice);
7303
7365
  const result = {
7304
7366
  action: "active",
7305
- signal: TO_PUBLIC_SIGNAL(signal, lastPrice),
7367
+ signal: publicSignal,
7306
7368
  currentPrice: lastPrice,
7307
7369
  strategyName: self.params.method.context.strategyName,
7308
7370
  exchangeName: self.params.method.context.exchangeName,
@@ -7310,7 +7372,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
7310
7372
  symbol: self.params.execution.context.symbol,
7311
7373
  percentTp: 0,
7312
7374
  percentSl: 0,
7313
- pnl: toProfitLossDto(signal, lastPrice),
7375
+ pnl: publicSignal.pnl,
7314
7376
  backtest: self.params.execution.context.backtest,
7315
7377
  createdAt: closeTimestamp,
7316
7378
  _backtestLastTimestamp: closeTimestamp,
@@ -7493,7 +7555,7 @@ class ClientStrategy {
7493
7555
  this.params.logger.debug("ClientStrategy getPendingSignal", {
7494
7556
  symbol,
7495
7557
  });
7496
- return this._pendingSignal ? TO_PUBLIC_SIGNAL(this._pendingSignal, currentPrice) : null;
7558
+ return this._pendingSignal ? TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice) : null;
7497
7559
  }
7498
7560
  /**
7499
7561
  * Retrieves the current scheduled signal.
@@ -7504,7 +7566,7 @@ class ClientStrategy {
7504
7566
  this.params.logger.debug("ClientStrategy getScheduledSignal", {
7505
7567
  symbol,
7506
7568
  });
7507
- return this._scheduledSignal ? TO_PUBLIC_SIGNAL(this._scheduledSignal, currentPrice) : null;
7569
+ return this._scheduledSignal ? TO_PUBLIC_SIGNAL("scheduled", this._scheduledSignal, currentPrice) : null;
7508
7570
  }
7509
7571
  /**
7510
7572
  * Checks if breakeven threshold has been reached for the current pending signal.
@@ -8313,6 +8375,7 @@ class ClientStrategy {
8313
8375
  signalId: cancelledSignal.id,
8314
8376
  });
8315
8377
  // Emit commit with correct timestamp from tick context
8378
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", cancelledSignal, currentPrice);
8316
8379
  await CALL_COMMIT_FN(this, {
8317
8380
  action: "cancel-scheduled",
8318
8381
  symbol: this.params.execution.context.symbol,
@@ -8326,14 +8389,17 @@ class ClientStrategy {
8326
8389
  totalEntries: cancelledSignal._entry?.length ?? 1,
8327
8390
  totalPartials: cancelledSignal._partial?.length ?? 0,
8328
8391
  originalPriceOpen: cancelledSignal.priceOpen,
8329
- pnl: toProfitLossDto(cancelledSignal, currentPrice),
8392
+ pnl: publicSignal.pnl,
8393
+ maxDrawdown: publicSignal.maxDrawdown,
8394
+ peakProfit: publicSignal.peakProfit,
8395
+ signal: publicSignal,
8330
8396
  note: cancelledSignal.cancelNote ?? cancelledSignal.note,
8331
8397
  });
8332
8398
  // Call onCancel callback
8333
8399
  await CALL_CANCEL_CALLBACKS_FN(this, this.params.execution.context.symbol, cancelledSignal, currentPrice, currentTime, this.params.execution.context.backtest);
8334
8400
  const result = {
8335
8401
  action: "cancelled",
8336
- signal: TO_PUBLIC_SIGNAL(cancelledSignal, currentPrice),
8402
+ signal: publicSignal,
8337
8403
  currentPrice,
8338
8404
  closeTimestamp: currentTime,
8339
8405
  strategyName: this.params.method.context.strategyName,
@@ -8367,6 +8433,7 @@ class ClientStrategy {
8367
8433
  signalId: closedSignal.id,
8368
8434
  });
8369
8435
  // Emit commit with correct timestamp from tick context
8436
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", closedSignal, currentPrice);
8370
8437
  await CALL_COMMIT_FN(this, {
8371
8438
  action: "close-pending",
8372
8439
  symbol: this.params.execution.context.symbol,
@@ -8380,7 +8447,10 @@ class ClientStrategy {
8380
8447
  totalEntries: closedSignal._entry?.length ?? 1,
8381
8448
  totalPartials: closedSignal._partial?.length ?? 0,
8382
8449
  originalPriceOpen: closedSignal.priceOpen,
8383
- pnl: toProfitLossDto(closedSignal, currentPrice),
8450
+ pnl: publicSignal.pnl,
8451
+ maxDrawdown: publicSignal.maxDrawdown,
8452
+ peakProfit: publicSignal.peakProfit,
8453
+ signal: publicSignal,
8384
8454
  note: closedSignal.closeNote ?? closedSignal.note,
8385
8455
  });
8386
8456
  // Call onClose callback
@@ -8390,14 +8460,13 @@ class ClientStrategy {
8390
8460
  // КРИТИЧНО: Очищаем состояние ClientBreakeven при закрытии позиции
8391
8461
  await CALL_BREAKEVEN_CLEAR_FN(this, this.params.execution.context.symbol, closedSignal, currentPrice, currentTime, this.params.execution.context.backtest);
8392
8462
  await CALL_RISK_REMOVE_SIGNAL_FN(this, this.params.execution.context.symbol, currentTime, this.params.execution.context.backtest);
8393
- const pnl = toProfitLossDto(closedSignal, currentPrice);
8394
8463
  const result = {
8395
8464
  action: "closed",
8396
- signal: TO_PUBLIC_SIGNAL(closedSignal, currentPrice),
8465
+ signal: publicSignal,
8397
8466
  currentPrice,
8398
8467
  closeReason: "closed",
8399
8468
  closeTimestamp: currentTime,
8400
- pnl,
8469
+ pnl: publicSignal.pnl,
8401
8470
  strategyName: this.params.method.context.strategyName,
8402
8471
  exchangeName: this.params.method.context.exchangeName,
8403
8472
  frameName: this.params.method.context.frameName,
@@ -8440,8 +8509,8 @@ class ClientStrategy {
8440
8509
  ...activatedSignal,
8441
8510
  pendingAt: currentTime,
8442
8511
  _isScheduled: false,
8443
- _peak: { price: activatedSignal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
8444
- _fall: { price: activatedSignal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0 },
8512
+ _peak: { price: activatedSignal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, pnlEntries: 0, priceOpen: 0 },
8513
+ _fall: { price: activatedSignal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, pnlEntries: 0, priceOpen: 0 },
8445
8514
  };
8446
8515
  const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(currentTime, currentPrice, pendingSignal, this);
8447
8516
  if (!syncOpenAllowed) {
@@ -8450,6 +8519,7 @@ class ClientStrategy {
8450
8519
  signalId: activatedSignal.id,
8451
8520
  });
8452
8521
  await this.setScheduledSignal(null);
8522
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", activatedSignal, currentPrice);
8453
8523
  await CALL_COMMIT_FN(this, {
8454
8524
  action: "cancel-scheduled",
8455
8525
  symbol: this.params.execution.context.symbol,
@@ -8462,7 +8532,10 @@ class ClientStrategy {
8462
8532
  totalEntries: activatedSignal._entry?.length ?? 1,
8463
8533
  totalPartials: activatedSignal._partial?.length ?? 0,
8464
8534
  originalPriceOpen: activatedSignal.priceOpen,
8465
- pnl: toProfitLossDto(activatedSignal, currentPrice),
8535
+ pnl: publicSignal.pnl,
8536
+ maxDrawdown: publicSignal.maxDrawdown,
8537
+ peakProfit: publicSignal.peakProfit,
8538
+ signal: publicSignal,
8466
8539
  note: activatedSignal.activateNote ?? activatedSignal.note,
8467
8540
  });
8468
8541
  return await RETURN_IDLE_FN(this, currentPrice);
@@ -8470,7 +8543,7 @@ class ClientStrategy {
8470
8543
  await this.setPendingSignal(pendingSignal);
8471
8544
  await CALL_RISK_ADD_SIGNAL_FN(this, this.params.execution.context.symbol, pendingSignal, currentTime, this.params.execution.context.backtest);
8472
8545
  // Emit commit AFTER successful risk check
8473
- const publicSignalForCommit = TO_PUBLIC_SIGNAL(pendingSignal, currentPrice);
8546
+ const publicSignalForCommit = TO_PUBLIC_SIGNAL("pending", pendingSignal, currentPrice);
8474
8547
  await CALL_COMMIT_FN(this, {
8475
8548
  action: "activate-scheduled",
8476
8549
  symbol: this.params.execution.context.symbol,
@@ -8482,7 +8555,10 @@ class ClientStrategy {
8482
8555
  activateId: activatedSignal.activateId,
8483
8556
  timestamp: currentTime,
8484
8557
  currentPrice,
8485
- pnl: toProfitLossDto(pendingSignal, currentPrice),
8558
+ pnl: publicSignalForCommit.pnl,
8559
+ maxDrawdown: publicSignalForCommit.maxDrawdown,
8560
+ peakProfit: publicSignalForCommit.peakProfit,
8561
+ signal: publicSignalForCommit,
8486
8562
  position: publicSignalForCommit.position,
8487
8563
  priceOpen: publicSignalForCommit.priceOpen,
8488
8564
  priceTakeProfit: publicSignalForCommit.priceTakeProfit,
@@ -8500,7 +8576,7 @@ class ClientStrategy {
8500
8576
  await CALL_OPEN_CALLBACKS_FN(this, this.params.execution.context.symbol, pendingSignal, currentPrice, currentTime, this.params.execution.context.backtest);
8501
8577
  const result = {
8502
8578
  action: "opened",
8503
- signal: TO_PUBLIC_SIGNAL(pendingSignal, currentPrice),
8579
+ signal: publicSignalForCommit,
8504
8580
  strategyName: this.params.method.context.strategyName,
8505
8581
  exchangeName: this.params.method.context.exchangeName,
8506
8582
  frameName: this.params.method.context.frameName,
@@ -8616,6 +8692,7 @@ class ClientStrategy {
8616
8692
  this._cancelledSignal = null; // Clear after using
8617
8693
  const closeTimestamp = this.params.execution.context.when.getTime();
8618
8694
  // Emit commit with correct timestamp from backtest context
8695
+ const publicSignal = TO_PUBLIC_SIGNAL("scheduled", cancelledSignal, currentPrice);
8619
8696
  await CALL_COMMIT_FN(this, {
8620
8697
  action: "cancel-scheduled",
8621
8698
  symbol: this.params.execution.context.symbol,
@@ -8629,13 +8706,16 @@ class ClientStrategy {
8629
8706
  totalEntries: cancelledSignal._entry?.length ?? 1,
8630
8707
  totalPartials: cancelledSignal._partial?.length ?? 0,
8631
8708
  originalPriceOpen: cancelledSignal.priceOpen,
8632
- pnl: toProfitLossDto(cancelledSignal, currentPrice),
8709
+ pnl: publicSignal.pnl,
8710
+ maxDrawdown: publicSignal.maxDrawdown,
8711
+ peakProfit: publicSignal.peakProfit,
8712
+ signal: publicSignal,
8633
8713
  note: cancelledSignal.cancelNote ?? cancelledSignal.note,
8634
8714
  });
8635
8715
  await CALL_CANCEL_CALLBACKS_FN(this, this.params.execution.context.symbol, cancelledSignal, currentPrice, closeTimestamp, this.params.execution.context.backtest);
8636
8716
  const cancelledResult = {
8637
8717
  action: "cancelled",
8638
- signal: TO_PUBLIC_SIGNAL(cancelledSignal, currentPrice),
8718
+ signal: publicSignal,
8639
8719
  currentPrice,
8640
8720
  closeTimestamp: closeTimestamp,
8641
8721
  strategyName: this.params.method.context.strategyName,
@@ -8671,6 +8751,7 @@ class ClientStrategy {
8671
8751
  }
8672
8752
  this._closedSignal = null; // Clear only after sync confirmed
8673
8753
  // Emit commit with correct timestamp from backtest context
8754
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", closedSignal, currentPrice);
8674
8755
  await CALL_COMMIT_FN(this, {
8675
8756
  action: "close-pending",
8676
8757
  symbol: this.params.execution.context.symbol,
@@ -8684,7 +8765,10 @@ class ClientStrategy {
8684
8765
  totalEntries: closedSignal._entry?.length ?? 1,
8685
8766
  totalPartials: closedSignal._partial?.length ?? 0,
8686
8767
  originalPriceOpen: closedSignal.priceOpen,
8687
- pnl: toProfitLossDto(closedSignal, currentPrice),
8768
+ pnl: publicSignal.pnl,
8769
+ maxDrawdown: publicSignal.maxDrawdown,
8770
+ peakProfit: publicSignal.peakProfit,
8771
+ signal: publicSignal,
8688
8772
  note: closedSignal.closeNote ?? closedSignal.note,
8689
8773
  });
8690
8774
  await CALL_CLOSE_CALLBACKS_FN(this, this.params.execution.context.symbol, closedSignal, currentPrice, closeTimestamp, this.params.execution.context.backtest);
@@ -8693,14 +8777,13 @@ class ClientStrategy {
8693
8777
  // КРИТИЧНО: Очищаем состояние ClientBreakeven при закрытии позиции
8694
8778
  await CALL_BREAKEVEN_CLEAR_FN(this, this.params.execution.context.symbol, closedSignal, currentPrice, closeTimestamp, this.params.execution.context.backtest);
8695
8779
  await CALL_RISK_REMOVE_SIGNAL_FN(this, this.params.execution.context.symbol, closeTimestamp, this.params.execution.context.backtest);
8696
- const pnl = toProfitLossDto(closedSignal, currentPrice);
8697
8780
  const closedResult = {
8698
8781
  action: "closed",
8699
- signal: TO_PUBLIC_SIGNAL(closedSignal, currentPrice),
8782
+ signal: publicSignal,
8700
8783
  currentPrice,
8701
8784
  closeReason: "closed",
8702
8785
  closeTimestamp: closeTimestamp,
8703
- pnl,
8786
+ pnl: publicSignal.pnl,
8704
8787
  strategyName: this.params.method.context.strategyName,
8705
8788
  exchangeName: this.params.method.context.exchangeName,
8706
8789
  frameName: this.params.method.context.frameName,
@@ -9156,7 +9239,7 @@ class ClientStrategy {
9156
9239
  });
9157
9240
  // Call onWrite callback for testing persist storage
9158
9241
  if (this.params.callbacks?.onWrite) {
9159
- this.params.callbacks.onWrite(this.params.execution.context.symbol, TO_PUBLIC_SIGNAL(this._pendingSignal, currentPrice), backtest);
9242
+ this.params.callbacks.onWrite(this.params.execution.context.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
9160
9243
  }
9161
9244
  if (!backtest) {
9162
9245
  await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.execution.context.symbol, this.params.strategyName, this.params.exchangeName);
@@ -9339,7 +9422,7 @@ class ClientStrategy {
9339
9422
  });
9340
9423
  // Call onWrite callback for testing persist storage
9341
9424
  if (this.params.callbacks?.onWrite) {
9342
- this.params.callbacks.onWrite(this.params.execution.context.symbol, TO_PUBLIC_SIGNAL(this._pendingSignal, currentPrice), backtest);
9425
+ this.params.callbacks.onWrite(this.params.execution.context.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
9343
9426
  }
9344
9427
  if (!backtest) {
9345
9428
  await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.execution.context.symbol, this.params.strategyName, this.params.exchangeName);
@@ -9537,7 +9620,7 @@ class ClientStrategy {
9537
9620
  });
9538
9621
  // Call onWrite callback for testing persist storage
9539
9622
  if (this.params.callbacks?.onWrite) {
9540
- const publicSignal = TO_PUBLIC_SIGNAL(this._pendingSignal, currentPrice);
9623
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
9541
9624
  this.params.callbacks.onWrite(this.params.execution.context.symbol, publicSignal, backtest);
9542
9625
  }
9543
9626
  if (!backtest) {
@@ -9786,7 +9869,7 @@ class ClientStrategy {
9786
9869
  });
9787
9870
  // Call onWrite callback for testing persist storage
9788
9871
  if (this.params.callbacks?.onWrite) {
9789
- const publicSignal = TO_PUBLIC_SIGNAL(this._pendingSignal, currentPrice);
9872
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
9790
9873
  this.params.callbacks.onWrite(this.params.execution.context.symbol, publicSignal, backtest);
9791
9874
  }
9792
9875
  if (!backtest) {
@@ -10022,7 +10105,7 @@ class ClientStrategy {
10022
10105
  });
10023
10106
  // Call onWrite callback for testing persist storage
10024
10107
  if (this.params.callbacks?.onWrite) {
10025
- const publicSignal = TO_PUBLIC_SIGNAL(this._pendingSignal, currentPrice);
10108
+ const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
10026
10109
  this.params.callbacks.onWrite(this.params.execution.context.symbol, publicSignal, backtest);
10027
10110
  }
10028
10111
  if (!backtest) {
@@ -10114,7 +10197,7 @@ class ClientStrategy {
10114
10197
  });
10115
10198
  // Call onWrite callback for testing persist storage
10116
10199
  if (this.params.callbacks?.onWrite) {
10117
- this.params.callbacks.onWrite(this.params.execution.context.symbol, TO_PUBLIC_SIGNAL(this._pendingSignal, currentPrice), backtest);
10200
+ this.params.callbacks.onWrite(this.params.execution.context.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
10118
10201
  }
10119
10202
  if (!backtest) {
10120
10203
  await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.execution.context.symbol, this.params.strategyName, this.params.exchangeName);
@@ -12485,12 +12568,15 @@ const alignToInterval = (date, interval) => {
12485
12568
 
12486
12569
  /** Symbol indicating that positions need to be fetched from persistence */
12487
12570
  const POSITION_NEED_FETCH = Symbol("risk-need-fetch");
12571
+ /** Get timestamp from execution context or fallback to aligned current time */
12488
12572
  const GET_CONTEXT_TIMESTAMP_FN = (self) => {
12489
12573
  if (ExecutionContextService.hasContext()) {
12490
12574
  return self.params.execution.context.when.getTime();
12491
12575
  }
12492
12576
  return alignToInterval(new Date(), "1m").getTime();
12493
12577
  };
12578
+ /** Zero PNL constant for scheduled signals (which don't have priceOpen or PNL yet) */
12579
+ const ZERO_PNL = { pnlPercentage: 0, priceOpen: 0, priceClose: 0, pnlCost: 0, pnlEntries: 0 };
12494
12580
  /**
12495
12581
  * Converts signal to risk validation format.
12496
12582
  *
@@ -12533,6 +12619,9 @@ const TO_RISK_SIGNAL = (signal, currentPrice, timestamp) => {
12533
12619
  const partialExecuted = ("_partial" in signal && Array.isArray(signal._partial))
12534
12620
  ? signal._partial.reduce((sum, partial) => sum + partial.percent, 0)
12535
12621
  : 0;
12622
+ const pnl = signal._isScheduled ? ZERO_PNL : toProfitLossDto(signal, currentPrice);
12623
+ const maxDrawdown = signal._isScheduled ? ZERO_PNL : pnl;
12624
+ const peakProfit = signal._isScheduled ? ZERO_PNL : pnl;
12536
12625
  return {
12537
12626
  ...structuredClone(signal),
12538
12627
  cost: signal.cost || GLOBAL_CONFIG.CC_POSITION_ENTRY_COST,
@@ -12546,7 +12635,9 @@ const TO_RISK_SIGNAL = (signal, currentPrice, timestamp) => {
12546
12635
  originalPriceTakeProfit: signal.priceTakeProfit,
12547
12636
  originalPriceOpen: signal.priceOpen ?? currentPrice,
12548
12637
  partialExecuted,
12549
- pnl: toProfitLossDto(signal, currentPrice),
12638
+ pnl,
12639
+ maxDrawdown,
12640
+ peakProfit,
12550
12641
  };
12551
12642
  };
12552
12643
  /** Key generator for active position map */
@@ -18816,7 +18907,9 @@ const backtest_columns = [
18816
18907
  key: "peakPnl",
18817
18908
  label: "Peak PNL",
18818
18909
  format: (data) => {
18819
- const v = data.signal._peak?.pnlPercentage;
18910
+ const v = data.signal.peakProfit?.pnlPercentage;
18911
+ if (v === undefined)
18912
+ return "N/A";
18820
18913
  return `${v > 0 ? "+" : ""}${v.toFixed(2)}%`;
18821
18914
  },
18822
18915
  isVisible: () => true,
@@ -18824,7 +18917,12 @@ const backtest_columns = [
18824
18917
  {
18825
18918
  key: "fallPnl",
18826
18919
  label: "Max DD PNL",
18827
- format: (data) => `${data.signal._fall?.pnlPercentage.toFixed(2)}%`,
18920
+ format: (data) => {
18921
+ const v = data.signal.maxDrawdown?.pnlPercentage;
18922
+ if (v === undefined)
18923
+ return "N/A";
18924
+ return `${v.toFixed(2)}%`;
18925
+ },
18828
18926
  isVisible: () => true,
18829
18927
  },
18830
18928
  ];
@@ -21385,8 +21483,8 @@ let ReportStorage$a = class ReportStorage {
21385
21483
  const tradesPerYear = avgDurationDays > 0 ? 365 / avgDurationDays : 0;
21386
21484
  const expectedYearlyReturns = avgPnl * tradesPerYear;
21387
21485
  // Calculate average peak and fall PNL across all signals
21388
- const avgPeakPnl = this._signalList.reduce((sum, s) => sum + (s.signal._peak?.pnlPercentage ?? 0), 0) / totalSignals;
21389
- const avgFallPnl = this._signalList.reduce((sum, s) => sum + (s.signal._fall?.pnlPercentage ?? 0), 0) / totalSignals;
21486
+ const avgPeakPnl = this._signalList.reduce((sum, s) => sum + (s.signal.peakProfit?.pnlPercentage ?? 0), 0) / totalSignals;
21487
+ const avgFallPnl = this._signalList.reduce((sum, s) => sum + (s.signal.maxDrawdown?.pnlPercentage ?? 0), 0) / totalSignals;
21390
21488
  return {
21391
21489
  signalList: this._signalList,
21392
21490
  totalSignals,
@@ -21915,8 +22013,8 @@ let ReportStorage$9 = class ReportStorage {
21915
22013
  duration: durationMin,
21916
22014
  pendingAt: data.signal.pendingAt,
21917
22015
  scheduledAt: data.signal.scheduledAt,
21918
- peakPnl: data.signal._peak?.pnlPercentage,
21919
- fallPnl: data.signal._fall?.pnlPercentage,
22016
+ peakPnl: data.signal.peakProfit?.pnlPercentage,
22017
+ fallPnl: data.signal.maxDrawdown?.pnlPercentage,
21920
22018
  };
21921
22019
  this._eventList.unshift(newEvent);
21922
22020
  // Trim queue if exceeded GLOBAL_CONFIG.CC_MAX_LIVE_MARKDOWN_ROWS
@@ -24067,8 +24165,8 @@ class HeatmapStorage {
24067
24165
  let avgPeakPnl = null;
24068
24166
  let avgFallPnl = null;
24069
24167
  if (signals.length > 0) {
24070
- avgPeakPnl = signals.reduce((acc, s) => acc + (s.signal._peak?.pnlPercentage ?? 0), 0) / signals.length;
24071
- avgFallPnl = signals.reduce((acc, s) => acc + (s.signal._fall?.pnlPercentage ?? 0), 0) / signals.length;
24168
+ avgPeakPnl = signals.reduce((acc, s) => acc + (s.signal.peakProfit?.pnlPercentage ?? 0), 0) / signals.length;
24169
+ avgFallPnl = signals.reduce((acc, s) => acc + (s.signal.maxDrawdown?.pnlPercentage ?? 0), 0) / signals.length;
24072
24170
  }
24073
24171
  // Apply safe math checks
24074
24172
  if (isUnsafe(winRate))
@@ -28195,8 +28293,16 @@ class BacktestReportService {
28195
28293
  pnlPriceClose: data.pnl.priceClose,
28196
28294
  totalPartials: data.signal?.totalPartials,
28197
28295
  cost: data.signal?.cost,
28198
- peakPnl: data.signal?._peak?.pnlPercentage,
28199
- fallPnl: data.signal?._fall?.pnlPercentage,
28296
+ peakProfitPriceOpen: data.signal?.peakProfit?.priceOpen,
28297
+ peakProfitPriceClose: data.signal?.peakProfit?.priceClose,
28298
+ peakProfitPercentage: data.signal?.peakProfit?.pnlPercentage,
28299
+ peakProfitCost: data.signal?.peakProfit?.pnlCost,
28300
+ peakProfitEntries: data.signal?.peakProfit?.pnlEntries,
28301
+ maxDrawdownPriceOpen: data.signal?.maxDrawdown?.priceOpen,
28302
+ maxDrawdownPriceClose: data.signal?.maxDrawdown?.priceClose,
28303
+ maxDrawdownPercentage: data.signal?.maxDrawdown?.pnlPercentage,
28304
+ maxDrawdownCost: data.signal?.maxDrawdown?.pnlCost,
28305
+ maxDrawdownEntries: data.signal?.maxDrawdown?.pnlEntries,
28200
28306
  }, { ...searchOptions, signalId: data.signal?.id });
28201
28307
  }
28202
28308
  else if (data.action === "closed") {
@@ -28229,8 +28335,16 @@ class BacktestReportService {
28229
28335
  closeReason: data.closeReason,
28230
28336
  closeTime: data.closeTimestamp,
28231
28337
  duration: durationMin,
28232
- peakPnl: data.signal?._peak?.pnlPercentage,
28233
- fallPnl: data.signal?._fall?.pnlPercentage,
28338
+ peakProfitPriceOpen: data.signal?.peakProfit?.priceOpen,
28339
+ peakProfitPriceClose: data.signal?.peakProfit?.priceClose,
28340
+ peakProfitPercentage: data.signal?.peakProfit?.pnlPercentage,
28341
+ peakProfitCost: data.signal?.peakProfit?.pnlCost,
28342
+ peakProfitEntries: data.signal?.peakProfit?.pnlEntries,
28343
+ maxDrawdownPriceOpen: data.signal?.maxDrawdown?.priceOpen,
28344
+ maxDrawdownPriceClose: data.signal?.maxDrawdown?.priceClose,
28345
+ maxDrawdownPercentage: data.signal?.maxDrawdown?.pnlPercentage,
28346
+ maxDrawdownCost: data.signal?.maxDrawdown?.pnlCost,
28347
+ maxDrawdownEntries: data.signal?.maxDrawdown?.pnlEntries,
28234
28348
  }, { ...searchOptions, signalId: data.signal?.id });
28235
28349
  }
28236
28350
  };
@@ -28393,8 +28507,16 @@ class LiveReportService {
28393
28507
  pnlPriceClose: data.pnl.priceClose,
28394
28508
  totalPartials: data.signal?.totalPartials,
28395
28509
  cost: data.signal?.cost,
28396
- peakPnl: data.signal?._peak?.pnlPercentage,
28397
- fallPnl: data.signal?._fall?.pnlPercentage,
28510
+ peakProfitPriceOpen: data.signal?.peakProfit?.priceOpen,
28511
+ peakProfitPriceClose: data.signal?.peakProfit?.priceClose,
28512
+ peakProfitPercentage: data.signal?.peakProfit?.pnlPercentage,
28513
+ peakProfitCost: data.signal?.peakProfit?.pnlCost,
28514
+ peakProfitEntries: data.signal?.peakProfit?.pnlEntries,
28515
+ maxDrawdownPriceOpen: data.signal?.maxDrawdown?.priceOpen,
28516
+ maxDrawdownPriceClose: data.signal?.maxDrawdown?.priceClose,
28517
+ maxDrawdownPercentage: data.signal?.maxDrawdown?.pnlPercentage,
28518
+ maxDrawdownCost: data.signal?.maxDrawdown?.pnlCost,
28519
+ maxDrawdownEntries: data.signal?.maxDrawdown?.pnlEntries,
28398
28520
  }, { ...searchOptions, signalId: data.signal?.id });
28399
28521
  }
28400
28522
  else if (data.action === "opened") {
@@ -28445,8 +28567,16 @@ class LiveReportService {
28445
28567
  pnlPriceClose: data.pnl.priceClose,
28446
28568
  totalPartials: data.signal?.totalPartials,
28447
28569
  cost: data.signal?.cost,
28448
- peakPnl: data.signal?._peak?.pnlPercentage,
28449
- fallPnl: data.signal?._fall?.pnlPercentage,
28570
+ peakProfitPriceOpen: data.signal?.peakProfit?.priceOpen,
28571
+ peakProfitPriceClose: data.signal?.peakProfit?.priceClose,
28572
+ peakProfitPercentage: data.signal?.peakProfit?.pnlPercentage,
28573
+ peakProfitCost: data.signal?.peakProfit?.pnlCost,
28574
+ peakProfitEntries: data.signal?.peakProfit?.pnlEntries,
28575
+ maxDrawdownPriceOpen: data.signal?.maxDrawdown?.priceOpen,
28576
+ maxDrawdownPriceClose: data.signal?.maxDrawdown?.priceClose,
28577
+ maxDrawdownPercentage: data.signal?.maxDrawdown?.pnlPercentage,
28578
+ maxDrawdownCost: data.signal?.maxDrawdown?.pnlCost,
28579
+ maxDrawdownEntries: data.signal?.maxDrawdown?.pnlEntries,
28450
28580
  }, { ...searchOptions, signalId: data.signal?.id });
28451
28581
  }
28452
28582
  else if (data.action === "closed") {
@@ -28479,8 +28609,16 @@ class LiveReportService {
28479
28609
  closeReason: data.closeReason,
28480
28610
  duration: durationMin,
28481
28611
  closeTime: data.closeTimestamp,
28482
- peakPnl: data.signal?._peak?.pnlPercentage,
28483
- fallPnl: data.signal?._fall?.pnlPercentage,
28612
+ peakProfitPriceOpen: data.signal?.peakProfit?.priceOpen,
28613
+ peakProfitPriceClose: data.signal?.peakProfit?.priceClose,
28614
+ peakProfitPercentage: data.signal?.peakProfit?.pnlPercentage,
28615
+ peakProfitCost: data.signal?.peakProfit?.pnlCost,
28616
+ peakProfitEntries: data.signal?.peakProfit?.pnlEntries,
28617
+ maxDrawdownPriceOpen: data.signal?.maxDrawdown?.priceOpen,
28618
+ maxDrawdownPriceClose: data.signal?.maxDrawdown?.priceClose,
28619
+ maxDrawdownPercentage: data.signal?.maxDrawdown?.pnlPercentage,
28620
+ maxDrawdownCost: data.signal?.maxDrawdown?.pnlCost,
28621
+ maxDrawdownEntries: data.signal?.maxDrawdown?.pnlEntries,
28484
28622
  }, { ...searchOptions, signalId: data.signal?.id });
28485
28623
  }
28486
28624
  else if (data.action === "cancelled") {
@@ -29072,8 +29210,16 @@ class HeatReportService {
29072
29210
  openTime: data.signal?.pendingAt,
29073
29211
  scheduledAt: data.signal?.scheduledAt,
29074
29212
  closeTime: data.closeTimestamp,
29075
- peakPnl: data.signal?._peak?.pnlPercentage,
29076
- fallPnl: data.signal?._fall?.pnlPercentage,
29213
+ peakProfitPriceOpen: data.signal?.peakProfit?.priceOpen,
29214
+ peakProfitPriceClose: data.signal?.peakProfit?.priceClose,
29215
+ peakProfitPercentage: data.signal?.peakProfit?.pnlPercentage,
29216
+ peakProfitCost: data.signal?.peakProfit?.pnlCost,
29217
+ peakProfitEntries: data.signal?.peakProfit?.pnlEntries,
29218
+ maxDrawdownPriceOpen: data.signal?.maxDrawdown?.priceOpen,
29219
+ maxDrawdownPriceClose: data.signal?.maxDrawdown?.priceClose,
29220
+ maxDrawdownPercentage: data.signal?.maxDrawdown?.pnlPercentage,
29221
+ maxDrawdownCost: data.signal?.maxDrawdown?.pnlCost,
29222
+ maxDrawdownEntries: data.signal?.maxDrawdown?.pnlEntries,
29077
29223
  }, {
29078
29224
  symbol: data.symbol,
29079
29225
  strategyName: data.strategyName,
@@ -29207,6 +29353,16 @@ class PartialReportService {
29207
29353
  pnlEntries: data.data.pnl.pnlEntries,
29208
29354
  pnlPriceOpen: data.data.pnl.priceOpen,
29209
29355
  pnlPriceClose: data.data.pnl.priceClose,
29356
+ peakProfitPercentage: data.data.peakProfit.pnlPercentage,
29357
+ peakProfitCost: data.data.peakProfit.pnlCost,
29358
+ peakProfitEntries: data.data.peakProfit.pnlEntries,
29359
+ peakProfitPriceOpen: data.data.peakProfit.priceOpen,
29360
+ peakProfitPriceClose: data.data.peakProfit.priceClose,
29361
+ maxDrawdownPercentage: data.data.maxDrawdown.pnlPercentage,
29362
+ maxDrawdownCost: data.data.maxDrawdown.pnlCost,
29363
+ maxDrawdownEntries: data.data.maxDrawdown.pnlEntries,
29364
+ maxDrawdownPriceOpen: data.data.maxDrawdown.priceOpen,
29365
+ maxDrawdownPriceClose: data.data.maxDrawdown.priceClose,
29210
29366
  }, {
29211
29367
  symbol: data.symbol,
29212
29368
  strategyName: data.data.strategyName,
@@ -29257,6 +29413,16 @@ class PartialReportService {
29257
29413
  pnlEntries: data.data.pnl.pnlEntries,
29258
29414
  pnlPriceOpen: data.data.pnl.priceOpen,
29259
29415
  pnlPriceClose: data.data.pnl.priceClose,
29416
+ peakProfitPercentage: data.data.peakProfit.pnlPercentage,
29417
+ peakProfitCost: data.data.peakProfit.pnlCost,
29418
+ peakProfitEntries: data.data.peakProfit.pnlEntries,
29419
+ peakProfitPriceOpen: data.data.peakProfit.priceOpen,
29420
+ peakProfitPriceClose: data.data.peakProfit.priceClose,
29421
+ maxDrawdownPercentage: data.data.maxDrawdown.pnlPercentage,
29422
+ maxDrawdownCost: data.data.maxDrawdown.pnlCost,
29423
+ maxDrawdownEntries: data.data.maxDrawdown.pnlEntries,
29424
+ maxDrawdownPriceOpen: data.data.maxDrawdown.priceOpen,
29425
+ maxDrawdownPriceClose: data.data.maxDrawdown.priceClose,
29260
29426
  }, {
29261
29427
  symbol: data.symbol,
29262
29428
  strategyName: data.data.strategyName,
@@ -29388,6 +29554,16 @@ class BreakevenReportService {
29388
29554
  pnlEntries: data.data.pnl.pnlEntries,
29389
29555
  pnlPriceOpen: data.data.pnl.priceOpen,
29390
29556
  pnlPriceClose: data.data.pnl.priceClose,
29557
+ peakProfitPercentage: data.data.peakProfit.pnlPercentage,
29558
+ peakProfitCost: data.data.peakProfit.pnlCost,
29559
+ peakProfitEntries: data.data.peakProfit.pnlEntries,
29560
+ peakProfitPriceOpen: data.data.peakProfit.priceOpen,
29561
+ peakProfitPriceClose: data.data.peakProfit.priceClose,
29562
+ maxDrawdownPercentage: data.data.maxDrawdown.pnlPercentage,
29563
+ maxDrawdownCost: data.data.maxDrawdown.pnlCost,
29564
+ maxDrawdownEntries: data.data.maxDrawdown.pnlEntries,
29565
+ maxDrawdownPriceOpen: data.data.maxDrawdown.priceOpen,
29566
+ maxDrawdownPriceClose: data.data.maxDrawdown.priceClose,
29391
29567
  }, {
29392
29568
  symbol: data.symbol,
29393
29569
  strategyName: data.data.strategyName,
@@ -29518,6 +29694,16 @@ class RiskReportService {
29518
29694
  pnlEntries: data.currentSignal?.pnl?.pnlEntries,
29519
29695
  pnlPriceOpen: data.currentSignal?.pnl?.priceOpen,
29520
29696
  pnlPriceClose: data.currentSignal?.pnl?.priceClose,
29697
+ peakProfitPercentage: data.currentSignal?.peakProfit?.pnlPercentage,
29698
+ peakProfitCost: data.currentSignal?.peakProfit?.pnlCost,
29699
+ peakProfitEntries: data.currentSignal?.peakProfit?.pnlEntries,
29700
+ peakProfitPriceOpen: data.currentSignal?.peakProfit?.priceOpen,
29701
+ peakProfitPriceClose: data.currentSignal?.peakProfit?.priceClose,
29702
+ maxDrawdownPercentage: data.currentSignal?.maxDrawdown?.pnlPercentage,
29703
+ maxDrawdownCost: data.currentSignal?.maxDrawdown?.pnlCost,
29704
+ maxDrawdownEntries: data.currentSignal?.maxDrawdown?.pnlEntries,
29705
+ maxDrawdownPriceOpen: data.currentSignal?.maxDrawdown?.priceOpen,
29706
+ maxDrawdownPriceClose: data.currentSignal?.maxDrawdown?.priceClose,
29521
29707
  }, {
29522
29708
  symbol: data.symbol,
29523
29709
  strategyName: data.strategyName,
@@ -29597,7 +29783,7 @@ class StrategyReportService {
29597
29783
  /**
29598
29784
  * Logs a cancel-scheduled event when a scheduled signal is cancelled.
29599
29785
  */
29600
- this.cancelScheduled = async (symbol, isBacktest, context, timestamp, signalId, pnl, totalPartials, cancelId, note) => {
29786
+ this.cancelScheduled = async (symbol, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, cancelId, note) => {
29601
29787
  this.loggerService.log("strategyReportService cancelScheduled", {
29602
29788
  symbol,
29603
29789
  isBacktest,
@@ -29619,6 +29805,16 @@ class StrategyReportService {
29619
29805
  pnlEntries: pnl.pnlEntries,
29620
29806
  pnlPriceOpen: pnl.priceOpen,
29621
29807
  pnlPriceClose: pnl.priceClose,
29808
+ peakProfitPercentage: peakProfit.pnlPercentage,
29809
+ peakProfitCost: peakProfit.pnlCost,
29810
+ peakProfitEntries: peakProfit.pnlEntries,
29811
+ peakProfitPriceOpen: peakProfit.priceOpen,
29812
+ peakProfitPriceClose: peakProfit.priceClose,
29813
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
29814
+ maxDrawdownCost: maxDrawdown.pnlCost,
29815
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
29816
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
29817
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29622
29818
  totalPartials,
29623
29819
  }, {
29624
29820
  signalId,
@@ -29632,7 +29828,7 @@ class StrategyReportService {
29632
29828
  /**
29633
29829
  * Logs a close-pending event when a pending signal is closed.
29634
29830
  */
29635
- this.closePending = async (symbol, isBacktest, context, timestamp, signalId, pnl, totalPartials, closeId, note) => {
29831
+ this.closePending = async (symbol, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, closeId, note) => {
29636
29832
  this.loggerService.log("strategyReportService closePending", {
29637
29833
  symbol,
29638
29834
  isBacktest,
@@ -29654,6 +29850,16 @@ class StrategyReportService {
29654
29850
  pnlEntries: pnl.pnlEntries,
29655
29851
  pnlPriceOpen: pnl.priceOpen,
29656
29852
  pnlPriceClose: pnl.priceClose,
29853
+ peakProfitPercentage: peakProfit.pnlPercentage,
29854
+ peakProfitCost: peakProfit.pnlCost,
29855
+ peakProfitEntries: peakProfit.pnlEntries,
29856
+ peakProfitPriceOpen: peakProfit.priceOpen,
29857
+ peakProfitPriceClose: peakProfit.priceClose,
29858
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
29859
+ maxDrawdownCost: maxDrawdown.pnlCost,
29860
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
29861
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
29862
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29657
29863
  totalPartials,
29658
29864
  }, {
29659
29865
  signalId,
@@ -29667,7 +29873,7 @@ class StrategyReportService {
29667
29873
  /**
29668
29874
  * Logs a partial-profit event when a portion of the position is closed at profit.
29669
29875
  */
29670
- this.partialProfit = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29876
+ this.partialProfit = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29671
29877
  this.loggerService.log("strategyReportService partialProfit", {
29672
29878
  symbol,
29673
29879
  percentToClose,
@@ -29700,6 +29906,16 @@ class StrategyReportService {
29700
29906
  pnlEntries: pnl.pnlEntries,
29701
29907
  pnlPriceOpen: pnl.priceOpen,
29702
29908
  pnlPriceClose: pnl.priceClose,
29909
+ peakProfitPercentage: peakProfit.pnlPercentage,
29910
+ peakProfitCost: peakProfit.pnlCost,
29911
+ peakProfitEntries: peakProfit.pnlEntries,
29912
+ peakProfitPriceOpen: peakProfit.priceOpen,
29913
+ peakProfitPriceClose: peakProfit.priceClose,
29914
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
29915
+ maxDrawdownCost: maxDrawdown.pnlCost,
29916
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
29917
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
29918
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29703
29919
  totalPartials,
29704
29920
  }, {
29705
29921
  signalId,
@@ -29713,7 +29929,7 @@ class StrategyReportService {
29713
29929
  /**
29714
29930
  * Logs a partial-loss event when a portion of the position is closed at loss.
29715
29931
  */
29716
- this.partialLoss = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29932
+ this.partialLoss = async (symbol, percentToClose, currentPrice, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29717
29933
  this.loggerService.log("strategyReportService partialLoss", {
29718
29934
  symbol,
29719
29935
  percentToClose,
@@ -29746,6 +29962,16 @@ class StrategyReportService {
29746
29962
  pnlEntries: pnl.pnlEntries,
29747
29963
  pnlPriceOpen: pnl.priceOpen,
29748
29964
  pnlPriceClose: pnl.priceClose,
29965
+ peakProfitPercentage: peakProfit.pnlPercentage,
29966
+ peakProfitCost: peakProfit.pnlCost,
29967
+ peakProfitEntries: peakProfit.pnlEntries,
29968
+ peakProfitPriceOpen: peakProfit.priceOpen,
29969
+ peakProfitPriceClose: peakProfit.priceClose,
29970
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
29971
+ maxDrawdownCost: maxDrawdown.pnlCost,
29972
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
29973
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
29974
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29749
29975
  totalPartials,
29750
29976
  }, {
29751
29977
  signalId,
@@ -29759,7 +29985,7 @@ class StrategyReportService {
29759
29985
  /**
29760
29986
  * Logs a trailing-stop event when the stop-loss is adjusted.
29761
29987
  */
29762
- this.trailingStop = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29988
+ this.trailingStop = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29763
29989
  this.loggerService.log("strategyReportService trailingStop", {
29764
29990
  symbol,
29765
29991
  percentShift,
@@ -29792,6 +30018,16 @@ class StrategyReportService {
29792
30018
  pnlEntries: pnl.pnlEntries,
29793
30019
  pnlPriceOpen: pnl.priceOpen,
29794
30020
  pnlPriceClose: pnl.priceClose,
30021
+ peakProfitPercentage: peakProfit.pnlPercentage,
30022
+ peakProfitCost: peakProfit.pnlCost,
30023
+ peakProfitEntries: peakProfit.pnlEntries,
30024
+ peakProfitPriceOpen: peakProfit.priceOpen,
30025
+ peakProfitPriceClose: peakProfit.priceClose,
30026
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
30027
+ maxDrawdownCost: maxDrawdown.pnlCost,
30028
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
30029
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
30030
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29795
30031
  totalPartials,
29796
30032
  }, {
29797
30033
  signalId,
@@ -29805,7 +30041,7 @@ class StrategyReportService {
29805
30041
  /**
29806
30042
  * Logs a trailing-take event when the take-profit is adjusted.
29807
30043
  */
29808
- this.trailingTake = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
30044
+ this.trailingTake = async (symbol, percentShift, currentPrice, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29809
30045
  this.loggerService.log("strategyReportService trailingTake", {
29810
30046
  symbol,
29811
30047
  percentShift,
@@ -29838,6 +30074,16 @@ class StrategyReportService {
29838
30074
  pnlEntries: pnl.pnlEntries,
29839
30075
  pnlPriceOpen: pnl.priceOpen,
29840
30076
  pnlPriceClose: pnl.priceClose,
30077
+ peakProfitPercentage: peakProfit.pnlPercentage,
30078
+ peakProfitCost: peakProfit.pnlCost,
30079
+ peakProfitEntries: peakProfit.pnlEntries,
30080
+ peakProfitPriceOpen: peakProfit.priceOpen,
30081
+ peakProfitPriceClose: peakProfit.priceClose,
30082
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
30083
+ maxDrawdownCost: maxDrawdown.pnlCost,
30084
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
30085
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
30086
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29841
30087
  totalPartials,
29842
30088
  }, {
29843
30089
  signalId,
@@ -29851,7 +30097,7 @@ class StrategyReportService {
29851
30097
  /**
29852
30098
  * Logs a breakeven event when the stop-loss is moved to entry price.
29853
30099
  */
29854
- this.breakeven = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
30100
+ this.breakeven = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen) => {
29855
30101
  this.loggerService.log("strategyReportService breakeven", {
29856
30102
  symbol,
29857
30103
  currentPrice,
@@ -29882,6 +30128,16 @@ class StrategyReportService {
29882
30128
  pnlEntries: pnl.pnlEntries,
29883
30129
  pnlPriceOpen: pnl.priceOpen,
29884
30130
  pnlPriceClose: pnl.priceClose,
30131
+ peakProfitPercentage: peakProfit.pnlPercentage,
30132
+ peakProfitCost: peakProfit.pnlCost,
30133
+ peakProfitEntries: peakProfit.pnlEntries,
30134
+ peakProfitPriceOpen: peakProfit.priceOpen,
30135
+ peakProfitPriceClose: peakProfit.priceClose,
30136
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
30137
+ maxDrawdownCost: maxDrawdown.pnlCost,
30138
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
30139
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
30140
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29885
30141
  totalPartials,
29886
30142
  }, {
29887
30143
  signalId,
@@ -29895,7 +30151,7 @@ class StrategyReportService {
29895
30151
  /**
29896
30152
  * Logs an activate-scheduled event when a scheduled signal is activated early.
29897
30153
  */
29898
- this.activateScheduled = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen, activateId, note) => {
30154
+ this.activateScheduled = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen, activateId, note) => {
29899
30155
  this.loggerService.log("strategyReportService activateScheduled", {
29900
30156
  symbol,
29901
30157
  currentPrice,
@@ -29929,6 +30185,16 @@ class StrategyReportService {
29929
30185
  pnlEntries: pnl.pnlEntries,
29930
30186
  pnlPriceOpen: pnl.priceOpen,
29931
30187
  pnlPriceClose: pnl.priceClose,
30188
+ peakProfitPercentage: peakProfit.pnlPercentage,
30189
+ peakProfitCost: peakProfit.pnlCost,
30190
+ peakProfitEntries: peakProfit.pnlEntries,
30191
+ peakProfitPriceOpen: peakProfit.priceOpen,
30192
+ peakProfitPriceClose: peakProfit.priceClose,
30193
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
30194
+ maxDrawdownCost: maxDrawdown.pnlCost,
30195
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
30196
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
30197
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29932
30198
  totalPartials,
29933
30199
  }, {
29934
30200
  signalId,
@@ -29942,7 +30208,7 @@ class StrategyReportService {
29942
30208
  /**
29943
30209
  * Logs an average-buy (DCA) event when a new averaging entry is added to an open position.
29944
30210
  */
29945
- this.averageBuy = async (symbol, currentPrice, effectivePriceOpen, totalEntries, isBacktest, context, timestamp, signalId, pnl, totalPartials, cost, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, originalPriceOpen) => {
30211
+ this.averageBuy = async (symbol, currentPrice, effectivePriceOpen, totalEntries, isBacktest, context, timestamp, signalId, pnl, peakProfit, maxDrawdown, totalPartials, cost, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, originalPriceOpen) => {
29946
30212
  this.loggerService.log("strategyReportService averageBuy", {
29947
30213
  symbol,
29948
30214
  currentPrice,
@@ -29976,6 +30242,16 @@ class StrategyReportService {
29976
30242
  pnlEntries: pnl.pnlEntries,
29977
30243
  pnlPriceOpen: pnl.priceOpen,
29978
30244
  pnlPriceClose: pnl.priceClose,
30245
+ peakProfitPercentage: peakProfit.pnlPercentage,
30246
+ peakProfitCost: peakProfit.pnlCost,
30247
+ peakProfitEntries: peakProfit.pnlEntries,
30248
+ peakProfitPriceOpen: peakProfit.priceOpen,
30249
+ peakProfitPriceClose: peakProfit.priceClose,
30250
+ maxDrawdownPercentage: maxDrawdown.pnlPercentage,
30251
+ maxDrawdownCost: maxDrawdown.pnlCost,
30252
+ maxDrawdownEntries: maxDrawdown.pnlEntries,
30253
+ maxDrawdownPriceOpen: maxDrawdown.priceOpen,
30254
+ maxDrawdownPriceClose: maxDrawdown.priceClose,
29979
30255
  totalPartials,
29980
30256
  cost,
29981
30257
  }, {
@@ -30003,63 +30279,63 @@ class StrategyReportService {
30003
30279
  exchangeName: event.exchangeName,
30004
30280
  frameName: event.frameName,
30005
30281
  strategyName: event.strategyName,
30006
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.cancelId, event.note));
30282
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.cancelId, event.note));
30007
30283
  const unClosePending = strategyCommitSubject
30008
30284
  .filter(({ action }) => action === "close-pending")
30009
30285
  .connect(async (event) => await this.closePending(event.symbol, event.backtest, {
30010
30286
  exchangeName: event.exchangeName,
30011
30287
  frameName: event.frameName,
30012
30288
  strategyName: event.strategyName,
30013
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.closeId, event.note));
30289
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.closeId, event.note));
30014
30290
  const unPartialProfit = strategyCommitSubject
30015
30291
  .filter(({ action }) => action === "partial-profit")
30016
30292
  .connect(async (event) => await this.partialProfit(event.symbol, event.percentToClose, event.currentPrice, event.backtest, {
30017
30293
  exchangeName: event.exchangeName,
30018
30294
  frameName: event.frameName,
30019
30295
  strategyName: event.strategyName,
30020
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30296
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30021
30297
  const unPartialLoss = strategyCommitSubject
30022
30298
  .filter(({ action }) => action === "partial-loss")
30023
30299
  .connect(async (event) => await this.partialLoss(event.symbol, event.percentToClose, event.currentPrice, event.backtest, {
30024
30300
  exchangeName: event.exchangeName,
30025
30301
  frameName: event.frameName,
30026
30302
  strategyName: event.strategyName,
30027
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30303
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30028
30304
  const unTrailingStop = strategyCommitSubject
30029
30305
  .filter(({ action }) => action === "trailing-stop")
30030
30306
  .connect(async (event) => await this.trailingStop(event.symbol, event.percentShift, event.currentPrice, event.backtest, {
30031
30307
  exchangeName: event.exchangeName,
30032
30308
  frameName: event.frameName,
30033
30309
  strategyName: event.strategyName,
30034
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30310
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30035
30311
  const unTrailingTake = strategyCommitSubject
30036
30312
  .filter(({ action }) => action === "trailing-take")
30037
30313
  .connect(async (event) => await this.trailingTake(event.symbol, event.percentShift, event.currentPrice, event.backtest, {
30038
30314
  exchangeName: event.exchangeName,
30039
30315
  frameName: event.frameName,
30040
30316
  strategyName: event.strategyName,
30041
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30317
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30042
30318
  const unBreakeven = strategyCommitSubject
30043
30319
  .filter(({ action }) => action === "breakeven")
30044
30320
  .connect(async (event) => await this.breakeven(event.symbol, event.currentPrice, event.backtest, {
30045
30321
  exchangeName: event.exchangeName,
30046
30322
  frameName: event.frameName,
30047
30323
  strategyName: event.strategyName,
30048
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30324
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen));
30049
30325
  const unActivateScheduled = strategyCommitSubject
30050
30326
  .filter(({ action }) => action === "activate-scheduled")
30051
30327
  .connect(async (event) => await this.activateScheduled(event.symbol, event.currentPrice, event.backtest, {
30052
30328
  exchangeName: event.exchangeName,
30053
30329
  frameName: event.frameName,
30054
30330
  strategyName: event.strategyName,
30055
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen, event.activateId, event.note));
30331
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.totalEntries, event.originalPriceOpen, event.activateId, event.note));
30056
30332
  const unAverageBuy = strategyCommitSubject
30057
30333
  .filter(({ action }) => action === "average-buy")
30058
30334
  .connect(async (event) => await this.averageBuy(event.symbol, event.currentPrice, event.effectivePriceOpen, event.totalEntries, event.backtest, {
30059
30335
  exchangeName: event.exchangeName,
30060
30336
  frameName: event.frameName,
30061
30337
  strategyName: event.strategyName,
30062
- }, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.cost, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.originalPriceOpen));
30338
+ }, event.timestamp, event.signalId, event.pnl, event.peakProfit, event.maxDrawdown, event.totalPartials, event.cost, event.position, event.priceOpen, event.priceTakeProfit, event.priceStopLoss, event.originalPriceTakeProfit, event.originalPriceStopLoss, event.scheduledAt, event.pendingAt, event.originalPriceOpen));
30063
30339
  const disposeFn = functoolsKit.compose(() => unCancelSchedule(), () => unClosePending(), () => unPartialProfit(), () => unPartialLoss(), () => unTrailingStop(), () => unTrailingTake(), () => unBreakeven(), () => unActivateScheduled(), () => unAverageBuy());
30064
30340
  return () => {
30065
30341
  disposeFn();
@@ -30158,6 +30434,16 @@ class SyncReportService {
30158
30434
  pnlEntries: data.pnl.pnlEntries,
30159
30435
  pnlPriceOpen: data.pnl.priceOpen,
30160
30436
  pnlPriceClose: data.pnl.priceClose,
30437
+ peakProfitPercentage: data.peakProfit.pnlPercentage,
30438
+ peakProfitCost: data.peakProfit.pnlCost,
30439
+ peakProfitEntries: data.peakProfit.pnlEntries,
30440
+ peakProfitPriceOpen: data.peakProfit.priceOpen,
30441
+ peakProfitPriceClose: data.peakProfit.priceClose,
30442
+ maxDrawdownPercentage: data.maxDrawdown.pnlPercentage,
30443
+ maxDrawdownCost: data.maxDrawdown.pnlCost,
30444
+ maxDrawdownEntries: data.maxDrawdown.pnlEntries,
30445
+ maxDrawdownPriceOpen: data.maxDrawdown.priceOpen,
30446
+ maxDrawdownPriceClose: data.maxDrawdown.priceClose,
30161
30447
  currentPrice: data.currentPrice,
30162
30448
  };
30163
30449
  const searchOptions = {
@@ -30268,6 +30554,16 @@ class HighestProfitReportService {
30268
30554
  priceOpen: data.signal.priceOpen,
30269
30555
  priceTakeProfit: data.signal.priceTakeProfit,
30270
30556
  priceStopLoss: data.signal.priceStopLoss,
30557
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
30558
+ peakProfitCost: data.signal.peakProfit.pnlCost,
30559
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
30560
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
30561
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
30562
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
30563
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
30564
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
30565
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
30566
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
30271
30567
  }, {
30272
30568
  symbol: data.symbol,
30273
30569
  strategyName: data.signal.strategyName,
@@ -31545,7 +31841,9 @@ class SyncMarkdownService {
31545
31841
  pendingAt: data.pendingAt,
31546
31842
  totalEntries: data.totalEntries,
31547
31843
  totalPartials: data.totalPartials,
31548
- pnl: data.pnl,
31844
+ pnl: data.signal.pnl,
31845
+ maxDrawdown: data.signal.maxDrawdown,
31846
+ peakProfit: data.signal.peakProfit,
31549
31847
  closeReason: data.action === "signal-close" ? data.closeReason : undefined,
31550
31848
  backtest: data.backtest,
31551
31849
  createdAt,
@@ -31720,6 +32018,8 @@ let ReportStorage$1 = class ReportStorage {
31720
32018
  signalId: data.id,
31721
32019
  position: data.position,
31722
32020
  pnl: data.pnl,
32021
+ maxDrawdown: data.maxDrawdown,
32022
+ peakProfit: data.peakProfit,
31723
32023
  currentPrice,
31724
32024
  priceOpen: data.priceOpen,
31725
32025
  priceTakeProfit: data.priceTakeProfit,
@@ -32331,6 +32631,16 @@ class MaxDrawdownReportService {
32331
32631
  priceOpen: data.signal.priceOpen,
32332
32632
  priceTakeProfit: data.signal.priceTakeProfit,
32333
32633
  priceStopLoss: data.signal.priceStopLoss,
32634
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
32635
+ peakProfitCost: data.signal.peakProfit.pnlCost,
32636
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
32637
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
32638
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
32639
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
32640
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
32641
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
32642
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
32643
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
32334
32644
  }, {
32335
32645
  symbol: data.symbol,
32336
32646
  strategyName: data.signal.strategyName,
@@ -32423,6 +32733,8 @@ class ReportStorage {
32423
32733
  signalId: data.id,
32424
32734
  position: data.position,
32425
32735
  pnl: data.pnl,
32736
+ maxDrawdown: data.maxDrawdown,
32737
+ peakProfit: data.peakProfit,
32426
32738
  currentPrice,
32427
32739
  priceOpen: data.priceOpen,
32428
32740
  priceTakeProfit: data.priceTakeProfit,
@@ -35374,6 +35686,9 @@ class BrokerAdapter {
35374
35686
  priceTakeProfit: event.signal.priceTakeProfit,
35375
35687
  priceStopLoss: event.signal.priceStopLoss,
35376
35688
  priceOpen: event.signal.priceOpen,
35689
+ pnl: event.signal.pnl,
35690
+ peakProfit: event.signal.peakProfit,
35691
+ maxDrawdown: event.signal.maxDrawdown,
35377
35692
  context: {
35378
35693
  strategyName: event.strategyName,
35379
35694
  exchangeName: event.exchangeName,
@@ -35391,7 +35706,10 @@ class BrokerAdapter {
35391
35706
  currentPrice: event.currentPrice,
35392
35707
  cost: event.signal.cost,
35393
35708
  symbol: event.symbol,
35394
- pnl: event.pnl,
35709
+ pnl: event.signal.pnl,
35710
+ priceOpen: event.signal.priceOpen,
35711
+ peakProfit: event.signal.peakProfit,
35712
+ maxDrawdown: event.signal.maxDrawdown,
35395
35713
  totalEntries: event.totalEntries,
35396
35714
  totalPartials: event.totalPartials,
35397
35715
  priceStopLoss: event.signal.priceStopLoss,
@@ -54433,11 +54751,23 @@ const CREATE_SIGNAL_NOTIFICATION_FN = (data) => {
54433
54751
  totalPartials: data.signal.totalPartials,
54434
54752
  cost: data.signal.cost,
54435
54753
  pnl: data.signal.pnl,
54754
+ maxDrawdown: data.signal.maxDrawdown,
54755
+ peakProfit: data.signal.peakProfit,
54436
54756
  pnlPercentage: data.signal.pnl.pnlPercentage,
54437
54757
  pnlPriceOpen: data.signal.pnl.priceOpen,
54438
54758
  pnlPriceClose: data.signal.pnl.priceClose,
54439
54759
  pnlCost: data.signal.pnl.pnlCost,
54440
54760
  pnlEntries: data.signal.pnl.pnlEntries,
54761
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
54762
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
54763
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
54764
+ peakProfitCost: data.signal.peakProfit.pnlCost,
54765
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
54766
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
54767
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
54768
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
54769
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
54770
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54441
54771
  note: data.signal.note,
54442
54772
  scheduledAt: data.signal.scheduledAt,
54443
54773
  pendingAt: data.signal.pendingAt,
@@ -54467,11 +54797,23 @@ const CREATE_SIGNAL_NOTIFICATION_FN = (data) => {
54467
54797
  totalEntries: data.signal.totalEntries,
54468
54798
  totalPartials: data.signal.totalPartials,
54469
54799
  pnlPercentage: data.pnl.pnlPercentage,
54470
- pnl: data.pnl,
54800
+ pnl: data.signal.pnl,
54801
+ maxDrawdown: data.signal.maxDrawdown,
54802
+ peakProfit: data.signal.peakProfit,
54471
54803
  pnlPriceOpen: data.pnl.priceOpen,
54472
54804
  pnlPriceClose: data.pnl.priceClose,
54473
54805
  pnlCost: data.pnl.pnlCost,
54474
54806
  pnlEntries: data.pnl.pnlEntries,
54807
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
54808
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
54809
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
54810
+ peakProfitCost: data.signal.peakProfit.pnlCost,
54811
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
54812
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
54813
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
54814
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
54815
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
54816
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54475
54817
  closeReason: data.closeReason,
54476
54818
  duration: durationMin,
54477
54819
  note: data.signal.note,
@@ -54501,11 +54843,23 @@ const CREATE_SIGNAL_NOTIFICATION_FN = (data) => {
54501
54843
  totalPartials: data.signal.totalPartials,
54502
54844
  cost: data.signal.cost,
54503
54845
  pnl: data.signal.pnl,
54846
+ maxDrawdown: data.signal.maxDrawdown,
54847
+ peakProfit: data.signal.peakProfit,
54504
54848
  pnlPercentage: data.signal.pnl.pnlPercentage,
54505
54849
  pnlPriceOpen: data.signal.pnl.priceOpen,
54506
54850
  pnlPriceClose: data.signal.pnl.priceClose,
54507
54851
  pnlCost: data.signal.pnl.pnlCost,
54508
54852
  pnlEntries: data.signal.pnl.pnlEntries,
54853
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
54854
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
54855
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
54856
+ peakProfitCost: data.signal.peakProfit.pnlCost,
54857
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
54858
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
54859
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
54860
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
54861
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
54862
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54509
54863
  scheduledAt: data.signal.scheduledAt,
54510
54864
  currentPrice: data.currentPrice,
54511
54865
  note: data.signal.note,
@@ -54570,11 +54924,23 @@ const CREATE_PARTIAL_PROFIT_NOTIFICATION_FN = (data) => ({
54570
54924
  totalEntries: data.data.totalEntries,
54571
54925
  totalPartials: data.data.totalPartials,
54572
54926
  pnl: data.data.pnl,
54927
+ maxDrawdown: data.data.maxDrawdown,
54928
+ peakProfit: data.data.peakProfit,
54573
54929
  pnlPercentage: data.data.pnl.pnlPercentage,
54574
54930
  pnlPriceOpen: data.data.pnl.priceOpen,
54575
54931
  pnlPriceClose: data.data.pnl.priceClose,
54576
54932
  pnlCost: data.data.pnl.pnlCost,
54577
54933
  pnlEntries: data.data.pnl.pnlEntries,
54934
+ peakProfitPriceOpen: data.data.peakProfit.priceOpen,
54935
+ peakProfitPriceClose: data.data.peakProfit.priceClose,
54936
+ peakProfitPercentage: data.data.peakProfit.pnlPercentage,
54937
+ peakProfitCost: data.data.peakProfit.pnlCost,
54938
+ peakProfitEntries: data.data.peakProfit.pnlEntries,
54939
+ maxDrawdownPriceOpen: data.data.maxDrawdown.priceOpen,
54940
+ maxDrawdownPriceClose: data.data.maxDrawdown.priceClose,
54941
+ maxDrawdownPercentage: data.data.maxDrawdown.pnlPercentage,
54942
+ maxDrawdownCost: data.data.maxDrawdown.pnlCost,
54943
+ maxDrawdownEntries: data.data.maxDrawdown.pnlEntries,
54578
54944
  note: data.data.note,
54579
54945
  scheduledAt: data.data.scheduledAt,
54580
54946
  pendingAt: data.data.pendingAt,
@@ -54606,11 +54972,23 @@ const CREATE_PARTIAL_LOSS_NOTIFICATION_FN = (data) => ({
54606
54972
  totalEntries: data.data.totalEntries,
54607
54973
  totalPartials: data.data.totalPartials,
54608
54974
  pnl: data.data.pnl,
54975
+ maxDrawdown: data.data.maxDrawdown,
54976
+ peakProfit: data.data.peakProfit,
54609
54977
  pnlPercentage: data.data.pnl.pnlPercentage,
54610
54978
  pnlPriceOpen: data.data.pnl.priceOpen,
54611
54979
  pnlPriceClose: data.data.pnl.priceClose,
54612
54980
  pnlCost: data.data.pnl.pnlCost,
54613
54981
  pnlEntries: data.data.pnl.pnlEntries,
54982
+ peakProfitPriceOpen: data.data.peakProfit.priceOpen,
54983
+ peakProfitPriceClose: data.data.peakProfit.priceClose,
54984
+ peakProfitPercentage: data.data.peakProfit.pnlPercentage,
54985
+ peakProfitCost: data.data.peakProfit.pnlCost,
54986
+ peakProfitEntries: data.data.peakProfit.pnlEntries,
54987
+ maxDrawdownPriceOpen: data.data.maxDrawdown.priceOpen,
54988
+ maxDrawdownPriceClose: data.data.maxDrawdown.priceClose,
54989
+ maxDrawdownPercentage: data.data.maxDrawdown.pnlPercentage,
54990
+ maxDrawdownCost: data.data.maxDrawdown.pnlCost,
54991
+ maxDrawdownEntries: data.data.maxDrawdown.pnlEntries,
54614
54992
  note: data.data.note,
54615
54993
  scheduledAt: data.data.scheduledAt,
54616
54994
  pendingAt: data.data.pendingAt,
@@ -54641,11 +55019,23 @@ const CREATE_BREAKEVEN_NOTIFICATION_FN = (data) => ({
54641
55019
  totalEntries: data.data.totalEntries,
54642
55020
  totalPartials: data.data.totalPartials,
54643
55021
  pnl: data.data.pnl,
55022
+ maxDrawdown: data.data.maxDrawdown,
55023
+ peakProfit: data.data.peakProfit,
54644
55024
  pnlPercentage: data.data.pnl.pnlPercentage,
54645
55025
  pnlPriceOpen: data.data.pnl.priceOpen,
54646
55026
  pnlPriceClose: data.data.pnl.priceClose,
54647
55027
  pnlCost: data.data.pnl.pnlCost,
54648
55028
  pnlEntries: data.data.pnl.pnlEntries,
55029
+ peakProfitPriceOpen: data.data.peakProfit.priceOpen,
55030
+ peakProfitPriceClose: data.data.peakProfit.priceClose,
55031
+ peakProfitPercentage: data.data.peakProfit.pnlPercentage,
55032
+ peakProfitCost: data.data.peakProfit.pnlCost,
55033
+ peakProfitEntries: data.data.peakProfit.pnlEntries,
55034
+ maxDrawdownPriceOpen: data.data.maxDrawdown.priceOpen,
55035
+ maxDrawdownPriceClose: data.data.maxDrawdown.priceClose,
55036
+ maxDrawdownPercentage: data.data.maxDrawdown.pnlPercentage,
55037
+ maxDrawdownCost: data.data.maxDrawdown.pnlCost,
55038
+ maxDrawdownEntries: data.data.maxDrawdown.pnlEntries,
54649
55039
  note: data.data.note,
54650
55040
  scheduledAt: data.data.scheduledAt,
54651
55041
  pendingAt: data.data.pendingAt,
@@ -54680,12 +55070,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54680
55070
  originalPriceOpen: data.originalPriceOpen,
54681
55071
  totalEntries: data.totalEntries,
54682
55072
  totalPartials: data.totalPartials,
54683
- pnl: data.pnl,
55073
+ pnl: data.signal.pnl,
55074
+ maxDrawdown: data.signal.maxDrawdown,
55075
+ peakProfit: data.signal.peakProfit,
54684
55076
  pnlPercentage: data.pnl.pnlPercentage,
54685
55077
  pnlPriceOpen: data.pnl.priceOpen,
54686
55078
  pnlPriceClose: data.pnl.priceClose,
54687
55079
  pnlCost: data.pnl.pnlCost,
54688
55080
  pnlEntries: data.pnl.pnlEntries,
55081
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55082
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55083
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55084
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55085
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55086
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55087
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55088
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55089
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55090
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54689
55091
  scheduledAt: data.scheduledAt,
54690
55092
  pendingAt: data.pendingAt,
54691
55093
  note: data.note,
@@ -54713,12 +55115,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54713
55115
  originalPriceOpen: data.originalPriceOpen,
54714
55116
  totalEntries: data.totalEntries,
54715
55117
  totalPartials: data.totalPartials,
54716
- pnl: data.pnl,
55118
+ pnl: data.signal.pnl,
55119
+ maxDrawdown: data.signal.maxDrawdown,
55120
+ peakProfit: data.signal.peakProfit,
54717
55121
  pnlPercentage: data.pnl.pnlPercentage,
54718
55122
  pnlPriceOpen: data.pnl.priceOpen,
54719
55123
  pnlPriceClose: data.pnl.priceClose,
54720
55124
  pnlCost: data.pnl.pnlCost,
54721
55125
  pnlEntries: data.pnl.pnlEntries,
55126
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55127
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55128
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55129
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55130
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55131
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55132
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55133
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55134
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55135
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54722
55136
  scheduledAt: data.scheduledAt,
54723
55137
  pendingAt: data.pendingAt,
54724
55138
  note: data.note,
@@ -54745,12 +55159,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54745
55159
  originalPriceOpen: data.originalPriceOpen,
54746
55160
  totalEntries: data.totalEntries,
54747
55161
  totalPartials: data.totalPartials,
54748
- pnl: data.pnl,
55162
+ pnl: data.signal.pnl,
55163
+ maxDrawdown: data.signal.maxDrawdown,
55164
+ peakProfit: data.signal.peakProfit,
54749
55165
  pnlPercentage: data.pnl.pnlPercentage,
54750
55166
  pnlPriceOpen: data.pnl.priceOpen,
54751
55167
  pnlPriceClose: data.pnl.priceClose,
54752
55168
  pnlCost: data.pnl.pnlCost,
54753
55169
  pnlEntries: data.pnl.pnlEntries,
55170
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55171
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55172
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55173
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55174
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55175
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55176
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55177
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55178
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55179
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54754
55180
  scheduledAt: data.scheduledAt,
54755
55181
  pendingAt: data.pendingAt,
54756
55182
  note: data.note,
@@ -54778,12 +55204,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54778
55204
  originalPriceOpen: data.originalPriceOpen,
54779
55205
  totalEntries: data.totalEntries,
54780
55206
  totalPartials: data.totalPartials,
54781
- pnl: data.pnl,
55207
+ pnl: data.signal.pnl,
55208
+ maxDrawdown: data.signal.maxDrawdown,
55209
+ peakProfit: data.signal.peakProfit,
54782
55210
  pnlPercentage: data.pnl.pnlPercentage,
54783
55211
  pnlPriceOpen: data.pnl.priceOpen,
54784
55212
  pnlPriceClose: data.pnl.priceClose,
54785
55213
  pnlCost: data.pnl.pnlCost,
54786
55214
  pnlEntries: data.pnl.pnlEntries,
55215
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55216
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55217
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55218
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55219
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55220
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55221
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55222
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55223
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55224
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54787
55225
  scheduledAt: data.scheduledAt,
54788
55226
  pendingAt: data.pendingAt,
54789
55227
  note: data.note,
@@ -54811,12 +55249,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54811
55249
  originalPriceOpen: data.originalPriceOpen,
54812
55250
  totalEntries: data.totalEntries,
54813
55251
  totalPartials: data.totalPartials,
54814
- pnl: data.pnl,
55252
+ pnl: data.signal.pnl,
55253
+ maxDrawdown: data.signal.maxDrawdown,
55254
+ peakProfit: data.signal.peakProfit,
54815
55255
  pnlPercentage: data.pnl.pnlPercentage,
54816
55256
  pnlPriceOpen: data.pnl.priceOpen,
54817
55257
  pnlPriceClose: data.pnl.priceClose,
54818
55258
  pnlCost: data.pnl.pnlCost,
54819
55259
  pnlEntries: data.pnl.pnlEntries,
55260
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55261
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55262
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55263
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55264
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55265
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55266
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55267
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55268
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55269
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54820
55270
  scheduledAt: data.scheduledAt,
54821
55271
  pendingAt: data.pendingAt,
54822
55272
  note: data.note,
@@ -54844,12 +55294,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54844
55294
  originalPriceOpen: data.originalPriceOpen,
54845
55295
  totalEntries: data.totalEntries,
54846
55296
  totalPartials: data.totalPartials,
54847
- pnl: data.pnl,
55297
+ pnl: data.signal.pnl,
55298
+ maxDrawdown: data.signal.maxDrawdown,
55299
+ peakProfit: data.signal.peakProfit,
54848
55300
  pnlPercentage: data.pnl.pnlPercentage,
54849
55301
  pnlPriceOpen: data.pnl.priceOpen,
54850
55302
  pnlPriceClose: data.pnl.priceClose,
54851
55303
  pnlCost: data.pnl.pnlCost,
54852
55304
  pnlEntries: data.pnl.pnlEntries,
55305
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55306
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55307
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55308
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55309
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55310
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55311
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55312
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55313
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55314
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54853
55315
  scheduledAt: data.scheduledAt,
54854
55316
  pendingAt: data.pendingAt,
54855
55317
  note: data.note,
@@ -54878,12 +55340,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54878
55340
  originalPriceTakeProfit: data.originalPriceTakeProfit,
54879
55341
  originalPriceStopLoss: data.originalPriceStopLoss,
54880
55342
  originalPriceOpen: data.originalPriceOpen,
54881
- pnl: data.pnl,
55343
+ pnl: data.signal.pnl,
55344
+ maxDrawdown: data.signal.maxDrawdown,
55345
+ peakProfit: data.signal.peakProfit,
54882
55346
  pnlPercentage: data.pnl.pnlPercentage,
54883
55347
  pnlPriceOpen: data.pnl.priceOpen,
54884
55348
  pnlPriceClose: data.pnl.priceClose,
54885
55349
  pnlCost: data.pnl.pnlCost,
54886
55350
  pnlEntries: data.pnl.pnlEntries,
55351
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55352
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55353
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55354
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55355
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55356
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55357
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55358
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55359
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55360
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54887
55361
  scheduledAt: data.scheduledAt,
54888
55362
  pendingAt: data.pendingAt,
54889
55363
  note: data.note,
@@ -54904,12 +55378,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54904
55378
  totalEntries: data.totalEntries,
54905
55379
  totalPartials: data.totalPartials,
54906
55380
  originalPriceOpen: data.originalPriceOpen,
54907
- pnl: data.pnl,
55381
+ pnl: data.signal.pnl,
55382
+ maxDrawdown: data.signal.maxDrawdown,
55383
+ peakProfit: data.signal.peakProfit,
54908
55384
  pnlPercentage: data.pnl.pnlPercentage,
54909
55385
  pnlPriceOpen: data.pnl.priceOpen,
54910
55386
  pnlPriceClose: data.pnl.priceClose,
54911
55387
  pnlCost: data.pnl.pnlCost,
54912
55388
  pnlEntries: data.pnl.pnlEntries,
55389
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55390
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55391
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55392
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55393
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55394
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55395
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55396
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55397
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55398
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54913
55399
  note: data.note,
54914
55400
  createdAt: data.timestamp,
54915
55401
  };
@@ -54928,12 +55414,24 @@ const CREATE_STRATEGY_COMMIT_NOTIFICATION_FN = (data) => {
54928
55414
  totalEntries: data.totalEntries,
54929
55415
  totalPartials: data.totalPartials,
54930
55416
  originalPriceOpen: data.originalPriceOpen,
54931
- pnl: data.pnl,
55417
+ pnl: data.signal.pnl,
55418
+ maxDrawdown: data.signal.maxDrawdown,
55419
+ peakProfit: data.signal.peakProfit,
54932
55420
  pnlPercentage: data.pnl.pnlPercentage,
54933
55421
  pnlPriceOpen: data.pnl.priceOpen,
54934
55422
  pnlPriceClose: data.pnl.priceClose,
54935
55423
  pnlCost: data.pnl.pnlCost,
54936
55424
  pnlEntries: data.pnl.pnlEntries,
55425
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55426
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55427
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55428
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55429
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55430
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55431
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55432
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55433
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55434
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54937
55435
  note: data.note,
54938
55436
  createdAt: data.timestamp,
54939
55437
  };
@@ -54958,12 +55456,24 @@ const CREATE_SIGNAL_SYNC_NOTIFICATION_FN = (data) => {
54958
55456
  exchangeName: data.exchangeName,
54959
55457
  signalId: data.signalId,
54960
55458
  currentPrice: data.currentPrice,
54961
- pnl: data.pnl,
55459
+ pnl: data.signal.pnl,
55460
+ maxDrawdown: data.signal.maxDrawdown,
55461
+ peakProfit: data.signal.peakProfit,
54962
55462
  pnlPercentage: data.pnl.pnlPercentage,
54963
55463
  pnlPriceOpen: data.pnl.priceOpen,
54964
55464
  pnlPriceClose: data.pnl.priceClose,
54965
55465
  pnlCost: data.pnl.pnlCost,
54966
55466
  pnlEntries: data.pnl.pnlEntries,
55467
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55468
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55469
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55470
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55471
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55472
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55473
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55474
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55475
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55476
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
54967
55477
  cost: data.cost,
54968
55478
  position: data.position,
54969
55479
  priceOpen: data.priceOpen,
@@ -54991,12 +55501,24 @@ const CREATE_SIGNAL_SYNC_NOTIFICATION_FN = (data) => {
54991
55501
  exchangeName: data.exchangeName,
54992
55502
  signalId: data.signalId,
54993
55503
  currentPrice: data.currentPrice,
54994
- pnl: data.pnl,
55504
+ pnl: data.signal.pnl,
55505
+ maxDrawdown: data.signal.maxDrawdown,
55506
+ peakProfit: data.signal.peakProfit,
54995
55507
  pnlPercentage: data.pnl.pnlPercentage,
54996
55508
  pnlPriceOpen: data.pnl.priceOpen,
54997
55509
  pnlPriceClose: data.pnl.priceClose,
54998
55510
  pnlCost: data.pnl.pnlCost,
54999
55511
  pnlEntries: data.pnl.pnlEntries,
55512
+ peakProfitPriceOpen: data.signal.peakProfit.priceOpen,
55513
+ peakProfitPriceClose: data.signal.peakProfit.priceClose,
55514
+ peakProfitPercentage: data.signal.peakProfit.pnlPercentage,
55515
+ peakProfitCost: data.signal.peakProfit.pnlCost,
55516
+ peakProfitEntries: data.signal.peakProfit.pnlEntries,
55517
+ maxDrawdownPriceOpen: data.signal.maxDrawdown.priceOpen,
55518
+ maxDrawdownPriceClose: data.signal.maxDrawdown.priceClose,
55519
+ maxDrawdownPercentage: data.signal.maxDrawdown.pnlPercentage,
55520
+ maxDrawdownCost: data.signal.maxDrawdown.pnlCost,
55521
+ maxDrawdownEntries: data.signal.maxDrawdown.pnlEntries,
55000
55522
  position: data.position,
55001
55523
  priceOpen: data.priceOpen,
55002
55524
  priceTakeProfit: data.priceTakeProfit,
@@ -55102,11 +55624,23 @@ const CREATE_SIGNAL_INFO_NOTIFICATION_FN = (data) => ({
55102
55624
  totalEntries: data.data.totalEntries,
55103
55625
  totalPartials: data.data.totalPartials,
55104
55626
  pnl: data.data.pnl,
55627
+ maxDrawdown: data.data.maxDrawdown,
55628
+ peakProfit: data.data.peakProfit,
55105
55629
  pnlPercentage: data.data.pnl.pnlPercentage,
55106
55630
  pnlPriceOpen: data.data.pnl.priceOpen,
55107
55631
  pnlPriceClose: data.data.pnl.priceClose,
55108
55632
  pnlCost: data.data.pnl.pnlCost,
55109
55633
  pnlEntries: data.data.pnl.pnlEntries,
55634
+ peakProfitPriceOpen: data.data.peakProfit.priceOpen,
55635
+ peakProfitPriceClose: data.data.peakProfit.priceClose,
55636
+ peakProfitPercentage: data.data.peakProfit.pnlPercentage,
55637
+ peakProfitCost: data.data.peakProfit.pnlCost,
55638
+ peakProfitEntries: data.data.peakProfit.pnlEntries,
55639
+ maxDrawdownPriceOpen: data.data.maxDrawdown.priceOpen,
55640
+ maxDrawdownPriceClose: data.data.maxDrawdown.priceClose,
55641
+ maxDrawdownPercentage: data.data.maxDrawdown.pnlPercentage,
55642
+ maxDrawdownCost: data.data.maxDrawdown.pnlCost,
55643
+ maxDrawdownEntries: data.data.maxDrawdown.pnlEntries,
55110
55644
  note: data.note,
55111
55645
  notificationId: data.notificationId,
55112
55646
  scheduledAt: data.data.scheduledAt,