backtest-kit 1.13.3 → 2.0.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
@@ -1,6 +1,6 @@
1
1
  import { createActivator } from 'di-kit';
2
2
  import { scoped } from 'di-scoped';
3
- import { Subject, trycatch, errorData, getErrorMessage, sleep, memoize, makeExtendable, singleshot, not, retry, randomString, isObject, ToolRegistry, and, resolveDocuments, str, timeout, TIMEOUT_SYMBOL as TIMEOUT_SYMBOL$1, compose, iterateDocuments, distinctDocuments, queued, singlerun } from 'functools-kit';
3
+ import { Subject, trycatch, errorData, getErrorMessage, sleep, memoize, makeExtendable, singleshot, not, retry, randomString, str, isObject, ToolRegistry, and, resolveDocuments, timeout, TIMEOUT_SYMBOL as TIMEOUT_SYMBOL$1, compose, iterateDocuments, distinctDocuments, queued, singlerun } from 'functools-kit';
4
4
  import * as fs from 'fs/promises';
5
5
  import fs__default, { mkdir, writeFile } from 'fs/promises';
6
6
  import path, { join, dirname } from 'path';
@@ -521,14 +521,21 @@ const breakevenSubject = new Subject();
521
521
  */
522
522
  const riskSubject = new Subject();
523
523
  /**
524
- * Ping emitter for scheduled signal monitoring events.
524
+ * Schedule ping emitter for scheduled signal monitoring events.
525
525
  * Emits every minute when a scheduled signal is being monitored (waiting for activation).
526
526
  * Allows users to track scheduled signal lifecycle and implement custom cancellation logic.
527
527
  */
528
- const pingSubject = new Subject();
528
+ const schedulePingSubject = new Subject();
529
+ /**
530
+ * Active ping emitter for active pending signal monitoring events.
531
+ * Emits every minute when an active pending signal is being monitored.
532
+ * Allows users to track active signal lifecycle and implement custom dynamic management logic.
533
+ */
534
+ const activePingSubject = new Subject();
529
535
 
530
536
  var emitters = /*#__PURE__*/Object.freeze({
531
537
  __proto__: null,
538
+ activePingSubject: activePingSubject,
532
539
  breakevenSubject: breakevenSubject,
533
540
  doneBacktestSubject: doneBacktestSubject,
534
541
  doneLiveSubject: doneLiveSubject,
@@ -538,11 +545,11 @@ var emitters = /*#__PURE__*/Object.freeze({
538
545
  partialLossSubject: partialLossSubject,
539
546
  partialProfitSubject: partialProfitSubject,
540
547
  performanceEmitter: performanceEmitter,
541
- pingSubject: pingSubject,
542
548
  progressBacktestEmitter: progressBacktestEmitter,
543
549
  progressOptimizerEmitter: progressOptimizerEmitter,
544
550
  progressWalkerEmitter: progressWalkerEmitter,
545
551
  riskSubject: riskSubject,
552
+ schedulePingSubject: schedulePingSubject,
546
553
  signalBacktestEmitter: signalBacktestEmitter,
547
554
  signalEmitter: signalEmitter,
548
555
  signalLiveEmitter: signalLiveEmitter,
@@ -753,11 +760,16 @@ class ClientExchange {
753
760
  const whenTimestamp = this.params.execution.context.when.getTime();
754
761
  const sinceTimestamp = since.getTime();
755
762
  const filteredData = allData.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= whenTimestamp);
756
- if (filteredData.length < limit) {
757
- this.params.logger.warn(`ClientExchange Expected ${limit} candles, got ${filteredData.length}`);
763
+ // Apply distinct by timestamp to remove duplicates
764
+ const uniqueData = Array.from(new Map(filteredData.map((candle) => [candle.timestamp, candle])).values());
765
+ if (filteredData.length !== uniqueData.length) {
766
+ this.params.logger.warn(`ClientExchange Removed ${filteredData.length - uniqueData.length} duplicate candles by timestamp`);
758
767
  }
759
- await CALL_CANDLE_DATA_CALLBACKS_FN(this, symbol, interval, since, limit, filteredData);
760
- return filteredData;
768
+ if (uniqueData.length < limit) {
769
+ this.params.logger.warn(`ClientExchange Expected ${limit} candles, got ${uniqueData.length}`);
770
+ }
771
+ await CALL_CANDLE_DATA_CALLBACKS_FN(this, symbol, interval, since, limit, uniqueData);
772
+ return uniqueData;
761
773
  }
762
774
  /**
763
775
  * Fetches future candles forwards from execution context time.
@@ -806,11 +818,16 @@ class ClientExchange {
806
818
  // Filter candles to strictly match the requested range
807
819
  const sinceTimestamp = since.getTime();
808
820
  const filteredData = allData.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= endTime);
809
- if (filteredData.length < limit) {
810
- this.params.logger.warn(`ClientExchange getNextCandles: Expected ${limit} candles, got ${filteredData.length}`);
821
+ // Apply distinct by timestamp to remove duplicates
822
+ const uniqueData = Array.from(new Map(filteredData.map((candle) => [candle.timestamp, candle])).values());
823
+ if (filteredData.length !== uniqueData.length) {
824
+ this.params.logger.warn(`ClientExchange getNextCandles: Removed ${filteredData.length - uniqueData.length} duplicate candles by timestamp`);
825
+ }
826
+ if (uniqueData.length < limit) {
827
+ this.params.logger.warn(`ClientExchange getNextCandles: Expected ${limit} candles, got ${uniqueData.length}`);
811
828
  }
812
- await CALL_CANDLE_DATA_CALLBACKS_FN(this, symbol, interval, since, limit, filteredData);
813
- return filteredData;
829
+ await CALL_CANDLE_DATA_CALLBACKS_FN(this, symbol, interval, since, limit, uniqueData);
830
+ return uniqueData;
814
831
  }
815
832
  /**
816
833
  * Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
@@ -3386,14 +3403,40 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
3386
3403
  await CALL_TICK_CALLBACKS_FN(self, self.params.execution.context.symbol, result, activationTime, self.params.execution.context.backtest);
3387
3404
  return result;
3388
3405
  };
3389
- const CALL_PING_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, scheduled, timestamp, backtest) => {
3406
+ const CALL_SCHEDULE_PING_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, scheduled, timestamp, backtest) => {
3390
3407
  await ExecutionContextService.runInContext(async () => {
3391
3408
  const publicSignal = TO_PUBLIC_SIGNAL(scheduled);
3392
- // Call system onPing callback first (emits to pingSubject)
3393
- await self.params.onPing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, publicSignal, self.params.execution.context.backtest, timestamp);
3394
- // Call user onPing callback only if signal is still active (not cancelled, not activated)
3395
- if (self.params.callbacks?.onPing) {
3396
- await self.params.callbacks.onPing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
3409
+ // Call system onSchedulePing callback first (emits to pingSubject)
3410
+ await self.params.onSchedulePing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, publicSignal, self.params.execution.context.backtest, timestamp);
3411
+ // Call user onSchedulePing callback only if signal is still active (not cancelled, not activated)
3412
+ if (self.params.callbacks?.onSchedulePing) {
3413
+ await self.params.callbacks.onSchedulePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
3414
+ }
3415
+ }, {
3416
+ when: new Date(timestamp),
3417
+ symbol: symbol,
3418
+ backtest: backtest,
3419
+ });
3420
+ }), {
3421
+ fallback: (error) => {
3422
+ const message = "ClientStrategy CALL_SCHEDULE_PING_CALLBACKS_FN thrown";
3423
+ const payload = {
3424
+ error: errorData(error),
3425
+ message: getErrorMessage(error),
3426
+ };
3427
+ backtest$1.loggerService.warn(message, payload);
3428
+ console.warn(message, payload);
3429
+ errorEmitter.next(error);
3430
+ },
3431
+ });
3432
+ const CALL_ACTIVE_PING_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, pending, timestamp, backtest) => {
3433
+ await ExecutionContextService.runInContext(async () => {
3434
+ const publicSignal = TO_PUBLIC_SIGNAL(pending);
3435
+ // Call system onActivePing callback first (emits to activePingSubject)
3436
+ await self.params.onActivePing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, publicSignal, self.params.execution.context.backtest, timestamp);
3437
+ // Call user onActivePing callback only if signal is still active (not closed)
3438
+ if (self.params.callbacks?.onActivePing) {
3439
+ await self.params.callbacks.onActivePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
3397
3440
  }
3398
3441
  }, {
3399
3442
  when: new Date(timestamp),
@@ -3402,7 +3445,7 @@ const CALL_PING_CALLBACKS_FN = trycatch(beginTime(async (self, symbol, scheduled
3402
3445
  });
3403
3446
  }), {
3404
3447
  fallback: (error) => {
3405
- const message = "ClientStrategy CALL_PING_CALLBACKS_FN thrown";
3448
+ const message = "ClientStrategy CALL_ACTIVE_PING_CALLBACKS_FN thrown";
3406
3449
  const payload = {
3407
3450
  error: errorData(error),
3408
3451
  message: getErrorMessage(error),
@@ -3774,10 +3817,10 @@ const CALL_BREAKEVEN_CLEAR_FN = trycatch(beginTime(async (self, symbol, signal,
3774
3817
  });
3775
3818
  const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
3776
3819
  const currentTime = self.params.execution.context.when.getTime();
3777
- await CALL_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentTime, self.params.execution.context.backtest);
3820
+ await CALL_SCHEDULE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentTime, self.params.execution.context.backtest);
3778
3821
  const pnl = toProfitLossDto(scheduled, currentPrice);
3779
3822
  const result = {
3780
- action: "active",
3823
+ action: "waiting",
3781
3824
  signal: TO_PUBLIC_SIGNAL(scheduled),
3782
3825
  currentPrice: currentPrice,
3783
3826
  strategyName: self.params.method.context.strategyName,
@@ -3904,6 +3947,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice) => {
3904
3947
  let percentTp = 0;
3905
3948
  let percentSl = 0;
3906
3949
  const currentTime = self.params.execution.context.when.getTime();
3950
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest);
3907
3951
  // Calculate percentage of path to TP/SL for partial fill/loss callbacks
3908
3952
  {
3909
3953
  if (signal.position === "long") {
@@ -4109,7 +4153,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
4109
4153
  const averagePrice = GET_AVG_PRICE_FN(recentCandles);
4110
4154
  // КРИТИЧНО: Проверяем был ли сигнал отменен пользователем через cancel()
4111
4155
  if (self._cancelledSignal) {
4112
- // Сигнал был отменен через cancel() в onPing
4156
+ // Сигнал был отменен через cancel() в onSchedulePing
4113
4157
  const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "user");
4114
4158
  return { activated: false, cancelled: true, activationIndex: i, result };
4115
4159
  }
@@ -4166,7 +4210,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
4166
4210
  result: null,
4167
4211
  };
4168
4212
  }
4169
- await CALL_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, candle.timestamp, true);
4213
+ await CALL_SCHEDULE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, candle.timestamp, true);
4170
4214
  }
4171
4215
  return {
4172
4216
  activated: false,
@@ -4192,6 +4236,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles) => {
4192
4236
  const startIndex = Math.max(0, i - (candlesCount - 1));
4193
4237
  const recentCandles = candles.slice(startIndex, i + 1);
4194
4238
  const averagePrice = GET_AVG_PRICE_FN(recentCandles);
4239
+ await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true);
4195
4240
  let shouldClose = false;
4196
4241
  let closeReason;
4197
4242
  // Check time expiration FIRST (КРИТИЧНО!)
@@ -4737,7 +4782,15 @@ class ClientStrategy {
4737
4782
  return result;
4738
4783
  }
4739
4784
  if (activated) {
4740
- const remainingCandles = candles.slice(activationIndex + 1);
4785
+ // КРИТИЧНО: activationIndex - индекс свечи активации в массиве candles
4786
+ // BacktestLogicPrivateService включил буфер в начало массива, поэтому перед activationIndex достаточно свечей
4787
+ // PROCESS_PENDING_SIGNAL_CANDLES_FN пропустит первые bufferCandlesCount свечей для VWAP
4788
+ // Чтобы обработка началась со СЛЕДУЮЩЕЙ свечи после активации (activationIndex + 1),
4789
+ // нужно взять срез начиная с (activationIndex + 1 - bufferCandlesCount)
4790
+ // Это даст буфер ИЗ scheduled фазы + свеча после активации как первая обрабатываемая
4791
+ const bufferCandlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT - 1;
4792
+ const sliceStart = Math.max(0, activationIndex + 1 - bufferCandlesCount);
4793
+ const remainingCandles = candles.slice(sliceStart);
4741
4794
  if (remainingCandles.length === 0) {
4742
4795
  const candlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT;
4743
4796
  const recentCandles = candles.slice(Math.max(0, activationIndex - (candlesCount - 1)), activationIndex + 1);
@@ -4753,35 +4806,23 @@ class ClientStrategy {
4753
4806
  const lastCandleTimestamp = candles[candles.length - 1].timestamp;
4754
4807
  const elapsedTime = lastCandleTimestamp - scheduled.scheduledAt;
4755
4808
  if (elapsedTime < maxTimeToWait) {
4756
- // Timeout NOT reached yet - signal is still active (waiting for price)
4757
- // Return active result to continue monitoring in next backtest() call
4758
- const candlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT;
4759
- const lastCandles = candles.slice(-candlesCount);
4760
- const lastPrice = GET_AVG_PRICE_FN(lastCandles);
4761
- this.params.logger.debug("ClientStrategy backtest scheduled signal still waiting (not expired)", {
4762
- symbol: this.params.execution.context.symbol,
4763
- signalId: scheduled.id,
4764
- elapsedMinutes: Math.floor(elapsedTime / 60000),
4765
- maxMinutes: GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES,
4766
- });
4767
- // Don't cancel - just return last active state
4768
- // In real backtest flow this won't happen as we process all candles at once,
4769
- // but this is correct behavior if someone calls backtest() with partial data
4770
- const pnl = toProfitLossDto(scheduled, lastPrice);
4771
- const result = {
4772
- action: "active",
4773
- signal: TO_PUBLIC_SIGNAL(scheduled),
4774
- currentPrice: lastPrice,
4775
- percentSl: 0,
4776
- percentTp: 0,
4777
- pnl,
4778
- strategyName: this.params.method.context.strategyName,
4779
- exchangeName: this.params.method.context.exchangeName,
4780
- frameName: this.params.method.context.frameName,
4781
- symbol: this.params.execution.context.symbol,
4782
- backtest: this.params.execution.context.backtest,
4783
- };
4784
- return result; // Cast to IStrategyBacktestResult (which includes Active)
4809
+ // EDGE CASE: backtest() called with partial candle data (should never happen in production)
4810
+ // In real backtest flow this won't happen as we process all candles at once
4811
+ // This indicates incorrect usage of backtest() - throw error instead of returning partial result
4812
+ const bufferCandlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT - 1;
4813
+ // For scheduled signal that has NOT activated: buffer + wait time only (no lifetime yet)
4814
+ const requiredCandlesCount = bufferCandlesCount + GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES + 1;
4815
+ throw new Error(str.newline(`ClientStrategy backtest: Insufficient candle data for scheduled signal (not yet activated). ` +
4816
+ `Signal scheduled at ${new Date(scheduled.scheduledAt).toISOString()}, ` +
4817
+ `last candle at ${new Date(lastCandleTimestamp).toISOString()}. ` +
4818
+ `Elapsed: ${Math.floor(elapsedTime / 60000)}min of ${GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES}min wait time. ` +
4819
+ `Provided ${candles.length} candles, but need at least ${requiredCandlesCount} candles. ` +
4820
+ `\nBreakdown: ` +
4821
+ `${bufferCandlesCount} buffer (VWAP) + ` +
4822
+ `${GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES} wait (for activation) = ${requiredCandlesCount} total. ` +
4823
+ `\nBuffer explanation: VWAP calculation requires ${GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT} candles, ` +
4824
+ `so first ${bufferCandlesCount} candles are skipped during scheduled phase processing. ` +
4825
+ `Provide complete candle range: [scheduledAt - ${bufferCandlesCount}min, scheduledAt + ${GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES}min].`));
4785
4826
  }
4786
4827
  // Timeout reached - cancel the scheduled signal
4787
4828
  const candlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT;
@@ -4811,9 +4852,29 @@ class ClientStrategy {
4811
4852
  if (closedResult) {
4812
4853
  return closedResult;
4813
4854
  }
4855
+ // Signal didn't close during candle processing - check if we have enough data
4814
4856
  const lastCandles = candles.slice(-GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT);
4815
4857
  const lastPrice = GET_AVG_PRICE_FN(lastCandles);
4816
4858
  const closeTimestamp = lastCandles[lastCandles.length - 1].timestamp;
4859
+ const signalTime = signal.pendingAt;
4860
+ const maxTimeToWait = signal.minuteEstimatedTime * 60 * 1000;
4861
+ const elapsedTime = closeTimestamp - signalTime;
4862
+ // Check if we actually reached time expiration or just ran out of candles
4863
+ if (elapsedTime < maxTimeToWait) {
4864
+ // EDGE CASE: backtest() called with insufficient candle data
4865
+ const bufferCandlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT - 1;
4866
+ const requiredCandlesCount = signal.minuteEstimatedTime + bufferCandlesCount + 1;
4867
+ throw new Error(str.newline(`ClientStrategy backtest: Insufficient candle data for pending signal. ` +
4868
+ `Signal opened at ${new Date(signal.pendingAt).toISOString()}, ` +
4869
+ `last candle at ${new Date(closeTimestamp).toISOString()}. ` +
4870
+ `Elapsed: ${Math.floor(elapsedTime / 60000)}min of ${signal.minuteEstimatedTime}min required. ` +
4871
+ `Provided ${candles.length} candles, but need at least ${requiredCandlesCount} candles. ` +
4872
+ `\nBreakdown: ${signal.minuteEstimatedTime} candles for signal lifetime + ${bufferCandlesCount} buffer candles. ` +
4873
+ `\nBuffer explanation: VWAP calculation requires ${GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT} candles, ` +
4874
+ `so first ${bufferCandlesCount} candles are skipped to ensure accurate price averaging. ` +
4875
+ `Provide complete candle range: [pendingAt - ${bufferCandlesCount}min, pendingAt + ${signal.minuteEstimatedTime}min].`));
4876
+ }
4877
+ // Time actually expired - close with time_expired
4817
4878
  return await CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN(this, signal, lastPrice, "time_expired", closeTimestamp);
4818
4879
  }
4819
4880
  /**
@@ -5602,6 +5663,9 @@ class ClientStrategy {
5602
5663
  const RISK_METHOD_NAME_GET_DATA = "RiskUtils.getData";
5603
5664
  const RISK_METHOD_NAME_GET_REPORT = "RiskUtils.getReport";
5604
5665
  const RISK_METHOD_NAME_DUMP = "RiskUtils.dump";
5666
+ const RISK_METHOD_NAME_CHECK_SIGNAL = "MergeRisk.checkSignal";
5667
+ const RISK_METHOD_NAME_ADD_SIGNAL = "MergeRisk.addSignal";
5668
+ const RISK_METHOD_NAME_REMOVE_SIGNAL = "MergeRisk.removeSignal";
5605
5669
  /**
5606
5670
  * Composite risk management class that combines multiple risk profiles.
5607
5671
  *
@@ -5657,7 +5721,7 @@ class MergeRisk {
5657
5721
  * @returns Promise resolving to true if all risks approve, false if any risk rejects
5658
5722
  */
5659
5723
  async checkSignal(params) {
5660
- backtest$1.loggerService.info("MergeRisk checkSignal", {
5724
+ backtest$1.loggerService.info(RISK_METHOD_NAME_CHECK_SIGNAL, {
5661
5725
  params,
5662
5726
  });
5663
5727
  for (const [riskName, risk] of Object.entries(this._riskMap)) {
@@ -5681,7 +5745,7 @@ class MergeRisk {
5681
5745
  * @returns Promise that resolves when all risks have registered the signal
5682
5746
  */
5683
5747
  async addSignal(symbol, context, positionData) {
5684
- backtest$1.loggerService.info("MergeRisk addSignal", {
5748
+ backtest$1.loggerService.info(RISK_METHOD_NAME_ADD_SIGNAL, {
5685
5749
  symbol,
5686
5750
  context,
5687
5751
  });
@@ -5698,7 +5762,7 @@ class MergeRisk {
5698
5762
  * @returns Promise that resolves when all risks have removed the signal
5699
5763
  */
5700
5764
  async removeSignal(symbol, context) {
5701
- backtest$1.loggerService.info("MergeRisk removeSignal", {
5765
+ backtest$1.loggerService.info(RISK_METHOD_NAME_REMOVE_SIGNAL, {
5702
5766
  symbol,
5703
5767
  context,
5704
5768
  });
@@ -5981,15 +6045,36 @@ const CREATE_KEY_FN$k = (symbol, strategyName, exchangeName, frameName, backtest
5981
6045
  return parts.join(":");
5982
6046
  };
5983
6047
  /**
5984
- * Creates a callback function for emitting ping events to pingSubject.
6048
+ * Creates a callback function for emitting schedule ping events to pingSubject.
5985
6049
  *
5986
6050
  * Called by ClientStrategy when a scheduled signal is being monitored every minute.
5987
6051
  * Emits PingContract event to all subscribers and calls ActionCoreService.
5988
6052
  *
5989
6053
  * @param self - Reference to StrategyConnectionService instance
5990
- * @returns Callback function for ping events
6054
+ * @returns Callback function for schedule ping events
6055
+ */
6056
+ const CREATE_COMMIT_SCHEDULE_PING_FN = (self) => async (symbol, strategyName, exchangeName, data, backtest, timestamp) => {
6057
+ const event = {
6058
+ symbol,
6059
+ strategyName,
6060
+ exchangeName,
6061
+ data,
6062
+ backtest,
6063
+ timestamp,
6064
+ };
6065
+ await schedulePingSubject.next(event);
6066
+ await self.actionCoreService.pingScheduled(backtest, event, { strategyName, exchangeName, frameName: data.frameName });
6067
+ };
6068
+ /**
6069
+ * Creates a callback function for emitting active ping events.
6070
+ *
6071
+ * Called by ClientStrategy when an active pending signal is being monitored every minute.
6072
+ * Placeholder for future activePingSubject implementation.
6073
+ *
6074
+ * @param self - Reference to StrategyConnectionService instance
6075
+ * @returns Callback function for active ping events
5991
6076
  */
5992
- const CREATE_COMMIT_PING_FN = (self) => async (symbol, strategyName, exchangeName, data, backtest, timestamp) => {
6077
+ const CREATE_COMMIT_ACTIVE_PING_FN = (self) => async (symbol, strategyName, exchangeName, data, backtest, timestamp) => {
5993
6078
  const event = {
5994
6079
  symbol,
5995
6080
  strategyName,
@@ -5998,8 +6083,8 @@ const CREATE_COMMIT_PING_FN = (self) => async (symbol, strategyName, exchangeNam
5998
6083
  backtest,
5999
6084
  timestamp,
6000
6085
  };
6001
- await pingSubject.next(event);
6002
- await self.actionCoreService.ping(backtest, event, { strategyName, exchangeName, frameName: data.frameName });
6086
+ await activePingSubject.next(event);
6087
+ await self.actionCoreService.pingActive(backtest, event, { strategyName, exchangeName, frameName: data.frameName });
6003
6088
  };
6004
6089
  /**
6005
6090
  * Creates a callback function for emitting init events.
@@ -6096,7 +6181,8 @@ class StrategyConnectionService {
6096
6181
  getSignal,
6097
6182
  callbacks,
6098
6183
  onInit: CREATE_COMMIT_INIT_FN(this),
6099
- onPing: CREATE_COMMIT_PING_FN(this),
6184
+ onSchedulePing: CREATE_COMMIT_SCHEDULE_PING_FN(this),
6185
+ onActivePing: CREATE_COMMIT_ACTIVE_PING_FN(this),
6100
6186
  onDispose: CREATE_COMMIT_DISPOSE_FN(this),
6101
6187
  });
6102
6188
  });
@@ -7489,8 +7575,8 @@ const CALL_SIGNAL_BACKTEST_CALLBACK_FN = trycatch(async (self, event, strategyNa
7489
7575
  });
7490
7576
  /** Wrapper to call breakeven callback with error handling */
7491
7577
  const CALL_BREAKEVEN_CALLBACK_FN = trycatch(async (self, event, strategyName, frameName, backtest) => {
7492
- if (self.params.callbacks?.onBreakeven) {
7493
- await self.params.callbacks.onBreakeven(event, self.params.actionName, strategyName, frameName, backtest);
7578
+ if (self.params.callbacks?.onBreakevenAvailable) {
7579
+ await self.params.callbacks.onBreakevenAvailable(event, self.params.actionName, strategyName, frameName, backtest);
7494
7580
  }
7495
7581
  }, {
7496
7582
  fallback: (error) => {
@@ -7506,8 +7592,8 @@ const CALL_BREAKEVEN_CALLBACK_FN = trycatch(async (self, event, strategyName, fr
7506
7592
  });
7507
7593
  /** Wrapper to call partialProfit callback with error handling */
7508
7594
  const CALL_PARTIAL_PROFIT_CALLBACK_FN = trycatch(async (self, event, strategyName, frameName, backtest) => {
7509
- if (self.params.callbacks?.onPartialProfit) {
7510
- await self.params.callbacks.onPartialProfit(event, self.params.actionName, strategyName, frameName, backtest);
7595
+ if (self.params.callbacks?.onPartialProfitAvailable) {
7596
+ await self.params.callbacks.onPartialProfitAvailable(event, self.params.actionName, strategyName, frameName, backtest);
7511
7597
  }
7512
7598
  }, {
7513
7599
  fallback: (error) => {
@@ -7523,8 +7609,8 @@ const CALL_PARTIAL_PROFIT_CALLBACK_FN = trycatch(async (self, event, strategyNam
7523
7609
  });
7524
7610
  /** Wrapper to call partialLoss callback with error handling */
7525
7611
  const CALL_PARTIAL_LOSS_CALLBACK_FN = trycatch(async (self, event, strategyName, frameName, backtest) => {
7526
- if (self.params.callbacks?.onPartialLoss) {
7527
- await self.params.callbacks.onPartialLoss(event, self.params.actionName, strategyName, frameName, backtest);
7612
+ if (self.params.callbacks?.onPartialLossAvailable) {
7613
+ await self.params.callbacks.onPartialLossAvailable(event, self.params.actionName, strategyName, frameName, backtest);
7528
7614
  }
7529
7615
  }, {
7530
7616
  fallback: (error) => {
@@ -7538,14 +7624,31 @@ const CALL_PARTIAL_LOSS_CALLBACK_FN = trycatch(async (self, event, strategyName,
7538
7624
  errorEmitter.next(error);
7539
7625
  },
7540
7626
  });
7541
- /** Wrapper to call ping callback with error handling */
7542
- const CALL_PING_CALLBACK_FN = trycatch(async (self, event, strategyName, frameName, backtest) => {
7543
- if (self.params.callbacks?.onPing) {
7544
- await self.params.callbacks.onPing(event, self.params.actionName, strategyName, frameName, backtest);
7627
+ /** Wrapper to call scheduled ping callback with error handling */
7628
+ const CALL_PING_SCHEDULED_CALLBACK_FN = trycatch(async (self, event, strategyName, frameName, backtest) => {
7629
+ if (self.params.callbacks?.onPingScheduled) {
7630
+ await self.params.callbacks.onPingScheduled(event, self.params.actionName, strategyName, frameName, backtest);
7631
+ }
7632
+ }, {
7633
+ fallback: (error) => {
7634
+ const message = "ClientAction CALL_PING_SCHEDULED_CALLBACK_FN thrown";
7635
+ const payload = {
7636
+ error: errorData(error),
7637
+ message: getErrorMessage(error),
7638
+ };
7639
+ backtest$1.loggerService.warn(message, payload);
7640
+ console.warn(message, payload);
7641
+ errorEmitter.next(error);
7642
+ },
7643
+ });
7644
+ /** Wrapper to call active ping callback with error handling */
7645
+ const CALL_PING_ACTIVE_CALLBACK_FN = trycatch(async (self, event, strategyName, frameName, backtest) => {
7646
+ if (self.params.callbacks?.onPingActive) {
7647
+ await self.params.callbacks.onPingActive(event, self.params.actionName, strategyName, frameName, backtest);
7545
7648
  }
7546
7649
  }, {
7547
7650
  fallback: (error) => {
7548
- const message = "ClientAction CALL_PING_CALLBACK_FN thrown";
7651
+ const message = "ClientAction CALL_PING_ACTIVE_CALLBACK_FN thrown";
7549
7652
  const payload = {
7550
7653
  error: errorData(error),
7551
7654
  message: getErrorMessage(error),
@@ -7620,6 +7723,7 @@ const CREATE_HANDLER_FN = (self) => {
7620
7723
  self.params.strategyName,
7621
7724
  self.params.frameName,
7622
7725
  self.params.actionName,
7726
+ self.params.backtest,
7623
7727
  ]);
7624
7728
  }
7625
7729
  return self.params.handler;
@@ -7811,8 +7915,8 @@ class ClientAction {
7811
7915
  /**
7812
7916
  * Handles breakeven events when stop-loss is moved to entry price.
7813
7917
  */
7814
- async breakeven(event) {
7815
- this.params.logger.debug("ClientAction breakeven", {
7918
+ async breakevenAvailable(event) {
7919
+ this.params.logger.debug("ClientAction breakevenAvailable", {
7816
7920
  actionName: this.params.actionName,
7817
7921
  strategyName: this.params.strategyName,
7818
7922
  frameName: this.params.frameName,
@@ -7821,8 +7925,8 @@ class ClientAction {
7821
7925
  await this.waitForInit();
7822
7926
  }
7823
7927
  // Call handler method if defined
7824
- if (this._handlerInstance?.breakeven) {
7825
- await this._handlerInstance.breakeven(event);
7928
+ if (this._handlerInstance?.breakevenAvailable) {
7929
+ await this._handlerInstance.breakevenAvailable(event);
7826
7930
  }
7827
7931
  // Call callback if defined
7828
7932
  await CALL_BREAKEVEN_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
@@ -7831,8 +7935,8 @@ class ClientAction {
7831
7935
  /**
7832
7936
  * Handles partial profit level events (10%, 20%, 30%, etc).
7833
7937
  */
7834
- async partialProfit(event) {
7835
- this.params.logger.debug("ClientAction partialProfit", {
7938
+ async partialProfitAvailable(event) {
7939
+ this.params.logger.debug("ClientAction partialProfitAvailable", {
7836
7940
  actionName: this.params.actionName,
7837
7941
  strategyName: this.params.strategyName,
7838
7942
  frameName: this.params.frameName,
@@ -7841,8 +7945,8 @@ class ClientAction {
7841
7945
  await this.waitForInit();
7842
7946
  }
7843
7947
  // Call handler method if defined
7844
- if (this._handlerInstance?.partialProfit) {
7845
- await this._handlerInstance.partialProfit(event);
7948
+ if (this._handlerInstance?.partialProfitAvailable) {
7949
+ await this._handlerInstance.partialProfitAvailable(event);
7846
7950
  }
7847
7951
  // Call callback if defined
7848
7952
  await CALL_PARTIAL_PROFIT_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
@@ -7851,8 +7955,8 @@ class ClientAction {
7851
7955
  /**
7852
7956
  * Handles partial loss level events (-10%, -20%, -30%, etc).
7853
7957
  */
7854
- async partialLoss(event) {
7855
- this.params.logger.debug("ClientAction partialLoss", {
7958
+ async partialLossAvailable(event) {
7959
+ this.params.logger.debug("ClientAction partialLossAvailable", {
7856
7960
  actionName: this.params.actionName,
7857
7961
  strategyName: this.params.strategyName,
7858
7962
  frameName: this.params.frameName,
@@ -7861,18 +7965,38 @@ class ClientAction {
7861
7965
  await this.waitForInit();
7862
7966
  }
7863
7967
  // Call handler method if defined
7864
- if (this._handlerInstance?.partialLoss) {
7865
- await this._handlerInstance.partialLoss(event);
7968
+ if (this._handlerInstance?.partialLossAvailable) {
7969
+ await this._handlerInstance.partialLossAvailable(event);
7866
7970
  }
7867
7971
  // Call callback if defined
7868
7972
  await CALL_PARTIAL_LOSS_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
7869
7973
  }
7870
7974
  ;
7871
7975
  /**
7872
- * Handles ping events during scheduled signal monitoring.
7976
+ * Handles scheduled ping events during scheduled signal monitoring.
7977
+ */
7978
+ async pingScheduled(event) {
7979
+ this.params.logger.debug("ClientAction pingScheduled", {
7980
+ actionName: this.params.actionName,
7981
+ strategyName: this.params.strategyName,
7982
+ frameName: this.params.frameName,
7983
+ });
7984
+ if (!this._handlerInstance) {
7985
+ await this.waitForInit();
7986
+ }
7987
+ // Call handler method if defined
7988
+ if (this._handlerInstance?.pingScheduled) {
7989
+ await this._handlerInstance.pingScheduled(event);
7990
+ }
7991
+ // Call callback if defined
7992
+ await CALL_PING_SCHEDULED_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
7993
+ }
7994
+ ;
7995
+ /**
7996
+ * Handles active ping events during active pending signal monitoring.
7873
7997
  */
7874
- async ping(event) {
7875
- this.params.logger.debug("ClientAction ping", {
7998
+ async pingActive(event) {
7999
+ this.params.logger.debug("ClientAction pingActive", {
7876
8000
  actionName: this.params.actionName,
7877
8001
  strategyName: this.params.strategyName,
7878
8002
  frameName: this.params.frameName,
@@ -7881,11 +8005,11 @@ class ClientAction {
7881
8005
  await this.waitForInit();
7882
8006
  }
7883
8007
  // Call handler method if defined
7884
- if (this._handlerInstance?.ping) {
7885
- await this._handlerInstance.ping(event);
8008
+ if (this._handlerInstance?.pingActive) {
8009
+ await this._handlerInstance.pingActive(event);
7886
8010
  }
7887
8011
  // Call callback if defined
7888
- await CALL_PING_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
8012
+ await CALL_PING_ACTIVE_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
7889
8013
  }
7890
8014
  ;
7891
8015
  /**
@@ -8053,13 +8177,13 @@ class ActionConnectionService {
8053
8177
  * @param backtest - Whether running in backtest mode
8054
8178
  * @param context - Execution context with action name, strategy name, exchange name, frame name
8055
8179
  */
8056
- this.breakeven = async (event, backtest, context) => {
8057
- this.loggerService.log("actionConnectionService breakeven", {
8180
+ this.breakevenAvailable = async (event, backtest, context) => {
8181
+ this.loggerService.log("actionConnectionService breakevenAvailable", {
8058
8182
  backtest,
8059
8183
  context,
8060
8184
  });
8061
8185
  const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
8062
- await action.breakeven(event);
8186
+ await action.breakevenAvailable(event);
8063
8187
  };
8064
8188
  /**
8065
8189
  * Routes partialProfit event to appropriate ClientAction instance.
@@ -8068,13 +8192,13 @@ class ActionConnectionService {
8068
8192
  * @param backtest - Whether running in backtest mode
8069
8193
  * @param context - Execution context with action name, strategy name, exchange name, frame name
8070
8194
  */
8071
- this.partialProfit = async (event, backtest, context) => {
8072
- this.loggerService.log("actionConnectionService partialProfit", {
8195
+ this.partialProfitAvailable = async (event, backtest, context) => {
8196
+ this.loggerService.log("actionConnectionService partialProfitAvailable", {
8073
8197
  backtest,
8074
8198
  context,
8075
8199
  });
8076
8200
  const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
8077
- await action.partialProfit(event);
8201
+ await action.partialProfitAvailable(event);
8078
8202
  };
8079
8203
  /**
8080
8204
  * Routes partialLoss event to appropriate ClientAction instance.
@@ -8083,28 +8207,43 @@ class ActionConnectionService {
8083
8207
  * @param backtest - Whether running in backtest mode
8084
8208
  * @param context - Execution context with action name, strategy name, exchange name, frame name
8085
8209
  */
8086
- this.partialLoss = async (event, backtest, context) => {
8087
- this.loggerService.log("actionConnectionService partialLoss", {
8210
+ this.partialLossAvailable = async (event, backtest, context) => {
8211
+ this.loggerService.log("actionConnectionService partialLossAvailable", {
8212
+ backtest,
8213
+ context,
8214
+ });
8215
+ const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
8216
+ await action.partialLossAvailable(event);
8217
+ };
8218
+ /**
8219
+ * Routes scheduled ping event to appropriate ClientAction instance.
8220
+ *
8221
+ * @param event - Scheduled ping event data
8222
+ * @param backtest - Whether running in backtest mode
8223
+ * @param context - Execution context with action name, strategy name, exchange name, frame name
8224
+ */
8225
+ this.pingScheduled = async (event, backtest, context) => {
8226
+ this.loggerService.log("actionConnectionService pingScheduled", {
8088
8227
  backtest,
8089
8228
  context,
8090
8229
  });
8091
8230
  const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
8092
- await action.partialLoss(event);
8231
+ await action.pingScheduled(event);
8093
8232
  };
8094
8233
  /**
8095
- * Routes ping event to appropriate ClientAction instance.
8234
+ * Routes active ping event to appropriate ClientAction instance.
8096
8235
  *
8097
- * @param event - Ping event data
8236
+ * @param event - Active ping event data
8098
8237
  * @param backtest - Whether running in backtest mode
8099
8238
  * @param context - Execution context with action name, strategy name, exchange name, frame name
8100
8239
  */
8101
- this.ping = async (event, backtest, context) => {
8102
- this.loggerService.log("actionConnectionService ping", {
8240
+ this.pingActive = async (event, backtest, context) => {
8241
+ this.loggerService.log("actionConnectionService pingActive", {
8103
8242
  backtest,
8104
8243
  context,
8105
8244
  });
8106
8245
  const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
8107
- await action.ping(event);
8246
+ await action.pingActive(event);
8108
8247
  };
8109
8248
  /**
8110
8249
  * Routes riskRejection event to appropriate ClientAction instance.
@@ -9168,81 +9307,102 @@ class ActionCoreService {
9168
9307
  * Routes breakeven event to all registered actions for the strategy.
9169
9308
  *
9170
9309
  * Retrieves action list from strategy schema (IStrategySchema.actions)
9171
- * and invokes the breakeven handler on each ClientAction instance sequentially.
9310
+ * and invokes the breakevenAvailable handler on each ClientAction instance sequentially.
9172
9311
  *
9173
9312
  * @param backtest - Whether running in backtest mode (true) or live mode (false)
9174
9313
  * @param event - Breakeven milestone data (stop-loss moved to entry price)
9175
9314
  * @param context - Strategy execution context with strategyName, exchangeName, frameName
9176
9315
  */
9177
- this.breakeven = async (backtest, event, context) => {
9178
- this.loggerService.log("actionCoreService breakeven", {
9316
+ this.breakevenAvailable = async (backtest, event, context) => {
9317
+ this.loggerService.log("actionCoreService breakevenAvailable", {
9179
9318
  context,
9180
9319
  });
9181
9320
  await this.validate(context);
9182
9321
  const { actions = [] } = this.strategySchemaService.get(context.strategyName);
9183
9322
  for (const actionName of actions) {
9184
- await this.actionConnectionService.breakeven(event, backtest, { actionName, ...context });
9323
+ await this.actionConnectionService.breakevenAvailable(event, backtest, { actionName, ...context });
9185
9324
  }
9186
9325
  };
9187
9326
  /**
9188
9327
  * Routes partial profit event to all registered actions for the strategy.
9189
9328
  *
9190
9329
  * Retrieves action list from strategy schema (IStrategySchema.actions)
9191
- * and invokes the partialProfit handler on each ClientAction instance sequentially.
9330
+ * and invokes the partialProfitAvailable handler on each ClientAction instance sequentially.
9192
9331
  *
9193
9332
  * @param backtest - Whether running in backtest mode (true) or live mode (false)
9194
9333
  * @param event - Profit milestone data with level (10%, 20%, etc.) and price
9195
9334
  * @param context - Strategy execution context with strategyName, exchangeName, frameName
9196
9335
  */
9197
- this.partialProfit = async (backtest, event, context) => {
9198
- this.loggerService.log("actionCoreService partialProfit", {
9336
+ this.partialProfitAvailable = async (backtest, event, context) => {
9337
+ this.loggerService.log("actionCoreService partialProfitAvailable", {
9199
9338
  context,
9200
9339
  });
9201
9340
  await this.validate(context);
9202
9341
  const { actions = [] } = this.strategySchemaService.get(context.strategyName);
9203
9342
  for (const actionName of actions) {
9204
- await this.actionConnectionService.partialProfit(event, backtest, { actionName, ...context });
9343
+ await this.actionConnectionService.partialProfitAvailable(event, backtest, { actionName, ...context });
9205
9344
  }
9206
9345
  };
9207
9346
  /**
9208
9347
  * Routes partial loss event to all registered actions for the strategy.
9209
9348
  *
9210
9349
  * Retrieves action list from strategy schema (IStrategySchema.actions)
9211
- * and invokes the partialLoss handler on each ClientAction instance sequentially.
9350
+ * and invokes the partialLossAvailable handler on each ClientAction instance sequentially.
9212
9351
  *
9213
9352
  * @param backtest - Whether running in backtest mode (true) or live mode (false)
9214
9353
  * @param event - Loss milestone data with level (-10%, -20%, etc.) and price
9215
9354
  * @param context - Strategy execution context with strategyName, exchangeName, frameName
9216
9355
  */
9217
- this.partialLoss = async (backtest, event, context) => {
9218
- this.loggerService.log("actionCoreService partialLoss", {
9356
+ this.partialLossAvailable = async (backtest, event, context) => {
9357
+ this.loggerService.log("actionCoreService partialLossAvailable", {
9219
9358
  context,
9220
9359
  });
9221
9360
  await this.validate(context);
9222
9361
  const { actions = [] } = this.strategySchemaService.get(context.strategyName);
9223
9362
  for (const actionName of actions) {
9224
- await this.actionConnectionService.partialLoss(event, backtest, { actionName, ...context });
9363
+ await this.actionConnectionService.partialLossAvailable(event, backtest, { actionName, ...context });
9225
9364
  }
9226
9365
  };
9227
9366
  /**
9228
- * Routes ping event to all registered actions for the strategy.
9367
+ * Routes scheduled ping event to all registered actions for the strategy.
9229
9368
  *
9230
9369
  * Retrieves action list from strategy schema (IStrategySchema.actions)
9231
- * and invokes the ping handler on each ClientAction instance sequentially.
9370
+ * and invokes the pingScheduled handler on each ClientAction instance sequentially.
9232
9371
  * Called every minute during scheduled signal monitoring.
9233
9372
  *
9234
9373
  * @param backtest - Whether running in backtest mode (true) or live mode (false)
9235
9374
  * @param event - Scheduled signal monitoring data
9236
9375
  * @param context - Strategy execution context with strategyName, exchangeName, frameName
9237
9376
  */
9238
- this.ping = async (backtest, event, context) => {
9239
- this.loggerService.log("actionCoreService ping", {
9377
+ this.pingScheduled = async (backtest, event, context) => {
9378
+ this.loggerService.log("actionCoreService pingScheduled", {
9379
+ context,
9380
+ });
9381
+ await this.validate(context);
9382
+ const { actions = [] } = this.strategySchemaService.get(context.strategyName);
9383
+ for (const actionName of actions) {
9384
+ await this.actionConnectionService.pingScheduled(event, backtest, { actionName, ...context });
9385
+ }
9386
+ };
9387
+ /**
9388
+ * Routes active ping event to all registered actions for the strategy.
9389
+ *
9390
+ * Retrieves action list from strategy schema (IStrategySchema.actions)
9391
+ * and invokes the pingActive handler on each ClientAction instance sequentially.
9392
+ * Called every minute during active pending signal monitoring.
9393
+ *
9394
+ * @param backtest - Whether running in backtest mode (true) or live mode (false)
9395
+ * @param event - Active pending signal monitoring data
9396
+ * @param context - Strategy execution context with strategyName, exchangeName, frameName
9397
+ */
9398
+ this.pingActive = async (backtest, event, context) => {
9399
+ this.loggerService.log("actionCoreService pingActive", {
9240
9400
  context,
9241
9401
  });
9242
9402
  await this.validate(context);
9243
9403
  const { actions = [] } = this.strategySchemaService.get(context.strategyName);
9244
9404
  for (const actionName of actions) {
9245
- await this.actionConnectionService.ping(event, backtest, { actionName, ...context });
9405
+ await this.actionConnectionService.pingActive(event, backtest, { actionName, ...context });
9246
9406
  }
9247
9407
  };
9248
9408
  /**
@@ -10361,7 +10521,11 @@ class LiveLogicPrivateService {
10361
10521
  await sleep(TICK_TTL);
10362
10522
  continue;
10363
10523
  }
10364
- // Yield opened, closed results
10524
+ if (result.action === "waiting") {
10525
+ await sleep(TICK_TTL);
10526
+ continue;
10527
+ }
10528
+ // Yield opened, closed, cancelled results
10365
10529
  yield result;
10366
10530
  // Check if strategy should stop after signal is closed
10367
10531
  if (result.action === "closed") {
@@ -12296,6 +12460,12 @@ var _a$1, _b$1;
12296
12460
  const MARKDOWN_METHOD_NAME_ENABLE = "MarkdownUtils.enable";
12297
12461
  const MARKDOWN_METHOD_NAME_DISABLE = "MarkdownUtils.disable";
12298
12462
  const MARKDOWN_METHOD_NAME_USE_ADAPTER = "MarkdownAdapter.useMarkdownAdapter";
12463
+ const MARKDOWN_METHOD_NAME_FILE_DUMP = "MarkdownFileAdapter.dump";
12464
+ const MARKDOWN_METHOD_NAME_FOLDER_DUMP = "MarkdownFolderAdapter.dump";
12465
+ const MARKDOWN_METHOD_NAME_WRITE_DATA = "MarkdownAdapter.writeData";
12466
+ const MARKDOWN_METHOD_NAME_USE_MD = "MarkdownAdapter.useMd";
12467
+ const MARKDOWN_METHOD_NAME_USE_JSONL = "MarkdownAdapter.useJsonl";
12468
+ const MARKDOWN_METHOD_NAME_USE_DUMMY = "MarkdownAdapter.useDummy";
12299
12469
  const WAIT_FOR_INIT_SYMBOL$1 = Symbol("wait-for-init");
12300
12470
  const WRITE_SAFE_SYMBOL$1 = Symbol("write-safe");
12301
12471
  /**
@@ -12389,7 +12559,7 @@ class MarkdownFileBase {
12389
12559
  * @throws Error if stream not initialized or write timeout exceeded
12390
12560
  */
12391
12561
  async dump(data, options) {
12392
- backtest$1.loggerService.debug("MarkdownFileAdapter.dump", {
12562
+ backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_FILE_DUMP, {
12393
12563
  markdownName: this.markdownName,
12394
12564
  options,
12395
12565
  });
@@ -12471,7 +12641,7 @@ class MarkdownFolderBase {
12471
12641
  * @throws Error if directory creation or file write fails
12472
12642
  */
12473
12643
  async dump(content, options) {
12474
- backtest$1.loggerService.debug("MarkdownFolderAdapter.dump", {
12644
+ backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_FOLDER_DUMP, {
12475
12645
  markdownName: this.markdownName,
12476
12646
  options,
12477
12647
  });
@@ -12711,7 +12881,7 @@ class MarkdownAdapter extends MarkdownUtils {
12711
12881
  * @internal - Use service-specific dump methods instead (e.g., Backtest.dump)
12712
12882
  */
12713
12883
  async writeData(markdownName, content, options) {
12714
- backtest$1.loggerService.debug("MarkdownAdapter.writeData", {
12884
+ backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_WRITE_DATA, {
12715
12885
  markdownName,
12716
12886
  options,
12717
12887
  });
@@ -12726,7 +12896,7 @@ class MarkdownAdapter extends MarkdownUtils {
12726
12896
  * Each dump creates a separate .md file.
12727
12897
  */
12728
12898
  useMd() {
12729
- backtest$1.loggerService.debug("MarkdownAdapter.useMd");
12899
+ backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_USE_MD);
12730
12900
  this.useMarkdownAdapter(MarkdownFolderBase);
12731
12901
  }
12732
12902
  /**
@@ -12735,7 +12905,7 @@ class MarkdownAdapter extends MarkdownUtils {
12735
12905
  * All dumps append to a single .jsonl file per markdown type.
12736
12906
  */
12737
12907
  useJsonl() {
12738
- backtest$1.loggerService.debug("MarkdownAdapter.useJsonl");
12908
+ backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_USE_JSONL);
12739
12909
  this.useMarkdownAdapter(MarkdownFileBase);
12740
12910
  }
12741
12911
  /**
@@ -12743,7 +12913,7 @@ class MarkdownAdapter extends MarkdownUtils {
12743
12913
  * All future markdown writes will be no-ops.
12744
12914
  */
12745
12915
  useDummy() {
12746
- backtest$1.loggerService.debug("MarkdownAdapter.useDummy");
12916
+ backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_USE_DUMMY);
12747
12917
  this.useMarkdownAdapter(MarkdownDummy);
12748
12918
  }
12749
12919
  }
@@ -13406,6 +13576,98 @@ let ReportStorage$5 = class ReportStorage {
13406
13576
  this._eventList.pop();
13407
13577
  }
13408
13578
  }
13579
+ /**
13580
+ * Adds a scheduled event to the storage.
13581
+ *
13582
+ * @param data - Scheduled tick result
13583
+ */
13584
+ addScheduledEvent(data) {
13585
+ this._eventList.unshift({
13586
+ timestamp: data.signal.scheduledAt,
13587
+ action: "scheduled",
13588
+ symbol: data.signal.symbol,
13589
+ signalId: data.signal.id,
13590
+ position: data.signal.position,
13591
+ note: data.signal.note,
13592
+ currentPrice: data.currentPrice,
13593
+ priceOpen: data.signal.priceOpen,
13594
+ priceTakeProfit: data.signal.priceTakeProfit,
13595
+ priceStopLoss: data.signal.priceStopLoss,
13596
+ originalPriceTakeProfit: data.signal.originalPriceTakeProfit,
13597
+ originalPriceStopLoss: data.signal.originalPriceStopLoss,
13598
+ totalExecuted: data.signal.totalExecuted,
13599
+ });
13600
+ // Trim queue if exceeded MAX_EVENTS
13601
+ if (this._eventList.length > MAX_EVENTS$6) {
13602
+ this._eventList.pop();
13603
+ }
13604
+ }
13605
+ /**
13606
+ * Adds a waiting event to the storage.
13607
+ * Replaces the last waiting event with the same signalId.
13608
+ *
13609
+ * @param data - Waiting tick result
13610
+ */
13611
+ addWaitingEvent(data) {
13612
+ const newEvent = {
13613
+ timestamp: Date.now(),
13614
+ action: "waiting",
13615
+ symbol: data.signal.symbol,
13616
+ signalId: data.signal.id,
13617
+ position: data.signal.position,
13618
+ note: data.signal.note,
13619
+ currentPrice: data.currentPrice,
13620
+ priceOpen: data.signal.priceOpen,
13621
+ priceTakeProfit: data.signal.priceTakeProfit,
13622
+ priceStopLoss: data.signal.priceStopLoss,
13623
+ originalPriceTakeProfit: data.signal.originalPriceTakeProfit,
13624
+ originalPriceStopLoss: data.signal.originalPriceStopLoss,
13625
+ totalExecuted: data.signal.totalExecuted,
13626
+ percentTp: data.percentTp,
13627
+ percentSl: data.percentSl,
13628
+ pnl: data.pnl.pnlPercentage,
13629
+ };
13630
+ // Find the last waiting event with the same signalId
13631
+ const lastWaitingIndex = this._eventList.findLastIndex((event) => event.action === "waiting" && event.signalId === data.signal.id);
13632
+ // Replace the last waiting event with the same signalId
13633
+ if (lastWaitingIndex !== -1) {
13634
+ this._eventList[lastWaitingIndex] = newEvent;
13635
+ return;
13636
+ }
13637
+ // If no previous waiting event found, add new event
13638
+ this._eventList.unshift(newEvent);
13639
+ // Trim queue if exceeded MAX_EVENTS
13640
+ if (this._eventList.length > MAX_EVENTS$6) {
13641
+ this._eventList.pop();
13642
+ }
13643
+ }
13644
+ /**
13645
+ * Adds a cancelled event to the storage.
13646
+ *
13647
+ * @param data - Cancelled tick result
13648
+ */
13649
+ addCancelledEvent(data) {
13650
+ this._eventList.unshift({
13651
+ timestamp: data.closeTimestamp,
13652
+ action: "cancelled",
13653
+ symbol: data.signal.symbol,
13654
+ signalId: data.signal.id,
13655
+ position: data.signal.position,
13656
+ note: data.signal.note,
13657
+ currentPrice: data.currentPrice,
13658
+ priceOpen: data.signal.priceOpen,
13659
+ priceTakeProfit: data.signal.priceTakeProfit,
13660
+ priceStopLoss: data.signal.priceStopLoss,
13661
+ originalPriceTakeProfit: data.signal.originalPriceTakeProfit,
13662
+ originalPriceStopLoss: data.signal.originalPriceStopLoss,
13663
+ totalExecuted: data.signal.totalExecuted,
13664
+ cancelReason: data.reason,
13665
+ });
13666
+ // Trim queue if exceeded MAX_EVENTS
13667
+ if (this._eventList.length > MAX_EVENTS$6) {
13668
+ this._eventList.pop();
13669
+ }
13670
+ }
13409
13671
  /**
13410
13672
  * Calculates statistical data from live trading events (Controller).
13411
13673
  * Returns null for any unsafe numeric values (NaN, Infinity, etc).
@@ -13663,6 +13925,12 @@ class LiveMarkdownService {
13663
13925
  if (data.action === "idle") {
13664
13926
  storage.addIdleEvent(data.currentPrice);
13665
13927
  }
13928
+ else if (data.action === "scheduled") {
13929
+ storage.addScheduledEvent(data);
13930
+ }
13931
+ else if (data.action === "waiting") {
13932
+ storage.addWaitingEvent(data);
13933
+ }
13666
13934
  else if (data.action === "opened") {
13667
13935
  storage.addOpenedEvent(data);
13668
13936
  }
@@ -13672,6 +13940,9 @@ class LiveMarkdownService {
13672
13940
  else if (data.action === "closed") {
13673
13941
  storage.addClosedEvent(data);
13674
13942
  }
13943
+ else if (data.action === "cancelled") {
13944
+ storage.addCancelledEvent(data);
13945
+ }
13675
13946
  };
13676
13947
  /**
13677
13948
  * Gets statistical data from all live trading events for a symbol-strategy pair.
@@ -18098,7 +18369,7 @@ const CREATE_COMMIT_PROFIT_FN = (self) => async (symbol, strategyName, exchangeN
18098
18369
  timestamp,
18099
18370
  };
18100
18371
  await partialProfitSubject.next(event);
18101
- await self.actionCoreService.partialProfit(backtest, event, { strategyName, exchangeName, frameName });
18372
+ await self.actionCoreService.partialProfitAvailable(backtest, event, { strategyName, exchangeName, frameName });
18102
18373
  };
18103
18374
  /**
18104
18375
  * Creates a callback function for emitting loss events to partialLossSubject.
@@ -18122,7 +18393,7 @@ const CREATE_COMMIT_LOSS_FN = (self) => async (symbol, strategyName, exchangeNam
18122
18393
  timestamp,
18123
18394
  };
18124
18395
  await partialLossSubject.next(event);
18125
- await self.actionCoreService.partialLoss(backtest, event, { strategyName, exchangeName, frameName });
18396
+ await self.actionCoreService.partialLossAvailable(backtest, event, { strategyName, exchangeName, frameName });
18126
18397
  };
18127
18398
  /**
18128
18399
  * Connection service for partial profit/loss tracking.
@@ -19271,7 +19542,7 @@ const CREATE_COMMIT_BREAKEVEN_FN = (self) => async (symbol, strategyName, exchan
19271
19542
  timestamp,
19272
19543
  };
19273
19544
  await breakevenSubject.next(event);
19274
- await self.actionCoreService.breakeven(backtest, event, { strategyName, exchangeName, frameName });
19545
+ await self.actionCoreService.breakevenAvailable(backtest, event, { strategyName, exchangeName, frameName });
19275
19546
  };
19276
19547
  /**
19277
19548
  * Connection service for breakeven tracking.
@@ -21356,6 +21627,43 @@ class LiveReportService {
21356
21627
  if (data.action === "idle") {
21357
21628
  await Report.writeData("live", baseEvent, searchOptions);
21358
21629
  }
21630
+ else if (data.action === "scheduled") {
21631
+ await Report.writeData("live", {
21632
+ ...baseEvent,
21633
+ signalId: data.signal?.id,
21634
+ position: data.signal?.position,
21635
+ note: data.signal?.note,
21636
+ priceOpen: data.signal?.priceOpen,
21637
+ priceTakeProfit: data.signal?.priceTakeProfit,
21638
+ priceStopLoss: data.signal?.priceStopLoss,
21639
+ originalPriceTakeProfit: data.signal?.originalPriceTakeProfit,
21640
+ originalPriceStopLoss: data.signal?.originalPriceStopLoss,
21641
+ totalExecuted: data.signal?.totalExecuted,
21642
+ scheduledAt: data.signal?.scheduledAt,
21643
+ minuteEstimatedTime: data.signal?.minuteEstimatedTime,
21644
+ }, { ...searchOptions, signalId: data.signal?.id });
21645
+ }
21646
+ else if (data.action === "waiting") {
21647
+ await Report.writeData("live", {
21648
+ ...baseEvent,
21649
+ signalId: data.signal?.id,
21650
+ position: data.signal?.position,
21651
+ note: data.signal?.note,
21652
+ priceOpen: data.signal?.priceOpen,
21653
+ priceTakeProfit: data.signal?.priceTakeProfit,
21654
+ priceStopLoss: data.signal?.priceStopLoss,
21655
+ originalPriceTakeProfit: data.signal?.originalPriceTakeProfit,
21656
+ originalPriceStopLoss: data.signal?.originalPriceStopLoss,
21657
+ totalExecuted: data.signal?.totalExecuted,
21658
+ scheduledAt: data.signal?.scheduledAt,
21659
+ minuteEstimatedTime: data.signal?.minuteEstimatedTime,
21660
+ percentTp: data.percentTp,
21661
+ percentSl: data.percentSl,
21662
+ pnl: data.pnl.pnlPercentage,
21663
+ pnlPriceOpen: data.pnl.priceOpen,
21664
+ pnlPriceClose: data.pnl.priceClose,
21665
+ }, { ...searchOptions, signalId: data.signal?.id });
21666
+ }
21359
21667
  else if (data.action === "opened") {
21360
21668
  await Report.writeData("live", {
21361
21669
  ...baseEvent,
@@ -21422,6 +21730,24 @@ class LiveReportService {
21422
21730
  closeTime: data.closeTimestamp,
21423
21731
  }, { ...searchOptions, signalId: data.signal?.id });
21424
21732
  }
21733
+ else if (data.action === "cancelled") {
21734
+ await Report.writeData("live", {
21735
+ ...baseEvent,
21736
+ signalId: data.signal?.id,
21737
+ position: data.signal?.position,
21738
+ note: data.signal?.note,
21739
+ priceOpen: data.signal?.priceOpen,
21740
+ priceTakeProfit: data.signal?.priceTakeProfit,
21741
+ priceStopLoss: data.signal?.priceStopLoss,
21742
+ originalPriceTakeProfit: data.signal?.originalPriceTakeProfit,
21743
+ originalPriceStopLoss: data.signal?.originalPriceStopLoss,
21744
+ totalExecuted: data.signal?.totalExecuted,
21745
+ scheduledAt: data.signal?.scheduledAt,
21746
+ minuteEstimatedTime: data.signal?.minuteEstimatedTime,
21747
+ cancelReason: data.reason,
21748
+ closeTime: data.closeTimestamp,
21749
+ }, { ...searchOptions, signalId: data.signal?.id });
21750
+ }
21425
21751
  };
21426
21752
  /**
21427
21753
  * Subscribes to live signal emitter to receive tick events.
@@ -22611,6 +22937,27 @@ const backtest = {
22611
22937
  init();
22612
22938
  var backtest$1 = backtest;
22613
22939
 
22940
+ const GET_TIMEFRAME_METHOD_NAME = "get.getBacktestTimeframe";
22941
+ /**
22942
+ * Retrieves current backtest timeframe for given symbol.
22943
+ * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
22944
+ * @returns Promise resolving to array of Date objects representing tick timestamps
22945
+ * @throws Error if called outside of backtest execution context
22946
+ */
22947
+ async function getBacktestTimeframe(symbol) {
22948
+ backtest$1.loggerService.info(GET_TIMEFRAME_METHOD_NAME, { symbol });
22949
+ if (!ExecutionContextService.hasContext()) {
22950
+ throw new Error("getBacktestTimeframe requires an execution context");
22951
+ }
22952
+ if (!MethodContextService.hasContext()) {
22953
+ throw new Error("getBacktestTimeframe requires a method context");
22954
+ }
22955
+ if (!backtest$1.executionContextService.context.backtest) {
22956
+ throw new Error("getBacktestTimeframe can only be used during backtest execution");
22957
+ }
22958
+ return await backtest$1.frameCoreService.getTimeframe(symbol, backtest$1.methodContextService.context.frameName);
22959
+ }
22960
+
22614
22961
  const METHOD_NAME = "validate.validate";
22615
22962
  /**
22616
22963
  * Retrieves all registered exchanges as a map
@@ -22806,12 +23153,197 @@ async function validate(args = {}) {
22806
23153
  return await validateInternal(args);
22807
23154
  }
22808
23155
 
23156
+ const GET_STRATEGY_METHOD_NAME = "get.getStrategySchema";
23157
+ const GET_EXCHANGE_METHOD_NAME = "get.getExchangeSchema";
23158
+ const GET_FRAME_METHOD_NAME = "get.getFrameSchema";
23159
+ const GET_WALKER_METHOD_NAME = "get.getWalkerSchema";
23160
+ const GET_SIZING_METHOD_NAME = "get.getSizingSchema";
23161
+ const GET_RISK_METHOD_NAME = "get.getRiskSchema";
23162
+ const GET_OPTIMIZER_METHOD_NAME = "get.getOptimizerSchema";
23163
+ const GET_ACTION_METHOD_NAME = "get.getActionSchema";
23164
+ /**
23165
+ * Retrieves a registered strategy schema by name.
23166
+ *
23167
+ * @param strategyName - Unique strategy identifier
23168
+ * @returns The strategy schema configuration object
23169
+ * @throws Error if strategy is not registered
23170
+ *
23171
+ * @example
23172
+ * ```typescript
23173
+ * const strategy = getStrategy("my-strategy");
23174
+ * console.log(strategy.interval); // "5m"
23175
+ * console.log(strategy.getSignal); // async function
23176
+ * ```
23177
+ */
23178
+ function getStrategySchema(strategyName) {
23179
+ backtest$1.loggerService.log(GET_STRATEGY_METHOD_NAME, {
23180
+ strategyName,
23181
+ });
23182
+ backtest$1.strategyValidationService.validate(strategyName, GET_STRATEGY_METHOD_NAME);
23183
+ return backtest$1.strategySchemaService.get(strategyName);
23184
+ }
23185
+ /**
23186
+ * Retrieves a registered exchange schema by name.
23187
+ *
23188
+ * @param exchangeName - Unique exchange identifier
23189
+ * @returns The exchange schema configuration object
23190
+ * @throws Error if exchange is not registered
23191
+ *
23192
+ * @example
23193
+ * ```typescript
23194
+ * const exchange = getExchange("binance");
23195
+ * console.log(exchange.getCandles); // async function
23196
+ * console.log(exchange.formatPrice); // async function
23197
+ * ```
23198
+ */
23199
+ function getExchangeSchema(exchangeName) {
23200
+ backtest$1.loggerService.log(GET_EXCHANGE_METHOD_NAME, {
23201
+ exchangeName,
23202
+ });
23203
+ backtest$1.exchangeValidationService.validate(exchangeName, GET_EXCHANGE_METHOD_NAME);
23204
+ return backtest$1.exchangeSchemaService.get(exchangeName);
23205
+ }
23206
+ /**
23207
+ * Retrieves a registered frame schema by name.
23208
+ *
23209
+ * @param frameName - Unique frame identifier
23210
+ * @returns The frame schema configuration object
23211
+ * @throws Error if frame is not registered
23212
+ *
23213
+ * @example
23214
+ * ```typescript
23215
+ * const frame = getFrame("1d-backtest");
23216
+ * console.log(frame.interval); // "1m"
23217
+ * console.log(frame.startDate); // Date object
23218
+ * console.log(frame.endDate); // Date object
23219
+ * ```
23220
+ */
23221
+ function getFrameSchema(frameName) {
23222
+ backtest$1.loggerService.log(GET_FRAME_METHOD_NAME, {
23223
+ frameName,
23224
+ });
23225
+ backtest$1.frameValidationService.validate(frameName, GET_FRAME_METHOD_NAME);
23226
+ return backtest$1.frameSchemaService.get(frameName);
23227
+ }
23228
+ /**
23229
+ * Retrieves a registered walker schema by name.
23230
+ *
23231
+ * @param walkerName - Unique walker identifier
23232
+ * @returns The walker schema configuration object
23233
+ * @throws Error if walker is not registered
23234
+ *
23235
+ * @example
23236
+ * ```typescript
23237
+ * const walker = getWalker("llm-prompt-optimizer");
23238
+ * console.log(walker.exchangeName); // "binance"
23239
+ * console.log(walker.frameName); // "1d-backtest"
23240
+ * console.log(walker.strategies); // ["my-strategy-v1", "my-strategy-v2"]
23241
+ * console.log(walker.metric); // "sharpeRatio"
23242
+ * ```
23243
+ */
23244
+ function getWalkerSchema(walkerName) {
23245
+ backtest$1.loggerService.log(GET_WALKER_METHOD_NAME, {
23246
+ walkerName,
23247
+ });
23248
+ backtest$1.walkerValidationService.validate(walkerName, GET_WALKER_METHOD_NAME);
23249
+ return backtest$1.walkerSchemaService.get(walkerName);
23250
+ }
23251
+ /**
23252
+ * Retrieves a registered sizing schema by name.
23253
+ *
23254
+ * @param sizingName - Unique sizing identifier
23255
+ * @returns The sizing schema configuration object
23256
+ * @throws Error if sizing is not registered
23257
+ *
23258
+ * @example
23259
+ * ```typescript
23260
+ * const sizing = getSizing("conservative");
23261
+ * console.log(sizing.method); // "fixed-percentage"
23262
+ * console.log(sizing.riskPercentage); // 1
23263
+ * console.log(sizing.maxPositionPercentage); // 10
23264
+ * ```
23265
+ */
23266
+ function getSizingSchema(sizingName) {
23267
+ backtest$1.loggerService.log(GET_SIZING_METHOD_NAME, {
23268
+ sizingName,
23269
+ });
23270
+ backtest$1.sizingValidationService.validate(sizingName, GET_SIZING_METHOD_NAME);
23271
+ return backtest$1.sizingSchemaService.get(sizingName);
23272
+ }
23273
+ /**
23274
+ * Retrieves a registered risk schema by name.
23275
+ *
23276
+ * @param riskName - Unique risk identifier
23277
+ * @returns The risk schema configuration object
23278
+ * @throws Error if risk is not registered
23279
+ *
23280
+ * @example
23281
+ * ```typescript
23282
+ * const risk = getRisk("conservative");
23283
+ * console.log(risk.maxConcurrentPositions); // 5
23284
+ * console.log(risk.validations); // Array of validation functions
23285
+ * ```
23286
+ */
23287
+ function getRiskSchema(riskName) {
23288
+ backtest$1.loggerService.log(GET_RISK_METHOD_NAME, {
23289
+ riskName,
23290
+ });
23291
+ backtest$1.riskValidationService.validate(riskName, GET_RISK_METHOD_NAME);
23292
+ return backtest$1.riskSchemaService.get(riskName);
23293
+ }
23294
+ /**
23295
+ * Retrieves a registered optimizer schema by name.
23296
+ *
23297
+ * @param optimizerName - Unique optimizer identifier
23298
+ * @returns The optimizer schema configuration object
23299
+ * @throws Error if optimizer is not registered
23300
+ *
23301
+ * @example
23302
+ * ```typescript
23303
+ * const optimizer = getOptimizer("llm-strategy-generator");
23304
+ * console.log(optimizer.rangeTrain); // Array of training ranges
23305
+ * console.log(optimizer.rangeTest); // Testing range
23306
+ * console.log(optimizer.source); // Array of data sources
23307
+ * console.log(optimizer.getPrompt); // async function
23308
+ * ```
23309
+ */
23310
+ function getOptimizerSchema(optimizerName) {
23311
+ backtest$1.loggerService.log(GET_OPTIMIZER_METHOD_NAME, {
23312
+ optimizerName,
23313
+ });
23314
+ backtest$1.optimizerValidationService.validate(optimizerName, GET_OPTIMIZER_METHOD_NAME);
23315
+ return backtest$1.optimizerSchemaService.get(optimizerName);
23316
+ }
23317
+ /**
23318
+ * Retrieves a registered action schema by name.
23319
+ *
23320
+ * @param actionName - Unique action identifier
23321
+ * @returns The action schema configuration object
23322
+ * @throws Error if action is not registered
23323
+ *
23324
+ * @example
23325
+ * ```typescript
23326
+ * const action = getAction("telegram-notifier");
23327
+ * console.log(action.handler); // Class constructor or object
23328
+ * console.log(action.callbacks); // Optional lifecycle callbacks
23329
+ * ```
23330
+ */
23331
+ function getActionSchema(actionName) {
23332
+ backtest$1.loggerService.log(GET_ACTION_METHOD_NAME, {
23333
+ actionName,
23334
+ });
23335
+ backtest$1.actionValidationService.validate(actionName, GET_ACTION_METHOD_NAME);
23336
+ return backtest$1.actionSchemaService.get(actionName);
23337
+ }
23338
+
22809
23339
  const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
22810
23340
  const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
22811
23341
  const FORMAT_PRICE_METHOD_NAME = "exchange.formatPrice";
22812
23342
  const FORMAT_QUANTITY_METHOD_NAME = "exchange.formatQuantity";
22813
23343
  const GET_DATE_METHOD_NAME = "exchange.getDate";
22814
23344
  const GET_MODE_METHOD_NAME = "exchange.getMode";
23345
+ const GET_SYMBOL_METHOD_NAME = "exchange.getSymbol";
23346
+ const GET_CONTEXT_METHOD_NAME = "exchange.getContext";
22815
23347
  const HAS_TRADE_CONTEXT_METHOD_NAME = "exchange.hasTradeContext";
22816
23348
  const GET_ORDER_BOOK_METHOD_NAME = "exchange.getOrderBook";
22817
23349
  /**
@@ -22994,6 +23526,48 @@ async function getMode() {
22994
23526
  const { backtest: bt } = backtest$1.executionContextService.context;
22995
23527
  return bt ? "backtest" : "live";
22996
23528
  }
23529
+ /**
23530
+ * Gets the current trading symbol from execution context.
23531
+ *
23532
+ * @returns Promise resolving to the current trading symbol (e.g., "BTCUSDT")
23533
+ * @throws Error if execution context is not active
23534
+ *
23535
+ * @example
23536
+ * ```typescript
23537
+ * const symbol = await getSymbol();
23538
+ * console.log(symbol); // "BTCUSDT"
23539
+ * ```
23540
+ */
23541
+ async function getSymbol() {
23542
+ backtest$1.loggerService.info(GET_SYMBOL_METHOD_NAME);
23543
+ if (!ExecutionContextService.hasContext()) {
23544
+ throw new Error("getSymbol requires an execution context");
23545
+ }
23546
+ const { symbol } = backtest$1.executionContextService.context;
23547
+ return symbol;
23548
+ }
23549
+ /**
23550
+ * Gets the current method context.
23551
+ *
23552
+ * Returns the context object from the method context service, which contains
23553
+ * information about the current method execution environment.
23554
+ *
23555
+ * @returns Promise resolving to the current method context object
23556
+ * @throws Error if method context is not active
23557
+ *
23558
+ * @example
23559
+ * ```typescript
23560
+ * const context = await getContext();
23561
+ * console.log(context); // { ...method context data... }
23562
+ * ```
23563
+ */
23564
+ async function getContext() {
23565
+ backtest$1.loggerService.info(GET_CONTEXT_METHOD_NAME);
23566
+ if (!MethodContextService.hasContext()) {
23567
+ throw new Error("getContext requires a method context");
23568
+ }
23569
+ return backtest$1.methodContextService.context;
23570
+ }
22997
23571
  /**
22998
23572
  * Fetches order book for a trading pair from the registered exchange.
22999
23573
  *
@@ -23030,52 +23604,12 @@ async function getOrderBook(symbol, depth) {
23030
23604
  return await backtest$1.exchangeConnectionService.getOrderBook(symbol, depth);
23031
23605
  }
23032
23606
 
23033
- const STOP_METHOD_NAME = "strategy.stop";
23034
- const CANCEL_METHOD_NAME = "strategy.cancel";
23035
- const PARTIAL_PROFIT_METHOD_NAME = "strategy.partialProfit";
23036
- const PARTIAL_LOSS_METHOD_NAME = "strategy.partialLoss";
23037
- const TRAILING_STOP_METHOD_NAME = "strategy.trailingStop";
23038
- const TRAILING_PROFIT_METHOD_NAME = "strategy.trailingTake";
23039
- const BREAKEVEN_METHOD_NAME = "strategy.breakeven";
23040
- /**
23041
- * Stops the strategy from generating new signals.
23042
- *
23043
- * Sets internal flag to prevent strategy from opening new signals.
23044
- * Current active signal (if any) will complete normally.
23045
- * Backtest/Live mode will stop at the next safe point (idle state or after signal closes).
23046
- *
23047
- * Automatically detects backtest/live mode from execution context.
23048
- *
23049
- * @param symbol - Trading pair symbol
23050
- * @param strategyName - Strategy name to stop
23051
- * @returns Promise that resolves when stop flag is set
23052
- *
23053
- * @example
23054
- * ```typescript
23055
- * import { stop } from "backtest-kit";
23056
- *
23057
- * // Stop strategy after some condition
23058
- * await stop("BTCUSDT", "my-strategy");
23059
- * ```
23060
- */
23061
- async function stop(symbol) {
23062
- backtest$1.loggerService.info(STOP_METHOD_NAME, {
23063
- symbol,
23064
- });
23065
- if (!ExecutionContextService.hasContext()) {
23066
- throw new Error("stop requires an execution context");
23067
- }
23068
- if (!MethodContextService.hasContext()) {
23069
- throw new Error("stop requires a method context");
23070
- }
23071
- const { backtest: isBacktest } = backtest$1.executionContextService.context;
23072
- const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
23073
- await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
23074
- exchangeName,
23075
- frameName,
23076
- strategyName,
23077
- });
23078
- }
23607
+ const CANCEL_METHOD_NAME = "strategy.commitCancel";
23608
+ const PARTIAL_PROFIT_METHOD_NAME = "strategy.commitPartialProfit";
23609
+ const PARTIAL_LOSS_METHOD_NAME = "strategy.commitPartialLoss";
23610
+ const TRAILING_STOP_METHOD_NAME = "strategy.commitTrailingStop";
23611
+ const TRAILING_PROFIT_METHOD_NAME = "strategy.commitTrailingTake";
23612
+ const BREAKEVEN_METHOD_NAME = "strategy.commitBreakeven";
23079
23613
  /**
23080
23614
  * Cancels the scheduled signal without stopping the strategy.
23081
23615
  *
@@ -23098,7 +23632,7 @@ async function stop(symbol) {
23098
23632
  * await cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
23099
23633
  * ```
23100
23634
  */
23101
- async function cancel(symbol, cancelId) {
23635
+ async function commitCancel(symbol, cancelId) {
23102
23636
  backtest$1.loggerService.info(CANCEL_METHOD_NAME, {
23103
23637
  symbol,
23104
23638
  cancelId,
@@ -23140,7 +23674,7 @@ async function cancel(symbol, cancelId) {
23140
23674
  * }
23141
23675
  * ```
23142
23676
  */
23143
- async function partialProfit(symbol, percentToClose) {
23677
+ async function commitPartialProfit(symbol, percentToClose) {
23144
23678
  backtest$1.loggerService.info(PARTIAL_PROFIT_METHOD_NAME, {
23145
23679
  symbol,
23146
23680
  percentToClose,
@@ -23183,7 +23717,7 @@ async function partialProfit(symbol, percentToClose) {
23183
23717
  * }
23184
23718
  * ```
23185
23719
  */
23186
- async function partialLoss(symbol, percentToClose) {
23720
+ async function commitPartialLoss(symbol, percentToClose) {
23187
23721
  backtest$1.loggerService.info(PARTIAL_LOSS_METHOD_NAME, {
23188
23722
  symbol,
23189
23723
  percentToClose,
@@ -23242,7 +23776,7 @@ async function partialLoss(symbol, percentToClose) {
23242
23776
  * // success3 = true (ACCEPTED: newDistance = 10% - 7% = 3%, newSL = 97 > 95, better protection)
23243
23777
  * ```
23244
23778
  */
23245
- async function trailingStop(symbol, percentShift, currentPrice) {
23779
+ async function commitTrailingStop(symbol, percentShift, currentPrice) {
23246
23780
  backtest$1.loggerService.info(TRAILING_STOP_METHOD_NAME, {
23247
23781
  symbol,
23248
23782
  percentShift,
@@ -23301,7 +23835,7 @@ async function trailingStop(symbol, percentShift, currentPrice) {
23301
23835
  * // success3 = true (ACCEPTED: newDistance = 10% - 5% = 5%, newTP = 105 < 107, more conservative)
23302
23836
  * ```
23303
23837
  */
23304
- async function trailingTake(symbol, percentShift, currentPrice) {
23838
+ async function commitTrailingTake(symbol, percentShift, currentPrice) {
23305
23839
  backtest$1.loggerService.info(TRAILING_PROFIT_METHOD_NAME, {
23306
23840
  symbol,
23307
23841
  percentShift,
@@ -23342,7 +23876,7 @@ async function trailingTake(symbol, percentShift, currentPrice) {
23342
23876
  * }
23343
23877
  * ```
23344
23878
  */
23345
- async function breakeven(symbol) {
23879
+ async function commitBreakeven(symbol) {
23346
23880
  backtest$1.loggerService.info(BREAKEVEN_METHOD_NAME, {
23347
23881
  symbol,
23348
23882
  });
@@ -23358,6 +23892,47 @@ async function breakeven(symbol) {
23358
23892
  return await backtest$1.strategyCoreService.breakeven(isBacktest, symbol, currentPrice, { exchangeName, frameName, strategyName });
23359
23893
  }
23360
23894
 
23895
+ const STOP_METHOD_NAME = "control.stop";
23896
+ /**
23897
+ * Stops the strategy from generating new signals.
23898
+ *
23899
+ * Sets internal flag to prevent strategy from opening new signals.
23900
+ * Current active signal (if any) will complete normally.
23901
+ * Backtest/Live mode will stop at the next safe point (idle state or after signal closes).
23902
+ *
23903
+ * Automatically detects backtest/live mode from execution context.
23904
+ *
23905
+ * @param symbol - Trading pair symbol
23906
+ * @param strategyName - Strategy name to stop
23907
+ * @returns Promise that resolves when stop flag is set
23908
+ *
23909
+ * @example
23910
+ * ```typescript
23911
+ * import { stop } from "backtest-kit";
23912
+ *
23913
+ * // Stop strategy after some condition
23914
+ * await stop("BTCUSDT", "my-strategy");
23915
+ * ```
23916
+ */
23917
+ async function stop(symbol) {
23918
+ backtest$1.loggerService.info(STOP_METHOD_NAME, {
23919
+ symbol,
23920
+ });
23921
+ if (!ExecutionContextService.hasContext()) {
23922
+ throw new Error("stop requires an execution context");
23923
+ }
23924
+ if (!MethodContextService.hasContext()) {
23925
+ throw new Error("stop requires a method context");
23926
+ }
23927
+ const { backtest: isBacktest } = backtest$1.executionContextService.context;
23928
+ const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
23929
+ await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
23930
+ exchangeName,
23931
+ frameName,
23932
+ strategyName,
23933
+ });
23934
+ }
23935
+
23361
23936
  /**
23362
23937
  * Sets custom logger implementation for the framework.
23363
23938
  *
@@ -23508,14 +24083,14 @@ function getDefaultColumns() {
23508
24083
  return DEFAULT_COLUMNS;
23509
24084
  }
23510
24085
 
23511
- const ADD_STRATEGY_METHOD_NAME = "add.addStrategy";
23512
- const ADD_EXCHANGE_METHOD_NAME = "add.addExchange";
23513
- const ADD_FRAME_METHOD_NAME = "add.addFrame";
23514
- const ADD_WALKER_METHOD_NAME = "add.addWalker";
23515
- const ADD_SIZING_METHOD_NAME = "add.addSizing";
23516
- const ADD_RISK_METHOD_NAME = "add.addRisk";
23517
- const ADD_OPTIMIZER_METHOD_NAME = "add.addOptimizer";
23518
- const ADD_ACTION_METHOD_NAME = "add.addAction";
24086
+ const ADD_STRATEGY_METHOD_NAME = "add.addStrategySchema";
24087
+ const ADD_EXCHANGE_METHOD_NAME = "add.addExchangeSchema";
24088
+ const ADD_FRAME_METHOD_NAME = "add.addFrameSchema";
24089
+ const ADD_WALKER_METHOD_NAME = "add.addWalkerSchema";
24090
+ const ADD_SIZING_METHOD_NAME = "add.addSizingSchema";
24091
+ const ADD_RISK_METHOD_NAME = "add.addRiskSchema";
24092
+ const ADD_OPTIMIZER_METHOD_NAME = "add.addOptimizerSchema";
24093
+ const ADD_ACTION_METHOD_NAME = "add.addActionSchema";
23519
24094
  /**
23520
24095
  * Registers a trading strategy in the framework.
23521
24096
  *
@@ -23550,7 +24125,7 @@ const ADD_ACTION_METHOD_NAME = "add.addAction";
23550
24125
  * });
23551
24126
  * ```
23552
24127
  */
23553
- function addStrategy(strategySchema) {
24128
+ function addStrategySchema(strategySchema) {
23554
24129
  backtest$1.loggerService.info(ADD_STRATEGY_METHOD_NAME, {
23555
24130
  strategySchema,
23556
24131
  });
@@ -23592,7 +24167,7 @@ function addStrategy(strategySchema) {
23592
24167
  * });
23593
24168
  * ```
23594
24169
  */
23595
- function addExchange(exchangeSchema) {
24170
+ function addExchangeSchema(exchangeSchema) {
23596
24171
  backtest$1.loggerService.info(ADD_EXCHANGE_METHOD_NAME, {
23597
24172
  exchangeSchema,
23598
24173
  });
@@ -23629,7 +24204,7 @@ function addExchange(exchangeSchema) {
23629
24204
  * });
23630
24205
  * ```
23631
24206
  */
23632
- function addFrame(frameSchema) {
24207
+ function addFrameSchema(frameSchema) {
23633
24208
  backtest$1.loggerService.info(ADD_FRAME_METHOD_NAME, {
23634
24209
  frameSchema,
23635
24210
  });
@@ -23673,7 +24248,7 @@ function addFrame(frameSchema) {
23673
24248
  * });
23674
24249
  * ```
23675
24250
  */
23676
- function addWalker(walkerSchema) {
24251
+ function addWalkerSchema(walkerSchema) {
23677
24252
  backtest$1.loggerService.info(ADD_WALKER_METHOD_NAME, {
23678
24253
  walkerSchema,
23679
24254
  });
@@ -23732,7 +24307,7 @@ function addWalker(walkerSchema) {
23732
24307
  * });
23733
24308
  * ```
23734
24309
  */
23735
- function addSizing(sizingSchema) {
24310
+ function addSizingSchema(sizingSchema) {
23736
24311
  backtest$1.loggerService.info(ADD_SIZING_METHOD_NAME, {
23737
24312
  sizingSchema,
23738
24313
  });
@@ -23800,7 +24375,7 @@ function addSizing(sizingSchema) {
23800
24375
  * });
23801
24376
  * ```
23802
24377
  */
23803
- function addRisk(riskSchema) {
24378
+ function addRiskSchema(riskSchema) {
23804
24379
  backtest$1.loggerService.info(ADD_RISK_METHOD_NAME, {
23805
24380
  riskSchema,
23806
24381
  });
@@ -23894,7 +24469,7 @@ function addRisk(riskSchema) {
23894
24469
  * });
23895
24470
  * ```
23896
24471
  */
23897
- function addOptimizer(optimizerSchema) {
24472
+ function addOptimizerSchema(optimizerSchema) {
23898
24473
  backtest$1.loggerService.info(ADD_OPTIMIZER_METHOD_NAME, {
23899
24474
  optimizerSchema,
23900
24475
  });
@@ -23969,7 +24544,7 @@ function addOptimizer(optimizerSchema) {
23969
24544
  * });
23970
24545
  * ```
23971
24546
  */
23972
- function addAction(actionSchema) {
24547
+ function addActionSchema(actionSchema) {
23973
24548
  backtest$1.loggerService.info(ADD_ACTION_METHOD_NAME, {
23974
24549
  actionSchema,
23975
24550
  });
@@ -23977,14 +24552,14 @@ function addAction(actionSchema) {
23977
24552
  backtest$1.actionSchemaService.register(actionSchema.actionName, actionSchema);
23978
24553
  }
23979
24554
 
23980
- const METHOD_NAME_OVERRIDE_STRATEGY = "function.override.overrideStrategy";
23981
- const METHOD_NAME_OVERRIDE_EXCHANGE = "function.override.overrideExchange";
23982
- const METHOD_NAME_OVERRIDE_FRAME = "function.override.overrideFrame";
23983
- const METHOD_NAME_OVERRIDE_WALKER = "function.override.overrideWalker";
23984
- const METHOD_NAME_OVERRIDE_SIZING = "function.override.overrideSizing";
23985
- const METHOD_NAME_OVERRIDE_RISK = "function.override.overrideRisk";
23986
- const METHOD_NAME_OVERRIDE_OPTIMIZER = "function.override.overrideOptimizer";
23987
- const METHOD_NAME_OVERRIDE_ACTION = "function.override.overrideAction";
24555
+ const METHOD_NAME_OVERRIDE_STRATEGY = "function.override.overrideStrategySchema";
24556
+ const METHOD_NAME_OVERRIDE_EXCHANGE = "function.override.overrideExchangeSchema";
24557
+ const METHOD_NAME_OVERRIDE_FRAME = "function.override.overrideFrameSchema";
24558
+ const METHOD_NAME_OVERRIDE_WALKER = "function.override.overrideWalkerSchema";
24559
+ const METHOD_NAME_OVERRIDE_SIZING = "function.override.overrideSizingSchema";
24560
+ const METHOD_NAME_OVERRIDE_RISK = "function.override.overrideRiskSchema";
24561
+ const METHOD_NAME_OVERRIDE_OPTIMIZER = "function.override.overrideOptimizerSchema";
24562
+ const METHOD_NAME_OVERRIDE_ACTION = "function.override.overrideActionSchema";
23988
24563
  /**
23989
24564
  * Overrides an existing trading strategy in the framework.
23990
24565
  *
@@ -24005,7 +24580,7 @@ const METHOD_NAME_OVERRIDE_ACTION = "function.override.overrideAction";
24005
24580
  * });
24006
24581
  * ```
24007
24582
  */
24008
- async function overrideStrategy(strategySchema) {
24583
+ async function overrideStrategySchema(strategySchema) {
24009
24584
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_STRATEGY, {
24010
24585
  strategySchema,
24011
24586
  });
@@ -24033,7 +24608,7 @@ async function overrideStrategy(strategySchema) {
24033
24608
  * });
24034
24609
  * ```
24035
24610
  */
24036
- async function overrideExchange(exchangeSchema) {
24611
+ async function overrideExchangeSchema(exchangeSchema) {
24037
24612
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_EXCHANGE, {
24038
24613
  exchangeSchema,
24039
24614
  });
@@ -24061,7 +24636,7 @@ async function overrideExchange(exchangeSchema) {
24061
24636
  * });
24062
24637
  * ```
24063
24638
  */
24064
- async function overrideFrame(frameSchema) {
24639
+ async function overrideFrameSchema(frameSchema) {
24065
24640
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_FRAME, {
24066
24641
  frameSchema,
24067
24642
  });
@@ -24090,7 +24665,7 @@ async function overrideFrame(frameSchema) {
24090
24665
  * });
24091
24666
  * ```
24092
24667
  */
24093
- async function overrideWalker(walkerSchema) {
24668
+ async function overrideWalkerSchema(walkerSchema) {
24094
24669
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_WALKER, {
24095
24670
  walkerSchema,
24096
24671
  });
@@ -24122,7 +24697,7 @@ async function overrideWalker(walkerSchema) {
24122
24697
  * });
24123
24698
  * ```
24124
24699
  */
24125
- async function overrideSizing(sizingSchema) {
24700
+ async function overrideSizingSchema(sizingSchema) {
24126
24701
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_SIZING, {
24127
24702
  sizingSchema,
24128
24703
  });
@@ -24149,7 +24724,7 @@ async function overrideSizing(sizingSchema) {
24149
24724
  * });
24150
24725
  * ```
24151
24726
  */
24152
- async function overrideRisk(riskSchema) {
24727
+ async function overrideRiskSchema(riskSchema) {
24153
24728
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_RISK, {
24154
24729
  riskSchema,
24155
24730
  });
@@ -24183,7 +24758,7 @@ async function overrideRisk(riskSchema) {
24183
24758
  * });
24184
24759
  * ```
24185
24760
  */
24186
- async function overrideOptimizer(optimizerSchema) {
24761
+ async function overrideOptimizerSchema(optimizerSchema) {
24187
24762
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_OPTIMIZER, {
24188
24763
  optimizerSchema,
24189
24764
  });
@@ -24250,7 +24825,7 @@ async function overrideOptimizer(optimizerSchema) {
24250
24825
  * });
24251
24826
  * ```
24252
24827
  */
24253
- async function overrideAction(actionSchema) {
24828
+ async function overrideActionSchema(actionSchema) {
24254
24829
  backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_ACTION, {
24255
24830
  actionSchema,
24256
24831
  });
@@ -24258,13 +24833,13 @@ async function overrideAction(actionSchema) {
24258
24833
  return backtest$1.actionSchemaService.override(actionSchema.actionName, actionSchema);
24259
24834
  }
24260
24835
 
24261
- const LIST_EXCHANGES_METHOD_NAME = "list.listExchanges";
24262
- const LIST_STRATEGIES_METHOD_NAME = "list.listStrategies";
24263
- const LIST_FRAMES_METHOD_NAME = "list.listFrames";
24264
- const LIST_WALKERS_METHOD_NAME = "list.listWalkers";
24265
- const LIST_SIZINGS_METHOD_NAME = "list.listSizings";
24266
- const LIST_RISKS_METHOD_NAME = "list.listRisks";
24267
- const LIST_OPTIMIZERS_METHOD_NAME = "list.listOptimizers";
24836
+ const LIST_EXCHANGES_METHOD_NAME = "list.listExchangeSchema";
24837
+ const LIST_STRATEGIES_METHOD_NAME = "list.listStrategySchema";
24838
+ const LIST_FRAMES_METHOD_NAME = "list.listFrameSchema";
24839
+ const LIST_WALKERS_METHOD_NAME = "list.listWalkerSchema";
24840
+ const LIST_SIZINGS_METHOD_NAME = "list.listSizingSchema";
24841
+ const LIST_RISKS_METHOD_NAME = "list.listRiskSchema";
24842
+ const LIST_OPTIMIZERS_METHOD_NAME = "list.listOptimizerSchema";
24268
24843
  /**
24269
24844
  * Returns a list of all registered exchange schemas.
24270
24845
  *
@@ -24290,7 +24865,7 @@ const LIST_OPTIMIZERS_METHOD_NAME = "list.listOptimizers";
24290
24865
  * // [{ exchangeName: "binance", note: "Binance cryptocurrency exchange", ... }]
24291
24866
  * ```
24292
24867
  */
24293
- async function listExchanges() {
24868
+ async function listExchangeSchema() {
24294
24869
  backtest$1.loggerService.log(LIST_EXCHANGES_METHOD_NAME);
24295
24870
  return await backtest$1.exchangeValidationService.list();
24296
24871
  }
@@ -24324,7 +24899,7 @@ async function listExchanges() {
24324
24899
  * // [{ strategyName: "my-strategy", note: "Simple moving average...", ... }]
24325
24900
  * ```
24326
24901
  */
24327
- async function listStrategies() {
24902
+ async function listStrategySchema() {
24328
24903
  backtest$1.loggerService.log(LIST_STRATEGIES_METHOD_NAME);
24329
24904
  return await backtest$1.strategyValidationService.list();
24330
24905
  }
@@ -24353,7 +24928,7 @@ async function listStrategies() {
24353
24928
  * // [{ frameName: "1d-backtest", note: "One day backtest...", ... }]
24354
24929
  * ```
24355
24930
  */
24356
- async function listFrames() {
24931
+ async function listFrameSchema() {
24357
24932
  backtest$1.loggerService.log(LIST_FRAMES_METHOD_NAME);
24358
24933
  return await backtest$1.frameValidationService.list();
24359
24934
  }
@@ -24383,7 +24958,7 @@ async function listFrames() {
24383
24958
  * // [{ walkerName: "llm-prompt-optimizer", note: "Compare LLM...", ... }]
24384
24959
  * ```
24385
24960
  */
24386
- async function listWalkers() {
24961
+ async function listWalkerSchema() {
24387
24962
  backtest$1.loggerService.log(LIST_WALKERS_METHOD_NAME);
24388
24963
  return await backtest$1.walkerValidationService.list();
24389
24964
  }
@@ -24422,7 +24997,7 @@ async function listWalkers() {
24422
24997
  * // ]
24423
24998
  * ```
24424
24999
  */
24425
- async function listSizings() {
25000
+ async function listSizingSchema() {
24426
25001
  backtest$1.loggerService.log(LIST_SIZINGS_METHOD_NAME);
24427
25002
  return await backtest$1.sizingValidationService.list();
24428
25003
  }
@@ -24458,7 +25033,7 @@ async function listSizings() {
24458
25033
  * // ]
24459
25034
  * ```
24460
25035
  */
24461
- async function listRisks() {
25036
+ async function listRiskSchema() {
24462
25037
  backtest$1.loggerService.log(LIST_RISKS_METHOD_NAME);
24463
25038
  return await backtest$1.riskValidationService.list();
24464
25039
  }
@@ -24498,7 +25073,7 @@ async function listRisks() {
24498
25073
  * // [{ optimizerName: "llm-strategy-generator", note: "Generates...", ... }]
24499
25074
  * ```
24500
25075
  */
24501
- async function listOptimizers() {
25076
+ async function listOptimizerSchema() {
24502
25077
  backtest$1.loggerService.log(LIST_OPTIMIZERS_METHOD_NAME);
24503
25078
  return await backtest$1.optimizerValidationService.list();
24504
25079
  }
@@ -24533,8 +25108,10 @@ const LISTEN_BREAKEVEN_METHOD_NAME = "event.listenBreakeven";
24533
25108
  const LISTEN_BREAKEVEN_ONCE_METHOD_NAME = "event.listenBreakevenOnce";
24534
25109
  const LISTEN_RISK_METHOD_NAME = "event.listenRisk";
24535
25110
  const LISTEN_RISK_ONCE_METHOD_NAME = "event.listenRiskOnce";
24536
- const LISTEN_PING_METHOD_NAME = "event.listenPing";
24537
- const LISTEN_PING_ONCE_METHOD_NAME = "event.listenPingOnce";
25111
+ const LISTEN_SCHEDULE_PING_METHOD_NAME = "event.listenSchedulePing";
25112
+ const LISTEN_SCHEDULE_PING_ONCE_METHOD_NAME = "event.listenSchedulePingOnce";
25113
+ const LISTEN_ACTIVE_PING_METHOD_NAME = "event.listenActivePing";
25114
+ const LISTEN_ACTIVE_PING_ONCE_METHOD_NAME = "event.listenActivePingOnce";
24538
25115
  /**
24539
25116
  * Subscribes to all signal events with queued async processing.
24540
25117
  *
@@ -25233,7 +25810,7 @@ function listenValidation(fn) {
25233
25810
  * unsubscribe();
25234
25811
  * ```
25235
25812
  */
25236
- function listenPartialProfit(fn) {
25813
+ function listenPartialProfitAvailable(fn) {
25237
25814
  backtest$1.loggerService.log(LISTEN_PARTIAL_PROFIT_METHOD_NAME);
25238
25815
  return partialProfitSubject.subscribe(queued(async (event) => fn(event)));
25239
25816
  }
@@ -25267,7 +25844,7 @@ function listenPartialProfit(fn) {
25267
25844
  * cancel();
25268
25845
  * ```
25269
25846
  */
25270
- function listenPartialProfitOnce(filterFn, fn) {
25847
+ function listenPartialProfitAvailableOnce(filterFn, fn) {
25271
25848
  backtest$1.loggerService.log(LISTEN_PARTIAL_PROFIT_ONCE_METHOD_NAME);
25272
25849
  return partialProfitSubject.filter(filterFn).once(fn);
25273
25850
  }
@@ -25295,7 +25872,7 @@ function listenPartialProfitOnce(filterFn, fn) {
25295
25872
  * unsubscribe();
25296
25873
  * ```
25297
25874
  */
25298
- function listenPartialLoss(fn) {
25875
+ function listenPartialLossAvailable(fn) {
25299
25876
  backtest$1.loggerService.log(LISTEN_PARTIAL_LOSS_METHOD_NAME);
25300
25877
  return partialLossSubject.subscribe(queued(async (event) => fn(event)));
25301
25878
  }
@@ -25329,7 +25906,7 @@ function listenPartialLoss(fn) {
25329
25906
  * cancel();
25330
25907
  * ```
25331
25908
  */
25332
- function listenPartialLossOnce(filterFn, fn) {
25909
+ function listenPartialLossAvailableOnce(filterFn, fn) {
25333
25910
  backtest$1.loggerService.log(LISTEN_PARTIAL_LOSS_ONCE_METHOD_NAME);
25334
25911
  return partialLossSubject.filter(filterFn).once(fn);
25335
25912
  }
@@ -25359,7 +25936,7 @@ function listenPartialLossOnce(filterFn, fn) {
25359
25936
  * unsubscribe();
25360
25937
  * ```
25361
25938
  */
25362
- function listenBreakeven(fn) {
25939
+ function listenBreakevenAvailable(fn) {
25363
25940
  backtest$1.loggerService.log(LISTEN_BREAKEVEN_METHOD_NAME);
25364
25941
  return breakevenSubject.subscribe(queued(async (event) => fn(event)));
25365
25942
  }
@@ -25393,7 +25970,7 @@ function listenBreakeven(fn) {
25393
25970
  * cancel();
25394
25971
  * ```
25395
25972
  */
25396
- function listenBreakevenOnce(filterFn, fn) {
25973
+ function listenBreakevenAvailableOnce(filterFn, fn) {
25397
25974
  backtest$1.loggerService.log(LISTEN_BREAKEVEN_ONCE_METHOD_NAME);
25398
25975
  return breakevenSubject.filter(filterFn).once(fn);
25399
25976
  }
@@ -25489,9 +26066,9 @@ function listenRiskOnce(filterFn, fn) {
25489
26066
  * unsubscribe();
25490
26067
  * ```
25491
26068
  */
25492
- function listenPing(fn) {
25493
- backtest$1.loggerService.log(LISTEN_PING_METHOD_NAME);
25494
- return pingSubject.subscribe(queued(async (event) => fn(event)));
26069
+ function listenSchedulePing(fn) {
26070
+ backtest$1.loggerService.log(LISTEN_SCHEDULE_PING_METHOD_NAME);
26071
+ return schedulePingSubject.subscribe(queued(async (event) => fn(event)));
25495
26072
  }
25496
26073
  /**
25497
26074
  * Subscribes to filtered ping events with one-time execution.
@@ -25523,9 +26100,74 @@ function listenPing(fn) {
25523
26100
  * cancel();
25524
26101
  * ```
25525
26102
  */
25526
- function listenPingOnce(filterFn, fn) {
25527
- backtest$1.loggerService.log(LISTEN_PING_ONCE_METHOD_NAME);
25528
- return pingSubject.filter(filterFn).once(fn);
26103
+ function listenSchedulePingOnce(filterFn, fn) {
26104
+ backtest$1.loggerService.log(LISTEN_SCHEDULE_PING_ONCE_METHOD_NAME);
26105
+ return schedulePingSubject.filter(filterFn).once(fn);
26106
+ }
26107
+ /**
26108
+ * Subscribes to active ping events with queued async processing.
26109
+ *
26110
+ * Listens for active pending signal monitoring events emitted every minute.
26111
+ * Useful for tracking active signal lifecycle and implementing dynamic management logic.
26112
+ *
26113
+ * Events are processed sequentially in order received, even if callback is async.
26114
+ * Uses queued wrapper to prevent concurrent execution of the callback.
26115
+ *
26116
+ * @param fn - Callback function to handle active ping events
26117
+ * @returns Unsubscribe function to stop listening
26118
+ *
26119
+ * @example
26120
+ * ```typescript
26121
+ * import { listenActivePing } from "./function/event";
26122
+ *
26123
+ * const unsubscribe = listenActivePing((event) => {
26124
+ * console.log(`[${event.backtest ? "Backtest" : "Live"}] Active Ping`);
26125
+ * console.log(`Symbol: ${event.symbol}, Strategy: ${event.strategyName}`);
26126
+ * console.log(`Signal ID: ${event.data.id}, Position: ${event.data.position}`);
26127
+ * console.log(`Timestamp: ${new Date(event.timestamp).toISOString()}`);
26128
+ * });
26129
+ *
26130
+ * // Later: stop listening
26131
+ * unsubscribe();
26132
+ * ```
26133
+ */
26134
+ function listenActivePing(fn) {
26135
+ backtest$1.loggerService.log(LISTEN_ACTIVE_PING_METHOD_NAME);
26136
+ return activePingSubject.subscribe(queued(async (event) => fn(event)));
26137
+ }
26138
+ /**
26139
+ * Subscribes to filtered active ping events with one-time execution.
26140
+ *
26141
+ * Listens for events matching the filter predicate, then executes callback once
26142
+ * and automatically unsubscribes. Useful for waiting for specific active ping conditions.
26143
+ *
26144
+ * @param filterFn - Predicate to filter which events trigger the callback
26145
+ * @param fn - Callback function to handle the filtered event (called only once)
26146
+ * @returns Unsubscribe function to cancel the listener before it fires
26147
+ *
26148
+ * @example
26149
+ * ```typescript
26150
+ * import { listenActivePingOnce } from "./function/event";
26151
+ *
26152
+ * // Wait for first active ping on BTCUSDT
26153
+ * listenActivePingOnce(
26154
+ * (event) => event.symbol === "BTCUSDT",
26155
+ * (event) => console.log("First BTCUSDT active ping received")
26156
+ * );
26157
+ *
26158
+ * // Wait for active ping in backtest mode
26159
+ * const cancel = listenActivePingOnce(
26160
+ * (event) => event.backtest === true,
26161
+ * (event) => console.log("Backtest active ping received at", new Date(event.timestamp))
26162
+ * );
26163
+ *
26164
+ * // Cancel if needed before event fires
26165
+ * cancel();
26166
+ * ```
26167
+ */
26168
+ function listenActivePingOnce(filterFn, fn) {
26169
+ backtest$1.loggerService.log(LISTEN_ACTIVE_PING_ONCE_METHOD_NAME);
26170
+ return activePingSubject.filter(filterFn).once(fn);
25529
26171
  }
25530
26172
 
25531
26173
  const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
@@ -25595,7 +26237,7 @@ const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
25595
26237
  * // ./dump/strategy/{uuid}/06_llm_output.md (final signal)
25596
26238
  * ```
25597
26239
  */
25598
- async function dumpSignal(signalId, history, signal, outputDir = "./dump/strategy") {
26240
+ async function dumpSignalData(signalId, history, signal, outputDir = "./dump/strategy") {
25599
26241
  backtest$1.loggerService.info(DUMP_SIGNAL_METHOD_NAME, {
25600
26242
  signalId,
25601
26243
  history,
@@ -25615,11 +26257,12 @@ const BACKTEST_METHOD_NAME_GET_STATUS = "BacktestUtils.getStatus";
25615
26257
  const BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL = "BacktestUtils.getPendingSignal";
25616
26258
  const BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL = "BacktestUtils.getScheduledSignal";
25617
26259
  const BACKTEST_METHOD_NAME_GET_BREAKEVEN = "BacktestUtils.getBreakeven";
25618
- const BACKTEST_METHOD_NAME_CANCEL = "BacktestUtils.cancel";
25619
- const BACKTEST_METHOD_NAME_PARTIAL_PROFIT = "BacktestUtils.partialProfit";
25620
- const BACKTEST_METHOD_NAME_PARTIAL_LOSS = "BacktestUtils.partialLoss";
25621
- const BACKTEST_METHOD_NAME_TRAILING_STOP = "BacktestUtils.trailingStop";
25622
- const BACKTEST_METHOD_NAME_TRAILING_PROFIT = "BacktestUtils.trailingTake";
26260
+ const BACKTEST_METHOD_NAME_BREAKEVEN = "Backtest.commitBreakeven";
26261
+ const BACKTEST_METHOD_NAME_CANCEL = "BacktestUtils.commitCancel";
26262
+ const BACKTEST_METHOD_NAME_PARTIAL_PROFIT = "BacktestUtils.commitPartialProfit";
26263
+ const BACKTEST_METHOD_NAME_PARTIAL_LOSS = "BacktestUtils.commitPartialLoss";
26264
+ const BACKTEST_METHOD_NAME_TRAILING_STOP = "BacktestUtils.commitTrailingStop";
26265
+ const BACKTEST_METHOD_NAME_TRAILING_PROFIT = "BacktestUtils.commitTrailingTake";
25623
26266
  const BACKTEST_METHOD_NAME_GET_DATA = "BacktestUtils.getData";
25624
26267
  /**
25625
26268
  * Internal task function that runs backtest and handles completion.
@@ -26143,14 +26786,14 @@ class BacktestUtils {
26143
26786
  * @example
26144
26787
  * ```typescript
26145
26788
  * // Cancel scheduled signal with custom ID
26146
- * await Backtest.cancel("BTCUSDT", "my-strategy", {
26789
+ * await Backtest.commitCancel("BTCUSDT", "my-strategy", {
26147
26790
  * exchangeName: "binance",
26148
26791
  * frameName: "frame1",
26149
26792
  * strategyName: "my-strategy"
26150
26793
  * }, "manual-cancel-001");
26151
26794
  * ```
26152
26795
  */
26153
- this.cancel = async (symbol, context, cancelId) => {
26796
+ this.commitCancel = async (symbol, context, cancelId) => {
26154
26797
  backtest$1.loggerService.info(BACKTEST_METHOD_NAME_CANCEL, {
26155
26798
  symbol,
26156
26799
  context,
@@ -26188,7 +26831,7 @@ class BacktestUtils {
26188
26831
  * @example
26189
26832
  * ```typescript
26190
26833
  * // Close 30% of LONG position at profit
26191
- * const success = await Backtest.partialProfit("BTCUSDT", 30, 45000, {
26834
+ * const success = await Backtest.commitPartialProfit("BTCUSDT", 30, 45000, {
26192
26835
  * exchangeName: "binance",
26193
26836
  * frameName: "frame1",
26194
26837
  * strategyName: "my-strategy"
@@ -26198,7 +26841,7 @@ class BacktestUtils {
26198
26841
  * }
26199
26842
  * ```
26200
26843
  */
26201
- this.partialProfit = async (symbol, percentToClose, currentPrice, context) => {
26844
+ this.commitPartialProfit = async (symbol, percentToClose, currentPrice, context) => {
26202
26845
  backtest$1.loggerService.info(BACKTEST_METHOD_NAME_PARTIAL_PROFIT, {
26203
26846
  symbol,
26204
26847
  percentToClose,
@@ -26237,7 +26880,7 @@ class BacktestUtils {
26237
26880
  * @example
26238
26881
  * ```typescript
26239
26882
  * // Close 40% of LONG position at loss
26240
- * const success = await Backtest.partialLoss("BTCUSDT", 40, 38000, {
26883
+ * const success = await Backtest.commitPartialLoss("BTCUSDT", 40, 38000, {
26241
26884
  * exchangeName: "binance",
26242
26885
  * frameName: "frame1",
26243
26886
  * strategyName: "my-strategy"
@@ -26247,7 +26890,7 @@ class BacktestUtils {
26247
26890
  * }
26248
26891
  * ```
26249
26892
  */
26250
- this.partialLoss = async (symbol, percentToClose, currentPrice, context) => {
26893
+ this.commitPartialLoss = async (symbol, percentToClose, currentPrice, context) => {
26251
26894
  backtest$1.loggerService.info(BACKTEST_METHOD_NAME_PARTIAL_LOSS, {
26252
26895
  symbol,
26253
26896
  percentToClose,
@@ -26295,7 +26938,7 @@ class BacktestUtils {
26295
26938
  * // LONG: entry=100, originalSL=90, distance=10%, currentPrice=102
26296
26939
  *
26297
26940
  * // First call: tighten by 5%
26298
- * await Backtest.trailingStop("BTCUSDT", -5, 102, {
26941
+ * await Backtest.commitTrailingStop("BTCUSDT", -5, 102, {
26299
26942
  * exchangeName: "binance",
26300
26943
  * frameName: "frame1",
26301
26944
  * strategyName: "my-strategy"
@@ -26303,15 +26946,15 @@ class BacktestUtils {
26303
26946
  * // newDistance = 10% - 5% = 5%, newSL = 95
26304
26947
  *
26305
26948
  * // Second call: try weaker protection (smaller percentShift)
26306
- * await Backtest.trailingStop("BTCUSDT", -3, 102, context);
26949
+ * await Backtest.commitTrailingStop("BTCUSDT", -3, 102, context);
26307
26950
  * // SKIPPED: newSL=97 < 95 (worse protection, larger % absorbs smaller)
26308
26951
  *
26309
26952
  * // Third call: stronger protection (larger percentShift)
26310
- * await Backtest.trailingStop("BTCUSDT", -7, 102, context);
26953
+ * await Backtest.commitTrailingStop("BTCUSDT", -7, 102, context);
26311
26954
  * // ACCEPTED: newDistance = 10% - 7% = 3%, newSL = 97 > 95 (better protection)
26312
26955
  * ```
26313
26956
  */
26314
- this.trailingStop = async (symbol, percentShift, currentPrice, context) => {
26957
+ this.commitTrailingStop = async (symbol, percentShift, currentPrice, context) => {
26315
26958
  backtest$1.loggerService.info(BACKTEST_METHOD_NAME_TRAILING_STOP, {
26316
26959
  symbol,
26317
26960
  percentShift,
@@ -26359,7 +27002,7 @@ class BacktestUtils {
26359
27002
  * // LONG: entry=100, originalTP=110, distance=10%, currentPrice=102
26360
27003
  *
26361
27004
  * // First call: bring TP closer by 3%
26362
- * await Backtest.trailingTake("BTCUSDT", -3, 102, {
27005
+ * await Backtest.commitTrailingTake("BTCUSDT", -3, 102, {
26363
27006
  * exchangeName: "binance",
26364
27007
  * frameName: "frame1",
26365
27008
  * strategyName: "my-strategy"
@@ -26367,15 +27010,15 @@ class BacktestUtils {
26367
27010
  * // newDistance = 10% - 3% = 7%, newTP = 107
26368
27011
  *
26369
27012
  * // Second call: try to move TP further (less conservative)
26370
- * await Backtest.trailingTake("BTCUSDT", 2, 102, context);
27013
+ * await Backtest.commitTrailingTake("BTCUSDT", 2, 102, context);
26371
27014
  * // SKIPPED: newTP=112 > 107 (less conservative, larger % absorbs smaller)
26372
27015
  *
26373
27016
  * // Third call: even more conservative
26374
- * await Backtest.trailingTake("BTCUSDT", -5, 102, context);
27017
+ * await Backtest.commitTrailingTake("BTCUSDT", -5, 102, context);
26375
27018
  * // ACCEPTED: newDistance = 10% - 5% = 5%, newTP = 105 < 107 (more conservative)
26376
27019
  * ```
26377
27020
  */
26378
- this.trailingTake = async (symbol, percentShift, currentPrice, context) => {
27021
+ this.commitTrailingTake = async (symbol, percentShift, currentPrice, context) => {
26379
27022
  backtest$1.loggerService.info(BACKTEST_METHOD_NAME_TRAILING_PROFIT, {
26380
27023
  symbol,
26381
27024
  percentShift,
@@ -26408,7 +27051,7 @@ class BacktestUtils {
26408
27051
  *
26409
27052
  * @example
26410
27053
  * ```typescript
26411
- * const moved = await Backtest.breakeven(
27054
+ * const moved = await Backtest.commitBreakeven(
26412
27055
  * "BTCUSDT",
26413
27056
  * 112,
26414
27057
  * { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" }
@@ -26416,22 +27059,22 @@ class BacktestUtils {
26416
27059
  * console.log(moved); // true (SL moved to entry price)
26417
27060
  * ```
26418
27061
  */
26419
- this.breakeven = async (symbol, currentPrice, context) => {
26420
- backtest$1.loggerService.info("Backtest.breakeven", {
27062
+ this.commitBreakeven = async (symbol, currentPrice, context) => {
27063
+ backtest$1.loggerService.info(BACKTEST_METHOD_NAME_BREAKEVEN, {
26421
27064
  symbol,
26422
27065
  currentPrice,
26423
27066
  context,
26424
27067
  });
26425
- backtest$1.strategyValidationService.validate(context.strategyName, "Backtest.breakeven");
26426
- backtest$1.exchangeValidationService.validate(context.exchangeName, "Backtest.breakeven");
27068
+ backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_BREAKEVEN);
27069
+ backtest$1.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_BREAKEVEN);
26427
27070
  {
26428
27071
  const { riskName, riskList, actions } = backtest$1.strategySchemaService.get(context.strategyName);
26429
27072
  riskName &&
26430
- backtest$1.riskValidationService.validate(riskName, "Backtest.breakeven");
27073
+ backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_BREAKEVEN);
26431
27074
  riskList &&
26432
- riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, "Backtest.breakeven"));
27075
+ riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_BREAKEVEN));
26433
27076
  actions &&
26434
- actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName, "Backtest.breakeven"));
27077
+ actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_BREAKEVEN));
26435
27078
  }
26436
27079
  return await backtest$1.strategyCoreService.breakeven(true, symbol, currentPrice, context);
26437
27080
  };
@@ -26603,11 +27246,12 @@ const LIVE_METHOD_NAME_GET_STATUS = "LiveUtils.getStatus";
26603
27246
  const LIVE_METHOD_NAME_GET_PENDING_SIGNAL = "LiveUtils.getPendingSignal";
26604
27247
  const LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL = "LiveUtils.getScheduledSignal";
26605
27248
  const LIVE_METHOD_NAME_GET_BREAKEVEN = "LiveUtils.getBreakeven";
26606
- const LIVE_METHOD_NAME_CANCEL = "LiveUtils.cancel";
26607
- const LIVE_METHOD_NAME_PARTIAL_PROFIT = "LiveUtils.partialProfit";
26608
- const LIVE_METHOD_NAME_PARTIAL_LOSS = "LiveUtils.partialLoss";
26609
- const LIVE_METHOD_NAME_TRAILING_STOP = "LiveUtils.trailingStop";
26610
- const LIVE_METHOD_NAME_TRAILING_PROFIT = "LiveUtils.trailingTake";
27249
+ const LIVE_METHOD_NAME_BREAKEVEN = "Live.commitBreakeven";
27250
+ const LIVE_METHOD_NAME_CANCEL = "LiveUtils.commitCancel";
27251
+ const LIVE_METHOD_NAME_PARTIAL_PROFIT = "LiveUtils.commitPartialProfit";
27252
+ const LIVE_METHOD_NAME_PARTIAL_LOSS = "LiveUtils.commitPartialLoss";
27253
+ const LIVE_METHOD_NAME_TRAILING_STOP = "LiveUtils.commitTrailingStop";
27254
+ const LIVE_METHOD_NAME_TRAILING_PROFIT = "LiveUtils.commitTrailingTake";
26611
27255
  /**
26612
27256
  * Internal task function that runs live trading and handles completion.
26613
27257
  * Consumes live trading results and updates instance state flags.
@@ -27097,14 +27741,14 @@ class LiveUtils {
27097
27741
  * @example
27098
27742
  * ```typescript
27099
27743
  * // Cancel scheduled signal in live trading with custom ID
27100
- * await Live.cancel("BTCUSDT", "my-strategy", {
27744
+ * await Live.commitCancel("BTCUSDT", "my-strategy", {
27101
27745
  * exchangeName: "binance",
27102
27746
  * frameName: "",
27103
27747
  * strategyName: "my-strategy"
27104
27748
  * }, "manual-cancel-001");
27105
27749
  * ```
27106
27750
  */
27107
- this.cancel = async (symbol, context, cancelId) => {
27751
+ this.commitCancel = async (symbol, context, cancelId) => {
27108
27752
  backtest$1.loggerService.info(LIVE_METHOD_NAME_CANCEL, {
27109
27753
  symbol,
27110
27754
  context,
@@ -27143,7 +27787,7 @@ class LiveUtils {
27143
27787
  * @example
27144
27788
  * ```typescript
27145
27789
  * // Close 30% of LONG position at profit
27146
- * const success = await Live.partialProfit("BTCUSDT", 30, 45000, {
27790
+ * const success = await Live.commitPartialProfit("BTCUSDT", 30, 45000, {
27147
27791
  * exchangeName: "binance",
27148
27792
  * strategyName: "my-strategy"
27149
27793
  * });
@@ -27152,7 +27796,7 @@ class LiveUtils {
27152
27796
  * }
27153
27797
  * ```
27154
27798
  */
27155
- this.partialProfit = async (symbol, percentToClose, currentPrice, context) => {
27799
+ this.commitPartialProfit = async (symbol, percentToClose, currentPrice, context) => {
27156
27800
  backtest$1.loggerService.info(LIVE_METHOD_NAME_PARTIAL_PROFIT, {
27157
27801
  symbol,
27158
27802
  percentToClose,
@@ -27192,7 +27836,7 @@ class LiveUtils {
27192
27836
  * @example
27193
27837
  * ```typescript
27194
27838
  * // Close 40% of LONG position at loss
27195
- * const success = await Live.partialLoss("BTCUSDT", 40, 38000, {
27839
+ * const success = await Live.commitPartialLoss("BTCUSDT", 40, 38000, {
27196
27840
  * exchangeName: "binance",
27197
27841
  * strategyName: "my-strategy"
27198
27842
  * });
@@ -27201,7 +27845,7 @@ class LiveUtils {
27201
27845
  * }
27202
27846
  * ```
27203
27847
  */
27204
- this.partialLoss = async (symbol, percentToClose, currentPrice, context) => {
27848
+ this.commitPartialLoss = async (symbol, percentToClose, currentPrice, context) => {
27205
27849
  backtest$1.loggerService.info(LIVE_METHOD_NAME_PARTIAL_LOSS, {
27206
27850
  symbol,
27207
27851
  percentToClose,
@@ -27250,22 +27894,22 @@ class LiveUtils {
27250
27894
  * // LONG: entry=100, originalSL=90, distance=10%, currentPrice=102
27251
27895
  *
27252
27896
  * // First call: tighten by 5%
27253
- * const success1 = await Live.trailingStop("BTCUSDT", -5, 102, {
27897
+ * const success1 = await Live.commitTrailingStop("BTCUSDT", -5, 102, {
27254
27898
  * exchangeName: "binance",
27255
27899
  * strategyName: "my-strategy"
27256
27900
  * });
27257
27901
  * // success1 = true, newDistance = 10% - 5% = 5%, newSL = 95
27258
27902
  *
27259
27903
  * // Second call: try weaker protection (smaller percentShift)
27260
- * const success2 = await Live.trailingStop("BTCUSDT", -3, 102, context);
27904
+ * const success2 = await Live.commitTrailingStop("BTCUSDT", -3, 102, context);
27261
27905
  * // success2 = false (SKIPPED: newSL=97 < 95, worse protection, larger % absorbs smaller)
27262
27906
  *
27263
27907
  * // Third call: stronger protection (larger percentShift)
27264
- * const success3 = await Live.trailingStop("BTCUSDT", -7, 102, context);
27908
+ * const success3 = await Live.commitTrailingStop("BTCUSDT", -7, 102, context);
27265
27909
  * // success3 = true (ACCEPTED: newDistance = 10% - 7% = 3%, newSL = 97 > 95, better protection)
27266
27910
  * ```
27267
27911
  */
27268
- this.trailingStop = async (symbol, percentShift, currentPrice, context) => {
27912
+ this.commitTrailingStop = async (symbol, percentShift, currentPrice, context) => {
27269
27913
  backtest$1.loggerService.info(LIVE_METHOD_NAME_TRAILING_STOP, {
27270
27914
  symbol,
27271
27915
  percentShift,
@@ -27314,22 +27958,22 @@ class LiveUtils {
27314
27958
  * // LONG: entry=100, originalTP=110, distance=10%, currentPrice=102
27315
27959
  *
27316
27960
  * // First call: bring TP closer by 3%
27317
- * const success1 = await Live.trailingTake("BTCUSDT", -3, 102, {
27961
+ * const success1 = await Live.commitTrailingTake("BTCUSDT", -3, 102, {
27318
27962
  * exchangeName: "binance",
27319
27963
  * strategyName: "my-strategy"
27320
27964
  * });
27321
27965
  * // success1 = true, newDistance = 10% - 3% = 7%, newTP = 107
27322
27966
  *
27323
27967
  * // Second call: try to move TP further (less conservative)
27324
- * const success2 = await Live.trailingTake("BTCUSDT", 2, 102, context);
27968
+ * const success2 = await Live.commitTrailingTake("BTCUSDT", 2, 102, context);
27325
27969
  * // success2 = false (SKIPPED: newTP=112 > 107, less conservative, larger % absorbs smaller)
27326
27970
  *
27327
27971
  * // Third call: even more conservative
27328
- * const success3 = await Live.trailingTake("BTCUSDT", -5, 102, context);
27972
+ * const success3 = await Live.commitTrailingTake("BTCUSDT", -5, 102, context);
27329
27973
  * // success3 = true (ACCEPTED: newDistance = 10% - 5% = 5%, newTP = 105 < 107, more conservative)
27330
27974
  * ```
27331
27975
  */
27332
- this.trailingTake = async (symbol, percentShift, currentPrice, context) => {
27976
+ this.commitTrailingTake = async (symbol, percentShift, currentPrice, context) => {
27333
27977
  backtest$1.loggerService.info(LIVE_METHOD_NAME_TRAILING_PROFIT, {
27334
27978
  symbol,
27335
27979
  percentShift,
@@ -27363,7 +28007,7 @@ class LiveUtils {
27363
28007
  *
27364
28008
  * @example
27365
28009
  * ```typescript
27366
- * const moved = await Live.breakeven(
28010
+ * const moved = await Live.commitBreakeven(
27367
28011
  * "BTCUSDT",
27368
28012
  * 112,
27369
28013
  * { strategyName: "my-strategy", exchangeName: "binance" }
@@ -27371,19 +28015,19 @@ class LiveUtils {
27371
28015
  * console.log(moved); // true (SL moved to entry price)
27372
28016
  * ```
27373
28017
  */
27374
- this.breakeven = async (symbol, currentPrice, context) => {
27375
- backtest$1.loggerService.info("Live.breakeven", {
28018
+ this.commitBreakeven = async (symbol, currentPrice, context) => {
28019
+ backtest$1.loggerService.info(LIVE_METHOD_NAME_BREAKEVEN, {
27376
28020
  symbol,
27377
28021
  currentPrice,
27378
28022
  context,
27379
28023
  });
27380
- backtest$1.strategyValidationService.validate(context.strategyName, "Live.breakeven");
27381
- backtest$1.exchangeValidationService.validate(context.exchangeName, "Live.breakeven");
28024
+ backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_BREAKEVEN);
28025
+ backtest$1.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_BREAKEVEN);
27382
28026
  {
27383
28027
  const { riskName, riskList, actions } = backtest$1.strategySchemaService.get(context.strategyName);
27384
- riskName && backtest$1.riskValidationService.validate(riskName, "Live.breakeven");
27385
- riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, "Live.breakeven"));
27386
- actions && actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName, "Live.breakeven"));
28028
+ riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_BREAKEVEN);
28029
+ riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_BREAKEVEN));
28030
+ actions && actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName, LIVE_METHOD_NAME_BREAKEVEN));
27387
28031
  }
27388
28032
  return await backtest$1.strategyCoreService.breakeven(false, symbol, currentPrice, {
27389
28033
  strategyName: context.strategyName,
@@ -29211,10 +29855,15 @@ class ExchangeInstance {
29211
29855
  const whenTimestamp = when.getTime();
29212
29856
  const sinceTimestamp = since.getTime();
29213
29857
  const filteredData = allData.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= whenTimestamp);
29214
- if (filteredData.length < limit) {
29215
- backtest$1.loggerService.warn(`ExchangeInstance Expected ${limit} candles, got ${filteredData.length}`);
29858
+ // Apply distinct by timestamp to remove duplicates
29859
+ const uniqueData = Array.from(new Map(filteredData.map((candle) => [candle.timestamp, candle])).values());
29860
+ if (filteredData.length !== uniqueData.length) {
29861
+ backtest$1.loggerService.warn(`ExchangeInstance Removed ${filteredData.length - uniqueData.length} duplicate candles by timestamp`);
29216
29862
  }
29217
- return filteredData;
29863
+ if (uniqueData.length < limit) {
29864
+ backtest$1.loggerService.warn(`ExchangeInstance Expected ${limit} candles, got ${uniqueData.length}`);
29865
+ }
29866
+ return uniqueData;
29218
29867
  };
29219
29868
  /**
29220
29869
  * Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
@@ -30393,10 +31042,11 @@ const METHOD_NAME_INIT = "ActionBase.init";
30393
31042
  const METHOD_NAME_EVENT = "ActionBase.event";
30394
31043
  const METHOD_NAME_SIGNAL_LIVE = "ActionBase.signalLive";
30395
31044
  const METHOD_NAME_SIGNAL_BACKTEST = "ActionBase.signalBacktest";
30396
- const METHOD_NAME_BREAKEVEN = "ActionBase.breakeven";
30397
- const METHOD_NAME_PARTIAL_PROFIT = "ActionBase.partialProfit";
30398
- const METHOD_NAME_PARTIAL_LOSS = "ActionBase.partialLoss";
30399
- const METHOD_NAME_PING = "ActionBase.ping";
31045
+ const METHOD_NAME_BREAKEVEN_AVAILABLE = "ActionBase.breakevenAvailable";
31046
+ const METHOD_NAME_PARTIAL_PROFIT_AVAILABLE = "ActionBase.partialProfitAvailable";
31047
+ const METHOD_NAME_PARTIAL_LOSS_AVAILABLE = "ActionBase.partialLossAvailable";
31048
+ const METHOD_NAME_PING_SCHEDULED = "ActionBase.pingScheduled";
31049
+ const METHOD_NAME_PING_ACTIVE = "ActionBase.pingActive";
30400
31050
  const METHOD_NAME_RISK_REJECTION = "ActionBase.riskRejection";
30401
31051
  const METHOD_NAME_DISPOSE = "ActionBase.dispose";
30402
31052
  const DEFAULT_SOURCE = "default";
@@ -30427,10 +31077,11 @@ const DEFAULT_SOURCE = "default";
30427
31077
  * - signal() - Called on every tick/candle (all modes)
30428
31078
  * - signalLive() - Called only in live mode
30429
31079
  * - signalBacktest() - Called only in backtest mode
30430
- * - breakeven() - Called when SL moved to entry
30431
- * - partialProfit() - Called on profit milestones (10%, 20%, etc.)
30432
- * - partialLoss() - Called on loss milestones (-10%, -20%, etc.)
30433
- * - ping() - Called every minute during scheduled signal monitoring
31080
+ * - breakevenAvailable() - Called when SL moved to entry
31081
+ * - partialProfitAvailable() - Called on profit milestones (10%, 20%, etc.)
31082
+ * - partialLossAvailable() - Called on loss milestones (-10%, -20%, etc.)
31083
+ * - pingScheduled() - Called every minute during scheduled signal monitoring
31084
+ * - pingActive() - Called every minute during active pending signal monitoring
30434
31085
  * - riskRejection() - Called when signal rejected by risk management
30435
31086
  *
30436
31087
  * @example
@@ -30471,7 +31122,7 @@ const DEFAULT_SOURCE = "default";
30471
31122
  * }
30472
31123
  *
30473
31124
  * // Register the action
30474
- * addAction({
31125
+ * addActionSchema({
30475
31126
  * actionName: "telegram-notifier",
30476
31127
  * handler: TelegramNotifier
30477
31128
  * });
@@ -30513,11 +31164,13 @@ class ActionBase {
30513
31164
  * @param strategyName - Strategy identifier this action is attached to
30514
31165
  * @param frameName - Timeframe identifier this action is attached to
30515
31166
  * @param actionName - Action identifier
31167
+ * @param backtest - If running in backtest
30516
31168
  */
30517
- constructor(strategyName, frameName, actionName) {
31169
+ constructor(strategyName, frameName, actionName, backtest) {
30518
31170
  this.strategyName = strategyName;
30519
31171
  this.frameName = frameName;
30520
31172
  this.actionName = actionName;
31173
+ this.backtest = backtest;
30521
31174
  }
30522
31175
  /**
30523
31176
  * Initializes the action handler.
@@ -30641,7 +31294,7 @@ class ActionBase {
30641
31294
  * Called once per signal when price moves far enough to cover fees and slippage.
30642
31295
  * Breakeven threshold: (CC_PERCENT_SLIPPAGE + CC_PERCENT_FEE) * 2 + CC_BREAKEVEN_THRESHOLD
30643
31296
  *
30644
- * Triggered by: ActionCoreService.breakeven() via BreakevenConnectionService
31297
+ * Triggered by: ActionCoreService.breakevenAvailable() via BreakevenConnectionService
30645
31298
  * Source: breakevenSubject.next() in CREATE_COMMIT_BREAKEVEN_FN callback
30646
31299
  * Frequency: Once per signal when threshold reached
30647
31300
  *
@@ -30651,7 +31304,7 @@ class ActionBase {
30651
31304
  *
30652
31305
  * @example
30653
31306
  * ```typescript
30654
- * async breakeven(event: BreakevenContract) {
31307
+ * async breakevenAvailable(event: BreakevenContract) {
30655
31308
  * await this.telegram.send(
30656
31309
  * `[${event.strategyName}] Breakeven reached! ` +
30657
31310
  * `Signal: ${event.data.side} @ ${event.currentPrice}`
@@ -30659,8 +31312,8 @@ class ActionBase {
30659
31312
  * }
30660
31313
  * ```
30661
31314
  */
30662
- breakeven(event, source = DEFAULT_SOURCE) {
30663
- backtest$1.loggerService.info(METHOD_NAME_BREAKEVEN, {
31315
+ breakevenAvailable(event, source = DEFAULT_SOURCE) {
31316
+ backtest$1.loggerService.info(METHOD_NAME_BREAKEVEN_AVAILABLE, {
30664
31317
  event,
30665
31318
  source,
30666
31319
  });
@@ -30671,7 +31324,7 @@ class ActionBase {
30671
31324
  * Called once per profit level per signal (deduplicated).
30672
31325
  * Use to track profit milestones and adjust position management.
30673
31326
  *
30674
- * Triggered by: ActionCoreService.partialProfit() via PartialConnectionService
31327
+ * Triggered by: ActionCoreService.partialProfitAvailable() via PartialConnectionService
30675
31328
  * Source: partialProfitSubject.next() in CREATE_COMMIT_PROFIT_FN callback
30676
31329
  * Frequency: Once per profit level per signal
30677
31330
  *
@@ -30681,7 +31334,7 @@ class ActionBase {
30681
31334
  *
30682
31335
  * @example
30683
31336
  * ```typescript
30684
- * async partialProfit(event: PartialProfitContract) {
31337
+ * async partialProfitAvailable(event: PartialProfitContract) {
30685
31338
  * await this.telegram.send(
30686
31339
  * `[${event.strategyName}] Profit ${event.level}% reached! ` +
30687
31340
  * `Current price: ${event.currentPrice}`
@@ -30690,8 +31343,8 @@ class ActionBase {
30690
31343
  * }
30691
31344
  * ```
30692
31345
  */
30693
- partialProfit(event, source = DEFAULT_SOURCE) {
30694
- backtest$1.loggerService.info(METHOD_NAME_PARTIAL_PROFIT, {
31346
+ partialProfitAvailable(event, source = DEFAULT_SOURCE) {
31347
+ backtest$1.loggerService.info(METHOD_NAME_PARTIAL_PROFIT_AVAILABLE, {
30695
31348
  event,
30696
31349
  source,
30697
31350
  });
@@ -30702,7 +31355,7 @@ class ActionBase {
30702
31355
  * Called once per loss level per signal (deduplicated).
30703
31356
  * Use to track loss milestones and implement risk management actions.
30704
31357
  *
30705
- * Triggered by: ActionCoreService.partialLoss() via PartialConnectionService
31358
+ * Triggered by: ActionCoreService.partialLossAvailable() via PartialConnectionService
30706
31359
  * Source: partialLossSubject.next() in CREATE_COMMIT_LOSS_FN callback
30707
31360
  * Frequency: Once per loss level per signal
30708
31361
  *
@@ -30712,7 +31365,7 @@ class ActionBase {
30712
31365
  *
30713
31366
  * @example
30714
31367
  * ```typescript
30715
- * async partialLoss(event: PartialLossContract) {
31368
+ * async partialLossAvailable(event: PartialLossContract) {
30716
31369
  * await this.telegram.send(
30717
31370
  * `[${event.strategyName}] Loss ${event.level}% reached! ` +
30718
31371
  * `Current price: ${event.currentPrice}`
@@ -30721,37 +31374,66 @@ class ActionBase {
30721
31374
  * }
30722
31375
  * ```
30723
31376
  */
30724
- partialLoss(event, source = DEFAULT_SOURCE) {
30725
- backtest$1.loggerService.info(METHOD_NAME_PARTIAL_LOSS, {
31377
+ partialLossAvailable(event, source = DEFAULT_SOURCE) {
31378
+ backtest$1.loggerService.info(METHOD_NAME_PARTIAL_LOSS_AVAILABLE, {
30726
31379
  event,
30727
31380
  source,
30728
31381
  });
30729
31382
  }
30730
31383
  /**
30731
- * Handles ping events during scheduled signal monitoring.
31384
+ * Handles scheduled ping events during scheduled signal monitoring.
30732
31385
  *
30733
31386
  * Called every minute while a scheduled signal is waiting for activation.
30734
31387
  * Use to monitor pending signals and track wait time.
30735
31388
  *
30736
- * Triggered by: ActionCoreService.ping() via StrategyConnectionService
30737
- * Source: pingSubject.next() in CREATE_COMMIT_PING_FN callback
31389
+ * Triggered by: ActionCoreService.pingScheduled() via StrategyConnectionService
31390
+ * Source: schedulePingSubject.next() in CREATE_COMMIT_SCHEDULE_PING_FN callback
30738
31391
  * Frequency: Every minute while scheduled signal is waiting
30739
31392
  *
30740
- * Default implementation: Logs ping event.
31393
+ * Default implementation: Logs scheduled ping event.
30741
31394
  *
30742
31395
  * @param event - Scheduled signal monitoring data with symbol, strategy info, signal data, timestamp
30743
31396
  *
30744
31397
  * @example
30745
31398
  * ```typescript
30746
- * ping(event: PingContract) {
31399
+ * pingScheduled(event: SchedulePingContract) {
30747
31400
  * const waitTime = Date.now() - event.data.timestampScheduled;
30748
31401
  * const waitMinutes = Math.floor(waitTime / 60000);
30749
31402
  * console.log(`Scheduled signal waiting ${waitMinutes} minutes`);
30750
31403
  * }
30751
31404
  * ```
30752
31405
  */
30753
- ping(event, source = DEFAULT_SOURCE) {
30754
- backtest$1.loggerService.info(METHOD_NAME_PING, {
31406
+ pingScheduled(event, source = DEFAULT_SOURCE) {
31407
+ backtest$1.loggerService.info(METHOD_NAME_PING_SCHEDULED, {
31408
+ event,
31409
+ source,
31410
+ });
31411
+ }
31412
+ /**
31413
+ * Handles active ping events during active pending signal monitoring.
31414
+ *
31415
+ * Called every minute while a pending signal is active (position open).
31416
+ * Use to monitor active positions and track lifecycle.
31417
+ *
31418
+ * Triggered by: ActionCoreService.pingActive() via StrategyConnectionService
31419
+ * Source: activePingSubject.next() in CREATE_COMMIT_ACTIVE_PING_FN callback
31420
+ * Frequency: Every minute while pending signal is active
31421
+ *
31422
+ * Default implementation: Logs active ping event.
31423
+ *
31424
+ * @param event - Active pending signal monitoring data with symbol, strategy info, signal data, timestamp
31425
+ *
31426
+ * @example
31427
+ * ```typescript
31428
+ * pingActive(event: ActivePingContract) {
31429
+ * const holdTime = Date.now() - event.data.pendingAt;
31430
+ * const holdMinutes = Math.floor(holdTime / 60000);
31431
+ * console.log(`Active signal holding ${holdMinutes} minutes`);
31432
+ * }
31433
+ * ```
31434
+ */
31435
+ pingActive(event, source = DEFAULT_SOURCE) {
31436
+ backtest$1.loggerService.info(METHOD_NAME_PING_ACTIVE, {
30755
31437
  event,
30756
31438
  source,
30757
31439
  });
@@ -30870,4 +31552,4 @@ const set = (object, path, value) => {
30870
31552
  }
30871
31553
  };
30872
31554
 
30873
- export { ActionBase, Backtest, Breakeven, Cache, Constant, Exchange, ExecutionContextService, Heat, Live, Markdown, MarkdownFileBase, MarkdownFolderBase, MethodContextService, Notification, Optimizer, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Report, ReportBase, Risk, Schedule, Walker, addAction, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, breakeven, cancel, dumpSignal, emitters, formatPrice, formatQuantity, get, getAveragePrice, getCandles, getColumns, getConfig, getDate, getDefaultColumns, getDefaultConfig, getMode, getOrderBook, hasTradeContext, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenBreakeven, listenBreakevenOnce, 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, overrideAction, overrideExchange, overrideFrame, overrideOptimizer, overrideRisk, overrideSizing, overrideStrategy, overrideWalker, partialLoss, partialProfit, roundTicks, set, setColumns, setConfig, setLogger, stop, trailingStop, trailingTake, validate };
31555
+ export { ActionBase, Backtest, Breakeven, Cache, Constant, Exchange, ExecutionContextService, Heat, Live, Markdown, MarkdownFileBase, MarkdownFolderBase, MethodContextService, Notification, Optimizer, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Report, ReportBase, Risk, Schedule, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addOptimizerSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, commitBreakeven, commitCancel, commitPartialLoss, commitPartialProfit, commitTrailingStop, commitTrailingTake, dumpSignalData, emitters, formatPrice, formatQuantity, get, getActionSchema, getAveragePrice, getBacktestTimeframe, getCandles, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getExchangeSchema, getFrameSchema, getMode, getOptimizerSchema, getOrderBook, getRiskSchema, getSizingSchema, getStrategySchema, getSymbol, getWalkerSchema, hasTradeContext, backtest as lib, listExchangeSchema, listFrameSchema, listOptimizerSchema, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideOptimizerSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, roundTicks, set, setColumns, setConfig, setLogger, stop, validate };