@backtest-kit/cli 5.10.0 → 5.10.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/README.md +23 -9
- package/build/index.cjs +20 -14
- package/build/index.mjs +22 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -450,9 +450,10 @@ For projects that compile to or use CommonJS. Loaded via `require()`:
|
|
|
450
450
|
| `--limit` | string | Number of candles to fetch (default: `250`) |
|
|
451
451
|
| `--when` | string | End date for candle window — ISO 8601 or Unix ms (default: now) |
|
|
452
452
|
| `--exchange` | string | Exchange name (default: first registered, falls back to CCXT Binance) |
|
|
453
|
-
| `--
|
|
454
|
-
| `--
|
|
455
|
-
| `--
|
|
453
|
+
| `--output` | string | Output file base name without extension (default: `.pine` file name) |
|
|
454
|
+
| `--json` | boolean | Write plots as a JSON array to `<pine-dir>/dump/{output}.json` |
|
|
455
|
+
| `--jsonl` | boolean | Write plots as JSONL (one row per line) to `<pine-dir>/dump/{output}.jsonl` |
|
|
456
|
+
| `--markdown` | boolean | Write Markdown table to `<pine-dir>/dump/{output}.md` |
|
|
456
457
|
|
|
457
458
|
**Important:** `limit` must cover indicator warmup bars — rows before warmup completes will show `N/A`
|
|
458
459
|
|
|
@@ -470,7 +471,7 @@ The CLI looks for `modules/pine.module` in two locations (first match wins):
|
|
|
470
471
|
```
|
|
471
472
|
my-project/
|
|
472
473
|
├── math/
|
|
473
|
-
│ ├──
|
|
474
|
+
│ ├── impulse_trend_15m.pine ← indicator
|
|
474
475
|
│ └── modules/
|
|
475
476
|
│ └── pine.module.ts ← loaded first (next to .pine file)
|
|
476
477
|
├── modules/
|
|
@@ -507,7 +508,7 @@ Before loading `pine.module`, the CLI loads `.env` files in the same order as fo
|
|
|
507
508
|
my-project/
|
|
508
509
|
├── math/
|
|
509
510
|
│ ├── .env ← loaded second (overrides root)
|
|
510
|
-
│ └──
|
|
511
|
+
│ └── impulse_trend_15m.pine
|
|
511
512
|
├── .env ← loaded first
|
|
512
513
|
└── package.json
|
|
513
514
|
```
|
|
@@ -538,7 +539,7 @@ addExchangeSchema({
|
|
|
538
539
|
Then run:
|
|
539
540
|
|
|
540
541
|
```bash
|
|
541
|
-
npx @backtest-kit/cli --pine ./math/
|
|
542
|
+
npx @backtest-kit/cli --pine ./math/impulse_trend_15m.pine \
|
|
542
543
|
--exchange my-exchange \
|
|
543
544
|
--symbol BTCUSDT \
|
|
544
545
|
--timeframe 15m \
|
|
@@ -551,7 +552,7 @@ Or add it to `package.json`:
|
|
|
551
552
|
```json
|
|
552
553
|
{
|
|
553
554
|
"scripts": {
|
|
554
|
-
"pine": "npx @backtest-kit/cli --pine ./math/
|
|
555
|
+
"pine": "npx @backtest-kit/cli --pine ./math/impulse_trend_15m.pine --symbol BTCUSDT --timeframe 15m --limit 180"
|
|
555
556
|
}
|
|
556
557
|
}
|
|
557
558
|
```
|
|
@@ -593,10 +594,23 @@ The CLI prints a Markdown table to stdout:
|
|
|
593
594
|
| 112653.90 | 1.0000 | 2025-09-22T22:15:00.000Z |
|
|
594
595
|
```
|
|
595
596
|
|
|
596
|
-
|
|
597
|
+
Save to `./math/dump/impulse_trend_15m.md` (uses `.pine` file name automatically, dump is created next to the `.pine` file):
|
|
597
598
|
|
|
598
599
|
```bash
|
|
599
|
-
|
|
600
|
+
npx @backtest-kit/cli --pine ./math/impulse_trend_15m.pine --markdown
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Override the output name with `--output`:
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
npx @backtest-kit/cli --pine ./math/impulse_trend_15m.pine --jsonl --output feb2026_bb
|
|
607
|
+
# → ./math/dump/feb2026_bb.jsonl
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Print to stdout (no flag):
|
|
611
|
+
|
|
612
|
+
```bash
|
|
613
|
+
npx @backtest-kit/cli --pine ./math/impulse_trend_15m.pine
|
|
600
614
|
```
|
|
601
615
|
|
|
602
616
|
## 🌍 Environment Variables
|
package/build/index.cjs
CHANGED
|
@@ -519,17 +519,21 @@ const getArgs = functoolsKit.singleshot(() => {
|
|
|
519
519
|
type: "string",
|
|
520
520
|
default: "",
|
|
521
521
|
},
|
|
522
|
-
|
|
522
|
+
output: {
|
|
523
523
|
type: "string",
|
|
524
524
|
default: "",
|
|
525
525
|
},
|
|
526
|
+
json: {
|
|
527
|
+
type: "boolean",
|
|
528
|
+
default: false,
|
|
529
|
+
},
|
|
526
530
|
jsonl: {
|
|
527
|
-
type: "
|
|
528
|
-
default:
|
|
531
|
+
type: "boolean",
|
|
532
|
+
default: false,
|
|
529
533
|
},
|
|
530
534
|
markdown: {
|
|
531
|
-
type: "
|
|
532
|
-
default:
|
|
535
|
+
type: "boolean",
|
|
536
|
+
default: false,
|
|
533
537
|
},
|
|
534
538
|
},
|
|
535
539
|
strict: false,
|
|
@@ -2380,21 +2384,23 @@ const main = async () => {
|
|
|
2380
2384
|
return true;
|
|
2381
2385
|
}))
|
|
2382
2386
|
.map((key) => [key, key]));
|
|
2383
|
-
const
|
|
2384
|
-
|
|
2387
|
+
const dumpName = values.output || path.basename(entryPoint, path.extname(entryPoint));
|
|
2388
|
+
const dumpDir = path.join(process.cwd(), "dump");
|
|
2389
|
+
if (values.json) {
|
|
2385
2390
|
const rows = EXTRACT_ROWS_FN(plots, signalSchema);
|
|
2386
|
-
await fs$1.
|
|
2391
|
+
await fs$1.mkdir(dumpDir, { recursive: true });
|
|
2392
|
+
await fs$1.writeFile(path.join(dumpDir, `${dumpName}.json`), JSON.stringify(rows, null, 2), "utf-8");
|
|
2387
2393
|
return;
|
|
2388
2394
|
}
|
|
2389
|
-
|
|
2390
|
-
if (jsonlPath) {
|
|
2395
|
+
if (values.jsonl) {
|
|
2391
2396
|
const rows = EXTRACT_ROWS_FN(plots, signalSchema);
|
|
2392
|
-
await fs$1.
|
|
2397
|
+
await fs$1.mkdir(dumpDir, { recursive: true });
|
|
2398
|
+
await fs$1.writeFile(path.join(dumpDir, `${dumpName}.jsonl`), rows.map((r) => JSON.stringify(r)).join("\n"), "utf-8");
|
|
2393
2399
|
return;
|
|
2394
2400
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
await fs$1.writeFile(
|
|
2401
|
+
if (values.markdown) {
|
|
2402
|
+
await fs$1.mkdir(dumpDir, { recursive: true });
|
|
2403
|
+
await fs$1.writeFile(path.join(dumpDir, `${dumpName}.md`), await BacktestKitPinets.toMarkdown(signalId, plots, signalSchema), "utf-8");
|
|
2398
2404
|
return;
|
|
2399
2405
|
}
|
|
2400
2406
|
console.log(await BacktestKitPinets.toMarkdown(signalId, plots, signalSchema));
|
package/build/index.mjs
CHANGED
|
@@ -4,8 +4,8 @@ import { Storage, Notification, Markdown, Report, Dump, Memory, StorageLive, Sto
|
|
|
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';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import fs$1, { access, readFile, writeFile } from 'fs/promises';
|
|
7
|
+
import path, { basename, extname, join } from 'path';
|
|
8
|
+
import fs$1, { access, readFile, mkdir, writeFile } from 'fs/promises';
|
|
9
9
|
import dotenv from 'dotenv';
|
|
10
10
|
import { createActivator } from 'di-kit';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
@@ -494,17 +494,21 @@ const getArgs = singleshot(() => {
|
|
|
494
494
|
type: "string",
|
|
495
495
|
default: "",
|
|
496
496
|
},
|
|
497
|
-
|
|
497
|
+
output: {
|
|
498
498
|
type: "string",
|
|
499
499
|
default: "",
|
|
500
500
|
},
|
|
501
|
+
json: {
|
|
502
|
+
type: "boolean",
|
|
503
|
+
default: false,
|
|
504
|
+
},
|
|
501
505
|
jsonl: {
|
|
502
|
-
type: "
|
|
503
|
-
default:
|
|
506
|
+
type: "boolean",
|
|
507
|
+
default: false,
|
|
504
508
|
},
|
|
505
509
|
markdown: {
|
|
506
|
-
type: "
|
|
507
|
-
default:
|
|
510
|
+
type: "boolean",
|
|
511
|
+
default: false,
|
|
508
512
|
},
|
|
509
513
|
},
|
|
510
514
|
strict: false,
|
|
@@ -2351,21 +2355,23 @@ const main = async () => {
|
|
|
2351
2355
|
return true;
|
|
2352
2356
|
}))
|
|
2353
2357
|
.map((key) => [key, key]));
|
|
2354
|
-
const
|
|
2355
|
-
|
|
2358
|
+
const dumpName = values.output || basename(entryPoint, extname(entryPoint));
|
|
2359
|
+
const dumpDir = join(process.cwd(), "dump");
|
|
2360
|
+
if (values.json) {
|
|
2356
2361
|
const rows = EXTRACT_ROWS_FN(plots, signalSchema);
|
|
2357
|
-
await
|
|
2362
|
+
await mkdir(dumpDir, { recursive: true });
|
|
2363
|
+
await writeFile(join(dumpDir, `${dumpName}.json`), JSON.stringify(rows, null, 2), "utf-8");
|
|
2358
2364
|
return;
|
|
2359
2365
|
}
|
|
2360
|
-
|
|
2361
|
-
if (jsonlPath) {
|
|
2366
|
+
if (values.jsonl) {
|
|
2362
2367
|
const rows = EXTRACT_ROWS_FN(plots, signalSchema);
|
|
2363
|
-
await
|
|
2368
|
+
await mkdir(dumpDir, { recursive: true });
|
|
2369
|
+
await writeFile(join(dumpDir, `${dumpName}.jsonl`), rows.map((r) => JSON.stringify(r)).join("\n"), "utf-8");
|
|
2364
2370
|
return;
|
|
2365
2371
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
await writeFile(
|
|
2372
|
+
if (values.markdown) {
|
|
2373
|
+
await mkdir(dumpDir, { recursive: true });
|
|
2374
|
+
await writeFile(join(dumpDir, `${dumpName}.md`), await toMarkdown(signalId, plots, signalSchema), "utf-8");
|
|
2369
2375
|
return;
|
|
2370
2376
|
}
|
|
2371
2377
|
console.log(await toMarkdown(signalId, plots, signalSchema));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtest-kit/cli",
|
|
3
|
-
"version": "5.10.
|
|
3
|
+
"version": "5.10.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",
|