backtest-kit 2.2.6 → 2.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.cjs CHANGED
@@ -556,10 +556,19 @@ const activePingSubject = new functoolsKit.Subject();
556
556
  * Used by StrategyReportService and StrategyMarkdownService for event logging and reporting.
557
557
  */
558
558
  const strategyCommitSubject = new functoolsKit.Subject();
559
+ /**
560
+ * ClientStrategy::backtest using return instead of async iterator emitter.
561
+ * If signal was scheduled to open, emits when the signal is actually opened.
562
+ *
563
+ * Allows to yield IStrategyTickResultOpened in addition to IStrategyTickResultClosed | IStrategyTickResultCancelled for
564
+ * BacktestLogicPrivateService::*run
565
+ */
566
+ const backtestScheduleOpenSubject = new functoolsKit.Subject();
559
567
 
560
568
  var emitters = /*#__PURE__*/Object.freeze({
561
569
  __proto__: null,
562
570
  activePingSubject: activePingSubject,
571
+ backtestScheduleOpenSubject: backtestScheduleOpenSubject,
563
572
  breakevenSubject: breakevenSubject,
564
573
  doneBacktestSubject: doneBacktestSubject,
565
574
  doneLiveSubject: doneLiveSubject,
@@ -4231,6 +4240,36 @@ const CALL_BREAKEVEN_CLEAR_FN = functoolsKit.trycatch(beginTime(async (self, sym
4231
4240
  errorEmitter.next(error);
4232
4241
  },
4233
4242
  });
4243
+ const CALL_BACKTEST_SCHEDULE_OPEN_FN = functoolsKit.trycatch(beginTime(async (self, symbol, signal, timestamp, backtest) => {
4244
+ await ExecutionContextService.runInContext(async () => {
4245
+ backtestScheduleOpenSubject.next({
4246
+ action: "opened",
4247
+ signal: TO_PUBLIC_SIGNAL(signal),
4248
+ strategyName: self.params.method.context.strategyName,
4249
+ exchangeName: self.params.method.context.exchangeName,
4250
+ frameName: self.params.method.context.frameName,
4251
+ symbol: symbol,
4252
+ currentPrice: signal.priceOpen,
4253
+ backtest: true,
4254
+ createdAt: timestamp,
4255
+ });
4256
+ }, {
4257
+ when: new Date(timestamp),
4258
+ symbol: symbol,
4259
+ backtest: backtest,
4260
+ });
4261
+ }), {
4262
+ fallback: (error) => {
4263
+ const message = "ClientStrategy CALL_BACKTEST_SCHEDULE_OPEN_FN thrown";
4264
+ const payload = {
4265
+ error: functoolsKit.errorData(error),
4266
+ message: functoolsKit.getErrorMessage(error),
4267
+ };
4268
+ bt.loggerService.warn(message, payload);
4269
+ console.warn(message, payload);
4270
+ errorEmitter.next(error);
4271
+ },
4272
+ });
4234
4273
  const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
4235
4274
  const currentTime = self.params.execution.context.when.getTime();
4236
4275
  await CALL_SCHEDULE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentTime, self.params.execution.context.backtest);
@@ -4520,6 +4559,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
4520
4559
  await self.setPendingSignal(activatedSignal);
4521
4560
  await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
4522
4561
  await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, activatedSignal, activatedSignal.priceOpen, activationTime, self.params.execution.context.backtest);
4562
+ await CALL_BACKTEST_SCHEDULE_OPEN_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
4523
4563
  return true;
4524
4564
  };
4525
4565
  const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, closeReason, closeTimestamp) => {
@@ -12095,6 +12135,20 @@ class BacktestLogicPrivateService {
12095
12135
  // backtest() сам обработает scheduled signal: найдет активацию/отмену
12096
12136
  // и если активируется - продолжит с TP/SL мониторингом
12097
12137
  let backtestResult;
12138
+ let unScheduleOpen;
12139
+ {
12140
+ const { strategyName, exchangeName, frameName } = this.methodContextService.context;
12141
+ unScheduleOpen = backtestScheduleOpenSubject.filter((event) => {
12142
+ let isOk = true;
12143
+ {
12144
+ isOk = isOk && event.strategyName === strategyName;
12145
+ isOk = isOk && event.exchangeName === exchangeName;
12146
+ isOk = isOk && event.frameName === frameName;
12147
+ isOk = isOk && event.symbol === symbol;
12148
+ }
12149
+ return isOk;
12150
+ }).connect(async (tick) => await signalBacktestEmitter.next(tick));
12151
+ }
12098
12152
  try {
12099
12153
  backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
12100
12154
  strategyName: this.methodContextService.context.strategyName,
@@ -12113,6 +12167,9 @@ class BacktestLogicPrivateService {
12113
12167
  i++;
12114
12168
  continue;
12115
12169
  }
12170
+ finally {
12171
+ unScheduleOpen && unScheduleOpen();
12172
+ }
12116
12173
  this.loggerService.info("backtestLogicPrivateService scheduled signal closed", {
12117
12174
  symbol,
12118
12175
  signalId: backtestResult.signal.id,
package/build/index.mjs CHANGED
@@ -536,10 +536,19 @@ const activePingSubject = new Subject();
536
536
  * Used by StrategyReportService and StrategyMarkdownService for event logging and reporting.
537
537
  */
538
538
  const strategyCommitSubject = new Subject();
539
+ /**
540
+ * ClientStrategy::backtest using return instead of async iterator emitter.
541
+ * If signal was scheduled to open, emits when the signal is actually opened.
542
+ *
543
+ * Allows to yield IStrategyTickResultOpened in addition to IStrategyTickResultClosed | IStrategyTickResultCancelled for
544
+ * BacktestLogicPrivateService::*run
545
+ */
546
+ const backtestScheduleOpenSubject = new Subject();
539
547
 
540
548
  var emitters = /*#__PURE__*/Object.freeze({
541
549
  __proto__: null,
542
550
  activePingSubject: activePingSubject,
551
+ backtestScheduleOpenSubject: backtestScheduleOpenSubject,
543
552
  breakevenSubject: breakevenSubject,
544
553
  doneBacktestSubject: doneBacktestSubject,
545
554
  doneLiveSubject: doneLiveSubject,
@@ -4211,6 +4220,36 @@ const CALL_BREAKEVEN_CLEAR_FN = trycatch(beginTime(async (self, symbol, signal,
4211
4220
  errorEmitter.next(error);
4212
4221
  },
4213
4222
  });
4223
+ const CALL_BACKTEST_SCHEDULE_OPEN_FN = trycatch(beginTime(async (self, symbol, signal, timestamp, backtest) => {
4224
+ await ExecutionContextService.runInContext(async () => {
4225
+ backtestScheduleOpenSubject.next({
4226
+ action: "opened",
4227
+ signal: TO_PUBLIC_SIGNAL(signal),
4228
+ strategyName: self.params.method.context.strategyName,
4229
+ exchangeName: self.params.method.context.exchangeName,
4230
+ frameName: self.params.method.context.frameName,
4231
+ symbol: symbol,
4232
+ currentPrice: signal.priceOpen,
4233
+ backtest: true,
4234
+ createdAt: timestamp,
4235
+ });
4236
+ }, {
4237
+ when: new Date(timestamp),
4238
+ symbol: symbol,
4239
+ backtest: backtest,
4240
+ });
4241
+ }), {
4242
+ fallback: (error) => {
4243
+ const message = "ClientStrategy CALL_BACKTEST_SCHEDULE_OPEN_FN thrown";
4244
+ const payload = {
4245
+ error: errorData(error),
4246
+ message: getErrorMessage(error),
4247
+ };
4248
+ bt.loggerService.warn(message, payload);
4249
+ console.warn(message, payload);
4250
+ errorEmitter.next(error);
4251
+ },
4252
+ });
4214
4253
  const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
4215
4254
  const currentTime = self.params.execution.context.when.getTime();
4216
4255
  await CALL_SCHEDULE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentTime, self.params.execution.context.backtest);
@@ -4500,6 +4539,7 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
4500
4539
  await self.setPendingSignal(activatedSignal);
4501
4540
  await CALL_RISK_ADD_SIGNAL_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
4502
4541
  await CALL_OPEN_CALLBACKS_FN(self, self.params.execution.context.symbol, activatedSignal, activatedSignal.priceOpen, activationTime, self.params.execution.context.backtest);
4542
+ await CALL_BACKTEST_SCHEDULE_OPEN_FN(self, self.params.execution.context.symbol, activatedSignal, activationTime, self.params.execution.context.backtest);
4503
4543
  return true;
4504
4544
  };
4505
4545
  const CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN = async (self, signal, averagePrice, closeReason, closeTimestamp) => {
@@ -12075,6 +12115,20 @@ class BacktestLogicPrivateService {
12075
12115
  // backtest() сам обработает scheduled signal: найдет активацию/отмену
12076
12116
  // и если активируется - продолжит с TP/SL мониторингом
12077
12117
  let backtestResult;
12118
+ let unScheduleOpen;
12119
+ {
12120
+ const { strategyName, exchangeName, frameName } = this.methodContextService.context;
12121
+ unScheduleOpen = backtestScheduleOpenSubject.filter((event) => {
12122
+ let isOk = true;
12123
+ {
12124
+ isOk = isOk && event.strategyName === strategyName;
12125
+ isOk = isOk && event.exchangeName === exchangeName;
12126
+ isOk = isOk && event.frameName === frameName;
12127
+ isOk = isOk && event.symbol === symbol;
12128
+ }
12129
+ return isOk;
12130
+ }).connect(async (tick) => await signalBacktestEmitter.next(tick));
12131
+ }
12078
12132
  try {
12079
12133
  backtestResult = await this.strategyCoreService.backtest(symbol, candles, when, true, {
12080
12134
  strategyName: this.methodContextService.context.strategyName,
@@ -12093,6 +12147,9 @@ class BacktestLogicPrivateService {
12093
12147
  i++;
12094
12148
  continue;
12095
12149
  }
12150
+ finally {
12151
+ unScheduleOpen && unScheduleOpen();
12152
+ }
12096
12153
  this.loggerService.info("backtestLogicPrivateService scheduled signal closed", {
12097
12154
  symbol,
12098
12155
  signalId: backtestResult.signal.id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "2.2.6",
3
+ "version": "2.2.7",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -14734,8 +14734,17 @@ declare const activePingSubject: Subject<ActivePingContract>;
14734
14734
  * Used by StrategyReportService and StrategyMarkdownService for event logging and reporting.
14735
14735
  */
14736
14736
  declare const strategyCommitSubject: Subject<StrategyCommitContract>;
14737
+ /**
14738
+ * ClientStrategy::backtest using return instead of async iterator emitter.
14739
+ * If signal was scheduled to open, emits when the signal is actually opened.
14740
+ *
14741
+ * Allows to yield IStrategyTickResultOpened in addition to IStrategyTickResultClosed | IStrategyTickResultCancelled for
14742
+ * BacktestLogicPrivateService::*run
14743
+ */
14744
+ declare const backtestScheduleOpenSubject: Subject<IStrategyTickResultOpened>;
14737
14745
 
14738
14746
  declare const emitters_activePingSubject: typeof activePingSubject;
14747
+ declare const emitters_backtestScheduleOpenSubject: typeof backtestScheduleOpenSubject;
14739
14748
  declare const emitters_breakevenSubject: typeof breakevenSubject;
14740
14749
  declare const emitters_doneBacktestSubject: typeof doneBacktestSubject;
14741
14750
  declare const emitters_doneLiveSubject: typeof doneLiveSubject;
@@ -14758,7 +14767,7 @@ declare const emitters_walkerCompleteSubject: typeof walkerCompleteSubject;
14758
14767
  declare const emitters_walkerEmitter: typeof walkerEmitter;
14759
14768
  declare const emitters_walkerStopSubject: typeof walkerStopSubject;
14760
14769
  declare namespace emitters {
14761
- export { emitters_activePingSubject as activePingSubject, emitters_breakevenSubject as breakevenSubject, emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_exitEmitter as exitEmitter, emitters_partialLossSubject as partialLossSubject, emitters_partialProfitSubject as partialProfitSubject, emitters_performanceEmitter as performanceEmitter, emitters_progressBacktestEmitter as progressBacktestEmitter, emitters_progressWalkerEmitter as progressWalkerEmitter, emitters_riskSubject as riskSubject, emitters_schedulePingSubject as schedulePingSubject, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_strategyCommitSubject as strategyCommitSubject, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter, emitters_walkerStopSubject as walkerStopSubject };
14770
+ export { emitters_activePingSubject as activePingSubject, emitters_backtestScheduleOpenSubject as backtestScheduleOpenSubject, emitters_breakevenSubject as breakevenSubject, emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_exitEmitter as exitEmitter, emitters_partialLossSubject as partialLossSubject, emitters_partialProfitSubject as partialProfitSubject, emitters_performanceEmitter as performanceEmitter, emitters_progressBacktestEmitter as progressBacktestEmitter, emitters_progressWalkerEmitter as progressWalkerEmitter, emitters_riskSubject as riskSubject, emitters_schedulePingSubject as schedulePingSubject, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_strategyCommitSubject as strategyCommitSubject, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter, emitters_walkerStopSubject as walkerStopSubject };
14762
14771
  }
14763
14772
 
14764
14773
  /**