backtest-kit 6.11.0 → 6.12.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 +1154 -98
- package/build/index.mjs +1152 -99
- package/package.json +2 -2
- package/types.d.ts +944 -194
package/build/index.mjs
CHANGED
|
@@ -6573,7 +6573,7 @@ const RETURN_IDLE_FN = async (self, currentPrice) => {
|
|
|
6573
6573
|
await CALL_TICK_CALLBACKS_FN(self, self.params.execution.context.symbol, result, currentTime, self.params.execution.context.backtest);
|
|
6574
6574
|
return result;
|
|
6575
6575
|
};
|
|
6576
|
-
const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp, reason, cancelId) => {
|
|
6576
|
+
const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp, reason, cancelId, cancelNote) => {
|
|
6577
6577
|
self.params.logger.info("ClientStrategy backtest scheduled signal cancelled", {
|
|
6578
6578
|
symbol: self.params.execution.context.symbol,
|
|
6579
6579
|
signalId: scheduled.id,
|
|
@@ -6598,7 +6598,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
|
|
|
6598
6598
|
totalPartials: scheduled._partial?.length ?? 0,
|
|
6599
6599
|
originalPriceOpen: scheduled.priceOpen,
|
|
6600
6600
|
pnl: toProfitLossDto(scheduled, averagePrice),
|
|
6601
|
-
note: scheduled.note,
|
|
6601
|
+
note: cancelNote ?? scheduled.note,
|
|
6602
6602
|
});
|
|
6603
6603
|
}
|
|
6604
6604
|
await CALL_CANCEL_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, averagePrice, closeTimestamp, self.params.execution.context.backtest);
|
|
@@ -6765,7 +6765,7 @@ const CLOSE_USER_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, closedSignal, aver
|
|
|
6765
6765
|
totalPartials: closedSignal._partial?.length ?? 0,
|
|
6766
6766
|
originalPriceOpen: closedSignal.priceOpen,
|
|
6767
6767
|
pnl: toProfitLossDto(closedSignal, averagePrice),
|
|
6768
|
-
note: closedSignal.note,
|
|
6768
|
+
note: closedSignal.closeNote ?? closedSignal.note,
|
|
6769
6769
|
});
|
|
6770
6770
|
await CALL_CLOSE_CALLBACKS_FN(self, self.params.execution.context.symbol, closedSignal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
|
|
6771
6771
|
await CALL_PARTIAL_CLEAR_FN(self, self.params.execution.context.symbol, closedSignal, averagePrice, closeTimestamp, self.params.execution.context.backtest);
|
|
@@ -6812,7 +6812,8 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
|
|
|
6812
6812
|
if (self._cancelledSignal) {
|
|
6813
6813
|
// Сигнал был отменен через cancel() в onSchedulePing
|
|
6814
6814
|
const cancelId = self._cancelledSignal.cancelId;
|
|
6815
|
-
const
|
|
6815
|
+
const cancelNote = self._cancelledSignal.cancelNote;
|
|
6816
|
+
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "user", cancelId, cancelNote);
|
|
6816
6817
|
return { outcome: "cancelled", result };
|
|
6817
6818
|
}
|
|
6818
6819
|
// КРИТИЧНО: Проверяем был ли сигнал активирован пользователем через activateScheduled()
|
|
@@ -6866,7 +6867,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
|
|
|
6866
6867
|
totalPartials: activatedSignal._partial?.length ?? 0,
|
|
6867
6868
|
originalPriceOpen: activatedSignal.priceOpen,
|
|
6868
6869
|
pnl: toProfitLossDto(activatedSignal, averagePrice),
|
|
6869
|
-
note: activatedSignal.note,
|
|
6870
|
+
note: activatedSignal.activateNote ?? activatedSignal.note,
|
|
6870
6871
|
});
|
|
6871
6872
|
return { outcome: "pending" };
|
|
6872
6873
|
}
|
|
@@ -6898,7 +6899,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
|
|
|
6898
6899
|
pendingAt: publicSignalForCommit.pendingAt,
|
|
6899
6900
|
totalEntries: publicSignalForCommit.totalEntries,
|
|
6900
6901
|
totalPartials: publicSignalForCommit.totalPartials,
|
|
6901
|
-
note: publicSignalForCommit.note,
|
|
6902
|
+
note: activatedSignal.activateNote ?? publicSignalForCommit.note,
|
|
6902
6903
|
});
|
|
6903
6904
|
await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, pendingSignal, pendingSignal.priceOpen, candle.timestamp, self.params.execution.context.backtest);
|
|
6904
6905
|
await CALL_BACKTEST_SCHEDULE_OPEN_FN(self, self.params.execution.context.symbol, pendingSignal, candle.timestamp, self.params.execution.context.backtest);
|
|
@@ -8019,6 +8020,44 @@ class ClientStrategy {
|
|
|
8019
8020
|
const currentPnl = toProfitLossDto(this._pendingSignal, currentPrice);
|
|
8020
8021
|
return Math.max(0, currentPnl.pnlCost - this._pendingSignal._fall.pnlCost);
|
|
8021
8022
|
}
|
|
8023
|
+
/**
|
|
8024
|
+
* Returns the peak-to-trough PnL percentage distance between the position's highest profit and deepest drawdown.
|
|
8025
|
+
*
|
|
8026
|
+
* Measures the total swing from the stored `_peak.pnlPercentage` to the stored `_fall.pnlPercentage`.
|
|
8027
|
+
* Computed as: max(0, peakPnlPercentage - fallPnlPercentage).
|
|
8028
|
+
*
|
|
8029
|
+
* Returns null if no pending signal exists.
|
|
8030
|
+
*
|
|
8031
|
+
* @param symbol - Trading pair symbol
|
|
8032
|
+
* @param currentPrice - Current market price
|
|
8033
|
+
* @returns Promise resolving to peak-to-trough PnL percentage distance (≥ 0) or null
|
|
8034
|
+
*/
|
|
8035
|
+
async getMaxDrawdownDistancePnlPercentage(symbol, currentPrice) {
|
|
8036
|
+
this.params.logger.debug("ClientStrategy getMaxDrawdownDistancePnlPercentage", { symbol, currentPrice });
|
|
8037
|
+
if (!this._pendingSignal) {
|
|
8038
|
+
return null;
|
|
8039
|
+
}
|
|
8040
|
+
return Math.max(0, this._pendingSignal._peak.pnlPercentage - this._pendingSignal._fall.pnlPercentage);
|
|
8041
|
+
}
|
|
8042
|
+
/**
|
|
8043
|
+
* Returns the peak-to-trough PnL cost distance between the position's highest profit and deepest drawdown.
|
|
8044
|
+
*
|
|
8045
|
+
* Measures the total swing from the stored `_peak.pnlCost` to the stored `_fall.pnlCost`.
|
|
8046
|
+
* Computed as: max(0, peakPnlCost - fallPnlCost).
|
|
8047
|
+
*
|
|
8048
|
+
* Returns null if no pending signal exists.
|
|
8049
|
+
*
|
|
8050
|
+
* @param symbol - Trading pair symbol
|
|
8051
|
+
* @param currentPrice - Current market price
|
|
8052
|
+
* @returns Promise resolving to peak-to-trough PnL cost distance (≥ 0) or null
|
|
8053
|
+
*/
|
|
8054
|
+
async getMaxDrawdownDistancePnlCost(symbol, currentPrice) {
|
|
8055
|
+
this.params.logger.debug("ClientStrategy getMaxDrawdownDistancePnlCost", { symbol, currentPrice });
|
|
8056
|
+
if (!this._pendingSignal) {
|
|
8057
|
+
return null;
|
|
8058
|
+
}
|
|
8059
|
+
return Math.max(0, this._pendingSignal._peak.pnlCost - this._pendingSignal._fall.pnlCost);
|
|
8060
|
+
}
|
|
8022
8061
|
/**
|
|
8023
8062
|
* Performs a single tick of strategy execution.
|
|
8024
8063
|
*
|
|
@@ -8083,7 +8122,7 @@ class ClientStrategy {
|
|
|
8083
8122
|
totalPartials: cancelledSignal._partial?.length ?? 0,
|
|
8084
8123
|
originalPriceOpen: cancelledSignal.priceOpen,
|
|
8085
8124
|
pnl: toProfitLossDto(cancelledSignal, currentPrice),
|
|
8086
|
-
note: cancelledSignal.note,
|
|
8125
|
+
note: cancelledSignal.cancelNote ?? cancelledSignal.note,
|
|
8087
8126
|
});
|
|
8088
8127
|
// Call onCancel callback
|
|
8089
8128
|
await CALL_CANCEL_CALLBACKS_FN(this, this.params.execution.context.symbol, cancelledSignal, currentPrice, currentTime, this.params.execution.context.backtest);
|
|
@@ -8137,7 +8176,7 @@ class ClientStrategy {
|
|
|
8137
8176
|
totalPartials: closedSignal._partial?.length ?? 0,
|
|
8138
8177
|
originalPriceOpen: closedSignal.priceOpen,
|
|
8139
8178
|
pnl: toProfitLossDto(closedSignal, currentPrice),
|
|
8140
|
-
note: closedSignal.note,
|
|
8179
|
+
note: closedSignal.closeNote ?? closedSignal.note,
|
|
8141
8180
|
});
|
|
8142
8181
|
// Call onClose callback
|
|
8143
8182
|
await CALL_CLOSE_CALLBACKS_FN(this, this.params.execution.context.symbol, closedSignal, currentPrice, currentTime, this.params.execution.context.backtest);
|
|
@@ -8219,7 +8258,7 @@ class ClientStrategy {
|
|
|
8219
8258
|
totalPartials: activatedSignal._partial?.length ?? 0,
|
|
8220
8259
|
originalPriceOpen: activatedSignal.priceOpen,
|
|
8221
8260
|
pnl: toProfitLossDto(activatedSignal, currentPrice),
|
|
8222
|
-
note: activatedSignal.note,
|
|
8261
|
+
note: activatedSignal.activateNote ?? activatedSignal.note,
|
|
8223
8262
|
});
|
|
8224
8263
|
return await RETURN_IDLE_FN(this, currentPrice);
|
|
8225
8264
|
}
|
|
@@ -8250,7 +8289,7 @@ class ClientStrategy {
|
|
|
8250
8289
|
pendingAt: publicSignalForCommit.pendingAt,
|
|
8251
8290
|
totalEntries: publicSignalForCommit.totalEntries,
|
|
8252
8291
|
totalPartials: publicSignalForCommit.totalPartials,
|
|
8253
|
-
note: publicSignalForCommit.note,
|
|
8292
|
+
note: activatedSignal.activateNote ?? publicSignalForCommit.note,
|
|
8254
8293
|
});
|
|
8255
8294
|
// Call onOpen callback
|
|
8256
8295
|
await CALL_OPEN_CALLBACKS_FN(this, this.params.execution.context.symbol, pendingSignal, currentPrice, currentTime, this.params.execution.context.backtest);
|
|
@@ -8386,7 +8425,7 @@ class ClientStrategy {
|
|
|
8386
8425
|
totalPartials: cancelledSignal._partial?.length ?? 0,
|
|
8387
8426
|
originalPriceOpen: cancelledSignal.priceOpen,
|
|
8388
8427
|
pnl: toProfitLossDto(cancelledSignal, currentPrice),
|
|
8389
|
-
note: cancelledSignal.note,
|
|
8428
|
+
note: cancelledSignal.cancelNote ?? cancelledSignal.note,
|
|
8390
8429
|
});
|
|
8391
8430
|
await CALL_CANCEL_CALLBACKS_FN(this, this.params.execution.context.symbol, cancelledSignal, currentPrice, closeTimestamp, this.params.execution.context.backtest);
|
|
8392
8431
|
const cancelledResult = {
|
|
@@ -8441,7 +8480,7 @@ class ClientStrategy {
|
|
|
8441
8480
|
totalPartials: closedSignal._partial?.length ?? 0,
|
|
8442
8481
|
originalPriceOpen: closedSignal.priceOpen,
|
|
8443
8482
|
pnl: toProfitLossDto(closedSignal, currentPrice),
|
|
8444
|
-
note: closedSignal.note,
|
|
8483
|
+
note: closedSignal.closeNote ?? closedSignal.note,
|
|
8445
8484
|
});
|
|
8446
8485
|
await CALL_CLOSE_CALLBACKS_FN(this, this.params.execution.context.symbol, closedSignal, currentPrice, closeTimestamp, this.params.execution.context.backtest);
|
|
8447
8486
|
// КРИТИЧНО: Очищаем состояние ClientPartial при закрытии позиции
|
|
@@ -8625,7 +8664,8 @@ class ClientStrategy {
|
|
|
8625
8664
|
* // Strategy continues, can generate new signals
|
|
8626
8665
|
* ```
|
|
8627
8666
|
*/
|
|
8628
|
-
async cancelScheduled(symbol, backtest,
|
|
8667
|
+
async cancelScheduled(symbol, backtest, payload) {
|
|
8668
|
+
const cancelId = payload.id;
|
|
8629
8669
|
this.params.logger.debug("ClientStrategy cancelScheduled", {
|
|
8630
8670
|
symbol,
|
|
8631
8671
|
hasScheduledSignal: this._scheduledSignal !== null,
|
|
@@ -8637,6 +8677,7 @@ class ClientStrategy {
|
|
|
8637
8677
|
if (this._scheduledSignal) {
|
|
8638
8678
|
this._cancelledSignal = Object.assign({}, this._scheduledSignal, {
|
|
8639
8679
|
cancelId,
|
|
8680
|
+
cancelNote: payload.note,
|
|
8640
8681
|
});
|
|
8641
8682
|
this._scheduledSignal = null;
|
|
8642
8683
|
}
|
|
@@ -8668,7 +8709,8 @@ class ClientStrategy {
|
|
|
8668
8709
|
* // Scheduled signal becomes pending signal immediately
|
|
8669
8710
|
* ```
|
|
8670
8711
|
*/
|
|
8671
|
-
async activateScheduled(symbol, backtest,
|
|
8712
|
+
async activateScheduled(symbol, backtest, payload) {
|
|
8713
|
+
const activateId = payload.id;
|
|
8672
8714
|
this.params.logger.debug("ClientStrategy activateScheduled", {
|
|
8673
8715
|
symbol,
|
|
8674
8716
|
hasScheduledSignal: this._scheduledSignal !== null,
|
|
@@ -8686,6 +8728,7 @@ class ClientStrategy {
|
|
|
8686
8728
|
if (this._scheduledSignal) {
|
|
8687
8729
|
this._activatedSignal = Object.assign({}, this._scheduledSignal, {
|
|
8688
8730
|
activateId,
|
|
8731
|
+
activateNote: payload.note,
|
|
8689
8732
|
});
|
|
8690
8733
|
this._scheduledSignal = null;
|
|
8691
8734
|
}
|
|
@@ -8717,7 +8760,8 @@ class ClientStrategy {
|
|
|
8717
8760
|
* // Strategy continues, can generate new signals
|
|
8718
8761
|
* ```
|
|
8719
8762
|
*/
|
|
8720
|
-
async closePending(symbol, backtest,
|
|
8763
|
+
async closePending(symbol, backtest, payload) {
|
|
8764
|
+
const closeId = payload.id;
|
|
8721
8765
|
this.params.logger.debug("ClientStrategy closePending", {
|
|
8722
8766
|
symbol,
|
|
8723
8767
|
hasPendingSignal: this._pendingSignal !== null,
|
|
@@ -8728,6 +8772,7 @@ class ClientStrategy {
|
|
|
8728
8772
|
if (this._pendingSignal) {
|
|
8729
8773
|
this._closedSignal = Object.assign({}, this._pendingSignal, {
|
|
8730
8774
|
closeId,
|
|
8775
|
+
closeNote: payload.note,
|
|
8731
8776
|
});
|
|
8732
8777
|
this._pendingSignal = null;
|
|
8733
8778
|
}
|
|
@@ -11218,6 +11263,48 @@ class StrategyConnectionService {
|
|
|
11218
11263
|
const currentPrice = await this.priceMetaService.getCurrentPrice(symbol, context, backtest);
|
|
11219
11264
|
return await strategy.getPositionHighestMaxDrawdownPnlCost(symbol, currentPrice);
|
|
11220
11265
|
};
|
|
11266
|
+
/**
|
|
11267
|
+
* Returns the peak-to-trough PnL percentage distance between the position's highest profit and deepest drawdown.
|
|
11268
|
+
*
|
|
11269
|
+
* Resolves current price via priceMetaService and delegates to
|
|
11270
|
+
* ClientStrategy.getMaxDrawdownDistancePnlPercentage().
|
|
11271
|
+
* Returns null if no pending signal exists.
|
|
11272
|
+
*
|
|
11273
|
+
* @param backtest - Whether running in backtest mode
|
|
11274
|
+
* @param symbol - Trading pair symbol
|
|
11275
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
11276
|
+
* @returns Promise resolving to peak-to-trough PnL percentage distance (≥ 0) or null
|
|
11277
|
+
*/
|
|
11278
|
+
this.getMaxDrawdownDistancePnlPercentage = async (backtest, symbol, context) => {
|
|
11279
|
+
this.loggerService.log("strategyConnectionService getMaxDrawdownDistancePnlPercentage", {
|
|
11280
|
+
symbol,
|
|
11281
|
+
context,
|
|
11282
|
+
});
|
|
11283
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11284
|
+
const currentPrice = await this.priceMetaService.getCurrentPrice(symbol, context, backtest);
|
|
11285
|
+
return await strategy.getMaxDrawdownDistancePnlPercentage(symbol, currentPrice);
|
|
11286
|
+
};
|
|
11287
|
+
/**
|
|
11288
|
+
* Returns the peak-to-trough PnL cost distance between the position's highest profit and deepest drawdown.
|
|
11289
|
+
*
|
|
11290
|
+
* Resolves current price via priceMetaService and delegates to
|
|
11291
|
+
* ClientStrategy.getMaxDrawdownDistancePnlCost().
|
|
11292
|
+
* Returns null if no pending signal exists.
|
|
11293
|
+
*
|
|
11294
|
+
* @param backtest - Whether running in backtest mode
|
|
11295
|
+
* @param symbol - Trading pair symbol
|
|
11296
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
11297
|
+
* @returns Promise resolving to peak-to-trough PnL cost distance (≥ 0) or null
|
|
11298
|
+
*/
|
|
11299
|
+
this.getMaxDrawdownDistancePnlCost = async (backtest, symbol, context) => {
|
|
11300
|
+
this.loggerService.log("strategyConnectionService getMaxDrawdownDistancePnlCost", {
|
|
11301
|
+
symbol,
|
|
11302
|
+
context,
|
|
11303
|
+
});
|
|
11304
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11305
|
+
const currentPrice = await this.priceMetaService.getCurrentPrice(symbol, context, backtest);
|
|
11306
|
+
return await strategy.getMaxDrawdownDistancePnlCost(symbol, currentPrice);
|
|
11307
|
+
};
|
|
11221
11308
|
/**
|
|
11222
11309
|
* Disposes the ClientStrategy instance for the given context.
|
|
11223
11310
|
*
|
|
@@ -11277,17 +11364,17 @@ class StrategyConnectionService {
|
|
|
11277
11364
|
* @param backtest - Whether running in backtest mode
|
|
11278
11365
|
* @param symbol - Trading pair symbol
|
|
11279
11366
|
* @param ctx - Context with strategyName, exchangeName, frameName
|
|
11280
|
-
* @param
|
|
11367
|
+
* @param payload - Optional commit payload with id and note
|
|
11281
11368
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
11282
11369
|
*/
|
|
11283
|
-
this.cancelScheduled = async (backtest, symbol, context,
|
|
11370
|
+
this.cancelScheduled = async (backtest, symbol, context, payload = {}) => {
|
|
11284
11371
|
this.loggerService.log("strategyConnectionService cancelScheduled", {
|
|
11285
11372
|
symbol,
|
|
11286
11373
|
context,
|
|
11287
|
-
|
|
11374
|
+
payload,
|
|
11288
11375
|
});
|
|
11289
11376
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11290
|
-
await strategy.cancelScheduled(symbol, backtest,
|
|
11377
|
+
await strategy.cancelScheduled(symbol, backtest, payload);
|
|
11291
11378
|
};
|
|
11292
11379
|
/**
|
|
11293
11380
|
* Closes the pending signal without stopping the strategy.
|
|
@@ -11302,17 +11389,17 @@ class StrategyConnectionService {
|
|
|
11302
11389
|
* @param backtest - Whether running in backtest mode
|
|
11303
11390
|
* @param symbol - Trading pair symbol
|
|
11304
11391
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
11305
|
-
* @param
|
|
11392
|
+
* @param payload - Optional commit payload with id and note
|
|
11306
11393
|
* @returns Promise that resolves when pending signal is closed
|
|
11307
11394
|
*/
|
|
11308
|
-
this.closePending = async (backtest, symbol, context,
|
|
11395
|
+
this.closePending = async (backtest, symbol, context, payload = {}) => {
|
|
11309
11396
|
this.loggerService.log("strategyConnectionService closePending", {
|
|
11310
11397
|
symbol,
|
|
11311
11398
|
context,
|
|
11312
|
-
|
|
11399
|
+
payload,
|
|
11313
11400
|
});
|
|
11314
11401
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11315
|
-
await strategy.closePending(symbol, backtest,
|
|
11402
|
+
await strategy.closePending(symbol, backtest, payload);
|
|
11316
11403
|
};
|
|
11317
11404
|
/**
|
|
11318
11405
|
* Checks whether `partialProfit` would succeed without executing it.
|
|
@@ -11591,7 +11678,7 @@ class StrategyConnectionService {
|
|
|
11591
11678
|
* @param backtest - Whether running in backtest mode
|
|
11592
11679
|
* @param symbol - Trading pair symbol
|
|
11593
11680
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
11594
|
-
* @param
|
|
11681
|
+
* @param payload - Optional commit payload with id and note
|
|
11595
11682
|
* @returns Promise that resolves when activation flag is set
|
|
11596
11683
|
*
|
|
11597
11684
|
* @example
|
|
@@ -11601,19 +11688,19 @@ class StrategyConnectionService {
|
|
|
11601
11688
|
* false,
|
|
11602
11689
|
* "BTCUSDT",
|
|
11603
11690
|
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "" },
|
|
11604
|
-
* "manual-activation"
|
|
11691
|
+
* { id: "manual-activation" }
|
|
11605
11692
|
* );
|
|
11606
11693
|
* ```
|
|
11607
11694
|
*/
|
|
11608
|
-
this.activateScheduled = async (backtest, symbol, context,
|
|
11695
|
+
this.activateScheduled = async (backtest, symbol, context, payload = {}) => {
|
|
11609
11696
|
this.loggerService.log("strategyConnectionService activateScheduled", {
|
|
11610
11697
|
symbol,
|
|
11611
11698
|
context,
|
|
11612
11699
|
backtest,
|
|
11613
|
-
|
|
11700
|
+
payload,
|
|
11614
11701
|
});
|
|
11615
11702
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11616
|
-
return await strategy.activateScheduled(symbol, backtest,
|
|
11703
|
+
return await strategy.activateScheduled(symbol, backtest, payload);
|
|
11617
11704
|
};
|
|
11618
11705
|
/**
|
|
11619
11706
|
* Checks whether `averageBuy` would succeed without executing it.
|
|
@@ -14648,18 +14735,18 @@ class StrategyCoreService {
|
|
|
14648
14735
|
* @param backtest - Whether running in backtest mode
|
|
14649
14736
|
* @param symbol - Trading pair symbol
|
|
14650
14737
|
* @param ctx - Context with strategyName, exchangeName, frameName
|
|
14651
|
-
* @param
|
|
14738
|
+
* @param payload - Optional commit payload with id and note
|
|
14652
14739
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
14653
14740
|
*/
|
|
14654
|
-
this.cancelScheduled = async (backtest, symbol, context,
|
|
14741
|
+
this.cancelScheduled = async (backtest, symbol, context, payload = {}) => {
|
|
14655
14742
|
this.loggerService.log("strategyCoreService cancelScheduled", {
|
|
14656
14743
|
symbol,
|
|
14657
14744
|
context,
|
|
14658
14745
|
backtest,
|
|
14659
|
-
|
|
14746
|
+
payload,
|
|
14660
14747
|
});
|
|
14661
14748
|
await this.validate(context);
|
|
14662
|
-
return await this.strategyConnectionService.cancelScheduled(backtest, symbol, context,
|
|
14749
|
+
return await this.strategyConnectionService.cancelScheduled(backtest, symbol, context, payload);
|
|
14663
14750
|
};
|
|
14664
14751
|
/**
|
|
14665
14752
|
* Closes the pending signal without stopping the strategy.
|
|
@@ -14675,18 +14762,18 @@ class StrategyCoreService {
|
|
|
14675
14762
|
* @param backtest - Whether running in backtest mode
|
|
14676
14763
|
* @param symbol - Trading pair symbol
|
|
14677
14764
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
14678
|
-
* @param
|
|
14765
|
+
* @param payload - Optional commit payload with id and note
|
|
14679
14766
|
* @returns Promise that resolves when pending signal is closed
|
|
14680
14767
|
*/
|
|
14681
|
-
this.closePending = async (backtest, symbol, context,
|
|
14768
|
+
this.closePending = async (backtest, symbol, context, payload = {}) => {
|
|
14682
14769
|
this.loggerService.log("strategyCoreService closePending", {
|
|
14683
14770
|
symbol,
|
|
14684
14771
|
context,
|
|
14685
14772
|
backtest,
|
|
14686
|
-
|
|
14773
|
+
payload,
|
|
14687
14774
|
});
|
|
14688
14775
|
await this.validate(context);
|
|
14689
|
-
return await this.strategyConnectionService.closePending(backtest, symbol, context,
|
|
14776
|
+
return await this.strategyConnectionService.closePending(backtest, symbol, context, payload);
|
|
14690
14777
|
};
|
|
14691
14778
|
/**
|
|
14692
14779
|
* Disposes the ClientStrategy instance for the given context.
|
|
@@ -15031,7 +15118,7 @@ class StrategyCoreService {
|
|
|
15031
15118
|
* @param backtest - Whether running in backtest mode
|
|
15032
15119
|
* @param symbol - Trading pair symbol
|
|
15033
15120
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15034
|
-
* @param
|
|
15121
|
+
* @param payload - Optional commit payload with id and note
|
|
15035
15122
|
* @returns Promise that resolves when activation flag is set
|
|
15036
15123
|
*
|
|
15037
15124
|
* @example
|
|
@@ -15041,19 +15128,19 @@ class StrategyCoreService {
|
|
|
15041
15128
|
* false,
|
|
15042
15129
|
* "BTCUSDT",
|
|
15043
15130
|
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "" },
|
|
15044
|
-
* "manual-activation"
|
|
15131
|
+
* { id: "manual-activation" }
|
|
15045
15132
|
* );
|
|
15046
15133
|
* ```
|
|
15047
15134
|
*/
|
|
15048
|
-
this.activateScheduled = async (backtest, symbol, context,
|
|
15135
|
+
this.activateScheduled = async (backtest, symbol, context, payload = {}) => {
|
|
15049
15136
|
this.loggerService.log("strategyCoreService activateScheduled", {
|
|
15050
15137
|
symbol,
|
|
15051
15138
|
context,
|
|
15052
15139
|
backtest,
|
|
15053
|
-
|
|
15140
|
+
payload,
|
|
15054
15141
|
});
|
|
15055
15142
|
await this.validate(context);
|
|
15056
|
-
return await this.strategyConnectionService.activateScheduled(backtest, symbol, context,
|
|
15143
|
+
return await this.strategyConnectionService.activateScheduled(backtest, symbol, context, payload);
|
|
15057
15144
|
};
|
|
15058
15145
|
/**
|
|
15059
15146
|
* Checks whether `averageBuy` would succeed without executing it.
|
|
@@ -15455,6 +15542,44 @@ class StrategyCoreService {
|
|
|
15455
15542
|
await this.validate(context);
|
|
15456
15543
|
return await this.strategyConnectionService.getPositionHighestMaxDrawdownPnlCost(backtest, symbol, context);
|
|
15457
15544
|
};
|
|
15545
|
+
/**
|
|
15546
|
+
* Returns the peak-to-trough PnL percentage distance between the position's highest profit and deepest drawdown.
|
|
15547
|
+
*
|
|
15548
|
+
* Delegates to StrategyConnectionService.getMaxDrawdownDistancePnlPercentage().
|
|
15549
|
+
* Returns null if no pending signal exists.
|
|
15550
|
+
*
|
|
15551
|
+
* @param backtest - Whether running in backtest mode
|
|
15552
|
+
* @param symbol - Trading pair symbol
|
|
15553
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15554
|
+
* @returns Promise resolving to peak-to-trough PnL percentage distance (≥ 0) or null
|
|
15555
|
+
*/
|
|
15556
|
+
this.getMaxDrawdownDistancePnlPercentage = async (backtest, symbol, context) => {
|
|
15557
|
+
this.loggerService.log("strategyCoreService getMaxDrawdownDistancePnlPercentage", {
|
|
15558
|
+
symbol,
|
|
15559
|
+
context,
|
|
15560
|
+
});
|
|
15561
|
+
await this.validate(context);
|
|
15562
|
+
return await this.strategyConnectionService.getMaxDrawdownDistancePnlPercentage(backtest, symbol, context);
|
|
15563
|
+
};
|
|
15564
|
+
/**
|
|
15565
|
+
* Returns the peak-to-trough PnL cost distance between the position's highest profit and deepest drawdown.
|
|
15566
|
+
*
|
|
15567
|
+
* Delegates to StrategyConnectionService.getMaxDrawdownDistancePnlCost().
|
|
15568
|
+
* Returns null if no pending signal exists.
|
|
15569
|
+
*
|
|
15570
|
+
* @param backtest - Whether running in backtest mode
|
|
15571
|
+
* @param symbol - Trading pair symbol
|
|
15572
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15573
|
+
* @returns Promise resolving to peak-to-trough PnL cost distance (≥ 0) or null
|
|
15574
|
+
*/
|
|
15575
|
+
this.getMaxDrawdownDistancePnlCost = async (backtest, symbol, context) => {
|
|
15576
|
+
this.loggerService.log("strategyCoreService getMaxDrawdownDistancePnlCost", {
|
|
15577
|
+
symbol,
|
|
15578
|
+
context,
|
|
15579
|
+
});
|
|
15580
|
+
await this.validate(context);
|
|
15581
|
+
return await this.strategyConnectionService.getMaxDrawdownDistancePnlCost(backtest, symbol, context);
|
|
15582
|
+
};
|
|
15458
15583
|
}
|
|
15459
15584
|
}
|
|
15460
15585
|
|
|
@@ -29054,7 +29179,7 @@ class StrategyReportService {
|
|
|
29054
29179
|
/**
|
|
29055
29180
|
* Logs a cancel-scheduled event when a scheduled signal is cancelled.
|
|
29056
29181
|
*/
|
|
29057
|
-
this.cancelScheduled = async (symbol, isBacktest, context, timestamp, signalId, pnl, totalPartials, cancelId) => {
|
|
29182
|
+
this.cancelScheduled = async (symbol, isBacktest, context, timestamp, signalId, pnl, totalPartials, cancelId, note) => {
|
|
29058
29183
|
this.loggerService.log("strategyReportService cancelScheduled", {
|
|
29059
29184
|
symbol,
|
|
29060
29185
|
isBacktest,
|
|
@@ -29067,6 +29192,7 @@ class StrategyReportService {
|
|
|
29067
29192
|
await ReportWriter.writeData("strategy", {
|
|
29068
29193
|
action: "cancel-scheduled",
|
|
29069
29194
|
cancelId,
|
|
29195
|
+
note,
|
|
29070
29196
|
symbol,
|
|
29071
29197
|
timestamp,
|
|
29072
29198
|
createdAt,
|
|
@@ -29088,7 +29214,7 @@ class StrategyReportService {
|
|
|
29088
29214
|
/**
|
|
29089
29215
|
* Logs a close-pending event when a pending signal is closed.
|
|
29090
29216
|
*/
|
|
29091
|
-
this.closePending = async (symbol, isBacktest, context, timestamp, signalId, pnl, totalPartials, closeId) => {
|
|
29217
|
+
this.closePending = async (symbol, isBacktest, context, timestamp, signalId, pnl, totalPartials, closeId, note) => {
|
|
29092
29218
|
this.loggerService.log("strategyReportService closePending", {
|
|
29093
29219
|
symbol,
|
|
29094
29220
|
isBacktest,
|
|
@@ -29101,6 +29227,7 @@ class StrategyReportService {
|
|
|
29101
29227
|
await ReportWriter.writeData("strategy", {
|
|
29102
29228
|
action: "close-pending",
|
|
29103
29229
|
closeId,
|
|
29230
|
+
note,
|
|
29104
29231
|
symbol,
|
|
29105
29232
|
timestamp,
|
|
29106
29233
|
createdAt,
|
|
@@ -29350,7 +29477,7 @@ class StrategyReportService {
|
|
|
29350
29477
|
/**
|
|
29351
29478
|
* Logs an activate-scheduled event when a scheduled signal is activated early.
|
|
29352
29479
|
*/
|
|
29353
|
-
this.activateScheduled = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen, activateId) => {
|
|
29480
|
+
this.activateScheduled = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen, activateId, note) => {
|
|
29354
29481
|
this.loggerService.log("strategyReportService activateScheduled", {
|
|
29355
29482
|
symbol,
|
|
29356
29483
|
currentPrice,
|
|
@@ -29364,6 +29491,7 @@ class StrategyReportService {
|
|
|
29364
29491
|
await ReportWriter.writeData("strategy", {
|
|
29365
29492
|
action: "activate-scheduled",
|
|
29366
29493
|
activateId,
|
|
29494
|
+
note,
|
|
29367
29495
|
currentPrice,
|
|
29368
29496
|
symbol,
|
|
29369
29497
|
timestamp,
|
|
@@ -29457,14 +29585,14 @@ class StrategyReportService {
|
|
|
29457
29585
|
exchangeName: event.exchangeName,
|
|
29458
29586
|
frameName: event.frameName,
|
|
29459
29587
|
strategyName: event.strategyName,
|
|
29460
|
-
}, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.cancelId));
|
|
29588
|
+
}, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.cancelId, event.note));
|
|
29461
29589
|
const unClosePending = strategyCommitSubject
|
|
29462
29590
|
.filter(({ action }) => action === "close-pending")
|
|
29463
29591
|
.connect(async (event) => await this.closePending(event.symbol, event.backtest, {
|
|
29464
29592
|
exchangeName: event.exchangeName,
|
|
29465
29593
|
frameName: event.frameName,
|
|
29466
29594
|
strategyName: event.strategyName,
|
|
29467
|
-
}, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.closeId));
|
|
29595
|
+
}, event.timestamp, event.signalId, event.pnl, event.totalPartials, event.closeId, event.note));
|
|
29468
29596
|
const unPartialProfit = strategyCommitSubject
|
|
29469
29597
|
.filter(({ action }) => action === "partial-profit")
|
|
29470
29598
|
.connect(async (event) => await this.partialProfit(event.symbol, event.percentToClose, event.currentPrice, event.backtest, {
|
|
@@ -29506,7 +29634,7 @@ class StrategyReportService {
|
|
|
29506
29634
|
exchangeName: event.exchangeName,
|
|
29507
29635
|
frameName: event.frameName,
|
|
29508
29636
|
strategyName: event.strategyName,
|
|
29509
|
-
}, 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));
|
|
29637
|
+
}, 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));
|
|
29510
29638
|
const unAverageBuy = strategyCommitSubject
|
|
29511
29639
|
.filter(({ action }) => action === "average-buy")
|
|
29512
29640
|
.connect(async (event) => await this.averageBuy(event.symbol, event.currentPrice, event.effectivePriceOpen, event.totalEntries, event.backtest, {
|
|
@@ -30045,8 +30173,9 @@ class StrategyMarkdownService {
|
|
|
30045
30173
|
* @param context - Strategy context with strategyName, exchangeName, frameName
|
|
30046
30174
|
* @param timestamp - Timestamp from StrategyCommitContract (execution context time)
|
|
30047
30175
|
* @param cancelId - Optional identifier for the cancellation reason
|
|
30176
|
+
* @param note - Optional note from commit payload
|
|
30048
30177
|
*/
|
|
30049
|
-
this.cancelScheduled = async (symbol, isBacktest, context, timestamp, signalId, pnl, cancelId) => {
|
|
30178
|
+
this.cancelScheduled = async (symbol, isBacktest, context, timestamp, signalId, pnl, cancelId, note) => {
|
|
30050
30179
|
this.loggerService.log("strategyMarkdownService cancelScheduled", {
|
|
30051
30180
|
symbol,
|
|
30052
30181
|
isBacktest,
|
|
@@ -30067,6 +30196,7 @@ class StrategyMarkdownService {
|
|
|
30067
30196
|
action: "cancel-scheduled",
|
|
30068
30197
|
pnl,
|
|
30069
30198
|
cancelId,
|
|
30199
|
+
note,
|
|
30070
30200
|
createdAt,
|
|
30071
30201
|
backtest: isBacktest,
|
|
30072
30202
|
});
|
|
@@ -30079,8 +30209,9 @@ class StrategyMarkdownService {
|
|
|
30079
30209
|
* @param context - Strategy context with strategyName, exchangeName, frameName
|
|
30080
30210
|
* @param timestamp - Timestamp from StrategyCommitContract (execution context time)
|
|
30081
30211
|
* @param closeId - Optional identifier for the close reason
|
|
30212
|
+
* @param note - Optional note from commit payload
|
|
30082
30213
|
*/
|
|
30083
|
-
this.closePending = async (symbol, isBacktest, context, timestamp, signalId, pnl, closeId) => {
|
|
30214
|
+
this.closePending = async (symbol, isBacktest, context, timestamp, signalId, pnl, closeId, note) => {
|
|
30084
30215
|
this.loggerService.log("strategyMarkdownService closePending", {
|
|
30085
30216
|
symbol,
|
|
30086
30217
|
isBacktest,
|
|
@@ -30101,6 +30232,7 @@ class StrategyMarkdownService {
|
|
|
30101
30232
|
action: "close-pending",
|
|
30102
30233
|
pnl,
|
|
30103
30234
|
closeId,
|
|
30235
|
+
note,
|
|
30104
30236
|
createdAt,
|
|
30105
30237
|
backtest: isBacktest,
|
|
30106
30238
|
});
|
|
@@ -30399,8 +30531,9 @@ class StrategyMarkdownService {
|
|
|
30399
30531
|
* @param scheduledAt - Signal creation timestamp in milliseconds
|
|
30400
30532
|
* @param pendingAt - Pending timestamp in milliseconds
|
|
30401
30533
|
* @param activateId - Optional identifier for the activation reason
|
|
30534
|
+
* @param note - Optional note from commit payload
|
|
30402
30535
|
*/
|
|
30403
|
-
this.activateScheduled = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen, activateId) => {
|
|
30536
|
+
this.activateScheduled = async (symbol, currentPrice, isBacktest, context, timestamp, signalId, pnl, totalPartials, position, priceOpen, priceTakeProfit, priceStopLoss, originalPriceTakeProfit, originalPriceStopLoss, scheduledAt, pendingAt, totalEntries, originalPriceOpen, activateId, note) => {
|
|
30404
30537
|
this.loggerService.log("strategyMarkdownService activateScheduled", {
|
|
30405
30538
|
symbol,
|
|
30406
30539
|
currentPrice,
|
|
@@ -30423,6 +30556,7 @@ class StrategyMarkdownService {
|
|
|
30423
30556
|
pnl,
|
|
30424
30557
|
totalPartials,
|
|
30425
30558
|
activateId,
|
|
30559
|
+
note,
|
|
30426
30560
|
currentPrice,
|
|
30427
30561
|
createdAt,
|
|
30428
30562
|
backtest: isBacktest,
|
|
@@ -30627,14 +30761,14 @@ class StrategyMarkdownService {
|
|
|
30627
30761
|
exchangeName: event.exchangeName,
|
|
30628
30762
|
frameName: event.frameName,
|
|
30629
30763
|
strategyName: event.strategyName,
|
|
30630
|
-
}, event.timestamp, event.signalId, event.pnl, event.cancelId));
|
|
30764
|
+
}, event.timestamp, event.signalId, event.pnl, event.cancelId, event.note));
|
|
30631
30765
|
const unClosePending = strategyCommitSubject
|
|
30632
30766
|
.filter(({ action }) => action === "close-pending")
|
|
30633
30767
|
.connect(async (event) => await this.closePending(event.symbol, event.backtest, {
|
|
30634
30768
|
exchangeName: event.exchangeName,
|
|
30635
30769
|
frameName: event.frameName,
|
|
30636
30770
|
strategyName: event.strategyName,
|
|
30637
|
-
}, event.timestamp, event.signalId, event.pnl, event.closeId));
|
|
30771
|
+
}, event.timestamp, event.signalId, event.pnl, event.closeId, event.note));
|
|
30638
30772
|
const unPartialProfit = strategyCommitSubject
|
|
30639
30773
|
.filter(({ action }) => action === "partial-profit")
|
|
30640
30774
|
.connect(async (event) => await this.partialProfit(event.symbol, event.percentToClose, event.currentPrice, event.backtest, {
|
|
@@ -30676,7 +30810,7 @@ class StrategyMarkdownService {
|
|
|
30676
30810
|
exchangeName: event.exchangeName,
|
|
30677
30811
|
frameName: event.frameName,
|
|
30678
30812
|
strategyName: event.strategyName,
|
|
30679
|
-
}, 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));
|
|
30813
|
+
}, 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));
|
|
30680
30814
|
const unAverageBuy = strategyCommitSubject
|
|
30681
30815
|
.filter(({ action }) => action === "average-buy")
|
|
30682
30816
|
.connect(async (event) => await this.averageBuy(event.symbol, event.currentPrice, event.effectivePriceOpen, event.totalEntries, event.backtest, {
|
|
@@ -35161,6 +35295,8 @@ const GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE_METHOD_NAME = "strateg
|
|
|
35161
35295
|
const GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST_METHOD_NAME = "strategy.getPositionHighestProfitDistancePnlCost";
|
|
35162
35296
|
const GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE_METHOD_NAME = "strategy.getPositionHighestMaxDrawdownPnlPercentage";
|
|
35163
35297
|
const GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST_METHOD_NAME = "strategy.getPositionHighestMaxDrawdownPnlCost";
|
|
35298
|
+
const GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE_METHOD_NAME = "strategy.getMaxDrawdownDistancePnlPercentage";
|
|
35299
|
+
const GET_MAX_DRAWDOWN_DISTANCE_PNL_COST_METHOD_NAME = "strategy.getMaxDrawdownDistancePnlCost";
|
|
35164
35300
|
const GET_POSITION_ENTRY_OVERLAP_METHOD_NAME = "strategy.getPositionEntryOverlap";
|
|
35165
35301
|
const GET_POSITION_PARTIAL_OVERLAP_METHOD_NAME = "strategy.getPositionPartialOverlap";
|
|
35166
35302
|
const HAS_NO_PENDING_SIGNAL_METHOD_NAME = "strategy.hasNoPendingSignal";
|
|
@@ -35176,7 +35312,7 @@ const HAS_NO_SCHEDULED_SIGNAL_METHOD_NAME = "strategy.hasNoScheduledSignal";
|
|
|
35176
35312
|
*
|
|
35177
35313
|
* @param symbol - Trading pair symbol
|
|
35178
35314
|
* @param strategyName - Strategy name
|
|
35179
|
-
* @param
|
|
35315
|
+
* @param payload - Optional commit payload with id and note
|
|
35180
35316
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
35181
35317
|
*
|
|
35182
35318
|
* @example
|
|
@@ -35184,13 +35320,13 @@ const HAS_NO_SCHEDULED_SIGNAL_METHOD_NAME = "strategy.hasNoScheduledSignal";
|
|
|
35184
35320
|
* import { commitCancelScheduled } from "backtest-kit";
|
|
35185
35321
|
*
|
|
35186
35322
|
* // Cancel scheduled signal with custom ID
|
|
35187
|
-
* await commitCancelScheduled("BTCUSDT", "manual-cancel-001");
|
|
35323
|
+
* await commitCancelScheduled("BTCUSDT", { id: "manual-cancel-001" });
|
|
35188
35324
|
* ```
|
|
35189
35325
|
*/
|
|
35190
|
-
async function commitCancelScheduled(symbol,
|
|
35326
|
+
async function commitCancelScheduled(symbol, payload = {}) {
|
|
35191
35327
|
backtest.loggerService.info(CANCEL_SCHEDULED_METHOD_NAME, {
|
|
35192
35328
|
symbol,
|
|
35193
|
-
|
|
35329
|
+
payload,
|
|
35194
35330
|
});
|
|
35195
35331
|
if (!ExecutionContextService.hasContext()) {
|
|
35196
35332
|
throw new Error("commitCancelScheduled requires an execution context");
|
|
@@ -35200,7 +35336,7 @@ async function commitCancelScheduled(symbol, cancelId) {
|
|
|
35200
35336
|
}
|
|
35201
35337
|
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
35202
35338
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
35203
|
-
await backtest.strategyCoreService.cancelScheduled(isBacktest, symbol, { exchangeName, frameName, strategyName },
|
|
35339
|
+
await backtest.strategyCoreService.cancelScheduled(isBacktest, symbol, { exchangeName, frameName, strategyName }, payload);
|
|
35204
35340
|
}
|
|
35205
35341
|
/**
|
|
35206
35342
|
* Closes the pending signal without stopping the strategy.
|
|
@@ -35212,7 +35348,7 @@ async function commitCancelScheduled(symbol, cancelId) {
|
|
|
35212
35348
|
* Automatically detects backtest/live mode from execution context.
|
|
35213
35349
|
*
|
|
35214
35350
|
* @param symbol - Trading pair symbol
|
|
35215
|
-
* @param
|
|
35351
|
+
* @param payload - Optional commit payload with id and note
|
|
35216
35352
|
* @returns Promise that resolves when pending signal is closed
|
|
35217
35353
|
*
|
|
35218
35354
|
* @example
|
|
@@ -35220,13 +35356,13 @@ async function commitCancelScheduled(symbol, cancelId) {
|
|
|
35220
35356
|
* import { commitClosePending } from "backtest-kit";
|
|
35221
35357
|
*
|
|
35222
35358
|
* // Close pending signal with custom ID
|
|
35223
|
-
* await commitClosePending("BTCUSDT", "manual-close-001");
|
|
35359
|
+
* await commitClosePending("BTCUSDT", { id: "manual-close-001" });
|
|
35224
35360
|
* ```
|
|
35225
35361
|
*/
|
|
35226
|
-
async function commitClosePending(symbol,
|
|
35362
|
+
async function commitClosePending(symbol, payload = {}) {
|
|
35227
35363
|
backtest.loggerService.info(CLOSE_PENDING_METHOD_NAME, {
|
|
35228
35364
|
symbol,
|
|
35229
|
-
|
|
35365
|
+
payload,
|
|
35230
35366
|
});
|
|
35231
35367
|
if (!ExecutionContextService.hasContext()) {
|
|
35232
35368
|
throw new Error("commitClosePending requires an execution context");
|
|
@@ -35236,7 +35372,7 @@ async function commitClosePending(symbol, closeId) {
|
|
|
35236
35372
|
}
|
|
35237
35373
|
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
35238
35374
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
35239
|
-
await backtest.strategyCoreService.closePending(isBacktest, symbol, { exchangeName, frameName, strategyName },
|
|
35375
|
+
await backtest.strategyCoreService.closePending(isBacktest, symbol, { exchangeName, frameName, strategyName }, payload);
|
|
35240
35376
|
}
|
|
35241
35377
|
/**
|
|
35242
35378
|
* Executes partial close at profit level (moving toward TP).
|
|
@@ -35699,7 +35835,7 @@ async function commitBreakeven(symbol) {
|
|
|
35699
35835
|
* Automatically detects backtest/live mode from execution context.
|
|
35700
35836
|
*
|
|
35701
35837
|
* @param symbol - Trading pair symbol
|
|
35702
|
-
* @param
|
|
35838
|
+
* @param payload - Optional commit payload with id and note
|
|
35703
35839
|
* @returns Promise that resolves when activation flag is set
|
|
35704
35840
|
*
|
|
35705
35841
|
* @example
|
|
@@ -35707,13 +35843,13 @@ async function commitBreakeven(symbol) {
|
|
|
35707
35843
|
* import { commitActivateScheduled } from "backtest-kit";
|
|
35708
35844
|
*
|
|
35709
35845
|
* // Activate scheduled signal early with custom ID
|
|
35710
|
-
* await commitActivateScheduled("BTCUSDT", "manual-activate-001");
|
|
35846
|
+
* await commitActivateScheduled("BTCUSDT", { id: "manual-activate-001" });
|
|
35711
35847
|
* ```
|
|
35712
35848
|
*/
|
|
35713
|
-
async function commitActivateScheduled(symbol,
|
|
35849
|
+
async function commitActivateScheduled(symbol, payload = {}) {
|
|
35714
35850
|
backtest.loggerService.info(ACTIVATE_SCHEDULED_METHOD_NAME, {
|
|
35715
35851
|
symbol,
|
|
35716
|
-
|
|
35852
|
+
payload,
|
|
35717
35853
|
});
|
|
35718
35854
|
if (!ExecutionContextService.hasContext()) {
|
|
35719
35855
|
throw new Error("commitActivateScheduled requires an execution context");
|
|
@@ -35723,7 +35859,7 @@ async function commitActivateScheduled(symbol, activateId) {
|
|
|
35723
35859
|
}
|
|
35724
35860
|
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
35725
35861
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
35726
|
-
await backtest.strategyCoreService.activateScheduled(isBacktest, symbol, { exchangeName, frameName, strategyName },
|
|
35862
|
+
await backtest.strategyCoreService.activateScheduled(isBacktest, symbol, { exchangeName, frameName, strategyName }, payload);
|
|
35727
35863
|
}
|
|
35728
35864
|
/**
|
|
35729
35865
|
* Adds a new DCA entry to the active pending signal.
|
|
@@ -36911,6 +37047,64 @@ async function getPositionHighestMaxDrawdownPnlCost(symbol) {
|
|
|
36911
37047
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
36912
37048
|
return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlCost(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
36913
37049
|
}
|
|
37050
|
+
/**
|
|
37051
|
+
* Returns the peak-to-trough PnL percentage distance between the position's highest profit and deepest drawdown.
|
|
37052
|
+
*
|
|
37053
|
+
* Computed as: max(0, peakPnlPercentage - fallPnlPercentage).
|
|
37054
|
+
* Returns null if no pending signal exists.
|
|
37055
|
+
*
|
|
37056
|
+
* @param symbol - Trading pair symbol
|
|
37057
|
+
* @returns Promise resolving to peak-to-trough PnL percentage distance (≥ 0) or null
|
|
37058
|
+
*
|
|
37059
|
+
* @example
|
|
37060
|
+
* ```typescript
|
|
37061
|
+
* import { getMaxDrawdownDistancePnlPercentage } from "backtest-kit";
|
|
37062
|
+
*
|
|
37063
|
+
* const dist = await getMaxDrawdownDistancePnlPercentage("BTCUSDT");
|
|
37064
|
+
* // e.g. 3.5 (peak was +3.5% above trough)
|
|
37065
|
+
* ```
|
|
37066
|
+
*/
|
|
37067
|
+
async function getMaxDrawdownDistancePnlPercentage(symbol) {
|
|
37068
|
+
backtest.loggerService.info(GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE_METHOD_NAME, { symbol });
|
|
37069
|
+
if (!ExecutionContextService.hasContext()) {
|
|
37070
|
+
throw new Error("getMaxDrawdownDistancePnlPercentage requires an execution context");
|
|
37071
|
+
}
|
|
37072
|
+
if (!MethodContextService.hasContext()) {
|
|
37073
|
+
throw new Error("getMaxDrawdownDistancePnlPercentage requires a method context");
|
|
37074
|
+
}
|
|
37075
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
37076
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37077
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlPercentage(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
37078
|
+
}
|
|
37079
|
+
/**
|
|
37080
|
+
* Returns the peak-to-trough PnL cost distance between the position's highest profit and deepest drawdown.
|
|
37081
|
+
*
|
|
37082
|
+
* Computed as: max(0, peakPnlCost - fallPnlCost).
|
|
37083
|
+
* Returns null if no pending signal exists.
|
|
37084
|
+
*
|
|
37085
|
+
* @param symbol - Trading pair symbol
|
|
37086
|
+
* @returns Promise resolving to peak-to-trough PnL cost distance (≥ 0) or null
|
|
37087
|
+
*
|
|
37088
|
+
* @example
|
|
37089
|
+
* ```typescript
|
|
37090
|
+
* import { getMaxDrawdownDistancePnlCost } from "backtest-kit";
|
|
37091
|
+
*
|
|
37092
|
+
* const dist = await getMaxDrawdownDistancePnlCost("BTCUSDT");
|
|
37093
|
+
* // e.g. 7.2 (peak was $7.2 above trough)
|
|
37094
|
+
* ```
|
|
37095
|
+
*/
|
|
37096
|
+
async function getMaxDrawdownDistancePnlCost(symbol) {
|
|
37097
|
+
backtest.loggerService.info(GET_MAX_DRAWDOWN_DISTANCE_PNL_COST_METHOD_NAME, { symbol });
|
|
37098
|
+
if (!ExecutionContextService.hasContext()) {
|
|
37099
|
+
throw new Error("getMaxDrawdownDistancePnlCost requires an execution context");
|
|
37100
|
+
}
|
|
37101
|
+
if (!MethodContextService.hasContext()) {
|
|
37102
|
+
throw new Error("getMaxDrawdownDistancePnlCost requires a method context");
|
|
37103
|
+
}
|
|
37104
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
37105
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37106
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlCost(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
37107
|
+
}
|
|
36914
37108
|
/**
|
|
36915
37109
|
* Checks whether the current price falls within the tolerance zone of any existing DCA entry level.
|
|
36916
37110
|
* Use this to prevent duplicate DCA entries at the same price area.
|
|
@@ -38584,6 +38778,8 @@ const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE =
|
|
|
38584
38778
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST = "BacktestUtils.getPositionHighestProfitDistancePnlCost";
|
|
38585
38779
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE = "BacktestUtils.getPositionHighestMaxDrawdownPnlPercentage";
|
|
38586
38780
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST = "BacktestUtils.getPositionHighestMaxDrawdownPnlCost";
|
|
38781
|
+
const BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE = "BacktestUtils.getMaxDrawdownDistancePnlPercentage";
|
|
38782
|
+
const BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST = "BacktestUtils.getMaxDrawdownDistancePnlCost";
|
|
38587
38783
|
const BACKTEST_METHOD_NAME_GET_POSITION_ENTRY_OVERLAP = "BacktestUtils.getPositionEntryOverlap";
|
|
38588
38784
|
const BACKTEST_METHOD_NAME_GET_POSITION_PARTIAL_OVERLAP = "BacktestUtils.getPositionPartialOverlap";
|
|
38589
38785
|
const BACKTEST_METHOD_NAME_BREAKEVEN = "Backtest.commitBreakeven";
|
|
@@ -39965,6 +40161,62 @@ class BacktestUtils {
|
|
|
39965
40161
|
}
|
|
39966
40162
|
return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlCost(true, symbol, context);
|
|
39967
40163
|
};
|
|
40164
|
+
/**
|
|
40165
|
+
* Returns the peak-to-trough PnL percentage distance between the position's highest profit and deepest drawdown.
|
|
40166
|
+
*
|
|
40167
|
+
* Computed as: max(0, peakPnlPercentage - fallPnlPercentage).
|
|
40168
|
+
* Returns null if no pending signal exists.
|
|
40169
|
+
*
|
|
40170
|
+
* @param symbol - Trading pair symbol
|
|
40171
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40172
|
+
* @returns peak-to-trough PnL percentage distance (≥ 0) or null if no active position
|
|
40173
|
+
*/
|
|
40174
|
+
this.getMaxDrawdownDistancePnlPercentage = async (symbol, context) => {
|
|
40175
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE, {
|
|
40176
|
+
symbol,
|
|
40177
|
+
context,
|
|
40178
|
+
});
|
|
40179
|
+
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
40180
|
+
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
40181
|
+
{
|
|
40182
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
40183
|
+
riskName &&
|
|
40184
|
+
backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
40185
|
+
riskList &&
|
|
40186
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE));
|
|
40187
|
+
actions &&
|
|
40188
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE));
|
|
40189
|
+
}
|
|
40190
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlPercentage(true, symbol, context);
|
|
40191
|
+
};
|
|
40192
|
+
/**
|
|
40193
|
+
* Returns the peak-to-trough PnL cost distance between the position's highest profit and deepest drawdown.
|
|
40194
|
+
*
|
|
40195
|
+
* Computed as: max(0, peakPnlCost - fallPnlCost).
|
|
40196
|
+
* Returns null if no pending signal exists.
|
|
40197
|
+
*
|
|
40198
|
+
* @param symbol - Trading pair symbol
|
|
40199
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40200
|
+
* @returns peak-to-trough PnL cost distance (≥ 0) or null if no active position
|
|
40201
|
+
*/
|
|
40202
|
+
this.getMaxDrawdownDistancePnlCost = async (symbol, context) => {
|
|
40203
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST, {
|
|
40204
|
+
symbol,
|
|
40205
|
+
context,
|
|
40206
|
+
});
|
|
40207
|
+
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
40208
|
+
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
40209
|
+
{
|
|
40210
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
40211
|
+
riskName &&
|
|
40212
|
+
backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
40213
|
+
riskList &&
|
|
40214
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST));
|
|
40215
|
+
actions &&
|
|
40216
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST));
|
|
40217
|
+
}
|
|
40218
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlCost(true, symbol, context);
|
|
40219
|
+
};
|
|
39968
40220
|
/**
|
|
39969
40221
|
* Checks whether the current price falls within the tolerance zone of any existing DCA entry level.
|
|
39970
40222
|
* Use this to prevent duplicate DCA entries at the same price area.
|
|
@@ -40099,7 +40351,7 @@ class BacktestUtils {
|
|
|
40099
40351
|
* @param symbol - Trading pair symbol
|
|
40100
40352
|
* @param strategyName - Strategy name
|
|
40101
40353
|
* @param context - Execution context with exchangeName and frameName
|
|
40102
|
-
* @param
|
|
40354
|
+
* @param payload - Optional commit payload with id and note
|
|
40103
40355
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
40104
40356
|
*
|
|
40105
40357
|
* @example
|
|
@@ -40109,14 +40361,14 @@ class BacktestUtils {
|
|
|
40109
40361
|
* exchangeName: "binance",
|
|
40110
40362
|
* frameName: "frame1",
|
|
40111
40363
|
* strategyName: "my-strategy"
|
|
40112
|
-
* }, "manual-cancel-001");
|
|
40364
|
+
* }, { id: "manual-cancel-001" });
|
|
40113
40365
|
* ```
|
|
40114
40366
|
*/
|
|
40115
|
-
this.commitCancelScheduled = async (symbol, context,
|
|
40367
|
+
this.commitCancelScheduled = async (symbol, context, payload = {}) => {
|
|
40116
40368
|
backtest.loggerService.info(BACKTEST_METHOD_NAME_CANCEL_SCHEDULED, {
|
|
40117
40369
|
symbol,
|
|
40118
40370
|
context,
|
|
40119
|
-
|
|
40371
|
+
payload,
|
|
40120
40372
|
});
|
|
40121
40373
|
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_CANCEL_SCHEDULED);
|
|
40122
40374
|
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_CANCEL_SCHEDULED);
|
|
@@ -40129,7 +40381,7 @@ class BacktestUtils {
|
|
|
40129
40381
|
actions &&
|
|
40130
40382
|
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_CANCEL_SCHEDULED));
|
|
40131
40383
|
}
|
|
40132
|
-
await backtest.strategyCoreService.cancelScheduled(true, symbol, context,
|
|
40384
|
+
await backtest.strategyCoreService.cancelScheduled(true, symbol, context, payload);
|
|
40133
40385
|
};
|
|
40134
40386
|
/**
|
|
40135
40387
|
* Closes the pending signal without stopping the strategy.
|
|
@@ -40140,7 +40392,7 @@ class BacktestUtils {
|
|
|
40140
40392
|
*
|
|
40141
40393
|
* @param symbol - Trading pair symbol
|
|
40142
40394
|
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40143
|
-
* @param
|
|
40395
|
+
* @param payload - Optional commit payload with id and note
|
|
40144
40396
|
* @returns Promise that resolves when pending signal is closed
|
|
40145
40397
|
*
|
|
40146
40398
|
* @example
|
|
@@ -40150,14 +40402,14 @@ class BacktestUtils {
|
|
|
40150
40402
|
* exchangeName: "binance",
|
|
40151
40403
|
* strategyName: "my-strategy",
|
|
40152
40404
|
* frameName: "1m"
|
|
40153
|
-
* }, "manual-close-001");
|
|
40405
|
+
* }, { id: "manual-close-001" });
|
|
40154
40406
|
* ```
|
|
40155
40407
|
*/
|
|
40156
|
-
this.commitClosePending = async (symbol, context,
|
|
40408
|
+
this.commitClosePending = async (symbol, context, payload = {}) => {
|
|
40157
40409
|
backtest.loggerService.info(BACKTEST_METHOD_NAME_CLOSE_PENDING, {
|
|
40158
40410
|
symbol,
|
|
40159
40411
|
context,
|
|
40160
|
-
|
|
40412
|
+
payload,
|
|
40161
40413
|
});
|
|
40162
40414
|
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_CLOSE_PENDING);
|
|
40163
40415
|
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_CLOSE_PENDING);
|
|
@@ -40170,7 +40422,7 @@ class BacktestUtils {
|
|
|
40170
40422
|
actions &&
|
|
40171
40423
|
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_CLOSE_PENDING));
|
|
40172
40424
|
}
|
|
40173
|
-
await backtest.strategyCoreService.closePending(true, symbol, context,
|
|
40425
|
+
await backtest.strategyCoreService.closePending(true, symbol, context, payload);
|
|
40174
40426
|
};
|
|
40175
40427
|
/**
|
|
40176
40428
|
* Executes partial close at profit level (moving toward TP).
|
|
@@ -40806,7 +41058,7 @@ class BacktestUtils {
|
|
|
40806
41058
|
*
|
|
40807
41059
|
* @param symbol - Trading pair symbol
|
|
40808
41060
|
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40809
|
-
* @param
|
|
41061
|
+
* @param payload - Optional commit payload with id and note
|
|
40810
41062
|
* @returns Promise that resolves when activation flag is set
|
|
40811
41063
|
*
|
|
40812
41064
|
* @example
|
|
@@ -40816,14 +41068,14 @@ class BacktestUtils {
|
|
|
40816
41068
|
* strategyName: "my-strategy",
|
|
40817
41069
|
* exchangeName: "binance",
|
|
40818
41070
|
* frameName: "1h"
|
|
40819
|
-
* }, "manual-activate-001");
|
|
41071
|
+
* }, { id: "manual-activate-001" });
|
|
40820
41072
|
* ```
|
|
40821
41073
|
*/
|
|
40822
|
-
this.commitActivateScheduled = async (symbol, context,
|
|
41074
|
+
this.commitActivateScheduled = async (symbol, context, payload = {}) => {
|
|
40823
41075
|
backtest.loggerService.info(BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED, {
|
|
40824
41076
|
symbol,
|
|
40825
41077
|
context,
|
|
40826
|
-
|
|
41078
|
+
payload,
|
|
40827
41079
|
});
|
|
40828
41080
|
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED);
|
|
40829
41081
|
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED);
|
|
@@ -40836,7 +41088,7 @@ class BacktestUtils {
|
|
|
40836
41088
|
actions &&
|
|
40837
41089
|
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED));
|
|
40838
41090
|
}
|
|
40839
|
-
await backtest.strategyCoreService.activateScheduled(true, symbol, context,
|
|
41091
|
+
await backtest.strategyCoreService.activateScheduled(true, symbol, context, payload);
|
|
40840
41092
|
};
|
|
40841
41093
|
/**
|
|
40842
41094
|
* Adds a new DCA entry to the active pending signal.
|
|
@@ -41094,6 +41346,8 @@ const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE = "Li
|
|
|
41094
41346
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST = "LiveUtils.getPositionHighestProfitDistancePnlCost";
|
|
41095
41347
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE = "LiveUtils.getPositionHighestMaxDrawdownPnlPercentage";
|
|
41096
41348
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST = "LiveUtils.getPositionHighestMaxDrawdownPnlCost";
|
|
41349
|
+
const LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE = "LiveUtils.getMaxDrawdownDistancePnlPercentage";
|
|
41350
|
+
const LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST = "LiveUtils.getMaxDrawdownDistancePnlCost";
|
|
41097
41351
|
const LIVE_METHOD_NAME_GET_POSITION_ENTRY_OVERLAP = "LiveUtils.getPositionEntryOverlap";
|
|
41098
41352
|
const LIVE_METHOD_NAME_GET_POSITION_PARTIAL_OVERLAP = "LiveUtils.getPositionPartialOverlap";
|
|
41099
41353
|
const LIVE_METHOD_NAME_BREAKEVEN = "Live.commitBreakeven";
|
|
@@ -42618,6 +42872,70 @@ class LiveUtils {
|
|
|
42618
42872
|
frameName: "",
|
|
42619
42873
|
});
|
|
42620
42874
|
};
|
|
42875
|
+
/**
|
|
42876
|
+
* Returns the peak-to-trough PnL percentage distance between the position's highest profit and deepest drawdown.
|
|
42877
|
+
*
|
|
42878
|
+
* Computed as: max(0, peakPnlPercentage - fallPnlPercentage).
|
|
42879
|
+
* Returns null if no pending signal exists.
|
|
42880
|
+
*
|
|
42881
|
+
* @param symbol - Trading pair symbol
|
|
42882
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
42883
|
+
* @returns peak-to-trough PnL percentage distance (≥ 0) or null if no active position
|
|
42884
|
+
*/
|
|
42885
|
+
this.getMaxDrawdownDistancePnlPercentage = async (symbol, context) => {
|
|
42886
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE, {
|
|
42887
|
+
symbol,
|
|
42888
|
+
context,
|
|
42889
|
+
});
|
|
42890
|
+
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
42891
|
+
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
42892
|
+
{
|
|
42893
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
42894
|
+
riskName &&
|
|
42895
|
+
backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
42896
|
+
riskList &&
|
|
42897
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE));
|
|
42898
|
+
actions &&
|
|
42899
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE));
|
|
42900
|
+
}
|
|
42901
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlPercentage(false, symbol, {
|
|
42902
|
+
strategyName: context.strategyName,
|
|
42903
|
+
exchangeName: context.exchangeName,
|
|
42904
|
+
frameName: "",
|
|
42905
|
+
});
|
|
42906
|
+
};
|
|
42907
|
+
/**
|
|
42908
|
+
* Returns the peak-to-trough PnL cost distance between the position's highest profit and deepest drawdown.
|
|
42909
|
+
*
|
|
42910
|
+
* Computed as: max(0, peakPnlCost - fallPnlCost).
|
|
42911
|
+
* Returns null if no pending signal exists.
|
|
42912
|
+
*
|
|
42913
|
+
* @param symbol - Trading pair symbol
|
|
42914
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
42915
|
+
* @returns peak-to-trough PnL cost distance (≥ 0) or null if no active position
|
|
42916
|
+
*/
|
|
42917
|
+
this.getMaxDrawdownDistancePnlCost = async (symbol, context) => {
|
|
42918
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST, {
|
|
42919
|
+
symbol,
|
|
42920
|
+
context,
|
|
42921
|
+
});
|
|
42922
|
+
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
42923
|
+
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
42924
|
+
{
|
|
42925
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
42926
|
+
riskName &&
|
|
42927
|
+
backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
42928
|
+
riskList &&
|
|
42929
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST));
|
|
42930
|
+
actions &&
|
|
42931
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST));
|
|
42932
|
+
}
|
|
42933
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlCost(false, symbol, {
|
|
42934
|
+
strategyName: context.strategyName,
|
|
42935
|
+
exchangeName: context.exchangeName,
|
|
42936
|
+
frameName: "",
|
|
42937
|
+
});
|
|
42938
|
+
};
|
|
42621
42939
|
/**
|
|
42622
42940
|
* Checks whether the current price falls within the tolerance zone of any existing DCA entry level.
|
|
42623
42941
|
* Use this to prevent duplicate DCA entries at the same price area.
|
|
@@ -42759,7 +43077,7 @@ class LiveUtils {
|
|
|
42759
43077
|
* @param symbol - Trading pair symbol
|
|
42760
43078
|
* @param strategyName - Strategy name
|
|
42761
43079
|
* @param context - Execution context with exchangeName and frameName
|
|
42762
|
-
* @param
|
|
43080
|
+
* @param payload - Optional commit payload with id and note
|
|
42763
43081
|
* @returns Promise that resolves when scheduled signal is cancelled
|
|
42764
43082
|
*
|
|
42765
43083
|
* @example
|
|
@@ -42769,14 +43087,14 @@ class LiveUtils {
|
|
|
42769
43087
|
* exchangeName: "binance",
|
|
42770
43088
|
* frameName: "",
|
|
42771
43089
|
* strategyName: "my-strategy"
|
|
42772
|
-
* }, "manual-cancel-001");
|
|
43090
|
+
* }, { id: "manual-cancel-001" });
|
|
42773
43091
|
* ```
|
|
42774
43092
|
*/
|
|
42775
|
-
this.commitCancelScheduled = async (symbol, context,
|
|
43093
|
+
this.commitCancelScheduled = async (symbol, context, payload = {}) => {
|
|
42776
43094
|
backtest.loggerService.info(LIVE_METHOD_NAME_CANCEL_SCHEDULED, {
|
|
42777
43095
|
symbol,
|
|
42778
43096
|
context,
|
|
42779
|
-
|
|
43097
|
+
payload,
|
|
42780
43098
|
});
|
|
42781
43099
|
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_CANCEL_SCHEDULED);
|
|
42782
43100
|
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_CANCEL_SCHEDULED);
|
|
@@ -42793,7 +43111,7 @@ class LiveUtils {
|
|
|
42793
43111
|
strategyName: context.strategyName,
|
|
42794
43112
|
exchangeName: context.exchangeName,
|
|
42795
43113
|
frameName: "",
|
|
42796
|
-
},
|
|
43114
|
+
}, payload);
|
|
42797
43115
|
};
|
|
42798
43116
|
/**
|
|
42799
43117
|
* Closes the pending signal without stopping the strategy.
|
|
@@ -42804,7 +43122,7 @@ class LiveUtils {
|
|
|
42804
43122
|
*
|
|
42805
43123
|
* @param symbol - Trading pair symbol
|
|
42806
43124
|
* @param context - Execution context with strategyName and exchangeName
|
|
42807
|
-
* @param
|
|
43125
|
+
* @param payload - Optional commit payload with id and note
|
|
42808
43126
|
* @returns Promise that resolves when pending signal is closed
|
|
42809
43127
|
*
|
|
42810
43128
|
* @example
|
|
@@ -42813,14 +43131,14 @@ class LiveUtils {
|
|
|
42813
43131
|
* await Live.commitClose("BTCUSDT", {
|
|
42814
43132
|
* exchangeName: "binance",
|
|
42815
43133
|
* strategyName: "my-strategy"
|
|
42816
|
-
* }, "manual-close-001");
|
|
43134
|
+
* }, { id: "manual-close-001" });
|
|
42817
43135
|
* ```
|
|
42818
43136
|
*/
|
|
42819
|
-
this.commitClosePending = async (symbol, context,
|
|
43137
|
+
this.commitClosePending = async (symbol, context, payload = {}) => {
|
|
42820
43138
|
backtest.loggerService.info(LIVE_METHOD_NAME_CLOSE_PENDING, {
|
|
42821
43139
|
symbol,
|
|
42822
43140
|
context,
|
|
42823
|
-
|
|
43141
|
+
payload,
|
|
42824
43142
|
});
|
|
42825
43143
|
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_CLOSE_PENDING);
|
|
42826
43144
|
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_CLOSE_PENDING);
|
|
@@ -42837,7 +43155,7 @@ class LiveUtils {
|
|
|
42837
43155
|
strategyName: context.strategyName,
|
|
42838
43156
|
exchangeName: context.exchangeName,
|
|
42839
43157
|
frameName: "",
|
|
42840
|
-
},
|
|
43158
|
+
}, payload);
|
|
42841
43159
|
};
|
|
42842
43160
|
/**
|
|
42843
43161
|
* Executes partial close at profit level (moving toward TP).
|
|
@@ -43631,7 +43949,7 @@ class LiveUtils {
|
|
|
43631
43949
|
*
|
|
43632
43950
|
* @param symbol - Trading pair symbol
|
|
43633
43951
|
* @param context - Execution context with strategyName and exchangeName
|
|
43634
|
-
* @param
|
|
43952
|
+
* @param payload - Optional commit payload with id and note
|
|
43635
43953
|
* @returns Promise that resolves when activation flag is set
|
|
43636
43954
|
*
|
|
43637
43955
|
* @example
|
|
@@ -43640,14 +43958,14 @@ class LiveUtils {
|
|
|
43640
43958
|
* await Live.commitActivateScheduled("BTCUSDT", {
|
|
43641
43959
|
* strategyName: "my-strategy",
|
|
43642
43960
|
* exchangeName: "binance"
|
|
43643
|
-
* }, "manual-activate-001");
|
|
43961
|
+
* }, { id: "manual-activate-001" });
|
|
43644
43962
|
* ```
|
|
43645
43963
|
*/
|
|
43646
|
-
this.commitActivateScheduled = async (symbol, context,
|
|
43964
|
+
this.commitActivateScheduled = async (symbol, context, payload = {}) => {
|
|
43647
43965
|
backtest.loggerService.info(LIVE_METHOD_NAME_ACTIVATE_SCHEDULED, {
|
|
43648
43966
|
symbol,
|
|
43649
43967
|
context,
|
|
43650
|
-
|
|
43968
|
+
payload,
|
|
43651
43969
|
});
|
|
43652
43970
|
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_ACTIVATE_SCHEDULED);
|
|
43653
43971
|
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_ACTIVATE_SCHEDULED);
|
|
@@ -43664,7 +43982,7 @@ class LiveUtils {
|
|
|
43664
43982
|
strategyName: context.strategyName,
|
|
43665
43983
|
exchangeName: context.exchangeName,
|
|
43666
43984
|
frameName: "",
|
|
43667
|
-
},
|
|
43985
|
+
}, payload);
|
|
43668
43986
|
};
|
|
43669
43987
|
/**
|
|
43670
43988
|
* Adds a new DCA entry to the active pending signal.
|
|
@@ -49735,6 +50053,741 @@ class MaxDrawdownUtils {
|
|
|
49735
50053
|
*/
|
|
49736
50054
|
const MaxDrawdown = new MaxDrawdownUtils();
|
|
49737
50055
|
|
|
50056
|
+
const REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT = "ReflectUtils.getPositionPnlPercent";
|
|
50057
|
+
const REFLECT_METHOD_NAME_GET_POSITION_PNL_COST = "ReflectUtils.getPositionPnlCost";
|
|
50058
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE = "ReflectUtils.getPositionHighestProfitPrice";
|
|
50059
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP = "ReflectUtils.getPositionHighestProfitTimestamp";
|
|
50060
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE = "ReflectUtils.getPositionHighestPnlPercentage";
|
|
50061
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST = "ReflectUtils.getPositionHighestPnlCost";
|
|
50062
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN = "ReflectUtils.getPositionHighestProfitBreakeven";
|
|
50063
|
+
const REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES = "ReflectUtils.getPositionDrawdownMinutes";
|
|
50064
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES = "ReflectUtils.getPositionHighestProfitMinutes";
|
|
50065
|
+
const REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES = "ReflectUtils.getPositionMaxDrawdownMinutes";
|
|
50066
|
+
const REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE = "ReflectUtils.getPositionMaxDrawdownPrice";
|
|
50067
|
+
const REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP = "ReflectUtils.getPositionMaxDrawdownTimestamp";
|
|
50068
|
+
const REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE = "ReflectUtils.getPositionMaxDrawdownPnlPercentage";
|
|
50069
|
+
const REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST = "ReflectUtils.getPositionMaxDrawdownPnlCost";
|
|
50070
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE = "ReflectUtils.getPositionHighestProfitDistancePnlPercentage";
|
|
50071
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST = "ReflectUtils.getPositionHighestProfitDistancePnlCost";
|
|
50072
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE = "ReflectUtils.getPositionHighestMaxDrawdownPnlPercentage";
|
|
50073
|
+
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST = "ReflectUtils.getPositionHighestMaxDrawdownPnlCost";
|
|
50074
|
+
const REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE = "ReflectUtils.getMaxDrawdownDistancePnlPercentage";
|
|
50075
|
+
const REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST = "ReflectUtils.getMaxDrawdownDistancePnlCost";
|
|
50076
|
+
/**
|
|
50077
|
+
* Utility class for real-time position reflection: PNL, peak profit, and drawdown queries.
|
|
50078
|
+
*
|
|
50079
|
+
* Provides unified access to strategyCoreService position state methods with logging
|
|
50080
|
+
* and full validation (strategy, exchange, frame, risk, actions).
|
|
50081
|
+
* Works for both live and backtest modes via the `backtest` parameter.
|
|
50082
|
+
* Exported as singleton instance for convenient usage.
|
|
50083
|
+
*
|
|
50084
|
+
* @example
|
|
50085
|
+
* ```typescript
|
|
50086
|
+
* import { Reflect } from "backtest-kit";
|
|
50087
|
+
*
|
|
50088
|
+
* // Get current unrealized PNL percentage
|
|
50089
|
+
* const pnl = await Reflect.getPositionPnlPercent(
|
|
50090
|
+
* "BTCUSDT",
|
|
50091
|
+
* 45000,
|
|
50092
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50093
|
+
* );
|
|
50094
|
+
* console.log(`PNL: ${pnl}%`);
|
|
50095
|
+
*
|
|
50096
|
+
* // Get peak profit reached
|
|
50097
|
+
* const peakPnl = await Reflect.getPositionHighestPnlPercentage(
|
|
50098
|
+
* "BTCUSDT",
|
|
50099
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50100
|
+
* );
|
|
50101
|
+
* console.log(`Peak PNL: ${peakPnl}%`);
|
|
50102
|
+
* ```
|
|
50103
|
+
*/
|
|
50104
|
+
class ReflectUtils {
|
|
50105
|
+
constructor() {
|
|
50106
|
+
/**
|
|
50107
|
+
* Returns the unrealized PNL percentage for the current pending signal at currentPrice.
|
|
50108
|
+
*
|
|
50109
|
+
* Accounts for partial closes, DCA entries, slippage and fees.
|
|
50110
|
+
* Returns null if no pending signal exists.
|
|
50111
|
+
*
|
|
50112
|
+
* @param symbol - Trading pair symbol
|
|
50113
|
+
* @param currentPrice - Current market price
|
|
50114
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50115
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50116
|
+
* @returns Promise resolving to PNL percentage or null
|
|
50117
|
+
*
|
|
50118
|
+
* @example
|
|
50119
|
+
* ```typescript
|
|
50120
|
+
* const pnl = await Reflect.getPositionPnlPercent(
|
|
50121
|
+
* "BTCUSDT",
|
|
50122
|
+
* 45000,
|
|
50123
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50124
|
+
* );
|
|
50125
|
+
* console.log(`PNL: ${pnl}%`);
|
|
50126
|
+
* ```
|
|
50127
|
+
*/
|
|
50128
|
+
this.getPositionPnlPercent = async (symbol, currentPrice, context, backtest$1 = false) => {
|
|
50129
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT, { symbol, currentPrice, context });
|
|
50130
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT);
|
|
50131
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT);
|
|
50132
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT);
|
|
50133
|
+
{
|
|
50134
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50135
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT);
|
|
50136
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT));
|
|
50137
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_PNL_PERCENT));
|
|
50138
|
+
}
|
|
50139
|
+
return await backtest.strategyCoreService.getPositionPnlPercent(backtest$1, symbol, currentPrice, context);
|
|
50140
|
+
};
|
|
50141
|
+
/**
|
|
50142
|
+
* Returns the unrealized PNL in dollars for the current pending signal at currentPrice.
|
|
50143
|
+
*
|
|
50144
|
+
* Calculated as: pnlPercentage / 100 × totalInvestedCost.
|
|
50145
|
+
* Accounts for partial closes, DCA entries, slippage and fees.
|
|
50146
|
+
* Returns null if no pending signal exists.
|
|
50147
|
+
*
|
|
50148
|
+
* @param symbol - Trading pair symbol
|
|
50149
|
+
* @param currentPrice - Current market price
|
|
50150
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50151
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50152
|
+
* @returns Promise resolving to PNL in dollars or null
|
|
50153
|
+
*
|
|
50154
|
+
* @example
|
|
50155
|
+
* ```typescript
|
|
50156
|
+
* const pnlCost = await Reflect.getPositionPnlCost(
|
|
50157
|
+
* "BTCUSDT",
|
|
50158
|
+
* 45000,
|
|
50159
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50160
|
+
* );
|
|
50161
|
+
* console.log(`PNL: $${pnlCost}`);
|
|
50162
|
+
* ```
|
|
50163
|
+
*/
|
|
50164
|
+
this.getPositionPnlCost = async (symbol, currentPrice, context, backtest$1 = false) => {
|
|
50165
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_PNL_COST, { symbol, currentPrice, context });
|
|
50166
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_PNL_COST);
|
|
50167
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_PNL_COST);
|
|
50168
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_PNL_COST);
|
|
50169
|
+
{
|
|
50170
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50171
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_PNL_COST);
|
|
50172
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_PNL_COST));
|
|
50173
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_PNL_COST));
|
|
50174
|
+
}
|
|
50175
|
+
return await backtest.strategyCoreService.getPositionPnlCost(backtest$1, symbol, currentPrice, context);
|
|
50176
|
+
};
|
|
50177
|
+
/**
|
|
50178
|
+
* Returns the best price reached in the profit direction during this position's life.
|
|
50179
|
+
*
|
|
50180
|
+
* Returns null if no pending signal exists.
|
|
50181
|
+
*
|
|
50182
|
+
* @param symbol - Trading pair symbol
|
|
50183
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50184
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50185
|
+
* @returns Promise resolving to price or null
|
|
50186
|
+
*
|
|
50187
|
+
* @example
|
|
50188
|
+
* ```typescript
|
|
50189
|
+
* const peakPrice = await Reflect.getPositionHighestProfitPrice(
|
|
50190
|
+
* "BTCUSDT",
|
|
50191
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50192
|
+
* );
|
|
50193
|
+
* console.log(`Peak price: ${peakPrice}`);
|
|
50194
|
+
* ```
|
|
50195
|
+
*/
|
|
50196
|
+
this.getPositionHighestProfitPrice = async (symbol, context, backtest$1 = false) => {
|
|
50197
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE, { symbol, context });
|
|
50198
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE);
|
|
50199
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE);
|
|
50200
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE);
|
|
50201
|
+
{
|
|
50202
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50203
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE);
|
|
50204
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE));
|
|
50205
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE));
|
|
50206
|
+
}
|
|
50207
|
+
return await backtest.strategyCoreService.getPositionHighestProfitPrice(backtest$1, symbol, context);
|
|
50208
|
+
};
|
|
50209
|
+
/**
|
|
50210
|
+
* Returns the timestamp when the best profit price was recorded during this position's life.
|
|
50211
|
+
*
|
|
50212
|
+
* Returns null if no pending signal exists.
|
|
50213
|
+
*
|
|
50214
|
+
* @param symbol - Trading pair symbol
|
|
50215
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50216
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50217
|
+
* @returns Promise resolving to timestamp in milliseconds or null
|
|
50218
|
+
*
|
|
50219
|
+
* @example
|
|
50220
|
+
* ```typescript
|
|
50221
|
+
* const ts = await Reflect.getPositionHighestProfitTimestamp(
|
|
50222
|
+
* "BTCUSDT",
|
|
50223
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50224
|
+
* );
|
|
50225
|
+
* console.log(`Peak at: ${new Date(ts).toISOString()}`);
|
|
50226
|
+
* ```
|
|
50227
|
+
*/
|
|
50228
|
+
this.getPositionHighestProfitTimestamp = async (symbol, context, backtest$1 = false) => {
|
|
50229
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP, { symbol, context });
|
|
50230
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP);
|
|
50231
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP);
|
|
50232
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP);
|
|
50233
|
+
{
|
|
50234
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50235
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP);
|
|
50236
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP));
|
|
50237
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP));
|
|
50238
|
+
}
|
|
50239
|
+
return await backtest.strategyCoreService.getPositionHighestProfitTimestamp(backtest$1, symbol, context);
|
|
50240
|
+
};
|
|
50241
|
+
/**
|
|
50242
|
+
* Returns the PnL percentage at the moment the best profit price was recorded during this position's life.
|
|
50243
|
+
*
|
|
50244
|
+
* Returns null if no pending signal exists.
|
|
50245
|
+
*
|
|
50246
|
+
* @param symbol - Trading pair symbol
|
|
50247
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50248
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50249
|
+
* @returns Promise resolving to PnL percentage or null
|
|
50250
|
+
*
|
|
50251
|
+
* @example
|
|
50252
|
+
* ```typescript
|
|
50253
|
+
* const peakPnl = await Reflect.getPositionHighestPnlPercentage(
|
|
50254
|
+
* "BTCUSDT",
|
|
50255
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50256
|
+
* );
|
|
50257
|
+
* console.log(`Peak PNL: ${peakPnl}%`);
|
|
50258
|
+
* ```
|
|
50259
|
+
*/
|
|
50260
|
+
this.getPositionHighestPnlPercentage = async (symbol, context, backtest$1 = false) => {
|
|
50261
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE, { symbol, context });
|
|
50262
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE);
|
|
50263
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE);
|
|
50264
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE);
|
|
50265
|
+
{
|
|
50266
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50267
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE);
|
|
50268
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE));
|
|
50269
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE));
|
|
50270
|
+
}
|
|
50271
|
+
return await backtest.strategyCoreService.getPositionHighestPnlPercentage(backtest$1, symbol, context);
|
|
50272
|
+
};
|
|
50273
|
+
/**
|
|
50274
|
+
* Returns the PnL cost (in quote currency) at the moment the best profit price was recorded during this position's life.
|
|
50275
|
+
*
|
|
50276
|
+
* Returns null if no pending signal exists.
|
|
50277
|
+
*
|
|
50278
|
+
* @param symbol - Trading pair symbol
|
|
50279
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50280
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50281
|
+
* @returns Promise resolving to PnL cost in quote currency or null
|
|
50282
|
+
*
|
|
50283
|
+
* @example
|
|
50284
|
+
* ```typescript
|
|
50285
|
+
* const peakCost = await Reflect.getPositionHighestPnlCost(
|
|
50286
|
+
* "BTCUSDT",
|
|
50287
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50288
|
+
* );
|
|
50289
|
+
* console.log(`Peak PNL: $${peakCost}`);
|
|
50290
|
+
* ```
|
|
50291
|
+
*/
|
|
50292
|
+
this.getPositionHighestPnlCost = async (symbol, context, backtest$1 = false) => {
|
|
50293
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST, { symbol, context });
|
|
50294
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST);
|
|
50295
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST);
|
|
50296
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST);
|
|
50297
|
+
{
|
|
50298
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50299
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST);
|
|
50300
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST));
|
|
50301
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST));
|
|
50302
|
+
}
|
|
50303
|
+
return await backtest.strategyCoreService.getPositionHighestPnlCost(backtest$1, symbol, context);
|
|
50304
|
+
};
|
|
50305
|
+
/**
|
|
50306
|
+
* Returns whether breakeven was mathematically reachable at the highest profit price.
|
|
50307
|
+
*
|
|
50308
|
+
* Returns null if no pending signal exists.
|
|
50309
|
+
*
|
|
50310
|
+
* @param symbol - Trading pair symbol
|
|
50311
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50312
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50313
|
+
* @returns Promise resolving to true if breakeven was reachable at peak, false otherwise, or null
|
|
50314
|
+
*
|
|
50315
|
+
* @example
|
|
50316
|
+
* ```typescript
|
|
50317
|
+
* const wasReachable = await Reflect.getPositionHighestProfitBreakeven(
|
|
50318
|
+
* "BTCUSDT",
|
|
50319
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50320
|
+
* );
|
|
50321
|
+
* console.log(`Breakeven reachable at peak: ${wasReachable}`);
|
|
50322
|
+
* ```
|
|
50323
|
+
*/
|
|
50324
|
+
this.getPositionHighestProfitBreakeven = async (symbol, context, backtest$1 = false) => {
|
|
50325
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN, { symbol, context });
|
|
50326
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN);
|
|
50327
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN);
|
|
50328
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN);
|
|
50329
|
+
{
|
|
50330
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50331
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN);
|
|
50332
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN));
|
|
50333
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN));
|
|
50334
|
+
}
|
|
50335
|
+
return await backtest.strategyCoreService.getPositionHighestProfitBreakeven(backtest$1, symbol, context);
|
|
50336
|
+
};
|
|
50337
|
+
/**
|
|
50338
|
+
* Returns the number of minutes elapsed since the highest profit price was recorded.
|
|
50339
|
+
*
|
|
50340
|
+
* Returns null if no pending signal exists.
|
|
50341
|
+
*
|
|
50342
|
+
* @param symbol - Trading pair symbol
|
|
50343
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50344
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50345
|
+
* @returns Promise resolving to minutes since highest profit price was recorded, or null
|
|
50346
|
+
*
|
|
50347
|
+
* @example
|
|
50348
|
+
* ```typescript
|
|
50349
|
+
* const minutes = await Reflect.getPositionDrawdownMinutes(
|
|
50350
|
+
* "BTCUSDT",
|
|
50351
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50352
|
+
* );
|
|
50353
|
+
* console.log(`Pulling back from peak for ${minutes} minutes`);
|
|
50354
|
+
* ```
|
|
50355
|
+
*/
|
|
50356
|
+
this.getPositionDrawdownMinutes = async (symbol, context, backtest$1 = false) => {
|
|
50357
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES, { symbol, context });
|
|
50358
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES);
|
|
50359
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES);
|
|
50360
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES);
|
|
50361
|
+
{
|
|
50362
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50363
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES);
|
|
50364
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES));
|
|
50365
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES));
|
|
50366
|
+
}
|
|
50367
|
+
return await backtest.strategyCoreService.getPositionDrawdownMinutes(backtest$1, symbol, context);
|
|
50368
|
+
};
|
|
50369
|
+
/**
|
|
50370
|
+
* Returns the number of minutes elapsed since the highest profit price was recorded.
|
|
50371
|
+
*
|
|
50372
|
+
* Alias for getPositionDrawdownMinutes — measures how long the position has been
|
|
50373
|
+
* pulling back from its peak profit level.
|
|
50374
|
+
* Returns null if no pending signal exists.
|
|
50375
|
+
*
|
|
50376
|
+
* @param symbol - Trading pair symbol
|
|
50377
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50378
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50379
|
+
* @returns Promise resolving to minutes since last profit peak or null
|
|
50380
|
+
*
|
|
50381
|
+
* @example
|
|
50382
|
+
* ```typescript
|
|
50383
|
+
* const minutes = await Reflect.getPositionHighestProfitMinutes(
|
|
50384
|
+
* "BTCUSDT",
|
|
50385
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50386
|
+
* );
|
|
50387
|
+
* console.log(`Pulling back from peak for ${minutes} minutes`);
|
|
50388
|
+
* ```
|
|
50389
|
+
*/
|
|
50390
|
+
this.getPositionHighestProfitMinutes = async (symbol, context, backtest$1 = false) => {
|
|
50391
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES, { symbol, context });
|
|
50392
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES);
|
|
50393
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES);
|
|
50394
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES);
|
|
50395
|
+
{
|
|
50396
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50397
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES);
|
|
50398
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES));
|
|
50399
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES));
|
|
50400
|
+
}
|
|
50401
|
+
return await backtest.strategyCoreService.getPositionHighestProfitMinutes(backtest$1, symbol, context);
|
|
50402
|
+
};
|
|
50403
|
+
/**
|
|
50404
|
+
* Returns the number of minutes elapsed since the worst loss price was recorded.
|
|
50405
|
+
*
|
|
50406
|
+
* Measures how long ago the deepest drawdown point occurred.
|
|
50407
|
+
* Zero when called at the exact moment the trough was set.
|
|
50408
|
+
* Returns null if no pending signal exists.
|
|
50409
|
+
*
|
|
50410
|
+
* @param symbol - Trading pair symbol
|
|
50411
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50412
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50413
|
+
* @returns Promise resolving to minutes since last drawdown trough or null
|
|
50414
|
+
*
|
|
50415
|
+
* @example
|
|
50416
|
+
* ```typescript
|
|
50417
|
+
* const minutes = await Reflect.getPositionMaxDrawdownMinutes(
|
|
50418
|
+
* "BTCUSDT",
|
|
50419
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50420
|
+
* );
|
|
50421
|
+
* console.log(`Drawdown trough was ${minutes} minutes ago`);
|
|
50422
|
+
* ```
|
|
50423
|
+
*/
|
|
50424
|
+
this.getPositionMaxDrawdownMinutes = async (symbol, context, backtest$1 = false) => {
|
|
50425
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES, { symbol, context });
|
|
50426
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES);
|
|
50427
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES);
|
|
50428
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES);
|
|
50429
|
+
{
|
|
50430
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50431
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES);
|
|
50432
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES));
|
|
50433
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES));
|
|
50434
|
+
}
|
|
50435
|
+
return await backtest.strategyCoreService.getPositionMaxDrawdownMinutes(backtest$1, symbol, context);
|
|
50436
|
+
};
|
|
50437
|
+
/**
|
|
50438
|
+
* Returns the worst price reached in the loss direction during this position's life.
|
|
50439
|
+
*
|
|
50440
|
+
* Returns null if no pending signal exists.
|
|
50441
|
+
*
|
|
50442
|
+
* @param symbol - Trading pair symbol
|
|
50443
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50444
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50445
|
+
* @returns Promise resolving to price or null
|
|
50446
|
+
*
|
|
50447
|
+
* @example
|
|
50448
|
+
* ```typescript
|
|
50449
|
+
* const troughPrice = await Reflect.getPositionMaxDrawdownPrice(
|
|
50450
|
+
* "BTCUSDT",
|
|
50451
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50452
|
+
* );
|
|
50453
|
+
* console.log(`Worst price: ${troughPrice}`);
|
|
50454
|
+
* ```
|
|
50455
|
+
*/
|
|
50456
|
+
this.getPositionMaxDrawdownPrice = async (symbol, context, backtest$1 = false) => {
|
|
50457
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE, { symbol, context });
|
|
50458
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE);
|
|
50459
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE);
|
|
50460
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE);
|
|
50461
|
+
{
|
|
50462
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50463
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE);
|
|
50464
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE));
|
|
50465
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE));
|
|
50466
|
+
}
|
|
50467
|
+
return await backtest.strategyCoreService.getPositionMaxDrawdownPrice(backtest$1, symbol, context);
|
|
50468
|
+
};
|
|
50469
|
+
/**
|
|
50470
|
+
* Returns the timestamp when the worst loss price was recorded during this position's life.
|
|
50471
|
+
*
|
|
50472
|
+
* Returns null if no pending signal exists.
|
|
50473
|
+
*
|
|
50474
|
+
* @param symbol - Trading pair symbol
|
|
50475
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50476
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50477
|
+
* @returns Promise resolving to timestamp in milliseconds or null
|
|
50478
|
+
*
|
|
50479
|
+
* @example
|
|
50480
|
+
* ```typescript
|
|
50481
|
+
* const ts = await Reflect.getPositionMaxDrawdownTimestamp(
|
|
50482
|
+
* "BTCUSDT",
|
|
50483
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50484
|
+
* );
|
|
50485
|
+
* console.log(`Worst drawdown at: ${new Date(ts).toISOString()}`);
|
|
50486
|
+
* ```
|
|
50487
|
+
*/
|
|
50488
|
+
this.getPositionMaxDrawdownTimestamp = async (symbol, context, backtest$1 = false) => {
|
|
50489
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP, { symbol, context });
|
|
50490
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP);
|
|
50491
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP);
|
|
50492
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP);
|
|
50493
|
+
{
|
|
50494
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50495
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP);
|
|
50496
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP));
|
|
50497
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP));
|
|
50498
|
+
}
|
|
50499
|
+
return await backtest.strategyCoreService.getPositionMaxDrawdownTimestamp(backtest$1, symbol, context);
|
|
50500
|
+
};
|
|
50501
|
+
/**
|
|
50502
|
+
* Returns the PnL percentage at the moment the worst loss price was recorded during this position's life.
|
|
50503
|
+
*
|
|
50504
|
+
* Returns null if no pending signal exists.
|
|
50505
|
+
*
|
|
50506
|
+
* @param symbol - Trading pair symbol
|
|
50507
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50508
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50509
|
+
* @returns Promise resolving to PnL percentage or null
|
|
50510
|
+
*
|
|
50511
|
+
* @example
|
|
50512
|
+
* ```typescript
|
|
50513
|
+
* const worstPnl = await Reflect.getPositionMaxDrawdownPnlPercentage(
|
|
50514
|
+
* "BTCUSDT",
|
|
50515
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50516
|
+
* );
|
|
50517
|
+
* console.log(`Worst PNL: ${worstPnl}%`);
|
|
50518
|
+
* ```
|
|
50519
|
+
*/
|
|
50520
|
+
this.getPositionMaxDrawdownPnlPercentage = async (symbol, context, backtest$1 = false) => {
|
|
50521
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE, { symbol, context });
|
|
50522
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50523
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50524
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50525
|
+
{
|
|
50526
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50527
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50528
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE));
|
|
50529
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE));
|
|
50530
|
+
}
|
|
50531
|
+
return await backtest.strategyCoreService.getPositionMaxDrawdownPnlPercentage(backtest$1, symbol, context);
|
|
50532
|
+
};
|
|
50533
|
+
/**
|
|
50534
|
+
* Returns the PnL cost (in quote currency) at the moment the worst loss price was recorded during this position's life.
|
|
50535
|
+
*
|
|
50536
|
+
* Returns null if no pending signal exists.
|
|
50537
|
+
*
|
|
50538
|
+
* @param symbol - Trading pair symbol
|
|
50539
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50540
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50541
|
+
* @returns Promise resolving to PnL cost in quote currency or null
|
|
50542
|
+
*
|
|
50543
|
+
* @example
|
|
50544
|
+
* ```typescript
|
|
50545
|
+
* const worstCost = await Reflect.getPositionMaxDrawdownPnlCost(
|
|
50546
|
+
* "BTCUSDT",
|
|
50547
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50548
|
+
* );
|
|
50549
|
+
* console.log(`Worst PNL: $${worstCost}`);
|
|
50550
|
+
* ```
|
|
50551
|
+
*/
|
|
50552
|
+
this.getPositionMaxDrawdownPnlCost = async (symbol, context, backtest$1 = false) => {
|
|
50553
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST, { symbol, context });
|
|
50554
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST);
|
|
50555
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST);
|
|
50556
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST);
|
|
50557
|
+
{
|
|
50558
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50559
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST);
|
|
50560
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST));
|
|
50561
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST));
|
|
50562
|
+
}
|
|
50563
|
+
return await backtest.strategyCoreService.getPositionMaxDrawdownPnlCost(backtest$1, symbol, context);
|
|
50564
|
+
};
|
|
50565
|
+
/**
|
|
50566
|
+
* Returns the distance in PnL percentage between the current price and the highest profit peak.
|
|
50567
|
+
*
|
|
50568
|
+
* Result is ≥ 0. Returns null if no pending signal exists.
|
|
50569
|
+
*
|
|
50570
|
+
* @param symbol - Trading pair symbol
|
|
50571
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50572
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50573
|
+
* @returns Promise resolving to drawdown distance in PnL% (≥ 0) or null
|
|
50574
|
+
*
|
|
50575
|
+
* @example
|
|
50576
|
+
* ```typescript
|
|
50577
|
+
* const distance = await Reflect.getPositionHighestProfitDistancePnlPercentage(
|
|
50578
|
+
* "BTCUSDT",
|
|
50579
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50580
|
+
* );
|
|
50581
|
+
* console.log(`Dropped ${distance}% from peak`);
|
|
50582
|
+
* ```
|
|
50583
|
+
*/
|
|
50584
|
+
this.getPositionHighestProfitDistancePnlPercentage = async (symbol, context, backtest$1 = false) => {
|
|
50585
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE, { symbol, context });
|
|
50586
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
|
|
50587
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
|
|
50588
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
|
|
50589
|
+
{
|
|
50590
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50591
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
|
|
50592
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE));
|
|
50593
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE));
|
|
50594
|
+
}
|
|
50595
|
+
return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlPercentage(backtest$1, symbol, context);
|
|
50596
|
+
};
|
|
50597
|
+
/**
|
|
50598
|
+
* Returns the distance in PnL cost between the current price and the highest profit peak.
|
|
50599
|
+
*
|
|
50600
|
+
* Result is ≥ 0. Returns null if no pending signal exists.
|
|
50601
|
+
*
|
|
50602
|
+
* @param symbol - Trading pair symbol
|
|
50603
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50604
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50605
|
+
* @returns Promise resolving to drawdown distance in PnL cost (≥ 0) or null
|
|
50606
|
+
*
|
|
50607
|
+
* @example
|
|
50608
|
+
* ```typescript
|
|
50609
|
+
* const distance = await Reflect.getPositionHighestProfitDistancePnlCost(
|
|
50610
|
+
* "BTCUSDT",
|
|
50611
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50612
|
+
* );
|
|
50613
|
+
* console.log(`Dropped $${distance} from peak`);
|
|
50614
|
+
* ```
|
|
50615
|
+
*/
|
|
50616
|
+
this.getPositionHighestProfitDistancePnlCost = async (symbol, context, backtest$1 = false) => {
|
|
50617
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST, { symbol, context });
|
|
50618
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
|
|
50619
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
|
|
50620
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
|
|
50621
|
+
{
|
|
50622
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50623
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
|
|
50624
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST));
|
|
50625
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST));
|
|
50626
|
+
}
|
|
50627
|
+
return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlCost(backtest$1, symbol, context);
|
|
50628
|
+
};
|
|
50629
|
+
/**
|
|
50630
|
+
* Returns the distance in PnL percentage between the current price and the worst drawdown trough.
|
|
50631
|
+
*
|
|
50632
|
+
* Result is ≥ 0. Returns null if no pending signal exists.
|
|
50633
|
+
*
|
|
50634
|
+
* @param symbol - Trading pair symbol
|
|
50635
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50636
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50637
|
+
* @returns Promise resolving to recovery distance from worst drawdown trough in PnL% (≥ 0) or null
|
|
50638
|
+
*
|
|
50639
|
+
* @example
|
|
50640
|
+
* ```typescript
|
|
50641
|
+
* const distance = await Reflect.getPositionHighestMaxDrawdownPnlPercentage(
|
|
50642
|
+
* "BTCUSDT",
|
|
50643
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50644
|
+
* );
|
|
50645
|
+
* console.log(`${distance}% above worst trough`);
|
|
50646
|
+
* ```
|
|
50647
|
+
*/
|
|
50648
|
+
this.getPositionHighestMaxDrawdownPnlPercentage = async (symbol, context, backtest$1 = false) => {
|
|
50649
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE, { symbol, context });
|
|
50650
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50651
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50652
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50653
|
+
{
|
|
50654
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50655
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
|
|
50656
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE));
|
|
50657
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE));
|
|
50658
|
+
}
|
|
50659
|
+
return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlPercentage(backtest$1, symbol, context);
|
|
50660
|
+
};
|
|
50661
|
+
/**
|
|
50662
|
+
* Returns the distance in PnL cost between the current price and the worst drawdown trough.
|
|
50663
|
+
*
|
|
50664
|
+
* Result is ≥ 0. Returns null if no pending signal exists.
|
|
50665
|
+
*
|
|
50666
|
+
* @param symbol - Trading pair symbol
|
|
50667
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50668
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50669
|
+
* @returns Promise resolving to recovery distance from worst drawdown trough in PnL cost (≥ 0) or null
|
|
50670
|
+
*
|
|
50671
|
+
* @example
|
|
50672
|
+
* ```typescript
|
|
50673
|
+
* const distance = await Reflect.getPositionHighestMaxDrawdownPnlCost(
|
|
50674
|
+
* "BTCUSDT",
|
|
50675
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50676
|
+
* );
|
|
50677
|
+
* console.log(`$${distance} above worst trough`);
|
|
50678
|
+
* ```
|
|
50679
|
+
*/
|
|
50680
|
+
this.getPositionHighestMaxDrawdownPnlCost = async (symbol, context, backtest$1 = false) => {
|
|
50681
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST, { symbol, context });
|
|
50682
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
|
|
50683
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
|
|
50684
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
|
|
50685
|
+
{
|
|
50686
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50687
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
|
|
50688
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST));
|
|
50689
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST));
|
|
50690
|
+
}
|
|
50691
|
+
return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlCost(backtest$1, symbol, context);
|
|
50692
|
+
};
|
|
50693
|
+
/**
|
|
50694
|
+
* Returns the peak-to-trough PnL percentage distance between the position's highest profit and deepest drawdown.
|
|
50695
|
+
*
|
|
50696
|
+
* Result is ≥ 0. Returns null if no pending signal exists.
|
|
50697
|
+
*
|
|
50698
|
+
* @param symbol - Trading pair symbol
|
|
50699
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50700
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50701
|
+
* @returns Promise resolving to peak-to-trough PnL percentage distance (≥ 0) or null
|
|
50702
|
+
*
|
|
50703
|
+
* @example
|
|
50704
|
+
* ```typescript
|
|
50705
|
+
* const distance = await Reflect.getMaxDrawdownDistancePnlPercentage(
|
|
50706
|
+
* "BTCUSDT",
|
|
50707
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50708
|
+
* );
|
|
50709
|
+
* console.log(`Peak-to-trough: ${distance}%`);
|
|
50710
|
+
* ```
|
|
50711
|
+
*/
|
|
50712
|
+
this.getMaxDrawdownDistancePnlPercentage = async (symbol, context, backtest$1 = false) => {
|
|
50713
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE, { symbol, context });
|
|
50714
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
50715
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
50716
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
50717
|
+
{
|
|
50718
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50719
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE);
|
|
50720
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE));
|
|
50721
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_PERCENTAGE));
|
|
50722
|
+
}
|
|
50723
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlPercentage(backtest$1, symbol, context);
|
|
50724
|
+
};
|
|
50725
|
+
/**
|
|
50726
|
+
* Returns the peak-to-trough PnL cost distance between the position's highest profit and deepest drawdown.
|
|
50727
|
+
*
|
|
50728
|
+
* Result is ≥ 0. Returns null if no pending signal exists.
|
|
50729
|
+
*
|
|
50730
|
+
* @param symbol - Trading pair symbol
|
|
50731
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
50732
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
50733
|
+
* @returns Promise resolving to peak-to-trough PnL cost distance (≥ 0) or null
|
|
50734
|
+
*
|
|
50735
|
+
* @example
|
|
50736
|
+
* ```typescript
|
|
50737
|
+
* const distance = await Reflect.getMaxDrawdownDistancePnlCost(
|
|
50738
|
+
* "BTCUSDT",
|
|
50739
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50740
|
+
* );
|
|
50741
|
+
* console.log(`Peak-to-trough: $${distance}`);
|
|
50742
|
+
* ```
|
|
50743
|
+
*/
|
|
50744
|
+
this.getMaxDrawdownDistancePnlCost = async (symbol, context, backtest$1 = false) => {
|
|
50745
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST, { symbol, context });
|
|
50746
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
50747
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
50748
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
50749
|
+
{
|
|
50750
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
50751
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST);
|
|
50752
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST));
|
|
50753
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_MAX_DRAWDOWN_DISTANCE_PNL_COST));
|
|
50754
|
+
}
|
|
50755
|
+
return await backtest.strategyCoreService.getMaxDrawdownDistancePnlCost(backtest$1, symbol, context);
|
|
50756
|
+
};
|
|
50757
|
+
}
|
|
50758
|
+
}
|
|
50759
|
+
/**
|
|
50760
|
+
* Singleton instance of ReflectUtils for convenient position state queries.
|
|
50761
|
+
*
|
|
50762
|
+
* @example
|
|
50763
|
+
* ```typescript
|
|
50764
|
+
* import { Reflect } from "backtest-kit";
|
|
50765
|
+
*
|
|
50766
|
+
* // Real-time PNL
|
|
50767
|
+
* const pnl = await Reflect.getPositionPnlPercent(
|
|
50768
|
+
* "BTCUSDT",
|
|
50769
|
+
* 45000,
|
|
50770
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50771
|
+
* );
|
|
50772
|
+
* console.log(`PNL: ${pnl}%`);
|
|
50773
|
+
*
|
|
50774
|
+
* // Peak profit
|
|
50775
|
+
* const peakPnl = await Reflect.getPositionHighestPnlPercentage(
|
|
50776
|
+
* "BTCUSDT",
|
|
50777
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50778
|
+
* );
|
|
50779
|
+
* console.log(`Peak PNL: ${peakPnl}%`);
|
|
50780
|
+
*
|
|
50781
|
+
* // Drawdown from peak
|
|
50782
|
+
* const drawdown = await Reflect.getPositionHighestProfitDistancePnlPercentage(
|
|
50783
|
+
* "BTCUSDT",
|
|
50784
|
+
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "frame1" }
|
|
50785
|
+
* );
|
|
50786
|
+
* console.log(`Dropped ${drawdown}% from peak`);
|
|
50787
|
+
* ```
|
|
50788
|
+
*/
|
|
50789
|
+
const Reflect$1 = new ReflectUtils();
|
|
50790
|
+
|
|
49738
50791
|
/**
|
|
49739
50792
|
* Utility class containing predefined trading constants for take-profit and stop-loss levels.
|
|
49740
50793
|
*
|
|
@@ -55802,4 +56855,4 @@ const validateSignal = (signal, currentPrice) => {
|
|
|
55802
56855
|
return !errors.length;
|
|
55803
56856
|
};
|
|
55804
56857
|
|
|
55805
|
-
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistCandleAdapter, PersistIntervalAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistMemoryAdapter, PersistNotificationAdapter, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PersistStorageAdapter, Position, PositionSize, Report, ReportBase, ReportWriter, Risk, Schedule, Storage, StorageBacktest, StorageLive, Strategy, Sync, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getRawCandles, getRiskSchema, getScheduledSignal, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, warmCandles, writeMemory };
|
|
56858
|
+
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistCandleAdapter, PersistIntervalAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistMemoryAdapter, PersistNotificationAdapter, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PersistStorageAdapter, Position, PositionSize, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Storage, StorageBacktest, StorageLive, Strategy, Sync, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getRawCandles, getRiskSchema, getScheduledSignal, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, warmCandles, writeMemory };
|