backtest-kit 3.3.2 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -487,6 +487,28 @@ npm install @backtest-kit/pinets pinets backtest-kit
487
487
  ```
488
488
 
489
489
 
490
+ ### @backtest-kit/graph
491
+
492
+ > **[Explore on NPM](https://www.npmjs.com/package/@backtest-kit/graph)** 🔗
493
+
494
+ The **@backtest-kit/graph** package lets you compose backtest-kit computations as a typed directed acyclic graph (DAG). Define source nodes that fetch market data and output nodes that compute derived values — then resolve the whole graph in topological order with automatic parallelism.
495
+
496
+ #### Key Features
497
+ - 🔌 **DAG Execution**: Nodes are resolved bottom-up in topological order with `Promise.all` parallelism
498
+ - 🔒 **Type-Safe Values**: TypeScript infers the return type of every node through the graph via generics
499
+ - 🧱 **Two APIs**: Low-level `INode` for runtime/storage, high-level `sourceNode` + `outputNode` builders for authoring
500
+ - 💾 **DB-Ready Serialization**: `serialize` / `deserialize` convert the graph to a flat `IFlatNode[]` list with `id` / `nodeIds`
501
+ - 🌐 **Context-Aware Fetch**: `sourceNode` receives `(symbol, when, exchangeName)` from the execution context automatically
502
+
503
+ #### Use Case
504
+ Perfect for multi-timeframe strategies where multiple Pine Script or indicator computations must be combined. Instead of manually chaining async calls, define each computation as a node and let the graph resolve dependencies in parallel. Adding a new filter or timeframe requires no changes to the existing wiring.
505
+
506
+ #### Get Started
507
+ ```bash
508
+ npm install @backtest-kit/graph backtest-kit
509
+ ```
510
+
511
+
490
512
  ### @backtest-kit/ui
491
513
 
492
514
  > **[Explore on NPM](https://www.npmjs.com/package/@backtest-kit/ui)** 📊
@@ -556,28 +578,6 @@ npm install @backtest-kit/signals backtest-kit
556
578
 
557
579
 
558
580
 
559
- ### @backtest-kit/graph
560
-
561
- > **[Explore on NPM](https://www.npmjs.com/package/@backtest-kit/graph)** 🔗
562
-
563
- The **@backtest-kit/graph** package lets you compose backtest-kit computations as a typed directed acyclic graph (DAG). Define source nodes that fetch market data and output nodes that compute derived values — then resolve the whole graph in topological order with automatic parallelism.
564
-
565
- #### Key Features
566
- - 🔌 **DAG Execution**: Nodes are resolved bottom-up in topological order with `Promise.all` parallelism
567
- - 🔒 **Type-Safe Values**: TypeScript infers the return type of every node through the graph via generics
568
- - 🧱 **Two APIs**: Low-level `INode` for runtime/storage, high-level `sourceNode` + `outputNode` builders for authoring
569
- - 💾 **DB-Ready Serialization**: `serialize` / `deserialize` convert the graph to a flat `IFlatNode[]` list with `id` / `nodeIds`
570
- - 🌐 **Context-Aware Fetch**: `sourceNode` receives `(symbol, when, exchangeName)` from the execution context automatically
571
-
572
- #### Use Case
573
- Perfect for multi-timeframe strategies where multiple Pine Script or indicator computations must be combined. Instead of manually chaining async calls, define each computation as a node and let the graph resolve dependencies in parallel. Adding a new filter or timeframe requires no changes to the existing wiring.
574
-
575
- #### Get Started
576
- ```bash
577
- npm install @backtest-kit/graph backtest-kit
578
- ```
579
-
580
-
581
581
  ### @backtest-kit/sidekick
582
582
 
583
583
  > **[Explore on NPM](https://www.npmjs.com/package/@backtest-kit/sidekick)** 🚀
package/build/index.cjs CHANGED
@@ -442,6 +442,14 @@ const GLOBAL_CONFIG = {
442
442
  * Default: 50 signals
443
443
  */
444
444
  CC_MAX_SIGNALS: 50,
445
+ /**
446
+ * Maximum number of log lines to keep in storage.
447
+ * Older log lines are removed when this limit is exceeded.
448
+ * This helps prevent unbounded log growth which can consume memory and degrade performance over time.
449
+ *
450
+ * Default: 1000 log lines
451
+ */
452
+ CC_MAX_LOG_LINES: 1000,
445
453
  /**
446
454
  * Enables mutex locking for candle fetching to prevent concurrent fetches of the same candles.
447
455
  * This can help avoid redundant API calls and ensure data consistency when multiple processes/threads attempt to fetch candles simultaneously.
@@ -776,6 +784,11 @@ const PERSIST_NOTIFICATION_UTILS_METHOD_NAME_WRITE_DATA = "PersistNotificationUt
776
784
  const PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_JSON = "PersistNotificationUtils.useJson";
777
785
  const PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_DUMMY = "PersistNotificationUtils.useDummy";
778
786
  const PERSIST_NOTIFICATION_UTILS_METHOD_NAME_USE_PERSIST_NOTIFICATION_ADAPTER = "PersistNotificationUtils.usePersistNotificationAdapter";
787
+ const PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA = "PersistLogUtils.readLogData";
788
+ const PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA = "PersistLogUtils.writeLogData";
789
+ const PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON = "PersistLogUtils.useJson";
790
+ const PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY = "PersistLogUtils.useDummy";
791
+ const PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER = "PersistLogUtils.usePersistLogAdapter";
779
792
  const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
780
793
  const BASE_UNLINK_RETRY_COUNT = 5;
781
794
  const BASE_UNLINK_RETRY_DELAY = 1000;
@@ -1946,6 +1959,106 @@ class PersistNotificationUtils {
1946
1959
  * Used by NotificationPersistLiveUtils/NotificationPersistBacktestUtils for notification persistence.
1947
1960
  */
1948
1961
  const PersistNotificationAdapter = new PersistNotificationUtils();
1962
+ /**
1963
+ * Utility class for managing log entry persistence.
1964
+ *
1965
+ * Features:
1966
+ * - Memoized storage instance
1967
+ * - Custom adapter support
1968
+ * - Atomic read/write operations for LogData
1969
+ * - Each log entry stored as separate file keyed by id
1970
+ * - Crash-safe log state management
1971
+ *
1972
+ * Used by LogPersistUtils for log entry persistence.
1973
+ */
1974
+ class PersistLogUtils {
1975
+ constructor() {
1976
+ this.PersistLogFactory = PersistBase;
1977
+ this._logStorage = null;
1978
+ /**
1979
+ * Reads persisted log entries.
1980
+ *
1981
+ * Called by LogPersistUtils.waitForInit() to restore state.
1982
+ * Uses keys() from PersistBase to iterate over all stored entries.
1983
+ * Returns empty array if no entries exist.
1984
+ *
1985
+ * @returns Promise resolving to array of log entries
1986
+ */
1987
+ this.readLogData = async () => {
1988
+ bt.loggerService.info(PERSIST_LOG_UTILS_METHOD_NAME_READ_DATA);
1989
+ const isInitial = !this._logStorage;
1990
+ const stateStorage = this.getLogStorage();
1991
+ await stateStorage.waitForInit(isInitial);
1992
+ const entries = [];
1993
+ for await (const entryId of stateStorage.keys()) {
1994
+ const entry = await stateStorage.readValue(entryId);
1995
+ entries.push(entry);
1996
+ }
1997
+ return entries;
1998
+ };
1999
+ /**
2000
+ * Writes log entries to disk with atomic file writes.
2001
+ *
2002
+ * Called by LogPersistUtils after each log call to persist state.
2003
+ * Uses entry.id as the storage key for individual file storage.
2004
+ * Uses atomic writes to prevent corruption on crashes.
2005
+ *
2006
+ * @param logData - Log entries to persist
2007
+ * @returns Promise that resolves when write is complete
2008
+ */
2009
+ this.writeLogData = async (logData) => {
2010
+ bt.loggerService.info(PERSIST_LOG_UTILS_METHOD_NAME_WRITE_DATA);
2011
+ const isInitial = !this._logStorage;
2012
+ const stateStorage = this.getLogStorage();
2013
+ await stateStorage.waitForInit(isInitial);
2014
+ for (const entry of logData) {
2015
+ if (await stateStorage.hasValue(entry.id)) {
2016
+ continue;
2017
+ }
2018
+ await stateStorage.writeValue(entry.id, entry);
2019
+ }
2020
+ };
2021
+ }
2022
+ getLogStorage() {
2023
+ if (!this._logStorage) {
2024
+ this._logStorage = Reflect.construct(this.PersistLogFactory, [
2025
+ `log`,
2026
+ `./dump/data/log/`,
2027
+ ]);
2028
+ }
2029
+ return this._logStorage;
2030
+ }
2031
+ /**
2032
+ * Registers a custom persistence adapter.
2033
+ *
2034
+ * @param Ctor - Custom PersistBase constructor
2035
+ */
2036
+ usePersistLogAdapter(Ctor) {
2037
+ bt.loggerService.info(PERSIST_LOG_UTILS_METHOD_NAME_USE_PERSIST_LOG_ADAPTER);
2038
+ this.PersistLogFactory = Ctor;
2039
+ }
2040
+ /**
2041
+ * Switches to the default JSON persist adapter.
2042
+ * All future persistence writes will use JSON storage.
2043
+ */
2044
+ useJson() {
2045
+ bt.loggerService.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_JSON);
2046
+ this.usePersistLogAdapter(PersistBase);
2047
+ }
2048
+ /**
2049
+ * Switches to a dummy persist adapter that discards all writes.
2050
+ * All future persistence writes will be no-ops.
2051
+ */
2052
+ useDummy() {
2053
+ bt.loggerService.log(PERSIST_LOG_UTILS_METHOD_NAME_USE_DUMMY);
2054
+ this.usePersistLogAdapter(PersistDummy);
2055
+ }
2056
+ }
2057
+ /**
2058
+ * Global singleton instance of PersistLogUtils.
2059
+ * Used by LogPersistUtils for log entry persistence.
2060
+ */
2061
+ const PersistLogAdapter = new PersistLogUtils();
1949
2062
 
1950
2063
  var _a$2, _b$2;
1951
2064
  const BUSY_DELAY = 100;
@@ -30882,6 +30995,416 @@ async function dumpMessages(resultId, history, result, outputDir = "./dump/strat
30882
30995
  }
30883
30996
  }
30884
30997
 
30998
+ const LOG_PERSIST_METHOD_NAME_WAIT_FOR_INIT = "LogPersistUtils.waitForInit";
30999
+ const LOG_PERSIST_METHOD_NAME_LOG = "LogPersistUtils.log";
31000
+ const LOG_PERSIST_METHOD_NAME_DEBUG = "LogPersistUtils.debug";
31001
+ const LOG_PERSIST_METHOD_NAME_INFO = "LogPersistUtils.info";
31002
+ const LOG_PERSIST_METHOD_NAME_WARN = "LogPersistUtils.warn";
31003
+ const LOG_PERSIST_METHOD_NAME_GET_LIST = "LogPersistUtils.getList";
31004
+ const LOG_MEMORY_METHOD_NAME_LOG = "LogMemoryUtils.log";
31005
+ const LOG_MEMORY_METHOD_NAME_DEBUG = "LogMemoryUtils.debug";
31006
+ const LOG_MEMORY_METHOD_NAME_INFO = "LogMemoryUtils.info";
31007
+ const LOG_MEMORY_METHOD_NAME_WARN = "LogMemoryUtils.warn";
31008
+ const LOG_MEMORY_METHOD_NAME_GET_LIST = "LogMemoryUtils.getList";
31009
+ const LOG_ADAPTER_METHOD_NAME_USE_LOGGER = "LogAdapter.useLogger";
31010
+ const LOG_ADAPTER_METHOD_NAME_USE_PERSIST = "LogAdapter.usePersist";
31011
+ const LOG_ADAPTER_METHOD_NAME_USE_MEMORY = "LogAdapter.useMemory";
31012
+ const LOG_ADAPTER_METHOD_NAME_USE_DUMMY = "LogAdapter.useDummy";
31013
+ /**
31014
+ * Backtest execution time retrieval function.
31015
+ * Returns the 'when' timestamp from the execution context if available, otherwise returns the current time.
31016
+ * This allows log entries to be timestamped according to the backtest timeline rather than real-world time, improving log relevance and user experience during backtest analysis.
31017
+ */
31018
+ const GET_DATE_FN = async () => {
31019
+ if (ExecutionContextService.hasContext()) {
31020
+ return new Date(bt.executionContextService.context.when);
31021
+ }
31022
+ return new Date();
31023
+ };
31024
+ /**
31025
+ * Persistent log adapter.
31026
+ *
31027
+ * Features:
31028
+ * - Persists log entries to disk using PersistLogAdapter
31029
+ * - Lazy initialization with singleshot pattern
31030
+ * - Maintains up to CC_MAX_LOG_LINES most recent entries
31031
+ * - Each entry stored individually keyed by its id
31032
+ *
31033
+ * Use this adapter (default) for log persistence across sessions.
31034
+ */
31035
+ class LogPersistUtils {
31036
+ constructor() {
31037
+ /** Array of log entries */
31038
+ this._entries = [];
31039
+ /**
31040
+ * Singleshot initialization function that loads entries from disk.
31041
+ * Protected by singleshot to ensure one-time execution.
31042
+ */
31043
+ this.waitForInit = functoolsKit.singleshot(async () => {
31044
+ bt.loggerService.info(LOG_PERSIST_METHOD_NAME_WAIT_FOR_INIT);
31045
+ const list = await PersistLogAdapter.readLogData();
31046
+ list.sort((a, b) => a.timestamp - b.timestamp);
31047
+ this._entries = list.slice(-GLOBAL_CONFIG.CC_MAX_LOG_LINES);
31048
+ });
31049
+ /**
31050
+ * Logs a general-purpose message.
31051
+ * Persists entry to disk after appending.
31052
+ * @param topic - The log topic / method name
31053
+ * @param args - Additional arguments
31054
+ */
31055
+ this.log = async (topic, ...args) => {
31056
+ bt.loggerService.info(LOG_PERSIST_METHOD_NAME_LOG, { topic });
31057
+ await this.waitForInit();
31058
+ const date = await GET_DATE_FN();
31059
+ this._entries.push({
31060
+ id: functoolsKit.randomString(),
31061
+ type: "log",
31062
+ timestamp: Date.now(),
31063
+ createdAt: date.toISOString(),
31064
+ topic,
31065
+ args,
31066
+ });
31067
+ this._enforceLimit();
31068
+ await PersistLogAdapter.writeLogData(this._entries);
31069
+ };
31070
+ /**
31071
+ * Logs a debug-level message.
31072
+ * Persists entry to disk after appending.
31073
+ * @param topic - The log topic / method name
31074
+ * @param args - Additional arguments
31075
+ */
31076
+ this.debug = async (topic, ...args) => {
31077
+ bt.loggerService.info(LOG_PERSIST_METHOD_NAME_DEBUG, { topic });
31078
+ await this.waitForInit();
31079
+ const date = await GET_DATE_FN();
31080
+ this._entries.push({
31081
+ id: functoolsKit.randomString(),
31082
+ type: "debug",
31083
+ timestamp: Date.now(),
31084
+ createdAt: date.toISOString(),
31085
+ topic,
31086
+ args,
31087
+ });
31088
+ this._enforceLimit();
31089
+ await PersistLogAdapter.writeLogData(this._entries);
31090
+ };
31091
+ /**
31092
+ * Logs an info-level message.
31093
+ * Persists entry to disk after appending.
31094
+ * @param topic - The log topic / method name
31095
+ * @param args - Additional arguments
31096
+ */
31097
+ this.info = async (topic, ...args) => {
31098
+ bt.loggerService.info(LOG_PERSIST_METHOD_NAME_INFO, { topic });
31099
+ await this.waitForInit();
31100
+ const date = await GET_DATE_FN();
31101
+ this._entries.push({
31102
+ id: functoolsKit.randomString(),
31103
+ type: "info",
31104
+ timestamp: Date.now(),
31105
+ createdAt: date.toISOString(),
31106
+ topic,
31107
+ args,
31108
+ });
31109
+ this._enforceLimit();
31110
+ await PersistLogAdapter.writeLogData(this._entries);
31111
+ };
31112
+ /**
31113
+ * Logs a warning-level message.
31114
+ * Persists entry to disk after appending.
31115
+ * @param topic - The log topic / method name
31116
+ * @param args - Additional arguments
31117
+ */
31118
+ this.warn = async (topic, ...args) => {
31119
+ bt.loggerService.info(LOG_PERSIST_METHOD_NAME_WARN, { topic });
31120
+ await this.waitForInit();
31121
+ const date = await GET_DATE_FN();
31122
+ this._entries.push({
31123
+ id: functoolsKit.randomString(),
31124
+ type: "warn",
31125
+ timestamp: Date.now(),
31126
+ createdAt: date.toISOString(),
31127
+ topic,
31128
+ args,
31129
+ });
31130
+ this._enforceLimit();
31131
+ await PersistLogAdapter.writeLogData(this._entries);
31132
+ };
31133
+ /**
31134
+ * Lists all stored log entries.
31135
+ * @returns Array of all log entries
31136
+ */
31137
+ this.getList = async () => {
31138
+ bt.loggerService.info(LOG_PERSIST_METHOD_NAME_GET_LIST);
31139
+ await this.waitForInit();
31140
+ return [...this._entries];
31141
+ };
31142
+ }
31143
+ /**
31144
+ * Removes oldest entries if limit is exceeded.
31145
+ */
31146
+ _enforceLimit() {
31147
+ if (this._entries.length > GLOBAL_CONFIG.CC_MAX_LOG_LINES) {
31148
+ this._entries.splice(0, this._entries.length - GLOBAL_CONFIG.CC_MAX_LOG_LINES);
31149
+ }
31150
+ }
31151
+ }
31152
+ /**
31153
+ * In-memory log adapter.
31154
+ *
31155
+ * Features:
31156
+ * - Stores log entries in memory only (no persistence)
31157
+ * - Maintains up to CC_MAX_LOG_LINES most recent entries
31158
+ * - Data is lost when application restarts
31159
+ * - Handles all log levels (log, debug, info, warn)
31160
+ *
31161
+ * Use this adapter for testing or when persistence is not required.
31162
+ */
31163
+ class LogMemoryUtils {
31164
+ constructor() {
31165
+ /** Array of log entries */
31166
+ this._entries = [];
31167
+ /**
31168
+ * Logs a general-purpose message.
31169
+ * Appends entry to in-memory array.
31170
+ * @param topic - The log topic / method name
31171
+ * @param args - Additional arguments
31172
+ */
31173
+ this.log = async (topic, ...args) => {
31174
+ bt.loggerService.info(LOG_MEMORY_METHOD_NAME_LOG, { topic });
31175
+ const date = await GET_DATE_FN();
31176
+ this._entries.push({
31177
+ id: functoolsKit.randomString(),
31178
+ type: "log",
31179
+ timestamp: Date.now(),
31180
+ createdAt: date.toISOString(),
31181
+ topic,
31182
+ args,
31183
+ });
31184
+ this._enforceLimit();
31185
+ };
31186
+ /**
31187
+ * Logs a debug-level message.
31188
+ * Appends entry to in-memory array.
31189
+ * @param topic - The log topic / method name
31190
+ * @param args - Additional arguments
31191
+ */
31192
+ this.debug = async (topic, ...args) => {
31193
+ bt.loggerService.info(LOG_MEMORY_METHOD_NAME_DEBUG, { topic });
31194
+ const date = await GET_DATE_FN();
31195
+ this._entries.push({
31196
+ id: functoolsKit.randomString(),
31197
+ type: "debug",
31198
+ timestamp: Date.now(),
31199
+ createdAt: date.toISOString(),
31200
+ topic,
31201
+ args,
31202
+ });
31203
+ this._enforceLimit();
31204
+ };
31205
+ /**
31206
+ * Logs an info-level message.
31207
+ * Appends entry to in-memory array.
31208
+ * @param topic - The log topic / method name
31209
+ * @param args - Additional arguments
31210
+ */
31211
+ this.info = async (topic, ...args) => {
31212
+ bt.loggerService.info(LOG_MEMORY_METHOD_NAME_INFO, { topic });
31213
+ const date = await GET_DATE_FN();
31214
+ this._entries.push({
31215
+ id: functoolsKit.randomString(),
31216
+ type: "info",
31217
+ timestamp: Date.now(),
31218
+ createdAt: date.toISOString(),
31219
+ topic,
31220
+ args,
31221
+ });
31222
+ this._enforceLimit();
31223
+ };
31224
+ /**
31225
+ * Logs a warning-level message.
31226
+ * Appends entry to in-memory array.
31227
+ * @param topic - The log topic / method name
31228
+ * @param args - Additional arguments
31229
+ */
31230
+ this.warn = async (topic, ...args) => {
31231
+ bt.loggerService.info(LOG_MEMORY_METHOD_NAME_WARN, { topic });
31232
+ const date = await GET_DATE_FN();
31233
+ this._entries.push({
31234
+ id: functoolsKit.randomString(),
31235
+ type: "warn",
31236
+ timestamp: Date.now(),
31237
+ createdAt: date.toISOString(),
31238
+ topic,
31239
+ args,
31240
+ });
31241
+ this._enforceLimit();
31242
+ };
31243
+ /**
31244
+ * Lists all stored log entries.
31245
+ * @returns Array of all log entries
31246
+ */
31247
+ this.getList = async () => {
31248
+ bt.loggerService.info(LOG_MEMORY_METHOD_NAME_GET_LIST);
31249
+ return [...this._entries];
31250
+ };
31251
+ }
31252
+ /**
31253
+ * Removes oldest entries if limit is exceeded.
31254
+ */
31255
+ _enforceLimit() {
31256
+ if (this._entries.length > GLOBAL_CONFIG.CC_MAX_LOG_LINES) {
31257
+ this._entries.splice(0, this._entries.length - GLOBAL_CONFIG.CC_MAX_LOG_LINES);
31258
+ }
31259
+ }
31260
+ }
31261
+ /**
31262
+ * Dummy log adapter that discards all writes.
31263
+ *
31264
+ * Features:
31265
+ * - No-op implementation for all methods
31266
+ * - getList always returns empty array
31267
+ *
31268
+ * Use this adapter to disable log storage completely.
31269
+ */
31270
+ class LogDummyUtils {
31271
+ /**
31272
+ * Always returns empty array (no storage).
31273
+ * @returns Empty array
31274
+ */
31275
+ async getList() {
31276
+ return [];
31277
+ }
31278
+ /**
31279
+ * No-op handler for general-purpose log.
31280
+ */
31281
+ log() {
31282
+ }
31283
+ /**
31284
+ * No-op handler for debug-level log.
31285
+ */
31286
+ debug() {
31287
+ }
31288
+ /**
31289
+ * No-op handler for info-level log.
31290
+ */
31291
+ info() {
31292
+ }
31293
+ /**
31294
+ * No-op handler for warning-level log.
31295
+ */
31296
+ warn() {
31297
+ }
31298
+ }
31299
+ /**
31300
+ * Log adapter with pluggable storage backend.
31301
+ *
31302
+ * Features:
31303
+ * - Adapter pattern for swappable log implementations
31304
+ * - Default adapter: LogMemoryUtils (in-memory storage)
31305
+ * - Alternative adapters: LogPersistUtils, LogDummyUtils
31306
+ * - Convenience methods: usePersist(), useMemory(), useDummy()
31307
+ */
31308
+ class LogAdapter {
31309
+ constructor() {
31310
+ /** Internal log utils instance */
31311
+ this._log = new LogMemoryUtils();
31312
+ /**
31313
+ * Lists all stored log entries.
31314
+ * Proxies call to the underlying log adapter.
31315
+ * @returns Array of all log entries
31316
+ */
31317
+ this.getList = async () => {
31318
+ if (this._log.getList) {
31319
+ return await this._log.getList();
31320
+ }
31321
+ return [];
31322
+ };
31323
+ /**
31324
+ * Logs a general-purpose message.
31325
+ * Proxies call to the underlying log adapter.
31326
+ * @param topic - The log topic / method name
31327
+ * @param args - Additional arguments
31328
+ */
31329
+ this.log = (topic, ...args) => {
31330
+ if (this._log.log) {
31331
+ this._log.log(topic, ...args);
31332
+ }
31333
+ };
31334
+ /**
31335
+ * Logs a debug-level message.
31336
+ * Proxies call to the underlying log adapter.
31337
+ * @param topic - The log topic / method name
31338
+ * @param args - Additional arguments
31339
+ */
31340
+ this.debug = (topic, ...args) => {
31341
+ if (this._log.debug) {
31342
+ this._log.debug(topic, ...args);
31343
+ }
31344
+ };
31345
+ /**
31346
+ * Logs an info-level message.
31347
+ * Proxies call to the underlying log adapter.
31348
+ * @param topic - The log topic / method name
31349
+ * @param args - Additional arguments
31350
+ */
31351
+ this.info = (topic, ...args) => {
31352
+ if (this._log.info) {
31353
+ this._log.info(topic, ...args);
31354
+ }
31355
+ };
31356
+ /**
31357
+ * Logs a warning-level message.
31358
+ * Proxies call to the underlying log adapter.
31359
+ * @param topic - The log topic / method name
31360
+ * @param args - Additional arguments
31361
+ */
31362
+ this.warn = (topic, ...args) => {
31363
+ if (this._log.warn) {
31364
+ this._log.warn(topic, ...args);
31365
+ }
31366
+ };
31367
+ /**
31368
+ * Sets the log adapter constructor.
31369
+ * All future log operations will use this adapter.
31370
+ * @param Ctor - Constructor for log adapter
31371
+ */
31372
+ this.useLogger = (Ctor) => {
31373
+ bt.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_LOGGER);
31374
+ this._log = Reflect.construct(Ctor, []);
31375
+ };
31376
+ /**
31377
+ * Switches to persistent log adapter.
31378
+ * Log entries will be persisted to disk.
31379
+ */
31380
+ this.usePersist = () => {
31381
+ bt.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_PERSIST);
31382
+ this._log = new LogPersistUtils();
31383
+ };
31384
+ /**
31385
+ * Switches to in-memory log adapter (default).
31386
+ * Log entries will be stored in memory only.
31387
+ */
31388
+ this.useMemory = () => {
31389
+ bt.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_MEMORY);
31390
+ this._log = new LogMemoryUtils();
31391
+ };
31392
+ /**
31393
+ * Switches to dummy log adapter.
31394
+ * All future log writes will be no-ops.
31395
+ */
31396
+ this.useDummy = () => {
31397
+ bt.loggerService.info(LOG_ADAPTER_METHOD_NAME_USE_DUMMY);
31398
+ this._log = new LogDummyUtils();
31399
+ };
31400
+ }
31401
+ }
31402
+ /**
31403
+ * Global singleton instance of LogAdapter.
31404
+ * Provides unified log management with pluggable backends.
31405
+ */
31406
+ const Log = new LogAdapter();
31407
+
30885
31408
  const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
30886
31409
  const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
30887
31410
  const BACKTEST_METHOD_NAME_STOP = "BacktestUtils.stop";
@@ -38289,6 +38812,7 @@ exports.Exchange = Exchange;
38289
38812
  exports.ExecutionContextService = ExecutionContextService;
38290
38813
  exports.Heat = Heat;
38291
38814
  exports.Live = Live;
38815
+ exports.Log = Log;
38292
38816
  exports.Markdown = Markdown;
38293
38817
  exports.MarkdownFileBase = MarkdownFileBase;
38294
38818
  exports.MarkdownFolderBase = MarkdownFolderBase;
@@ -38301,6 +38825,7 @@ exports.Performance = Performance;
38301
38825
  exports.PersistBase = PersistBase;
38302
38826
  exports.PersistBreakevenAdapter = PersistBreakevenAdapter;
38303
38827
  exports.PersistCandleAdapter = PersistCandleAdapter;
38828
+ exports.PersistLogAdapter = PersistLogAdapter;
38304
38829
  exports.PersistNotificationAdapter = PersistNotificationAdapter;
38305
38830
  exports.PersistPartialAdapter = PersistPartialAdapter;
38306
38831
  exports.PersistRiskAdapter = PersistRiskAdapter;