@backtest-kit/cli 9.3.0 → 9.5.0

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
@@ -732,6 +732,8 @@ Broker.enable();
732
732
 
733
733
  `@backtest-kit/cli` loads a `{projectRoot}/config/setup.config` file once before any module hooks or strategy code run. Use it to perform one-time initialization that must happen before the first persistence call — registering a custom storage backend, configuring a logger, seeding global state, or anything else the process needs before `backtest-kit` starts.
734
734
 
735
+ **Important:** When `setup.config` is present, the CLI skips its own default adapter registration — it does **not** call `usePersist()` / `useLocal()` / `useMemory()` for any of the persistence slots. This means your config takes full ownership of the persistence layer: whatever adapters you register in `{projectRoot}/config/setup.config` are the ones `backtest-kit` uses, with no interference from the CLI defaults.
736
+
735
737
  ### Example: MongoDB + Redis persistence via `@backtest-kit/mongo`
736
738
 
737
739
  The most common use-case is swapping the default file-based persistence for a production-grade backend. Install `@backtest-kit/mongo` and call `setup()` — it registers all 15 persistence adapters in one call and reads connection parameters from environment variables:
package/build/index.cjs CHANGED
@@ -24,7 +24,7 @@ var jsdom = require('jsdom');
24
24
  var Mustache = require('mustache');
25
25
  var standalone = require('@babel/standalone');
26
26
  var pluginUMD = require('@babel/plugin-transform-modules-umd');
27
- var module$1 = require('module');
27
+ var Module = require('module');
28
28
  var BacktestKitGraph = require('@backtest-kit/graph');
29
29
  var BacktestKitOllama = require('@backtest-kit/ollama');
30
30
  var BacktestKitPinets = require('@backtest-kit/pinets');
@@ -266,6 +266,136 @@ const TYPES = {
266
266
 
267
267
  const entrySubject = new functoolsKit.BehaviorSubject();
268
268
 
269
+ const SETUP_ADAPTER_FN = () => {
270
+ {
271
+ BacktestKit.Dump.useMarkdown();
272
+ }
273
+ {
274
+ BacktestKit.SessionLive.usePersist();
275
+ BacktestKit.SessionBacktest.useLocal();
276
+ }
277
+ {
278
+ BacktestKit.StorageLive.usePersist();
279
+ BacktestKit.StorageBacktest.useMemory();
280
+ }
281
+ {
282
+ BacktestKit.RecentLive.usePersist();
283
+ BacktestKit.RecentBacktest.useMemory();
284
+ }
285
+ {
286
+ BacktestKit.NotificationLive.usePersist();
287
+ BacktestKit.NotificationBacktest.useMemory();
288
+ }
289
+ {
290
+ BacktestKit.RecentLive.usePersist();
291
+ BacktestKit.RecentBacktest.useMemory();
292
+ }
293
+ {
294
+ BacktestKit.MemoryLive.usePersist();
295
+ BacktestKit.MemoryBacktest.useLocal();
296
+ }
297
+ {
298
+ BacktestKit.StateLive.usePersist();
299
+ BacktestKit.StateBacktest.useLocal();
300
+ }
301
+ {
302
+ BacktestKit.Markdown.useDummy();
303
+ BacktestKit.Log.useJsonl();
304
+ }
305
+ };
306
+ class SetupUtils {
307
+ constructor() {
308
+ this.enable = functoolsKit.singleshot(() => {
309
+ cli.loggerService.debug("SetupUtils enable");
310
+ {
311
+ const config = cli.configService.getNotificationConfig();
312
+ BacktestKit.Notification.enable(config);
313
+ }
314
+ {
315
+ BacktestKit.Recent.enable();
316
+ BacktestKit.Storage.enable();
317
+ }
318
+ {
319
+ BacktestKit.Markdown.enable();
320
+ BacktestKit.Report.enable();
321
+ BacktestKit.Dump.enable();
322
+ BacktestKit.State.enable();
323
+ BacktestKit.Memory.enable();
324
+ }
325
+ if (!cli.configConnectionService.hasConfig("setup.config")) {
326
+ SETUP_ADAPTER_FN();
327
+ }
328
+ });
329
+ this.clear = () => {
330
+ cli.loggerService.debug("SetupUtils clear");
331
+ if (!this.enable.hasValue()) {
332
+ return;
333
+ }
334
+ this.enable.clear();
335
+ {
336
+ BacktestKit.Recent.disable();
337
+ BacktestKit.Storage.disable();
338
+ BacktestKit.Notification.disable();
339
+ }
340
+ {
341
+ BacktestKit.Markdown.disable();
342
+ BacktestKit.Report.disable();
343
+ BacktestKit.Dump.disable();
344
+ BacktestKit.Memory.disable();
345
+ }
346
+ {
347
+ BacktestKit.Markdown.clear();
348
+ BacktestKit.Report.clear();
349
+ BacktestKit.MarkdownWriter.clear();
350
+ BacktestKit.ReportWriter.clear();
351
+ }
352
+ {
353
+ BacktestKit.PersistSignalAdapter.clear();
354
+ BacktestKit.PersistRiskAdapter.clear();
355
+ BacktestKit.PersistScheduleAdapter.clear();
356
+ BacktestKit.PersistPartialAdapter.clear();
357
+ BacktestKit.PersistBreakevenAdapter.clear();
358
+ BacktestKit.PersistCandleAdapter.clear();
359
+ BacktestKit.PersistStorageAdapter.clear();
360
+ BacktestKit.PersistNotificationAdapter.clear();
361
+ BacktestKit.PersistLogAdapter.clear();
362
+ BacktestKit.PersistMeasureAdapter.clear();
363
+ BacktestKit.PersistIntervalAdapter.clear();
364
+ BacktestKit.PersistMemoryAdapter.clear();
365
+ BacktestKit.PersistRecentAdapter.clear();
366
+ BacktestKit.PersistStateAdapter.clear();
367
+ BacktestKit.PersistSessionAdapter.clear();
368
+ }
369
+ {
370
+ BacktestKit.Dump.clear();
371
+ BacktestKit.Log.clear();
372
+ BacktestKit.Markdown.clear();
373
+ }
374
+ {
375
+ BacktestKit.StorageLive.clear();
376
+ BacktestKit.StorageBacktest.clear();
377
+ }
378
+ {
379
+ BacktestKit.NotificationLive.clear();
380
+ BacktestKit.NotificationBacktest.clear();
381
+ }
382
+ {
383
+ BacktestKit.RecentLive.clear();
384
+ BacktestKit.RecentBacktest.clear();
385
+ }
386
+ };
387
+ this.update = () => {
388
+ cli.loggerService.debug("SetupUtils update");
389
+ if (cli.configConnectionService.hasConfig("setup.config")) {
390
+ return;
391
+ }
392
+ BacktestKit.Log.useJsonl();
393
+ BacktestKit.Dump.useMarkdown();
394
+ };
395
+ }
396
+ }
397
+ const Setup = new SetupUtils();
398
+
269
399
  const __filename$3 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
270
400
  const __dirname$3 = path.dirname(__filename$3);
271
401
  let _is_launched = false;
@@ -327,7 +457,7 @@ class ResolveService {
327
457
  {
328
458
  const cwd = process.cwd();
329
459
  process.chdir(moduleRoot);
330
- cwd !== moduleRoot && BacktestKit.Log.useJsonl();
460
+ cwd !== moduleRoot && Setup.update();
331
461
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
332
462
  dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
333
463
  this.loaderService.import(absolutePath);
@@ -753,123 +883,6 @@ const notifyVerbose = functoolsKit.singleshot(() => {
753
883
  });
754
884
  });
755
885
 
756
- class SetupUtils {
757
- constructor() {
758
- this.enable = functoolsKit.singleshot(() => {
759
- cli.loggerService.debug("SetupUtils enable");
760
- {
761
- const config = cli.configService.getNotificationConfig();
762
- BacktestKit.Notification.enable(config);
763
- }
764
- {
765
- BacktestKit.Recent.enable();
766
- BacktestKit.Storage.enable();
767
- }
768
- {
769
- BacktestKit.Markdown.enable();
770
- BacktestKit.Report.enable();
771
- BacktestKit.Dump.enable();
772
- BacktestKit.State.enable();
773
- BacktestKit.Memory.enable();
774
- }
775
- {
776
- BacktestKit.Dump.useMarkdown();
777
- }
778
- {
779
- BacktestKit.SessionLive.usePersist();
780
- BacktestKit.SessionBacktest.useLocal();
781
- }
782
- {
783
- BacktestKit.StorageLive.usePersist();
784
- BacktestKit.StorageBacktest.useMemory();
785
- }
786
- {
787
- BacktestKit.RecentLive.usePersist();
788
- BacktestKit.RecentBacktest.useMemory();
789
- }
790
- {
791
- BacktestKit.NotificationLive.usePersist();
792
- BacktestKit.NotificationBacktest.useMemory();
793
- }
794
- {
795
- BacktestKit.RecentLive.usePersist();
796
- BacktestKit.RecentBacktest.useMemory();
797
- }
798
- {
799
- BacktestKit.MemoryLive.usePersist();
800
- BacktestKit.MemoryBacktest.useLocal();
801
- }
802
- {
803
- BacktestKit.StateLive.usePersist();
804
- BacktestKit.StateBacktest.useLocal();
805
- }
806
- {
807
- BacktestKit.Markdown.useDummy();
808
- BacktestKit.Log.useJsonl();
809
- }
810
- });
811
- this.clear = () => {
812
- cli.loggerService.debug("SetupUtils clear");
813
- if (!this.enable.hasValue()) {
814
- return;
815
- }
816
- this.enable.clear();
817
- {
818
- BacktestKit.Recent.disable();
819
- BacktestKit.Storage.disable();
820
- BacktestKit.Notification.disable();
821
- }
822
- {
823
- BacktestKit.Markdown.disable();
824
- BacktestKit.Report.disable();
825
- BacktestKit.Dump.disable();
826
- BacktestKit.Memory.disable();
827
- }
828
- {
829
- BacktestKit.Markdown.clear();
830
- BacktestKit.Report.clear();
831
- BacktestKit.MarkdownWriter.clear();
832
- BacktestKit.ReportWriter.clear();
833
- }
834
- {
835
- BacktestKit.PersistSignalAdapter.clear();
836
- BacktestKit.PersistRiskAdapter.clear();
837
- BacktestKit.PersistScheduleAdapter.clear();
838
- BacktestKit.PersistPartialAdapter.clear();
839
- BacktestKit.PersistBreakevenAdapter.clear();
840
- BacktestKit.PersistCandleAdapter.clear();
841
- BacktestKit.PersistStorageAdapter.clear();
842
- BacktestKit.PersistNotificationAdapter.clear();
843
- BacktestKit.PersistLogAdapter.clear();
844
- BacktestKit.PersistMeasureAdapter.clear();
845
- BacktestKit.PersistIntervalAdapter.clear();
846
- BacktestKit.PersistMemoryAdapter.clear();
847
- BacktestKit.PersistRecentAdapter.clear();
848
- BacktestKit.PersistStateAdapter.clear();
849
- BacktestKit.PersistSessionAdapter.clear();
850
- }
851
- {
852
- BacktestKit.Dump.clear();
853
- BacktestKit.Log.clear();
854
- BacktestKit.Markdown.clear();
855
- }
856
- {
857
- BacktestKit.StorageLive.clear();
858
- BacktestKit.StorageBacktest.clear();
859
- }
860
- {
861
- BacktestKit.NotificationLive.clear();
862
- BacktestKit.NotificationBacktest.clear();
863
- }
864
- {
865
- BacktestKit.RecentLive.clear();
866
- BacktestKit.RecentBacktest.clear();
867
- }
868
- };
869
- }
870
- }
871
- const Setup = new SetupUtils();
872
-
873
886
  const DEFAULT_CACHE_LIST$1 = ["1m", "15m", "30m", "1h", "4h"];
874
887
  const GET_CACHE_INTERVAL_LIST_FN$1 = () => {
875
888
  const { values } = getArgs();
@@ -897,6 +910,10 @@ class BacktestMainService {
897
910
  this.loggerService.log("backtestMainService run", {
898
911
  payload,
899
912
  });
913
+ {
914
+ await this.configConnectionService.loadConfig("setup.config");
915
+ await this.configConnectionService.loadConfig("loader.config");
916
+ }
900
917
  {
901
918
  await this.configService.waitForInit();
902
919
  Setup.enable();
@@ -909,7 +926,6 @@ class BacktestMainService {
909
926
  const cwd = process.cwd();
910
927
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
911
928
  }
912
- await this.configConnectionService.loadConfig("setup.config");
913
929
  {
914
930
  await this.resolveService.attachJavascript(payload.entryPoint);
915
931
  await this.moduleConnectionService.loadModule("backtest.module");
@@ -1016,6 +1032,10 @@ class WalkerMainService {
1016
1032
  this.configConnectionService = inject(TYPES.configConnectionService);
1017
1033
  this.run = functoolsKit.singleshot(async (payload) => {
1018
1034
  this.loggerService.log("walkerMainService run", { payload });
1035
+ {
1036
+ await this.configConnectionService.loadConfig("setup.config");
1037
+ await this.configConnectionService.loadConfig("loader.config");
1038
+ }
1019
1039
  {
1020
1040
  await this.configService.waitForInit();
1021
1041
  Setup.enable();
@@ -1034,7 +1054,7 @@ class WalkerMainService {
1034
1054
  Setup.enable();
1035
1055
  }
1036
1056
  {
1037
- cwd !== moduleRoot && BacktestKit.Log.useJsonl();
1057
+ cwd !== moduleRoot && Setup.update();
1038
1058
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1039
1059
  dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
1040
1060
  }
@@ -1053,7 +1073,6 @@ class WalkerMainService {
1053
1073
  const cwd = process.cwd();
1054
1074
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1055
1075
  }
1056
- await this.configConnectionService.loadConfig("setup.config");
1057
1076
  await this.moduleConnectionService.loadModule("walker.module");
1058
1077
  {
1059
1078
  this.exchangeSchemaService.addSchema();
@@ -1110,7 +1129,7 @@ class WalkerMainService {
1110
1129
  }
1111
1130
  restoreSnapshot();
1112
1131
  {
1113
- cwd !== moduleRoot && BacktestKit.Log.useJsonl();
1132
+ cwd !== moduleRoot && Setup.update();
1114
1133
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1115
1134
  dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
1116
1135
  }
@@ -1241,6 +1260,10 @@ class LiveMainService {
1241
1260
  this.loggerService.log("liveMainService run", {
1242
1261
  payload,
1243
1262
  });
1263
+ {
1264
+ await this.configConnectionService.loadConfig("setup.config");
1265
+ await this.configConnectionService.loadConfig("loader.config");
1266
+ }
1244
1267
  {
1245
1268
  await this.configService.waitForInit();
1246
1269
  Setup.enable();
@@ -1253,7 +1276,6 @@ class LiveMainService {
1253
1276
  const cwd = process.cwd();
1254
1277
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1255
1278
  }
1256
- await this.configConnectionService.loadConfig("setup.config");
1257
1279
  {
1258
1280
  await this.resolveService.attachJavascript(payload.entryPoint);
1259
1281
  await this.moduleConnectionService.loadModule("live.module");
@@ -1327,6 +1349,10 @@ class PaperMainService {
1327
1349
  this.configConnectionService = inject(TYPES.configConnectionService);
1328
1350
  this.run = functoolsKit.singleshot(async (payload) => {
1329
1351
  this.loggerService.log("paperMainService init");
1352
+ {
1353
+ await this.configConnectionService.loadConfig("setup.config");
1354
+ await this.configConnectionService.loadConfig("loader.config");
1355
+ }
1330
1356
  {
1331
1357
  await this.configService.waitForInit();
1332
1358
  Setup.enable();
@@ -1339,7 +1365,6 @@ class PaperMainService {
1339
1365
  const cwd = process.cwd();
1340
1366
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1341
1367
  }
1342
- await this.configConnectionService.loadConfig("setup.config");
1343
1368
  {
1344
1369
  await this.resolveService.attachJavascript(payload.entryPoint);
1345
1370
  await this.moduleConnectionService.loadModule("paper.module");
@@ -2540,12 +2565,22 @@ class ModuleConnectionService {
2540
2565
  this.loggerService = inject(TYPES.loggerService);
2541
2566
  this.resolveService = inject(TYPES.resolveService);
2542
2567
  this.loaderService = inject(TYPES.loaderService);
2543
- this.loadModule = async (fileName) => {
2544
- this.loggerService.log("moduleConnectionService loadModule", {
2568
+ this.hasModule = (fileName) => {
2569
+ this.loggerService.log("moduleConnectionService hasModule", {
2545
2570
  fileName,
2546
2571
  });
2547
- return await LOAD_MODULE_MODULE_FN(fileName, this);
2572
+ return this.loadModule.has(fileName);
2548
2573
  };
2574
+ this.loadModule = functoolsKit.memoize(([fileName]) => `${fileName}`, async (fileName) => {
2575
+ this.loggerService.log("moduleConnectionService loadModule", {
2576
+ fileName,
2577
+ });
2578
+ const module = await LOAD_MODULE_MODULE_FN(fileName, this);
2579
+ if (!module) {
2580
+ this.loadModule.clear(fileName);
2581
+ }
2582
+ return module;
2583
+ });
2549
2584
  }
2550
2585
  }
2551
2586
 
@@ -2588,6 +2623,18 @@ class BabelService {
2588
2623
  }
2589
2624
  }
2590
2625
 
2626
+ const require$1 = Module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
2627
+ const ModuleWithCache = Module;
2628
+ function overrideModule(moduleName, newExports) {
2629
+ const cache = ModuleWithCache._cache;
2630
+ const key = require$1.resolve(moduleName);
2631
+ if (!cache[key]) {
2632
+ cache[key] = new ModuleWithCache(key);
2633
+ cache[key].loaded = true;
2634
+ }
2635
+ cache[key].exports = newExports;
2636
+ }
2637
+
2591
2638
  /**
2592
2639
  * This file is used to define any aliases for imports in the client code. This is useful for mocking modules during testing or for providing alternative implementations of certain modules.
2593
2640
  * For example, if we want to mock the "pinets" module during testing, we can add an entry to the IMPORT_ALIAS object that points to our mock implementation. Then, when the client code tries to import "pinets", it will receive our mock implementation instead of the actual "pinets" module.
@@ -2770,7 +2817,7 @@ class ClientLoader {
2770
2817
  this.params.logger.log("ClientLoader baseRequire", {
2771
2818
  basePath: this.params.path,
2772
2819
  });
2773
- return module$1.createRequire(this.__filename);
2820
+ return Module.createRequire(this.__filename);
2774
2821
  });
2775
2822
  this.__filename = path.join(params.path, "index.cjs");
2776
2823
  this.__dirname = path.dirname(this.__filename);
@@ -2824,6 +2871,13 @@ globalThis.BacktestKitGraph = BacktestKitGraph__namespace;
2824
2871
  globalThis.BacktestKitOllama = BacktestKitOllama__namespace;
2825
2872
  globalThis.BacktestKitPinets = BacktestKitPinets__namespace;
2826
2873
  globalThis.BacktestKitSignals = BacktestKitSignals__namespace;
2874
+ overrideModule('backtest-kit', BacktestKit__namespace);
2875
+ overrideModule('@backtest-kit/cli', BacktestKitCli);
2876
+ overrideModule('@backtest-kit/ui', BacktestKitUi__namespace);
2877
+ overrideModule('@backtest-kit/graph', BacktestKitGraph__namespace);
2878
+ overrideModule('@backtest-kit/ollama', BacktestKitOllama__namespace);
2879
+ overrideModule('@backtest-kit/pinets', BacktestKitPinets__namespace);
2880
+ overrideModule('@backtest-kit/signals', BacktestKitSignals__namespace);
2827
2881
 
2828
2882
  const GET_ALIAS_EXPORTS_FN = (self) => {
2829
2883
  const instance = self.getInstance(self.resolveService.OVERRIDE_CONFIG_DIR);
@@ -2831,9 +2885,7 @@ const GET_ALIAS_EXPORTS_FN = (self) => {
2831
2885
  return null;
2832
2886
  }
2833
2887
  const exports = instance.import("alias.config");
2834
- return "default" in exports
2835
- ? exports.default
2836
- : exports;
2888
+ return "default" in exports ? exports.default : exports;
2837
2889
  };
2838
2890
  const INIT_ALIAS_FN = (self) => {
2839
2891
  const alias = GET_ALIAS_EXPORTS_FN(self);
@@ -2843,7 +2895,10 @@ const INIT_ALIAS_FN = (self) => {
2843
2895
  if (!functoolsKit.isObject(alias)) {
2844
2896
  return;
2845
2897
  }
2846
- Object.assign(IMPORT_ALIAS, alias);
2898
+ {
2899
+ Object.entries(alias).forEach(([name, module]) => overrideModule(name, module));
2900
+ Object.assign(IMPORT_ALIAS, alias);
2901
+ }
2847
2902
  };
2848
2903
  class LoaderService {
2849
2904
  constructor() {
@@ -2914,12 +2969,22 @@ class ConfigConnectionService {
2914
2969
  this.loggerService = inject(TYPES.loggerService);
2915
2970
  this.resolveService = inject(TYPES.resolveService);
2916
2971
  this.loaderService = inject(TYPES.loaderService);
2917
- this.loadConfig = (fileName) => {
2918
- this.loggerService.log("configConnectionService loadConfig", {
2972
+ this.hasConfig = (fileName) => {
2973
+ this.loggerService.log("configConnectionService hasConfig", {
2919
2974
  fileName,
2920
2975
  });
2921
- return LOAD_CONFIG_CONFIG_FN(fileName, this);
2976
+ return this.loadConfig.has(fileName);
2922
2977
  };
2978
+ this.loadConfig = functoolsKit.memoize(([fileName]) => `${fileName}`, async (fileName) => {
2979
+ this.loggerService.log("configConnectionService loadConfig", {
2980
+ fileName,
2981
+ });
2982
+ const config = await LOAD_CONFIG_CONFIG_FN(fileName, this);
2983
+ if (!config) {
2984
+ this.loadConfig.clear(fileName);
2985
+ }
2986
+ return config;
2987
+ });
2923
2988
  }
2924
2989
  }
2925
2990
 
@@ -3075,7 +3140,7 @@ const main$g = async () => {
3075
3140
  if (MODES.some((mode) => values[mode])) {
3076
3141
  return;
3077
3142
  }
3078
- process.stdout.write(`@backtest-kit/cli ${"9.3.0"}\n`);
3143
+ process.stdout.write(`@backtest-kit/cli ${"9.5.0"}\n`);
3079
3144
  process.stdout.write("\n");
3080
3145
  process.stdout.write(`Run with --help to see available commands.\n`);
3081
3146
  process.stdout.write("\n");
@@ -3356,26 +3421,36 @@ const main$a = async () => {
3356
3421
  process.exit(1);
3357
3422
  return;
3358
3423
  }
3359
- const [entryPoint = null] = getPositionals();
3360
- if (!entryPoint) {
3361
- throw new Error("Entry point is required");
3424
+ const entryPoints = getPositionals();
3425
+ if (!entryPoints.length) {
3426
+ throw new Error("At least one entry point is required");
3362
3427
  }
3363
- if (!values.noFlush) {
3428
+ for (const entryPoint of entryPoints) {
3429
+ if (values.noFlush) {
3430
+ continue;
3431
+ }
3364
3432
  await flush(entryPoint);
3365
3433
  }
3366
- await cli.configService.waitForInit();
3367
- Setup.enable();
3434
+ {
3435
+ await cli.configConnectionService.loadConfig("setup.config");
3436
+ await cli.configConnectionService.loadConfig("loader.config");
3437
+ }
3438
+ {
3439
+ await cli.configService.waitForInit();
3440
+ Setup.enable();
3441
+ }
3368
3442
  cli.frontendProviderService.connect();
3369
3443
  cli.telegramProviderService.connect();
3370
3444
  {
3371
3445
  const cwd = process.cwd();
3372
3446
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3373
3447
  }
3374
- await cli.configConnectionService.loadConfig("setup.config");
3375
3448
  await cli.moduleConnectionService.loadModule(MODE_MODULE[mode]);
3376
3449
  listenFinish();
3377
3450
  createGracefulShutdown(mode)();
3378
- await cli.resolveService.attachEntry(entryPoint);
3451
+ for (const entryPoint of entryPoints) {
3452
+ await cli.resolveService.attachEntry(entryPoint);
3453
+ }
3379
3454
  };
3380
3455
  main$a();
3381
3456
 
@@ -3460,7 +3535,10 @@ const main$7 = async () => {
3460
3535
  const cwd = process.cwd();
3461
3536
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3462
3537
  }
3463
- await cli.configConnectionService.loadConfig("setup.config");
3538
+ {
3539
+ await cli.configConnectionService.loadConfig("setup.config");
3540
+ await cli.configConnectionService.loadConfig("loader.config");
3541
+ }
3464
3542
  await cli.moduleConnectionService.loadModule("pine.module");
3465
3543
  {
3466
3544
  await cli.exchangeSchemaService.addSchema();
@@ -3538,6 +3616,10 @@ const main$6 = async () => {
3538
3616
  console.warn("--editor and --pine are mutually exclusive. Use one at a time.");
3539
3617
  process.exit(1);
3540
3618
  }
3619
+ {
3620
+ await cli.configConnectionService.loadConfig("setup.config");
3621
+ await cli.configConnectionService.loadConfig("loader.config");
3622
+ }
3541
3623
  {
3542
3624
  await cli.configService.waitForInit();
3543
3625
  Setup.enable();
@@ -3546,7 +3628,6 @@ const main$6 = async () => {
3546
3628
  const cwd = process.cwd();
3547
3629
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3548
3630
  }
3549
- await cli.configConnectionService.loadConfig("setup.config");
3550
3631
  await cli.moduleConnectionService.loadModule("editor.module");
3551
3632
  {
3552
3633
  await cli.exchangeSchemaService.addSchema();
@@ -3580,7 +3661,10 @@ const main$5 = async () => {
3580
3661
  const cwd = process.cwd();
3581
3662
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3582
3663
  }
3583
- await cli.configConnectionService.loadConfig("setup.config");
3664
+ {
3665
+ await cli.configConnectionService.loadConfig("setup.config");
3666
+ await cli.configConnectionService.loadConfig("loader.config");
3667
+ }
3584
3668
  await cli.moduleConnectionService.loadModule("dump.module");
3585
3669
  {
3586
3670
  await cli.exchangeSchemaService.addSchema();
@@ -3648,7 +3732,10 @@ const main$4 = async () => {
3648
3732
  const cwd = process.cwd();
3649
3733
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3650
3734
  }
3651
- await cli.configConnectionService.loadConfig("setup.config");
3735
+ {
3736
+ await cli.configConnectionService.loadConfig("setup.config");
3737
+ await cli.configConnectionService.loadConfig("loader.config");
3738
+ }
3652
3739
  await cli.moduleConnectionService.loadModule("pnldebug.module");
3653
3740
  {
3654
3741
  await cli.exchangeSchemaService.addSchema();
@@ -4103,7 +4190,7 @@ const main$1 = async () => {
4103
4190
  if (!values.help) {
4104
4191
  return;
4105
4192
  }
4106
- process.stdout.write(`@backtest-kit/cli ${"9.3.0"}\n\n`);
4193
+ process.stdout.write(`@backtest-kit/cli ${"9.5.0"}\n\n`);
4107
4194
  process.stdout.write(HELP_TEXT);
4108
4195
  process.exit(0);
4109
4196
  };
@@ -4117,7 +4204,7 @@ const main = async () => {
4117
4204
  if (!values.version) {
4118
4205
  return;
4119
4206
  }
4120
- process.stdout.write(`@backtest-kit/cli ${"9.3.0"}\n`);
4207
+ process.stdout.write(`@backtest-kit/cli ${"9.5.0"}\n`);
4121
4208
  process.exit(0);
4122
4209
  };
4123
4210
  main();
package/build/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import * as BacktestKit from 'backtest-kit';
3
- import { setConfig, Log, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, Notification, Recent, Storage, Markdown, Report, Dump, State, Memory, SessionLive, SessionBacktest, StorageLive, StorageBacktest, RecentLive, RecentBacktest, NotificationLive, NotificationBacktest, MemoryLive, MemoryBacktest, StateLive, StateBacktest, MarkdownWriter, ReportWriter, PersistSignalAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistPartialAdapter, PersistBreakevenAdapter, PersistCandleAdapter, PersistStorageAdapter, PersistNotificationAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistIntervalAdapter, PersistMemoryAdapter, PersistRecentAdapter, PersistStateAdapter, PersistSessionAdapter, listStrategySchema, overrideExchangeSchema, Backtest, System, Cache, Interval, alignToInterval, addWalkerSchema, overrideWalkerSchema, Walker, listenDoneWalker, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync, listenSignalNotify, Exchange } from 'backtest-kit';
3
+ import { setConfig, Notification, Recent, Storage, Markdown, Report, Dump, State, Memory, MarkdownWriter, ReportWriter, PersistSignalAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistPartialAdapter, PersistBreakevenAdapter, PersistCandleAdapter, PersistStorageAdapter, PersistNotificationAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistIntervalAdapter, PersistMemoryAdapter, PersistRecentAdapter, PersistStateAdapter, PersistSessionAdapter, Log, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, RecentLive, RecentBacktest, SessionLive, SessionBacktest, MemoryLive, MemoryBacktest, StateLive, StateBacktest, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, System, Cache, Interval, alignToInterval, addWalkerSchema, overrideWalkerSchema, Walker, listenDoneWalker, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync, listenSignalNotify, Exchange } from 'backtest-kit';
4
4
  import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, createAwaiter, execpool, queued, sleep, randomString, TIMEOUT_SYMBOL, typo, retry, trycatch, memoize, isObject } from 'functools-kit';
5
5
  import fs, { constants, realpathSync } from 'fs';
6
6
  import * as stackTrace from 'stack-trace';
@@ -24,7 +24,7 @@ import { JSDOM } from 'jsdom';
24
24
  import Mustache from 'mustache';
25
25
  import { registerPlugin, transform } from '@babel/standalone';
26
26
  import pluginUMD from '@babel/plugin-transform-modules-umd';
27
- import { createRequire } from 'module';
27
+ import Module, { createRequire } from 'module';
28
28
  import * as BacktestKitGraph from '@backtest-kit/graph';
29
29
  import * as BacktestKitOllama from '@backtest-kit/ollama';
30
30
  import * as BacktestKitPinets from '@backtest-kit/pinets';
@@ -241,6 +241,136 @@ const TYPES = {
241
241
 
242
242
  const entrySubject = new BehaviorSubject();
243
243
 
244
+ const SETUP_ADAPTER_FN = () => {
245
+ {
246
+ Dump.useMarkdown();
247
+ }
248
+ {
249
+ SessionLive.usePersist();
250
+ SessionBacktest.useLocal();
251
+ }
252
+ {
253
+ StorageLive.usePersist();
254
+ StorageBacktest.useMemory();
255
+ }
256
+ {
257
+ RecentLive.usePersist();
258
+ RecentBacktest.useMemory();
259
+ }
260
+ {
261
+ NotificationLive.usePersist();
262
+ NotificationBacktest.useMemory();
263
+ }
264
+ {
265
+ RecentLive.usePersist();
266
+ RecentBacktest.useMemory();
267
+ }
268
+ {
269
+ MemoryLive.usePersist();
270
+ MemoryBacktest.useLocal();
271
+ }
272
+ {
273
+ StateLive.usePersist();
274
+ StateBacktest.useLocal();
275
+ }
276
+ {
277
+ Markdown.useDummy();
278
+ Log.useJsonl();
279
+ }
280
+ };
281
+ class SetupUtils {
282
+ constructor() {
283
+ this.enable = singleshot(() => {
284
+ cli.loggerService.debug("SetupUtils enable");
285
+ {
286
+ const config = cli.configService.getNotificationConfig();
287
+ Notification.enable(config);
288
+ }
289
+ {
290
+ Recent.enable();
291
+ Storage.enable();
292
+ }
293
+ {
294
+ Markdown.enable();
295
+ Report.enable();
296
+ Dump.enable();
297
+ State.enable();
298
+ Memory.enable();
299
+ }
300
+ if (!cli.configConnectionService.hasConfig("setup.config")) {
301
+ SETUP_ADAPTER_FN();
302
+ }
303
+ });
304
+ this.clear = () => {
305
+ cli.loggerService.debug("SetupUtils clear");
306
+ if (!this.enable.hasValue()) {
307
+ return;
308
+ }
309
+ this.enable.clear();
310
+ {
311
+ Recent.disable();
312
+ Storage.disable();
313
+ Notification.disable();
314
+ }
315
+ {
316
+ Markdown.disable();
317
+ Report.disable();
318
+ Dump.disable();
319
+ Memory.disable();
320
+ }
321
+ {
322
+ Markdown.clear();
323
+ Report.clear();
324
+ MarkdownWriter.clear();
325
+ ReportWriter.clear();
326
+ }
327
+ {
328
+ PersistSignalAdapter.clear();
329
+ PersistRiskAdapter.clear();
330
+ PersistScheduleAdapter.clear();
331
+ PersistPartialAdapter.clear();
332
+ PersistBreakevenAdapter.clear();
333
+ PersistCandleAdapter.clear();
334
+ PersistStorageAdapter.clear();
335
+ PersistNotificationAdapter.clear();
336
+ PersistLogAdapter.clear();
337
+ PersistMeasureAdapter.clear();
338
+ PersistIntervalAdapter.clear();
339
+ PersistMemoryAdapter.clear();
340
+ PersistRecentAdapter.clear();
341
+ PersistStateAdapter.clear();
342
+ PersistSessionAdapter.clear();
343
+ }
344
+ {
345
+ Dump.clear();
346
+ Log.clear();
347
+ Markdown.clear();
348
+ }
349
+ {
350
+ StorageLive.clear();
351
+ StorageBacktest.clear();
352
+ }
353
+ {
354
+ NotificationLive.clear();
355
+ NotificationBacktest.clear();
356
+ }
357
+ {
358
+ RecentLive.clear();
359
+ RecentBacktest.clear();
360
+ }
361
+ };
362
+ this.update = () => {
363
+ cli.loggerService.debug("SetupUtils update");
364
+ if (cli.configConnectionService.hasConfig("setup.config")) {
365
+ return;
366
+ }
367
+ Log.useJsonl();
368
+ Dump.useMarkdown();
369
+ };
370
+ }
371
+ }
372
+ const Setup = new SetupUtils();
373
+
244
374
  const __filename$2 = fileURLToPath(import.meta.url);
245
375
  const __dirname$2 = path.dirname(__filename$2);
246
376
  let _is_launched = false;
@@ -302,7 +432,7 @@ class ResolveService {
302
432
  {
303
433
  const cwd = process.cwd();
304
434
  process.chdir(moduleRoot);
305
- cwd !== moduleRoot && Log.useJsonl();
435
+ cwd !== moduleRoot && Setup.update();
306
436
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
307
437
  dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
308
438
  this.loaderService.import(absolutePath);
@@ -728,123 +858,6 @@ const notifyVerbose = singleshot(() => {
728
858
  });
729
859
  });
730
860
 
731
- class SetupUtils {
732
- constructor() {
733
- this.enable = singleshot(() => {
734
- cli.loggerService.debug("SetupUtils enable");
735
- {
736
- const config = cli.configService.getNotificationConfig();
737
- Notification.enable(config);
738
- }
739
- {
740
- Recent.enable();
741
- Storage.enable();
742
- }
743
- {
744
- Markdown.enable();
745
- Report.enable();
746
- Dump.enable();
747
- State.enable();
748
- Memory.enable();
749
- }
750
- {
751
- Dump.useMarkdown();
752
- }
753
- {
754
- SessionLive.usePersist();
755
- SessionBacktest.useLocal();
756
- }
757
- {
758
- StorageLive.usePersist();
759
- StorageBacktest.useMemory();
760
- }
761
- {
762
- RecentLive.usePersist();
763
- RecentBacktest.useMemory();
764
- }
765
- {
766
- NotificationLive.usePersist();
767
- NotificationBacktest.useMemory();
768
- }
769
- {
770
- RecentLive.usePersist();
771
- RecentBacktest.useMemory();
772
- }
773
- {
774
- MemoryLive.usePersist();
775
- MemoryBacktest.useLocal();
776
- }
777
- {
778
- StateLive.usePersist();
779
- StateBacktest.useLocal();
780
- }
781
- {
782
- Markdown.useDummy();
783
- Log.useJsonl();
784
- }
785
- });
786
- this.clear = () => {
787
- cli.loggerService.debug("SetupUtils clear");
788
- if (!this.enable.hasValue()) {
789
- return;
790
- }
791
- this.enable.clear();
792
- {
793
- Recent.disable();
794
- Storage.disable();
795
- Notification.disable();
796
- }
797
- {
798
- Markdown.disable();
799
- Report.disable();
800
- Dump.disable();
801
- Memory.disable();
802
- }
803
- {
804
- Markdown.clear();
805
- Report.clear();
806
- MarkdownWriter.clear();
807
- ReportWriter.clear();
808
- }
809
- {
810
- PersistSignalAdapter.clear();
811
- PersistRiskAdapter.clear();
812
- PersistScheduleAdapter.clear();
813
- PersistPartialAdapter.clear();
814
- PersistBreakevenAdapter.clear();
815
- PersistCandleAdapter.clear();
816
- PersistStorageAdapter.clear();
817
- PersistNotificationAdapter.clear();
818
- PersistLogAdapter.clear();
819
- PersistMeasureAdapter.clear();
820
- PersistIntervalAdapter.clear();
821
- PersistMemoryAdapter.clear();
822
- PersistRecentAdapter.clear();
823
- PersistStateAdapter.clear();
824
- PersistSessionAdapter.clear();
825
- }
826
- {
827
- Dump.clear();
828
- Log.clear();
829
- Markdown.clear();
830
- }
831
- {
832
- StorageLive.clear();
833
- StorageBacktest.clear();
834
- }
835
- {
836
- NotificationLive.clear();
837
- NotificationBacktest.clear();
838
- }
839
- {
840
- RecentLive.clear();
841
- RecentBacktest.clear();
842
- }
843
- };
844
- }
845
- }
846
- const Setup = new SetupUtils();
847
-
848
861
  const DEFAULT_CACHE_LIST$1 = ["1m", "15m", "30m", "1h", "4h"];
849
862
  const GET_CACHE_INTERVAL_LIST_FN$1 = () => {
850
863
  const { values } = getArgs();
@@ -872,6 +885,10 @@ class BacktestMainService {
872
885
  this.loggerService.log("backtestMainService run", {
873
886
  payload,
874
887
  });
888
+ {
889
+ await this.configConnectionService.loadConfig("setup.config");
890
+ await this.configConnectionService.loadConfig("loader.config");
891
+ }
875
892
  {
876
893
  await this.configService.waitForInit();
877
894
  Setup.enable();
@@ -884,7 +901,6 @@ class BacktestMainService {
884
901
  const cwd = process.cwd();
885
902
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
886
903
  }
887
- await this.configConnectionService.loadConfig("setup.config");
888
904
  {
889
905
  await this.resolveService.attachJavascript(payload.entryPoint);
890
906
  await this.moduleConnectionService.loadModule("backtest.module");
@@ -991,6 +1007,10 @@ class WalkerMainService {
991
1007
  this.configConnectionService = inject(TYPES.configConnectionService);
992
1008
  this.run = singleshot(async (payload) => {
993
1009
  this.loggerService.log("walkerMainService run", { payload });
1010
+ {
1011
+ await this.configConnectionService.loadConfig("setup.config");
1012
+ await this.configConnectionService.loadConfig("loader.config");
1013
+ }
994
1014
  {
995
1015
  await this.configService.waitForInit();
996
1016
  Setup.enable();
@@ -1009,7 +1029,7 @@ class WalkerMainService {
1009
1029
  Setup.enable();
1010
1030
  }
1011
1031
  {
1012
- cwd !== moduleRoot && Log.useJsonl();
1032
+ cwd !== moduleRoot && Setup.update();
1013
1033
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1014
1034
  dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
1015
1035
  }
@@ -1028,7 +1048,6 @@ class WalkerMainService {
1028
1048
  const cwd = process.cwd();
1029
1049
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1030
1050
  }
1031
- await this.configConnectionService.loadConfig("setup.config");
1032
1051
  await this.moduleConnectionService.loadModule("walker.module");
1033
1052
  {
1034
1053
  this.exchangeSchemaService.addSchema();
@@ -1085,7 +1104,7 @@ class WalkerMainService {
1085
1104
  }
1086
1105
  restoreSnapshot();
1087
1106
  {
1088
- cwd !== moduleRoot && Log.useJsonl();
1107
+ cwd !== moduleRoot && Setup.update();
1089
1108
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1090
1109
  dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
1091
1110
  }
@@ -1216,6 +1235,10 @@ class LiveMainService {
1216
1235
  this.loggerService.log("liveMainService run", {
1217
1236
  payload,
1218
1237
  });
1238
+ {
1239
+ await this.configConnectionService.loadConfig("setup.config");
1240
+ await this.configConnectionService.loadConfig("loader.config");
1241
+ }
1219
1242
  {
1220
1243
  await this.configService.waitForInit();
1221
1244
  Setup.enable();
@@ -1228,7 +1251,6 @@ class LiveMainService {
1228
1251
  const cwd = process.cwd();
1229
1252
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1230
1253
  }
1231
- await this.configConnectionService.loadConfig("setup.config");
1232
1254
  {
1233
1255
  await this.resolveService.attachJavascript(payload.entryPoint);
1234
1256
  await this.moduleConnectionService.loadModule("live.module");
@@ -1302,6 +1324,10 @@ class PaperMainService {
1302
1324
  this.configConnectionService = inject(TYPES.configConnectionService);
1303
1325
  this.run = singleshot(async (payload) => {
1304
1326
  this.loggerService.log("paperMainService init");
1327
+ {
1328
+ await this.configConnectionService.loadConfig("setup.config");
1329
+ await this.configConnectionService.loadConfig("loader.config");
1330
+ }
1305
1331
  {
1306
1332
  await this.configService.waitForInit();
1307
1333
  Setup.enable();
@@ -1314,7 +1340,6 @@ class PaperMainService {
1314
1340
  const cwd = process.cwd();
1315
1341
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
1316
1342
  }
1317
- await this.configConnectionService.loadConfig("setup.config");
1318
1343
  {
1319
1344
  await this.resolveService.attachJavascript(payload.entryPoint);
1320
1345
  await this.moduleConnectionService.loadModule("paper.module");
@@ -2515,12 +2540,22 @@ class ModuleConnectionService {
2515
2540
  this.loggerService = inject(TYPES.loggerService);
2516
2541
  this.resolveService = inject(TYPES.resolveService);
2517
2542
  this.loaderService = inject(TYPES.loaderService);
2518
- this.loadModule = async (fileName) => {
2519
- this.loggerService.log("moduleConnectionService loadModule", {
2543
+ this.hasModule = (fileName) => {
2544
+ this.loggerService.log("moduleConnectionService hasModule", {
2520
2545
  fileName,
2521
2546
  });
2522
- return await LOAD_MODULE_MODULE_FN(fileName, this);
2547
+ return this.loadModule.has(fileName);
2523
2548
  };
2549
+ this.loadModule = memoize(([fileName]) => `${fileName}`, async (fileName) => {
2550
+ this.loggerService.log("moduleConnectionService loadModule", {
2551
+ fileName,
2552
+ });
2553
+ const module = await LOAD_MODULE_MODULE_FN(fileName, this);
2554
+ if (!module) {
2555
+ this.loadModule.clear(fileName);
2556
+ }
2557
+ return module;
2558
+ });
2524
2559
  }
2525
2560
  }
2526
2561
 
@@ -2563,6 +2598,18 @@ class BabelService {
2563
2598
  }
2564
2599
  }
2565
2600
 
2601
+ const require = createRequire(import.meta.url);
2602
+ const ModuleWithCache = Module;
2603
+ function overrideModule(moduleName, newExports) {
2604
+ const cache = ModuleWithCache._cache;
2605
+ const key = require.resolve(moduleName);
2606
+ if (!cache[key]) {
2607
+ cache[key] = new ModuleWithCache(key);
2608
+ cache[key].loaded = true;
2609
+ }
2610
+ cache[key].exports = newExports;
2611
+ }
2612
+
2566
2613
  /**
2567
2614
  * This file is used to define any aliases for imports in the client code. This is useful for mocking modules during testing or for providing alternative implementations of certain modules.
2568
2615
  * For example, if we want to mock the "pinets" module during testing, we can add an entry to the IMPORT_ALIAS object that points to our mock implementation. Then, when the client code tries to import "pinets", it will receive our mock implementation instead of the actual "pinets" module.
@@ -2795,6 +2842,13 @@ globalThis.BacktestKitGraph = BacktestKitGraph;
2795
2842
  globalThis.BacktestKitOllama = BacktestKitOllama;
2796
2843
  globalThis.BacktestKitPinets = BacktestKitPinets;
2797
2844
  globalThis.BacktestKitSignals = BacktestKitSignals;
2845
+ overrideModule('backtest-kit', BacktestKit);
2846
+ overrideModule('@backtest-kit/cli', BacktestKitCli);
2847
+ overrideModule('@backtest-kit/ui', BacktestKitUi);
2848
+ overrideModule('@backtest-kit/graph', BacktestKitGraph);
2849
+ overrideModule('@backtest-kit/ollama', BacktestKitOllama);
2850
+ overrideModule('@backtest-kit/pinets', BacktestKitPinets);
2851
+ overrideModule('@backtest-kit/signals', BacktestKitSignals);
2798
2852
 
2799
2853
  const GET_ALIAS_EXPORTS_FN = (self) => {
2800
2854
  const instance = self.getInstance(self.resolveService.OVERRIDE_CONFIG_DIR);
@@ -2802,9 +2856,7 @@ const GET_ALIAS_EXPORTS_FN = (self) => {
2802
2856
  return null;
2803
2857
  }
2804
2858
  const exports = instance.import("alias.config");
2805
- return "default" in exports
2806
- ? exports.default
2807
- : exports;
2859
+ return "default" in exports ? exports.default : exports;
2808
2860
  };
2809
2861
  const INIT_ALIAS_FN = (self) => {
2810
2862
  const alias = GET_ALIAS_EXPORTS_FN(self);
@@ -2814,7 +2866,10 @@ const INIT_ALIAS_FN = (self) => {
2814
2866
  if (!isObject(alias)) {
2815
2867
  return;
2816
2868
  }
2817
- Object.assign(IMPORT_ALIAS, alias);
2869
+ {
2870
+ Object.entries(alias).forEach(([name, module]) => overrideModule(name, module));
2871
+ Object.assign(IMPORT_ALIAS, alias);
2872
+ }
2818
2873
  };
2819
2874
  class LoaderService {
2820
2875
  constructor() {
@@ -2885,12 +2940,22 @@ class ConfigConnectionService {
2885
2940
  this.loggerService = inject(TYPES.loggerService);
2886
2941
  this.resolveService = inject(TYPES.resolveService);
2887
2942
  this.loaderService = inject(TYPES.loaderService);
2888
- this.loadConfig = (fileName) => {
2889
- this.loggerService.log("configConnectionService loadConfig", {
2943
+ this.hasConfig = (fileName) => {
2944
+ this.loggerService.log("configConnectionService hasConfig", {
2890
2945
  fileName,
2891
2946
  });
2892
- return LOAD_CONFIG_CONFIG_FN(fileName, this);
2947
+ return this.loadConfig.has(fileName);
2893
2948
  };
2949
+ this.loadConfig = memoize(([fileName]) => `${fileName}`, async (fileName) => {
2950
+ this.loggerService.log("configConnectionService loadConfig", {
2951
+ fileName,
2952
+ });
2953
+ const config = await LOAD_CONFIG_CONFIG_FN(fileName, this);
2954
+ if (!config) {
2955
+ this.loadConfig.clear(fileName);
2956
+ }
2957
+ return config;
2958
+ });
2894
2959
  }
2895
2960
  }
2896
2961
 
@@ -3046,7 +3111,7 @@ const main$g = async () => {
3046
3111
  if (MODES.some((mode) => values[mode])) {
3047
3112
  return;
3048
3113
  }
3049
- process.stdout.write(`@backtest-kit/cli ${"9.3.0"}\n`);
3114
+ process.stdout.write(`@backtest-kit/cli ${"9.5.0"}\n`);
3050
3115
  process.stdout.write("\n");
3051
3116
  process.stdout.write(`Run with --help to see available commands.\n`);
3052
3117
  process.stdout.write("\n");
@@ -3327,26 +3392,36 @@ const main$a = async () => {
3327
3392
  process.exit(1);
3328
3393
  return;
3329
3394
  }
3330
- const [entryPoint = null] = getPositionals();
3331
- if (!entryPoint) {
3332
- throw new Error("Entry point is required");
3395
+ const entryPoints = getPositionals();
3396
+ if (!entryPoints.length) {
3397
+ throw new Error("At least one entry point is required");
3333
3398
  }
3334
- if (!values.noFlush) {
3399
+ for (const entryPoint of entryPoints) {
3400
+ if (values.noFlush) {
3401
+ continue;
3402
+ }
3335
3403
  await flush(entryPoint);
3336
3404
  }
3337
- await cli.configService.waitForInit();
3338
- Setup.enable();
3405
+ {
3406
+ await cli.configConnectionService.loadConfig("setup.config");
3407
+ await cli.configConnectionService.loadConfig("loader.config");
3408
+ }
3409
+ {
3410
+ await cli.configService.waitForInit();
3411
+ Setup.enable();
3412
+ }
3339
3413
  cli.frontendProviderService.connect();
3340
3414
  cli.telegramProviderService.connect();
3341
3415
  {
3342
3416
  const cwd = process.cwd();
3343
3417
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3344
3418
  }
3345
- await cli.configConnectionService.loadConfig("setup.config");
3346
3419
  await cli.moduleConnectionService.loadModule(MODE_MODULE[mode]);
3347
3420
  listenFinish();
3348
3421
  createGracefulShutdown(mode)();
3349
- await cli.resolveService.attachEntry(entryPoint);
3422
+ for (const entryPoint of entryPoints) {
3423
+ await cli.resolveService.attachEntry(entryPoint);
3424
+ }
3350
3425
  };
3351
3426
  main$a();
3352
3427
 
@@ -3431,7 +3506,10 @@ const main$7 = async () => {
3431
3506
  const cwd = process.cwd();
3432
3507
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3433
3508
  }
3434
- await cli.configConnectionService.loadConfig("setup.config");
3509
+ {
3510
+ await cli.configConnectionService.loadConfig("setup.config");
3511
+ await cli.configConnectionService.loadConfig("loader.config");
3512
+ }
3435
3513
  await cli.moduleConnectionService.loadModule("pine.module");
3436
3514
  {
3437
3515
  await cli.exchangeSchemaService.addSchema();
@@ -3509,6 +3587,10 @@ const main$6 = async () => {
3509
3587
  console.warn("--editor and --pine are mutually exclusive. Use one at a time.");
3510
3588
  process.exit(1);
3511
3589
  }
3590
+ {
3591
+ await cli.configConnectionService.loadConfig("setup.config");
3592
+ await cli.configConnectionService.loadConfig("loader.config");
3593
+ }
3512
3594
  {
3513
3595
  await cli.configService.waitForInit();
3514
3596
  Setup.enable();
@@ -3517,7 +3599,6 @@ const main$6 = async () => {
3517
3599
  const cwd = process.cwd();
3518
3600
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3519
3601
  }
3520
- await cli.configConnectionService.loadConfig("setup.config");
3521
3602
  await cli.moduleConnectionService.loadModule("editor.module");
3522
3603
  {
3523
3604
  await cli.exchangeSchemaService.addSchema();
@@ -3551,7 +3632,10 @@ const main$5 = async () => {
3551
3632
  const cwd = process.cwd();
3552
3633
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3553
3634
  }
3554
- await cli.configConnectionService.loadConfig("setup.config");
3635
+ {
3636
+ await cli.configConnectionService.loadConfig("setup.config");
3637
+ await cli.configConnectionService.loadConfig("loader.config");
3638
+ }
3555
3639
  await cli.moduleConnectionService.loadModule("dump.module");
3556
3640
  {
3557
3641
  await cli.exchangeSchemaService.addSchema();
@@ -3619,7 +3703,10 @@ const main$4 = async () => {
3619
3703
  const cwd = process.cwd();
3620
3704
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3621
3705
  }
3622
- await cli.configConnectionService.loadConfig("setup.config");
3706
+ {
3707
+ await cli.configConnectionService.loadConfig("setup.config");
3708
+ await cli.configConnectionService.loadConfig("loader.config");
3709
+ }
3623
3710
  await cli.moduleConnectionService.loadModule("pnldebug.module");
3624
3711
  {
3625
3712
  await cli.exchangeSchemaService.addSchema();
@@ -4074,7 +4161,7 @@ const main$1 = async () => {
4074
4161
  if (!values.help) {
4075
4162
  return;
4076
4163
  }
4077
- process.stdout.write(`@backtest-kit/cli ${"9.3.0"}\n\n`);
4164
+ process.stdout.write(`@backtest-kit/cli ${"9.5.0"}\n\n`);
4078
4165
  process.stdout.write(HELP_TEXT);
4079
4166
  process.exit(0);
4080
4167
  };
@@ -4088,7 +4175,7 @@ const main = async () => {
4088
4175
  if (!values.version) {
4089
4176
  return;
4090
4177
  }
4091
- process.stdout.write(`@backtest-kit/cli ${"9.3.0"}\n`);
4178
+ process.stdout.write(`@backtest-kit/cli ${"9.5.0"}\n`);
4092
4179
  process.exit(0);
4093
4180
  };
4094
4181
  main();
@@ -15,17 +15,17 @@
15
15
  "@types/node": "25.6.0"
16
16
  },
17
17
  "dependencies": {
18
- "@backtest-kit/cli": "9.3.0",
19
- "@backtest-kit/graph": "9.3.0",
20
- "@backtest-kit/pinets": "9.3.0",
21
- "@backtest-kit/signals": "9.3.0",
22
- "@backtest-kit/ui": "9.3.0",
18
+ "@backtest-kit/cli": "9.5.0",
19
+ "@backtest-kit/graph": "9.5.0",
20
+ "@backtest-kit/pinets": "9.5.0",
21
+ "@backtest-kit/signals": "9.5.0",
22
+ "@backtest-kit/ui": "9.5.0",
23
23
  "@tavily/core": "0.7.2",
24
24
  "@tensorflow/tfjs": "4.22.0",
25
25
  "@tensorflow/tfjs-backend-wasm": "4.22.0",
26
26
  "@tensorflow/tfjs-core": "4.22.0",
27
27
  "agent-swarm-kit": "2.6.0",
28
- "backtest-kit": "9.3.0",
28
+ "backtest-kit": "9.5.0",
29
29
  "dayjs": "1.11.20",
30
30
  "functools-kit": "2.3.0",
31
31
  "garch": "1.2.3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtest-kit/cli",
3
- "version": "9.3.0",
3
+ "version": "9.5.0",
4
4
  "description": "Zero-boilerplate CLI runner for backtest-kit strategies. Run backtests, paper trading, and live bots with candle cache warming, web dashboard, and Telegram notifications — no setup code required.",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
@@ -63,11 +63,11 @@
63
63
  "devDependencies": {
64
64
  "@babel/plugin-transform-modules-umd": "7.27.1",
65
65
  "@babel/standalone": "7.29.1",
66
- "@backtest-kit/graph": "9.3.0",
67
- "@backtest-kit/ollama": "9.3.0",
68
- "@backtest-kit/pinets": "9.3.0",
69
- "@backtest-kit/signals": "9.3.0",
70
- "@backtest-kit/ui": "9.3.0",
66
+ "@backtest-kit/graph": "9.5.0",
67
+ "@backtest-kit/ollama": "9.5.0",
68
+ "@backtest-kit/pinets": "9.5.0",
69
+ "@backtest-kit/signals": "9.5.0",
70
+ "@backtest-kit/ui": "9.5.0",
71
71
  "@rollup/plugin-replace": "6.0.3",
72
72
  "@rollup/plugin-typescript": "11.1.6",
73
73
  "@types/image-size": "0.7.0",
@@ -75,7 +75,7 @@
75
75
  "@types/mustache": "4.2.6",
76
76
  "@types/node": "22.9.0",
77
77
  "@types/stack-trace": "0.0.33",
78
- "backtest-kit": "9.3.0",
78
+ "backtest-kit": "9.5.0",
79
79
  "glob": "11.0.1",
80
80
  "markdown-it": "14.1.1",
81
81
  "rimraf": "6.0.1",
@@ -90,12 +90,12 @@
90
90
  "peerDependencies": {
91
91
  "@babel/plugin-transform-modules-umd": "^7.27.1",
92
92
  "@babel/standalone": "^7.29.1",
93
- "@backtest-kit/graph": "^9.3.0",
94
- "@backtest-kit/ollama": "^9.3.0",
95
- "@backtest-kit/pinets": "^9.3.0",
96
- "@backtest-kit/signals": "^9.3.0",
97
- "@backtest-kit/ui": "^9.3.0",
98
- "backtest-kit": "^9.3.0",
93
+ "@backtest-kit/graph": "^9.5.0",
94
+ "@backtest-kit/ollama": "^9.5.0",
95
+ "@backtest-kit/pinets": "^9.5.0",
96
+ "@backtest-kit/signals": "^9.5.0",
97
+ "@backtest-kit/ui": "^9.5.0",
98
+ "backtest-kit": "^9.5.0",
99
99
  "markdown-it": "^14.1.1",
100
100
  "typescript": "^5.0.0"
101
101
  },
@@ -13,12 +13,12 @@
13
13
  "license": "ISC",
14
14
  "type": "commonjs",
15
15
  "dependencies": {
16
- "@backtest-kit/cli": "^9.3.0",
17
- "@backtest-kit/graph": "^9.3.0",
18
- "@backtest-kit/pinets": "^9.3.0",
19
- "@backtest-kit/ui": "^9.3.0",
16
+ "@backtest-kit/cli": "^9.5.0",
17
+ "@backtest-kit/graph": "^9.5.0",
18
+ "@backtest-kit/pinets": "^9.5.0",
19
+ "@backtest-kit/ui": "^9.5.0",
20
20
  "agent-swarm-kit": "^2.6.0",
21
- "backtest-kit": "^9.3.0",
21
+ "backtest-kit": "^9.5.0",
22
22
  "functools-kit": "^2.3.0",
23
23
  "garch": "^1.2.3",
24
24
  "get-moment-stamp": "^1.1.2",
package/types.d.ts CHANGED
@@ -249,7 +249,8 @@ declare class ConfigConnectionService {
249
249
  readonly loggerService: LoggerService;
250
250
  readonly resolveService: ResolveService;
251
251
  readonly loaderService: LoaderService;
252
- loadConfig: (fileName: string) => Promise<ModuleExports>;
252
+ hasConfig: (fileName: string) => boolean;
253
+ loadConfig: ((fileName: string) => Promise<ModuleExports>) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, Promise<ModuleExports>>;
253
254
  }
254
255
 
255
256
  declare class FrontendProviderService {
@@ -381,7 +382,8 @@ declare class ModuleConnectionService {
381
382
  readonly loggerService: LoggerService;
382
383
  readonly resolveService: ResolveService;
383
384
  readonly loaderService: LoaderService;
384
- loadModule: (fileName: string) => Promise<boolean>;
385
+ hasModule: (fileName: string) => boolean;
386
+ loadModule: ((fileName: string) => Promise<boolean>) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, Promise<boolean>>;
385
387
  }
386
388
 
387
389
  declare class ConfigService {
@@ -420,6 +422,7 @@ declare const cli: {
420
422
  declare class SetupUtils {
421
423
  enable: (() => void) & functools_kit.ISingleshotClearable<() => void>;
422
424
  clear: () => void;
425
+ update: () => void;
423
426
  }
424
427
  declare const Setup: SetupUtils;
425
428