backtest-kit 1.5.47 → 1.6.1

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
@@ -1746,6 +1746,12 @@ const partialLossSubject = new functoolsKit.Subject();
1746
1746
  * Does not emit for allowed signals (prevents spam).
1747
1747
  */
1748
1748
  const riskSubject = new functoolsKit.Subject();
1749
+ /**
1750
+ * Ping emitter for scheduled signal monitoring events.
1751
+ * Emits every minute when a scheduled signal is being monitored (waiting for activation).
1752
+ * Allows users to track scheduled signal lifecycle and implement custom cancellation logic.
1753
+ */
1754
+ const pingSubject = new functoolsKit.Subject();
1749
1755
 
1750
1756
  var emitters = /*#__PURE__*/Object.freeze({
1751
1757
  __proto__: null,
@@ -1757,6 +1763,7 @@ var emitters = /*#__PURE__*/Object.freeze({
1757
1763
  partialLossSubject: partialLossSubject,
1758
1764
  partialProfitSubject: partialProfitSubject,
1759
1765
  performanceEmitter: performanceEmitter,
1766
+ pingSubject: pingSubject,
1760
1767
  progressBacktestEmitter: progressBacktestEmitter,
1761
1768
  progressOptimizerEmitter: progressOptimizerEmitter,
1762
1769
  progressWalkerEmitter: progressWalkerEmitter,
@@ -2245,6 +2252,7 @@ const CHECK_SCHEDULED_SIGNAL_TIMEOUT_FN = async (self, scheduled, currentPrice)
2245
2252
  exchangeName: self.params.method.context.exchangeName,
2246
2253
  symbol: self.params.execution.context.symbol,
2247
2254
  backtest: self.params.execution.context.backtest,
2255
+ reason: "timeout",
2248
2256
  };
2249
2257
  if (self.params.callbacks?.onTick) {
2250
2258
  self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
@@ -2281,7 +2289,7 @@ const CHECK_SCHEDULED_SIGNAL_PRICE_ACTIVATION_FN = (scheduled, currentPrice) =>
2281
2289
  return { shouldActivate, shouldCancel };
2282
2290
  };
2283
2291
  const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPrice) => {
2284
- self.params.logger.info("ClientStrategy scheduled signal cancelled", {
2292
+ self.params.logger.info("ClientStrategy scheduled signal cancelled by StopLoss", {
2285
2293
  symbol: self.params.execution.context.symbol,
2286
2294
  signalId: scheduled.id,
2287
2295
  position: scheduled.position,
@@ -2289,14 +2297,19 @@ const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPr
2289
2297
  priceStopLoss: scheduled.priceStopLoss,
2290
2298
  });
2291
2299
  await self.setScheduledSignal(null);
2300
+ if (self.params.callbacks?.onCancel) {
2301
+ self.params.callbacks.onCancel(self.params.execution.context.symbol, scheduled, currentPrice, self.params.execution.context.backtest);
2302
+ }
2292
2303
  const result = {
2293
- action: "idle",
2294
- signal: null,
2304
+ action: "cancelled",
2305
+ signal: scheduled,
2306
+ currentPrice: currentPrice,
2307
+ closeTimestamp: self.params.execution.context.when.getTime(),
2295
2308
  strategyName: self.params.method.context.strategyName,
2296
2309
  exchangeName: self.params.method.context.exchangeName,
2297
2310
  symbol: self.params.execution.context.symbol,
2298
- currentPrice: currentPrice,
2299
2311
  backtest: self.params.execution.context.backtest,
2312
+ reason: "price_reject",
2300
2313
  };
2301
2314
  if (self.params.callbacks?.onTick) {
2302
2315
  self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
@@ -2371,7 +2384,16 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
2371
2384
  }
2372
2385
  return result;
2373
2386
  };
2387
+ const CALL_PING_CALLBACKS_FN = async (self, scheduled, timestamp) => {
2388
+ // Call system onPing callback first (emits to pingSubject)
2389
+ await self.params.onPing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, scheduled, self.params.execution.context.backtest, timestamp);
2390
+ // Call user onPing callback only if signal is still active (not cancelled, not activated)
2391
+ if (self.params.callbacks?.onPing) {
2392
+ await self.params.callbacks.onPing(self.params.execution.context.symbol, scheduled, new Date(timestamp), self.params.execution.context.backtest);
2393
+ }
2394
+ };
2374
2395
  const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
2396
+ await CALL_PING_CALLBACKS_FN(self, scheduled, self.params.execution.context.when.getTime());
2375
2397
  const result = {
2376
2398
  action: "active",
2377
2399
  signal: scheduled,
@@ -2599,13 +2621,14 @@ const RETURN_IDLE_FN = async (self, currentPrice) => {
2599
2621
  }
2600
2622
  return result;
2601
2623
  };
2602
- const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp) => {
2624
+ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp, reason) => {
2603
2625
  self.params.logger.info("ClientStrategy backtest scheduled signal cancelled", {
2604
2626
  symbol: self.params.execution.context.symbol,
2605
2627
  signalId: scheduled.id,
2606
2628
  closeTimestamp,
2607
2629
  averagePrice,
2608
2630
  priceStopLoss: scheduled.priceStopLoss,
2631
+ reason,
2609
2632
  });
2610
2633
  await self.setScheduledSignal(null);
2611
2634
  if (self.params.callbacks?.onCancel) {
@@ -2620,6 +2643,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
2620
2643
  exchangeName: self.params.method.context.exchangeName,
2621
2644
  symbol: self.params.execution.context.symbol,
2622
2645
  backtest: self.params.execution.context.backtest,
2646
+ reason,
2623
2647
  };
2624
2648
  if (self.params.callbacks?.onTick) {
2625
2649
  self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
@@ -2735,10 +2759,16 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
2735
2759
  }
2736
2760
  const recentCandles = candles.slice(Math.max(0, i - (candlesCount - 1)), i + 1);
2737
2761
  const averagePrice = GET_AVG_PRICE_FN(recentCandles);
2762
+ // КРИТИЧНО: Проверяем был ли сигнал отменен пользователем через cancel()
2763
+ if (self._cancelledSignal) {
2764
+ // Сигнал был отменен через cancel() в onPing
2765
+ const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "user");
2766
+ return { activated: false, cancelled: true, activationIndex: i, result };
2767
+ }
2738
2768
  // КРИТИЧНО: Проверяем timeout ПЕРЕД проверкой цены
2739
2769
  const elapsedTime = candle.timestamp - scheduled.scheduledAt;
2740
2770
  if (elapsedTime >= maxTimeToWait) {
2741
- const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp);
2771
+ const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "timeout");
2742
2772
  return { activated: false, cancelled: true, activationIndex: i, result };
2743
2773
  }
2744
2774
  let shouldActivate = false;
@@ -2776,7 +2806,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
2776
2806
  }
2777
2807
  }
2778
2808
  if (shouldCancel) {
2779
- const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp);
2809
+ const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "price_reject");
2780
2810
  return { activated: false, cancelled: true, activationIndex: i, result };
2781
2811
  }
2782
2812
  if (shouldActivate) {
@@ -2788,6 +2818,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
2788
2818
  result: null,
2789
2819
  };
2790
2820
  }
2821
+ await CALL_PING_CALLBACKS_FN(self, scheduled, candle.timestamp);
2791
2822
  }
2792
2823
  return {
2793
2824
  activated: false,
@@ -2941,8 +2972,9 @@ class ClientStrategy {
2941
2972
  this.params = params;
2942
2973
  this._isStopped = false;
2943
2974
  this._pendingSignal = null;
2944
- this._scheduledSignal = null;
2945
2975
  this._lastSignalTimestamp = null;
2976
+ this._scheduledSignal = null;
2977
+ this._cancelledSignal = null;
2946
2978
  /**
2947
2979
  * Initializes strategy state by loading persisted signal from disk.
2948
2980
  *
@@ -3009,6 +3041,18 @@ class ClientStrategy {
3009
3041
  });
3010
3042
  return this._pendingSignal;
3011
3043
  }
3044
+ /**
3045
+ * Retrieves the current scheduled signal.
3046
+ * If no scheduled signal exists, returns null.
3047
+ * @returns Promise resolving to the scheduled signal or null.
3048
+ */
3049
+ async getScheduledSignal(symbol, strategyName) {
3050
+ this.params.logger.debug("ClientStrategy getScheduledSignal", {
3051
+ symbol,
3052
+ strategyName,
3053
+ });
3054
+ return this._scheduledSignal;
3055
+ }
3012
3056
  /**
3013
3057
  * Returns the stopped state of the strategy.
3014
3058
  *
@@ -3068,6 +3112,33 @@ class ClientStrategy {
3068
3112
  const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
3069
3113
  return await RETURN_IDLE_FN(this, currentPrice);
3070
3114
  }
3115
+ // Check if scheduled signal was cancelled - emit cancelled event once
3116
+ if (this._cancelledSignal) {
3117
+ const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
3118
+ const cancelledSignal = this._cancelledSignal;
3119
+ this._cancelledSignal = null; // Clear after emitting
3120
+ this.params.logger.info("ClientStrategy tick: scheduled signal was cancelled", {
3121
+ symbol: this.params.execution.context.symbol,
3122
+ signalId: cancelledSignal.id,
3123
+ });
3124
+ // Call onCancel callback
3125
+ if (this.params.callbacks?.onCancel) {
3126
+ this.params.callbacks.onCancel(this.params.execution.context.symbol, cancelledSignal, currentPrice, this.params.execution.context.backtest);
3127
+ }
3128
+ const result = {
3129
+ action: "cancelled",
3130
+ signal: cancelledSignal,
3131
+ currentPrice,
3132
+ closeTimestamp: currentTime,
3133
+ strategyName: this.params.method.context.strategyName,
3134
+ exchangeName: this.params.method.context.exchangeName,
3135
+ symbol: this.params.execution.context.symbol,
3136
+ backtest: this.params.execution.context.backtest,
3137
+ reason: "user",
3138
+ cancelId: cancelledSignal.cancelId,
3139
+ };
3140
+ return result;
3141
+ }
3071
3142
  // Monitor scheduled signal
3072
3143
  if (this._scheduledSignal && !this._pendingSignal) {
3073
3144
  const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
@@ -3158,6 +3229,29 @@ class ClientStrategy {
3158
3229
  if (!this.params.execution.context.backtest) {
3159
3230
  throw new Error("ClientStrategy backtest: running in live context");
3160
3231
  }
3232
+ // If signal was cancelled - return cancelled
3233
+ if (this._cancelledSignal) {
3234
+ this.params.logger.debug("ClientStrategy backtest: no signal (cancelled or not created)");
3235
+ const currentPrice = await this.params.exchange.getAveragePrice(symbol);
3236
+ const cancelledSignal = this._cancelledSignal;
3237
+ this._cancelledSignal = null; // Clear after using
3238
+ if (this.params.callbacks?.onCancel) {
3239
+ this.params.callbacks.onCancel(this.params.execution.context.symbol, cancelledSignal, currentPrice, this.params.execution.context.backtest);
3240
+ }
3241
+ const cancelledResult = {
3242
+ action: "cancelled",
3243
+ signal: cancelledSignal,
3244
+ currentPrice,
3245
+ closeTimestamp: this.params.execution.context.when.getTime(),
3246
+ strategyName: this.params.method.context.strategyName,
3247
+ exchangeName: this.params.method.context.exchangeName,
3248
+ symbol: this.params.execution.context.symbol,
3249
+ backtest: true,
3250
+ reason: "user",
3251
+ cancelId: cancelledSignal.cancelId,
3252
+ };
3253
+ return cancelledResult;
3254
+ }
3161
3255
  if (!this._pendingSignal && !this._scheduledSignal) {
3162
3256
  throw new Error("ClientStrategy backtest: no pending or scheduled signal");
3163
3257
  }
@@ -3230,7 +3324,7 @@ class ClientStrategy {
3230
3324
  maxMinutes: GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES,
3231
3325
  reason: "timeout - price never reached priceOpen",
3232
3326
  });
3233
- return await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(this, scheduled, lastPrice, lastCandleTimestamp);
3327
+ return await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(this, scheduled, lastPrice, lastCandleTimestamp, "timeout");
3234
3328
  }
3235
3329
  }
3236
3330
  // Process pending signal
@@ -3288,6 +3382,47 @@ class ClientStrategy {
3288
3382
  }
3289
3383
  await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
3290
3384
  }
3385
+ /**
3386
+ * Cancels the scheduled signal without stopping the strategy.
3387
+ *
3388
+ * Clears the scheduled signal (waiting for priceOpen activation).
3389
+ * Does NOT affect active pending signals or strategy operation.
3390
+ * Does NOT set stop flag - strategy can continue generating new signals.
3391
+ *
3392
+ * Use case: Cancel a scheduled entry that is no longer desired without stopping the entire strategy.
3393
+ *
3394
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
3395
+ * @param strategyName - Name of the strategy
3396
+ * @param backtest - Whether running in backtest mode
3397
+ * @returns Promise that resolves when scheduled signal is cleared
3398
+ *
3399
+ * @example
3400
+ * ```typescript
3401
+ * // Cancel scheduled signal without stopping strategy
3402
+ * await strategy.cancel("BTCUSDT", "my-strategy", false);
3403
+ * // Strategy continues, can generate new signals
3404
+ * ```
3405
+ */
3406
+ async cancel(symbol, strategyName, backtest, cancelId) {
3407
+ this.params.logger.debug("ClientStrategy cancel", {
3408
+ symbol,
3409
+ strategyName,
3410
+ hasScheduledSignal: this._scheduledSignal !== null,
3411
+ backtest,
3412
+ cancelId,
3413
+ });
3414
+ // Save cancelled signal for next tick to emit cancelled event
3415
+ if (this._scheduledSignal) {
3416
+ this._cancelledSignal = Object.assign({}, this._scheduledSignal, {
3417
+ cancelId,
3418
+ });
3419
+ this._scheduledSignal = null;
3420
+ }
3421
+ if (backtest) {
3422
+ return;
3423
+ }
3424
+ await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
3425
+ }
3291
3426
  }
3292
3427
 
3293
3428
  const RISK_METHOD_NAME_GET_DATA = "RiskUtils.getData";
@@ -3614,6 +3749,27 @@ const GET_RISK_FN = (dto, backtest, self) => {
3614
3749
  ...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
3615
3750
  ]);
3616
3751
  };
3752
+ /**
3753
+ * Callback function for emitting ping events to pingSubject.
3754
+ *
3755
+ * Called by ClientStrategy when a scheduled signal is being monitored every minute.
3756
+ * Emits PingContract event to all subscribers.
3757
+ *
3758
+ * @param symbol - Trading pair symbol
3759
+ * @param strategyName - Strategy name that is monitoring this scheduled signal
3760
+ * @param exchangeName - Exchange name where this scheduled signal is being executed
3761
+ * @param data - Scheduled signal row data
3762
+ * @param backtest - True if backtest mode
3763
+ * @param timestamp - Event timestamp in milliseconds
3764
+ */
3765
+ const COMMIT_PING_FN = async (symbol, strategyName, exchangeName, data, backtest, timestamp) => await pingSubject.next({
3766
+ symbol,
3767
+ strategyName,
3768
+ exchangeName,
3769
+ data,
3770
+ backtest,
3771
+ timestamp,
3772
+ });
3617
3773
  /**
3618
3774
  * Connection service routing strategy operations to correct ClientStrategy instance.
3619
3775
  *
@@ -3671,6 +3827,7 @@ class StrategyConnectionService {
3671
3827
  strategyName,
3672
3828
  getSignal,
3673
3829
  callbacks,
3830
+ onPing: COMMIT_PING_FN,
3674
3831
  });
3675
3832
  });
3676
3833
  /**
@@ -3692,6 +3849,25 @@ class StrategyConnectionService {
3692
3849
  const strategy = this.getStrategy(symbol, strategyName, backtest);
3693
3850
  return await strategy.getPendingSignal(symbol, strategyName);
3694
3851
  };
3852
+ /**
3853
+ * Retrieves the currently active scheduled signal for the strategy.
3854
+ * If no scheduled signal exists, returns null.
3855
+ * Used internally for monitoring scheduled signal activation.
3856
+ *
3857
+ * @param symbol - Trading pair symbol
3858
+ * @param strategyName - Name of strategy to get scheduled signal for
3859
+ *
3860
+ * @returns Promise resolving to scheduled signal or null
3861
+ */
3862
+ this.getScheduledSignal = async (backtest, symbol, strategyName) => {
3863
+ this.loggerService.log("strategyConnectionService getScheduledSignal", {
3864
+ symbol,
3865
+ strategyName,
3866
+ backtest,
3867
+ });
3868
+ const strategy = this.getStrategy(symbol, strategyName, backtest);
3869
+ return await strategy.getScheduledSignal(symbol, strategyName);
3870
+ };
3695
3871
  /**
3696
3872
  * Retrieves the stopped state of the strategy.
3697
3873
  *
@@ -3807,6 +3983,28 @@ class StrategyConnectionService {
3807
3983
  this.getStrategy.clear();
3808
3984
  }
3809
3985
  };
3986
+ /**
3987
+ * Cancels the scheduled signal for the specified strategy.
3988
+ *
3989
+ * Delegates to ClientStrategy.cancel() which clears the scheduled signal
3990
+ * without stopping the strategy or affecting pending signals.
3991
+ *
3992
+ * Note: Cancelled event will be emitted on next tick() call when strategy
3993
+ * detects the scheduled signal was cancelled.
3994
+ *
3995
+ * @param backtest - Whether running in backtest mode
3996
+ * @param ctx - Context with symbol and strategyName
3997
+ * @param cancelId - Optional cancellation ID for user-initiated cancellations
3998
+ * @returns Promise that resolves when scheduled signal is cancelled
3999
+ */
4000
+ this.cancel = async (backtest, ctx, cancelId) => {
4001
+ this.loggerService.log("strategyConnectionService cancel", {
4002
+ ctx,
4003
+ cancelId,
4004
+ });
4005
+ const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
4006
+ await strategy.cancel(ctx.symbol, ctx.strategyName, backtest, cancelId);
4007
+ };
3810
4008
  }
3811
4009
  }
3812
4010
 
@@ -4752,6 +4950,26 @@ class StrategyCoreService {
4752
4950
  await this.validate(symbol, strategyName);
4753
4951
  return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
4754
4952
  };
4953
+ /**
4954
+ * Retrieves the currently active scheduled signal for the symbol.
4955
+ * If no scheduled signal exists, returns null.
4956
+ * Used internally for monitoring scheduled signal activation.
4957
+ *
4958
+ * @param symbol - Trading pair symbol
4959
+ * @param strategyName - Name of the strategy
4960
+ * @returns Promise resolving to scheduled signal or null
4961
+ */
4962
+ this.getScheduledSignal = async (backtest, symbol, strategyName) => {
4963
+ this.loggerService.log("strategyCoreService getScheduledSignal", {
4964
+ symbol,
4965
+ strategyName,
4966
+ });
4967
+ if (!MethodContextService.hasContext()) {
4968
+ throw new Error("strategyCoreService getScheduledSignal requires a method context");
4969
+ }
4970
+ await this.validate(symbol, strategyName);
4971
+ return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, strategyName);
4972
+ };
4755
4973
  /**
4756
4974
  * Checks if the strategy has been stopped.
4757
4975
  *
@@ -4854,6 +5072,27 @@ class StrategyCoreService {
4854
5072
  await this.validate(ctx.symbol, ctx.strategyName);
4855
5073
  return await this.strategyConnectionService.stop(backtest, ctx);
4856
5074
  };
5075
+ /**
5076
+ * Cancels the scheduled signal without stopping the strategy.
5077
+ *
5078
+ * Delegates to StrategyConnectionService.cancel() to clear scheduled signal
5079
+ * and emit cancelled event through emitters.
5080
+ * Does not require execution context.
5081
+ *
5082
+ * @param backtest - Whether running in backtest mode
5083
+ * @param ctx - Context with symbol and strategyName
5084
+ * @param cancelId - Optional cancellation ID for user-initiated cancellations
5085
+ * @returns Promise that resolves when scheduled signal is cancelled
5086
+ */
5087
+ this.cancel = async (backtest, ctx, cancelId) => {
5088
+ this.loggerService.log("strategyCoreService cancel", {
5089
+ ctx,
5090
+ backtest,
5091
+ cancelId,
5092
+ });
5093
+ await this.validate(ctx.symbol, ctx.strategyName);
5094
+ return await this.strategyConnectionService.cancel(backtest, ctx, cancelId);
5095
+ };
4857
5096
  /**
4858
5097
  * Clears the memoized ClientStrategy instance from cache.
4859
5098
  *
@@ -7177,12 +7416,17 @@ const risk_columns = [
7177
7416
  * - Signal identification (symbol, signal ID, position)
7178
7417
  * - Price data (current price, entry price, take profit, stop loss)
7179
7418
  * - Timing information (wait time in minutes before activation or cancellation)
7419
+ * - Cancellation details (reason: timeout/stoploss/user, optional user cancel ID)
7180
7420
  *
7181
7421
  * @remarks
7182
7422
  * This configuration tracks the lifecycle of scheduled signals from creation to activation or cancellation.
7183
7423
  * The "note" column visibility is controlled by {@link GLOBAL_CONFIG.CC_REPORT_SHOW_SIGNAL_NOTE}.
7184
7424
  * Helps analyze signal scheduling effectiveness and cancellation patterns.
7185
7425
  *
7426
+ * Cancellation tracking includes:
7427
+ * - cancelReason: "timeout" (expired wait time), "price_reject" (price hit SL), "user" (manual cancellation)
7428
+ * - cancelId: Optional ID provided when calling Backtest.cancel() or Live.cancel()
7429
+ *
7186
7430
  * @example
7187
7431
  * ```typescript
7188
7432
  * import { schedule_columns } from "./assets/schedule.columns";
@@ -7191,9 +7435,9 @@ const risk_columns = [
7191
7435
  * const service = new ScheduleMarkdownService();
7192
7436
  * await service.getReport("BTCUSDT", "my-strategy", schedule_columns);
7193
7437
  *
7194
- * // Or customize for timing analysis
7438
+ * // Or customize for cancellation analysis
7195
7439
  * const customColumns = schedule_columns.filter(col =>
7196
- * ["timestamp", "action", "symbol", "duration"].includes(col.key)
7440
+ * ["timestamp", "action", "cancelReason", "cancelId"].includes(col.key)
7197
7441
  * );
7198
7442
  * await service.getReport("BTCUSDT", "my-strategy", customColumns);
7199
7443
  * ```
@@ -7242,7 +7486,7 @@ const schedule_columns = [
7242
7486
  {
7243
7487
  key: "currentPrice",
7244
7488
  label: "Current Price",
7245
- format: (data) => `${data.currentPrice.toFixed(8)} USD`,
7489
+ format: (data) => data.currentPrice ? `${data.currentPrice.toFixed(8)} USD` : "N/A",
7246
7490
  isVisible: () => true,
7247
7491
  },
7248
7492
  {
@@ -7269,6 +7513,18 @@ const schedule_columns = [
7269
7513
  format: (data) => data.duration !== undefined ? `${data.duration}` : "N/A",
7270
7514
  isVisible: () => true,
7271
7515
  },
7516
+ {
7517
+ key: "cancelReason",
7518
+ label: "Cancel Reason",
7519
+ format: (data) => data.cancelReason ? data.cancelReason.toUpperCase() : "N/A",
7520
+ isVisible: () => true,
7521
+ },
7522
+ {
7523
+ key: "cancelId",
7524
+ label: "Cancel ID",
7525
+ format: (data) => data.cancelId ?? "N/A",
7526
+ isVisible: () => true,
7527
+ },
7272
7528
  ];
7273
7529
 
7274
7530
  /**
@@ -8449,6 +8705,8 @@ let ReportStorage$3 = class ReportStorage {
8449
8705
  stopLoss: data.signal.priceStopLoss,
8450
8706
  closeTimestamp: data.closeTimestamp,
8451
8707
  duration: durationMin,
8708
+ cancelReason: data.reason,
8709
+ cancelId: data.cancelId,
8452
8710
  };
8453
8711
  this._eventList.unshift(newEvent);
8454
8712
  // Trim queue if exceeded MAX_EVENTS
@@ -14729,6 +14987,8 @@ const LISTEN_PARTIAL_LOSS_METHOD_NAME = "event.listenPartialLoss";
14729
14987
  const LISTEN_PARTIAL_LOSS_ONCE_METHOD_NAME = "event.listenPartialLossOnce";
14730
14988
  const LISTEN_RISK_METHOD_NAME = "event.listenRisk";
14731
14989
  const LISTEN_RISK_ONCE_METHOD_NAME = "event.listenRiskOnce";
14990
+ const LISTEN_PING_METHOD_NAME = "event.listenPing";
14991
+ const LISTEN_PING_ONCE_METHOD_NAME = "event.listenPingOnce";
14732
14992
  /**
14733
14993
  * Subscribes to all signal events with queued async processing.
14734
14994
  *
@@ -15596,6 +15856,67 @@ function listenRiskOnce(filterFn, fn) {
15596
15856
  backtest$1.loggerService.log(LISTEN_RISK_ONCE_METHOD_NAME);
15597
15857
  return riskSubject.filter(filterFn).once(fn);
15598
15858
  }
15859
+ /**
15860
+ * Subscribes to ping events during scheduled signal monitoring with queued async processing.
15861
+ *
15862
+ * Events are emitted every minute when a scheduled signal is being monitored (waiting for activation).
15863
+ * Allows tracking of scheduled signal lifecycle and custom monitoring logic.
15864
+ *
15865
+ * @param fn - Callback function to handle ping events
15866
+ * @returns Unsubscribe function to stop listening
15867
+ *
15868
+ * @example
15869
+ * ```typescript
15870
+ * import { listenPing } from "./function/event";
15871
+ *
15872
+ * const unsubscribe = listenPing((event) => {
15873
+ * console.log(`Ping for ${event.symbol} at ${new Date(event.timestamp).toISOString()}`);
15874
+ * console.log(`Strategy: ${event.strategyName}, Exchange: ${event.exchangeName}`);
15875
+ * console.log(`Mode: ${event.backtest ? "Backtest" : "Live"}`);
15876
+ * });
15877
+ *
15878
+ * // Later: stop listening
15879
+ * unsubscribe();
15880
+ * ```
15881
+ */
15882
+ function listenPing(fn) {
15883
+ backtest$1.loggerService.log(LISTEN_PING_METHOD_NAME);
15884
+ return pingSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
15885
+ }
15886
+ /**
15887
+ * Subscribes to filtered ping events with one-time execution.
15888
+ *
15889
+ * Listens for events matching the filter predicate, then executes callback once
15890
+ * and automatically unsubscribes. Useful for waiting for specific ping conditions.
15891
+ *
15892
+ * @param filterFn - Predicate to filter which events trigger the callback
15893
+ * @param fn - Callback function to handle the filtered event (called only once)
15894
+ * @returns Unsubscribe function to cancel the listener before it fires
15895
+ *
15896
+ * @example
15897
+ * ```typescript
15898
+ * import { listenPingOnce } from "./function/event";
15899
+ *
15900
+ * // Wait for first ping on BTCUSDT
15901
+ * listenPingOnce(
15902
+ * (event) => event.symbol === "BTCUSDT",
15903
+ * (event) => console.log("First BTCUSDT ping received")
15904
+ * );
15905
+ *
15906
+ * // Wait for ping in backtest mode
15907
+ * const cancel = listenPingOnce(
15908
+ * (event) => event.backtest === true,
15909
+ * (event) => console.log("Backtest ping received at", new Date(event.timestamp))
15910
+ * );
15911
+ *
15912
+ * // Cancel if needed before event fires
15913
+ * cancel();
15914
+ * ```
15915
+ */
15916
+ function listenPingOnce(filterFn, fn) {
15917
+ backtest$1.loggerService.log(LISTEN_PING_ONCE_METHOD_NAME);
15918
+ return pingSubject.filter(filterFn).once(fn);
15919
+ }
15599
15920
 
15600
15921
  const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
15601
15922
  const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
@@ -15869,6 +16190,8 @@ const BACKTEST_METHOD_NAME_GET_REPORT = "BacktestUtils.getReport";
15869
16190
  const BACKTEST_METHOD_NAME_DUMP = "BacktestUtils.dump";
15870
16191
  const BACKTEST_METHOD_NAME_TASK = "BacktestUtils.task";
15871
16192
  const BACKTEST_METHOD_NAME_GET_STATUS = "BacktestUtils.getStatus";
16193
+ const BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL = "BacktestUtils.getPendingSignal";
16194
+ const BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL = "BacktestUtils.getScheduledSignal";
15872
16195
  /**
15873
16196
  * Internal task function that runs backtest and handles completion.
15874
16197
  * Consumes backtest results and updates instance state flags.
@@ -16059,6 +16382,54 @@ class BacktestInstance {
16059
16382
  this._isStopped = true;
16060
16383
  };
16061
16384
  };
16385
+ /**
16386
+ * Retrieves the currently active pending signal for the strategy.
16387
+ * If no active signal exists, returns null.
16388
+ *
16389
+ * @param symbol - Trading pair symbol
16390
+ * @param strategyName - Name of strategy to get pending signal for
16391
+ * @returns Promise resolving to pending signal or null
16392
+ *
16393
+ * @example
16394
+ * ```typescript
16395
+ * const instance = new BacktestInstance();
16396
+ * const pending = await instance.getPendingSignal("BTCUSDT", "my-strategy");
16397
+ * if (pending) {
16398
+ * console.log("Active signal:", pending.id);
16399
+ * }
16400
+ * ```
16401
+ */
16402
+ this.getPendingSignal = async (symbol, strategyName) => {
16403
+ backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL, {
16404
+ symbol,
16405
+ strategyName,
16406
+ });
16407
+ return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, strategyName);
16408
+ };
16409
+ /**
16410
+ * Retrieves the currently active scheduled signal for the strategy.
16411
+ * If no scheduled signal exists, returns null.
16412
+ *
16413
+ * @param symbol - Trading pair symbol
16414
+ * @param strategyName - Name of strategy to get scheduled signal for
16415
+ * @returns Promise resolving to scheduled signal or null
16416
+ *
16417
+ * @example
16418
+ * ```typescript
16419
+ * const instance = new BacktestInstance();
16420
+ * const scheduled = await instance.getScheduledSignal("BTCUSDT", "my-strategy");
16421
+ * if (scheduled) {
16422
+ * console.log("Scheduled signal:", scheduled.id);
16423
+ * }
16424
+ * ```
16425
+ */
16426
+ this.getScheduledSignal = async (symbol, strategyName) => {
16427
+ backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL, {
16428
+ symbol,
16429
+ strategyName,
16430
+ });
16431
+ return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, strategyName);
16432
+ };
16062
16433
  /**
16063
16434
  * Stops the strategy from generating new signals.
16064
16435
  *
@@ -16083,6 +16454,32 @@ class BacktestInstance {
16083
16454
  });
16084
16455
  await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
16085
16456
  };
16457
+ /**
16458
+ * Cancels the scheduled signal without stopping the strategy.
16459
+ *
16460
+ * Clears the scheduled signal (waiting for priceOpen activation).
16461
+ * Does NOT affect active pending signals or strategy operation.
16462
+ * Does NOT set stop flag - strategy can continue generating new signals.
16463
+ *
16464
+ * @param symbol - Trading pair symbol
16465
+ * @param strategyName - Strategy name
16466
+ * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
16467
+ * @returns Promise that resolves when scheduled signal is cancelled
16468
+ *
16469
+ * @example
16470
+ * ```typescript
16471
+ * const instance = new BacktestInstance();
16472
+ * await instance.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
16473
+ * ```
16474
+ */
16475
+ this.cancel = async (symbol, strategyName, cancelId) => {
16476
+ backtest$1.loggerService.info("BacktestInstance.cancel", {
16477
+ symbol,
16478
+ strategyName,
16479
+ cancelId,
16480
+ });
16481
+ await backtest$1.strategyCoreService.cancel(true, { symbol, strategyName }, cancelId);
16482
+ };
16086
16483
  /**
16087
16484
  * Gets statistical data from all closed signals for a symbol-strategy pair.
16088
16485
  *
@@ -16234,6 +16631,58 @@ class BacktestUtils {
16234
16631
  const instance = this._getInstance(symbol, context.strategyName);
16235
16632
  return instance.background(symbol, context);
16236
16633
  };
16634
+ /**
16635
+ * Retrieves the currently active pending signal for the strategy.
16636
+ * If no active signal exists, returns null.
16637
+ *
16638
+ * @param symbol - Trading pair symbol
16639
+ * @param strategyName - Name of strategy to get pending signal for
16640
+ * @returns Promise resolving to pending signal or null
16641
+ *
16642
+ * @example
16643
+ * ```typescript
16644
+ * const pending = await Backtest.getPendingSignal("BTCUSDT", "my-strategy");
16645
+ * if (pending) {
16646
+ * console.log("Active signal:", pending.id);
16647
+ * }
16648
+ * ```
16649
+ */
16650
+ this.getPendingSignal = async (symbol, strategyName) => {
16651
+ backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16652
+ {
16653
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
16654
+ riskName && backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
16655
+ riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL));
16656
+ }
16657
+ const instance = this._getInstance(symbol, strategyName);
16658
+ return await instance.getPendingSignal(symbol, strategyName);
16659
+ };
16660
+ /**
16661
+ * Retrieves the currently active scheduled signal for the strategy.
16662
+ * If no scheduled signal exists, returns null.
16663
+ *
16664
+ * @param symbol - Trading pair symbol
16665
+ * @param strategyName - Name of strategy to get scheduled signal for
16666
+ * @returns Promise resolving to scheduled signal or null
16667
+ *
16668
+ * @example
16669
+ * ```typescript
16670
+ * const scheduled = await Backtest.getScheduledSignal("BTCUSDT", "my-strategy");
16671
+ * if (scheduled) {
16672
+ * console.log("Scheduled signal:", scheduled.id);
16673
+ * }
16674
+ * ```
16675
+ */
16676
+ this.getScheduledSignal = async (symbol, strategyName) => {
16677
+ backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16678
+ {
16679
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
16680
+ riskName && backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
16681
+ riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL));
16682
+ }
16683
+ const instance = this._getInstance(symbol, strategyName);
16684
+ return await instance.getScheduledSignal(symbol, strategyName);
16685
+ };
16237
16686
  /**
16238
16687
  * Stops the strategy from generating new signals.
16239
16688
  *
@@ -16261,6 +16710,34 @@ class BacktestUtils {
16261
16710
  const instance = this._getInstance(symbol, strategyName);
16262
16711
  return await instance.stop(symbol, strategyName);
16263
16712
  };
16713
+ /**
16714
+ * Cancels the scheduled signal without stopping the strategy.
16715
+ *
16716
+ * Clears the scheduled signal (waiting for priceOpen activation).
16717
+ * Does NOT affect active pending signals or strategy operation.
16718
+ * Does NOT set stop flag - strategy can continue generating new signals.
16719
+ *
16720
+ * @param symbol - Trading pair symbol
16721
+ * @param strategyName - Strategy name
16722
+ * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
16723
+ * @returns Promise that resolves when scheduled signal is cancelled
16724
+ *
16725
+ * @example
16726
+ * ```typescript
16727
+ * // Cancel scheduled signal with custom ID
16728
+ * await Backtest.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
16729
+ * ```
16730
+ */
16731
+ this.cancel = async (symbol, strategyName, cancelId) => {
16732
+ backtest$1.strategyValidationService.validate(strategyName, "BacktestUtils.cancel");
16733
+ {
16734
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
16735
+ riskName && backtest$1.riskValidationService.validate(riskName, "BacktestUtils.cancel");
16736
+ riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, "BacktestUtils.cancel"));
16737
+ }
16738
+ const instance = this._getInstance(symbol, strategyName);
16739
+ return await instance.cancel(symbol, strategyName, cancelId);
16740
+ };
16264
16741
  /**
16265
16742
  * Gets statistical data from all closed signals for a symbol-strategy pair.
16266
16743
  *
@@ -16382,6 +16859,9 @@ const LIVE_METHOD_NAME_GET_DATA = "LiveUtils.getData";
16382
16859
  const LIVE_METHOD_NAME_DUMP = "LiveUtils.dump";
16383
16860
  const LIVE_METHOD_NAME_TASK = "LiveUtils.task";
16384
16861
  const LIVE_METHOD_NAME_GET_STATUS = "LiveUtils.getStatus";
16862
+ const LIVE_METHOD_NAME_GET_PENDING_SIGNAL = "LiveUtils.getPendingSignal";
16863
+ const LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL = "LiveUtils.getScheduledSignal";
16864
+ const LIVE_METHOD_NAME_CANCEL = "LiveUtils.cancel";
16385
16865
  /**
16386
16866
  * Internal task function that runs live trading and handles completion.
16387
16867
  * Consumes live trading results and updates instance state flags.
@@ -16576,6 +17056,54 @@ class LiveInstance {
16576
17056
  this._isStopped = true;
16577
17057
  };
16578
17058
  };
17059
+ /**
17060
+ * Retrieves the currently active pending signal for the strategy.
17061
+ * If no active signal exists, returns null.
17062
+ *
17063
+ * @param symbol - Trading pair symbol
17064
+ * @param strategyName - Name of strategy to get pending signal for
17065
+ * @returns Promise resolving to pending signal or null
17066
+ *
17067
+ * @example
17068
+ * ```typescript
17069
+ * const instance = new LiveInstance();
17070
+ * const pending = await instance.getPendingSignal("BTCUSDT", "my-strategy");
17071
+ * if (pending) {
17072
+ * console.log("Active signal:", pending.id);
17073
+ * }
17074
+ * ```
17075
+ */
17076
+ this.getPendingSignal = async (symbol, strategyName) => {
17077
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_PENDING_SIGNAL, {
17078
+ symbol,
17079
+ strategyName,
17080
+ });
17081
+ return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, strategyName);
17082
+ };
17083
+ /**
17084
+ * Retrieves the currently active scheduled signal for the strategy.
17085
+ * If no scheduled signal exists, returns null.
17086
+ *
17087
+ * @param symbol - Trading pair symbol
17088
+ * @param strategyName - Name of strategy to get scheduled signal for
17089
+ * @returns Promise resolving to scheduled signal or null
17090
+ *
17091
+ * @example
17092
+ * ```typescript
17093
+ * const instance = new LiveInstance();
17094
+ * const scheduled = await instance.getScheduledSignal("BTCUSDT", "my-strategy");
17095
+ * if (scheduled) {
17096
+ * console.log("Scheduled signal:", scheduled.id);
17097
+ * }
17098
+ * ```
17099
+ */
17100
+ this.getScheduledSignal = async (symbol, strategyName) => {
17101
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL, {
17102
+ symbol,
17103
+ strategyName,
17104
+ });
17105
+ return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, strategyName);
17106
+ };
16579
17107
  /**
16580
17108
  * Stops the strategy from generating new signals.
16581
17109
  *
@@ -16600,6 +17128,32 @@ class LiveInstance {
16600
17128
  });
16601
17129
  await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
16602
17130
  };
17131
+ /**
17132
+ * Cancels the scheduled signal without stopping the strategy.
17133
+ *
17134
+ * Clears the scheduled signal (waiting for priceOpen activation).
17135
+ * Does NOT affect active pending signals or strategy operation.
17136
+ * Does NOT set stop flag - strategy can continue generating new signals.
17137
+ *
17138
+ * @param symbol - Trading pair symbol
17139
+ * @param strategyName - Strategy name
17140
+ * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
17141
+ * @returns Promise that resolves when scheduled signal is cancelled
17142
+ *
17143
+ * @example
17144
+ * ```typescript
17145
+ * const instance = new LiveInstance();
17146
+ * await instance.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17147
+ * ```
17148
+ */
17149
+ this.cancel = async (symbol, strategyName, cancelId) => {
17150
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_CANCEL, {
17151
+ symbol,
17152
+ strategyName,
17153
+ cancelId,
17154
+ });
17155
+ await backtest$1.strategyCoreService.cancel(false, { symbol, strategyName }, cancelId);
17156
+ };
16603
17157
  /**
16604
17158
  * Gets statistical data from all live trading events for a symbol-strategy pair.
16605
17159
  *
@@ -16762,6 +17316,58 @@ class LiveUtils {
16762
17316
  const instance = this._getInstance(symbol, context.strategyName);
16763
17317
  return instance.background(symbol, context);
16764
17318
  };
17319
+ /**
17320
+ * Retrieves the currently active pending signal for the strategy.
17321
+ * If no active signal exists, returns null.
17322
+ *
17323
+ * @param symbol - Trading pair symbol
17324
+ * @param strategyName - Name of strategy to get pending signal for
17325
+ * @returns Promise resolving to pending signal or null
17326
+ *
17327
+ * @example
17328
+ * ```typescript
17329
+ * const pending = await Live.getPendingSignal("BTCUSDT", "my-strategy");
17330
+ * if (pending) {
17331
+ * console.log("Active signal:", pending.id);
17332
+ * }
17333
+ * ```
17334
+ */
17335
+ this.getPendingSignal = async (symbol, strategyName) => {
17336
+ backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17337
+ {
17338
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17339
+ riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
17340
+ riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL));
17341
+ }
17342
+ const instance = this._getInstance(symbol, strategyName);
17343
+ return await instance.getPendingSignal(symbol, strategyName);
17344
+ };
17345
+ /**
17346
+ * Retrieves the currently active scheduled signal for the strategy.
17347
+ * If no scheduled signal exists, returns null.
17348
+ *
17349
+ * @param symbol - Trading pair symbol
17350
+ * @param strategyName - Name of strategy to get scheduled signal for
17351
+ * @returns Promise resolving to scheduled signal or null
17352
+ *
17353
+ * @example
17354
+ * ```typescript
17355
+ * const scheduled = await Live.getScheduledSignal("BTCUSDT", "my-strategy");
17356
+ * if (scheduled) {
17357
+ * console.log("Scheduled signal:", scheduled.id);
17358
+ * }
17359
+ * ```
17360
+ */
17361
+ this.getScheduledSignal = async (symbol, strategyName) => {
17362
+ backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17363
+ {
17364
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17365
+ riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
17366
+ riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL));
17367
+ }
17368
+ const instance = this._getInstance(symbol, strategyName);
17369
+ return await instance.getScheduledSignal(symbol, strategyName);
17370
+ };
16765
17371
  /**
16766
17372
  * Stops the strategy from generating new signals.
16767
17373
  *
@@ -16789,6 +17395,34 @@ class LiveUtils {
16789
17395
  const instance = this._getInstance(symbol, strategyName);
16790
17396
  return await instance.stop(symbol, strategyName);
16791
17397
  };
17398
+ /**
17399
+ * Cancels the scheduled signal without stopping the strategy.
17400
+ *
17401
+ * Clears the scheduled signal (waiting for priceOpen activation).
17402
+ * Does NOT affect active pending signals or strategy operation.
17403
+ * Does NOT set stop flag - strategy can continue generating new signals.
17404
+ *
17405
+ * @param symbol - Trading pair symbol
17406
+ * @param strategyName - Strategy name
17407
+ * @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
17408
+ * @returns Promise that resolves when scheduled signal is cancelled
17409
+ *
17410
+ * @example
17411
+ * ```typescript
17412
+ * // Cancel scheduled signal in live trading with custom ID
17413
+ * await Live.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
17414
+ * ```
17415
+ */
17416
+ this.cancel = async (symbol, strategyName, cancelId) => {
17417
+ backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_CANCEL);
17418
+ {
17419
+ const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
17420
+ riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL);
17421
+ riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL));
17422
+ }
17423
+ const instance = this._getInstance(symbol, strategyName);
17424
+ return await instance.cancel(symbol, strategyName, cancelId);
17425
+ };
16792
17426
  /**
16793
17427
  * Gets statistical data from all live trading events for a symbol-strategy pair.
16794
17428
  *
@@ -19012,6 +19646,8 @@ exports.listenPartialLossOnce = listenPartialLossOnce;
19012
19646
  exports.listenPartialProfit = listenPartialProfit;
19013
19647
  exports.listenPartialProfitOnce = listenPartialProfitOnce;
19014
19648
  exports.listenPerformance = listenPerformance;
19649
+ exports.listenPing = listenPing;
19650
+ exports.listenPingOnce = listenPingOnce;
19015
19651
  exports.listenRisk = listenRisk;
19016
19652
  exports.listenRiskOnce = listenRiskOnce;
19017
19653
  exports.listenSignal = listenSignal;