@backtest-kit/cli 5.6.0 → 5.9.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
@@ -302,11 +302,11 @@ Requires `CC_TELEGRAM_TOKEN` and `CC_TELEGRAM_CHANNEL` in your environment.
302
302
 
303
303
  The CLI supports **mode-specific module files** that are loaded as side-effect imports before the strategy starts. Each file is expected to call `Broker.useBrokerAdapter()` from `backtest-kit` to register a broker adapter.
304
304
 
305
- | Mode | Module file | Loaded before |
306
- |---------------|---------------------------------|-----------------------------|
307
- | `--live` | `./modules/live.module.mjs` | `Live.background()` |
308
- | `--paper` | `./modules/paper.module.mjs` | `Live.background()` (paper) |
309
- | `--backtest` | `./modules/backtest.module.mjs` | `Backtest.background()` |
305
+ | Command Line Args | Module file | Loaded before |
306
+ |-------------------|---------------------------------|-----------------------------|
307
+ | `--live` | `./modules/live.module.mjs` | `Live.background()` |
308
+ | `--paper` | `./modules/paper.module.mjs` | `Live.background()` (paper) |
309
+ | `--backtest` | `./modules/backtest.module.mjs` | `Backtest.background()` |
310
310
 
311
311
  > File is resolved relative to `cwd` (the strategy directory). All of `.mjs`, `.cjs`, `.ts` extensions are tried automatically. Missing module is a soft warning — not an error.
312
312
 
package/build/index.cjs CHANGED
@@ -94,6 +94,10 @@ var BacktestKitSignals__namespace = /*#__PURE__*/_interopNamespaceDefault(Backte
94
94
  BacktestKit.Markdown.enable();
95
95
  BacktestKit.Report.enable();
96
96
  }
97
+ {
98
+ BacktestKit.Dump.useMarkdown();
99
+ BacktestKit.Memory.usePersist();
100
+ }
97
101
  {
98
102
  BacktestKit.StorageLive.usePersist();
99
103
  BacktestKit.StorageBacktest.useMemory();
@@ -116,6 +120,25 @@ BacktestKit.setConfig({
116
120
  BacktestKit.setConfig({
117
121
  CC_MAX_SIGNAL_GENERATION_SECONDS: 15 * 60,
118
122
  });
123
+ BacktestKit.setConfig({
124
+ CC_MAX_BACKTEST_MARKDOWN_ROWS: 1000,
125
+ CC_MAX_BREAKEVEN_MARKDOWN_ROWS: 1000,
126
+ CC_MAX_HEATMAP_MARKDOWN_ROWS: 1000,
127
+ CC_MAX_HIGHEST_PROFIT_MARKDOWN_ROWS: 1000,
128
+ CC_MAX_LIVE_MARKDOWN_ROWS: 1000,
129
+ CC_MAX_PARTIAL_MARKDOWN_ROWS: 1000,
130
+ CC_MAX_RISK_MARKDOWN_ROWS: 1000,
131
+ CC_MAX_SCHEDULE_MARKDOWN_ROWS: 1000,
132
+ CC_MAX_STRATEGY_MARKDOWN_ROWS: 1000,
133
+ CC_MAX_SYNC_MARKDOWN_ROWS: 1000,
134
+ CC_MAX_PERFORMANCE_MARKDOWN_ROWS: 1000,
135
+ });
136
+ BacktestKit.setConfig({
137
+ CC_MAX_SIGNAL_LIFETIME_MINUTES: Infinity,
138
+ });
139
+ BacktestKit.setConfig({
140
+ CC_WALKER_MARKDOWN_TOP_N: 10,
141
+ });
119
142
  BacktestKit.Log.useJsonl();
120
143
 
121
144
  const ERROR_HANDLER_INSTALLED = Symbol.for("error-handler-installed");
@@ -266,8 +289,13 @@ class ResolveService {
266
289
  this.loggerService = inject(TYPES.loggerService);
267
290
  this.loaderService = inject(TYPES.loaderService);
268
291
  this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$1, '..', 'template');
292
+ this.DEFAULT_MODULES_DIR = path.resolve(__dirname$1, '..', 'modules');
269
293
  this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
270
294
  this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
295
+ this.getIsLaunched = () => {
296
+ this.loggerService.log("resolveService getIsLaunched");
297
+ return _is_launched;
298
+ };
271
299
  this.attachEntryPoint = async (entryPoint) => {
272
300
  this.loggerService.log("resolveService attachEntryPoint");
273
301
  if (_is_launched) {
@@ -1719,25 +1747,36 @@ class TelegramTemplateService {
1719
1747
  }
1720
1748
  }
1721
1749
 
1750
+ const GET_MODULE_VARIANTS_FN = (fileName, self) => {
1751
+ const result = [];
1752
+ result.push({
1753
+ filePath: path.join(process.cwd(), "modules", fileName),
1754
+ baseDir: path.join(process.cwd(), "modules")
1755
+ });
1756
+ result.push({
1757
+ filePath: path.join(self.resolveService.OVERRIDE_MODULES_DIR, fileName),
1758
+ baseDir: self.resolveService.OVERRIDE_MODULES_DIR,
1759
+ });
1760
+ result.push({
1761
+ filePath: path.join(self.resolveService.DEFAULT_MODULES_DIR, fileName),
1762
+ baseDir: self.resolveService.DEFAULT_MODULES_DIR,
1763
+ });
1764
+ return result;
1765
+ };
1722
1766
  const LOAD_MODULE_MODULE_FN = async (fileName, self) => {
1723
- const overridePath = path.join(self.resolveService.OVERRIDE_MODULES_DIR, fileName);
1724
- const targetPath = path.join(process.cwd(), "modules", fileName);
1725
- const hasOverride = await fs$1
1726
- .access(overridePath, fs.constants.F_OK | fs.constants.R_OK)
1727
- .then(() => true)
1728
- .catch(() => false);
1729
- const resolvedFile = hasOverride ? overridePath : targetPath;
1730
- try {
1731
- if (self.loaderService.check(resolvedFile)) {
1732
- self.loaderService.import(resolvedFile);
1733
- return true;
1767
+ for (const { filePath, baseDir } of GET_MODULE_VARIANTS_FN(fileName, self)) {
1768
+ try {
1769
+ if (await self.loaderService.check(filePath, baseDir)) {
1770
+ self.loaderService.import(filePath, baseDir);
1771
+ return true;
1772
+ }
1773
+ }
1774
+ catch {
1775
+ console.warn(`Module module import failed filePath=${filePath} baseDir=${baseDir}`);
1776
+ process.exit(-1);
1734
1777
  }
1735
- return false;
1736
- }
1737
- catch {
1738
- console.warn(`Module module import failed for file: ${resolvedFile}`);
1739
- return false;
1740
1778
  }
1779
+ return false;
1741
1780
  };
1742
1781
  class ModuleConnectionService {
1743
1782
  constructor() {
@@ -2231,6 +2270,9 @@ function setLogger(logger) {
2231
2270
 
2232
2271
  let _is_started = false;
2233
2272
  async function run(mode, args) {
2273
+ if (cli.resolveService.getIsLaunched()) {
2274
+ throw new Error("Entry point is already attached. Multiple entry points are not allowed.");
2275
+ }
2234
2276
  {
2235
2277
  if (_is_started) {
2236
2278
  throw new Error("Should be called only once");
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 { Storage, Notification, Markdown, Report, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, setConfig, Log, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync } from 'backtest-kit';
3
+ import { Storage, Notification, Markdown, Report, Dump, Memory, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, setConfig, Log, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync } from 'backtest-kit';
4
4
  import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, execpool, queued, sleep, randomString, createAwaiter, TIMEOUT_SYMBOL, typo, retry, trycatch, memoize } from 'functools-kit';
5
5
  import fs, { constants } from 'fs';
6
6
  import * as stackTrace from 'stack-trace';
@@ -68,6 +68,10 @@ import * as BacktestKitSignals from '@backtest-kit/signals';
68
68
  Markdown.enable();
69
69
  Report.enable();
70
70
  }
71
+ {
72
+ Dump.useMarkdown();
73
+ Memory.usePersist();
74
+ }
71
75
  {
72
76
  StorageLive.usePersist();
73
77
  StorageBacktest.useMemory();
@@ -90,6 +94,25 @@ setConfig({
90
94
  setConfig({
91
95
  CC_MAX_SIGNAL_GENERATION_SECONDS: 15 * 60,
92
96
  });
97
+ setConfig({
98
+ CC_MAX_BACKTEST_MARKDOWN_ROWS: 1000,
99
+ CC_MAX_BREAKEVEN_MARKDOWN_ROWS: 1000,
100
+ CC_MAX_HEATMAP_MARKDOWN_ROWS: 1000,
101
+ CC_MAX_HIGHEST_PROFIT_MARKDOWN_ROWS: 1000,
102
+ CC_MAX_LIVE_MARKDOWN_ROWS: 1000,
103
+ CC_MAX_PARTIAL_MARKDOWN_ROWS: 1000,
104
+ CC_MAX_RISK_MARKDOWN_ROWS: 1000,
105
+ CC_MAX_SCHEDULE_MARKDOWN_ROWS: 1000,
106
+ CC_MAX_STRATEGY_MARKDOWN_ROWS: 1000,
107
+ CC_MAX_SYNC_MARKDOWN_ROWS: 1000,
108
+ CC_MAX_PERFORMANCE_MARKDOWN_ROWS: 1000,
109
+ });
110
+ setConfig({
111
+ CC_MAX_SIGNAL_LIFETIME_MINUTES: Infinity,
112
+ });
113
+ setConfig({
114
+ CC_WALKER_MARKDOWN_TOP_N: 10,
115
+ });
93
116
  Log.useJsonl();
94
117
 
95
118
  const ERROR_HANDLER_INSTALLED = Symbol.for("error-handler-installed");
@@ -240,8 +263,13 @@ class ResolveService {
240
263
  this.loggerService = inject(TYPES.loggerService);
241
264
  this.loaderService = inject(TYPES.loaderService);
242
265
  this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname, '..', 'template');
266
+ this.DEFAULT_MODULES_DIR = path.resolve(__dirname, '..', 'modules');
243
267
  this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
244
268
  this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
269
+ this.getIsLaunched = () => {
270
+ this.loggerService.log("resolveService getIsLaunched");
271
+ return _is_launched;
272
+ };
245
273
  this.attachEntryPoint = async (entryPoint) => {
246
274
  this.loggerService.log("resolveService attachEntryPoint");
247
275
  if (_is_launched) {
@@ -1693,25 +1721,36 @@ class TelegramTemplateService {
1693
1721
  }
1694
1722
  }
1695
1723
 
1724
+ const GET_MODULE_VARIANTS_FN = (fileName, self) => {
1725
+ const result = [];
1726
+ result.push({
1727
+ filePath: path.join(process.cwd(), "modules", fileName),
1728
+ baseDir: path.join(process.cwd(), "modules")
1729
+ });
1730
+ result.push({
1731
+ filePath: path.join(self.resolveService.OVERRIDE_MODULES_DIR, fileName),
1732
+ baseDir: self.resolveService.OVERRIDE_MODULES_DIR,
1733
+ });
1734
+ result.push({
1735
+ filePath: path.join(self.resolveService.DEFAULT_MODULES_DIR, fileName),
1736
+ baseDir: self.resolveService.DEFAULT_MODULES_DIR,
1737
+ });
1738
+ return result;
1739
+ };
1696
1740
  const LOAD_MODULE_MODULE_FN = async (fileName, self) => {
1697
- const overridePath = path.join(self.resolveService.OVERRIDE_MODULES_DIR, fileName);
1698
- const targetPath = path.join(process.cwd(), "modules", fileName);
1699
- const hasOverride = await fs$1
1700
- .access(overridePath, constants.F_OK | constants.R_OK)
1701
- .then(() => true)
1702
- .catch(() => false);
1703
- const resolvedFile = hasOverride ? overridePath : targetPath;
1704
- try {
1705
- if (self.loaderService.check(resolvedFile)) {
1706
- self.loaderService.import(resolvedFile);
1707
- return true;
1741
+ for (const { filePath, baseDir } of GET_MODULE_VARIANTS_FN(fileName, self)) {
1742
+ try {
1743
+ if (await self.loaderService.check(filePath, baseDir)) {
1744
+ self.loaderService.import(filePath, baseDir);
1745
+ return true;
1746
+ }
1747
+ }
1748
+ catch {
1749
+ console.warn(`Module module import failed filePath=${filePath} baseDir=${baseDir}`);
1750
+ process.exit(-1);
1708
1751
  }
1709
- return false;
1710
- }
1711
- catch {
1712
- console.warn(`Module module import failed for file: ${resolvedFile}`);
1713
- return false;
1714
1752
  }
1753
+ return false;
1715
1754
  };
1716
1755
  class ModuleConnectionService {
1717
1756
  constructor() {
@@ -2201,6 +2240,9 @@ function setLogger(logger) {
2201
2240
 
2202
2241
  let _is_started = false;
2203
2242
  async function run(mode, args) {
2243
+ if (cli.resolveService.getIsLaunched()) {
2244
+ throw new Error("Entry point is already attached. Multiple entry points are not allowed.");
2245
+ }
2204
2246
  {
2205
2247
  if (_is_started) {
2206
2248
  throw new Error("Should be called only once");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtest-kit/cli",
3
- "version": "5.6.0",
3
+ "version": "5.9.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",
@@ -60,11 +60,11 @@
60
60
  "devDependencies": {
61
61
  "@babel/plugin-transform-modules-umd": "7.27.1",
62
62
  "@babel/standalone": "7.29.1",
63
- "@backtest-kit/ui": "5.6.0",
64
- "@backtest-kit/graph": "5.6.0",
65
- "@backtest-kit/ollama": "5.6.0",
66
- "@backtest-kit/pinets": "5.6.0",
67
- "@backtest-kit/signals": "5.6.0",
63
+ "@backtest-kit/ui": "5.9.0",
64
+ "@backtest-kit/graph": "5.9.0",
65
+ "@backtest-kit/ollama": "5.9.0",
66
+ "@backtest-kit/pinets": "5.9.0",
67
+ "@backtest-kit/signals": "5.9.0",
68
68
  "@rollup/plugin-replace": "6.0.3",
69
69
  "@rollup/plugin-typescript": "11.1.6",
70
70
  "@types/image-size": "0.7.0",
@@ -72,7 +72,7 @@
72
72
  "@types/mustache": "4.2.6",
73
73
  "@types/node": "22.9.0",
74
74
  "@types/stack-trace": "0.0.33",
75
- "backtest-kit": "5.6.0",
75
+ "backtest-kit": "5.9.0",
76
76
  "glob": "11.0.1",
77
77
  "markdown-it": "14.1.1",
78
78
  "rimraf": "6.0.1",
@@ -87,12 +87,12 @@
87
87
  "peerDependencies": {
88
88
  "@babel/plugin-transform-modules-umd": "^7.27.1",
89
89
  "@babel/standalone": "^7.29.1",
90
- "@backtest-kit/ui": "^5.6.0",
91
- "@backtest-kit/graph": "^5.6.0",
92
- "@backtest-kit/ollama": "^5.6.0",
93
- "@backtest-kit/pinets": "^5.6.0",
94
- "@backtest-kit/signals": "^5.6.0",
95
- "backtest-kit": "^5.6.0",
90
+ "@backtest-kit/ui": "^5.9.0",
91
+ "@backtest-kit/graph": "^5.9.0",
92
+ "@backtest-kit/ollama": "^5.9.0",
93
+ "@backtest-kit/pinets": "^5.9.0",
94
+ "@backtest-kit/signals": "^5.9.0",
95
+ "backtest-kit": "^5.9.0",
96
96
  "markdown-it": "^14.1.1",
97
97
  "typescript": "^5.0.0"
98
98
  },
package/types.d.ts CHANGED
@@ -99,8 +99,10 @@ declare class ResolveService {
99
99
  readonly loggerService: LoggerService;
100
100
  readonly loaderService: LoaderService;
101
101
  readonly DEFAULT_TEMPLATE_DIR: string;
102
+ readonly DEFAULT_MODULES_DIR: string;
102
103
  readonly OVERRIDE_TEMPLATE_DIR: string;
103
104
  readonly OVERRIDE_MODULES_DIR: string;
105
+ getIsLaunched: () => boolean;
104
106
  attachEntryPoint: (entryPoint: string) => Promise<void>;
105
107
  }
106
108