backtest-kit 13.2.0 → 13.4.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 +51 -47
- package/build/index.mjs +51 -47
- package/package.json +1 -1
- package/types.d.ts +19 -19
package/build/index.cjs
CHANGED
|
@@ -7601,7 +7601,7 @@ const WAIT_FOR_INIT_FN$4 = async (self) => {
|
|
|
7601
7601
|
// an already-cleared _pendingSignal, and cancel/activate belong to the scheduled
|
|
7602
7602
|
// signal — none of them are tied to the currently-pending signal's id. A queued
|
|
7603
7603
|
// createSignal is a not-yet-consumed signal source and likewise stands on its own.
|
|
7604
|
-
self._userSignal = strategyData.
|
|
7604
|
+
self._userSignal = strategyData.createdSignal;
|
|
7605
7605
|
self._closedSignal = strategyData.closedSignal;
|
|
7606
7606
|
self._cancelledSignal = strategyData.cancelledSignal;
|
|
7607
7607
|
self._activatedSignal = strategyData.activatedSignal;
|
|
@@ -7680,7 +7680,7 @@ const PERSIST_STRATEGY_FN = async (self) => {
|
|
|
7680
7680
|
}
|
|
7681
7681
|
await PersistStrategyAdapter.writeStrategyData({
|
|
7682
7682
|
pendingSignalId: self._pendingSignal?.id ?? null,
|
|
7683
|
-
|
|
7683
|
+
createdSignal: self._userSignal,
|
|
7684
7684
|
commitQueue: self._commitQueue,
|
|
7685
7685
|
closedSignal: self._closedSignal,
|
|
7686
7686
|
cancelledSignal: self._cancelledSignal,
|
|
@@ -8365,7 +8365,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
8365
8365
|
return null;
|
|
8366
8366
|
}
|
|
8367
8367
|
await self.setScheduledSignal(null);
|
|
8368
|
-
await self.setPendingSignal(activatedSignal);
|
|
8368
|
+
await self.setPendingSignal(activatedSignal, activatedSignal.priceOpen);
|
|
8369
8369
|
await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
|
|
8370
8370
|
await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, self._pendingSignal, self._pendingSignal.priceOpen, activationTime, self.params.execution.context.backtest);
|
|
8371
8371
|
const result = {
|
|
@@ -8389,7 +8389,7 @@ const CALL_SCHEDULE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (s
|
|
|
8389
8389
|
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);
|
|
8390
8390
|
// Call user onSchedulePing callback only if signal is still active (not cancelled, not activated)
|
|
8391
8391
|
if (self.params.callbacks?.onSchedulePing) {
|
|
8392
|
-
await self.params.callbacks.onSchedulePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
|
|
8392
|
+
await self.params.callbacks.onSchedulePing(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8393
8393
|
}
|
|
8394
8394
|
}, {
|
|
8395
8395
|
when: new Date(timestamp),
|
|
@@ -8415,7 +8415,7 @@ const CALL_ACTIVE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (sel
|
|
|
8415
8415
|
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);
|
|
8416
8416
|
// Call user onActivePing callback only if signal is still active (not closed)
|
|
8417
8417
|
if (self.params.callbacks?.onActivePing) {
|
|
8418
|
-
await self.params.callbacks.onActivePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
|
|
8418
|
+
await self.params.callbacks.onActivePing(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8419
8419
|
}
|
|
8420
8420
|
}, {
|
|
8421
8421
|
when: new Date(timestamp),
|
|
@@ -8459,7 +8459,7 @@ const CALL_ACTIVE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, sy
|
|
|
8459
8459
|
await ExecutionContextService.runInContext(async () => {
|
|
8460
8460
|
if (self.params.callbacks?.onActive) {
|
|
8461
8461
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8462
|
-
await self.params.callbacks.onActive(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8462
|
+
await self.params.callbacks.onActive(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8463
8463
|
}
|
|
8464
8464
|
}, {
|
|
8465
8465
|
when: new Date(timestamp),
|
|
@@ -8482,7 +8482,7 @@ const CALL_SCHEDULE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self,
|
|
|
8482
8482
|
await ExecutionContextService.runInContext(async () => {
|
|
8483
8483
|
if (self.params.callbacks?.onSchedule) {
|
|
8484
8484
|
const publicSignal = TO_PUBLIC_SIGNAL("scheduled", signal, currentPrice);
|
|
8485
|
-
await self.params.callbacks.onSchedule(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8485
|
+
await self.params.callbacks.onSchedule(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8486
8486
|
}
|
|
8487
8487
|
}, {
|
|
8488
8488
|
when: new Date(timestamp),
|
|
@@ -8505,7 +8505,7 @@ const CALL_CANCEL_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, sy
|
|
|
8505
8505
|
await ExecutionContextService.runInContext(async () => {
|
|
8506
8506
|
if (self.params.callbacks?.onCancel) {
|
|
8507
8507
|
const publicSignal = TO_PUBLIC_SIGNAL("scheduled", signal, currentPrice);
|
|
8508
|
-
await self.params.callbacks.onCancel(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8508
|
+
await self.params.callbacks.onCancel(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8509
8509
|
}
|
|
8510
8510
|
}, {
|
|
8511
8511
|
when: new Date(timestamp),
|
|
@@ -8528,7 +8528,7 @@ const CALL_OPEN_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symb
|
|
|
8528
8528
|
await ExecutionContextService.runInContext(async () => {
|
|
8529
8529
|
if (self.params.callbacks?.onOpen) {
|
|
8530
8530
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, priceOpen);
|
|
8531
|
-
await self.params.callbacks.onOpen(self.params.execution.context.symbol, publicSignal, priceOpen, self.params.execution.context.backtest);
|
|
8531
|
+
await self.params.callbacks.onOpen(self.params.execution.context.symbol, publicSignal, priceOpen, new Date(timestamp), self.params.execution.context.backtest);
|
|
8532
8532
|
}
|
|
8533
8533
|
}, {
|
|
8534
8534
|
when: new Date(timestamp),
|
|
@@ -8551,7 +8551,7 @@ const CALL_CLOSE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, sym
|
|
|
8551
8551
|
await ExecutionContextService.runInContext(async () => {
|
|
8552
8552
|
if (self.params.callbacks?.onClose) {
|
|
8553
8553
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8554
|
-
await self.params.callbacks.onClose(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8554
|
+
await self.params.callbacks.onClose(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8555
8555
|
}
|
|
8556
8556
|
}, {
|
|
8557
8557
|
when: new Date(timestamp),
|
|
@@ -8573,7 +8573,7 @@ const CALL_CLOSE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, sym
|
|
|
8573
8573
|
const CALL_TICK_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, result, timestamp, backtest) => {
|
|
8574
8574
|
await ExecutionContextService.runInContext(async () => {
|
|
8575
8575
|
if (self.params.callbacks?.onTick) {
|
|
8576
|
-
await self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
8576
|
+
await self.params.callbacks.onTick(self.params.execution.context.symbol, result, result.currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8577
8577
|
}
|
|
8578
8578
|
}, {
|
|
8579
8579
|
when: new Date(timestamp),
|
|
@@ -8595,7 +8595,7 @@ const CALL_TICK_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symb
|
|
|
8595
8595
|
const CALL_IDLE_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, currentPrice, timestamp, backtest) => {
|
|
8596
8596
|
await ExecutionContextService.runInContext(async () => {
|
|
8597
8597
|
if (self.params.callbacks?.onIdle) {
|
|
8598
|
-
await self.params.callbacks.onIdle(self.params.execution.context.symbol, currentPrice, self.params.execution.context.backtest);
|
|
8598
|
+
await self.params.callbacks.onIdle(self.params.execution.context.symbol, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8599
8599
|
}
|
|
8600
8600
|
}, {
|
|
8601
8601
|
when: new Date(timestamp),
|
|
@@ -8727,7 +8727,7 @@ const CALL_PARTIAL_PROFIT_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (
|
|
|
8727
8727
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8728
8728
|
await self.params.partial.profit(symbol, publicSignal, currentPrice, percentTp, backtest, new Date(timestamp));
|
|
8729
8729
|
if (self.params.callbacks?.onPartialProfit) {
|
|
8730
|
-
await self.params.callbacks.onPartialProfit(symbol, publicSignal, currentPrice,
|
|
8730
|
+
await self.params.callbacks.onPartialProfit(symbol, publicSignal, percentTp, currentPrice, new Date(timestamp), backtest);
|
|
8731
8731
|
}
|
|
8732
8732
|
}, {
|
|
8733
8733
|
when: new Date(timestamp),
|
|
@@ -8751,7 +8751,7 @@ const CALL_PARTIAL_LOSS_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (se
|
|
|
8751
8751
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8752
8752
|
await self.params.partial.loss(symbol, publicSignal, currentPrice, percentSl, backtest, new Date(timestamp));
|
|
8753
8753
|
if (self.params.callbacks?.onPartialLoss) {
|
|
8754
|
-
await self.params.callbacks.onPartialLoss(symbol, publicSignal, currentPrice,
|
|
8754
|
+
await self.params.callbacks.onPartialLoss(symbol, publicSignal, percentSl, currentPrice, new Date(timestamp), backtest);
|
|
8755
8755
|
}
|
|
8756
8756
|
}, {
|
|
8757
8757
|
when: new Date(timestamp),
|
|
@@ -8775,7 +8775,7 @@ const CALL_BREAKEVEN_CHECK_FN = functoolsKit.trycatch(beginTime(async (self, sym
|
|
|
8775
8775
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8776
8776
|
const isBreakeven = await self.params.breakeven.check(symbol, publicSignal, currentPrice, backtest, new Date(timestamp));
|
|
8777
8777
|
if (self.params.callbacks?.onBreakeven) {
|
|
8778
|
-
isBreakeven && await self.params.callbacks.onBreakeven(symbol, publicSignal, currentPrice, backtest);
|
|
8778
|
+
isBreakeven && await self.params.callbacks.onBreakeven(symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
8779
8779
|
}
|
|
8780
8780
|
}, {
|
|
8781
8781
|
when: new Date(timestamp),
|
|
@@ -8978,7 +8978,7 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
|
|
|
8978
8978
|
// КРИТИЧНО: Очищаем состояние ClientBreakeven при закрытии позиции
|
|
8979
8979
|
await CALL_BREAKEVEN_CLEAR_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
|
|
8980
8980
|
await CALL_RISK_REMOVE_SIGNAL_FN(self, self.params.execution.context.symbol, currentTime, self.params.execution.context.backtest);
|
|
8981
|
-
await self.setPendingSignal(null);
|
|
8981
|
+
await self.setPendingSignal(null, currentPrice);
|
|
8982
8982
|
const result = {
|
|
8983
8983
|
action: "closed",
|
|
8984
8984
|
signal: publicSignal,
|
|
@@ -9016,7 +9016,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
9016
9016
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9017
9017
|
signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
9018
9018
|
if (self.params.callbacks?.onWrite) {
|
|
9019
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
9019
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9020
9020
|
}
|
|
9021
9021
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9022
9022
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9036,7 +9036,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
9036
9036
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9037
9037
|
signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
9038
9038
|
if (self.params.callbacks?.onWrite) {
|
|
9039
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
9039
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9040
9040
|
}
|
|
9041
9041
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9042
9042
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9061,7 +9061,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
9061
9061
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9062
9062
|
signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
9063
9063
|
if (self.params.callbacks?.onWrite) {
|
|
9064
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
9064
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9065
9065
|
}
|
|
9066
9066
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9067
9067
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9081,7 +9081,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
9081
9081
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9082
9082
|
signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
9083
9083
|
if (self.params.callbacks?.onWrite) {
|
|
9084
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
9084
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9085
9085
|
}
|
|
9086
9086
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9087
9087
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9252,7 +9252,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
|
|
|
9252
9252
|
return false;
|
|
9253
9253
|
}
|
|
9254
9254
|
await self.setScheduledSignal(null);
|
|
9255
|
-
await self.setPendingSignal(activatedSignal);
|
|
9255
|
+
await self.setPendingSignal(activatedSignal, activatedSignal.priceOpen);
|
|
9256
9256
|
await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
|
|
9257
9257
|
await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, activatedSignal, activatedSignal.priceOpen, activationTime, self.params.execution.context.backtest);
|
|
9258
9258
|
await CALL_BACKTEST_SCHEDULE_OPEN_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
|
|
@@ -9290,7 +9290,7 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
|
|
|
9290
9290
|
// КРИТИЧНО: Очищаем состояние ClientBreakeven при закрытии позиции
|
|
9291
9291
|
await CALL_BREAKEVEN_CLEAR_FN(self, self.params.execution.context.symbol, signal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
|
|
9292
9292
|
await CALL_RISK_REMOVE_SIGNAL_FN(self, self.params.execution.context.symbol, closeTimestamp, self.params.execution.context.backtest);
|
|
9293
|
-
await self.setPendingSignal(null);
|
|
9293
|
+
await self.setPendingSignal(null, averagePrice);
|
|
9294
9294
|
const result = {
|
|
9295
9295
|
action: "closed",
|
|
9296
9296
|
signal: publicSignal,
|
|
@@ -9454,7 +9454,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
|
|
|
9454
9454
|
return { outcome: "pending" };
|
|
9455
9455
|
}
|
|
9456
9456
|
await self.setScheduledSignal(null);
|
|
9457
|
-
await self.setPendingSignal(pendingSignal);
|
|
9457
|
+
await self.setPendingSignal(pendingSignal, averagePrice);
|
|
9458
9458
|
await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, pendingSignal, candle.timestamp, self.params.execution.context.backtest);
|
|
9459
9459
|
// Emit commit AFTER successful risk check
|
|
9460
9460
|
const publicSignalForCommit = TO_PUBLIC_SIGNAL("pending", pendingSignal, averagePrice);
|
|
@@ -9660,7 +9660,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9660
9660
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9661
9661
|
signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9662
9662
|
if (self.params.callbacks?.onWrite) {
|
|
9663
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9663
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9664
9664
|
}
|
|
9665
9665
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9666
9666
|
}
|
|
@@ -9677,7 +9677,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9677
9677
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9678
9678
|
signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9679
9679
|
if (self.params.callbacks?.onWrite) {
|
|
9680
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9680
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9681
9681
|
}
|
|
9682
9682
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9683
9683
|
}
|
|
@@ -9700,7 +9700,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9700
9700
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9701
9701
|
signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9702
9702
|
if (self.params.callbacks?.onWrite) {
|
|
9703
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9703
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9704
9704
|
}
|
|
9705
9705
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9706
9706
|
}
|
|
@@ -9717,7 +9717,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9717
9717
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9718
9718
|
signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9719
9719
|
if (self.params.callbacks?.onWrite) {
|
|
9720
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9720
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9721
9721
|
}
|
|
9722
9722
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9723
9723
|
}
|
|
@@ -9878,9 +9878,10 @@ class ClientStrategy {
|
|
|
9878
9878
|
* Uses atomic file writes to prevent corruption.
|
|
9879
9879
|
*
|
|
9880
9880
|
* @param pendingSignal - New signal state (null to clear)
|
|
9881
|
+
* @param currentPrice - Current market price (forwarded to the onWrite callback)
|
|
9881
9882
|
* @returns Promise that resolves when update is complete
|
|
9882
9883
|
*/
|
|
9883
|
-
async setPendingSignal(pendingSignal) {
|
|
9884
|
+
async setPendingSignal(pendingSignal, currentPrice) {
|
|
9884
9885
|
this.params.logger.debug("ClientStrategy setPendingSignal", {
|
|
9885
9886
|
pendingSignal,
|
|
9886
9887
|
});
|
|
@@ -9899,7 +9900,7 @@ class ClientStrategy {
|
|
|
9899
9900
|
// даже в backtest режиме, чтобы тесты могли перехватывать вызовы через mock adapter
|
|
9900
9901
|
if (this.params.callbacks?.onWrite) {
|
|
9901
9902
|
const publicSignal = this._pendingSignal ? this._pendingSignal : null;
|
|
9902
|
-
this.params.callbacks.onWrite(this.params.execution.context.symbol, publicSignal, this.params.execution.context.backtest);
|
|
9903
|
+
this.params.callbacks.onWrite(this.params.execution.context.symbol, publicSignal, currentPrice, this.params.execution.context.when, this.params.execution.context.backtest);
|
|
9903
9904
|
}
|
|
9904
9905
|
if (this.params.execution.context.backtest) {
|
|
9905
9906
|
return;
|
|
@@ -10748,7 +10749,7 @@ class ClientStrategy {
|
|
|
10748
10749
|
const currentTime = this.params.execution.context.when.getTime();
|
|
10749
10750
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
10750
10751
|
// Process queued commit events with proper timestamp
|
|
10751
|
-
await PROCESS_COMMIT_QUEUE_FN(this,
|
|
10752
|
+
await PROCESS_COMMIT_QUEUE_FN(this, currentPrice, currentTime);
|
|
10752
10753
|
// Check if scheduled signal was cancelled - emit cancelled event once
|
|
10753
10754
|
// NOTE: No _isStopped check here - cancellation must work for graceful shutdown
|
|
10754
10755
|
if (this._cancelledSignal) {
|
|
@@ -10934,7 +10935,7 @@ class ClientStrategy {
|
|
|
10934
10935
|
});
|
|
10935
10936
|
return await RETURN_IDLE_FN(this, currentPrice);
|
|
10936
10937
|
}
|
|
10937
|
-
await this.setPendingSignal(pendingSignal);
|
|
10938
|
+
await this.setPendingSignal(pendingSignal, currentPrice);
|
|
10938
10939
|
await CALL_RISK_ADD_SIGNAL_FN(this, this.params.execution.context.symbol, pendingSignal, currentTime, this.params.execution.context.backtest);
|
|
10939
10940
|
// Emit commit AFTER successful risk check
|
|
10940
10941
|
const publicSignalForCommit = TO_PUBLIC_SIGNAL("pending", pendingSignal, currentPrice);
|
|
@@ -11017,7 +11018,7 @@ class ClientStrategy {
|
|
|
11017
11018
|
await this.setScheduledSignal(signal);
|
|
11018
11019
|
return await OPEN_NEW_SCHEDULED_SIGNAL_FN(this, this._scheduledSignal);
|
|
11019
11020
|
}
|
|
11020
|
-
await this.setPendingSignal(signal);
|
|
11021
|
+
await this.setPendingSignal(signal, signal.priceOpen);
|
|
11021
11022
|
}
|
|
11022
11023
|
if (this._pendingSignal) {
|
|
11023
11024
|
const openResult = await OPEN_NEW_PENDING_SIGNAL_FN(this, this._pendingSignal);
|
|
@@ -11025,7 +11026,7 @@ class ClientStrategy {
|
|
|
11025
11026
|
return openResult;
|
|
11026
11027
|
}
|
|
11027
11028
|
// Risk rejected - clear pending signal and return idle
|
|
11028
|
-
await this.setPendingSignal(null);
|
|
11029
|
+
await this.setPendingSignal(null, this._pendingSignal.priceOpen);
|
|
11029
11030
|
}
|
|
11030
11031
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
11031
11032
|
return await RETURN_IDLE_FN(this, currentPrice);
|
|
@@ -11548,7 +11549,7 @@ class ClientStrategy {
|
|
|
11548
11549
|
this.params.logger.debug("ClientStrategy getStatus", { symbol });
|
|
11549
11550
|
return {
|
|
11550
11551
|
pendingSignalId: this._pendingSignal?.id ?? null,
|
|
11551
|
-
|
|
11552
|
+
createdSignal: this._userSignal,
|
|
11552
11553
|
commitQueue: this._commitQueue,
|
|
11553
11554
|
closedSignal: this._closedSignal,
|
|
11554
11555
|
cancelledSignal: this._cancelledSignal,
|
|
@@ -11723,7 +11724,7 @@ class ClientStrategy {
|
|
|
11723
11724
|
});
|
|
11724
11725
|
// Call onWrite callback for testing persist storage
|
|
11725
11726
|
if (this.params.callbacks?.onWrite) {
|
|
11726
|
-
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
|
|
11727
|
+
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), currentPrice, new Date(timestamp), backtest);
|
|
11727
11728
|
}
|
|
11728
11729
|
if (!backtest) {
|
|
11729
11730
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -11908,7 +11909,7 @@ class ClientStrategy {
|
|
|
11908
11909
|
});
|
|
11909
11910
|
// Call onWrite callback for testing persist storage
|
|
11910
11911
|
if (this.params.callbacks?.onWrite) {
|
|
11911
|
-
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
|
|
11912
|
+
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), currentPrice, new Date(timestamp), backtest);
|
|
11912
11913
|
}
|
|
11913
11914
|
if (!backtest) {
|
|
11914
11915
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12052,7 +12053,7 @@ class ClientStrategy {
|
|
|
12052
12053
|
* // Returns false (already at breakeven, no change)
|
|
12053
12054
|
* ```
|
|
12054
12055
|
*/
|
|
12055
|
-
async breakeven(symbol, currentPrice, backtest) {
|
|
12056
|
+
async breakeven(symbol, currentPrice, backtest, timestamp) {
|
|
12056
12057
|
this.params.logger.debug("ClientStrategy breakeven", {
|
|
12057
12058
|
symbol,
|
|
12058
12059
|
currentPrice,
|
|
@@ -12109,7 +12110,7 @@ class ClientStrategy {
|
|
|
12109
12110
|
// Call onWrite callback for testing persist storage
|
|
12110
12111
|
if (this.params.callbacks?.onWrite) {
|
|
12111
12112
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
|
|
12112
|
-
this.params.callbacks.onWrite(this.params.symbol, publicSignal, backtest);
|
|
12113
|
+
this.params.callbacks.onWrite(this.params.symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
12113
12114
|
}
|
|
12114
12115
|
if (!backtest) {
|
|
12115
12116
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12258,7 +12259,7 @@ class ClientStrategy {
|
|
|
12258
12259
|
* // success4 = false (SKIPPED: currentPrice (92) < newSL (95) - would trigger immediate stop)
|
|
12259
12260
|
* ```
|
|
12260
12261
|
*/
|
|
12261
|
-
async trailingStop(symbol, percentShift, currentPrice, backtest) {
|
|
12262
|
+
async trailingStop(symbol, percentShift, currentPrice, backtest, timestamp) {
|
|
12262
12263
|
this.params.logger.debug("ClientStrategy trailingStop", {
|
|
12263
12264
|
symbol,
|
|
12264
12265
|
percentShift,
|
|
@@ -12360,7 +12361,7 @@ class ClientStrategy {
|
|
|
12360
12361
|
// Call onWrite callback for testing persist storage
|
|
12361
12362
|
if (this.params.callbacks?.onWrite) {
|
|
12362
12363
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
|
|
12363
|
-
this.params.callbacks.onWrite(this.params.symbol, publicSignal, backtest);
|
|
12364
|
+
this.params.callbacks.onWrite(this.params.symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
12364
12365
|
}
|
|
12365
12366
|
if (!backtest) {
|
|
12366
12367
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12496,7 +12497,7 @@ class ClientStrategy {
|
|
|
12496
12497
|
* // success4 = true
|
|
12497
12498
|
* ```
|
|
12498
12499
|
*/
|
|
12499
|
-
async trailingTake(symbol, percentShift, currentPrice, backtest) {
|
|
12500
|
+
async trailingTake(symbol, percentShift, currentPrice, backtest, timestamp) {
|
|
12500
12501
|
this.params.logger.debug("ClientStrategy trailingTake", {
|
|
12501
12502
|
symbol,
|
|
12502
12503
|
percentShift,
|
|
@@ -12598,7 +12599,7 @@ class ClientStrategy {
|
|
|
12598
12599
|
// Call onWrite callback for testing persist storage
|
|
12599
12600
|
if (this.params.callbacks?.onWrite) {
|
|
12600
12601
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
|
|
12601
|
-
this.params.callbacks.onWrite(this.params.symbol, publicSignal, backtest);
|
|
12602
|
+
this.params.callbacks.onWrite(this.params.symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
12602
12603
|
}
|
|
12603
12604
|
if (!backtest) {
|
|
12604
12605
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12691,7 +12692,7 @@ class ClientStrategy {
|
|
|
12691
12692
|
});
|
|
12692
12693
|
// Call onWrite callback for testing persist storage
|
|
12693
12694
|
if (this.params.callbacks?.onWrite) {
|
|
12694
|
-
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
|
|
12695
|
+
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), currentPrice, new Date(timestamp), backtest);
|
|
12695
12696
|
}
|
|
12696
12697
|
if (!backtest) {
|
|
12697
12698
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -14514,7 +14515,8 @@ class StrategyConnectionService {
|
|
|
14514
14515
|
backtest,
|
|
14515
14516
|
});
|
|
14516
14517
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
14517
|
-
|
|
14518
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
14519
|
+
return await strategy.trailingStop(symbol, percentShift, currentPrice, backtest, timestamp);
|
|
14518
14520
|
};
|
|
14519
14521
|
/**
|
|
14520
14522
|
* Checks whether `trailingTake` would succeed without executing it.
|
|
@@ -14568,7 +14570,8 @@ class StrategyConnectionService {
|
|
|
14568
14570
|
backtest,
|
|
14569
14571
|
});
|
|
14570
14572
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
14571
|
-
|
|
14573
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
14574
|
+
return await strategy.trailingTake(symbol, percentShift, currentPrice, backtest, timestamp);
|
|
14572
14575
|
};
|
|
14573
14576
|
/**
|
|
14574
14577
|
* Checks whether `breakeven` would succeed without executing it.
|
|
@@ -14614,7 +14617,8 @@ class StrategyConnectionService {
|
|
|
14614
14617
|
backtest,
|
|
14615
14618
|
});
|
|
14616
14619
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
14617
|
-
|
|
14620
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
14621
|
+
return await strategy.breakeven(symbol, currentPrice, backtest, timestamp);
|
|
14618
14622
|
};
|
|
14619
14623
|
/**
|
|
14620
14624
|
* Activates a scheduled signal early without waiting for price to reach priceOpen.
|
|
@@ -20819,7 +20823,7 @@ class LiveLogicPrivateService {
|
|
|
20819
20823
|
});
|
|
20820
20824
|
}
|
|
20821
20825
|
catch (error) {
|
|
20822
|
-
console.warn(`
|
|
20826
|
+
console.warn(`liveLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
20823
20827
|
this.loggerService.warn("liveLogicPrivateService tick failed, retrying after sleep", {
|
|
20824
20828
|
symbol,
|
|
20825
20829
|
when: when.toISOString(),
|
package/build/index.mjs
CHANGED
|
@@ -7581,7 +7581,7 @@ const WAIT_FOR_INIT_FN$4 = async (self) => {
|
|
|
7581
7581
|
// an already-cleared _pendingSignal, and cancel/activate belong to the scheduled
|
|
7582
7582
|
// signal — none of them are tied to the currently-pending signal's id. A queued
|
|
7583
7583
|
// createSignal is a not-yet-consumed signal source and likewise stands on its own.
|
|
7584
|
-
self._userSignal = strategyData.
|
|
7584
|
+
self._userSignal = strategyData.createdSignal;
|
|
7585
7585
|
self._closedSignal = strategyData.closedSignal;
|
|
7586
7586
|
self._cancelledSignal = strategyData.cancelledSignal;
|
|
7587
7587
|
self._activatedSignal = strategyData.activatedSignal;
|
|
@@ -7660,7 +7660,7 @@ const PERSIST_STRATEGY_FN = async (self) => {
|
|
|
7660
7660
|
}
|
|
7661
7661
|
await PersistStrategyAdapter.writeStrategyData({
|
|
7662
7662
|
pendingSignalId: self._pendingSignal?.id ?? null,
|
|
7663
|
-
|
|
7663
|
+
createdSignal: self._userSignal,
|
|
7664
7664
|
commitQueue: self._commitQueue,
|
|
7665
7665
|
closedSignal: self._closedSignal,
|
|
7666
7666
|
cancelledSignal: self._cancelledSignal,
|
|
@@ -8345,7 +8345,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
8345
8345
|
return null;
|
|
8346
8346
|
}
|
|
8347
8347
|
await self.setScheduledSignal(null);
|
|
8348
|
-
await self.setPendingSignal(activatedSignal);
|
|
8348
|
+
await self.setPendingSignal(activatedSignal, activatedSignal.priceOpen);
|
|
8349
8349
|
await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
|
|
8350
8350
|
await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, self._pendingSignal, self._pendingSignal.priceOpen, activationTime, self.params.execution.context.backtest);
|
|
8351
8351
|
const result = {
|
|
@@ -8369,7 +8369,7 @@ const CALL_SCHEDULE_PING_CALLBACKS_FN = trycatch(beginTime(async (self, symbol,
|
|
|
8369
8369
|
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);
|
|
8370
8370
|
// Call user onSchedulePing callback only if signal is still active (not cancelled, not activated)
|
|
8371
8371
|
if (self.params.callbacks?.onSchedulePing) {
|
|
8372
|
-
await self.params.callbacks.onSchedulePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
|
|
8372
|
+
await self.params.callbacks.onSchedulePing(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8373
8373
|
}
|
|
8374
8374
|
}, {
|
|
8375
8375
|
when: new Date(timestamp),
|
|
@@ -8395,7 +8395,7 @@ const CALL_ACTIVE_PING_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, pe
|
|
|
8395
8395
|
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);
|
|
8396
8396
|
// Call user onActivePing callback only if signal is still active (not closed)
|
|
8397
8397
|
if (self.params.callbacks?.onActivePing) {
|
|
8398
|
-
await self.params.callbacks.onActivePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
|
|
8398
|
+
await self.params.callbacks.onActivePing(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8399
8399
|
}
|
|
8400
8400
|
}, {
|
|
8401
8401
|
when: new Date(timestamp),
|
|
@@ -8439,7 +8439,7 @@ const CALL_ACTIVE_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, signal,
|
|
|
8439
8439
|
await ExecutionContextService.runInContext(async () => {
|
|
8440
8440
|
if (self.params.callbacks?.onActive) {
|
|
8441
8441
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8442
|
-
await self.params.callbacks.onActive(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8442
|
+
await self.params.callbacks.onActive(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8443
8443
|
}
|
|
8444
8444
|
}, {
|
|
8445
8445
|
when: new Date(timestamp),
|
|
@@ -8462,7 +8462,7 @@ const CALL_SCHEDULE_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, signa
|
|
|
8462
8462
|
await ExecutionContextService.runInContext(async () => {
|
|
8463
8463
|
if (self.params.callbacks?.onSchedule) {
|
|
8464
8464
|
const publicSignal = TO_PUBLIC_SIGNAL("scheduled", signal, currentPrice);
|
|
8465
|
-
await self.params.callbacks.onSchedule(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8465
|
+
await self.params.callbacks.onSchedule(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8466
8466
|
}
|
|
8467
8467
|
}, {
|
|
8468
8468
|
when: new Date(timestamp),
|
|
@@ -8485,7 +8485,7 @@ const CALL_CANCEL_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, signal,
|
|
|
8485
8485
|
await ExecutionContextService.runInContext(async () => {
|
|
8486
8486
|
if (self.params.callbacks?.onCancel) {
|
|
8487
8487
|
const publicSignal = TO_PUBLIC_SIGNAL("scheduled", signal, currentPrice);
|
|
8488
|
-
await self.params.callbacks.onCancel(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8488
|
+
await self.params.callbacks.onCancel(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8489
8489
|
}
|
|
8490
8490
|
}, {
|
|
8491
8491
|
when: new Date(timestamp),
|
|
@@ -8508,7 +8508,7 @@ const CALL_OPEN_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, signal, p
|
|
|
8508
8508
|
await ExecutionContextService.runInContext(async () => {
|
|
8509
8509
|
if (self.params.callbacks?.onOpen) {
|
|
8510
8510
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, priceOpen);
|
|
8511
|
-
await self.params.callbacks.onOpen(self.params.execution.context.symbol, publicSignal, priceOpen, self.params.execution.context.backtest);
|
|
8511
|
+
await self.params.callbacks.onOpen(self.params.execution.context.symbol, publicSignal, priceOpen, new Date(timestamp), self.params.execution.context.backtest);
|
|
8512
8512
|
}
|
|
8513
8513
|
}, {
|
|
8514
8514
|
when: new Date(timestamp),
|
|
@@ -8531,7 +8531,7 @@ const CALL_CLOSE_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, signal,
|
|
|
8531
8531
|
await ExecutionContextService.runInContext(async () => {
|
|
8532
8532
|
if (self.params.callbacks?.onClose) {
|
|
8533
8533
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8534
|
-
await self.params.callbacks.onClose(self.params.execution.context.symbol, publicSignal, currentPrice, self.params.execution.context.backtest);
|
|
8534
|
+
await self.params.callbacks.onClose(self.params.execution.context.symbol, publicSignal, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8535
8535
|
}
|
|
8536
8536
|
}, {
|
|
8537
8537
|
when: new Date(timestamp),
|
|
@@ -8553,7 +8553,7 @@ const CALL_CLOSE_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, signal,
|
|
|
8553
8553
|
const CALL_TICK_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, result, timestamp, backtest) => {
|
|
8554
8554
|
await ExecutionContextService.runInContext(async () => {
|
|
8555
8555
|
if (self.params.callbacks?.onTick) {
|
|
8556
|
-
await self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
8556
|
+
await self.params.callbacks.onTick(self.params.execution.context.symbol, result, result.currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8557
8557
|
}
|
|
8558
8558
|
}, {
|
|
8559
8559
|
when: new Date(timestamp),
|
|
@@ -8575,7 +8575,7 @@ const CALL_TICK_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, result, t
|
|
|
8575
8575
|
const CALL_IDLE_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, currentPrice, timestamp, backtest) => {
|
|
8576
8576
|
await ExecutionContextService.runInContext(async () => {
|
|
8577
8577
|
if (self.params.callbacks?.onIdle) {
|
|
8578
|
-
await self.params.callbacks.onIdle(self.params.execution.context.symbol, currentPrice, self.params.execution.context.backtest);
|
|
8578
|
+
await self.params.callbacks.onIdle(self.params.execution.context.symbol, currentPrice, new Date(timestamp), self.params.execution.context.backtest);
|
|
8579
8579
|
}
|
|
8580
8580
|
}, {
|
|
8581
8581
|
when: new Date(timestamp),
|
|
@@ -8707,7 +8707,7 @@ const CALL_PARTIAL_PROFIT_CALLBACKS_FN = trycatch(beginTime(async (self, symbol,
|
|
|
8707
8707
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8708
8708
|
await self.params.partial.profit(symbol, publicSignal, currentPrice, percentTp, backtest, new Date(timestamp));
|
|
8709
8709
|
if (self.params.callbacks?.onPartialProfit) {
|
|
8710
|
-
await self.params.callbacks.onPartialProfit(symbol, publicSignal, currentPrice,
|
|
8710
|
+
await self.params.callbacks.onPartialProfit(symbol, publicSignal, percentTp, currentPrice, new Date(timestamp), backtest);
|
|
8711
8711
|
}
|
|
8712
8712
|
}, {
|
|
8713
8713
|
when: new Date(timestamp),
|
|
@@ -8731,7 +8731,7 @@ const CALL_PARTIAL_LOSS_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, s
|
|
|
8731
8731
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8732
8732
|
await self.params.partial.loss(symbol, publicSignal, currentPrice, percentSl, backtest, new Date(timestamp));
|
|
8733
8733
|
if (self.params.callbacks?.onPartialLoss) {
|
|
8734
|
-
await self.params.callbacks.onPartialLoss(symbol, publicSignal, currentPrice,
|
|
8734
|
+
await self.params.callbacks.onPartialLoss(symbol, publicSignal, percentSl, currentPrice, new Date(timestamp), backtest);
|
|
8735
8735
|
}
|
|
8736
8736
|
}, {
|
|
8737
8737
|
when: new Date(timestamp),
|
|
@@ -8755,7 +8755,7 @@ const CALL_BREAKEVEN_CHECK_FN = trycatch(beginTime(async (self, symbol, signal,
|
|
|
8755
8755
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8756
8756
|
const isBreakeven = await self.params.breakeven.check(symbol, publicSignal, currentPrice, backtest, new Date(timestamp));
|
|
8757
8757
|
if (self.params.callbacks?.onBreakeven) {
|
|
8758
|
-
isBreakeven && await self.params.callbacks.onBreakeven(symbol, publicSignal, currentPrice, backtest);
|
|
8758
|
+
isBreakeven && await self.params.callbacks.onBreakeven(symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
8759
8759
|
}
|
|
8760
8760
|
}, {
|
|
8761
8761
|
when: new Date(timestamp),
|
|
@@ -8958,7 +8958,7 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
|
|
|
8958
8958
|
// КРИТИЧНО: Очищаем состояние ClientBreakeven при закрытии позиции
|
|
8959
8959
|
await CALL_BREAKEVEN_CLEAR_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
|
|
8960
8960
|
await CALL_RISK_REMOVE_SIGNAL_FN(self, self.params.execution.context.symbol, currentTime, self.params.execution.context.backtest);
|
|
8961
|
-
await self.setPendingSignal(null);
|
|
8961
|
+
await self.setPendingSignal(null, currentPrice);
|
|
8962
8962
|
const result = {
|
|
8963
8963
|
action: "closed",
|
|
8964
8964
|
signal: publicSignal,
|
|
@@ -8996,7 +8996,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
8996
8996
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
8997
8997
|
signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
8998
8998
|
if (self.params.callbacks?.onWrite) {
|
|
8999
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
8999
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9000
9000
|
}
|
|
9001
9001
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9002
9002
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9016,7 +9016,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
9016
9016
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9017
9017
|
signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
9018
9018
|
if (self.params.callbacks?.onWrite) {
|
|
9019
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
9019
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9020
9020
|
}
|
|
9021
9021
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9022
9022
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9041,7 +9041,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
9041
9041
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9042
9042
|
signal._peak = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
9043
9043
|
if (self.params.callbacks?.onWrite) {
|
|
9044
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
9044
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9045
9045
|
}
|
|
9046
9046
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9047
9047
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9061,7 +9061,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backt
|
|
|
9061
9061
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9062
9062
|
signal._fall = { price: currentPrice, timestamp: currentTime, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceClose: pnl.priceClose, priceOpen: pnl.priceOpen };
|
|
9063
9063
|
if (self.params.callbacks?.onWrite) {
|
|
9064
|
-
self.params.callbacks.onWrite(signal.symbol, signal, backtest);
|
|
9064
|
+
self.params.callbacks.onWrite(signal.symbol, signal, currentPrice, new Date(currentTime), backtest);
|
|
9065
9065
|
}
|
|
9066
9066
|
!backtest && await PersistSignalAdapter.writeSignalData(signal, self.params.execution.context.symbol, self.params.strategyName, self.params.exchangeName);
|
|
9067
9067
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, currentPrice), currentPrice, currentTime);
|
|
@@ -9232,7 +9232,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
|
|
|
9232
9232
|
return false;
|
|
9233
9233
|
}
|
|
9234
9234
|
await self.setScheduledSignal(null);
|
|
9235
|
-
await self.setPendingSignal(activatedSignal);
|
|
9235
|
+
await self.setPendingSignal(activatedSignal, activatedSignal.priceOpen);
|
|
9236
9236
|
await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
|
|
9237
9237
|
await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, activatedSignal, activatedSignal.priceOpen, activationTime, self.params.execution.context.backtest);
|
|
9238
9238
|
await CALL_BACKTEST_SCHEDULE_OPEN_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
|
|
@@ -9270,7 +9270,7 @@ const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, c
|
|
|
9270
9270
|
// КРИТИЧНО: Очищаем состояние ClientBreakeven при закрытии позиции
|
|
9271
9271
|
await CALL_BREAKEVEN_CLEAR_FN(self, self.params.execution.context.symbol, signal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
|
|
9272
9272
|
await CALL_RISK_REMOVE_SIGNAL_FN(self, self.params.execution.context.symbol, closeTimestamp, self.params.execution.context.backtest);
|
|
9273
|
-
await self.setPendingSignal(null);
|
|
9273
|
+
await self.setPendingSignal(null, averagePrice);
|
|
9274
9274
|
const result = {
|
|
9275
9275
|
action: "closed",
|
|
9276
9276
|
signal: publicSignal,
|
|
@@ -9434,7 +9434,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
|
|
|
9434
9434
|
return { outcome: "pending" };
|
|
9435
9435
|
}
|
|
9436
9436
|
await self.setScheduledSignal(null);
|
|
9437
|
-
await self.setPendingSignal(pendingSignal);
|
|
9437
|
+
await self.setPendingSignal(pendingSignal, averagePrice);
|
|
9438
9438
|
await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, pendingSignal, candle.timestamp, self.params.execution.context.backtest);
|
|
9439
9439
|
// Emit commit AFTER successful risk check
|
|
9440
9440
|
const publicSignalForCommit = TO_PUBLIC_SIGNAL("pending", pendingSignal, averagePrice);
|
|
@@ -9640,7 +9640,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9640
9640
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9641
9641
|
signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9642
9642
|
if (self.params.callbacks?.onWrite) {
|
|
9643
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9643
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9644
9644
|
}
|
|
9645
9645
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9646
9646
|
}
|
|
@@ -9657,7 +9657,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9657
9657
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9658
9658
|
signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9659
9659
|
if (self.params.callbacks?.onWrite) {
|
|
9660
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9660
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9661
9661
|
}
|
|
9662
9662
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9663
9663
|
}
|
|
@@ -9680,7 +9680,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9680
9680
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9681
9681
|
signal._peak = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9682
9682
|
if (self.params.callbacks?.onWrite) {
|
|
9683
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9683
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9684
9684
|
}
|
|
9685
9685
|
await self.params.onHighestProfit(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9686
9686
|
}
|
|
@@ -9697,7 +9697,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles, frameEnd
|
|
|
9697
9697
|
const { pnl } = TO_PUBLIC_SIGNAL("pending", signal, averagePrice);
|
|
9698
9698
|
signal._fall = { price: averagePrice, timestamp: currentCandleTimestamp, pnlCost: pnl.pnlCost, pnlPercentage: pnl.pnlPercentage, pnlEntries: pnl.pnlEntries, priceOpen: pnl.priceOpen, priceClose: pnl.priceClose };
|
|
9699
9699
|
if (self.params.callbacks?.onWrite) {
|
|
9700
|
-
self.params.callbacks.onWrite(signal.symbol, signal, true);
|
|
9700
|
+
self.params.callbacks.onWrite(signal.symbol, signal, averagePrice, new Date(currentCandleTimestamp), true);
|
|
9701
9701
|
}
|
|
9702
9702
|
await self.params.onMaxDrawdown(TO_PUBLIC_SIGNAL("pending", signal, averagePrice), averagePrice, currentCandleTimestamp);
|
|
9703
9703
|
}
|
|
@@ -9858,9 +9858,10 @@ class ClientStrategy {
|
|
|
9858
9858
|
* Uses atomic file writes to prevent corruption.
|
|
9859
9859
|
*
|
|
9860
9860
|
* @param pendingSignal - New signal state (null to clear)
|
|
9861
|
+
* @param currentPrice - Current market price (forwarded to the onWrite callback)
|
|
9861
9862
|
* @returns Promise that resolves when update is complete
|
|
9862
9863
|
*/
|
|
9863
|
-
async setPendingSignal(pendingSignal) {
|
|
9864
|
+
async setPendingSignal(pendingSignal, currentPrice) {
|
|
9864
9865
|
this.params.logger.debug("ClientStrategy setPendingSignal", {
|
|
9865
9866
|
pendingSignal,
|
|
9866
9867
|
});
|
|
@@ -9879,7 +9880,7 @@ class ClientStrategy {
|
|
|
9879
9880
|
// даже в backtest режиме, чтобы тесты могли перехватывать вызовы через mock adapter
|
|
9880
9881
|
if (this.params.callbacks?.onWrite) {
|
|
9881
9882
|
const publicSignal = this._pendingSignal ? this._pendingSignal : null;
|
|
9882
|
-
this.params.callbacks.onWrite(this.params.execution.context.symbol, publicSignal, this.params.execution.context.backtest);
|
|
9883
|
+
this.params.callbacks.onWrite(this.params.execution.context.symbol, publicSignal, currentPrice, this.params.execution.context.when, this.params.execution.context.backtest);
|
|
9883
9884
|
}
|
|
9884
9885
|
if (this.params.execution.context.backtest) {
|
|
9885
9886
|
return;
|
|
@@ -10728,7 +10729,7 @@ class ClientStrategy {
|
|
|
10728
10729
|
const currentTime = this.params.execution.context.when.getTime();
|
|
10729
10730
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
10730
10731
|
// Process queued commit events with proper timestamp
|
|
10731
|
-
await PROCESS_COMMIT_QUEUE_FN(this,
|
|
10732
|
+
await PROCESS_COMMIT_QUEUE_FN(this, currentPrice, currentTime);
|
|
10732
10733
|
// Check if scheduled signal was cancelled - emit cancelled event once
|
|
10733
10734
|
// NOTE: No _isStopped check here - cancellation must work for graceful shutdown
|
|
10734
10735
|
if (this._cancelledSignal) {
|
|
@@ -10914,7 +10915,7 @@ class ClientStrategy {
|
|
|
10914
10915
|
});
|
|
10915
10916
|
return await RETURN_IDLE_FN(this, currentPrice);
|
|
10916
10917
|
}
|
|
10917
|
-
await this.setPendingSignal(pendingSignal);
|
|
10918
|
+
await this.setPendingSignal(pendingSignal, currentPrice);
|
|
10918
10919
|
await CALL_RISK_ADD_SIGNAL_FN(this, this.params.execution.context.symbol, pendingSignal, currentTime, this.params.execution.context.backtest);
|
|
10919
10920
|
// Emit commit AFTER successful risk check
|
|
10920
10921
|
const publicSignalForCommit = TO_PUBLIC_SIGNAL("pending", pendingSignal, currentPrice);
|
|
@@ -10997,7 +10998,7 @@ class ClientStrategy {
|
|
|
10997
10998
|
await this.setScheduledSignal(signal);
|
|
10998
10999
|
return await OPEN_NEW_SCHEDULED_SIGNAL_FN(this, this._scheduledSignal);
|
|
10999
11000
|
}
|
|
11000
|
-
await this.setPendingSignal(signal);
|
|
11001
|
+
await this.setPendingSignal(signal, signal.priceOpen);
|
|
11001
11002
|
}
|
|
11002
11003
|
if (this._pendingSignal) {
|
|
11003
11004
|
const openResult = await OPEN_NEW_PENDING_SIGNAL_FN(this, this._pendingSignal);
|
|
@@ -11005,7 +11006,7 @@ class ClientStrategy {
|
|
|
11005
11006
|
return openResult;
|
|
11006
11007
|
}
|
|
11007
11008
|
// Risk rejected - clear pending signal and return idle
|
|
11008
|
-
await this.setPendingSignal(null);
|
|
11009
|
+
await this.setPendingSignal(null, this._pendingSignal.priceOpen);
|
|
11009
11010
|
}
|
|
11010
11011
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
11011
11012
|
return await RETURN_IDLE_FN(this, currentPrice);
|
|
@@ -11528,7 +11529,7 @@ class ClientStrategy {
|
|
|
11528
11529
|
this.params.logger.debug("ClientStrategy getStatus", { symbol });
|
|
11529
11530
|
return {
|
|
11530
11531
|
pendingSignalId: this._pendingSignal?.id ?? null,
|
|
11531
|
-
|
|
11532
|
+
createdSignal: this._userSignal,
|
|
11532
11533
|
commitQueue: this._commitQueue,
|
|
11533
11534
|
closedSignal: this._closedSignal,
|
|
11534
11535
|
cancelledSignal: this._cancelledSignal,
|
|
@@ -11703,7 +11704,7 @@ class ClientStrategy {
|
|
|
11703
11704
|
});
|
|
11704
11705
|
// Call onWrite callback for testing persist storage
|
|
11705
11706
|
if (this.params.callbacks?.onWrite) {
|
|
11706
|
-
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
|
|
11707
|
+
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), currentPrice, new Date(timestamp), backtest);
|
|
11707
11708
|
}
|
|
11708
11709
|
if (!backtest) {
|
|
11709
11710
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -11888,7 +11889,7 @@ class ClientStrategy {
|
|
|
11888
11889
|
});
|
|
11889
11890
|
// Call onWrite callback for testing persist storage
|
|
11890
11891
|
if (this.params.callbacks?.onWrite) {
|
|
11891
|
-
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
|
|
11892
|
+
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), currentPrice, new Date(timestamp), backtest);
|
|
11892
11893
|
}
|
|
11893
11894
|
if (!backtest) {
|
|
11894
11895
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12032,7 +12033,7 @@ class ClientStrategy {
|
|
|
12032
12033
|
* // Returns false (already at breakeven, no change)
|
|
12033
12034
|
* ```
|
|
12034
12035
|
*/
|
|
12035
|
-
async breakeven(symbol, currentPrice, backtest) {
|
|
12036
|
+
async breakeven(symbol, currentPrice, backtest, timestamp) {
|
|
12036
12037
|
this.params.logger.debug("ClientStrategy breakeven", {
|
|
12037
12038
|
symbol,
|
|
12038
12039
|
currentPrice,
|
|
@@ -12089,7 +12090,7 @@ class ClientStrategy {
|
|
|
12089
12090
|
// Call onWrite callback for testing persist storage
|
|
12090
12091
|
if (this.params.callbacks?.onWrite) {
|
|
12091
12092
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
|
|
12092
|
-
this.params.callbacks.onWrite(this.params.symbol, publicSignal, backtest);
|
|
12093
|
+
this.params.callbacks.onWrite(this.params.symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
12093
12094
|
}
|
|
12094
12095
|
if (!backtest) {
|
|
12095
12096
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12238,7 +12239,7 @@ class ClientStrategy {
|
|
|
12238
12239
|
* // success4 = false (SKIPPED: currentPrice (92) < newSL (95) - would trigger immediate stop)
|
|
12239
12240
|
* ```
|
|
12240
12241
|
*/
|
|
12241
|
-
async trailingStop(symbol, percentShift, currentPrice, backtest) {
|
|
12242
|
+
async trailingStop(symbol, percentShift, currentPrice, backtest, timestamp) {
|
|
12242
12243
|
this.params.logger.debug("ClientStrategy trailingStop", {
|
|
12243
12244
|
symbol,
|
|
12244
12245
|
percentShift,
|
|
@@ -12340,7 +12341,7 @@ class ClientStrategy {
|
|
|
12340
12341
|
// Call onWrite callback for testing persist storage
|
|
12341
12342
|
if (this.params.callbacks?.onWrite) {
|
|
12342
12343
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
|
|
12343
|
-
this.params.callbacks.onWrite(this.params.symbol, publicSignal, backtest);
|
|
12344
|
+
this.params.callbacks.onWrite(this.params.symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
12344
12345
|
}
|
|
12345
12346
|
if (!backtest) {
|
|
12346
12347
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12476,7 +12477,7 @@ class ClientStrategy {
|
|
|
12476
12477
|
* // success4 = true
|
|
12477
12478
|
* ```
|
|
12478
12479
|
*/
|
|
12479
|
-
async trailingTake(symbol, percentShift, currentPrice, backtest) {
|
|
12480
|
+
async trailingTake(symbol, percentShift, currentPrice, backtest, timestamp) {
|
|
12480
12481
|
this.params.logger.debug("ClientStrategy trailingTake", {
|
|
12481
12482
|
symbol,
|
|
12482
12483
|
percentShift,
|
|
@@ -12578,7 +12579,7 @@ class ClientStrategy {
|
|
|
12578
12579
|
// Call onWrite callback for testing persist storage
|
|
12579
12580
|
if (this.params.callbacks?.onWrite) {
|
|
12580
12581
|
const publicSignal = TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice);
|
|
12581
|
-
this.params.callbacks.onWrite(this.params.symbol, publicSignal, backtest);
|
|
12582
|
+
this.params.callbacks.onWrite(this.params.symbol, publicSignal, currentPrice, new Date(timestamp), backtest);
|
|
12582
12583
|
}
|
|
12583
12584
|
if (!backtest) {
|
|
12584
12585
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -12671,7 +12672,7 @@ class ClientStrategy {
|
|
|
12671
12672
|
});
|
|
12672
12673
|
// Call onWrite callback for testing persist storage
|
|
12673
12674
|
if (this.params.callbacks?.onWrite) {
|
|
12674
|
-
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), backtest);
|
|
12675
|
+
this.params.callbacks.onWrite(this.params.symbol, TO_PUBLIC_SIGNAL("pending", this._pendingSignal, currentPrice), currentPrice, new Date(timestamp), backtest);
|
|
12675
12676
|
}
|
|
12676
12677
|
if (!backtest) {
|
|
12677
12678
|
await PersistSignalAdapter.writeSignalData(this._pendingSignal, this.params.symbol, this.params.strategyName, this.params.exchangeName);
|
|
@@ -14494,7 +14495,8 @@ class StrategyConnectionService {
|
|
|
14494
14495
|
backtest,
|
|
14495
14496
|
});
|
|
14496
14497
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
14497
|
-
|
|
14498
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
14499
|
+
return await strategy.trailingStop(symbol, percentShift, currentPrice, backtest, timestamp);
|
|
14498
14500
|
};
|
|
14499
14501
|
/**
|
|
14500
14502
|
* Checks whether `trailingTake` would succeed without executing it.
|
|
@@ -14548,7 +14550,8 @@ class StrategyConnectionService {
|
|
|
14548
14550
|
backtest,
|
|
14549
14551
|
});
|
|
14550
14552
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
14551
|
-
|
|
14553
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
14554
|
+
return await strategy.trailingTake(symbol, percentShift, currentPrice, backtest, timestamp);
|
|
14552
14555
|
};
|
|
14553
14556
|
/**
|
|
14554
14557
|
* Checks whether `breakeven` would succeed without executing it.
|
|
@@ -14594,7 +14597,8 @@ class StrategyConnectionService {
|
|
|
14594
14597
|
backtest,
|
|
14595
14598
|
});
|
|
14596
14599
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
14597
|
-
|
|
14600
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
14601
|
+
return await strategy.breakeven(symbol, currentPrice, backtest, timestamp);
|
|
14598
14602
|
};
|
|
14599
14603
|
/**
|
|
14600
14604
|
* Activates a scheduled signal early without waiting for price to reach priceOpen.
|
|
@@ -20799,7 +20803,7 @@ class LiveLogicPrivateService {
|
|
|
20799
20803
|
});
|
|
20800
20804
|
}
|
|
20801
20805
|
catch (error) {
|
|
20802
|
-
console.warn(`
|
|
20806
|
+
console.warn(`liveLogicPrivateService tick failed when=${when.toISOString()} symbol=${symbol} strategyName=${this.methodContextService.context.strategyName} exchangeName=${this.methodContextService.context.exchangeName}`);
|
|
20803
20807
|
this.loggerService.warn("liveLogicPrivateService tick failed, retrying after sleep", {
|
|
20804
20808
|
symbol,
|
|
20805
20809
|
when: when.toISOString(),
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -2442,7 +2442,7 @@ type StrategyStatus = {
|
|
|
2442
2442
|
* of params.getSignal (set via createPending / createScheduled), or null if none queued.
|
|
2443
2443
|
* createPending and createScheduled overwrite the same slot, so only the latest wins.
|
|
2444
2444
|
*/
|
|
2445
|
-
|
|
2445
|
+
createdSignal: ISignalDto | null;
|
|
2446
2446
|
/** Queued commit events (average-buy / partial-* / trailing-* / breakeven) not yet drained */
|
|
2447
2447
|
commitQueue: ICommitRow[];
|
|
2448
2448
|
/** Deferred user-initiated close (closePending), or null if none pending */
|
|
@@ -2902,31 +2902,31 @@ type ICommitRow = IPartialProfitCommitRow | IPartialLossCommitRow | IBreakevenCo
|
|
|
2902
2902
|
*/
|
|
2903
2903
|
interface IStrategyCallbacks {
|
|
2904
2904
|
/** Called on every tick with the result */
|
|
2905
|
-
onTick: (symbol: string, result: IStrategyTickResult, backtest: boolean) => void | Promise<void>;
|
|
2905
|
+
onTick: (symbol: string, result: IStrategyTickResult, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2906
2906
|
/** Called when new signal is opened (after validation) */
|
|
2907
|
-
onOpen: (symbol: string, data: IPublicSignalRow, currentPrice: number, backtest: boolean) => void | Promise<void>;
|
|
2907
|
+
onOpen: (symbol: string, data: IPublicSignalRow, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2908
2908
|
/** Called when signal is being monitored (active state) */
|
|
2909
|
-
onActive: (symbol: string, data: IPublicSignalRow, currentPrice: number, backtest: boolean) => void | Promise<void>;
|
|
2909
|
+
onActive: (symbol: string, data: IPublicSignalRow, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2910
2910
|
/** Called when no active signal exists (idle state) */
|
|
2911
|
-
onIdle: (symbol: string, currentPrice: number, backtest: boolean) => void | Promise<void>;
|
|
2911
|
+
onIdle: (symbol: string, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2912
2912
|
/** Called when signal is closed with final price */
|
|
2913
|
-
onClose: (symbol: string, data: IPublicSignalRow, priceClose: number, backtest: boolean) => void | Promise<void>;
|
|
2913
|
+
onClose: (symbol: string, data: IPublicSignalRow, priceClose: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2914
2914
|
/** Called when scheduled signal is created (delayed entry) */
|
|
2915
|
-
onSchedule: (symbol: string, data: IPublicSignalRow, currentPrice: number, backtest: boolean) => void | Promise<void>;
|
|
2915
|
+
onSchedule: (symbol: string, data: IPublicSignalRow, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2916
2916
|
/** Called when scheduled signal is cancelled without opening position */
|
|
2917
|
-
onCancel: (symbol: string, data: IPublicSignalRow, currentPrice: number, backtest: boolean) => void | Promise<void>;
|
|
2918
|
-
/** Called when signal is written to persist storage (for testing) */
|
|
2919
|
-
onWrite: (symbol: string, data: ISignalRow | null, backtest: boolean) => void;
|
|
2917
|
+
onCancel: (symbol: string, data: IPublicSignalRow, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2918
|
+
/** Called when signal is written to persist storage (for testing, backtest only) */
|
|
2919
|
+
onWrite: (symbol: string, data: ISignalRow | null, currentPrice: number, when: Date, backtest: boolean) => void;
|
|
2920
2920
|
/** Called when signal is in partial profit state (price moved favorably but not reached TP yet) */
|
|
2921
|
-
onPartialProfit: (symbol: string, data: IPublicSignalRow,
|
|
2921
|
+
onPartialProfit: (symbol: string, data: IPublicSignalRow, revenuePercent: number, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2922
2922
|
/** Called when signal is in partial loss state (price moved against position but not hit SL yet) */
|
|
2923
|
-
onPartialLoss: (symbol: string, data: IPublicSignalRow,
|
|
2923
|
+
onPartialLoss: (symbol: string, data: IPublicSignalRow, lossPercent: number, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2924
2924
|
/** Called when signal reaches breakeven (stop-loss moved to entry price to protect capital) */
|
|
2925
|
-
onBreakeven: (symbol: string, data: IPublicSignalRow, currentPrice: number, backtest: boolean) => void | Promise<void>;
|
|
2925
|
+
onBreakeven: (symbol: string, data: IPublicSignalRow, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2926
2926
|
/** Called every minute for scheduled signals regardless of strategy interval (for custom monitoring like checking if signal should be cancelled) */
|
|
2927
|
-
onSchedulePing: (symbol: string, data: IPublicSignalRow, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2927
|
+
onSchedulePing: (symbol: string, data: IPublicSignalRow, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2928
2928
|
/** Called every minute for active pending signals regardless of strategy interval (for custom monitoring and dynamic management) */
|
|
2929
|
-
onActivePing: (symbol: string, data: IPublicSignalRow, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2929
|
+
onActivePing: (symbol: string, data: IPublicSignalRow, currentPrice: number, when: Date, backtest: boolean) => void | Promise<void>;
|
|
2930
2930
|
}
|
|
2931
2931
|
/**
|
|
2932
2932
|
* Strategy schema registered via addStrategy().
|
|
@@ -3656,7 +3656,7 @@ interface IStrategy {
|
|
|
3656
3656
|
* }
|
|
3657
3657
|
* ```
|
|
3658
3658
|
*/
|
|
3659
|
-
trailingStop: (symbol: string, percentShift: number, currentPrice: number, backtest: boolean) => Promise<boolean>;
|
|
3659
|
+
trailingStop: (symbol: string, percentShift: number, currentPrice: number, backtest: boolean, timestamp: number) => Promise<boolean>;
|
|
3660
3660
|
/**
|
|
3661
3661
|
* Checks whether `trailingStop` would succeed without executing it.
|
|
3662
3662
|
*
|
|
@@ -3724,7 +3724,7 @@ interface IStrategy {
|
|
|
3724
3724
|
* }
|
|
3725
3725
|
* ```
|
|
3726
3726
|
*/
|
|
3727
|
-
trailingTake: (symbol: string, percentShift: number, currentPrice: number, backtest: boolean) => Promise<boolean>;
|
|
3727
|
+
trailingTake: (symbol: string, percentShift: number, currentPrice: number, backtest: boolean, timestamp: number) => Promise<boolean>;
|
|
3728
3728
|
/**
|
|
3729
3729
|
* Checks whether `trailingTake` would succeed without executing it.
|
|
3730
3730
|
*
|
|
@@ -3794,7 +3794,7 @@ interface IStrategy {
|
|
|
3794
3794
|
* }
|
|
3795
3795
|
* ```
|
|
3796
3796
|
*/
|
|
3797
|
-
breakeven: (symbol: string, currentPrice: number, backtest: boolean) => Promise<boolean>;
|
|
3797
|
+
breakeven: (symbol: string, currentPrice: number, backtest: boolean, timestamp: number) => Promise<boolean>;
|
|
3798
3798
|
/**
|
|
3799
3799
|
* Checks whether `breakeven` would succeed without executing it.
|
|
3800
3800
|
*
|
|
@@ -14228,7 +14228,7 @@ type StrategyData = {
|
|
|
14228
14228
|
* of params.getSignal (set via createPending / createScheduled), or null if none queued.
|
|
14229
14229
|
* createPending and createScheduled overwrite the same slot, so only the latest wins.
|
|
14230
14230
|
*/
|
|
14231
|
-
|
|
14231
|
+
createdSignal: ISignalDto | null;
|
|
14232
14232
|
/** Queued commit events (average-buy / partial-* / trailing-* / breakeven) not yet drained */
|
|
14233
14233
|
commitQueue: ICommitRow[];
|
|
14234
14234
|
/** Deferred user-initiated close (closePending), or null if none pending */
|