backtest-kit 5.6.3 → 5.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.cjs CHANGED
@@ -6475,6 +6475,18 @@ class ClientStrategy {
6475
6475
  });
6476
6476
  return this._pendingSignal !== null;
6477
6477
  }
6478
+ /**
6479
+ * Checks if there is a scheduled signal.
6480
+ *
6481
+ * @param symbol - Trading symbol to check for scheduled signal
6482
+ * @returns Promise resolving to true if a scheduled signal exists, false otherwise
6483
+ */
6484
+ async hasScheduledSignal(symbol) {
6485
+ this.params.logger.debug("ClientStrategy hasScheduledSignal", {
6486
+ symbol,
6487
+ });
6488
+ return this._scheduledSignal !== null;
6489
+ }
6478
6490
  /**
6479
6491
  * Updates pending signal and persists to disk in live mode.
6480
6492
  *
@@ -10034,6 +10046,22 @@ class StrategyConnectionService {
10034
10046
  const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
10035
10047
  return await strategy.hasPendingSignal(symbol);
10036
10048
  };
10049
+ /**
10050
+ * Checks if there is an active scheduled signal for the strategy.
10051
+ * Delegates to ClientStrategy.hasScheduledSignal() which checks if there is a waiting position signal
10052
+ * @param backtest - Whether running in backtest mode
10053
+ * @param symbol - Trading pair symbol
10054
+ * @param context - Execution context with strategyName, exchangeName, frameName
10055
+ * @returns Promise resolving to true if there is a waiting scheduled signal, false otherwise
10056
+ */
10057
+ this.hasScheduledSignal = async (backtest, symbol, context) => {
10058
+ this.loggerService.log("strategyConnectionService hasScheduledSignal", {
10059
+ symbol,
10060
+ context,
10061
+ });
10062
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
10063
+ return await strategy.hasScheduledSignal(symbol);
10064
+ };
10037
10065
  /**
10038
10066
  * Returns the original estimated duration for the current pending signal.
10039
10067
  *
@@ -14385,6 +14413,24 @@ class StrategyCoreService {
14385
14413
  await this.validate(context);
14386
14414
  return await this.strategyConnectionService.hasPendingSignal(backtest, symbol, context);
14387
14415
  };
14416
+ /**
14417
+ * Checks if there is a waiting scheduled signal for the symbol.
14418
+ * Validates strategy existence and delegates to connection service
14419
+ * to check if a scheduled signal exists for the symbol.
14420
+ * Does not require execution context as this is a state query operation.
14421
+ * @param backtest - Whether running in backtest mode
14422
+ * @param symbol - Trading pair symbol
14423
+ * @param context - Execution context with strategyName, exchangeName, frameName
14424
+ * @returns Promise<boolean> - true if scheduled signal exists, false otherwise
14425
+ */
14426
+ this.hasScheduledSignal = async (backtest, symbol, context) => {
14427
+ this.loggerService.log("strategyCoreService hasScheduledSignal", {
14428
+ symbol,
14429
+ context,
14430
+ });
14431
+ await this.validate(context);
14432
+ return await this.strategyConnectionService.hasScheduledSignal(backtest, symbol, context);
14433
+ };
14388
14434
  /**
14389
14435
  * Returns the original estimated duration for the current pending signal.
14390
14436
  *
@@ -36118,6 +36164,8 @@ const BACKTEST_METHOD_NAME_TRAILING_PROFIT_COST = "BacktestUtils.commitTrailingT
36118
36164
  const BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED = "Backtest.commitActivateScheduled";
36119
36165
  const BACKTEST_METHOD_NAME_AVERAGE_BUY = "Backtest.commitAverageBuy";
36120
36166
  const BACKTEST_METHOD_NAME_GET_DATA = "BacktestUtils.getData";
36167
+ const BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "BacktestUtils.hasNoPendingSignal";
36168
+ const BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "BacktestUtils.hasNoScheduledSignal";
36121
36169
  /**
36122
36170
  * Internal task function that runs backtest and handles completion.
36123
36171
  * Consumes backtest results and updates instance state flags.
@@ -36621,6 +36669,74 @@ class BacktestUtils {
36621
36669
  }
36622
36670
  return await bt.strategyCoreService.getScheduledSignal(true, symbol, currentPrice, context);
36623
36671
  };
36672
+ /**
36673
+ * Returns true if there is NO active pending signal for the given symbol.
36674
+ *
36675
+ * Inverse of strategyCoreService.hasPendingSignal. Use to guard signal generation logic.
36676
+ *
36677
+ * @param symbol - Trading pair symbol
36678
+ * @param context - Execution context with strategyName, exchangeName, frameName
36679
+ * @returns Promise<boolean> - true if no pending signal exists, false if one does
36680
+ *
36681
+ * @example
36682
+ * ```typescript
36683
+ * if (await Backtest.hasNoPendingSignal("BTCUSDT", { strategyName, exchangeName, frameName })) {
36684
+ * // safe to open a new position
36685
+ * }
36686
+ * ```
36687
+ */
36688
+ this.hasNoPendingSignal = async (symbol, context) => {
36689
+ bt.loggerService.info(BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL, {
36690
+ symbol,
36691
+ context,
36692
+ });
36693
+ bt.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
36694
+ bt.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
36695
+ {
36696
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
36697
+ riskName &&
36698
+ bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
36699
+ riskList &&
36700
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
36701
+ actions &&
36702
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
36703
+ }
36704
+ return await functoolsKit.not(bt.strategyCoreService.hasPendingSignal(true, symbol, context));
36705
+ };
36706
+ /**
36707
+ * Returns true if there is NO active scheduled signal for the given symbol.
36708
+ *
36709
+ * Inverse of strategyCoreService.hasScheduledSignal. Use to guard signal generation logic.
36710
+ *
36711
+ * @param symbol - Trading pair symbol
36712
+ * @param context - Execution context with strategyName, exchangeName, frameName
36713
+ * @returns Promise<boolean> - true if no scheduled signal exists, false if one does
36714
+ *
36715
+ * @example
36716
+ * ```typescript
36717
+ * if (await Backtest.hasNoScheduledSignal("BTCUSDT", { strategyName, exchangeName, frameName })) {
36718
+ * // safe to schedule a new signal
36719
+ * }
36720
+ * ```
36721
+ */
36722
+ this.hasNoScheduledSignal = async (symbol, context) => {
36723
+ bt.loggerService.info(BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL, {
36724
+ symbol,
36725
+ context,
36726
+ });
36727
+ bt.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
36728
+ bt.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
36729
+ {
36730
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
36731
+ riskName &&
36732
+ bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
36733
+ riskList &&
36734
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
36735
+ actions &&
36736
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
36737
+ }
36738
+ return await functoolsKit.not(bt.strategyCoreService.hasScheduledSignal(true, symbol, context));
36739
+ };
36624
36740
  /**
36625
36741
  * Checks if breakeven threshold has been reached for the current pending signal.
36626
36742
  *
@@ -38266,6 +38382,8 @@ const LIVE_METHOD_NAME_TRAILING_STOP_COST = "LiveUtils.commitTrailingStopCost";
38266
38382
  const LIVE_METHOD_NAME_TRAILING_PROFIT_COST = "LiveUtils.commitTrailingTakeCost";
38267
38383
  const LIVE_METHOD_NAME_ACTIVATE_SCHEDULED = "Live.commitActivateScheduled";
38268
38384
  const LIVE_METHOD_NAME_AVERAGE_BUY = "Live.commitAverageBuy";
38385
+ const LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "LiveUtils.hasNoPendingSignal";
38386
+ const LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "LiveUtils.hasNoScheduledSignal";
38269
38387
  /**
38270
38388
  * Internal task function that runs live trading and handles completion.
38271
38389
  * Consumes live trading results and updates instance state flags.
@@ -38798,6 +38916,82 @@ class LiveUtils {
38798
38916
  frameName: "",
38799
38917
  });
38800
38918
  };
38919
+ /**
38920
+ * Returns true if there is NO active pending signal for the given symbol.
38921
+ *
38922
+ * Inverse of strategyCoreService.hasPendingSignal. Use to guard signal generation logic.
38923
+ *
38924
+ * @param symbol - Trading pair symbol
38925
+ * @param context - Execution context with strategyName and exchangeName
38926
+ * @returns Promise<boolean> - true if no pending signal exists, false if one does
38927
+ *
38928
+ * @example
38929
+ * ```typescript
38930
+ * if (await Live.hasNoPendingSignal("BTCUSDT", { strategyName, exchangeName })) {
38931
+ * // safe to open a new position
38932
+ * }
38933
+ * ```
38934
+ */
38935
+ this.hasNoPendingSignal = async (symbol, context) => {
38936
+ bt.loggerService.info(LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL, {
38937
+ symbol,
38938
+ context,
38939
+ });
38940
+ bt.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
38941
+ bt.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
38942
+ {
38943
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
38944
+ riskName &&
38945
+ bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
38946
+ riskList &&
38947
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
38948
+ actions &&
38949
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
38950
+ }
38951
+ return await functoolsKit.not(bt.strategyCoreService.hasPendingSignal(false, symbol, {
38952
+ strategyName: context.strategyName,
38953
+ exchangeName: context.exchangeName,
38954
+ frameName: "",
38955
+ }));
38956
+ };
38957
+ /**
38958
+ * Returns true if there is NO active scheduled signal for the given symbol.
38959
+ *
38960
+ * Inverse of strategyCoreService.hasScheduledSignal. Use to guard signal generation logic.
38961
+ *
38962
+ * @param symbol - Trading pair symbol
38963
+ * @param context - Execution context with strategyName and exchangeName
38964
+ * @returns Promise<boolean> - true if no scheduled signal exists, false if one does
38965
+ *
38966
+ * @example
38967
+ * ```typescript
38968
+ * if (await Live.hasNoScheduledSignal("BTCUSDT", { strategyName, exchangeName })) {
38969
+ * // safe to schedule a new signal
38970
+ * }
38971
+ * ```
38972
+ */
38973
+ this.hasNoScheduledSignal = async (symbol, context) => {
38974
+ bt.loggerService.info(LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL, {
38975
+ symbol,
38976
+ context,
38977
+ });
38978
+ bt.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
38979
+ bt.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
38980
+ {
38981
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
38982
+ riskName &&
38983
+ bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
38984
+ riskList &&
38985
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
38986
+ actions &&
38987
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
38988
+ }
38989
+ return await functoolsKit.not(bt.strategyCoreService.hasScheduledSignal(false, symbol, {
38990
+ strategyName: context.strategyName,
38991
+ exchangeName: context.exchangeName,
38992
+ frameName: "",
38993
+ }));
38994
+ };
38801
38995
  /**
38802
38996
  * Checks if breakeven threshold has been reached for the current pending signal.
38803
38997
  *
package/build/index.mjs CHANGED
@@ -6455,6 +6455,18 @@ class ClientStrategy {
6455
6455
  });
6456
6456
  return this._pendingSignal !== null;
6457
6457
  }
6458
+ /**
6459
+ * Checks if there is a scheduled signal.
6460
+ *
6461
+ * @param symbol - Trading symbol to check for scheduled signal
6462
+ * @returns Promise resolving to true if a scheduled signal exists, false otherwise
6463
+ */
6464
+ async hasScheduledSignal(symbol) {
6465
+ this.params.logger.debug("ClientStrategy hasScheduledSignal", {
6466
+ symbol,
6467
+ });
6468
+ return this._scheduledSignal !== null;
6469
+ }
6458
6470
  /**
6459
6471
  * Updates pending signal and persists to disk in live mode.
6460
6472
  *
@@ -10014,6 +10026,22 @@ class StrategyConnectionService {
10014
10026
  const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
10015
10027
  return await strategy.hasPendingSignal(symbol);
10016
10028
  };
10029
+ /**
10030
+ * Checks if there is an active scheduled signal for the strategy.
10031
+ * Delegates to ClientStrategy.hasScheduledSignal() which checks if there is a waiting position signal
10032
+ * @param backtest - Whether running in backtest mode
10033
+ * @param symbol - Trading pair symbol
10034
+ * @param context - Execution context with strategyName, exchangeName, frameName
10035
+ * @returns Promise resolving to true if there is a waiting scheduled signal, false otherwise
10036
+ */
10037
+ this.hasScheduledSignal = async (backtest, symbol, context) => {
10038
+ this.loggerService.log("strategyConnectionService hasScheduledSignal", {
10039
+ symbol,
10040
+ context,
10041
+ });
10042
+ const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
10043
+ return await strategy.hasScheduledSignal(symbol);
10044
+ };
10017
10045
  /**
10018
10046
  * Returns the original estimated duration for the current pending signal.
10019
10047
  *
@@ -14365,6 +14393,24 @@ class StrategyCoreService {
14365
14393
  await this.validate(context);
14366
14394
  return await this.strategyConnectionService.hasPendingSignal(backtest, symbol, context);
14367
14395
  };
14396
+ /**
14397
+ * Checks if there is a waiting scheduled signal for the symbol.
14398
+ * Validates strategy existence and delegates to connection service
14399
+ * to check if a scheduled signal exists for the symbol.
14400
+ * Does not require execution context as this is a state query operation.
14401
+ * @param backtest - Whether running in backtest mode
14402
+ * @param symbol - Trading pair symbol
14403
+ * @param context - Execution context with strategyName, exchangeName, frameName
14404
+ * @returns Promise<boolean> - true if scheduled signal exists, false otherwise
14405
+ */
14406
+ this.hasScheduledSignal = async (backtest, symbol, context) => {
14407
+ this.loggerService.log("strategyCoreService hasScheduledSignal", {
14408
+ symbol,
14409
+ context,
14410
+ });
14411
+ await this.validate(context);
14412
+ return await this.strategyConnectionService.hasScheduledSignal(backtest, symbol, context);
14413
+ };
14368
14414
  /**
14369
14415
  * Returns the original estimated duration for the current pending signal.
14370
14416
  *
@@ -36098,6 +36144,8 @@ const BACKTEST_METHOD_NAME_TRAILING_PROFIT_COST = "BacktestUtils.commitTrailingT
36098
36144
  const BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED = "Backtest.commitActivateScheduled";
36099
36145
  const BACKTEST_METHOD_NAME_AVERAGE_BUY = "Backtest.commitAverageBuy";
36100
36146
  const BACKTEST_METHOD_NAME_GET_DATA = "BacktestUtils.getData";
36147
+ const BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "BacktestUtils.hasNoPendingSignal";
36148
+ const BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "BacktestUtils.hasNoScheduledSignal";
36101
36149
  /**
36102
36150
  * Internal task function that runs backtest and handles completion.
36103
36151
  * Consumes backtest results and updates instance state flags.
@@ -36601,6 +36649,74 @@ class BacktestUtils {
36601
36649
  }
36602
36650
  return await bt.strategyCoreService.getScheduledSignal(true, symbol, currentPrice, context);
36603
36651
  };
36652
+ /**
36653
+ * Returns true if there is NO active pending signal for the given symbol.
36654
+ *
36655
+ * Inverse of strategyCoreService.hasPendingSignal. Use to guard signal generation logic.
36656
+ *
36657
+ * @param symbol - Trading pair symbol
36658
+ * @param context - Execution context with strategyName, exchangeName, frameName
36659
+ * @returns Promise<boolean> - true if no pending signal exists, false if one does
36660
+ *
36661
+ * @example
36662
+ * ```typescript
36663
+ * if (await Backtest.hasNoPendingSignal("BTCUSDT", { strategyName, exchangeName, frameName })) {
36664
+ * // safe to open a new position
36665
+ * }
36666
+ * ```
36667
+ */
36668
+ this.hasNoPendingSignal = async (symbol, context) => {
36669
+ bt.loggerService.info(BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL, {
36670
+ symbol,
36671
+ context,
36672
+ });
36673
+ bt.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
36674
+ bt.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
36675
+ {
36676
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
36677
+ riskName &&
36678
+ bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
36679
+ riskList &&
36680
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
36681
+ actions &&
36682
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
36683
+ }
36684
+ return await not(bt.strategyCoreService.hasPendingSignal(true, symbol, context));
36685
+ };
36686
+ /**
36687
+ * Returns true if there is NO active scheduled signal for the given symbol.
36688
+ *
36689
+ * Inverse of strategyCoreService.hasScheduledSignal. Use to guard signal generation logic.
36690
+ *
36691
+ * @param symbol - Trading pair symbol
36692
+ * @param context - Execution context with strategyName, exchangeName, frameName
36693
+ * @returns Promise<boolean> - true if no scheduled signal exists, false if one does
36694
+ *
36695
+ * @example
36696
+ * ```typescript
36697
+ * if (await Backtest.hasNoScheduledSignal("BTCUSDT", { strategyName, exchangeName, frameName })) {
36698
+ * // safe to schedule a new signal
36699
+ * }
36700
+ * ```
36701
+ */
36702
+ this.hasNoScheduledSignal = async (symbol, context) => {
36703
+ bt.loggerService.info(BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL, {
36704
+ symbol,
36705
+ context,
36706
+ });
36707
+ bt.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
36708
+ bt.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
36709
+ {
36710
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
36711
+ riskName &&
36712
+ bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
36713
+ riskList &&
36714
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
36715
+ actions &&
36716
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
36717
+ }
36718
+ return await not(bt.strategyCoreService.hasScheduledSignal(true, symbol, context));
36719
+ };
36604
36720
  /**
36605
36721
  * Checks if breakeven threshold has been reached for the current pending signal.
36606
36722
  *
@@ -38246,6 +38362,8 @@ const LIVE_METHOD_NAME_TRAILING_STOP_COST = "LiveUtils.commitTrailingStopCost";
38246
38362
  const LIVE_METHOD_NAME_TRAILING_PROFIT_COST = "LiveUtils.commitTrailingTakeCost";
38247
38363
  const LIVE_METHOD_NAME_ACTIVATE_SCHEDULED = "Live.commitActivateScheduled";
38248
38364
  const LIVE_METHOD_NAME_AVERAGE_BUY = "Live.commitAverageBuy";
38365
+ const LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "LiveUtils.hasNoPendingSignal";
38366
+ const LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "LiveUtils.hasNoScheduledSignal";
38249
38367
  /**
38250
38368
  * Internal task function that runs live trading and handles completion.
38251
38369
  * Consumes live trading results and updates instance state flags.
@@ -38778,6 +38896,82 @@ class LiveUtils {
38778
38896
  frameName: "",
38779
38897
  });
38780
38898
  };
38899
+ /**
38900
+ * Returns true if there is NO active pending signal for the given symbol.
38901
+ *
38902
+ * Inverse of strategyCoreService.hasPendingSignal. Use to guard signal generation logic.
38903
+ *
38904
+ * @param symbol - Trading pair symbol
38905
+ * @param context - Execution context with strategyName and exchangeName
38906
+ * @returns Promise<boolean> - true if no pending signal exists, false if one does
38907
+ *
38908
+ * @example
38909
+ * ```typescript
38910
+ * if (await Live.hasNoPendingSignal("BTCUSDT", { strategyName, exchangeName })) {
38911
+ * // safe to open a new position
38912
+ * }
38913
+ * ```
38914
+ */
38915
+ this.hasNoPendingSignal = async (symbol, context) => {
38916
+ bt.loggerService.info(LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL, {
38917
+ symbol,
38918
+ context,
38919
+ });
38920
+ bt.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
38921
+ bt.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
38922
+ {
38923
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
38924
+ riskName &&
38925
+ bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL);
38926
+ riskList &&
38927
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
38928
+ actions &&
38929
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL));
38930
+ }
38931
+ return await not(bt.strategyCoreService.hasPendingSignal(false, symbol, {
38932
+ strategyName: context.strategyName,
38933
+ exchangeName: context.exchangeName,
38934
+ frameName: "",
38935
+ }));
38936
+ };
38937
+ /**
38938
+ * Returns true if there is NO active scheduled signal for the given symbol.
38939
+ *
38940
+ * Inverse of strategyCoreService.hasScheduledSignal. Use to guard signal generation logic.
38941
+ *
38942
+ * @param symbol - Trading pair symbol
38943
+ * @param context - Execution context with strategyName and exchangeName
38944
+ * @returns Promise<boolean> - true if no scheduled signal exists, false if one does
38945
+ *
38946
+ * @example
38947
+ * ```typescript
38948
+ * if (await Live.hasNoScheduledSignal("BTCUSDT", { strategyName, exchangeName })) {
38949
+ * // safe to schedule a new signal
38950
+ * }
38951
+ * ```
38952
+ */
38953
+ this.hasNoScheduledSignal = async (symbol, context) => {
38954
+ bt.loggerService.info(LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL, {
38955
+ symbol,
38956
+ context,
38957
+ });
38958
+ bt.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
38959
+ bt.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
38960
+ {
38961
+ const { riskName, riskList, actions } = bt.strategySchemaService.get(context.strategyName);
38962
+ riskName &&
38963
+ bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL);
38964
+ riskList &&
38965
+ riskList.forEach((riskName) => bt.riskValidationService.validate(riskName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
38966
+ actions &&
38967
+ actions.forEach((actionName) => bt.actionValidationService.validate(actionName, LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL));
38968
+ }
38969
+ return await not(bt.strategyCoreService.hasScheduledSignal(false, symbol, {
38970
+ strategyName: context.strategyName,
38971
+ exchangeName: context.exchangeName,
38972
+ frameName: "",
38973
+ }));
38974
+ };
38781
38975
  /**
38782
38976
  * Checks if breakeven threshold has been reached for the current pending signal.
38783
38977
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "5.6.3",
3
+ "version": "5.6.4",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -3399,6 +3399,15 @@ interface IStrategy {
3399
3399
  * @returns Promise resolving to true if pending signal exists, false otherwise
3400
3400
  */
3401
3401
  hasPendingSignal: (symbol: string) => Promise<boolean>;
3402
+ /**
3403
+ * Checks if there is an active scheduled signal for the symbol.
3404
+ *
3405
+ * Used internally to determine if TP/SL monitoring should occur on tick.
3406
+ *
3407
+ * @param symbol - Trading pair symbol
3408
+ * @returns Promise resolving to true if scheduled signal exists, false otherwise
3409
+ */
3410
+ hasScheduledSignal: (symbol: string) => Promise<boolean>;
3402
3411
  /**
3403
3412
  * Returns the original estimated duration for the current pending signal.
3404
3413
  *
@@ -12295,6 +12304,48 @@ declare class BacktestUtils {
12295
12304
  exchangeName: ExchangeName;
12296
12305
  frameName: FrameName;
12297
12306
  }) => Promise<IScheduledSignalRow>;
12307
+ /**
12308
+ * Returns true if there is NO active pending signal for the given symbol.
12309
+ *
12310
+ * Inverse of strategyCoreService.hasPendingSignal. Use to guard signal generation logic.
12311
+ *
12312
+ * @param symbol - Trading pair symbol
12313
+ * @param context - Execution context with strategyName, exchangeName, frameName
12314
+ * @returns Promise<boolean> - true if no pending signal exists, false if one does
12315
+ *
12316
+ * @example
12317
+ * ```typescript
12318
+ * if (await Backtest.hasNoPendingSignal("BTCUSDT", { strategyName, exchangeName, frameName })) {
12319
+ * // safe to open a new position
12320
+ * }
12321
+ * ```
12322
+ */
12323
+ hasNoPendingSignal: (symbol: string, context: {
12324
+ strategyName: StrategyName;
12325
+ exchangeName: ExchangeName;
12326
+ frameName: FrameName;
12327
+ }) => Promise<boolean>;
12328
+ /**
12329
+ * Returns true if there is NO active scheduled signal for the given symbol.
12330
+ *
12331
+ * Inverse of strategyCoreService.hasScheduledSignal. Use to guard signal generation logic.
12332
+ *
12333
+ * @param symbol - Trading pair symbol
12334
+ * @param context - Execution context with strategyName, exchangeName, frameName
12335
+ * @returns Promise<boolean> - true if no scheduled signal exists, false if one does
12336
+ *
12337
+ * @example
12338
+ * ```typescript
12339
+ * if (await Backtest.hasNoScheduledSignal("BTCUSDT", { strategyName, exchangeName, frameName })) {
12340
+ * // safe to schedule a new signal
12341
+ * }
12342
+ * ```
12343
+ */
12344
+ hasNoScheduledSignal: (symbol: string, context: {
12345
+ strategyName: StrategyName;
12346
+ exchangeName: ExchangeName;
12347
+ frameName: FrameName;
12348
+ }) => Promise<boolean>;
12298
12349
  /**
12299
12350
  * Checks if breakeven threshold has been reached for the current pending signal.
12300
12351
  *
@@ -13546,6 +13597,46 @@ declare class LiveUtils {
13546
13597
  strategyName: StrategyName;
13547
13598
  exchangeName: ExchangeName;
13548
13599
  }) => Promise<IScheduledSignalRow>;
13600
+ /**
13601
+ * Returns true if there is NO active pending signal for the given symbol.
13602
+ *
13603
+ * Inverse of strategyCoreService.hasPendingSignal. Use to guard signal generation logic.
13604
+ *
13605
+ * @param symbol - Trading pair symbol
13606
+ * @param context - Execution context with strategyName and exchangeName
13607
+ * @returns Promise<boolean> - true if no pending signal exists, false if one does
13608
+ *
13609
+ * @example
13610
+ * ```typescript
13611
+ * if (await Live.hasNoPendingSignal("BTCUSDT", { strategyName, exchangeName })) {
13612
+ * // safe to open a new position
13613
+ * }
13614
+ * ```
13615
+ */
13616
+ hasNoPendingSignal: (symbol: string, context: {
13617
+ strategyName: StrategyName;
13618
+ exchangeName: ExchangeName;
13619
+ }) => Promise<boolean>;
13620
+ /**
13621
+ * Returns true if there is NO active scheduled signal for the given symbol.
13622
+ *
13623
+ * Inverse of strategyCoreService.hasScheduledSignal. Use to guard signal generation logic.
13624
+ *
13625
+ * @param symbol - Trading pair symbol
13626
+ * @param context - Execution context with strategyName and exchangeName
13627
+ * @returns Promise<boolean> - true if no scheduled signal exists, false if one does
13628
+ *
13629
+ * @example
13630
+ * ```typescript
13631
+ * if (await Live.hasNoScheduledSignal("BTCUSDT", { strategyName, exchangeName })) {
13632
+ * // safe to schedule a new signal
13633
+ * }
13634
+ * ```
13635
+ */
13636
+ hasNoScheduledSignal: (symbol: string, context: {
13637
+ strategyName: StrategyName;
13638
+ exchangeName: ExchangeName;
13639
+ }) => Promise<boolean>;
13549
13640
  /**
13550
13641
  * Checks if breakeven threshold has been reached for the current pending signal.
13551
13642
  *
@@ -22432,6 +22523,19 @@ declare class StrategyConnectionService implements TStrategy$1 {
22432
22523
  exchangeName: ExchangeName;
22433
22524
  frameName: FrameName;
22434
22525
  }) => Promise<boolean>;
22526
+ /**
22527
+ * Checks if there is an active scheduled signal for the strategy.
22528
+ * Delegates to ClientStrategy.hasScheduledSignal() which checks if there is a waiting position signal
22529
+ * @param backtest - Whether running in backtest mode
22530
+ * @param symbol - Trading pair symbol
22531
+ * @param context - Execution context with strategyName, exchangeName, frameName
22532
+ * @returns Promise resolving to true if there is a waiting scheduled signal, false otherwise
22533
+ */
22534
+ hasScheduledSignal: (backtest: boolean, symbol: string, context: {
22535
+ strategyName: StrategyName;
22536
+ exchangeName: ExchangeName;
22537
+ frameName: FrameName;
22538
+ }) => Promise<boolean>;
22435
22539
  /**
22436
22540
  * Returns the original estimated duration for the current pending signal.
22437
22541
  *
@@ -24186,6 +24290,21 @@ declare class StrategyCoreService implements TStrategy {
24186
24290
  exchangeName: ExchangeName;
24187
24291
  frameName: FrameName;
24188
24292
  }) => Promise<boolean>;
24293
+ /**
24294
+ * Checks if there is a waiting scheduled signal for the symbol.
24295
+ * Validates strategy existence and delegates to connection service
24296
+ * to check if a scheduled signal exists for the symbol.
24297
+ * Does not require execution context as this is a state query operation.
24298
+ * @param backtest - Whether running in backtest mode
24299
+ * @param symbol - Trading pair symbol
24300
+ * @param context - Execution context with strategyName, exchangeName, frameName
24301
+ * @returns Promise<boolean> - true if scheduled signal exists, false otherwise
24302
+ */
24303
+ hasScheduledSignal: (backtest: boolean, symbol: string, context: {
24304
+ strategyName: StrategyName;
24305
+ exchangeName: ExchangeName;
24306
+ frameName: FrameName;
24307
+ }) => Promise<boolean>;
24189
24308
  /**
24190
24309
  * Returns the original estimated duration for the current pending signal.
24191
24310
  *