@backtest-kit/cli 6.7.1 → 6.7.2

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
@@ -341,6 +341,67 @@ npm run backtest:dec
341
341
 
342
342
  Each strategy run produces its own `dump/` directory, making it straightforward to compare results across time periods — both by inspection and by pointing an AI agent at a specific strategy folder.
343
343
 
344
+ ## 🔗 Shared Import Aliases
345
+
346
+ `@backtest-kit/cli` automatically turns every **top-level folder in `cwd`** into a bare import alias available inside any strategy file. No configuration needed — just create the folder.
347
+
348
+ ### How It Works
349
+
350
+ When the CLI loads a strategy file, it scans the current working directory for subdirectories and registers each one as an import alias. The alias name is the folder name. Both barrel imports and deep subpath imports are supported:
351
+
352
+ | Import | Resolves to |
353
+ |--------|-------------|
354
+ | `import { fn } from "utils"` | `<cwd>/utils/index.ts` (or `.js`, `.mjs`, `.cjs`) |
355
+ | `import { calcRSI } from "math/rsi"` | `<cwd>/math/rsi.ts` |
356
+ | `import { research } from "logic"` | `<cwd>/logic/index.ts` |
357
+ | `import { ResearchResponseContract } from "logic/contract/ResearchResponse.contract"` | `<cwd>/logic/contract/ResearchResponse.contract.ts` |
358
+
359
+ ### Project Structure
360
+
361
+ ```
362
+ my-project/
363
+ ├── utils/ ← import { formatDate } from "utils"
364
+ │ └── index.ts
365
+ ├── math/ ← import { calcRSI } from "math/rsi"
366
+ │ └── rsi.ts
367
+ ├── logic/ ← import { research } from "logic"
368
+ │ ├── index.ts ← barrel
369
+ │ └── contract/
370
+ │ └── ResearchResponse.contract.ts ← import { ... } from "logic/contract/ResearchResponse.contract"
371
+ └── content/
372
+ ├── feb_2026.strategy.ts ← uses all three aliases freely
373
+ └── mar_2026.strategy.ts ← same aliases, no duplication
374
+ ```
375
+
376
+ This lets you extract shared utilities, math helpers, or AI agent logic (e.g. `agent-swarm-kit` workflows) into named folders and reuse them across every strategy in the project without relative path hell.
377
+
378
+ ### TypeScript Support
379
+
380
+ Add a matching `paths` entry to your `tsconfig.json` so the editor resolves the aliases:
381
+
382
+ ```json
383
+ {
384
+ "compilerOptions": {
385
+ "moduleResolution": "bundler",
386
+ "paths": {
387
+ "logic": ["./logic/index.ts"],
388
+ "logic/*": ["./logic/*"],
389
+ "math": ["./math/index.ts"],
390
+ "math/*": ["./math/*"],
391
+ "utils": ["./utils/index.ts"],
392
+ "utils/*": ["./utils/*"]
393
+ }
394
+ },
395
+ "include": [
396
+ "./logic",
397
+ "./math",
398
+ "./utils",
399
+ "./content",
400
+ "./modules",
401
+ ],
402
+ }
403
+ ```
404
+
344
405
  ## 🔔 Integrations
345
406
 
346
407
  ### Web Dashboard (`--ui`)
package/build/index.cjs CHANGED
@@ -239,6 +239,7 @@ class ResolveService {
239
239
  this.DEFAULT_MODULES_DIR = path.resolve(__dirname$2, '..', 'modules');
240
240
  this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
241
241
  this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
242
+ this.IMPORT_PATHS_DIR = process.cwd();
242
243
  this.getIsLaunched = () => {
243
244
  this.loggerService.log("resolveService getIsLaunched");
244
245
  return _is_launched;
@@ -2108,6 +2109,7 @@ class BabelService {
2108
2109
  }
2109
2110
 
2110
2111
  const USE_ESMODULE_DEFAULT = false;
2112
+ const IMPORT_PATHS_EXCLUDE = new Set(["dump", "logs", "node_modules"]);
2111
2113
  const TRANSPILE_FN = functoolsKit.memoize(([path]) => `${path}`, (path, code, self, require) => {
2112
2114
  const __filename = self.__filename;
2113
2115
  const __dirname = self.__dirname;
@@ -2206,6 +2208,20 @@ const ENTRY_FACTORY = (filePath, self, seen) => {
2206
2208
  }
2207
2209
  throw new Error(`Failed to load module at ${filePath} (basepath: ${self.params.path})`);
2208
2210
  };
2211
+ const READ_IMPORT_PATHS_MAP_FN = functoolsKit.singleshot((importPathsDir) => {
2212
+ const entries = fs.readdirSync(importPathsDir, { withFileTypes: true });
2213
+ const map = {};
2214
+ for (const entry of entries) {
2215
+ if (!entry.isDirectory()) {
2216
+ continue;
2217
+ }
2218
+ if (IMPORT_PATHS_EXCLUDE.has(entry.name)) {
2219
+ continue;
2220
+ }
2221
+ map[entry.name] = path.join(importPathsDir, entry.name);
2222
+ }
2223
+ return map;
2224
+ });
2209
2225
  const CREATE_BASE_REQUIRE_FN = (self, seen) => {
2210
2226
  const baseRequire = self.baseRequire();
2211
2227
  return new Proxy(baseRequire, {
@@ -2230,6 +2246,19 @@ const CREATE_BASE_REQUIRE_FN = (self, seen) => {
2230
2246
  const child = self.fork(path.dirname(resolved));
2231
2247
  return child.import(resolved, seen);
2232
2248
  }
2249
+ const importPathsMap = READ_IMPORT_PATHS_MAP_FN(self.params.resolve.IMPORT_PATHS_DIR);
2250
+ if (id in importPathsMap) {
2251
+ const resolved = importPathsMap[id];
2252
+ const child = self.fork(resolved);
2253
+ return child.import(resolved, seen);
2254
+ }
2255
+ const importPathsKey = Object.keys(importPathsMap).find((key) => id === key || id.startsWith(`${key}/`));
2256
+ if (importPathsKey) {
2257
+ const subPath = id.slice(importPathsKey.length);
2258
+ const resolved = path.join(importPathsMap[importPathsKey], subPath);
2259
+ const child = self.fork(path.dirname(resolved));
2260
+ return child.import(resolved, seen);
2261
+ }
2233
2262
  return baseRequire(id);
2234
2263
  },
2235
2264
  });
@@ -2260,6 +2289,7 @@ class ClientLoader {
2260
2289
  path: basePath,
2261
2290
  babel: this.params.babel,
2262
2291
  logger: this.params.logger,
2292
+ resolve: this.params.resolve,
2263
2293
  });
2264
2294
  }
2265
2295
  import(filePath, seen = new Set()) {
@@ -2304,9 +2334,11 @@ class LoaderService {
2304
2334
  constructor() {
2305
2335
  this.babelService = inject(TYPES.babelService);
2306
2336
  this.loggerService = inject(TYPES.loggerService);
2337
+ this.resolveService = inject(TYPES.resolveService);
2307
2338
  this.getInstance = functoolsKit.memoize(([basePath]) => `${basePath}`, (basePath) => new ClientLoader({
2308
2339
  babel: this.babelService,
2309
2340
  logger: this.loggerService,
2341
+ resolve: this.resolveService,
2310
2342
  path: basePath,
2311
2343
  }));
2312
2344
  this.import = (filePath, basePath = process.cwd()) => {
@@ -2541,7 +2573,7 @@ const main$b = async () => {
2541
2573
  if (MODES.some((mode) => values[mode])) {
2542
2574
  return;
2543
2575
  }
2544
- process.stdout.write(`@backtest-kit/cli ${"6.7.1"}\n`);
2576
+ process.stdout.write(`@backtest-kit/cli ${"6.7.2"}\n`);
2545
2577
  process.stdout.write("\n");
2546
2578
  process.stdout.write(`Run with --help to see available commands.\n`);
2547
2579
  process.stdout.write("\n");
@@ -3109,7 +3141,7 @@ const main$1 = async () => {
3109
3141
  if (!values.help) {
3110
3142
  return;
3111
3143
  }
3112
- process.stdout.write(`@backtest-kit/cli ${"6.7.1"}\n\n`);
3144
+ process.stdout.write(`@backtest-kit/cli ${"6.7.2"}\n\n`);
3113
3145
  process.stdout.write(HELP_TEXT);
3114
3146
  process.exit(0);
3115
3147
  };
@@ -3123,7 +3155,7 @@ const main = async () => {
3123
3155
  if (!values.version) {
3124
3156
  return;
3125
3157
  }
3126
- process.stdout.write(`@backtest-kit/cli ${"6.7.1"}\n`);
3158
+ process.stdout.write(`@backtest-kit/cli ${"6.7.2"}\n`);
3127
3159
  process.exit(0);
3128
3160
  };
3129
3161
  main();
package/build/index.mjs CHANGED
@@ -214,6 +214,7 @@ class ResolveService {
214
214
  this.DEFAULT_MODULES_DIR = path.resolve(__dirname$1, '..', 'modules');
215
215
  this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
216
216
  this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
217
+ this.IMPORT_PATHS_DIR = process.cwd();
217
218
  this.getIsLaunched = () => {
218
219
  this.loggerService.log("resolveService getIsLaunched");
219
220
  return _is_launched;
@@ -2083,6 +2084,7 @@ class BabelService {
2083
2084
  }
2084
2085
 
2085
2086
  const USE_ESMODULE_DEFAULT = false;
2087
+ const IMPORT_PATHS_EXCLUDE = new Set(["dump", "logs", "node_modules"]);
2086
2088
  const TRANSPILE_FN = memoize(([path]) => `${path}`, (path, code, self, require) => {
2087
2089
  const __filename = self.__filename;
2088
2090
  const __dirname = self.__dirname;
@@ -2177,6 +2179,20 @@ const ENTRY_FACTORY = (filePath, self, seen) => {
2177
2179
  }
2178
2180
  throw new Error(`Failed to load module at ${filePath} (basepath: ${self.params.path})`);
2179
2181
  };
2182
+ const READ_IMPORT_PATHS_MAP_FN = singleshot((importPathsDir) => {
2183
+ const entries = fs.readdirSync(importPathsDir, { withFileTypes: true });
2184
+ const map = {};
2185
+ for (const entry of entries) {
2186
+ if (!entry.isDirectory()) {
2187
+ continue;
2188
+ }
2189
+ if (IMPORT_PATHS_EXCLUDE.has(entry.name)) {
2190
+ continue;
2191
+ }
2192
+ map[entry.name] = path.join(importPathsDir, entry.name);
2193
+ }
2194
+ return map;
2195
+ });
2180
2196
  const CREATE_BASE_REQUIRE_FN = (self, seen) => {
2181
2197
  const baseRequire = self.baseRequire();
2182
2198
  return new Proxy(baseRequire, {
@@ -2201,6 +2217,19 @@ const CREATE_BASE_REQUIRE_FN = (self, seen) => {
2201
2217
  const child = self.fork(path.dirname(resolved));
2202
2218
  return child.import(resolved, seen);
2203
2219
  }
2220
+ const importPathsMap = READ_IMPORT_PATHS_MAP_FN(self.params.resolve.IMPORT_PATHS_DIR);
2221
+ if (id in importPathsMap) {
2222
+ const resolved = importPathsMap[id];
2223
+ const child = self.fork(resolved);
2224
+ return child.import(resolved, seen);
2225
+ }
2226
+ const importPathsKey = Object.keys(importPathsMap).find((key) => id === key || id.startsWith(`${key}/`));
2227
+ if (importPathsKey) {
2228
+ const subPath = id.slice(importPathsKey.length);
2229
+ const resolved = path.join(importPathsMap[importPathsKey], subPath);
2230
+ const child = self.fork(path.dirname(resolved));
2231
+ return child.import(resolved, seen);
2232
+ }
2204
2233
  return baseRequire(id);
2205
2234
  },
2206
2235
  });
@@ -2231,6 +2260,7 @@ class ClientLoader {
2231
2260
  path: basePath,
2232
2261
  babel: this.params.babel,
2233
2262
  logger: this.params.logger,
2263
+ resolve: this.params.resolve,
2234
2264
  });
2235
2265
  }
2236
2266
  import(filePath, seen = new Set()) {
@@ -2275,9 +2305,11 @@ class LoaderService {
2275
2305
  constructor() {
2276
2306
  this.babelService = inject(TYPES.babelService);
2277
2307
  this.loggerService = inject(TYPES.loggerService);
2308
+ this.resolveService = inject(TYPES.resolveService);
2278
2309
  this.getInstance = memoize(([basePath]) => `${basePath}`, (basePath) => new ClientLoader({
2279
2310
  babel: this.babelService,
2280
2311
  logger: this.loggerService,
2312
+ resolve: this.resolveService,
2281
2313
  path: basePath,
2282
2314
  }));
2283
2315
  this.import = (filePath, basePath = process.cwd()) => {
@@ -2512,7 +2544,7 @@ const main$b = async () => {
2512
2544
  if (MODES.some((mode) => values[mode])) {
2513
2545
  return;
2514
2546
  }
2515
- process.stdout.write(`@backtest-kit/cli ${"6.7.1"}\n`);
2547
+ process.stdout.write(`@backtest-kit/cli ${"6.7.2"}\n`);
2516
2548
  process.stdout.write("\n");
2517
2549
  process.stdout.write(`Run with --help to see available commands.\n`);
2518
2550
  process.stdout.write("\n");
@@ -3080,7 +3112,7 @@ const main$1 = async () => {
3080
3112
  if (!values.help) {
3081
3113
  return;
3082
3114
  }
3083
- process.stdout.write(`@backtest-kit/cli ${"6.7.1"}\n\n`);
3115
+ process.stdout.write(`@backtest-kit/cli ${"6.7.2"}\n\n`);
3084
3116
  process.stdout.write(HELP_TEXT);
3085
3117
  process.exit(0);
3086
3118
  };
@@ -3094,7 +3126,7 @@ const main = async () => {
3094
3126
  if (!values.version) {
3095
3127
  return;
3096
3128
  }
3097
- process.stdout.write(`@backtest-kit/cli ${"6.7.1"}\n`);
3129
+ process.stdout.write(`@backtest-kit/cli ${"6.7.2"}\n`);
3098
3130
  process.exit(0);
3099
3131
  };
3100
3132
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtest-kit/cli",
3
- "version": "6.7.1",
3
+ "version": "6.7.2",
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",
@@ -12,7 +12,7 @@
12
12
  "license": "ISC",
13
13
  "type": "commonjs",
14
14
  "dependencies": {
15
- "@backtest-kit/cli": "^6.7.1",
15
+ "@backtest-kit/cli": "^6.7.2",
16
16
  "@backtest-kit/graph": "^6.7.0",
17
17
  "@backtest-kit/pinets": "^6.7.0",
18
18
  "@backtest-kit/ui": "^6.7.0",
package/types.d.ts CHANGED
@@ -110,18 +110,28 @@ declare class FrameSchemaService {
110
110
  declare class LoaderService {
111
111
  private readonly babelService;
112
112
  private readonly loggerService;
113
+ private readonly resolveService;
113
114
  private getInstance;
114
115
  import: (filePath: string, basePath?: string) => any;
115
116
  check: (filePath: string, basePath?: string) => Promise<boolean>;
116
117
  }
117
118
 
118
- declare class ResolveService {
119
+ interface IResolve {
120
+ DEFAULT_TEMPLATE_DIR: string;
121
+ DEFAULT_MODULES_DIR: string;
122
+ OVERRIDE_TEMPLATE_DIR: string;
123
+ OVERRIDE_MODULES_DIR: string;
124
+ IMPORT_PATHS_DIR: string;
125
+ }
126
+
127
+ declare class ResolveService implements IResolve {
119
128
  readonly loggerService: LoggerService;
120
129
  readonly loaderService: LoaderService;
121
130
  readonly DEFAULT_TEMPLATE_DIR: string;
122
131
  readonly DEFAULT_MODULES_DIR: string;
123
132
  readonly OVERRIDE_TEMPLATE_DIR: string;
124
133
  readonly OVERRIDE_MODULES_DIR: string;
134
+ readonly IMPORT_PATHS_DIR: string;
125
135
  getIsLaunched: () => boolean;
126
136
  attachPine: (pinePath: string) => Promise<string>;
127
137
  attachStrategy: (jsPath: string) => Promise<void>;