@backtest-kit/cli 9.6.0 → 9.7.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.
Files changed (34) hide show
  1. package/README.md +1854 -1738
  2. package/build/index.cjs +268 -204
  3. package/build/index.mjs +268 -204
  4. package/config/notification.config.mjs +13 -13
  5. package/config/symbol.config.mjs +460 -460
  6. package/docker/.env.example +2 -2
  7. package/docker/README.md +1 -0
  8. package/docker/content/feb_2026/feb_2026.strategy.ts +11 -11
  9. package/docker/content/feb_2026/modules/backtest.module.ts +83 -83
  10. package/docker/docker-compose.yaml +46 -46
  11. package/docker/package.json +38 -38
  12. package/docker/tsconfig.json +36 -36
  13. package/package.json +126 -126
  14. package/template/average-buy.mustache +22 -22
  15. package/template/breakeven.mustache +21 -21
  16. package/template/cancel-scheduled.mustache +14 -14
  17. package/template/cancelled.mustache +21 -21
  18. package/template/close-pending.mustache +16 -16
  19. package/template/closed.mustache +23 -23
  20. package/template/opened.mustache +22 -22
  21. package/template/partial-loss.mustache +22 -22
  22. package/template/partial-profit.mustache +22 -22
  23. package/template/project/README.md +1 -0
  24. package/template/project/config/symbol.config.ts +460 -460
  25. package/template/project/package.mustache +28 -28
  26. package/template/risk.mustache +19 -19
  27. package/template/scheduled.mustache +22 -22
  28. package/template/signal-close.mustache +22 -22
  29. package/template/signal-info.mustache +20 -20
  30. package/template/signal-open.mustache +22 -22
  31. package/template/source/CLAUDE.md +160 -160
  32. package/template/trailing-stop.mustache +21 -21
  33. package/template/trailing-take.mustache +21 -21
  34. package/types.d.ts +1 -6
package/build/index.mjs CHANGED
@@ -885,9 +885,15 @@ class BacktestMainService {
885
885
  this.loggerService.log("backtestMainService run", {
886
886
  payload,
887
887
  });
888
+ await this.configConnectionService.loadConfig("setup.config");
888
889
  {
889
- await this.configConnectionService.loadConfig("setup.config");
890
- await this.configConnectionService.loadConfig("loader.config");
890
+ const loader = await this.configConnectionService.loadConfig("loader.config");
891
+ if (typeof loader === "function") {
892
+ await loader();
893
+ }
894
+ if (typeof loader?.loader === "function") {
895
+ await loader.loader();
896
+ }
891
897
  }
892
898
  {
893
899
  await this.configService.waitForInit();
@@ -1007,9 +1013,15 @@ class WalkerMainService {
1007
1013
  this.configConnectionService = inject(TYPES.configConnectionService);
1008
1014
  this.run = singleshot(async (payload) => {
1009
1015
  this.loggerService.log("walkerMainService run", { payload });
1016
+ await this.configConnectionService.loadConfig("setup.config");
1010
1017
  {
1011
- await this.configConnectionService.loadConfig("setup.config");
1012
- await this.configConnectionService.loadConfig("loader.config");
1018
+ const loader = await this.configConnectionService.loadConfig("loader.config");
1019
+ if (typeof loader === "function") {
1020
+ await loader();
1021
+ }
1022
+ if (typeof loader?.loader === "function") {
1023
+ await loader.loader();
1024
+ }
1013
1025
  }
1014
1026
  {
1015
1027
  await this.configService.waitForInit();
@@ -1235,9 +1247,15 @@ class LiveMainService {
1235
1247
  this.loggerService.log("liveMainService run", {
1236
1248
  payload,
1237
1249
  });
1250
+ await this.configConnectionService.loadConfig("setup.config");
1238
1251
  {
1239
- await this.configConnectionService.loadConfig("setup.config");
1240
- await this.configConnectionService.loadConfig("loader.config");
1252
+ const loader = await this.configConnectionService.loadConfig("loader.config");
1253
+ if (typeof loader === "function") {
1254
+ await loader();
1255
+ }
1256
+ if (typeof loader?.loader === "function") {
1257
+ await loader.loader();
1258
+ }
1241
1259
  }
1242
1260
  {
1243
1261
  await this.configService.waitForInit();
@@ -1324,9 +1342,15 @@ class PaperMainService {
1324
1342
  this.configConnectionService = inject(TYPES.configConnectionService);
1325
1343
  this.run = singleshot(async (payload) => {
1326
1344
  this.loggerService.log("paperMainService init");
1345
+ await this.configConnectionService.loadConfig("setup.config");
1327
1346
  {
1328
- await this.configConnectionService.loadConfig("setup.config");
1329
- await this.configConnectionService.loadConfig("loader.config");
1347
+ const loader = await this.configConnectionService.loadConfig("loader.config");
1348
+ if (typeof loader === "function") {
1349
+ await loader();
1350
+ }
1351
+ if (typeof loader?.loader === "function") {
1352
+ await loader.loader();
1353
+ }
1330
1354
  }
1331
1355
  {
1332
1356
  await this.configService.waitForInit();
@@ -2884,8 +2908,14 @@ const GET_ALIAS_EXPORTS_FN = (self) => {
2884
2908
  continue;
2885
2909
  }
2886
2910
  const instance = self.getInstance(baseDir);
2887
- const exports = instance.import(filePath);
2888
- return "default" in exports ? exports.default : exports;
2911
+ const alias = instance.import(filePath);
2912
+ if (!alias) {
2913
+ return null;
2914
+ }
2915
+ if ("default" in alias) {
2916
+ return alias.default;
2917
+ }
2918
+ return alias;
2889
2919
  }
2890
2920
  return null;
2891
2921
  };
@@ -2984,6 +3014,10 @@ class ConfigConnectionService {
2984
3014
  const config = await LOAD_CONFIG_CONFIG_FN(fileName, this);
2985
3015
  if (!config) {
2986
3016
  this.loadConfig.clear(fileName);
3017
+ return null;
3018
+ }
3019
+ if ("default" in config) {
3020
+ return config.default;
2987
3021
  }
2988
3022
  return config;
2989
3023
  });
@@ -3129,10 +3163,10 @@ init();
3129
3163
 
3130
3164
  const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "pnldebug", "brokerdebug", "flush", "init", "docker", "help", "version"];
3131
3165
  const ENTRY_PATH$1 = "./node_modules/@backtest-kit/cli/build/index.mjs";
3132
- const HELP_TEXT$1 = `
3133
- Example:
3134
-
3135
- node ${ENTRY_PATH$1} --help
3166
+ const HELP_TEXT$1 = `
3167
+ Example:
3168
+
3169
+ node ${ENTRY_PATH$1} --help
3136
3170
  `.trimStart();
3137
3171
  const main$g = async () => {
3138
3172
  if (!getEntry(import.meta.url)) {
@@ -3142,7 +3176,7 @@ const main$g = async () => {
3142
3176
  if (MODES.some((mode) => values[mode])) {
3143
3177
  return;
3144
3178
  }
3145
- process.stdout.write(`@backtest-kit/cli ${"9.6.0"}\n`);
3179
+ process.stdout.write(`@backtest-kit/cli ${"9.7.0"}\n`);
3146
3180
  process.stdout.write("\n");
3147
3181
  process.stdout.write(`Run with --help to see available commands.\n`);
3148
3182
  process.stdout.write("\n");
@@ -3433,9 +3467,15 @@ const main$a = async () => {
3433
3467
  }
3434
3468
  await flush(entryPoint);
3435
3469
  }
3470
+ await cli.configConnectionService.loadConfig("setup.config");
3436
3471
  {
3437
- await cli.configConnectionService.loadConfig("setup.config");
3438
- await cli.configConnectionService.loadConfig("loader.config");
3472
+ const loader = await cli.configConnectionService.loadConfig("loader.config");
3473
+ if (typeof loader === "function") {
3474
+ await loader();
3475
+ }
3476
+ if (typeof loader?.loader === "function") {
3477
+ await loader.loader();
3478
+ }
3439
3479
  }
3440
3480
  {
3441
3481
  await cli.configService.waitForInit();
@@ -3537,9 +3577,15 @@ const main$7 = async () => {
3537
3577
  const cwd = process.cwd();
3538
3578
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3539
3579
  }
3580
+ await cli.configConnectionService.loadConfig("setup.config");
3540
3581
  {
3541
- await cli.configConnectionService.loadConfig("setup.config");
3542
- await cli.configConnectionService.loadConfig("loader.config");
3582
+ const loader = await cli.configConnectionService.loadConfig("loader.config");
3583
+ if (typeof loader === "function") {
3584
+ await loader();
3585
+ }
3586
+ if (typeof loader?.loader === "function") {
3587
+ await loader.loader();
3588
+ }
3543
3589
  }
3544
3590
  await cli.moduleConnectionService.loadModule("pine.module");
3545
3591
  {
@@ -3618,9 +3664,15 @@ const main$6 = async () => {
3618
3664
  console.warn("--editor and --pine are mutually exclusive. Use one at a time.");
3619
3665
  process.exit(1);
3620
3666
  }
3667
+ await cli.configConnectionService.loadConfig("setup.config");
3621
3668
  {
3622
- await cli.configConnectionService.loadConfig("setup.config");
3623
- await cli.configConnectionService.loadConfig("loader.config");
3669
+ const loader = await cli.configConnectionService.loadConfig("loader.config");
3670
+ if (typeof loader === "function") {
3671
+ await loader();
3672
+ }
3673
+ if (typeof loader?.loader === "function") {
3674
+ await loader.loader();
3675
+ }
3624
3676
  }
3625
3677
  {
3626
3678
  await cli.configService.waitForInit();
@@ -3663,9 +3715,15 @@ const main$5 = async () => {
3663
3715
  const cwd = process.cwd();
3664
3716
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3665
3717
  }
3718
+ await cli.configConnectionService.loadConfig("setup.config");
3666
3719
  {
3667
- await cli.configConnectionService.loadConfig("setup.config");
3668
- await cli.configConnectionService.loadConfig("loader.config");
3720
+ const loader = await cli.configConnectionService.loadConfig("loader.config");
3721
+ if (typeof loader === "function") {
3722
+ await loader();
3723
+ }
3724
+ if (typeof loader?.loader === "function") {
3725
+ await loader.loader();
3726
+ }
3669
3727
  }
3670
3728
  await cli.moduleConnectionService.loadModule("dump.module");
3671
3729
  {
@@ -3734,9 +3792,15 @@ const main$4 = async () => {
3734
3792
  const cwd = process.cwd();
3735
3793
  dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
3736
3794
  }
3795
+ await cli.configConnectionService.loadConfig("setup.config");
3737
3796
  {
3738
- await cli.configConnectionService.loadConfig("setup.config");
3739
- await cli.configConnectionService.loadConfig("loader.config");
3797
+ const loader = await cli.configConnectionService.loadConfig("loader.config");
3798
+ if (typeof loader === "function") {
3799
+ await loader();
3800
+ }
3801
+ if (typeof loader?.loader === "function") {
3802
+ await loader.loader();
3803
+ }
3740
3804
  }
3741
3805
  await cli.moduleConnectionService.loadModule("pnldebug.module");
3742
3806
  {
@@ -4006,183 +4070,183 @@ const main$2 = async () => {
4006
4070
  main$2();
4007
4071
 
4008
4072
  const ENTRY_PATH = "./node_modules/@backtest-kit/cli/build/index.mjs";
4009
- const HELP_TEXT = `
4010
- Usage:
4011
- node index.mjs --<mode> [flags] [entry-point]
4012
-
4013
- Modes:
4014
-
4015
- --backtest <entry> Run strategy against historical candle data
4016
- --walker <entry...> Run Walker A/B strategy comparison across multiple strategies
4017
- --paper <entry> Paper trading (live prices, no real orders)
4018
- --live <entry> Live trading with real orders
4019
- --pine <entry> Execute a local .pine indicator file
4020
- --editor Open the Pine Script visual editor in the browser
4021
- --dump Fetch and save raw OHLCV candles
4022
- --pnldebug Simulate PnL per minute for a given entry price and direction
4023
- --brokerdebug Fire a single broker commit against the live broker adapter
4024
- --flush <entry...> Delete report/log/markdown/agent folders from strategy dump dir
4025
- --init Scaffold a new project in the current directory
4026
- --docker Scaffold a Docker workspace for running strategies in a container
4027
- --help Print this help message
4028
-
4029
- Backtest flags:
4030
-
4031
- --symbol <string> Trading pair (default: BTCUSDT)
4032
- --strategy <string> Strategy name from addStrategySchema (default: first registered)
4033
- --exchange <string> Exchange name from addExchangeSchema (default: first registered)
4034
- --frame <string> Frame name from addFrameSchema (default: first registered)
4035
- --cacheInterval <string> Comma-separated intervals to pre-cache (default: "1m, 15m, 30m, 4h")
4036
- --noCache Skip candle cache warming before the run
4037
- --noFlush Skip removing report/log/markdown/agent folders before backtest run
4038
- --verbose Log every candle fetch to stdout
4039
- --ui Start web dashboard at http://localhost:60050
4040
- --telegram Send trade notifications to Telegram
4041
-
4042
- Walker flags (--walker):
4043
-
4044
- --symbol <string> Trading pair (default: BTCUSDT)
4045
- --cacheInterval <string> Comma-separated intervals to pre-cache (default: "1m, 15m, 30m, 4h")
4046
- --noCache Skip candle cache warming before the run
4047
- --noFlush Skip removing report/log/markdown/agent folders before walker run
4048
- --verbose Log every candle fetch to stdout
4049
- --output <string> Output file base name (default: walker_{SYMBOL}_{TIMESTAMP})
4050
- --json Save results as JSON to ./dump/<output>.json
4051
- --markdown Save report as Markdown to ./dump/<output>.md
4052
-
4053
- Each positional argument is a strategy entry point. All strategy files are loaded without
4054
- changing process.cwd() — .env is read from the working directory only.
4055
- addWalkerSchema is called automatically using the registered exchange and frame.
4056
- After comparison completes the report is printed to stdout (or saved if --json/--markdown).
4057
-
4058
- Module file ./modules/walker.module is loaded automatically if it exists.
4059
-
4060
- Paper / Live flags:
4061
-
4062
- --symbol <string> Trading pair (default: BTCUSDT)
4063
- --strategy <string> Strategy name (default: first registered)
4064
- --exchange <string> Exchange name (default: first registered)
4065
- --verbose Log every candle fetch to stdout
4066
- --ui Start web dashboard
4067
- --telegram Send Telegram notifications
4068
-
4069
- PineScript flags (--pine):
4070
-
4071
- --symbol <string> Trading pair (default: BTCUSDT)
4072
- --timeframe <string> Candle interval (default: 15m)
4073
- --limit <string> Number of candles to fetch (default: 250)
4074
- --when <string> End date — ISO 8601 or Unix ms (default: now)
4075
- --exchange <string> Exchange name (default: first registered)
4076
- --output <string> Output file base name without extension
4077
- --json Save output as JSON array to <pine-dir>/dump/<output>.json
4078
- --jsonl Save output as JSONL to <pine-dir>/dump/<output>.jsonl
4079
- --markdown Save output as Markdown table to <pine-dir>/dump/<output>.md
4080
-
4081
- Only plot() calls with display=display.data_window produce output columns.
4082
- Module file ./modules/pine.module is loaded automatically if it exists.
4083
-
4084
- Candle dump flags (--dump):
4085
-
4086
- --symbol <string> Trading pair (default: BTCUSDT)
4087
- --timeframe <string> Candle interval (default: 15m)
4088
- --limit <string> Number of candles (default: 250)
4089
- --when <string> End date — ISO 8601 or Unix ms (default: now)
4090
- --exchange <string> Exchange name (default: first registered)
4091
- --output <string> Output file base name (default: {SYMBOL}_{LIMIT}_{TIMEFRAME}_{TIMESTAMP})
4092
- --json Save as JSON array to ./dump/<output>.json
4093
- --jsonl Save as JSONL to ./dump/<output>.jsonl
4094
-
4095
- Module file ./modules/dump.module is loaded automatically if it exists.
4096
-
4097
- PnL debug flags (--pnldebug):
4098
-
4099
- --symbol <string> Trading pair (default: BTCUSDT)
4100
- --priceopen <number> Entry price (required)
4101
- --direction <string> Position direction: long or short (default: long)
4102
- --when <string> Start timestamp — ISO 8601 or Unix ms (default: now)
4103
- --minutes <string> Number of 1m candles to simulate (default: 60)
4104
- --exchange <string> Exchange name (default: first registered)
4105
- --output <string> Output file base name (default: {SYMBOL}_{DIRECTION}_{PRICEOPEN}_{TIMESTAMP})
4106
- --json Save as JSON array to ./dump/<output>.json
4107
- --jsonl Save as JSONL to ./dump/<output>.jsonl
4108
- --markdown Save as Markdown table to ./dump/<output>.md
4109
-
4110
- Module file ./modules/pnldebug.module is loaded automatically if it exists.
4111
-
4112
- Broker debug flags (--brokerdebug):
4113
-
4114
- --symbol <string> Trading pair (default: BTCUSDT)
4115
- --exchange <string> Exchange name (default: first registered)
4116
- --commit <string> Commit type to fire: signal-open, signal-close, partial-profit,
4117
- partial-loss, average-buy, trailing-stop, trailing-take, breakeven
4118
- (default: signal-open)
4119
-
4120
- Loads ./live.module, fetches the last candle for --symbol/--timeframe, and calls
4121
- the selected broker commit with synthetic payload values derived from current price.
4122
-
4123
- Flush flags (--flush):
4124
-
4125
- One or more positional entry points. For each entry point the following
4126
- subdirectories are removed from <entry-dir>/dump/:
4127
-
4128
- report log markdown agent
4129
-
4130
- Init flags (--init):
4131
-
4132
- --output <string> Target directory name (default: backtest-kit-project)
4133
-
4134
- Scaffolds a project and runs scripts/fetch_docs.mjs to download library docs.
4135
-
4136
- Docker flags (--docker):
4137
-
4138
- --output <string> Target directory name (default: backtest-kit-docker)
4139
-
4140
- Scaffolds a Docker workspace: docker-compose.yaml, .env.example, package.json,
4141
- tsconfig.json, and a sample strategy under content/. Run npm install then
4142
- docker compose up to start the container.
4143
-
4144
- Module hooks (loaded automatically by each mode):
4145
-
4146
- modules/backtest.module --backtest Broker adapter for backtest
4147
- modules/walker.module --walker Broker adapter for walker comparison
4148
- modules/paper.module --paper Broker adapter for paper trading
4149
- modules/live.module --live Broker adapter for live trading
4150
- modules/pine.module --pine Exchange schema for PineScript runs
4151
- modules/editor.module --editor Exchange schema for the visual Pine editor
4152
- modules/dump.module --dump Exchange schema for candle dumps
4153
- modules/pnldebug.module --pnldebug Exchange schema for PnL debug runs
4154
- modules/brokerdebug.module --brokerdebug Broker adapter used for broker commit testing
4155
-
4156
- --flush has no associated module. It only removes dump subdirectories.
4157
-
4158
- Extensions .ts, .mjs, .cjs are tried automatically. Missing module = soft warning.
4159
-
4160
- Environment variables:
4161
-
4162
- CC_TELEGRAM_TOKEN Telegram bot token (required for --telegram)
4163
- CC_TELEGRAM_CHANNEL Telegram channel or chat ID (required for --telegram)
4164
- CC_WWWROOT_HOST UI server bind address (default: 0.0.0.0)
4165
- CC_WWWROOT_PORT UI server port (default: 60050)
4166
-
4167
- Examples:
4168
-
4169
- node ${ENTRY_PATH} --backtest ./content/feb_2026.strategy.ts
4170
- node ${ENTRY_PATH} --backtest --symbol BTCUSDT --noCache --noFlush --ui ./content/feb_2026.strategy.ts
4171
- node ${ENTRY_PATH} --walker ./content/feb_2026_v1.strategy.ts ./content/feb_2026_v2.strategy.ts ./content/feb_2026_v3.strategy.ts
4172
- node ${ENTRY_PATH} --walker --symbol BTCUSDT --noCache --noFlush --markdown ./content/feb_2026_v1.ts ./content/feb_2026_v2.ts
4173
- node ${ENTRY_PATH} --paper --symbol ETHUSDT ./content/feb_2026.strategy.ts
4174
- node ${ENTRY_PATH} --live --ui --telegram ./content/feb_2026.strategy.ts
4175
- node ${ENTRY_PATH} --pine ./math/feb_2026.pine --timeframe 15m --limit 500 --jsonl
4176
- node ${ENTRY_PATH} --editor
4177
- node ${ENTRY_PATH} --dump --symbol BTCUSDT --timeframe 15m --limit 500 --jsonl
4178
- node ${ENTRY_PATH} --pnldebug --symbol BTCUSDT --priceopen 64069.50 --direction short --when "2025-02-25" --minutes 120
4179
- node ${ENTRY_PATH} --pnldebug --priceopen 67956.73 --direction long --when 1772064000000 --minutes 60 --markdown
4180
- node ${ENTRY_PATH} --brokerdebug --commit signal-open --symbol BTCUSDT
4181
- node ${ENTRY_PATH} --brokerdebug --commit partial-profit --symbol ETHUSDT
4182
- node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts
4183
- node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts ./content/feb_2026.strategy/feb_2026.test.ts
4184
- node ${ENTRY_PATH} --init --output my-trading-bot
4185
- node ${ENTRY_PATH} --docker --output my-docker-workspace
4073
+ const HELP_TEXT = `
4074
+ Usage:
4075
+ node index.mjs --<mode> [flags] [entry-point]
4076
+
4077
+ Modes:
4078
+
4079
+ --backtest <entry> Run strategy against historical candle data
4080
+ --walker <entry...> Run Walker A/B strategy comparison across multiple strategies
4081
+ --paper <entry> Paper trading (live prices, no real orders)
4082
+ --live <entry> Live trading with real orders
4083
+ --pine <entry> Execute a local .pine indicator file
4084
+ --editor Open the Pine Script visual editor in the browser
4085
+ --dump Fetch and save raw OHLCV candles
4086
+ --pnldebug Simulate PnL per minute for a given entry price and direction
4087
+ --brokerdebug Fire a single broker commit against the live broker adapter
4088
+ --flush <entry...> Delete report/log/markdown/agent folders from strategy dump dir
4089
+ --init Scaffold a new project in the current directory
4090
+ --docker Scaffold a Docker workspace for running strategies in a container
4091
+ --help Print this help message
4092
+
4093
+ Backtest flags:
4094
+
4095
+ --symbol <string> Trading pair (default: BTCUSDT)
4096
+ --strategy <string> Strategy name from addStrategySchema (default: first registered)
4097
+ --exchange <string> Exchange name from addExchangeSchema (default: first registered)
4098
+ --frame <string> Frame name from addFrameSchema (default: first registered)
4099
+ --cacheInterval <string> Comma-separated intervals to pre-cache (default: "1m, 15m, 30m, 4h")
4100
+ --noCache Skip candle cache warming before the run
4101
+ --noFlush Skip removing report/log/markdown/agent folders before backtest run
4102
+ --verbose Log every candle fetch to stdout
4103
+ --ui Start web dashboard at http://localhost:60050
4104
+ --telegram Send trade notifications to Telegram
4105
+
4106
+ Walker flags (--walker):
4107
+
4108
+ --symbol <string> Trading pair (default: BTCUSDT)
4109
+ --cacheInterval <string> Comma-separated intervals to pre-cache (default: "1m, 15m, 30m, 4h")
4110
+ --noCache Skip candle cache warming before the run
4111
+ --noFlush Skip removing report/log/markdown/agent folders before walker run
4112
+ --verbose Log every candle fetch to stdout
4113
+ --output <string> Output file base name (default: walker_{SYMBOL}_{TIMESTAMP})
4114
+ --json Save results as JSON to ./dump/<output>.json
4115
+ --markdown Save report as Markdown to ./dump/<output>.md
4116
+
4117
+ Each positional argument is a strategy entry point. All strategy files are loaded without
4118
+ changing process.cwd() — .env is read from the working directory only.
4119
+ addWalkerSchema is called automatically using the registered exchange and frame.
4120
+ After comparison completes the report is printed to stdout (or saved if --json/--markdown).
4121
+
4122
+ Module file ./modules/walker.module is loaded automatically if it exists.
4123
+
4124
+ Paper / Live flags:
4125
+
4126
+ --symbol <string> Trading pair (default: BTCUSDT)
4127
+ --strategy <string> Strategy name (default: first registered)
4128
+ --exchange <string> Exchange name (default: first registered)
4129
+ --verbose Log every candle fetch to stdout
4130
+ --ui Start web dashboard
4131
+ --telegram Send Telegram notifications
4132
+
4133
+ PineScript flags (--pine):
4134
+
4135
+ --symbol <string> Trading pair (default: BTCUSDT)
4136
+ --timeframe <string> Candle interval (default: 15m)
4137
+ --limit <string> Number of candles to fetch (default: 250)
4138
+ --when <string> End date — ISO 8601 or Unix ms (default: now)
4139
+ --exchange <string> Exchange name (default: first registered)
4140
+ --output <string> Output file base name without extension
4141
+ --json Save output as JSON array to <pine-dir>/dump/<output>.json
4142
+ --jsonl Save output as JSONL to <pine-dir>/dump/<output>.jsonl
4143
+ --markdown Save output as Markdown table to <pine-dir>/dump/<output>.md
4144
+
4145
+ Only plot() calls with display=display.data_window produce output columns.
4146
+ Module file ./modules/pine.module is loaded automatically if it exists.
4147
+
4148
+ Candle dump flags (--dump):
4149
+
4150
+ --symbol <string> Trading pair (default: BTCUSDT)
4151
+ --timeframe <string> Candle interval (default: 15m)
4152
+ --limit <string> Number of candles (default: 250)
4153
+ --when <string> End date — ISO 8601 or Unix ms (default: now)
4154
+ --exchange <string> Exchange name (default: first registered)
4155
+ --output <string> Output file base name (default: {SYMBOL}_{LIMIT}_{TIMEFRAME}_{TIMESTAMP})
4156
+ --json Save as JSON array to ./dump/<output>.json
4157
+ --jsonl Save as JSONL to ./dump/<output>.jsonl
4158
+
4159
+ Module file ./modules/dump.module is loaded automatically if it exists.
4160
+
4161
+ PnL debug flags (--pnldebug):
4162
+
4163
+ --symbol <string> Trading pair (default: BTCUSDT)
4164
+ --priceopen <number> Entry price (required)
4165
+ --direction <string> Position direction: long or short (default: long)
4166
+ --when <string> Start timestamp — ISO 8601 or Unix ms (default: now)
4167
+ --minutes <string> Number of 1m candles to simulate (default: 60)
4168
+ --exchange <string> Exchange name (default: first registered)
4169
+ --output <string> Output file base name (default: {SYMBOL}_{DIRECTION}_{PRICEOPEN}_{TIMESTAMP})
4170
+ --json Save as JSON array to ./dump/<output>.json
4171
+ --jsonl Save as JSONL to ./dump/<output>.jsonl
4172
+ --markdown Save as Markdown table to ./dump/<output>.md
4173
+
4174
+ Module file ./modules/pnldebug.module is loaded automatically if it exists.
4175
+
4176
+ Broker debug flags (--brokerdebug):
4177
+
4178
+ --symbol <string> Trading pair (default: BTCUSDT)
4179
+ --exchange <string> Exchange name (default: first registered)
4180
+ --commit <string> Commit type to fire: signal-open, signal-close, partial-profit,
4181
+ partial-loss, average-buy, trailing-stop, trailing-take, breakeven
4182
+ (default: signal-open)
4183
+
4184
+ Loads ./live.module, fetches the last candle for --symbol/--timeframe, and calls
4185
+ the selected broker commit with synthetic payload values derived from current price.
4186
+
4187
+ Flush flags (--flush):
4188
+
4189
+ One or more positional entry points. For each entry point the following
4190
+ subdirectories are removed from <entry-dir>/dump/:
4191
+
4192
+ report log markdown agent
4193
+
4194
+ Init flags (--init):
4195
+
4196
+ --output <string> Target directory name (default: backtest-kit-project)
4197
+
4198
+ Scaffolds a project and runs scripts/fetch_docs.mjs to download library docs.
4199
+
4200
+ Docker flags (--docker):
4201
+
4202
+ --output <string> Target directory name (default: backtest-kit-docker)
4203
+
4204
+ Scaffolds a Docker workspace: docker-compose.yaml, .env.example, package.json,
4205
+ tsconfig.json, and a sample strategy under content/. Run npm install then
4206
+ docker compose up to start the container.
4207
+
4208
+ Module hooks (loaded automatically by each mode):
4209
+
4210
+ modules/backtest.module --backtest Broker adapter for backtest
4211
+ modules/walker.module --walker Broker adapter for walker comparison
4212
+ modules/paper.module --paper Broker adapter for paper trading
4213
+ modules/live.module --live Broker adapter for live trading
4214
+ modules/pine.module --pine Exchange schema for PineScript runs
4215
+ modules/editor.module --editor Exchange schema for the visual Pine editor
4216
+ modules/dump.module --dump Exchange schema for candle dumps
4217
+ modules/pnldebug.module --pnldebug Exchange schema for PnL debug runs
4218
+ modules/brokerdebug.module --brokerdebug Broker adapter used for broker commit testing
4219
+
4220
+ --flush has no associated module. It only removes dump subdirectories.
4221
+
4222
+ Extensions .ts, .mjs, .cjs are tried automatically. Missing module = soft warning.
4223
+
4224
+ Environment variables:
4225
+
4226
+ CC_TELEGRAM_TOKEN Telegram bot token (required for --telegram)
4227
+ CC_TELEGRAM_CHANNEL Telegram channel or chat ID (required for --telegram)
4228
+ CC_WWWROOT_HOST UI server bind address (default: 0.0.0.0)
4229
+ CC_WWWROOT_PORT UI server port (default: 60050)
4230
+
4231
+ Examples:
4232
+
4233
+ node ${ENTRY_PATH} --backtest ./content/feb_2026.strategy.ts
4234
+ node ${ENTRY_PATH} --backtest --symbol BTCUSDT --noCache --noFlush --ui ./content/feb_2026.strategy.ts
4235
+ node ${ENTRY_PATH} --walker ./content/feb_2026_v1.strategy.ts ./content/feb_2026_v2.strategy.ts ./content/feb_2026_v3.strategy.ts
4236
+ node ${ENTRY_PATH} --walker --symbol BTCUSDT --noCache --noFlush --markdown ./content/feb_2026_v1.ts ./content/feb_2026_v2.ts
4237
+ node ${ENTRY_PATH} --paper --symbol ETHUSDT ./content/feb_2026.strategy.ts
4238
+ node ${ENTRY_PATH} --live --ui --telegram ./content/feb_2026.strategy.ts
4239
+ node ${ENTRY_PATH} --pine ./math/feb_2026.pine --timeframe 15m --limit 500 --jsonl
4240
+ node ${ENTRY_PATH} --editor
4241
+ node ${ENTRY_PATH} --dump --symbol BTCUSDT --timeframe 15m --limit 500 --jsonl
4242
+ node ${ENTRY_PATH} --pnldebug --symbol BTCUSDT --priceopen 64069.50 --direction short --when "2025-02-25" --minutes 120
4243
+ node ${ENTRY_PATH} --pnldebug --priceopen 67956.73 --direction long --when 1772064000000 --minutes 60 --markdown
4244
+ node ${ENTRY_PATH} --brokerdebug --commit signal-open --symbol BTCUSDT
4245
+ node ${ENTRY_PATH} --brokerdebug --commit partial-profit --symbol ETHUSDT
4246
+ node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts
4247
+ node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts ./content/feb_2026.strategy/feb_2026.test.ts
4248
+ node ${ENTRY_PATH} --init --output my-trading-bot
4249
+ node ${ENTRY_PATH} --docker --output my-docker-workspace
4186
4250
  `.trimStart();
4187
4251
  const main$1 = async () => {
4188
4252
  if (!getEntry(import.meta.url)) {
@@ -4192,7 +4256,7 @@ const main$1 = async () => {
4192
4256
  if (!values.help) {
4193
4257
  return;
4194
4258
  }
4195
- process.stdout.write(`@backtest-kit/cli ${"9.6.0"}\n\n`);
4259
+ process.stdout.write(`@backtest-kit/cli ${"9.7.0"}\n\n`);
4196
4260
  process.stdout.write(HELP_TEXT);
4197
4261
  process.exit(0);
4198
4262
  };
@@ -4206,7 +4270,7 @@ const main = async () => {
4206
4270
  if (!values.version) {
4207
4271
  return;
4208
4272
  }
4209
- process.stdout.write(`@backtest-kit/cli ${"9.6.0"}\n`);
4273
+ process.stdout.write(`@backtest-kit/cli ${"9.7.0"}\n`);
4210
4274
  process.exit(0);
4211
4275
  };
4212
4276
  main();
@@ -1,13 +1,13 @@
1
- export default {
2
- signal: true,
3
- risk: true,
4
- info: true,
5
- breakeven: true,
6
- common_error: true,
7
- critical_error: true,
8
- validation_error: true,
9
- partial_loss: false,
10
- partial_profit: false,
11
- signal_sync: false,
12
- strategy_commit: true,
13
- };
1
+ export default {
2
+ signal: true,
3
+ risk: true,
4
+ info: true,
5
+ breakeven: true,
6
+ common_error: true,
7
+ critical_error: true,
8
+ validation_error: true,
9
+ partial_loss: false,
10
+ partial_profit: false,
11
+ signal_sync: false,
12
+ strategy_commit: true,
13
+ };