backtest-kit 2.2.17 → 2.2.18

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
@@ -2867,73 +2867,78 @@ const PROCESS_COMMIT_QUEUE_FN = async (self, timestamp) => {
2867
2867
  return;
2868
2868
  }
2869
2869
  const queue = self._commitQueue;
2870
- self._commitQueue = [];
2870
+ {
2871
+ self._commitQueue = [];
2872
+ }
2871
2873
  for (const commit of queue) {
2872
- switch (commit.action) {
2873
- case "partial-profit":
2874
- await CALL_COMMIT_FN(self, {
2875
- action: "partial-profit",
2876
- symbol: commit.symbol,
2877
- strategyName: self.params.strategyName,
2878
- exchangeName: self.params.exchangeName,
2879
- frameName: self.params.frameName,
2880
- backtest: commit.backtest,
2881
- percentToClose: commit.percentToClose,
2882
- currentPrice: commit.currentPrice,
2883
- timestamp,
2884
- });
2885
- break;
2886
- case "partial-loss":
2887
- await CALL_COMMIT_FN(self, {
2888
- action: "partial-loss",
2889
- symbol: commit.symbol,
2890
- strategyName: self.params.strategyName,
2891
- exchangeName: self.params.exchangeName,
2892
- frameName: self.params.frameName,
2893
- backtest: commit.backtest,
2894
- percentToClose: commit.percentToClose,
2895
- currentPrice: commit.currentPrice,
2896
- timestamp,
2897
- });
2898
- break;
2899
- case "breakeven":
2900
- await CALL_COMMIT_FN(self, {
2901
- action: "breakeven",
2902
- symbol: commit.symbol,
2903
- strategyName: self.params.strategyName,
2904
- exchangeName: self.params.exchangeName,
2905
- frameName: self.params.frameName,
2906
- backtest: commit.backtest,
2907
- currentPrice: commit.currentPrice,
2908
- timestamp,
2909
- });
2910
- break;
2911
- case "trailing-stop":
2912
- await CALL_COMMIT_FN(self, {
2913
- action: "trailing-stop",
2914
- symbol: commit.symbol,
2915
- strategyName: self.params.strategyName,
2916
- exchangeName: self.params.exchangeName,
2917
- frameName: self.params.frameName,
2918
- backtest: commit.backtest,
2919
- percentShift: commit.percentShift,
2920
- currentPrice: commit.currentPrice,
2921
- timestamp,
2922
- });
2923
- break;
2924
- case "trailing-take":
2925
- await CALL_COMMIT_FN(self, {
2926
- action: "trailing-take",
2927
- symbol: commit.symbol,
2928
- strategyName: self.params.strategyName,
2929
- exchangeName: self.params.exchangeName,
2930
- frameName: self.params.frameName,
2931
- backtest: commit.backtest,
2932
- percentShift: commit.percentShift,
2933
- currentPrice: commit.currentPrice,
2934
- timestamp,
2935
- });
2936
- break;
2874
+ if (commit.action === "partial-profit") {
2875
+ await CALL_COMMIT_FN(self, {
2876
+ action: "partial-profit",
2877
+ symbol: commit.symbol,
2878
+ strategyName: self.params.strategyName,
2879
+ exchangeName: self.params.exchangeName,
2880
+ frameName: self.params.frameName,
2881
+ backtest: commit.backtest,
2882
+ percentToClose: commit.percentToClose,
2883
+ currentPrice: commit.currentPrice,
2884
+ timestamp,
2885
+ });
2886
+ continue;
2887
+ }
2888
+ if (commit.action === "partial-loss") {
2889
+ await CALL_COMMIT_FN(self, {
2890
+ action: "partial-loss",
2891
+ symbol: commit.symbol,
2892
+ strategyName: self.params.strategyName,
2893
+ exchangeName: self.params.exchangeName,
2894
+ frameName: self.params.frameName,
2895
+ backtest: commit.backtest,
2896
+ percentToClose: commit.percentToClose,
2897
+ currentPrice: commit.currentPrice,
2898
+ timestamp,
2899
+ });
2900
+ continue;
2901
+ }
2902
+ if (commit.action === "breakeven") {
2903
+ await CALL_COMMIT_FN(self, {
2904
+ action: "breakeven",
2905
+ symbol: commit.symbol,
2906
+ strategyName: self.params.strategyName,
2907
+ exchangeName: self.params.exchangeName,
2908
+ frameName: self.params.frameName,
2909
+ backtest: commit.backtest,
2910
+ currentPrice: commit.currentPrice,
2911
+ timestamp,
2912
+ });
2913
+ continue;
2914
+ }
2915
+ if (commit.action === "trailing-stop") {
2916
+ await CALL_COMMIT_FN(self, {
2917
+ action: "trailing-stop",
2918
+ symbol: commit.symbol,
2919
+ strategyName: self.params.strategyName,
2920
+ exchangeName: self.params.exchangeName,
2921
+ frameName: self.params.frameName,
2922
+ backtest: commit.backtest,
2923
+ percentShift: commit.percentShift,
2924
+ currentPrice: commit.currentPrice,
2925
+ timestamp,
2926
+ });
2927
+ continue;
2928
+ }
2929
+ if (commit.action === "trailing-take") {
2930
+ await CALL_COMMIT_FN(self, {
2931
+ action: "trailing-take",
2932
+ symbol: commit.symbol,
2933
+ strategyName: self.params.strategyName,
2934
+ exchangeName: self.params.exchangeName,
2935
+ frameName: self.params.frameName,
2936
+ backtest: commit.backtest,
2937
+ percentShift: commit.percentShift,
2938
+ currentPrice: commit.currentPrice,
2939
+ timestamp,
2940
+ });
2941
+ continue;
2937
2942
  }
2938
2943
  }
2939
2944
  };
@@ -23626,7 +23631,7 @@ class RiskReportService {
23626
23631
  strategyName: data.strategyName,
23627
23632
  exchangeName: data.exchangeName,
23628
23633
  frameName: data.frameName,
23629
- signalId: "",
23634
+ signalId: data.pendingSignal?.id || "",
23630
23635
  walkerName: "",
23631
23636
  });
23632
23637
  };
@@ -31617,53 +31622,64 @@ class ConstantUtils {
31617
31622
  const Constant = new ConstantUtils();
31618
31623
 
31619
31624
  const MAX_SIGNALS = 25;
31620
- const STORAGE_BACKTEST_METHOD_NAME_WAIT_FOR_INIT = "StorageBacktestUtils.waitForInit";
31621
- const STORAGE_BACKTEST_METHOD_NAME_UPDATE_STORAGE = "StorageBacktestUtils._updateStorage";
31622
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_OPENED = "StorageBacktestUtils.handleOpened";
31623
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CLOSED = "StorageBacktestUtils.handleClosed";
31624
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED = "StorageBacktestUtils.handleScheduled";
31625
- const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CANCELLED = "StorageBacktestUtils.handleCancelled";
31626
- const STORAGE_BACKTEST_METHOD_NAME_FIND_BY_ID = "StorageBacktestUtils.findById";
31627
- const STORAGE_BACKTEST_METHOD_NAME_LIST = "StorageBacktestUtils.list";
31628
- const STORAGE_LIVE_METHOD_NAME_WAIT_FOR_INIT = "StorageLiveUtils.waitForInit";
31629
- const STORAGE_LIVE_METHOD_NAME_UPDATE_STORAGE = "StorageLiveUtils._updateStorage";
31630
- const STORAGE_LIVE_METHOD_NAME_HANDLE_OPENED = "StorageLiveUtils.handleOpened";
31631
- const STORAGE_LIVE_METHOD_NAME_HANDLE_CLOSED = "StorageLiveUtils.handleClosed";
31632
- const STORAGE_LIVE_METHOD_NAME_HANDLE_SCHEDULED = "StorageLiveUtils.handleScheduled";
31633
- const STORAGE_LIVE_METHOD_NAME_HANDLE_CANCELLED = "StorageLiveUtils.handleCancelled";
31634
- const STORAGE_LIVE_METHOD_NAME_FIND_BY_ID = "StorageLiveUtils.findById";
31635
- const STORAGE_LIVE_METHOD_NAME_LIST = "StorageLiveUtils.list";
31625
+ const STORAGE_BACKTEST_METHOD_NAME_WAIT_FOR_INIT = "StoragePersistBacktestUtils.waitForInit";
31626
+ const STORAGE_BACKTEST_METHOD_NAME_UPDATE_STORAGE = "StoragePersistBacktestUtils._updateStorage";
31627
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_OPENED = "StoragePersistBacktestUtils.handleOpened";
31628
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CLOSED = "StoragePersistBacktestUtils.handleClosed";
31629
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED = "StoragePersistBacktestUtils.handleScheduled";
31630
+ const STORAGE_BACKTEST_METHOD_NAME_HANDLE_CANCELLED = "StoragePersistBacktestUtils.handleCancelled";
31631
+ const STORAGE_BACKTEST_METHOD_NAME_FIND_BY_ID = "StoragePersistBacktestUtils.findById";
31632
+ const STORAGE_BACKTEST_METHOD_NAME_LIST = "StoragePersistBacktestUtils.list";
31633
+ const STORAGE_LIVE_METHOD_NAME_WAIT_FOR_INIT = "StoragePersistLiveUtils.waitForInit";
31634
+ const STORAGE_LIVE_METHOD_NAME_UPDATE_STORAGE = "StoragePersistLiveUtils._updateStorage";
31635
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_OPENED = "StoragePersistLiveUtils.handleOpened";
31636
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_CLOSED = "StoragePersistLiveUtils.handleClosed";
31637
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_SCHEDULED = "StoragePersistLiveUtils.handleScheduled";
31638
+ const STORAGE_LIVE_METHOD_NAME_HANDLE_CANCELLED = "StoragePersistLiveUtils.handleCancelled";
31639
+ const STORAGE_LIVE_METHOD_NAME_FIND_BY_ID = "StoragePersistLiveUtils.findById";
31640
+ const STORAGE_LIVE_METHOD_NAME_LIST = "StoragePersistLiveUtils.list";
31641
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_OPENED = "StorageMemoryBacktestUtils.handleOpened";
31642
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CLOSED = "StorageMemoryBacktestUtils.handleClosed";
31643
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED = "StorageMemoryBacktestUtils.handleScheduled";
31644
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CANCELLED = "StorageMemoryBacktestUtils.handleCancelled";
31645
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_FIND_BY_ID = "StorageMemoryBacktestUtils.findById";
31646
+ const STORAGE_MEMORY_BACKTEST_METHOD_NAME_LIST = "StorageMemoryBacktestUtils.list";
31647
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_OPENED = "StorageMemoryLiveUtils.handleOpened";
31648
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CLOSED = "StorageMemoryLiveUtils.handleClosed";
31649
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_SCHEDULED = "StorageMemoryLiveUtils.handleScheduled";
31650
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CANCELLED = "StorageMemoryLiveUtils.handleCancelled";
31651
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_FIND_BY_ID = "StorageMemoryLiveUtils.findById";
31652
+ const STORAGE_MEMORY_LIVE_METHOD_NAME_LIST = "StorageMemoryLiveUtils.list";
31636
31653
  const STORAGE_ADAPTER_METHOD_NAME_ENABLE = "StorageAdapter.enable";
31637
31654
  const STORAGE_ADAPTER_METHOD_NAME_DISABLE = "StorageAdapter.disable";
31638
31655
  const STORAGE_ADAPTER_METHOD_NAME_FIND_SIGNAL_BY_ID = "StorageAdapter.findSignalById";
31639
31656
  const STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_BACKTEST = "StorageAdapter.listSignalBacktest";
31640
31657
  const STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_LIVE = "StorageAdapter.listSignalLive";
31658
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER = "StorageBacktestAdapter.useStorageAdapter";
31659
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY = "StorageBacktestAdapter.useDummy";
31660
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST = "StorageBacktestAdapter.usePersist";
31661
+ const STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY = "StorageBacktestAdapter.useMemory";
31662
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER = "StorageLiveAdapter.useStorageAdapter";
31663
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY = "StorageLiveAdapter.useDummy";
31664
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST = "StorageLiveAdapter.usePersist";
31665
+ const STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY = "StorageLiveAdapter.useMemory";
31641
31666
  /**
31642
- * Utility class for managing backtest signal history.
31643
- *
31644
- * Stores trading signal history for admin dashboard display during backtesting
31645
- * with automatic initialization, deduplication, and storage limits.
31646
- *
31647
- * @example
31648
- * ```typescript
31649
- * import { StorageBacktestUtils } from "./classes/Storage";
31667
+ * Persistent storage adapter for backtest signals.
31650
31668
  *
31651
- * const storage = new StorageBacktestUtils();
31652
- *
31653
- * // Handle signal events
31654
- * await storage.handleOpened(tickResult);
31655
- * await storage.handleClosed(tickResult);
31669
+ * Features:
31670
+ * - Persists signals to disk using PersistStorageAdapter
31671
+ * - Lazy initialization with singleshot pattern
31672
+ * - Maintains up to MAX_SIGNALS (25) most recent signals
31673
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
31674
+ * - Prevents duplicate updates based on timestamp comparison
31656
31675
  *
31657
- * // Query signals
31658
- * const signal = await storage.findById("signal-123");
31659
- * const allSignals = await storage.list();
31660
- * ```
31676
+ * Use this adapter (default) for backtest signal persistence across sessions.
31661
31677
  */
31662
- class StorageBacktestUtils {
31678
+ class StoragePersistBacktestUtils {
31663
31679
  constructor() {
31664
31680
  /**
31665
- * Initializes storage by loading existing signal history from persist layer.
31666
- * Uses singleshot to ensure initialization happens only once.
31681
+ * Singleshot initialization function that loads signals from disk.
31682
+ * Protected by singleshot to ensure one-time execution.
31667
31683
  */
31668
31684
  this.waitForInit = functoolsKit.singleshot(async () => {
31669
31685
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_WAIT_FOR_INIT);
@@ -31675,9 +31691,8 @@ class StorageBacktestUtils {
31675
31691
  });
31676
31692
  /**
31677
31693
  * Handles signal opened event.
31678
- *
31679
- * @param tick - Tick result containing opened signal data
31680
- * @returns Promise resolving when storage is updated
31694
+ * Updates storage with opened status if not stale.
31695
+ * @param tick - The opened signal tick data
31681
31696
  */
31682
31697
  this.handleOpened = async (tick) => {
31683
31698
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_OPENED, {
@@ -31699,9 +31714,8 @@ class StorageBacktestUtils {
31699
31714
  };
31700
31715
  /**
31701
31716
  * Handles signal closed event.
31702
- *
31703
- * @param tick - Tick result containing closed signal data
31704
- * @returns Promise resolving when storage is updated
31717
+ * Updates storage with closed status and PnL if not stale.
31718
+ * @param tick - The closed signal tick data
31705
31719
  */
31706
31720
  this.handleClosed = async (tick) => {
31707
31721
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_CLOSED, {
@@ -31724,9 +31738,8 @@ class StorageBacktestUtils {
31724
31738
  };
31725
31739
  /**
31726
31740
  * Handles signal scheduled event.
31727
- *
31728
- * @param tick - Tick result containing scheduled signal data
31729
- * @returns Promise resolving when storage is updated
31741
+ * Updates storage with scheduled status if not stale.
31742
+ * @param tick - The scheduled signal tick data
31730
31743
  */
31731
31744
  this.handleScheduled = async (tick) => {
31732
31745
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED, {
@@ -31748,9 +31761,8 @@ class StorageBacktestUtils {
31748
31761
  };
31749
31762
  /**
31750
31763
  * Handles signal cancelled event.
31751
- *
31752
- * @param tick - Tick result containing cancelled signal data
31753
- * @returns Promise resolving when storage is updated
31764
+ * Updates storage with cancelled status if not stale.
31765
+ * @param tick - The cancelled signal tick data
31754
31766
  */
31755
31767
  this.handleCancelled = async (tick) => {
31756
31768
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_HANDLE_CANCELLED, {
@@ -31771,10 +31783,9 @@ class StorageBacktestUtils {
31771
31783
  await this._updateStorage();
31772
31784
  };
31773
31785
  /**
31774
- * Finds a signal by its unique identifier.
31775
- *
31776
- * @param id - Signal identifier
31777
- * @returns Promise resolving to signal row or null if not found
31786
+ * Finds a signal by its ID.
31787
+ * @param id - The signal ID to search for
31788
+ * @returns The signal row or null if not found
31778
31789
  */
31779
31790
  this.findById = async (id) => {
31780
31791
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_FIND_BY_ID, { id });
@@ -31782,9 +31793,8 @@ class StorageBacktestUtils {
31782
31793
  return this._signals.get(id) ?? null;
31783
31794
  };
31784
31795
  /**
31785
- * Lists all stored backtest signals.
31786
- *
31787
- * @returns Promise resolving to array of signal rows
31796
+ * Lists all stored signals.
31797
+ * @returns Array of all signal rows
31788
31798
  */
31789
31799
  this.list = async () => {
31790
31800
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_LIST);
@@ -31793,15 +31803,14 @@ class StorageBacktestUtils {
31793
31803
  };
31794
31804
  }
31795
31805
  /**
31796
- * Persists current signal history to storage.
31797
- * Sorts by priority and limits to MAX_SIGNALS entries.
31798
- *
31799
- * @throws Error if storage not initialized
31806
+ * Persists the current signal map to disk storage.
31807
+ * Sorts signals by priority and keeps only the most recent MAX_SIGNALS.
31808
+ * @throws Error if not initialized
31800
31809
  */
31801
31810
  async _updateStorage() {
31802
31811
  bt.loggerService.info(STORAGE_BACKTEST_METHOD_NAME_UPDATE_STORAGE);
31803
31812
  if (!this._signals) {
31804
- throw new Error("StorageBacktestUtils not initialized. Call waitForInit first.");
31813
+ throw new Error("StoragePersistBacktestUtils not initialized. Call waitForInit first.");
31805
31814
  }
31806
31815
  const signalList = Array.from(this._signals.values());
31807
31816
  signalList.sort((a, b) => a.priority - b.priority);
@@ -31809,31 +31818,190 @@ class StorageBacktestUtils {
31809
31818
  }
31810
31819
  }
31811
31820
  /**
31812
- * Utility class for managing live trading signal history.
31821
+ * In-memory storage adapter for backtest signals.
31813
31822
  *
31814
- * Stores trading signal history for admin dashboard display during live trading
31815
- * with automatic initialization, deduplication, and storage limits.
31823
+ * Features:
31824
+ * - Stores signals in memory only (no persistence)
31825
+ * - Fast read/write operations
31826
+ * - Data is lost when application restarts
31827
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
31828
+ * - Prevents duplicate updates based on timestamp comparison
31816
31829
  *
31817
- * @example
31818
- * ```typescript
31819
- * import { StorageLiveUtils } from "./classes/Storage";
31830
+ * Use this adapter for testing or when persistence is not required.
31831
+ */
31832
+ class StorageMemoryBacktestUtils {
31833
+ constructor() {
31834
+ /** Map of signal IDs to signal rows */
31835
+ this._signals = new Map();
31836
+ /**
31837
+ * Handles signal opened event.
31838
+ * Updates in-memory storage with opened status if not stale.
31839
+ * @param tick - The opened signal tick data
31840
+ */
31841
+ this.handleOpened = async (tick) => {
31842
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_OPENED, {
31843
+ signalId: tick.signal.id,
31844
+ });
31845
+ const lastStorage = this._signals.get(tick.signal.id);
31846
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
31847
+ return;
31848
+ }
31849
+ this._signals.set(tick.signal.id, {
31850
+ ...tick.signal,
31851
+ status: "opened",
31852
+ priority: Date.now(),
31853
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
31854
+ updatedAt: tick.createdAt,
31855
+ });
31856
+ };
31857
+ /**
31858
+ * Handles signal closed event.
31859
+ * Updates in-memory storage with closed status and PnL if not stale.
31860
+ * @param tick - The closed signal tick data
31861
+ */
31862
+ this.handleClosed = async (tick) => {
31863
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CLOSED, {
31864
+ signalId: tick.signal.id,
31865
+ });
31866
+ const lastStorage = this._signals.get(tick.signal.id);
31867
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
31868
+ return;
31869
+ }
31870
+ this._signals.set(tick.signal.id, {
31871
+ ...tick.signal,
31872
+ status: "closed",
31873
+ priority: Date.now(),
31874
+ pnl: tick.pnl,
31875
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
31876
+ updatedAt: tick.createdAt,
31877
+ });
31878
+ };
31879
+ /**
31880
+ * Handles signal scheduled event.
31881
+ * Updates in-memory storage with scheduled status if not stale.
31882
+ * @param tick - The scheduled signal tick data
31883
+ */
31884
+ this.handleScheduled = async (tick) => {
31885
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SCHEDULED, {
31886
+ signalId: tick.signal.id,
31887
+ });
31888
+ const lastStorage = this._signals.get(tick.signal.id);
31889
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
31890
+ return;
31891
+ }
31892
+ this._signals.set(tick.signal.id, {
31893
+ ...tick.signal,
31894
+ status: "scheduled",
31895
+ priority: Date.now(),
31896
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
31897
+ updatedAt: tick.createdAt,
31898
+ });
31899
+ };
31900
+ /**
31901
+ * Handles signal cancelled event.
31902
+ * Updates in-memory storage with cancelled status if not stale.
31903
+ * @param tick - The cancelled signal tick data
31904
+ */
31905
+ this.handleCancelled = async (tick) => {
31906
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_HANDLE_CANCELLED, {
31907
+ signalId: tick.signal.id,
31908
+ });
31909
+ const lastStorage = this._signals.get(tick.signal.id);
31910
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
31911
+ return;
31912
+ }
31913
+ this._signals.set(tick.signal.id, {
31914
+ ...tick.signal,
31915
+ status: "cancelled",
31916
+ priority: Date.now(),
31917
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
31918
+ updatedAt: tick.createdAt,
31919
+ });
31920
+ };
31921
+ /**
31922
+ * Finds a signal by its ID.
31923
+ * @param id - The signal ID to search for
31924
+ * @returns The signal row or null if not found
31925
+ */
31926
+ this.findById = async (id) => {
31927
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_FIND_BY_ID, { id });
31928
+ return this._signals.get(id) ?? null;
31929
+ };
31930
+ /**
31931
+ * Lists all stored signals.
31932
+ * @returns Array of all signal rows
31933
+ */
31934
+ this.list = async () => {
31935
+ bt.loggerService.info(STORAGE_MEMORY_BACKTEST_METHOD_NAME_LIST);
31936
+ return Array.from(this._signals.values());
31937
+ };
31938
+ }
31939
+ }
31940
+ /**
31941
+ * Dummy storage adapter for backtest signals that discards all writes.
31942
+ *
31943
+ * Features:
31944
+ * - No-op implementation for all methods
31945
+ * - findById always returns null
31946
+ * - list always returns empty array
31820
31947
  *
31821
- * const storage = new StorageLiveUtils();
31948
+ * Use this adapter to disable backtest signal storage completely.
31949
+ */
31950
+ class StorageDummyBacktestUtils {
31951
+ constructor() {
31952
+ /**
31953
+ * No-op handler for signal opened event.
31954
+ */
31955
+ this.handleOpened = async () => {
31956
+ };
31957
+ /**
31958
+ * No-op handler for signal closed event.
31959
+ */
31960
+ this.handleClosed = async () => {
31961
+ };
31962
+ /**
31963
+ * No-op handler for signal scheduled event.
31964
+ */
31965
+ this.handleScheduled = async () => {
31966
+ };
31967
+ /**
31968
+ * No-op handler for signal cancelled event.
31969
+ */
31970
+ this.handleCancelled = async () => {
31971
+ };
31972
+ /**
31973
+ * Always returns null (no storage).
31974
+ * @returns null
31975
+ */
31976
+ this.findById = async () => {
31977
+ return null;
31978
+ };
31979
+ /**
31980
+ * Always returns empty array (no storage).
31981
+ * @returns Empty array
31982
+ */
31983
+ this.list = async () => {
31984
+ return [];
31985
+ };
31986
+ }
31987
+ }
31988
+ /**
31989
+ * Persistent storage adapter for live trading signals.
31822
31990
  *
31823
- * // Handle signal events
31824
- * await storage.handleOpened(tickResult);
31825
- * await storage.handleClosed(tickResult);
31991
+ * Features:
31992
+ * - Persists signals to disk using PersistStorageAdapter
31993
+ * - Lazy initialization with singleshot pattern
31994
+ * - Maintains up to MAX_SIGNALS (25) most recent signals
31995
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
31996
+ * - Prevents duplicate updates based on timestamp comparison
31826
31997
  *
31827
- * // Query signals
31828
- * const signal = await storage.findById("signal-123");
31829
- * const allSignals = await storage.list();
31830
- * ```
31998
+ * Use this adapter (default) for live signal persistence across sessions.
31831
31999
  */
31832
- class StorageLiveUtils {
32000
+ class StoragePersistLiveUtils {
31833
32001
  constructor() {
31834
32002
  /**
31835
- * Initializes storage by loading existing signal history from persist layer.
31836
- * Uses singleshot to ensure initialization happens only once.
32003
+ * Singleshot initialization function that loads signals from disk.
32004
+ * Protected by singleshot to ensure one-time execution.
31837
32005
  */
31838
32006
  this.waitForInit = functoolsKit.singleshot(async () => {
31839
32007
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_WAIT_FOR_INIT);
@@ -31845,9 +32013,8 @@ class StorageLiveUtils {
31845
32013
  });
31846
32014
  /**
31847
32015
  * Handles signal opened event.
31848
- *
31849
- * @param tick - Tick result containing opened signal data
31850
- * @returns Promise resolving when history is updated
32016
+ * Updates storage with opened status if not stale.
32017
+ * @param tick - The opened signal tick data
31851
32018
  */
31852
32019
  this.handleOpened = async (tick) => {
31853
32020
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_OPENED, {
@@ -31869,9 +32036,8 @@ class StorageLiveUtils {
31869
32036
  };
31870
32037
  /**
31871
32038
  * Handles signal closed event.
31872
- *
31873
- * @param tick - Tick result containing closed signal data
31874
- * @returns Promise resolving when history is updated
32039
+ * Updates storage with closed status and PnL if not stale.
32040
+ * @param tick - The closed signal tick data
31875
32041
  */
31876
32042
  this.handleClosed = async (tick) => {
31877
32043
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_CLOSED, {
@@ -31894,9 +32060,8 @@ class StorageLiveUtils {
31894
32060
  };
31895
32061
  /**
31896
32062
  * Handles signal scheduled event.
31897
- *
31898
- * @param tick - Tick result containing scheduled signal data
31899
- * @returns Promise resolving when history is updated
32063
+ * Updates storage with scheduled status if not stale.
32064
+ * @param tick - The scheduled signal tick data
31900
32065
  */
31901
32066
  this.handleScheduled = async (tick) => {
31902
32067
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_SCHEDULED, {
@@ -31918,9 +32083,8 @@ class StorageLiveUtils {
31918
32083
  };
31919
32084
  /**
31920
32085
  * Handles signal cancelled event.
31921
- *
31922
- * @param tick - Tick result containing cancelled signal data
31923
- * @returns Promise resolving when history is updated
32086
+ * Updates storage with cancelled status if not stale.
32087
+ * @param tick - The cancelled signal tick data
31924
32088
  */
31925
32089
  this.handleCancelled = async (tick) => {
31926
32090
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_HANDLE_CANCELLED, {
@@ -31941,10 +32105,9 @@ class StorageLiveUtils {
31941
32105
  await this._updateStorage();
31942
32106
  };
31943
32107
  /**
31944
- * Finds a signal by its unique identifier.
31945
- *
31946
- * @param id - Signal identifier
31947
- * @returns Promise resolving to signal row or null if not found
32108
+ * Finds a signal by its ID.
32109
+ * @param id - The signal ID to search for
32110
+ * @returns The signal row or null if not found
31948
32111
  */
31949
32112
  this.findById = async (id) => {
31950
32113
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_FIND_BY_ID, { id });
@@ -31952,9 +32115,8 @@ class StorageLiveUtils {
31952
32115
  return this._signals.get(id) ?? null;
31953
32116
  };
31954
32117
  /**
31955
- * Lists all stored live signals.
31956
- *
31957
- * @returns Promise resolving to array of signal rows
32118
+ * Lists all stored signals.
32119
+ * @returns Array of all signal rows
31958
32120
  */
31959
32121
  this.list = async () => {
31960
32122
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_LIST);
@@ -31963,15 +32125,14 @@ class StorageLiveUtils {
31963
32125
  };
31964
32126
  }
31965
32127
  /**
31966
- * Persists current signal history to storage.
31967
- * Sorts by priority and limits to MAX_SIGNALS entries.
31968
- *
31969
- * @throws Error if storage not initialized
32128
+ * Persists the current signal map to disk storage.
32129
+ * Sorts signals by priority and keeps only the most recent MAX_SIGNALS.
32130
+ * @throws Error if not initialized
31970
32131
  */
31971
32132
  async _updateStorage() {
31972
32133
  bt.loggerService.info(STORAGE_LIVE_METHOD_NAME_UPDATE_STORAGE);
31973
32134
  if (!this._signals) {
31974
- throw new Error("StorageLiveUtils not initialized. Call waitForInit first.");
32135
+ throw new Error("StoragePersistLiveUtils not initialized. Call waitForInit first.");
31975
32136
  }
31976
32137
  const signalList = Array.from(this._signals.values());
31977
32138
  signalList.sort((a, b) => a.priority - b.priority);
@@ -31979,36 +32140,385 @@ class StorageLiveUtils {
31979
32140
  }
31980
32141
  }
31981
32142
  /**
31982
- * Main storage adapter for signal history management.
32143
+ * In-memory storage adapter for live trading signals.
31983
32144
  *
31984
- * Provides unified interface for accessing backtest and live signal history
31985
- * for admin dashboard. Subscribes to signal emitters and automatically
31986
- * updates history on signal events.
32145
+ * Features:
32146
+ * - Stores signals in memory only (no persistence)
32147
+ * - Fast read/write operations
32148
+ * - Data is lost when application restarts
32149
+ * - Handles signal lifecycle events (opened, closed, scheduled, cancelled)
32150
+ * - Prevents duplicate updates based on timestamp comparison
31987
32151
  *
31988
- * @example
31989
- * ```typescript
31990
- * import { Storage } from "./classes/Storage";
32152
+ * Use this adapter for testing or when persistence is not required.
32153
+ */
32154
+ class StorageMemoryLiveUtils {
32155
+ constructor() {
32156
+ /** Map of signal IDs to signal rows */
32157
+ this._signals = new Map();
32158
+ /**
32159
+ * Handles signal opened event.
32160
+ * Updates in-memory storage with opened status if not stale.
32161
+ * @param tick - The opened signal tick data
32162
+ */
32163
+ this.handleOpened = async (tick) => {
32164
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_OPENED, {
32165
+ signalId: tick.signal.id,
32166
+ });
32167
+ const lastStorage = this._signals.get(tick.signal.id);
32168
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32169
+ return;
32170
+ }
32171
+ this._signals.set(tick.signal.id, {
32172
+ ...tick.signal,
32173
+ status: "opened",
32174
+ priority: Date.now(),
32175
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32176
+ updatedAt: tick.createdAt,
32177
+ });
32178
+ };
32179
+ /**
32180
+ * Handles signal closed event.
32181
+ * Updates in-memory storage with closed status and PnL if not stale.
32182
+ * @param tick - The closed signal tick data
32183
+ */
32184
+ this.handleClosed = async (tick) => {
32185
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CLOSED, {
32186
+ signalId: tick.signal.id,
32187
+ });
32188
+ const lastStorage = this._signals.get(tick.signal.id);
32189
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32190
+ return;
32191
+ }
32192
+ this._signals.set(tick.signal.id, {
32193
+ ...tick.signal,
32194
+ status: "closed",
32195
+ priority: Date.now(),
32196
+ pnl: tick.pnl,
32197
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32198
+ updatedAt: tick.createdAt,
32199
+ });
32200
+ };
32201
+ /**
32202
+ * Handles signal scheduled event.
32203
+ * Updates in-memory storage with scheduled status if not stale.
32204
+ * @param tick - The scheduled signal tick data
32205
+ */
32206
+ this.handleScheduled = async (tick) => {
32207
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_SCHEDULED, {
32208
+ signalId: tick.signal.id,
32209
+ });
32210
+ const lastStorage = this._signals.get(tick.signal.id);
32211
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32212
+ return;
32213
+ }
32214
+ this._signals.set(tick.signal.id, {
32215
+ ...tick.signal,
32216
+ status: "scheduled",
32217
+ priority: Date.now(),
32218
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32219
+ updatedAt: tick.createdAt,
32220
+ });
32221
+ };
32222
+ /**
32223
+ * Handles signal cancelled event.
32224
+ * Updates in-memory storage with cancelled status if not stale.
32225
+ * @param tick - The cancelled signal tick data
32226
+ */
32227
+ this.handleCancelled = async (tick) => {
32228
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_HANDLE_CANCELLED, {
32229
+ signalId: tick.signal.id,
32230
+ });
32231
+ const lastStorage = this._signals.get(tick.signal.id);
32232
+ if (lastStorage && lastStorage.updatedAt > tick.createdAt) {
32233
+ return;
32234
+ }
32235
+ this._signals.set(tick.signal.id, {
32236
+ ...tick.signal,
32237
+ status: "cancelled",
32238
+ priority: Date.now(),
32239
+ createdAt: lastStorage ? lastStorage.createdAt : tick.createdAt,
32240
+ updatedAt: tick.createdAt,
32241
+ });
32242
+ };
32243
+ /**
32244
+ * Finds a signal by its ID.
32245
+ * @param id - The signal ID to search for
32246
+ * @returns The signal row or null if not found
32247
+ */
32248
+ this.findById = async (id) => {
32249
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_FIND_BY_ID, { id });
32250
+ return this._signals.get(id) ?? null;
32251
+ };
32252
+ /**
32253
+ * Lists all stored signals.
32254
+ * @returns Array of all signal rows
32255
+ */
32256
+ this.list = async () => {
32257
+ bt.loggerService.info(STORAGE_MEMORY_LIVE_METHOD_NAME_LIST);
32258
+ return Array.from(this._signals.values());
32259
+ };
32260
+ }
32261
+ }
32262
+ /**
32263
+ * Dummy storage adapter for live trading signals that discards all writes.
31991
32264
  *
31992
- * // Enable signal history tracking
31993
- * const unsubscribe = Storage.enable();
32265
+ * Features:
32266
+ * - No-op implementation for all methods
32267
+ * - findById always returns null
32268
+ * - list always returns empty array
31994
32269
  *
31995
- * // Query signals
31996
- * const backtestSignals = await Storage.listSignalBacktest();
31997
- * const liveSignals = await Storage.listSignalLive();
31998
- * const signal = await Storage.findSignalById("signal-123");
32270
+ * Use this adapter to disable live signal storage completely.
32271
+ */
32272
+ class StorageDummyLiveUtils {
32273
+ constructor() {
32274
+ /**
32275
+ * No-op handler for signal opened event.
32276
+ */
32277
+ this.handleOpened = async () => {
32278
+ };
32279
+ /**
32280
+ * No-op handler for signal closed event.
32281
+ */
32282
+ this.handleClosed = async () => {
32283
+ };
32284
+ /**
32285
+ * No-op handler for signal scheduled event.
32286
+ */
32287
+ this.handleScheduled = async () => {
32288
+ };
32289
+ /**
32290
+ * No-op handler for signal cancelled event.
32291
+ */
32292
+ this.handleCancelled = async () => {
32293
+ };
32294
+ /**
32295
+ * Always returns null (no storage).
32296
+ * @returns null
32297
+ */
32298
+ this.findById = async () => {
32299
+ return null;
32300
+ };
32301
+ /**
32302
+ * Always returns empty array (no storage).
32303
+ * @returns Empty array
32304
+ */
32305
+ this.list = async () => {
32306
+ return [];
32307
+ };
32308
+ }
32309
+ }
32310
+ /**
32311
+ * Backtest storage adapter with pluggable storage backend.
31999
32312
  *
32000
- * // Disable tracking
32001
- * Storage.disable();
32002
- * ```
32313
+ * Features:
32314
+ * - Adapter pattern for swappable storage implementations
32315
+ * - Default adapter: StoragePersistBacktestUtils (persistent storage)
32316
+ * - Alternative adapters: StorageMemoryBacktestUtils, StorageDummyBacktestUtils
32317
+ * - Convenience methods: usePersist(), useMemory(), useDummy()
32318
+ */
32319
+ class StorageBacktestAdapter {
32320
+ constructor() {
32321
+ /** Internal storage utils instance */
32322
+ this._signalBacktestUtils = new StorageMemoryBacktestUtils();
32323
+ /**
32324
+ * Handles signal opened event.
32325
+ * Proxies call to the underlying storage adapter.
32326
+ * @param tick - The opened signal tick data
32327
+ */
32328
+ this.handleOpened = async (tick) => {
32329
+ return await this._signalBacktestUtils.handleOpened(tick);
32330
+ };
32331
+ /**
32332
+ * Handles signal closed event.
32333
+ * Proxies call to the underlying storage adapter.
32334
+ * @param tick - The closed signal tick data
32335
+ */
32336
+ this.handleClosed = async (tick) => {
32337
+ return await this._signalBacktestUtils.handleClosed(tick);
32338
+ };
32339
+ /**
32340
+ * Handles signal scheduled event.
32341
+ * Proxies call to the underlying storage adapter.
32342
+ * @param tick - The scheduled signal tick data
32343
+ */
32344
+ this.handleScheduled = async (tick) => {
32345
+ return await this._signalBacktestUtils.handleScheduled(tick);
32346
+ };
32347
+ /**
32348
+ * Handles signal cancelled event.
32349
+ * Proxies call to the underlying storage adapter.
32350
+ * @param tick - The cancelled signal tick data
32351
+ */
32352
+ this.handleCancelled = async (tick) => {
32353
+ return await this._signalBacktestUtils.handleCancelled(tick);
32354
+ };
32355
+ /**
32356
+ * Finds a signal by its ID.
32357
+ * Proxies call to the underlying storage adapter.
32358
+ * @param id - The signal ID to search for
32359
+ * @returns The signal row or null if not found
32360
+ */
32361
+ this.findById = async (id) => {
32362
+ return await this._signalBacktestUtils.findById(id);
32363
+ };
32364
+ /**
32365
+ * Lists all stored signals.
32366
+ * Proxies call to the underlying storage adapter.
32367
+ * @returns Array of all signal rows
32368
+ */
32369
+ this.list = async () => {
32370
+ return await this._signalBacktestUtils.list();
32371
+ };
32372
+ /**
32373
+ * Sets the storage adapter constructor.
32374
+ * All future storage operations will use this adapter.
32375
+ *
32376
+ * @param Ctor - Constructor for storage adapter
32377
+ */
32378
+ this.useStorageAdapter = (Ctor) => {
32379
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
32380
+ this._signalBacktestUtils = Reflect.construct(Ctor, []);
32381
+ };
32382
+ /**
32383
+ * Switches to dummy storage adapter.
32384
+ * All future storage writes will be no-ops.
32385
+ */
32386
+ this.useDummy = () => {
32387
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_DUMMY);
32388
+ this._signalBacktestUtils = new StorageDummyBacktestUtils();
32389
+ };
32390
+ /**
32391
+ * Switches to persistent storage adapter (default).
32392
+ * Signals will be persisted to disk.
32393
+ */
32394
+ this.usePersist = () => {
32395
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
32396
+ this._signalBacktestUtils = new StoragePersistBacktestUtils();
32397
+ };
32398
+ /**
32399
+ * Switches to in-memory storage adapter.
32400
+ * Signals will be stored in memory only.
32401
+ */
32402
+ this.useMemory = () => {
32403
+ bt.loggerService.info(STORAGE_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
32404
+ this._signalBacktestUtils = new StorageMemoryBacktestUtils();
32405
+ };
32406
+ }
32407
+ }
32408
+ /**
32409
+ * Live trading storage adapter with pluggable storage backend.
32410
+ *
32411
+ * Features:
32412
+ * - Adapter pattern for swappable storage implementations
32413
+ * - Default adapter: StoragePersistLiveUtils (persistent storage)
32414
+ * - Alternative adapters: StorageMemoryLiveUtils, StorageDummyLiveUtils
32415
+ * - Convenience methods: usePersist(), useMemory(), useDummy()
32416
+ */
32417
+ class StorageLiveAdapter {
32418
+ constructor() {
32419
+ /** Internal storage utils instance */
32420
+ this._signalLiveUtils = new StoragePersistLiveUtils();
32421
+ /**
32422
+ * Handles signal opened event.
32423
+ * Proxies call to the underlying storage adapter.
32424
+ * @param tick - The opened signal tick data
32425
+ */
32426
+ this.handleOpened = async (tick) => {
32427
+ return await this._signalLiveUtils.handleOpened(tick);
32428
+ };
32429
+ /**
32430
+ * Handles signal closed event.
32431
+ * Proxies call to the underlying storage adapter.
32432
+ * @param tick - The closed signal tick data
32433
+ */
32434
+ this.handleClosed = async (tick) => {
32435
+ return await this._signalLiveUtils.handleClosed(tick);
32436
+ };
32437
+ /**
32438
+ * Handles signal scheduled event.
32439
+ * Proxies call to the underlying storage adapter.
32440
+ * @param tick - The scheduled signal tick data
32441
+ */
32442
+ this.handleScheduled = async (tick) => {
32443
+ return await this._signalLiveUtils.handleScheduled(tick);
32444
+ };
32445
+ /**
32446
+ * Handles signal cancelled event.
32447
+ * Proxies call to the underlying storage adapter.
32448
+ * @param tick - The cancelled signal tick data
32449
+ */
32450
+ this.handleCancelled = async (tick) => {
32451
+ return await this._signalLiveUtils.handleCancelled(tick);
32452
+ };
32453
+ /**
32454
+ * Finds a signal by its ID.
32455
+ * Proxies call to the underlying storage adapter.
32456
+ * @param id - The signal ID to search for
32457
+ * @returns The signal row or null if not found
32458
+ */
32459
+ this.findById = async (id) => {
32460
+ return await this._signalLiveUtils.findById(id);
32461
+ };
32462
+ /**
32463
+ * Lists all stored signals.
32464
+ * Proxies call to the underlying storage adapter.
32465
+ * @returns Array of all signal rows
32466
+ */
32467
+ this.list = async () => {
32468
+ return await this._signalLiveUtils.list();
32469
+ };
32470
+ /**
32471
+ * Sets the storage adapter constructor.
32472
+ * All future storage operations will use this adapter.
32473
+ *
32474
+ * @param Ctor - Constructor for storage adapter
32475
+ */
32476
+ this.useStorageAdapter = (Ctor) => {
32477
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
32478
+ this._signalLiveUtils = Reflect.construct(Ctor, []);
32479
+ };
32480
+ /**
32481
+ * Switches to dummy storage adapter.
32482
+ * All future storage writes will be no-ops.
32483
+ */
32484
+ this.useDummy = () => {
32485
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_DUMMY);
32486
+ this._signalLiveUtils = new StorageDummyLiveUtils();
32487
+ };
32488
+ /**
32489
+ * Switches to persistent storage adapter (default).
32490
+ * Signals will be persisted to disk.
32491
+ */
32492
+ this.usePersist = () => {
32493
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
32494
+ this._signalLiveUtils = new StoragePersistLiveUtils();
32495
+ };
32496
+ /**
32497
+ * Switches to in-memory storage adapter.
32498
+ * Signals will be stored in memory only.
32499
+ */
32500
+ this.useMemory = () => {
32501
+ bt.loggerService.info(STORAGE_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
32502
+ this._signalLiveUtils = new StorageMemoryLiveUtils();
32503
+ };
32504
+ }
32505
+ }
32506
+ /**
32507
+ * Main storage adapter that manages both backtest and live signal storage.
32508
+ *
32509
+ * Features:
32510
+ * - Subscribes to signal emitters for automatic storage updates
32511
+ * - Provides unified access to both backtest and live signals
32512
+ * - Singleshot enable pattern prevents duplicate subscriptions
32513
+ * - Cleanup function for proper unsubscription
32003
32514
  */
32004
32515
  class StorageAdapter {
32005
32516
  constructor() {
32006
- this._signalLiveUtils = new StorageLiveUtils();
32007
- this._signalBacktestUtils = new StorageBacktestUtils();
32008
32517
  /**
32009
- * Enables signal history tracking by subscribing to emitters.
32518
+ * Enables signal storage by subscribing to signal emitters.
32519
+ * Uses singleshot to ensure one-time subscription.
32010
32520
  *
32011
- * @returns Cleanup function to unsubscribe from all emitters
32521
+ * @returns Cleanup function that unsubscribes from all emitters
32012
32522
  */
32013
32523
  this.enable = functoolsKit.singleshot(() => {
32014
32524
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_ENABLE);
@@ -32017,31 +32527,31 @@ class StorageAdapter {
32017
32527
  {
32018
32528
  const unBacktestOpen = signalBacktestEmitter
32019
32529
  .filter(({ action }) => action === "opened")
32020
- .connect((tick) => this._signalBacktestUtils.handleOpened(tick));
32530
+ .connect((tick) => StorageBacktest.handleOpened(tick));
32021
32531
  const unBacktestClose = signalBacktestEmitter
32022
32532
  .filter(({ action }) => action === "closed")
32023
- .connect((tick) => this._signalBacktestUtils.handleClosed(tick));
32533
+ .connect((tick) => StorageBacktest.handleClosed(tick));
32024
32534
  const unBacktestScheduled = signalBacktestEmitter
32025
32535
  .filter(({ action }) => action === "scheduled")
32026
- .connect((tick) => this._signalBacktestUtils.handleScheduled(tick));
32536
+ .connect((tick) => StorageBacktest.handleScheduled(tick));
32027
32537
  const unBacktestCancelled = signalBacktestEmitter
32028
32538
  .filter(({ action }) => action === "cancelled")
32029
- .connect((tick) => this._signalBacktestUtils.handleCancelled(tick));
32539
+ .connect((tick) => StorageBacktest.handleCancelled(tick));
32030
32540
  unBacktest = functoolsKit.compose(() => unBacktestOpen(), () => unBacktestClose(), () => unBacktestScheduled(), () => unBacktestCancelled());
32031
32541
  }
32032
32542
  {
32033
32543
  const unLiveOpen = signalLiveEmitter
32034
32544
  .filter(({ action }) => action === "opened")
32035
- .connect((tick) => this._signalLiveUtils.handleOpened(tick));
32545
+ .connect((tick) => StorageLive.handleOpened(tick));
32036
32546
  const unLiveClose = signalLiveEmitter
32037
32547
  .filter(({ action }) => action === "closed")
32038
- .connect((tick) => this._signalLiveUtils.handleClosed(tick));
32548
+ .connect((tick) => StorageLive.handleClosed(tick));
32039
32549
  const unLiveScheduled = signalLiveEmitter
32040
32550
  .filter(({ action }) => action === "scheduled")
32041
- .connect((tick) => this._signalLiveUtils.handleScheduled(tick));
32551
+ .connect((tick) => StorageLive.handleScheduled(tick));
32042
32552
  const unLiveCancelled = signalLiveEmitter
32043
32553
  .filter(({ action }) => action === "cancelled")
32044
- .connect((tick) => this._signalLiveUtils.handleCancelled(tick));
32554
+ .connect((tick) => StorageLive.handleCancelled(tick));
32045
32555
  unLive = functoolsKit.compose(() => unLiveOpen(), () => unLiveClose(), () => unLiveScheduled(), () => unLiveCancelled());
32046
32556
  }
32047
32557
  return () => {
@@ -32051,7 +32561,8 @@ class StorageAdapter {
32051
32561
  };
32052
32562
  });
32053
32563
  /**
32054
- * Disables signal history tracking by unsubscribing from emitters.
32564
+ * Disables signal storage by unsubscribing from all emitters.
32565
+ * Safe to call multiple times.
32055
32566
  */
32056
32567
  this.disable = () => {
32057
32568
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_DISABLE);
@@ -32061,11 +32572,12 @@ class StorageAdapter {
32061
32572
  }
32062
32573
  };
32063
32574
  /**
32064
- * Finds a signal by ID across both backtest and live history.
32575
+ * Finds a signal by ID across both backtest and live storage.
32065
32576
  *
32066
- * @param id - Signal identifier
32067
- * @returns Promise resolving to signal row
32068
- * @throws Error if signal not found in either storage
32577
+ * @param id - The signal ID to search for
32578
+ * @returns The signal row or throws if not found
32579
+ * @throws Error if StorageAdapter is not enabled
32580
+ * @throws Error if signal is not found in either storage
32069
32581
  */
32070
32582
  this.findSignalById = async (id) => {
32071
32583
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_FIND_SIGNAL_BY_ID, { id });
@@ -32073,41 +32585,57 @@ class StorageAdapter {
32073
32585
  throw new Error("StorageAdapter is not enabled. Call enable() first.");
32074
32586
  }
32075
32587
  let result = null;
32076
- if ((result = await this._signalBacktestUtils.findById(id))) {
32588
+ if ((result = await StorageBacktest.findById(id))) {
32077
32589
  return result;
32078
32590
  }
32079
- if ((result = await this._signalLiveUtils.findById(id))) {
32591
+ if ((result = await StorageLive.findById(id))) {
32080
32592
  return result;
32081
32593
  }
32082
32594
  throw new Error(`Storage signal with id ${id} not found`);
32083
32595
  };
32084
32596
  /**
32085
- * Lists all backtest signal history.
32597
+ * Lists all backtest signals from storage.
32086
32598
  *
32087
- * @returns Promise resolving to array of backtest signal rows
32599
+ * @returns Array of all backtest signal rows
32600
+ * @throws Error if StorageAdapter is not enabled
32088
32601
  */
32089
32602
  this.listSignalBacktest = async () => {
32090
32603
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_BACKTEST);
32091
32604
  if (!this.enable.hasValue()) {
32092
32605
  throw new Error("StorageAdapter is not enabled. Call enable() first.");
32093
32606
  }
32094
- return await this._signalBacktestUtils.list();
32607
+ return await StorageBacktest.list();
32095
32608
  };
32096
32609
  /**
32097
- * Lists all live signal history.
32610
+ * Lists all live signals from storage.
32098
32611
  *
32099
- * @returns Promise resolving to array of live signal rows
32612
+ * @returns Array of all live signal rows
32613
+ * @throws Error if StorageAdapter is not enabled
32100
32614
  */
32101
32615
  this.listSignalLive = async () => {
32102
32616
  bt.loggerService.info(STORAGE_ADAPTER_METHOD_NAME_LIST_SIGNAL_LIVE);
32103
32617
  if (!this.enable.hasValue()) {
32104
32618
  throw new Error("StorageAdapter is not enabled. Call enable() first.");
32105
32619
  }
32106
- return await this._signalLiveUtils.list();
32620
+ return await StorageLive.list();
32107
32621
  };
32108
32622
  }
32109
32623
  }
32624
+ /**
32625
+ * Global singleton instance of StorageAdapter.
32626
+ * Provides unified signal storage management for backtest and live trading.
32627
+ */
32110
32628
  const Storage = new StorageAdapter();
32629
+ /**
32630
+ * Global singleton instance of StorageLiveAdapter.
32631
+ * Provides live trading signal storage with pluggable backends.
32632
+ */
32633
+ const StorageLive = new StorageLiveAdapter();
32634
+ /**
32635
+ * Global singleton instance of StorageBacktestAdapter.
32636
+ * Provides backtest signal storage with pluggable backends.
32637
+ */
32638
+ const StorageBacktest = new StorageBacktestAdapter();
32111
32639
 
32112
32640
  const EXCHANGE_METHOD_NAME_GET_CANDLES = "ExchangeUtils.getCandles";
32113
32641
  const EXCHANGE_METHOD_NAME_GET_AVERAGE_PRICE = "ExchangeUtils.getAveragePrice";
@@ -34144,6 +34672,8 @@ exports.ReportBase = ReportBase;
34144
34672
  exports.Risk = Risk;
34145
34673
  exports.Schedule = Schedule;
34146
34674
  exports.Storage = Storage;
34675
+ exports.StorageBacktest = StorageBacktest;
34676
+ exports.StorageLive = StorageLive;
34147
34677
  exports.Strategy = Strategy;
34148
34678
  exports.Walker = Walker;
34149
34679
  exports.addActionSchema = addActionSchema;