@backtest-kit/cli 6.2.0 → 6.2.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/build/index.cjs CHANGED
@@ -829,8 +829,15 @@ class WalkerMainService {
829
829
  this.moduleConnectionService = inject(TYPES.moduleConnectionService);
830
830
  this.run = functoolsKit.singleshot(async (payload) => {
831
831
  this.loggerService.log("walkerMainService run", { payload });
832
+ const strategyMap = new Map();
832
833
  for (const entryPoint of payload.entryPoints) {
833
834
  await this.resolveService.attachStrategy(entryPoint);
835
+ for (const { strategyName } of await BacktestKit.listStrategySchema()) {
836
+ if (strategyMap.has(strategyName)) {
837
+ continue;
838
+ }
839
+ strategyMap.set(strategyName, entryPoint);
840
+ }
834
841
  }
835
842
  await this.moduleConnectionService.loadModule("./walker.module");
836
843
  {
@@ -867,19 +874,38 @@ class WalkerMainService {
867
874
  if (!frameName) {
868
875
  throw new Error("Frame name is required");
869
876
  }
877
+ const cwd = process.cwd();
878
+ const self = this;
879
+ const callbacks = {
880
+ async onStrategyStart(strategyName) {
881
+ const entryPoint = strategyMap.get(strategyName);
882
+ if (!entryPoint) {
883
+ return;
884
+ }
885
+ const absolutePath = path.resolve(entryPoint);
886
+ const moduleRoot = path.dirname(absolutePath);
887
+ {
888
+ process.chdir(moduleRoot);
889
+ cwd !== moduleRoot && BacktestKit.Log.useJsonl();
890
+ dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
891
+ dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
892
+ }
893
+ if (!payload.noCache) {
894
+ await self.cacheLogicService.execute(payload.cacheInterval, {
895
+ exchangeName,
896
+ frameName,
897
+ symbol,
898
+ });
899
+ }
900
+ },
901
+ };
870
902
  BacktestKit.addWalkerSchema({
871
903
  walkerName: WALKER_NAME,
872
904
  exchangeName,
873
905
  frameName,
874
906
  strategies: strategyNames,
907
+ callbacks,
875
908
  });
876
- if (!payload.noCache) {
877
- await this.cacheLogicService.execute(payload.cacheInterval, {
878
- exchangeName,
879
- frameName,
880
- symbol,
881
- });
882
- }
883
909
  if (payload.verbose) {
884
910
  BacktestKit.overrideExchangeSchema({
885
911
  exchangeName,
@@ -895,8 +921,9 @@ class WalkerMainService {
895
921
  BacktestKit.overrideWalkerSchema({
896
922
  walkerName: WALKER_NAME,
897
923
  callbacks: {
898
- onStrategyStart(strategyName, symbol) {
924
+ async onStrategyStart(strategyName, symbol) {
899
925
  console.log(`Strategy started: ${strategyName} for symbol: ${symbol}`);
926
+ await callbacks.onStrategyStart(strategyName);
900
927
  },
901
928
  onStrategyError(strategyName, symbol, error) {
902
929
  console.error(`Strategy error: ${strategyName} for symbol: ${symbol}`, error);
@@ -917,9 +944,12 @@ class WalkerMainService {
917
944
  unWalker();
918
945
  res();
919
946
  });
920
- payload.verbose && console.time("Walker");
921
- await awaiter;
922
- payload.verbose && console.timeEnd("Walker");
947
+ {
948
+ payload.verbose && console.time("Walker");
949
+ await awaiter;
950
+ payload.verbose && console.timeEnd("Walker");
951
+ }
952
+ process.chdir(cwd);
923
953
  const dumpName = payload.output || `walker_${symbol}_${Date.now()}`;
924
954
  const dumpDir = path.join(process.cwd(), "dump");
925
955
  if (payload.json) {
@@ -2119,7 +2149,7 @@ const TRANSPILE_FN = functoolsKit.memoize(([path]) => `${path}`, (path, code, se
2119
2149
  eval(self.params.babel.transpile(code));
2120
2150
  }
2121
2151
  catch (error) {
2122
- console.log(`Error during transpilation error=\`${functoolsKit.getErrorMessage(error)}\` path=${path} __filename=\`${__filename}\` __dirname=\`${__dirname}\``);
2152
+ console.log(`Error during transpilation error=\`${functoolsKit.getErrorMessage(error)}\` path=\`${path}\` __filename=\`${__filename}\` __dirname=\`${__dirname}\``);
2123
2153
  process.exit(-1);
2124
2154
  }
2125
2155
  return {
@@ -2426,7 +2456,7 @@ const main$b = async () => {
2426
2456
  if (MODES.some((mode) => values[mode])) {
2427
2457
  return;
2428
2458
  }
2429
- process.stdout.write(`@backtest-kit/cli ${"6.2.0"}\n`);
2459
+ process.stdout.write(`@backtest-kit/cli ${"6.2.1"}\n`);
2430
2460
  process.stdout.write("\n");
2431
2461
  process.stdout.write(`Run with --help to see available commands.\n`);
2432
2462
  process.stdout.write("\n");
@@ -2827,6 +2857,20 @@ function runScript(scriptPath, cwd) {
2827
2857
  child.on("error", reject);
2828
2858
  });
2829
2859
  }
2860
+ function runNpmInstall(cwd) {
2861
+ return new Promise((resolve, reject) => {
2862
+ const npm = process.platform === "win32" ? "npm.cmd" : "npm";
2863
+ const child = child_process.spawn(npm, ["install"], { cwd, stdio: "inherit", shell: true });
2864
+ child.on("close", (code) => {
2865
+ if (code !== 0) {
2866
+ reject(new Error(`npm install exited with code ${code}`));
2867
+ return;
2868
+ }
2869
+ resolve();
2870
+ });
2871
+ child.on("error", reject);
2872
+ });
2873
+ }
2830
2874
  const main$2 = async () => {
2831
2875
  if (!getEntry((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))) {
2832
2876
  return;
@@ -2847,6 +2891,8 @@ const main$2 = async () => {
2847
2891
  await copyDir(templatePath, projectPath, { PROJECT_NAME: projectName });
2848
2892
  console.log(`Fetching docs...`);
2849
2893
  await runScript(path.join(projectPath, "scripts/fetch_docs.mjs"), projectPath);
2894
+ console.log(`Installing dependencies...`);
2895
+ await runNpmInstall(projectPath);
2850
2896
  console.log(`Done! Project created at ${projectPath}`);
2851
2897
  process.exit(0);
2852
2898
  };
@@ -2978,7 +3024,7 @@ const main$1 = async () => {
2978
3024
  if (!values.help) {
2979
3025
  return;
2980
3026
  }
2981
- process.stdout.write(`@backtest-kit/cli ${"6.2.0"}\n\n`);
3027
+ process.stdout.write(`@backtest-kit/cli ${"6.2.1"}\n\n`);
2982
3028
  process.stdout.write(HELP_TEXT);
2983
3029
  process.exit(0);
2984
3030
  };
@@ -2992,7 +3038,7 @@ const main = async () => {
2992
3038
  if (!values.version) {
2993
3039
  return;
2994
3040
  }
2995
- process.stdout.write(`@backtest-kit/cli ${"6.2.0"}\n`);
3041
+ process.stdout.write(`@backtest-kit/cli ${"6.2.1"}\n`);
2996
3042
  process.exit(0);
2997
3043
  };
2998
3044
  main();
package/build/index.mjs CHANGED
@@ -804,8 +804,15 @@ class WalkerMainService {
804
804
  this.moduleConnectionService = inject(TYPES.moduleConnectionService);
805
805
  this.run = singleshot(async (payload) => {
806
806
  this.loggerService.log("walkerMainService run", { payload });
807
+ const strategyMap = new Map();
807
808
  for (const entryPoint of payload.entryPoints) {
808
809
  await this.resolveService.attachStrategy(entryPoint);
810
+ for (const { strategyName } of await listStrategySchema()) {
811
+ if (strategyMap.has(strategyName)) {
812
+ continue;
813
+ }
814
+ strategyMap.set(strategyName, entryPoint);
815
+ }
809
816
  }
810
817
  await this.moduleConnectionService.loadModule("./walker.module");
811
818
  {
@@ -842,19 +849,38 @@ class WalkerMainService {
842
849
  if (!frameName) {
843
850
  throw new Error("Frame name is required");
844
851
  }
852
+ const cwd = process.cwd();
853
+ const self = this;
854
+ const callbacks = {
855
+ async onStrategyStart(strategyName) {
856
+ const entryPoint = strategyMap.get(strategyName);
857
+ if (!entryPoint) {
858
+ return;
859
+ }
860
+ const absolutePath = path.resolve(entryPoint);
861
+ const moduleRoot = path.dirname(absolutePath);
862
+ {
863
+ process.chdir(moduleRoot);
864
+ cwd !== moduleRoot && Log.useJsonl();
865
+ dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
866
+ dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
867
+ }
868
+ if (!payload.noCache) {
869
+ await self.cacheLogicService.execute(payload.cacheInterval, {
870
+ exchangeName,
871
+ frameName,
872
+ symbol,
873
+ });
874
+ }
875
+ },
876
+ };
845
877
  addWalkerSchema({
846
878
  walkerName: WALKER_NAME,
847
879
  exchangeName,
848
880
  frameName,
849
881
  strategies: strategyNames,
882
+ callbacks,
850
883
  });
851
- if (!payload.noCache) {
852
- await this.cacheLogicService.execute(payload.cacheInterval, {
853
- exchangeName,
854
- frameName,
855
- symbol,
856
- });
857
- }
858
884
  if (payload.verbose) {
859
885
  overrideExchangeSchema({
860
886
  exchangeName,
@@ -870,8 +896,9 @@ class WalkerMainService {
870
896
  overrideWalkerSchema({
871
897
  walkerName: WALKER_NAME,
872
898
  callbacks: {
873
- onStrategyStart(strategyName, symbol) {
899
+ async onStrategyStart(strategyName, symbol) {
874
900
  console.log(`Strategy started: ${strategyName} for symbol: ${symbol}`);
901
+ await callbacks.onStrategyStart(strategyName);
875
902
  },
876
903
  onStrategyError(strategyName, symbol, error) {
877
904
  console.error(`Strategy error: ${strategyName} for symbol: ${symbol}`, error);
@@ -892,9 +919,12 @@ class WalkerMainService {
892
919
  unWalker();
893
920
  res();
894
921
  });
895
- payload.verbose && console.time("Walker");
896
- await awaiter;
897
- payload.verbose && console.timeEnd("Walker");
922
+ {
923
+ payload.verbose && console.time("Walker");
924
+ await awaiter;
925
+ payload.verbose && console.timeEnd("Walker");
926
+ }
927
+ process.chdir(cwd);
898
928
  const dumpName = payload.output || `walker_${symbol}_${Date.now()}`;
899
929
  const dumpDir = join(process.cwd(), "dump");
900
930
  if (payload.json) {
@@ -2094,7 +2124,7 @@ const TRANSPILE_FN = memoize(([path]) => `${path}`, (path, code, self, require)
2094
2124
  eval(self.params.babel.transpile(code));
2095
2125
  }
2096
2126
  catch (error) {
2097
- console.log(`Error during transpilation error=\`${getErrorMessage(error)}\` path=${path} __filename=\`${__filename}\` __dirname=\`${__dirname}\``);
2127
+ console.log(`Error during transpilation error=\`${getErrorMessage(error)}\` path=\`${path}\` __filename=\`${__filename}\` __dirname=\`${__dirname}\``);
2098
2128
  process.exit(-1);
2099
2129
  }
2100
2130
  return {
@@ -2397,7 +2427,7 @@ const main$b = async () => {
2397
2427
  if (MODES.some((mode) => values[mode])) {
2398
2428
  return;
2399
2429
  }
2400
- process.stdout.write(`@backtest-kit/cli ${"6.2.0"}\n`);
2430
+ process.stdout.write(`@backtest-kit/cli ${"6.2.1"}\n`);
2401
2431
  process.stdout.write("\n");
2402
2432
  process.stdout.write(`Run with --help to see available commands.\n`);
2403
2433
  process.stdout.write("\n");
@@ -2798,6 +2828,20 @@ function runScript(scriptPath, cwd) {
2798
2828
  child.on("error", reject);
2799
2829
  });
2800
2830
  }
2831
+ function runNpmInstall(cwd) {
2832
+ return new Promise((resolve, reject) => {
2833
+ const npm = process.platform === "win32" ? "npm.cmd" : "npm";
2834
+ const child = spawn(npm, ["install"], { cwd, stdio: "inherit", shell: true });
2835
+ child.on("close", (code) => {
2836
+ if (code !== 0) {
2837
+ reject(new Error(`npm install exited with code ${code}`));
2838
+ return;
2839
+ }
2840
+ resolve();
2841
+ });
2842
+ child.on("error", reject);
2843
+ });
2844
+ }
2801
2845
  const main$2 = async () => {
2802
2846
  if (!getEntry(import.meta.url)) {
2803
2847
  return;
@@ -2818,6 +2862,8 @@ const main$2 = async () => {
2818
2862
  await copyDir(templatePath, projectPath, { PROJECT_NAME: projectName });
2819
2863
  console.log(`Fetching docs...`);
2820
2864
  await runScript(join(projectPath, "scripts/fetch_docs.mjs"), projectPath);
2865
+ console.log(`Installing dependencies...`);
2866
+ await runNpmInstall(projectPath);
2821
2867
  console.log(`Done! Project created at ${projectPath}`);
2822
2868
  process.exit(0);
2823
2869
  };
@@ -2949,7 +2995,7 @@ const main$1 = async () => {
2949
2995
  if (!values.help) {
2950
2996
  return;
2951
2997
  }
2952
- process.stdout.write(`@backtest-kit/cli ${"6.2.0"}\n\n`);
2998
+ process.stdout.write(`@backtest-kit/cli ${"6.2.1"}\n\n`);
2953
2999
  process.stdout.write(HELP_TEXT);
2954
3000
  process.exit(0);
2955
3001
  };
@@ -2963,7 +3009,7 @@ const main = async () => {
2963
3009
  if (!values.version) {
2964
3010
  return;
2965
3011
  }
2966
- process.stdout.write(`@backtest-kit/cli ${"6.2.0"}\n`);
3012
+ process.stdout.write(`@backtest-kit/cli ${"6.2.1"}\n`);
2967
3013
  process.exit(0);
2968
3014
  };
2969
3015
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtest-kit/cli",
3
- "version": "6.2.0",
3
+ "version": "6.2.1",
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",
@@ -87,7 +87,7 @@ npm start -- --live --symbol BTCUSDT --ui --telegram ./content/feb_2026.strategy
87
87
 
88
88
  Module file `./modules/live.module.ts` is loaded automatically if it exists. Use it to register a `Broker` adapter that intercepts every trade mutation before internal state changes — exchange rejection rolls back the operation atomically.
89
89
 
90
- ## 🚶 Walker — A/B Strategy Comparison (`--walker`)
90
+ ## ⚖️ Walker — A/B Strategy Comparison (`--walker`)
91
91
 
92
92
  Runs the same historical period across multiple strategy files and prints a ranked comparison report. Use it to pick the best variant before committing to a single strategy.
93
93
 
@@ -12,7 +12,7 @@
12
12
  "license": "ISC",
13
13
  "type": "commonjs",
14
14
  "dependencies": {
15
- "@backtest-kit/cli": "^6.2.0",
15
+ "@backtest-kit/cli": "^6.2.1",
16
16
  "@backtest-kit/graph": "^6.2.0",
17
17
  "@backtest-kit/pinets": "^6.2.0",
18
18
  "@backtest-kit/ui": "^6.2.0",