backtest-kit 6.9.0 → 6.10.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.mjs CHANGED
@@ -7970,6 +7970,90 @@ class ClientStrategy {
7970
7970
  }
7971
7971
  return this._pendingSignal._fall.pnlCost;
7972
7972
  }
7973
+ /**
7974
+ * Returns the distance in PnL percentage between the current price and the highest profit peak.
7975
+ *
7976
+ * Measures how much PnL% the position has given back from its best point.
7977
+ * Computed as: max(0, peakPnlPercentage - currentPnlPercentage).
7978
+ * Zero when called at the exact moment the peak was set, or when current PnL >= peak PnL.
7979
+ *
7980
+ * Returns null if no pending signal exists.
7981
+ *
7982
+ * @param symbol - Trading pair symbol
7983
+ * @param currentPrice - Current market price
7984
+ * @returns Promise resolving to drawdown distance in PnL% (≥ 0) or null
7985
+ */
7986
+ async getPositionHighestProfitDistancePnlPercentage(symbol, currentPrice) {
7987
+ this.params.logger.debug("ClientStrategy getPositionHighestProfitDistancePnlPercentage", { symbol, currentPrice });
7988
+ if (!this._pendingSignal) {
7989
+ return null;
7990
+ }
7991
+ const currentPnl = toProfitLossDto(this._pendingSignal, currentPrice);
7992
+ return Math.max(0, this._pendingSignal._peak.pnlPercentage - currentPnl.pnlPercentage);
7993
+ }
7994
+ /**
7995
+ * Returns the distance in PnL cost between the current price and the highest profit peak.
7996
+ *
7997
+ * Measures how much PnL cost the position has given back from its best point.
7998
+ * Computed as: max(0, peakPnlCost - currentPnlCost).
7999
+ * Zero when called at the exact moment the peak was set, or when current PnL >= peak PnL.
8000
+ *
8001
+ * Returns null if no pending signal exists.
8002
+ *
8003
+ * @param symbol - Trading pair symbol
8004
+ * @param currentPrice - Current market price
8005
+ * @returns Promise resolving to drawdown distance in PnL cost (≥ 0) or null
8006
+ */
8007
+ async getPositionHighestProfitDistancePnlCost(symbol, currentPrice) {
8008
+ this.params.logger.debug("ClientStrategy getPositionHighestProfitDistancePnlCost", { symbol, currentPrice });
8009
+ if (!this._pendingSignal) {
8010
+ return null;
8011
+ }
8012
+ const currentPnl = toProfitLossDto(this._pendingSignal, currentPrice);
8013
+ return Math.max(0, this._pendingSignal._peak.pnlCost - currentPnl.pnlCost);
8014
+ }
8015
+ /**
8016
+ * Returns the distance in PnL percentage between the current price and the worst drawdown trough.
8017
+ *
8018
+ * Measures how much the position has recovered from its deepest loss point.
8019
+ * Computed as: max(0, currentPnlPercentage - fallPnlPercentage).
8020
+ * Zero when called at the exact moment the trough was set, or when current PnL <= trough PnL.
8021
+ *
8022
+ * Returns null if no pending signal exists.
8023
+ *
8024
+ * @param symbol - Trading pair symbol
8025
+ * @param currentPrice - Current market price
8026
+ * @returns Promise resolving to recovery distance in PnL% (≥ 0) or null
8027
+ */
8028
+ async getPositionHighestMaxDrawdownPnlPercentage(symbol, currentPrice) {
8029
+ this.params.logger.debug("ClientStrategy getPositionHighestMaxDrawdownPnlPercentage", { symbol, currentPrice });
8030
+ if (!this._pendingSignal) {
8031
+ return null;
8032
+ }
8033
+ const currentPnl = toProfitLossDto(this._pendingSignal, currentPrice);
8034
+ return Math.max(0, currentPnl.pnlPercentage - this._pendingSignal._fall.pnlPercentage);
8035
+ }
8036
+ /**
8037
+ * Returns the distance in PnL cost between the current price and the worst drawdown trough.
8038
+ *
8039
+ * Measures how much the position has recovered from its deepest loss point.
8040
+ * Computed as: max(0, currentPnlCost - fallPnlCost).
8041
+ * Zero when called at the exact moment the trough was set, or when current PnL <= trough PnL.
8042
+ *
8043
+ * Returns null if no pending signal exists.
8044
+ *
8045
+ * @param symbol - Trading pair symbol
8046
+ * @param currentPrice - Current market price
8047
+ * @returns Promise resolving to recovery distance in PnL cost (≥ 0) or null
8048
+ */
8049
+ async getPositionHighestMaxDrawdownPnlCost(symbol, currentPrice) {
8050
+ this.params.logger.debug("ClientStrategy getPositionHighestMaxDrawdownPnlCost", { symbol, currentPrice });
8051
+ if (!this._pendingSignal) {
8052
+ return null;
8053
+ }
8054
+ const currentPnl = toProfitLossDto(this._pendingSignal, currentPrice);
8055
+ return Math.max(0, currentPnl.pnlCost - this._pendingSignal._fall.pnlCost);
8056
+ }
7973
8057
  /**
7974
8058
  * Performs a single tick of strategy execution.
7975
8059
  *
@@ -11077,6 +11161,90 @@ class StrategyConnectionService {
11077
11161
  const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
11078
11162
  return await strategy.getPositionMaxDrawdownPnlCost(symbol);
11079
11163
  };
11164
+ /**
11165
+ * Returns the distance in PnL percentage between the current price and the highest profit peak.
11166
+ *
11167
+ * Resolves current price via priceMetaService and delegates to
11168
+ * ClientStrategy.getPositionHighestProfitDistancePnlPercentage().
11169
+ * Returns null if no pending signal exists.
11170
+ *
11171
+ * @param backtest - Whether running in backtest mode
11172
+ * @param symbol - Trading pair symbol
11173
+ * @param context - Execution context with strategyName, exchangeName, frameName
11174
+ * @returns Promise resolving to drawdown distance in PnL% (≥ 0) or null
11175
+ */
11176
+ this.getPositionHighestProfitDistancePnlPercentage = async (backtest, symbol, context) => {
11177
+ this.loggerService.log("strategyConnectionService getPositionHighestProfitDistancePnlPercentage", {
11178
+ symbol,
11179
+ context,
11180
+ });
11181
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
11182
+ const currentPrice = await this.priceMetaService.getCurrentPrice(symbol, context, backtest);
11183
+ return await strategy.getPositionHighestProfitDistancePnlPercentage(symbol, currentPrice);
11184
+ };
11185
+ /**
11186
+ * Returns the distance in PnL cost between the current price and the highest profit peak.
11187
+ *
11188
+ * Resolves current price via priceMetaService and delegates to
11189
+ * ClientStrategy.getPositionHighestProfitDistancePnlCost().
11190
+ * Returns null if no pending signal exists.
11191
+ *
11192
+ * @param backtest - Whether running in backtest mode
11193
+ * @param symbol - Trading pair symbol
11194
+ * @param context - Execution context with strategyName, exchangeName, frameName
11195
+ * @returns Promise resolving to drawdown distance in PnL cost (≥ 0) or null
11196
+ */
11197
+ this.getPositionHighestProfitDistancePnlCost = async (backtest, symbol, context) => {
11198
+ this.loggerService.log("strategyConnectionService getPositionHighestProfitDistancePnlCost", {
11199
+ symbol,
11200
+ context,
11201
+ });
11202
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
11203
+ const currentPrice = await this.priceMetaService.getCurrentPrice(symbol, context, backtest);
11204
+ return await strategy.getPositionHighestProfitDistancePnlCost(symbol, currentPrice);
11205
+ };
11206
+ /**
11207
+ * Returns the distance in PnL percentage between the current price and the worst drawdown trough.
11208
+ *
11209
+ * Resolves current price via priceMetaService and delegates to
11210
+ * ClientStrategy.getPositionHighestMaxDrawdownPnlPercentage().
11211
+ * Returns null if no pending signal exists.
11212
+ *
11213
+ * @param backtest - Whether running in backtest mode
11214
+ * @param symbol - Trading pair symbol
11215
+ * @param context - Execution context with strategyName, exchangeName, frameName
11216
+ * @returns Promise resolving to recovery distance in PnL% (≥ 0) or null
11217
+ */
11218
+ this.getPositionHighestMaxDrawdownPnlPercentage = async (backtest, symbol, context) => {
11219
+ this.loggerService.log("strategyConnectionService getPositionHighestMaxDrawdownPnlPercentage", {
11220
+ symbol,
11221
+ context,
11222
+ });
11223
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
11224
+ const currentPrice = await this.priceMetaService.getCurrentPrice(symbol, context, backtest);
11225
+ return await strategy.getPositionHighestMaxDrawdownPnlPercentage(symbol, currentPrice);
11226
+ };
11227
+ /**
11228
+ * Returns the distance in PnL cost between the current price and the worst drawdown trough.
11229
+ *
11230
+ * Resolves current price via priceMetaService and delegates to
11231
+ * ClientStrategy.getPositionHighestMaxDrawdownPnlCost().
11232
+ * Returns null if no pending signal exists.
11233
+ *
11234
+ * @param backtest - Whether running in backtest mode
11235
+ * @param symbol - Trading pair symbol
11236
+ * @param context - Execution context with strategyName, exchangeName, frameName
11237
+ * @returns Promise resolving to recovery distance in PnL cost (≥ 0) or null
11238
+ */
11239
+ this.getPositionHighestMaxDrawdownPnlCost = async (backtest, symbol, context) => {
11240
+ this.loggerService.log("strategyConnectionService getPositionHighestMaxDrawdownPnlCost", {
11241
+ symbol,
11242
+ context,
11243
+ });
11244
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
11245
+ const currentPrice = await this.priceMetaService.getCurrentPrice(symbol, context, backtest);
11246
+ return await strategy.getPositionHighestMaxDrawdownPnlCost(symbol, currentPrice);
11247
+ };
11080
11248
  /**
11081
11249
  * Disposes the ClientStrategy instance for the given context.
11082
11250
  *
@@ -15238,6 +15406,82 @@ class StrategyCoreService {
15238
15406
  await this.validate(context);
15239
15407
  return await this.strategyConnectionService.getPositionMaxDrawdownPnlCost(backtest, symbol, context);
15240
15408
  };
15409
+ /**
15410
+ * Returns the distance in PnL percentage between the current price and the highest profit peak.
15411
+ *
15412
+ * Delegates to StrategyConnectionService.getPositionHighestProfitDistancePnlPercentage().
15413
+ * Returns null if no pending signal exists.
15414
+ *
15415
+ * @param backtest - Whether running in backtest mode
15416
+ * @param symbol - Trading pair symbol
15417
+ * @param context - Execution context with strategyName, exchangeName, frameName
15418
+ * @returns Promise resolving to drawdown distance in PnL% (≥ 0) or null
15419
+ */
15420
+ this.getPositionHighestProfitDistancePnlPercentage = async (backtest, symbol, context) => {
15421
+ this.loggerService.log("strategyCoreService getPositionHighestProfitDistancePnlPercentage", {
15422
+ symbol,
15423
+ context,
15424
+ });
15425
+ await this.validate(context);
15426
+ return await this.strategyConnectionService.getPositionHighestProfitDistancePnlPercentage(backtest, symbol, context);
15427
+ };
15428
+ /**
15429
+ * Returns the distance in PnL cost between the current price and the highest profit peak.
15430
+ *
15431
+ * Delegates to StrategyConnectionService.getPositionHighestProfitDistancePnlCost().
15432
+ * Returns null if no pending signal exists.
15433
+ *
15434
+ * @param backtest - Whether running in backtest mode
15435
+ * @param symbol - Trading pair symbol
15436
+ * @param context - Execution context with strategyName, exchangeName, frameName
15437
+ * @returns Promise resolving to drawdown distance in PnL cost (≥ 0) or null
15438
+ */
15439
+ this.getPositionHighestProfitDistancePnlCost = async (backtest, symbol, context) => {
15440
+ this.loggerService.log("strategyCoreService getPositionHighestProfitDistancePnlCost", {
15441
+ symbol,
15442
+ context,
15443
+ });
15444
+ await this.validate(context);
15445
+ return await this.strategyConnectionService.getPositionHighestProfitDistancePnlCost(backtest, symbol, context);
15446
+ };
15447
+ /**
15448
+ * Returns the distance in PnL percentage between the current price and the worst drawdown trough.
15449
+ *
15450
+ * Delegates to StrategyConnectionService.getPositionHighestMaxDrawdownPnlPercentage().
15451
+ * Returns null if no pending signal exists.
15452
+ *
15453
+ * @param backtest - Whether running in backtest mode
15454
+ * @param symbol - Trading pair symbol
15455
+ * @param context - Execution context with strategyName, exchangeName, frameName
15456
+ * @returns Promise resolving to recovery distance in PnL% (≥ 0) or null
15457
+ */
15458
+ this.getPositionHighestMaxDrawdownPnlPercentage = async (backtest, symbol, context) => {
15459
+ this.loggerService.log("strategyCoreService getPositionHighestMaxDrawdownPnlPercentage", {
15460
+ symbol,
15461
+ context,
15462
+ });
15463
+ await this.validate(context);
15464
+ return await this.strategyConnectionService.getPositionHighestMaxDrawdownPnlPercentage(backtest, symbol, context);
15465
+ };
15466
+ /**
15467
+ * Returns the distance in PnL cost between the current price and the worst drawdown trough.
15468
+ *
15469
+ * Delegates to StrategyConnectionService.getPositionHighestMaxDrawdownPnlCost().
15470
+ * Returns null if no pending signal exists.
15471
+ *
15472
+ * @param backtest - Whether running in backtest mode
15473
+ * @param symbol - Trading pair symbol
15474
+ * @param context - Execution context with strategyName, exchangeName, frameName
15475
+ * @returns Promise resolving to recovery distance in PnL cost (≥ 0) or null
15476
+ */
15477
+ this.getPositionHighestMaxDrawdownPnlCost = async (backtest, symbol, context) => {
15478
+ this.loggerService.log("strategyCoreService getPositionHighestMaxDrawdownPnlCost", {
15479
+ symbol,
15480
+ context,
15481
+ });
15482
+ await this.validate(context);
15483
+ return await this.strategyConnectionService.getPositionHighestMaxDrawdownPnlCost(backtest, symbol, context);
15484
+ };
15241
15485
  }
15242
15486
  }
15243
15487
 
@@ -34893,6 +35137,10 @@ const GET_POSITION_MAX_DRAWDOWN_PRICE_METHOD_NAME = "strategy.getPositionMaxDraw
34893
35137
  const GET_POSITION_MAX_DRAWDOWN_TIMESTAMP_METHOD_NAME = "strategy.getPositionMaxDrawdownTimestamp";
34894
35138
  const GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE_METHOD_NAME = "strategy.getPositionMaxDrawdownPnlPercentage";
34895
35139
  const GET_POSITION_MAX_DRAWDOWN_PNL_COST_METHOD_NAME = "strategy.getPositionMaxDrawdownPnlCost";
35140
+ const GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE_METHOD_NAME = "strategy.getPositionHighestProfitDistancePnlPercentage";
35141
+ const GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST_METHOD_NAME = "strategy.getPositionHighestProfitDistancePnlCost";
35142
+ const GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE_METHOD_NAME = "strategy.getPositionHighestMaxDrawdownPnlPercentage";
35143
+ const GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST_METHOD_NAME = "strategy.getPositionHighestMaxDrawdownPnlCost";
34896
35144
  const GET_POSITION_ENTRY_OVERLAP_METHOD_NAME = "strategy.getPositionEntryOverlap";
34897
35145
  const GET_POSITION_PARTIAL_OVERLAP_METHOD_NAME = "strategy.getPositionPartialOverlap";
34898
35146
  const HAS_NO_PENDING_SIGNAL_METHOD_NAME = "strategy.hasNoPendingSignal";
@@ -36527,6 +36775,122 @@ async function getPositionMaxDrawdownPnlCost(symbol) {
36527
36775
  const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
36528
36776
  return await backtest.strategyCoreService.getPositionMaxDrawdownPnlCost(isBacktest, symbol, { exchangeName, frameName, strategyName });
36529
36777
  }
36778
+ /**
36779
+ * Returns the distance in PnL percentage between the current price and the highest profit peak.
36780
+ *
36781
+ * Computed as: max(0, peakPnlPercentage - currentPnlPercentage).
36782
+ * Returns null if no pending signal exists.
36783
+ *
36784
+ * @param symbol - Trading pair symbol
36785
+ * @returns Promise resolving to drawdown distance in PnL% (≥ 0) or null
36786
+ *
36787
+ * @example
36788
+ * ```typescript
36789
+ * import { getPositionHighestProfitDistancePnlPercentage } from "backtest-kit";
36790
+ *
36791
+ * const dist = await getPositionHighestProfitDistancePnlPercentage("BTCUSDT");
36792
+ * // e.g. 1.5 (gave back 1.5% from peak)
36793
+ * ```
36794
+ */
36795
+ async function getPositionHighestProfitDistancePnlPercentage(symbol) {
36796
+ backtest.loggerService.info(GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE_METHOD_NAME, { symbol });
36797
+ if (!ExecutionContextService.hasContext()) {
36798
+ throw new Error("getPositionHighestProfitDistancePnlPercentage requires an execution context");
36799
+ }
36800
+ if (!MethodContextService.hasContext()) {
36801
+ throw new Error("getPositionHighestProfitDistancePnlPercentage requires a method context");
36802
+ }
36803
+ const { backtest: isBacktest } = backtest.executionContextService.context;
36804
+ const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
36805
+ return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlPercentage(isBacktest, symbol, { exchangeName, frameName, strategyName });
36806
+ }
36807
+ /**
36808
+ * Returns the distance in PnL cost between the current price and the highest profit peak.
36809
+ *
36810
+ * Computed as: max(0, peakPnlCost - currentPnlCost).
36811
+ * Returns null if no pending signal exists.
36812
+ *
36813
+ * @param symbol - Trading pair symbol
36814
+ * @returns Promise resolving to drawdown distance in PnL cost (≥ 0) or null
36815
+ *
36816
+ * @example
36817
+ * ```typescript
36818
+ * import { getPositionHighestProfitDistancePnlCost } from "backtest-kit";
36819
+ *
36820
+ * const dist = await getPositionHighestProfitDistancePnlCost("BTCUSDT");
36821
+ * // e.g. 3.2 (gave back $3.2 from peak)
36822
+ * ```
36823
+ */
36824
+ async function getPositionHighestProfitDistancePnlCost(symbol) {
36825
+ backtest.loggerService.info(GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST_METHOD_NAME, { symbol });
36826
+ if (!ExecutionContextService.hasContext()) {
36827
+ throw new Error("getPositionHighestProfitDistancePnlCost requires an execution context");
36828
+ }
36829
+ if (!MethodContextService.hasContext()) {
36830
+ throw new Error("getPositionHighestProfitDistancePnlCost requires a method context");
36831
+ }
36832
+ const { backtest: isBacktest } = backtest.executionContextService.context;
36833
+ const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
36834
+ return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlCost(isBacktest, symbol, { exchangeName, frameName, strategyName });
36835
+ }
36836
+ /**
36837
+ * Returns the distance in PnL percentage between the current price and the worst drawdown trough.
36838
+ *
36839
+ * Computed as: max(0, currentPnlPercentage - fallPnlPercentage).
36840
+ * Returns null if no pending signal exists.
36841
+ *
36842
+ * @param symbol - Trading pair symbol
36843
+ * @returns Promise resolving to recovery distance in PnL% (≥ 0) or null
36844
+ *
36845
+ * @example
36846
+ * ```typescript
36847
+ * import { getPositionHighestMaxDrawdownPnlPercentage } from "backtest-kit";
36848
+ *
36849
+ * const dist = await getPositionHighestMaxDrawdownPnlPercentage("BTCUSDT");
36850
+ * // e.g. 2.1 (recovered 2.1% from trough)
36851
+ * ```
36852
+ */
36853
+ async function getPositionHighestMaxDrawdownPnlPercentage(symbol) {
36854
+ backtest.loggerService.info(GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE_METHOD_NAME, { symbol });
36855
+ if (!ExecutionContextService.hasContext()) {
36856
+ throw new Error("getPositionHighestMaxDrawdownPnlPercentage requires an execution context");
36857
+ }
36858
+ if (!MethodContextService.hasContext()) {
36859
+ throw new Error("getPositionHighestMaxDrawdownPnlPercentage requires a method context");
36860
+ }
36861
+ const { backtest: isBacktest } = backtest.executionContextService.context;
36862
+ const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
36863
+ return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlPercentage(isBacktest, symbol, { exchangeName, frameName, strategyName });
36864
+ }
36865
+ /**
36866
+ * Returns the distance in PnL cost between the current price and the worst drawdown trough.
36867
+ *
36868
+ * Computed as: max(0, currentPnlCost - fallPnlCost).
36869
+ * Returns null if no pending signal exists.
36870
+ *
36871
+ * @param symbol - Trading pair symbol
36872
+ * @returns Promise resolving to recovery distance in PnL cost (≥ 0) or null
36873
+ *
36874
+ * @example
36875
+ * ```typescript
36876
+ * import { getPositionHighestMaxDrawdownPnlCost } from "backtest-kit";
36877
+ *
36878
+ * const dist = await getPositionHighestMaxDrawdownPnlCost("BTCUSDT");
36879
+ * // e.g. 4.8 (recovered $4.8 from trough)
36880
+ * ```
36881
+ */
36882
+ async function getPositionHighestMaxDrawdownPnlCost(symbol) {
36883
+ backtest.loggerService.info(GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST_METHOD_NAME, { symbol });
36884
+ if (!ExecutionContextService.hasContext()) {
36885
+ throw new Error("getPositionHighestMaxDrawdownPnlCost requires an execution context");
36886
+ }
36887
+ if (!MethodContextService.hasContext()) {
36888
+ throw new Error("getPositionHighestMaxDrawdownPnlCost requires a method context");
36889
+ }
36890
+ const { backtest: isBacktest } = backtest.executionContextService.context;
36891
+ const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
36892
+ return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlCost(isBacktest, symbol, { exchangeName, frameName, strategyName });
36893
+ }
36530
36894
  /**
36531
36895
  * Checks whether the current price falls within the tolerance zone of any existing DCA entry level.
36532
36896
  * Use this to prevent duplicate DCA entries at the same price area.
@@ -38196,6 +38560,10 @@ const BACKTEST_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE = "BacktestUtils.getP
38196
38560
  const BACKTEST_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP = "BacktestUtils.getPositionMaxDrawdownTimestamp";
38197
38561
  const BACKTEST_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE = "BacktestUtils.getPositionMaxDrawdownPnlPercentage";
38198
38562
  const BACKTEST_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST = "BacktestUtils.getPositionMaxDrawdownPnlCost";
38563
+ const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE = "BacktestUtils.getPositionHighestProfitDistancePnlPercentage";
38564
+ const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST = "BacktestUtils.getPositionHighestProfitDistancePnlCost";
38565
+ const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE = "BacktestUtils.getPositionHighestMaxDrawdownPnlPercentage";
38566
+ const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST = "BacktestUtils.getPositionHighestMaxDrawdownPnlCost";
38199
38567
  const BACKTEST_METHOD_NAME_GET_POSITION_ENTRY_OVERLAP = "BacktestUtils.getPositionEntryOverlap";
38200
38568
  const BACKTEST_METHOD_NAME_GET_POSITION_PARTIAL_OVERLAP = "BacktestUtils.getPositionPartialOverlap";
38201
38569
  const BACKTEST_METHOD_NAME_BREAKEVEN = "Backtest.commitBreakeven";
@@ -39465,6 +39833,118 @@ class BacktestUtils {
39465
39833
  }
39466
39834
  return await backtest.strategyCoreService.getPositionMaxDrawdownPnlCost(true, symbol, context);
39467
39835
  };
39836
+ /**
39837
+ * Returns the distance in PnL percentage between the current price and the highest profit peak.
39838
+ *
39839
+ * Computed as: max(0, peakPnlPercentage - currentPnlPercentage).
39840
+ * Returns null if no pending signal exists.
39841
+ *
39842
+ * @param symbol - Trading pair symbol
39843
+ * @param context - Execution context with strategyName, exchangeName, and frameName
39844
+ * @returns drawdown distance in PnL% (≥ 0) or null if no active position
39845
+ */
39846
+ this.getPositionHighestProfitDistancePnlPercentage = async (symbol, context) => {
39847
+ backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE, {
39848
+ symbol,
39849
+ context,
39850
+ });
39851
+ backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
39852
+ backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
39853
+ {
39854
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
39855
+ riskName &&
39856
+ backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
39857
+ riskList &&
39858
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE));
39859
+ actions &&
39860
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE));
39861
+ }
39862
+ return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlPercentage(true, symbol, context);
39863
+ };
39864
+ /**
39865
+ * Returns the distance in PnL cost between the current price and the highest profit peak.
39866
+ *
39867
+ * Computed as: max(0, peakPnlCost - currentPnlCost).
39868
+ * Returns null if no pending signal exists.
39869
+ *
39870
+ * @param symbol - Trading pair symbol
39871
+ * @param context - Execution context with strategyName, exchangeName, and frameName
39872
+ * @returns drawdown distance in PnL cost (≥ 0) or null if no active position
39873
+ */
39874
+ this.getPositionHighestProfitDistancePnlCost = async (symbol, context) => {
39875
+ backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST, {
39876
+ symbol,
39877
+ context,
39878
+ });
39879
+ backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
39880
+ backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
39881
+ {
39882
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
39883
+ riskName &&
39884
+ backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
39885
+ riskList &&
39886
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST));
39887
+ actions &&
39888
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST));
39889
+ }
39890
+ return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlCost(true, symbol, context);
39891
+ };
39892
+ /**
39893
+ * Returns the distance in PnL percentage between the current price and the worst drawdown trough.
39894
+ *
39895
+ * Computed as: max(0, currentPnlPercentage - fallPnlPercentage).
39896
+ * Returns null if no pending signal exists.
39897
+ *
39898
+ * @param symbol - Trading pair symbol
39899
+ * @param context - Execution context with strategyName, exchangeName, and frameName
39900
+ * @returns recovery distance in PnL% (≥ 0) or null if no active position
39901
+ */
39902
+ this.getPositionHighestMaxDrawdownPnlPercentage = async (symbol, context) => {
39903
+ backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE, {
39904
+ symbol,
39905
+ context,
39906
+ });
39907
+ backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
39908
+ backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
39909
+ {
39910
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
39911
+ riskName &&
39912
+ backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
39913
+ riskList &&
39914
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE));
39915
+ actions &&
39916
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE));
39917
+ }
39918
+ return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlPercentage(true, symbol, context);
39919
+ };
39920
+ /**
39921
+ * Returns the distance in PnL cost between the current price and the worst drawdown trough.
39922
+ *
39923
+ * Computed as: max(0, currentPnlCost - fallPnlCost).
39924
+ * Returns null if no pending signal exists.
39925
+ *
39926
+ * @param symbol - Trading pair symbol
39927
+ * @param context - Execution context with strategyName, exchangeName, and frameName
39928
+ * @returns recovery distance in PnL cost (≥ 0) or null if no active position
39929
+ */
39930
+ this.getPositionHighestMaxDrawdownPnlCost = async (symbol, context) => {
39931
+ backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST, {
39932
+ symbol,
39933
+ context,
39934
+ });
39935
+ backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
39936
+ backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
39937
+ {
39938
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
39939
+ riskName &&
39940
+ backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
39941
+ riskList &&
39942
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST));
39943
+ actions &&
39944
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST));
39945
+ }
39946
+ return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlCost(true, symbol, context);
39947
+ };
39468
39948
  /**
39469
39949
  * Checks whether the current price falls within the tolerance zone of any existing DCA entry level.
39470
39950
  * Use this to prevent duplicate DCA entries at the same price area.
@@ -40590,6 +41070,10 @@ const LIVE_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PRICE = "LiveUtils.getPositionM
40590
41070
  const LIVE_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_TIMESTAMP = "LiveUtils.getPositionMaxDrawdownTimestamp";
40591
41071
  const LIVE_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_PERCENTAGE = "LiveUtils.getPositionMaxDrawdownPnlPercentage";
40592
41072
  const LIVE_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_PNL_COST = "LiveUtils.getPositionMaxDrawdownPnlCost";
41073
+ const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE = "LiveUtils.getPositionHighestProfitDistancePnlPercentage";
41074
+ const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST = "LiveUtils.getPositionHighestProfitDistancePnlCost";
41075
+ const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE = "LiveUtils.getPositionHighestMaxDrawdownPnlPercentage";
41076
+ const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST = "LiveUtils.getPositionHighestMaxDrawdownPnlCost";
40593
41077
  const LIVE_METHOD_NAME_GET_POSITION_ENTRY_OVERLAP = "LiveUtils.getPositionEntryOverlap";
40594
41078
  const LIVE_METHOD_NAME_GET_POSITION_PARTIAL_OVERLAP = "LiveUtils.getPositionPartialOverlap";
40595
41079
  const LIVE_METHOD_NAME_BREAKEVEN = "Live.commitBreakeven";
@@ -41986,6 +42470,134 @@ class LiveUtils {
41986
42470
  frameName: "",
41987
42471
  });
41988
42472
  };
42473
+ /**
42474
+ * Returns the distance in PnL percentage between the current price and the highest profit peak.
42475
+ *
42476
+ * Computed as: max(0, peakPnlPercentage - currentPnlPercentage).
42477
+ * Returns null if no pending signal exists.
42478
+ *
42479
+ * @param symbol - Trading pair symbol
42480
+ * @param context - Execution context with strategyName and exchangeName
42481
+ * @returns drawdown distance in PnL% (≥ 0) or null if no active position
42482
+ */
42483
+ this.getPositionHighestProfitDistancePnlPercentage = async (symbol, context) => {
42484
+ backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE, {
42485
+ symbol,
42486
+ context,
42487
+ });
42488
+ backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
42489
+ backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
42490
+ {
42491
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
42492
+ riskName &&
42493
+ backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE);
42494
+ riskList &&
42495
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE));
42496
+ actions &&
42497
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_PERCENTAGE));
42498
+ }
42499
+ return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlPercentage(false, symbol, {
42500
+ strategyName: context.strategyName,
42501
+ exchangeName: context.exchangeName,
42502
+ frameName: "",
42503
+ });
42504
+ };
42505
+ /**
42506
+ * Returns the distance in PnL cost between the current price and the highest profit peak.
42507
+ *
42508
+ * Computed as: max(0, peakPnlCost - currentPnlCost).
42509
+ * Returns null if no pending signal exists.
42510
+ *
42511
+ * @param symbol - Trading pair symbol
42512
+ * @param context - Execution context with strategyName and exchangeName
42513
+ * @returns drawdown distance in PnL cost (≥ 0) or null if no active position
42514
+ */
42515
+ this.getPositionHighestProfitDistancePnlCost = async (symbol, context) => {
42516
+ backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST, {
42517
+ symbol,
42518
+ context,
42519
+ });
42520
+ backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
42521
+ backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
42522
+ {
42523
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
42524
+ riskName &&
42525
+ backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST);
42526
+ riskList &&
42527
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST));
42528
+ actions &&
42529
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_DISTANCE_PNL_COST));
42530
+ }
42531
+ return await backtest.strategyCoreService.getPositionHighestProfitDistancePnlCost(false, symbol, {
42532
+ strategyName: context.strategyName,
42533
+ exchangeName: context.exchangeName,
42534
+ frameName: "",
42535
+ });
42536
+ };
42537
+ /**
42538
+ * Returns the distance in PnL percentage between the current price and the worst drawdown trough.
42539
+ *
42540
+ * Computed as: max(0, currentPnlPercentage - fallPnlPercentage).
42541
+ * Returns null if no pending signal exists.
42542
+ *
42543
+ * @param symbol - Trading pair symbol
42544
+ * @param context - Execution context with strategyName and exchangeName
42545
+ * @returns recovery distance in PnL% (≥ 0) or null if no active position
42546
+ */
42547
+ this.getPositionHighestMaxDrawdownPnlPercentage = async (symbol, context) => {
42548
+ backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE, {
42549
+ symbol,
42550
+ context,
42551
+ });
42552
+ backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
42553
+ backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
42554
+ {
42555
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
42556
+ riskName &&
42557
+ backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE);
42558
+ riskList &&
42559
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE));
42560
+ actions &&
42561
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_PERCENTAGE));
42562
+ }
42563
+ return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlPercentage(false, symbol, {
42564
+ strategyName: context.strategyName,
42565
+ exchangeName: context.exchangeName,
42566
+ frameName: "",
42567
+ });
42568
+ };
42569
+ /**
42570
+ * Returns the distance in PnL cost between the current price and the worst drawdown trough.
42571
+ *
42572
+ * Computed as: max(0, currentPnlCost - fallPnlCost).
42573
+ * Returns null if no pending signal exists.
42574
+ *
42575
+ * @param symbol - Trading pair symbol
42576
+ * @param context - Execution context with strategyName and exchangeName
42577
+ * @returns recovery distance in PnL cost (≥ 0) or null if no active position
42578
+ */
42579
+ this.getPositionHighestMaxDrawdownPnlCost = async (symbol, context) => {
42580
+ backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST, {
42581
+ symbol,
42582
+ context,
42583
+ });
42584
+ backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
42585
+ backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
42586
+ {
42587
+ const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
42588
+ riskName &&
42589
+ backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST);
42590
+ riskList &&
42591
+ riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST));
42592
+ actions &&
42593
+ actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_HIGHEST_MAX_DRAWDOWN_PNL_COST));
42594
+ }
42595
+ return await backtest.strategyCoreService.getPositionHighestMaxDrawdownPnlCost(false, symbol, {
42596
+ strategyName: context.strategyName,
42597
+ exchangeName: context.exchangeName,
42598
+ frameName: "",
42599
+ });
42600
+ };
41989
42601
  /**
41990
42602
  * Checks whether the current price falls within the tolerance zone of any existing DCA entry level.
41991
42603
  * Use this to prevent duplicate DCA entries at the same price area.
@@ -53625,17 +54237,17 @@ const CREATE_KEY_FN = (strategyName, exchangeName, frameName, isBacktest) => {
53625
54237
  * @example
53626
54238
  * ```typescript
53627
54239
  * const instance = new IntervalFnInstance(mySignalFn, "1h");
53628
- * await instance.run("BTCUSDT"); // → ISignalIntervalDto | null (fn called)
53629
- * await instance.run("BTCUSDT"); // → null (skipped, same interval)
54240
+ * await instance.run("BTCUSDT"); // → T | null (fn called)
54241
+ * await instance.run("BTCUSDT"); // → null (skipped, same interval)
53630
54242
  * // After 1 hour passes:
53631
- * await instance.run("BTCUSDT"); // → ISignalIntervalDto | null (fn called again)
54243
+ * await instance.run("BTCUSDT"); // → T | null (fn called again)
53632
54244
  * ```
53633
54245
  */
53634
54246
  class IntervalFnInstance {
53635
54247
  /**
53636
54248
  * Creates a new IntervalFnInstance.
53637
54249
  *
53638
- * @param fn - Signal function to fire once per interval
54250
+ * @param fn - Function to fire once per interval
53639
54251
  * @param interval - Candle interval that controls the firing boundary
53640
54252
  */
53641
54253
  constructor(fn, interval) {
@@ -53655,7 +54267,7 @@ class IntervalFnInstance {
53655
54267
  * Requires active method context and execution context.
53656
54268
  *
53657
54269
  * @param symbol - Trading pair symbol (e.g. "BTCUSDT")
53658
- * @returns The signal returned by `fn` on the first non-null fire, `null` on all subsequent calls
54270
+ * @returns The value returned by `fn` on the first non-null fire, `null` on all subsequent calls
53659
54271
  * within the same interval or when `fn` itself returned `null`
53660
54272
  * @throws Error if method context, execution context, or interval is missing
53661
54273
  */
@@ -53716,13 +54328,13 @@ class IntervalFnInstance {
53716
54328
  *
53717
54329
  * Fired state survives process restarts — unlike `IntervalFnInstance` which is in-memory only.
53718
54330
  *
53719
- * @template T - Async function type: `(symbol: string, ...args) => Promise<ISignalIntervalDto | null>`
54331
+ * @template T - Async function type: `(symbol: string, ...args) => Promise<R | null>`
53720
54332
  *
53721
54333
  * @example
53722
54334
  * ```typescript
53723
54335
  * const instance = new IntervalFileInstance(fetchSignal, "1h", "mySignal");
53724
- * await instance.run("BTCUSDT"); // → ISignalIntervalDto | null (fn called, result written to disk)
53725
- * await instance.run("BTCUSDT"); // → null (record exists, already fired)
54336
+ * await instance.run("BTCUSDT"); // → R | null (fn called, result written to disk)
54337
+ * await instance.run("BTCUSDT"); // → null (record exists, already fired)
53726
54338
  * ```
53727
54339
  */
53728
54340
  class IntervalFileInstance {
@@ -53752,7 +54364,7 @@ class IntervalFileInstance {
53752
54364
  this.interval = interval;
53753
54365
  this.name = name;
53754
54366
  /**
53755
- * Execute the async signal function with persistent once-per-interval enforcement.
54367
+ * Execute the async function with persistent once-per-interval enforcement.
53756
54368
  *
53757
54369
  * Algorithm:
53758
54370
  * 1. Build bucket = `${name}_${interval}_${index}` — fixed per instance, used as directory name.
@@ -53764,13 +54376,13 @@ class IntervalFileInstance {
53764
54376
  *
53765
54377
  * Requires active method context and execution context.
53766
54378
  *
53767
- * @param args - Arguments forwarded to the wrapped function (first must be `symbol: string`)
53768
- * @returns The signal on the first non-null fire, `null` if already fired this interval
54379
+ * @param symbol - Trading pair symbol (e.g. "BTCUSDT")
54380
+ * @returns The value on the first non-null fire, `null` if already fired this interval
53769
54381
  * or if `fn` itself returned `null`
53770
54382
  * @throws Error if method context, execution context, or interval is missing
53771
54383
  */
53772
- this.run = async (...args) => {
53773
- backtest.loggerService.debug(INTERVAL_FILE_INSTANCE_METHOD_NAME_RUN, { args });
54384
+ this.run = async (symbol) => {
54385
+ backtest.loggerService.debug(INTERVAL_FILE_INSTANCE_METHOD_NAME_RUN, { symbol });
53774
54386
  const step = INTERVAL_MINUTES[this.interval];
53775
54387
  {
53776
54388
  if (!MethodContextService.hasContext()) {
@@ -53783,7 +54395,6 @@ class IntervalFileInstance {
53783
54395
  throw new Error(`IntervalFileInstance unknown interval=${this.interval}`);
53784
54396
  }
53785
54397
  }
53786
- const [symbol] = args;
53787
54398
  const { when } = backtest.executionContextService.context;
53788
54399
  const alignedTs = align(when.getTime(), this.interval);
53789
54400
  const bucket = `${this.name}_${this.interval}_${this.index}`;
@@ -53792,7 +54403,7 @@ class IntervalFileInstance {
53792
54403
  if (cached !== null) {
53793
54404
  return null;
53794
54405
  }
53795
- const result = await this.fn.call(null, ...args);
54406
+ const result = await this.fn(symbol, when);
53796
54407
  if (result !== null) {
53797
54408
  await PersistIntervalAdapter.writeIntervalData({ id: entityKey, data: result, removed: false }, bucket, entityKey);
53798
54409
  }
@@ -53823,8 +54434,8 @@ IntervalFileInstance._indexCounter = 0;
53823
54434
  * import { Interval } from "./classes/Interval";
53824
54435
  *
53825
54436
  * const fireOncePerHour = Interval.fn(mySignalFn, { interval: "1h" });
53826
- * await fireOncePerHour("BTCUSDT", when); // fn called — returns its result
53827
- * await fireOncePerHour("BTCUSDT", when); // returns null (same interval)
54437
+ * await fireOncePerHour("BTCUSDT"); // fn called — returns its result
54438
+ * await fireOncePerHour("BTCUSDT"); // returns null (same interval)
53828
54439
  * ```
53829
54440
  */
53830
54441
  class IntervalUtils {
@@ -53850,19 +54461,19 @@ class IntervalUtils {
53850
54461
  *
53851
54462
  * @param run - Signal function to wrap
53852
54463
  * @param context.interval - Candle interval that controls the firing boundary
53853
- * @returns Wrapped function with the same signature as `TIntervalFn`, plus a `clear()` method
54464
+ * @returns Wrapped function with the same signature as `TIntervalFn<T>`, plus a `clear()` method
53854
54465
  *
53855
54466
  * @example
53856
54467
  * ```typescript
53857
54468
  * const fireOnce = Interval.fn(mySignalFn, { interval: "15m" });
53858
54469
  *
53859
- * await fireOnce("BTCUSDT", when); // → signal or null (fn called)
53860
- * await fireOnce("BTCUSDT", when); // → null (same interval, skipped)
54470
+ * await fireOnce("BTCUSDT"); // → T or null (fn called)
54471
+ * await fireOnce("BTCUSDT"); // → null (same interval, skipped)
53861
54472
  * ```
53862
54473
  */
53863
54474
  this.fn = (run, context) => {
53864
54475
  backtest.loggerService.info(INTERVAL_METHOD_NAME_FN, { context });
53865
- const wrappedFn = (symbol, _when) => {
54476
+ const wrappedFn = (symbol) => {
53866
54477
  const instance = this._getInstance(run, context.interval);
53867
54478
  return instance.run(symbol);
53868
54479
  };
@@ -53899,7 +54510,7 @@ class IntervalUtils {
53899
54510
  *
53900
54511
  * @example
53901
54512
  * ```typescript
53902
- * const fetchSignal = async (symbol: string, period: number) => { ... };
54513
+ * const fetchSignal = async (symbol: string, when: Date) => { ... };
53903
54514
  * const fireOnce = Interval.file(fetchSignal, { interval: "1h", name: "fetchSignal" });
53904
54515
  * await fireOnce.clear(); // delete disk records so the function fires again next call
53905
54516
  * ```
@@ -53909,9 +54520,9 @@ class IntervalUtils {
53909
54520
  {
53910
54521
  this._getFileInstance(run, context.interval, context.name);
53911
54522
  }
53912
- const wrappedFn = (...args) => {
54523
+ const wrappedFn = (symbol) => {
53913
54524
  const instance = this._getFileInstance(run, context.interval, context.name);
53914
- return instance.run(...args);
54525
+ return instance.run(symbol);
53915
54526
  };
53916
54527
  wrappedFn.clear = async () => {
53917
54528
  backtest.loggerService.info(INTERVAL_METHOD_NAME_FILE_CLEAR);
@@ -55082,4 +55693,4 @@ const validateSignal = (signal, currentPrice) => {
55082
55693
  return !errors.length;
55083
55694
  };
55084
55695
 
55085
- 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, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, 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 };
55696
+ 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 };