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