backtest-kit 1.4.1 → 1.4.3

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
@@ -1623,6 +1623,11 @@ const progressBacktestEmitter = new functoolsKit.Subject();
1623
1623
  * Emits progress updates during walker execution.
1624
1624
  */
1625
1625
  const progressWalkerEmitter = new functoolsKit.Subject();
1626
+ /**
1627
+ * Progress emitter for optimizer execution progress.
1628
+ * Emits progress updates during optimizer execution.
1629
+ */
1630
+ const progressOptimizerEmitter = new functoolsKit.Subject();
1626
1631
  /**
1627
1632
  * Performance emitter for execution metrics.
1628
1633
  * Emits performance metrics for profiling and bottleneck detection.
@@ -1669,6 +1674,7 @@ var emitters = /*#__PURE__*/Object.freeze({
1669
1674
  partialProfitSubject: partialProfitSubject,
1670
1675
  performanceEmitter: performanceEmitter,
1671
1676
  progressBacktestEmitter: progressBacktestEmitter,
1677
+ progressOptimizerEmitter: progressOptimizerEmitter,
1672
1678
  progressWalkerEmitter: progressWalkerEmitter,
1673
1679
  signalBacktestEmitter: signalBacktestEmitter,
1674
1680
  signalEmitter: signalEmitter,
@@ -9129,9 +9135,19 @@ const RESOLVE_PAGINATION_FN = async (fetch, filterData) => {
9129
9135
  */
9130
9136
  const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9131
9137
  const strategyList = [];
9138
+ const totalSources = self.params.rangeTrain.length * self.params.source.length;
9139
+ let processedSources = 0;
9132
9140
  for (const { startDate, endDate } of self.params.rangeTrain) {
9133
9141
  const messageList = [];
9134
9142
  for (const source of self.params.source) {
9143
+ // Emit progress event at the start of processing each source
9144
+ await self.params.onProgress({
9145
+ optimizerName: self.params.optimizerName,
9146
+ symbol,
9147
+ totalSources,
9148
+ processedSources,
9149
+ progress: totalSources > 0 ? processedSources / totalSources : 0,
9150
+ });
9135
9151
  if (typeof source === "function") {
9136
9152
  const data = await RESOLVE_PAGINATION_FN(source, {
9137
9153
  symbol,
@@ -9152,6 +9168,7 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9152
9168
  role: "assistant",
9153
9169
  content: assistantContent,
9154
9170
  });
9171
+ processedSources++;
9155
9172
  }
9156
9173
  else {
9157
9174
  const { fetch, name = DEFAULT_SOURCE_NAME, assistant = DEFAULT_ASSISTANT_FN, user = DEFAULT_USER_FN, } = source;
@@ -9174,6 +9191,7 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9174
9191
  role: "assistant",
9175
9192
  content: assistantContent,
9176
9193
  });
9194
+ processedSources++;
9177
9195
  }
9178
9196
  const name = "name" in source
9179
9197
  ? source.name || DEFAULT_SOURCE_NAME
@@ -9186,6 +9204,14 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9186
9204
  });
9187
9205
  }
9188
9206
  }
9207
+ // Emit final progress event (100%)
9208
+ await self.params.onProgress({
9209
+ optimizerName: self.params.optimizerName,
9210
+ symbol,
9211
+ totalSources,
9212
+ processedSources: totalSources,
9213
+ progress: 1.0,
9214
+ });
9189
9215
  if (self.params.callbacks?.onData) {
9190
9216
  await self.params.callbacks.onData(symbol, strategyList);
9191
9217
  }
@@ -9358,6 +9384,10 @@ class ClientOptimizer {
9358
9384
  }
9359
9385
  }
9360
9386
 
9387
+ /**
9388
+ * Callback function for emitting progress events to progressOptimizerEmitter.
9389
+ */
9390
+ const COMMIT_PROGRESS_FN = async (progress) => progressOptimizerEmitter.next(progress);
9361
9391
  /**
9362
9392
  * Service for creating and caching optimizer client instances.
9363
9393
  * Handles dependency injection and template merging.
@@ -9401,6 +9431,7 @@ class OptimizerConnectionService {
9401
9431
  return new ClientOptimizer({
9402
9432
  optimizerName,
9403
9433
  logger: this.loggerService,
9434
+ onProgress: COMMIT_PROGRESS_FN,
9404
9435
  getPrompt,
9405
9436
  rangeTest,
9406
9437
  rangeTrain,
@@ -11315,6 +11346,7 @@ const LISTEN_DONE_WALKER_METHOD_NAME = "event.listenDoneWalker";
11315
11346
  const LISTEN_DONE_WALKER_ONCE_METHOD_NAME = "event.listenDoneWalkerOnce";
11316
11347
  const LISTEN_PROGRESS_METHOD_NAME = "event.listenBacktestProgress";
11317
11348
  const LISTEN_PROGRESS_WALKER_METHOD_NAME = "event.listenWalkerProgress";
11349
+ const LISTEN_PROGRESS_OPTIMIZER_METHOD_NAME = "event.listenOptimizerProgress";
11318
11350
  const LISTEN_PERFORMANCE_METHOD_NAME = "event.listenPerformance";
11319
11351
  const LISTEN_WALKER_METHOD_NAME = "event.listenWalker";
11320
11352
  const LISTEN_WALKER_ONCE_METHOD_NAME = "event.listenWalkerOnce";
@@ -11765,6 +11797,34 @@ function listenWalkerProgress(fn) {
11765
11797
  backtest$1.loggerService.log(LISTEN_PROGRESS_WALKER_METHOD_NAME);
11766
11798
  return progressWalkerEmitter.subscribe(functoolsKit.queued(async (event) => fn(event)));
11767
11799
  }
11800
+ /**
11801
+ * Subscribes to optimizer progress events with queued async processing.
11802
+ *
11803
+ * Emits during optimizer execution to track data source processing progress.
11804
+ * Events are processed sequentially in order received, even if callback is async.
11805
+ * Uses queued wrapper to prevent concurrent execution of the callback.
11806
+ *
11807
+ * @param fn - Callback function to handle optimizer progress events
11808
+ * @returns Unsubscribe function to stop listening to events
11809
+ *
11810
+ * @example
11811
+ * ```typescript
11812
+ * import { listenOptimizerProgress } from "backtest-kit";
11813
+ *
11814
+ * const unsubscribe = listenOptimizerProgress((event) => {
11815
+ * console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
11816
+ * console.log(`${event.processedSources} / ${event.totalSources} sources`);
11817
+ * console.log(`Optimizer: ${event.optimizerName}, Symbol: ${event.symbol}`);
11818
+ * });
11819
+ *
11820
+ * // Later: stop listening
11821
+ * unsubscribe();
11822
+ * ```
11823
+ */
11824
+ function listenOptimizerProgress(fn) {
11825
+ backtest$1.loggerService.log(LISTEN_PROGRESS_OPTIMIZER_METHOD_NAME);
11826
+ return progressOptimizerEmitter.subscribe(functoolsKit.queued(async (event) => fn(event)));
11827
+ }
11768
11828
  /**
11769
11829
  * Subscribes to performance metric events with queued async processing.
11770
11830
  *
@@ -13571,7 +13631,89 @@ class PartialUtils {
13571
13631
  */
13572
13632
  const Partial = new PartialUtils();
13573
13633
 
13634
+ /**
13635
+ * Utility class containing predefined trading constants for take-profit and stop-loss levels.
13636
+ *
13637
+ * Based on Kelly Criterion with exponential risk decay.
13638
+ * Values represent percentage of distance traveled towards final TP/SL target.
13639
+ *
13640
+ * Example: If final TP is at +10% profit:
13641
+ * - TP_LEVEL1 (30) triggers when price reaches 30% of distance = +3% profit
13642
+ * - TP_LEVEL2 (60) triggers when price reaches 60% of distance = +6% profit
13643
+ * - TP_LEVEL3 (90) triggers when price reaches 90% of distance = +9% profit
13644
+ */
13645
+ class ConstantUtils {
13646
+ constructor() {
13647
+ /**
13648
+ * Take Profit Level 1 (Kelly-optimized early partial).
13649
+ * Triggers at 30% of distance to final TP target.
13650
+ * Lock in profit early, let rest run.
13651
+ */
13652
+ this.TP_LEVEL1 = 30;
13653
+ /**
13654
+ * Take Profit Level 2 (Kelly-optimized mid partial).
13655
+ * Triggers at 60% of distance to final TP target.
13656
+ * Secure majority of position while trend continues.
13657
+ */
13658
+ this.TP_LEVEL2 = 60;
13659
+ /**
13660
+ * Take Profit Level 3 (Kelly-optimized final partial).
13661
+ * Triggers at 90% of distance to final TP target.
13662
+ * Near-complete exit, minimal exposure remains.
13663
+ */
13664
+ this.TP_LEVEL3 = 90;
13665
+ /**
13666
+ * Stop Loss Level 1 (Kelly-optimized early warning).
13667
+ * Triggers at 40% of distance to final SL target.
13668
+ * Reduce exposure when setup weakens.
13669
+ */
13670
+ this.SL_LEVEL1 = 40;
13671
+ /**
13672
+ * Stop Loss Level 2 (Kelly-optimized final exit).
13673
+ * Triggers at 80% of distance to final SL target.
13674
+ * Exit remaining position before catastrophic loss.
13675
+ */
13676
+ this.SL_LEVEL2 = 80;
13677
+ }
13678
+ }
13679
+ /**
13680
+ * Global singleton instance of ConstantUtils.
13681
+ * Provides static-like access to predefined trading level constants.
13682
+ *
13683
+ * Kelly-optimized scaling strategy:
13684
+ * Profit side (pyramiding out):
13685
+ * - Close 33% at 30% progress (quick profit lock)
13686
+ * - Close 33% at 60% progress (secure gains)
13687
+ * - Close 34% at 90% progress (exit near target)
13688
+ *
13689
+ * Loss side (damage control):
13690
+ * - Close 50% at 40% progress (reduce risk early)
13691
+ * - Close 50% at 80% progress (exit before full stop)
13692
+ *
13693
+ * @example
13694
+ * ```typescript
13695
+ * // Final targets: TP at +10%, SL at -5%
13696
+ * listenPartialProfit(async (event) => {
13697
+ * // event.level emits: 10, 20, 30, 40, 50...
13698
+ * if (event.level === Constant.TP_LEVEL1) { await close(33); } // at +3% profit
13699
+ * if (event.level === Constant.TP_LEVEL2) { await close(33); } // at +6% profit
13700
+ * if (event.level === Constant.TP_LEVEL3) { await close(34); } // at +9% profit
13701
+ * });
13702
+ * ```
13703
+ *
13704
+ * @example
13705
+ * ```typescript
13706
+ * listenPartialLoss(async (event) => {
13707
+ * // event.level emits: 10, 20, 30, 40, 50...
13708
+ * if (event.level === Constant.SL_LEVEL1) { await close(50); } // at -2% loss
13709
+ * if (event.level === Constant.SL_LEVEL2) { await close(50); } // at -4% loss
13710
+ * });
13711
+ * ```
13712
+ */
13713
+ const Constant = new ConstantUtils();
13714
+
13574
13715
  exports.Backtest = Backtest;
13716
+ exports.Constant = Constant;
13575
13717
  exports.ExecutionContextService = ExecutionContextService;
13576
13718
  exports.Heat = Heat;
13577
13719
  exports.Live = Live;
@@ -13617,6 +13759,7 @@ exports.listenDoneLiveOnce = listenDoneLiveOnce;
13617
13759
  exports.listenDoneWalker = listenDoneWalker;
13618
13760
  exports.listenDoneWalkerOnce = listenDoneWalkerOnce;
13619
13761
  exports.listenError = listenError;
13762
+ exports.listenOptimizerProgress = listenOptimizerProgress;
13620
13763
  exports.listenPartialLoss = listenPartialLoss;
13621
13764
  exports.listenPartialLossOnce = listenPartialLossOnce;
13622
13765
  exports.listenPartialProfit = listenPartialProfit;
package/build/index.mjs CHANGED
@@ -1621,6 +1621,11 @@ const progressBacktestEmitter = new Subject();
1621
1621
  * Emits progress updates during walker execution.
1622
1622
  */
1623
1623
  const progressWalkerEmitter = new Subject();
1624
+ /**
1625
+ * Progress emitter for optimizer execution progress.
1626
+ * Emits progress updates during optimizer execution.
1627
+ */
1628
+ const progressOptimizerEmitter = new Subject();
1624
1629
  /**
1625
1630
  * Performance emitter for execution metrics.
1626
1631
  * Emits performance metrics for profiling and bottleneck detection.
@@ -1667,6 +1672,7 @@ var emitters = /*#__PURE__*/Object.freeze({
1667
1672
  partialProfitSubject: partialProfitSubject,
1668
1673
  performanceEmitter: performanceEmitter,
1669
1674
  progressBacktestEmitter: progressBacktestEmitter,
1675
+ progressOptimizerEmitter: progressOptimizerEmitter,
1670
1676
  progressWalkerEmitter: progressWalkerEmitter,
1671
1677
  signalBacktestEmitter: signalBacktestEmitter,
1672
1678
  signalEmitter: signalEmitter,
@@ -9127,9 +9133,19 @@ const RESOLVE_PAGINATION_FN = async (fetch, filterData) => {
9127
9133
  */
9128
9134
  const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9129
9135
  const strategyList = [];
9136
+ const totalSources = self.params.rangeTrain.length * self.params.source.length;
9137
+ let processedSources = 0;
9130
9138
  for (const { startDate, endDate } of self.params.rangeTrain) {
9131
9139
  const messageList = [];
9132
9140
  for (const source of self.params.source) {
9141
+ // Emit progress event at the start of processing each source
9142
+ await self.params.onProgress({
9143
+ optimizerName: self.params.optimizerName,
9144
+ symbol,
9145
+ totalSources,
9146
+ processedSources,
9147
+ progress: totalSources > 0 ? processedSources / totalSources : 0,
9148
+ });
9133
9149
  if (typeof source === "function") {
9134
9150
  const data = await RESOLVE_PAGINATION_FN(source, {
9135
9151
  symbol,
@@ -9150,6 +9166,7 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9150
9166
  role: "assistant",
9151
9167
  content: assistantContent,
9152
9168
  });
9169
+ processedSources++;
9153
9170
  }
9154
9171
  else {
9155
9172
  const { fetch, name = DEFAULT_SOURCE_NAME, assistant = DEFAULT_ASSISTANT_FN, user = DEFAULT_USER_FN, } = source;
@@ -9172,6 +9189,7 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9172
9189
  role: "assistant",
9173
9190
  content: assistantContent,
9174
9191
  });
9192
+ processedSources++;
9175
9193
  }
9176
9194
  const name = "name" in source
9177
9195
  ? source.name || DEFAULT_SOURCE_NAME
@@ -9184,6 +9202,14 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
9184
9202
  });
9185
9203
  }
9186
9204
  }
9205
+ // Emit final progress event (100%)
9206
+ await self.params.onProgress({
9207
+ optimizerName: self.params.optimizerName,
9208
+ symbol,
9209
+ totalSources,
9210
+ processedSources: totalSources,
9211
+ progress: 1.0,
9212
+ });
9187
9213
  if (self.params.callbacks?.onData) {
9188
9214
  await self.params.callbacks.onData(symbol, strategyList);
9189
9215
  }
@@ -9356,6 +9382,10 @@ class ClientOptimizer {
9356
9382
  }
9357
9383
  }
9358
9384
 
9385
+ /**
9386
+ * Callback function for emitting progress events to progressOptimizerEmitter.
9387
+ */
9388
+ const COMMIT_PROGRESS_FN = async (progress) => progressOptimizerEmitter.next(progress);
9359
9389
  /**
9360
9390
  * Service for creating and caching optimizer client instances.
9361
9391
  * Handles dependency injection and template merging.
@@ -9399,6 +9429,7 @@ class OptimizerConnectionService {
9399
9429
  return new ClientOptimizer({
9400
9430
  optimizerName,
9401
9431
  logger: this.loggerService,
9432
+ onProgress: COMMIT_PROGRESS_FN,
9402
9433
  getPrompt,
9403
9434
  rangeTest,
9404
9435
  rangeTrain,
@@ -11313,6 +11344,7 @@ const LISTEN_DONE_WALKER_METHOD_NAME = "event.listenDoneWalker";
11313
11344
  const LISTEN_DONE_WALKER_ONCE_METHOD_NAME = "event.listenDoneWalkerOnce";
11314
11345
  const LISTEN_PROGRESS_METHOD_NAME = "event.listenBacktestProgress";
11315
11346
  const LISTEN_PROGRESS_WALKER_METHOD_NAME = "event.listenWalkerProgress";
11347
+ const LISTEN_PROGRESS_OPTIMIZER_METHOD_NAME = "event.listenOptimizerProgress";
11316
11348
  const LISTEN_PERFORMANCE_METHOD_NAME = "event.listenPerformance";
11317
11349
  const LISTEN_WALKER_METHOD_NAME = "event.listenWalker";
11318
11350
  const LISTEN_WALKER_ONCE_METHOD_NAME = "event.listenWalkerOnce";
@@ -11763,6 +11795,34 @@ function listenWalkerProgress(fn) {
11763
11795
  backtest$1.loggerService.log(LISTEN_PROGRESS_WALKER_METHOD_NAME);
11764
11796
  return progressWalkerEmitter.subscribe(queued(async (event) => fn(event)));
11765
11797
  }
11798
+ /**
11799
+ * Subscribes to optimizer progress events with queued async processing.
11800
+ *
11801
+ * Emits during optimizer execution to track data source processing progress.
11802
+ * Events are processed sequentially in order received, even if callback is async.
11803
+ * Uses queued wrapper to prevent concurrent execution of the callback.
11804
+ *
11805
+ * @param fn - Callback function to handle optimizer progress events
11806
+ * @returns Unsubscribe function to stop listening to events
11807
+ *
11808
+ * @example
11809
+ * ```typescript
11810
+ * import { listenOptimizerProgress } from "backtest-kit";
11811
+ *
11812
+ * const unsubscribe = listenOptimizerProgress((event) => {
11813
+ * console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
11814
+ * console.log(`${event.processedSources} / ${event.totalSources} sources`);
11815
+ * console.log(`Optimizer: ${event.optimizerName}, Symbol: ${event.symbol}`);
11816
+ * });
11817
+ *
11818
+ * // Later: stop listening
11819
+ * unsubscribe();
11820
+ * ```
11821
+ */
11822
+ function listenOptimizerProgress(fn) {
11823
+ backtest$1.loggerService.log(LISTEN_PROGRESS_OPTIMIZER_METHOD_NAME);
11824
+ return progressOptimizerEmitter.subscribe(queued(async (event) => fn(event)));
11825
+ }
11766
11826
  /**
11767
11827
  * Subscribes to performance metric events with queued async processing.
11768
11828
  *
@@ -13569,4 +13629,85 @@ class PartialUtils {
13569
13629
  */
13570
13630
  const Partial = new PartialUtils();
13571
13631
 
13572
- export { Backtest, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
13632
+ /**
13633
+ * Utility class containing predefined trading constants for take-profit and stop-loss levels.
13634
+ *
13635
+ * Based on Kelly Criterion with exponential risk decay.
13636
+ * Values represent percentage of distance traveled towards final TP/SL target.
13637
+ *
13638
+ * Example: If final TP is at +10% profit:
13639
+ * - TP_LEVEL1 (30) triggers when price reaches 30% of distance = +3% profit
13640
+ * - TP_LEVEL2 (60) triggers when price reaches 60% of distance = +6% profit
13641
+ * - TP_LEVEL3 (90) triggers when price reaches 90% of distance = +9% profit
13642
+ */
13643
+ class ConstantUtils {
13644
+ constructor() {
13645
+ /**
13646
+ * Take Profit Level 1 (Kelly-optimized early partial).
13647
+ * Triggers at 30% of distance to final TP target.
13648
+ * Lock in profit early, let rest run.
13649
+ */
13650
+ this.TP_LEVEL1 = 30;
13651
+ /**
13652
+ * Take Profit Level 2 (Kelly-optimized mid partial).
13653
+ * Triggers at 60% of distance to final TP target.
13654
+ * Secure majority of position while trend continues.
13655
+ */
13656
+ this.TP_LEVEL2 = 60;
13657
+ /**
13658
+ * Take Profit Level 3 (Kelly-optimized final partial).
13659
+ * Triggers at 90% of distance to final TP target.
13660
+ * Near-complete exit, minimal exposure remains.
13661
+ */
13662
+ this.TP_LEVEL3 = 90;
13663
+ /**
13664
+ * Stop Loss Level 1 (Kelly-optimized early warning).
13665
+ * Triggers at 40% of distance to final SL target.
13666
+ * Reduce exposure when setup weakens.
13667
+ */
13668
+ this.SL_LEVEL1 = 40;
13669
+ /**
13670
+ * Stop Loss Level 2 (Kelly-optimized final exit).
13671
+ * Triggers at 80% of distance to final SL target.
13672
+ * Exit remaining position before catastrophic loss.
13673
+ */
13674
+ this.SL_LEVEL2 = 80;
13675
+ }
13676
+ }
13677
+ /**
13678
+ * Global singleton instance of ConstantUtils.
13679
+ * Provides static-like access to predefined trading level constants.
13680
+ *
13681
+ * Kelly-optimized scaling strategy:
13682
+ * Profit side (pyramiding out):
13683
+ * - Close 33% at 30% progress (quick profit lock)
13684
+ * - Close 33% at 60% progress (secure gains)
13685
+ * - Close 34% at 90% progress (exit near target)
13686
+ *
13687
+ * Loss side (damage control):
13688
+ * - Close 50% at 40% progress (reduce risk early)
13689
+ * - Close 50% at 80% progress (exit before full stop)
13690
+ *
13691
+ * @example
13692
+ * ```typescript
13693
+ * // Final targets: TP at +10%, SL at -5%
13694
+ * listenPartialProfit(async (event) => {
13695
+ * // event.level emits: 10, 20, 30, 40, 50...
13696
+ * if (event.level === Constant.TP_LEVEL1) { await close(33); } // at +3% profit
13697
+ * if (event.level === Constant.TP_LEVEL2) { await close(33); } // at +6% profit
13698
+ * if (event.level === Constant.TP_LEVEL3) { await close(34); } // at +9% profit
13699
+ * });
13700
+ * ```
13701
+ *
13702
+ * @example
13703
+ * ```typescript
13704
+ * listenPartialLoss(async (event) => {
13705
+ * // event.level emits: 10, 20, 30, 40, 50...
13706
+ * if (event.level === Constant.SL_LEVEL1) { await close(50); } // at -2% loss
13707
+ * if (event.level === Constant.SL_LEVEL2) { await close(50); } // at -4% loss
13708
+ * });
13709
+ * ```
13710
+ */
13711
+ const Constant = new ConstantUtils();
13712
+
13713
+ export { Backtest, Constant, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -1517,6 +1517,35 @@ interface MessageModel {
1517
1517
  content: string;
1518
1518
  }
1519
1519
 
1520
+ /**
1521
+ * Contract for optimizer progress events.
1522
+ *
1523
+ * Emitted during optimizer execution to track progress.
1524
+ * Contains information about total sources, processed sources, and completion percentage.
1525
+ *
1526
+ * @example
1527
+ * ```typescript
1528
+ * import { listenOptimizerProgress } from "backtest-kit";
1529
+ *
1530
+ * listenOptimizerProgress((event) => {
1531
+ * console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
1532
+ * console.log(`Processed: ${event.processedSources} / ${event.totalSources}`);
1533
+ * });
1534
+ * ```
1535
+ */
1536
+ interface ProgressOptimizerContract {
1537
+ /** optimizerName - Name of the optimizer being executed */
1538
+ optimizerName: string;
1539
+ /** symbol - Trading symbol (e.g., "BTCUSDT") */
1540
+ symbol: string;
1541
+ /** totalSources - Total number of sources to process */
1542
+ totalSources: number;
1543
+ /** processedSources - Number of sources processed so far */
1544
+ processedSources: number;
1545
+ /** progress - Completion percentage from 0.0 to 1.0 */
1546
+ progress: number;
1547
+ }
1548
+
1520
1549
  /**
1521
1550
  * Unique identifier for data rows in optimizer sources.
1522
1551
  * Can be either a string or numeric ID.
@@ -1844,6 +1873,11 @@ interface IOptimizerSchema {
1844
1873
  * @returns Strategy prompt/logic description
1845
1874
  */
1846
1875
  getPrompt: (symbol: string, messages: MessageModel[]) => string | Promise<string>;
1876
+ /**
1877
+ * Callback invoked to report progress during optimizer operations.
1878
+ * @param progress - Progress details including processed sources and percentage
1879
+ */
1880
+ onProgress(progress: ProgressOptimizerContract): void;
1847
1881
  /**
1848
1882
  * Optional custom template overrides.
1849
1883
  * If not provided, uses defaults from OptimizerTemplateService.
@@ -3208,6 +3242,31 @@ declare function listenBacktestProgress(fn: (event: ProgressBacktestContract) =>
3208
3242
  * ```
3209
3243
  */
3210
3244
  declare function listenWalkerProgress(fn: (event: ProgressWalkerContract) => void): () => void;
3245
+ /**
3246
+ * Subscribes to optimizer progress events with queued async processing.
3247
+ *
3248
+ * Emits during optimizer execution to track data source processing progress.
3249
+ * Events are processed sequentially in order received, even if callback is async.
3250
+ * Uses queued wrapper to prevent concurrent execution of the callback.
3251
+ *
3252
+ * @param fn - Callback function to handle optimizer progress events
3253
+ * @returns Unsubscribe function to stop listening to events
3254
+ *
3255
+ * @example
3256
+ * ```typescript
3257
+ * import { listenOptimizerProgress } from "backtest-kit";
3258
+ *
3259
+ * const unsubscribe = listenOptimizerProgress((event) => {
3260
+ * console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
3261
+ * console.log(`${event.processedSources} / ${event.totalSources} sources`);
3262
+ * console.log(`Optimizer: ${event.optimizerName}, Symbol: ${event.symbol}`);
3263
+ * });
3264
+ *
3265
+ * // Later: stop listening
3266
+ * unsubscribe();
3267
+ * ```
3268
+ */
3269
+ declare function listenOptimizerProgress(fn: (event: ProgressOptimizerContract) => void): () => void;
3211
3270
  /**
3212
3271
  * Subscribes to performance metric events with queued async processing.
3213
3272
  *
@@ -5975,6 +6034,85 @@ declare class PartialUtils {
5975
6034
  */
5976
6035
  declare const Partial$1: PartialUtils;
5977
6036
 
6037
+ /**
6038
+ * Utility class containing predefined trading constants for take-profit and stop-loss levels.
6039
+ *
6040
+ * Based on Kelly Criterion with exponential risk decay.
6041
+ * Values represent percentage of distance traveled towards final TP/SL target.
6042
+ *
6043
+ * Example: If final TP is at +10% profit:
6044
+ * - TP_LEVEL1 (30) triggers when price reaches 30% of distance = +3% profit
6045
+ * - TP_LEVEL2 (60) triggers when price reaches 60% of distance = +6% profit
6046
+ * - TP_LEVEL3 (90) triggers when price reaches 90% of distance = +9% profit
6047
+ */
6048
+ declare class ConstantUtils {
6049
+ /**
6050
+ * Take Profit Level 1 (Kelly-optimized early partial).
6051
+ * Triggers at 30% of distance to final TP target.
6052
+ * Lock in profit early, let rest run.
6053
+ */
6054
+ readonly TP_LEVEL1 = 30;
6055
+ /**
6056
+ * Take Profit Level 2 (Kelly-optimized mid partial).
6057
+ * Triggers at 60% of distance to final TP target.
6058
+ * Secure majority of position while trend continues.
6059
+ */
6060
+ readonly TP_LEVEL2 = 60;
6061
+ /**
6062
+ * Take Profit Level 3 (Kelly-optimized final partial).
6063
+ * Triggers at 90% of distance to final TP target.
6064
+ * Near-complete exit, minimal exposure remains.
6065
+ */
6066
+ readonly TP_LEVEL3 = 90;
6067
+ /**
6068
+ * Stop Loss Level 1 (Kelly-optimized early warning).
6069
+ * Triggers at 40% of distance to final SL target.
6070
+ * Reduce exposure when setup weakens.
6071
+ */
6072
+ readonly SL_LEVEL1 = 40;
6073
+ /**
6074
+ * Stop Loss Level 2 (Kelly-optimized final exit).
6075
+ * Triggers at 80% of distance to final SL target.
6076
+ * Exit remaining position before catastrophic loss.
6077
+ */
6078
+ readonly SL_LEVEL2 = 80;
6079
+ }
6080
+ /**
6081
+ * Global singleton instance of ConstantUtils.
6082
+ * Provides static-like access to predefined trading level constants.
6083
+ *
6084
+ * Kelly-optimized scaling strategy:
6085
+ * Profit side (pyramiding out):
6086
+ * - Close 33% at 30% progress (quick profit lock)
6087
+ * - Close 33% at 60% progress (secure gains)
6088
+ * - Close 34% at 90% progress (exit near target)
6089
+ *
6090
+ * Loss side (damage control):
6091
+ * - Close 50% at 40% progress (reduce risk early)
6092
+ * - Close 50% at 80% progress (exit before full stop)
6093
+ *
6094
+ * @example
6095
+ * ```typescript
6096
+ * // Final targets: TP at +10%, SL at -5%
6097
+ * listenPartialProfit(async (event) => {
6098
+ * // event.level emits: 10, 20, 30, 40, 50...
6099
+ * if (event.level === Constant.TP_LEVEL1) { await close(33); } // at +3% profit
6100
+ * if (event.level === Constant.TP_LEVEL2) { await close(33); } // at +6% profit
6101
+ * if (event.level === Constant.TP_LEVEL3) { await close(34); } // at +9% profit
6102
+ * });
6103
+ * ```
6104
+ *
6105
+ * @example
6106
+ * ```typescript
6107
+ * listenPartialLoss(async (event) => {
6108
+ * // event.level emits: 10, 20, 30, 40, 50...
6109
+ * if (event.level === Constant.SL_LEVEL1) { await close(50); } // at -2% loss
6110
+ * if (event.level === Constant.SL_LEVEL2) { await close(50); } // at -4% loss
6111
+ * });
6112
+ * ```
6113
+ */
6114
+ declare const Constant: ConstantUtils;
6115
+
5978
6116
  /**
5979
6117
  * Global signal emitter for all trading events (live + backtest).
5980
6118
  * Emits all signal events regardless of execution mode.
@@ -6020,6 +6158,11 @@ declare const progressBacktestEmitter: Subject<ProgressBacktestContract>;
6020
6158
  * Emits progress updates during walker execution.
6021
6159
  */
6022
6160
  declare const progressWalkerEmitter: Subject<ProgressWalkerContract>;
6161
+ /**
6162
+ * Progress emitter for optimizer execution progress.
6163
+ * Emits progress updates during optimizer execution.
6164
+ */
6165
+ declare const progressOptimizerEmitter: Subject<ProgressOptimizerContract>;
6023
6166
  /**
6024
6167
  * Performance emitter for execution metrics.
6025
6168
  * Emits performance metrics for profiling and bottleneck detection.
@@ -6064,6 +6207,7 @@ declare const emitters_partialLossSubject: typeof partialLossSubject;
6064
6207
  declare const emitters_partialProfitSubject: typeof partialProfitSubject;
6065
6208
  declare const emitters_performanceEmitter: typeof performanceEmitter;
6066
6209
  declare const emitters_progressBacktestEmitter: typeof progressBacktestEmitter;
6210
+ declare const emitters_progressOptimizerEmitter: typeof progressOptimizerEmitter;
6067
6211
  declare const emitters_progressWalkerEmitter: typeof progressWalkerEmitter;
6068
6212
  declare const emitters_signalBacktestEmitter: typeof signalBacktestEmitter;
6069
6213
  declare const emitters_signalEmitter: typeof signalEmitter;
@@ -6073,7 +6217,7 @@ declare const emitters_walkerCompleteSubject: typeof walkerCompleteSubject;
6073
6217
  declare const emitters_walkerEmitter: typeof walkerEmitter;
6074
6218
  declare const emitters_walkerStopSubject: typeof walkerStopSubject;
6075
6219
  declare namespace emitters {
6076
- export { emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_partialLossSubject as partialLossSubject, emitters_partialProfitSubject as partialProfitSubject, emitters_performanceEmitter as performanceEmitter, emitters_progressBacktestEmitter as progressBacktestEmitter, emitters_progressWalkerEmitter as progressWalkerEmitter, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter, emitters_walkerStopSubject as walkerStopSubject };
6220
+ export { emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_partialLossSubject as partialLossSubject, emitters_partialProfitSubject as partialProfitSubject, emitters_performanceEmitter as performanceEmitter, emitters_progressBacktestEmitter as progressBacktestEmitter, emitters_progressOptimizerEmitter as progressOptimizerEmitter, emitters_progressWalkerEmitter as progressWalkerEmitter, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter, emitters_walkerStopSubject as walkerStopSubject };
6077
6221
  }
6078
6222
 
6079
6223
  /**
@@ -8540,4 +8684,4 @@ declare const backtest: {
8540
8684
  loggerService: LoggerService;
8541
8685
  };
8542
8686
 
8543
- export { Backtest, type BacktestStatistics, type CandleInterval, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IHeatmapStatistics, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatistics, type MessageModel, type MessageRole, MethodContextService, Optimizer, Partial$1 as Partial, type PartialData, type PartialLossContract, type PartialProfitContract, type PartialStatistics, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressWalkerContract, type RiskData, Schedule, type ScheduleData, type ScheduleStatistics, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, Walker, type WalkerContract, type WalkerMetric, type WalkerStatistics, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
8687
+ export { Backtest, type BacktestStatistics, type CandleInterval, Constant, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IHeatmapStatistics, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatistics, type MessageModel, type MessageRole, MethodContextService, Optimizer, Partial$1 as Partial, type PartialData, type PartialLossContract, type PartialProfitContract, type PartialStatistics, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressOptimizerContract, type ProgressWalkerContract, type RiskData, Schedule, type ScheduleData, type ScheduleStatistics, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, Walker, type WalkerContract, type WalkerMetric, type WalkerStatistics, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };