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