@backtest-kit/cli 8.2.0 → 8.3.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 +42 -0
- package/build/index.cjs +132 -44
- package/build/index.mjs +132 -44
- package/docker/.env.example +2 -0
- package/docker/content/feb_2026/feb_2026.strategy.ts +11 -0
- package/docker/content/feb_2026/modules/backtest.module.ts +83 -0
- package/docker/docker-compose.yaml +24 -0
- package/docker/package.json +38 -0
- package/docker/tsconfig.json +36 -0
- package/package.json +15 -14
- package/template/project/package.mustache +5 -5
package/README.md
CHANGED
|
@@ -1369,6 +1369,48 @@ Or via the pre-configured npm script:
|
|
|
1369
1369
|
npm run sync:lib
|
|
1370
1370
|
```
|
|
1371
1371
|
|
|
1372
|
+
## 🐳 Running in Docker (`--docker`)
|
|
1373
|
+
|
|
1374
|
+
CLI can scaffold a ready-to-use Docker workspace: self-contained directory with `docker-compose.yaml` and a strategy entry point.
|
|
1375
|
+
|
|
1376
|
+
### CLI Flags
|
|
1377
|
+
|
|
1378
|
+
| Flag | Type | Description |
|
|
1379
|
+
|------|------|-------------|
|
|
1380
|
+
| `--docker` | boolean | Scaffold a Docker workspace |
|
|
1381
|
+
| `--output` | string | Target directory name (default: `backtest-kit-docker`) |
|
|
1382
|
+
|
|
1383
|
+
### Usage
|
|
1384
|
+
|
|
1385
|
+
```bash
|
|
1386
|
+
npx @backtest-kit/cli --docker
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
Creates `./backtest-kit-docker/` in the current working directory.
|
|
1390
|
+
|
|
1391
|
+
Override the directory name with `--output`:
|
|
1392
|
+
|
|
1393
|
+
```bash
|
|
1394
|
+
npx @backtest-kit/cli --docker --output my-docker-workspace
|
|
1395
|
+
```
|
|
1396
|
+
|
|
1397
|
+
The target directory must not exist or must be empty — the command aborts if it contains any files.
|
|
1398
|
+
|
|
1399
|
+
### Generated Workspace Structure
|
|
1400
|
+
|
|
1401
|
+
```
|
|
1402
|
+
backtest-kit-docker/
|
|
1403
|
+
├── docker-compose.yaml # ready-to-run service definition
|
|
1404
|
+
├── .env.example # environment variable reference
|
|
1405
|
+
├── package.json # dependencies for editing strategies locally
|
|
1406
|
+
├── tsconfig.json # TypeScript config for content/
|
|
1407
|
+
└── content/
|
|
1408
|
+
└── feb_2026/
|
|
1409
|
+
├── feb_2026.strategy.ts # example strategy entry point
|
|
1410
|
+
└── modules/
|
|
1411
|
+
└── backtest.module.ts # CCXT Binance exchange + frame schema
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1372
1414
|
## 🌍 Environment Variables
|
|
1373
1415
|
|
|
1374
1416
|
Create a `.env` file in your project root:
|
package/build/index.cjs
CHANGED
|
@@ -266,16 +266,16 @@ const TYPES = {
|
|
|
266
266
|
|
|
267
267
|
const entrySubject = new functoolsKit.BehaviorSubject();
|
|
268
268
|
|
|
269
|
-
const __filename$
|
|
270
|
-
const __dirname$
|
|
269
|
+
const __filename$3 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
270
|
+
const __dirname$3 = path.dirname(__filename$3);
|
|
271
271
|
let _is_launched = false;
|
|
272
272
|
class ResolveService {
|
|
273
273
|
constructor() {
|
|
274
274
|
this.loggerService = inject(TYPES.loggerService);
|
|
275
275
|
this.loaderService = inject(TYPES.loaderService);
|
|
276
|
-
this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$
|
|
277
|
-
this.DEFAULT_MODULES_DIR = path.resolve(__dirname$
|
|
278
|
-
this.DEFAULT_CONFIG_DIR = path.resolve(__dirname$
|
|
276
|
+
this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$3, '..', 'template');
|
|
277
|
+
this.DEFAULT_MODULES_DIR = path.resolve(__dirname$3, '..', 'modules');
|
|
278
|
+
this.DEFAULT_CONFIG_DIR = path.resolve(__dirname$3, '..', 'config');
|
|
279
279
|
this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
|
|
280
280
|
this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
|
|
281
281
|
this.OVERRIDE_CONFIG_DIR = path.resolve(process.cwd(), 'config');
|
|
@@ -598,6 +598,10 @@ const getArgs = functoolsKit.singleshot(() => {
|
|
|
598
598
|
type: "boolean",
|
|
599
599
|
default: false,
|
|
600
600
|
},
|
|
601
|
+
docker: {
|
|
602
|
+
type: "boolean",
|
|
603
|
+
default: false,
|
|
604
|
+
},
|
|
601
605
|
help: {
|
|
602
606
|
type: "boolean",
|
|
603
607
|
default: false,
|
|
@@ -3007,14 +3011,14 @@ const cli = {
|
|
|
3007
3011
|
};
|
|
3008
3012
|
init();
|
|
3009
3013
|
|
|
3010
|
-
const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "pnldebug", "brokerdebug", "flush", "init", "help", "version"];
|
|
3014
|
+
const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "pnldebug", "brokerdebug", "flush", "init", "docker", "help", "version"];
|
|
3011
3015
|
const ENTRY_PATH$1 = "./node_modules/@backtest-kit/cli/build/index.mjs";
|
|
3012
3016
|
const HELP_TEXT$1 = `
|
|
3013
3017
|
Example:
|
|
3014
3018
|
|
|
3015
3019
|
node ${ENTRY_PATH$1} --help
|
|
3016
3020
|
`.trimStart();
|
|
3017
|
-
const main$
|
|
3021
|
+
const main$f = async () => {
|
|
3018
3022
|
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)))) {
|
|
3019
3023
|
return;
|
|
3020
3024
|
}
|
|
@@ -3022,14 +3026,14 @@ const main$e = async () => {
|
|
|
3022
3026
|
if (MODES.some((mode) => values[mode])) {
|
|
3023
3027
|
return;
|
|
3024
3028
|
}
|
|
3025
|
-
process.stdout.write(`@backtest-kit/cli ${"8.
|
|
3029
|
+
process.stdout.write(`@backtest-kit/cli ${"8.3.0"}\n`);
|
|
3026
3030
|
process.stdout.write("\n");
|
|
3027
3031
|
process.stdout.write(`Run with --help to see available commands.\n`);
|
|
3028
3032
|
process.stdout.write("\n");
|
|
3029
3033
|
process.stdout.write(HELP_TEXT$1);
|
|
3030
3034
|
process.exit(0);
|
|
3031
3035
|
};
|
|
3032
|
-
main$
|
|
3036
|
+
main$f();
|
|
3033
3037
|
|
|
3034
3038
|
const notifyShutdown = functoolsKit.singleshot(async () => {
|
|
3035
3039
|
console.log("Graceful shutdown initiated. Press Ctrl+C again to force quit.");
|
|
@@ -3045,7 +3049,7 @@ const flush = async (entryPoint) => {
|
|
|
3045
3049
|
console.log(`Removed: ${target}`);
|
|
3046
3050
|
}
|
|
3047
3051
|
};
|
|
3048
|
-
const main$
|
|
3052
|
+
const main$e = async () => {
|
|
3049
3053
|
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)))) {
|
|
3050
3054
|
return;
|
|
3051
3055
|
}
|
|
@@ -3062,7 +3066,7 @@ const main$d = async () => {
|
|
|
3062
3066
|
}
|
|
3063
3067
|
process.exit(0);
|
|
3064
3068
|
};
|
|
3065
|
-
main$
|
|
3069
|
+
main$e();
|
|
3066
3070
|
|
|
3067
3071
|
const BEFORE_EXIT_FN$5 = functoolsKit.singleshot(async () => {
|
|
3068
3072
|
process.off("SIGINT", BEFORE_EXIT_FN$5);
|
|
@@ -3084,7 +3088,7 @@ const BEFORE_EXIT_FN$5 = functoolsKit.singleshot(async () => {
|
|
|
3084
3088
|
const listenGracefulShutdown$5 = functoolsKit.singleshot(() => {
|
|
3085
3089
|
process.on("SIGINT", BEFORE_EXIT_FN$5);
|
|
3086
3090
|
});
|
|
3087
|
-
const main$
|
|
3091
|
+
const main$d = async () => {
|
|
3088
3092
|
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)))) {
|
|
3089
3093
|
return;
|
|
3090
3094
|
}
|
|
@@ -3099,7 +3103,7 @@ const main$c = async () => {
|
|
|
3099
3103
|
await cli.backtestMainService.connect();
|
|
3100
3104
|
listenGracefulShutdown$5();
|
|
3101
3105
|
};
|
|
3102
|
-
main$
|
|
3106
|
+
main$d();
|
|
3103
3107
|
|
|
3104
3108
|
const BEFORE_EXIT_FN$4 = functoolsKit.singleshot(async () => {
|
|
3105
3109
|
process.off("SIGINT", BEFORE_EXIT_FN$4);
|
|
@@ -3117,7 +3121,7 @@ const BEFORE_EXIT_FN$4 = functoolsKit.singleshot(async () => {
|
|
|
3117
3121
|
const listenGracefulShutdown$4 = functoolsKit.singleshot(() => {
|
|
3118
3122
|
process.on("SIGINT", BEFORE_EXIT_FN$4);
|
|
3119
3123
|
});
|
|
3120
|
-
const main$
|
|
3124
|
+
const main$c = async () => {
|
|
3121
3125
|
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)))) {
|
|
3122
3126
|
return;
|
|
3123
3127
|
}
|
|
@@ -3133,7 +3137,7 @@ const main$b = async () => {
|
|
|
3133
3137
|
listenGracefulShutdown$4();
|
|
3134
3138
|
await cli.walkerMainService.connect();
|
|
3135
3139
|
};
|
|
3136
|
-
main$
|
|
3140
|
+
main$c();
|
|
3137
3141
|
|
|
3138
3142
|
const BEFORE_EXIT_FN$3 = functoolsKit.singleshot(async () => {
|
|
3139
3143
|
process.off("SIGINT", BEFORE_EXIT_FN$3);
|
|
@@ -3154,7 +3158,7 @@ const BEFORE_EXIT_FN$3 = functoolsKit.singleshot(async () => {
|
|
|
3154
3158
|
const listenGracefulShutdown$3 = functoolsKit.singleshot(() => {
|
|
3155
3159
|
process.on("SIGINT", BEFORE_EXIT_FN$3);
|
|
3156
3160
|
});
|
|
3157
|
-
const main$
|
|
3161
|
+
const main$b = async () => {
|
|
3158
3162
|
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)))) {
|
|
3159
3163
|
return;
|
|
3160
3164
|
}
|
|
@@ -3165,7 +3169,7 @@ const main$a = async () => {
|
|
|
3165
3169
|
cli.paperMainService.connect();
|
|
3166
3170
|
listenGracefulShutdown$3();
|
|
3167
3171
|
};
|
|
3168
|
-
main$
|
|
3172
|
+
main$b();
|
|
3169
3173
|
|
|
3170
3174
|
const BEFORE_EXIT_FN$2 = functoolsKit.singleshot(async () => {
|
|
3171
3175
|
process.off("SIGINT", BEFORE_EXIT_FN$2);
|
|
@@ -3186,7 +3190,7 @@ const BEFORE_EXIT_FN$2 = functoolsKit.singleshot(async () => {
|
|
|
3186
3190
|
const listenGracefulShutdown$2 = functoolsKit.singleshot(() => {
|
|
3187
3191
|
process.on("SIGINT", BEFORE_EXIT_FN$2);
|
|
3188
3192
|
});
|
|
3189
|
-
const main$
|
|
3193
|
+
const main$a = async () => {
|
|
3190
3194
|
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)))) {
|
|
3191
3195
|
return;
|
|
3192
3196
|
}
|
|
@@ -3197,7 +3201,7 @@ const main$9 = async () => {
|
|
|
3197
3201
|
await cli.liveMainService.connect();
|
|
3198
3202
|
listenGracefulShutdown$2();
|
|
3199
3203
|
};
|
|
3200
|
-
main$
|
|
3204
|
+
main$a();
|
|
3201
3205
|
|
|
3202
3206
|
const BEFORE_EXIT_FN$1 = functoolsKit.singleshot(async () => {
|
|
3203
3207
|
process.off("SIGINT", BEFORE_EXIT_FN$1);
|
|
@@ -3207,7 +3211,7 @@ const BEFORE_EXIT_FN$1 = functoolsKit.singleshot(async () => {
|
|
|
3207
3211
|
const listenGracefulShutdown$1 = functoolsKit.singleshot(() => {
|
|
3208
3212
|
process.on("SIGINT", BEFORE_EXIT_FN$1);
|
|
3209
3213
|
});
|
|
3210
|
-
const main$
|
|
3214
|
+
const main$9 = async () => {
|
|
3211
3215
|
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)))) {
|
|
3212
3216
|
return;
|
|
3213
3217
|
}
|
|
@@ -3217,7 +3221,7 @@ const main$8 = async () => {
|
|
|
3217
3221
|
}
|
|
3218
3222
|
listenGracefulShutdown$1();
|
|
3219
3223
|
};
|
|
3220
|
-
main$
|
|
3224
|
+
main$9();
|
|
3221
3225
|
|
|
3222
3226
|
const BEFORE_EXIT_FN = functoolsKit.singleshot(async () => {
|
|
3223
3227
|
process.off("SIGINT", BEFORE_EXIT_FN);
|
|
@@ -3227,7 +3231,7 @@ const BEFORE_EXIT_FN = functoolsKit.singleshot(async () => {
|
|
|
3227
3231
|
const listenGracefulShutdown = functoolsKit.singleshot(() => {
|
|
3228
3232
|
process.on("SIGINT", BEFORE_EXIT_FN);
|
|
3229
3233
|
});
|
|
3230
|
-
const main$
|
|
3234
|
+
const main$8 = async () => {
|
|
3231
3235
|
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)))) {
|
|
3232
3236
|
return;
|
|
3233
3237
|
}
|
|
@@ -3237,7 +3241,7 @@ const main$7 = async () => {
|
|
|
3237
3241
|
}
|
|
3238
3242
|
listenGracefulShutdown();
|
|
3239
3243
|
};
|
|
3240
|
-
main$
|
|
3244
|
+
main$8();
|
|
3241
3245
|
|
|
3242
3246
|
const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
3243
3247
|
const keys = Object.keys(schema);
|
|
@@ -3259,7 +3263,7 @@ const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
|
3259
3263
|
}
|
|
3260
3264
|
return rows;
|
|
3261
3265
|
};
|
|
3262
|
-
const main$
|
|
3266
|
+
const main$7 = async () => {
|
|
3263
3267
|
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)))) {
|
|
3264
3268
|
return;
|
|
3265
3269
|
}
|
|
@@ -3339,9 +3343,9 @@ const main$6 = async () => {
|
|
|
3339
3343
|
console.log(await BacktestKitPinets.toMarkdown(signalId, plots, signalSchema));
|
|
3340
3344
|
process.exit(0);
|
|
3341
3345
|
};
|
|
3342
|
-
main$
|
|
3346
|
+
main$7();
|
|
3343
3347
|
|
|
3344
|
-
const main$
|
|
3348
|
+
const main$6 = async () => {
|
|
3345
3349
|
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)))) {
|
|
3346
3350
|
return;
|
|
3347
3351
|
}
|
|
@@ -3376,9 +3380,9 @@ const main$5 = async () => {
|
|
|
3376
3380
|
};
|
|
3377
3381
|
process.on("SIGINT", beforeExit);
|
|
3378
3382
|
};
|
|
3379
|
-
main$
|
|
3383
|
+
main$6();
|
|
3380
3384
|
|
|
3381
|
-
const main$
|
|
3385
|
+
const main$5 = async () => {
|
|
3382
3386
|
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)))) {
|
|
3383
3387
|
return;
|
|
3384
3388
|
}
|
|
@@ -3439,9 +3443,9 @@ const main$4 = async () => {
|
|
|
3439
3443
|
console.log(JSON.stringify(candles, null, 2));
|
|
3440
3444
|
process.exit(0);
|
|
3441
3445
|
};
|
|
3442
|
-
main$
|
|
3446
|
+
main$5();
|
|
3443
3447
|
|
|
3444
|
-
const main$
|
|
3448
|
+
const main$4 = async () => {
|
|
3445
3449
|
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)))) {
|
|
3446
3450
|
return;
|
|
3447
3451
|
}
|
|
@@ -3535,16 +3539,16 @@ const main$3 = async () => {
|
|
|
3535
3539
|
}
|
|
3536
3540
|
process.exit(0);
|
|
3537
3541
|
};
|
|
3538
|
-
main$
|
|
3542
|
+
main$4();
|
|
3539
3543
|
|
|
3540
|
-
const __filename$
|
|
3541
|
-
const __dirname$
|
|
3544
|
+
const __filename$2 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
3545
|
+
const __dirname$2 = path.dirname(__filename$2);
|
|
3542
3546
|
const MUSTACHE_EXT = ".mustache";
|
|
3543
3547
|
const MUSTACHE_RENAME = {
|
|
3544
3548
|
"gitignore": ".gitignore",
|
|
3545
3549
|
"package": "package.json",
|
|
3546
3550
|
};
|
|
3547
|
-
async function isDirEmpty(dirPath) {
|
|
3551
|
+
async function isDirEmpty$1(dirPath) {
|
|
3548
3552
|
try {
|
|
3549
3553
|
const files = await fs$1.readdir(dirPath);
|
|
3550
3554
|
return files.length === 0;
|
|
@@ -3556,13 +3560,13 @@ async function isDirEmpty(dirPath) {
|
|
|
3556
3560
|
throw error;
|
|
3557
3561
|
}
|
|
3558
3562
|
}
|
|
3559
|
-
async function copyDir(srcDir, destDir, data) {
|
|
3563
|
+
async function copyDir$1(srcDir, destDir, data) {
|
|
3560
3564
|
await fs$1.mkdir(destDir, { recursive: true });
|
|
3561
3565
|
const entries = await fs$1.readdir(srcDir, { withFileTypes: true });
|
|
3562
3566
|
for (const entry of entries) {
|
|
3563
3567
|
const srcPath = path.join(srcDir, entry.name);
|
|
3564
3568
|
if (entry.isDirectory()) {
|
|
3565
|
-
await copyDir(srcPath, path.join(destDir, entry.name), data);
|
|
3569
|
+
await copyDir$1(srcPath, path.join(destDir, entry.name), data);
|
|
3566
3570
|
continue;
|
|
3567
3571
|
}
|
|
3568
3572
|
if (entry.name === ".gitkeep") {
|
|
@@ -3598,7 +3602,7 @@ function runScript(scriptPath, cwd) {
|
|
|
3598
3602
|
child.on("error", reject);
|
|
3599
3603
|
});
|
|
3600
3604
|
}
|
|
3601
|
-
function runNpmInstall(cwd) {
|
|
3605
|
+
function runNpmInstall$1(cwd) {
|
|
3602
3606
|
return new Promise((resolve, reject) => {
|
|
3603
3607
|
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3604
3608
|
const child = child_process.spawn(npm, ["install"], { cwd, stdio: "inherit", shell: true });
|
|
@@ -3612,7 +3616,7 @@ function runNpmInstall(cwd) {
|
|
|
3612
3616
|
child.on("error", reject);
|
|
3613
3617
|
});
|
|
3614
3618
|
}
|
|
3615
|
-
const main$
|
|
3619
|
+
const main$3 = async () => {
|
|
3616
3620
|
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)))) {
|
|
3617
3621
|
return;
|
|
3618
3622
|
}
|
|
@@ -3622,21 +3626,95 @@ const main$2 = async () => {
|
|
|
3622
3626
|
}
|
|
3623
3627
|
const projectName = values.output || "backtest-kit-project";
|
|
3624
3628
|
const projectPath = path.join(process.cwd(), projectName);
|
|
3625
|
-
const templatePath = path.join(__dirname$
|
|
3626
|
-
const isEmpty = await isDirEmpty(projectPath);
|
|
3629
|
+
const templatePath = path.join(__dirname$2, "../template/project");
|
|
3630
|
+
const isEmpty = await isDirEmpty$1(projectPath);
|
|
3627
3631
|
if (!isEmpty) {
|
|
3628
3632
|
console.error(`Directory "${projectName}" already exists and is not empty.`);
|
|
3629
3633
|
process.exit(1);
|
|
3630
3634
|
}
|
|
3631
3635
|
console.log(`Creating project in ${projectPath}`);
|
|
3632
|
-
await copyDir(templatePath, projectPath, { PROJECT_NAME: projectName });
|
|
3636
|
+
await copyDir$1(templatePath, projectPath, { PROJECT_NAME: projectName });
|
|
3633
3637
|
console.log(`Fetching docs...`);
|
|
3634
3638
|
await runScript(path.join(projectPath, "scripts/fetch_docs.mjs"), projectPath);
|
|
3635
3639
|
console.log(`Installing dependencies...`);
|
|
3636
|
-
await runNpmInstall(projectPath);
|
|
3640
|
+
await runNpmInstall$1(projectPath);
|
|
3637
3641
|
console.log(`Done! Project created at ${projectPath}`);
|
|
3638
3642
|
process.exit(0);
|
|
3639
3643
|
};
|
|
3644
|
+
main$3();
|
|
3645
|
+
|
|
3646
|
+
const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
3647
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
3648
|
+
async function isDirEmpty(dirPath) {
|
|
3649
|
+
try {
|
|
3650
|
+
const files = await fs$1.readdir(dirPath);
|
|
3651
|
+
return files.length === 0;
|
|
3652
|
+
}
|
|
3653
|
+
catch (error) {
|
|
3654
|
+
if (error.code === "ENOENT") {
|
|
3655
|
+
return true;
|
|
3656
|
+
}
|
|
3657
|
+
throw error;
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
async function copyDir(srcDir, destDir) {
|
|
3661
|
+
await fs$1.mkdir(destDir, { recursive: true });
|
|
3662
|
+
const entries = await fs$1.readdir(srcDir, { withFileTypes: true });
|
|
3663
|
+
for (const entry of entries) {
|
|
3664
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
3665
|
+
if (entry.isDirectory()) {
|
|
3666
|
+
await copyDir(srcPath, path.join(destDir, entry.name));
|
|
3667
|
+
continue;
|
|
3668
|
+
}
|
|
3669
|
+
if (entry.name === ".gitkeep") {
|
|
3670
|
+
continue;
|
|
3671
|
+
}
|
|
3672
|
+
const destPath = path.join(destDir, entry.name);
|
|
3673
|
+
await fs$1.copyFile(srcPath, destPath);
|
|
3674
|
+
console.log(` -> ${destPath}`);
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
function runNpmInstall(cwd) {
|
|
3678
|
+
return new Promise((resolve, reject) => {
|
|
3679
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3680
|
+
const child = child_process.spawn(npm, ["install"], { cwd, stdio: "inherit", shell: true });
|
|
3681
|
+
child.on("close", (code) => {
|
|
3682
|
+
if (code !== 0) {
|
|
3683
|
+
reject(new Error(`npm install exited with code ${code}`));
|
|
3684
|
+
return;
|
|
3685
|
+
}
|
|
3686
|
+
resolve();
|
|
3687
|
+
});
|
|
3688
|
+
child.on("error", reject);
|
|
3689
|
+
});
|
|
3690
|
+
}
|
|
3691
|
+
const main$2 = async () => {
|
|
3692
|
+
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)))) {
|
|
3693
|
+
return;
|
|
3694
|
+
}
|
|
3695
|
+
const { values } = getArgs();
|
|
3696
|
+
if (!values.docker) {
|
|
3697
|
+
return;
|
|
3698
|
+
}
|
|
3699
|
+
const projectName = values.output || "backtest-kit-docker";
|
|
3700
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
3701
|
+
const templatePath = path.join(__dirname$1, "../docker");
|
|
3702
|
+
const isEmpty = await isDirEmpty(projectPath);
|
|
3703
|
+
if (!isEmpty) {
|
|
3704
|
+
console.error(`Directory "${projectName}" already exists and is not empty.`);
|
|
3705
|
+
process.exit(1);
|
|
3706
|
+
}
|
|
3707
|
+
console.log(`Creating Docker workspace in ${projectPath}`);
|
|
3708
|
+
await copyDir(templatePath, projectPath);
|
|
3709
|
+
console.log(`Installing dependencies...`);
|
|
3710
|
+
await runNpmInstall(projectPath);
|
|
3711
|
+
console.log(`Done! Docker workspace created at ${projectPath}`);
|
|
3712
|
+
console.log(`Next steps:`);
|
|
3713
|
+
console.log(` cd ${projectName}`);
|
|
3714
|
+
console.log(` docker compose up -d`);
|
|
3715
|
+
console.log(` docker compose logs -f`);
|
|
3716
|
+
process.exit(0);
|
|
3717
|
+
};
|
|
3640
3718
|
main$2();
|
|
3641
3719
|
|
|
3642
3720
|
const ENTRY_PATH = "./node_modules/@backtest-kit/cli/build/index.mjs";
|
|
@@ -3657,6 +3735,7 @@ Modes:
|
|
|
3657
3735
|
--brokerdebug Fire a single broker commit against the live broker adapter
|
|
3658
3736
|
--flush <entry...> Delete report/log/markdown/agent folders from strategy dump dir
|
|
3659
3737
|
--init Scaffold a new project in the current directory
|
|
3738
|
+
--docker Scaffold a Docker workspace for running strategies in a container
|
|
3660
3739
|
--help Print this help message
|
|
3661
3740
|
|
|
3662
3741
|
Backtest flags:
|
|
@@ -3766,6 +3845,14 @@ Init flags (--init):
|
|
|
3766
3845
|
|
|
3767
3846
|
Scaffolds a project and runs scripts/fetch_docs.mjs to download library docs.
|
|
3768
3847
|
|
|
3848
|
+
Docker flags (--docker):
|
|
3849
|
+
|
|
3850
|
+
--output <string> Target directory name (default: backtest-kit-docker)
|
|
3851
|
+
|
|
3852
|
+
Scaffolds a Docker workspace: docker-compose.yaml, .env.example, package.json,
|
|
3853
|
+
tsconfig.json, and a sample strategy under content/. Run npm install then
|
|
3854
|
+
docker compose up to start the container.
|
|
3855
|
+
|
|
3769
3856
|
Module hooks (loaded automatically by each mode):
|
|
3770
3857
|
|
|
3771
3858
|
modules/backtest.module --backtest Broker adapter for backtest
|
|
@@ -3807,6 +3894,7 @@ Examples:
|
|
|
3807
3894
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts
|
|
3808
3895
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts ./content/feb_2026.strategy/feb_2026.test.ts
|
|
3809
3896
|
node ${ENTRY_PATH} --init --output my-trading-bot
|
|
3897
|
+
node ${ENTRY_PATH} --docker --output my-docker-workspace
|
|
3810
3898
|
`.trimStart();
|
|
3811
3899
|
const main$1 = async () => {
|
|
3812
3900
|
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)))) {
|
|
@@ -3816,7 +3904,7 @@ const main$1 = async () => {
|
|
|
3816
3904
|
if (!values.help) {
|
|
3817
3905
|
return;
|
|
3818
3906
|
}
|
|
3819
|
-
process.stdout.write(`@backtest-kit/cli ${"8.
|
|
3907
|
+
process.stdout.write(`@backtest-kit/cli ${"8.3.0"}\n\n`);
|
|
3820
3908
|
process.stdout.write(HELP_TEXT);
|
|
3821
3909
|
process.exit(0);
|
|
3822
3910
|
};
|
|
@@ -3830,7 +3918,7 @@ const main = async () => {
|
|
|
3830
3918
|
if (!values.version) {
|
|
3831
3919
|
return;
|
|
3832
3920
|
}
|
|
3833
|
-
process.stdout.write(`@backtest-kit/cli ${"8.
|
|
3921
|
+
process.stdout.write(`@backtest-kit/cli ${"8.3.0"}\n`);
|
|
3834
3922
|
process.exit(0);
|
|
3835
3923
|
};
|
|
3836
3924
|
main();
|
package/build/index.mjs
CHANGED
|
@@ -241,16 +241,16 @@ const TYPES = {
|
|
|
241
241
|
|
|
242
242
|
const entrySubject = new BehaviorSubject();
|
|
243
243
|
|
|
244
|
-
const __filename$
|
|
245
|
-
const __dirname$
|
|
244
|
+
const __filename$2 = fileURLToPath(import.meta.url);
|
|
245
|
+
const __dirname$2 = path.dirname(__filename$2);
|
|
246
246
|
let _is_launched = false;
|
|
247
247
|
class ResolveService {
|
|
248
248
|
constructor() {
|
|
249
249
|
this.loggerService = inject(TYPES.loggerService);
|
|
250
250
|
this.loaderService = inject(TYPES.loaderService);
|
|
251
|
-
this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$
|
|
252
|
-
this.DEFAULT_MODULES_DIR = path.resolve(__dirname$
|
|
253
|
-
this.DEFAULT_CONFIG_DIR = path.resolve(__dirname$
|
|
251
|
+
this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$2, '..', 'template');
|
|
252
|
+
this.DEFAULT_MODULES_DIR = path.resolve(__dirname$2, '..', 'modules');
|
|
253
|
+
this.DEFAULT_CONFIG_DIR = path.resolve(__dirname$2, '..', 'config');
|
|
254
254
|
this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
|
|
255
255
|
this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
|
|
256
256
|
this.OVERRIDE_CONFIG_DIR = path.resolve(process.cwd(), 'config');
|
|
@@ -573,6 +573,10 @@ const getArgs = singleshot(() => {
|
|
|
573
573
|
type: "boolean",
|
|
574
574
|
default: false,
|
|
575
575
|
},
|
|
576
|
+
docker: {
|
|
577
|
+
type: "boolean",
|
|
578
|
+
default: false,
|
|
579
|
+
},
|
|
576
580
|
help: {
|
|
577
581
|
type: "boolean",
|
|
578
582
|
default: false,
|
|
@@ -2978,14 +2982,14 @@ const cli = {
|
|
|
2978
2982
|
};
|
|
2979
2983
|
init();
|
|
2980
2984
|
|
|
2981
|
-
const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "pnldebug", "brokerdebug", "flush", "init", "help", "version"];
|
|
2985
|
+
const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "pnldebug", "brokerdebug", "flush", "init", "docker", "help", "version"];
|
|
2982
2986
|
const ENTRY_PATH$1 = "./node_modules/@backtest-kit/cli/build/index.mjs";
|
|
2983
2987
|
const HELP_TEXT$1 = `
|
|
2984
2988
|
Example:
|
|
2985
2989
|
|
|
2986
2990
|
node ${ENTRY_PATH$1} --help
|
|
2987
2991
|
`.trimStart();
|
|
2988
|
-
const main$
|
|
2992
|
+
const main$f = async () => {
|
|
2989
2993
|
if (!getEntry(import.meta.url)) {
|
|
2990
2994
|
return;
|
|
2991
2995
|
}
|
|
@@ -2993,14 +2997,14 @@ const main$e = async () => {
|
|
|
2993
2997
|
if (MODES.some((mode) => values[mode])) {
|
|
2994
2998
|
return;
|
|
2995
2999
|
}
|
|
2996
|
-
process.stdout.write(`@backtest-kit/cli ${"8.
|
|
3000
|
+
process.stdout.write(`@backtest-kit/cli ${"8.3.0"}\n`);
|
|
2997
3001
|
process.stdout.write("\n");
|
|
2998
3002
|
process.stdout.write(`Run with --help to see available commands.\n`);
|
|
2999
3003
|
process.stdout.write("\n");
|
|
3000
3004
|
process.stdout.write(HELP_TEXT$1);
|
|
3001
3005
|
process.exit(0);
|
|
3002
3006
|
};
|
|
3003
|
-
main$
|
|
3007
|
+
main$f();
|
|
3004
3008
|
|
|
3005
3009
|
const notifyShutdown = singleshot(async () => {
|
|
3006
3010
|
console.log("Graceful shutdown initiated. Press Ctrl+C again to force quit.");
|
|
@@ -3016,7 +3020,7 @@ const flush = async (entryPoint) => {
|
|
|
3016
3020
|
console.log(`Removed: ${target}`);
|
|
3017
3021
|
}
|
|
3018
3022
|
};
|
|
3019
|
-
const main$
|
|
3023
|
+
const main$e = async () => {
|
|
3020
3024
|
if (!getEntry(import.meta.url)) {
|
|
3021
3025
|
return;
|
|
3022
3026
|
}
|
|
@@ -3033,7 +3037,7 @@ const main$d = async () => {
|
|
|
3033
3037
|
}
|
|
3034
3038
|
process.exit(0);
|
|
3035
3039
|
};
|
|
3036
|
-
main$
|
|
3040
|
+
main$e();
|
|
3037
3041
|
|
|
3038
3042
|
const BEFORE_EXIT_FN$5 = singleshot(async () => {
|
|
3039
3043
|
process.off("SIGINT", BEFORE_EXIT_FN$5);
|
|
@@ -3055,7 +3059,7 @@ const BEFORE_EXIT_FN$5 = singleshot(async () => {
|
|
|
3055
3059
|
const listenGracefulShutdown$5 = singleshot(() => {
|
|
3056
3060
|
process.on("SIGINT", BEFORE_EXIT_FN$5);
|
|
3057
3061
|
});
|
|
3058
|
-
const main$
|
|
3062
|
+
const main$d = async () => {
|
|
3059
3063
|
if (!getEntry(import.meta.url)) {
|
|
3060
3064
|
return;
|
|
3061
3065
|
}
|
|
@@ -3070,7 +3074,7 @@ const main$c = async () => {
|
|
|
3070
3074
|
await cli.backtestMainService.connect();
|
|
3071
3075
|
listenGracefulShutdown$5();
|
|
3072
3076
|
};
|
|
3073
|
-
main$
|
|
3077
|
+
main$d();
|
|
3074
3078
|
|
|
3075
3079
|
const BEFORE_EXIT_FN$4 = singleshot(async () => {
|
|
3076
3080
|
process.off("SIGINT", BEFORE_EXIT_FN$4);
|
|
@@ -3088,7 +3092,7 @@ const BEFORE_EXIT_FN$4 = singleshot(async () => {
|
|
|
3088
3092
|
const listenGracefulShutdown$4 = singleshot(() => {
|
|
3089
3093
|
process.on("SIGINT", BEFORE_EXIT_FN$4);
|
|
3090
3094
|
});
|
|
3091
|
-
const main$
|
|
3095
|
+
const main$c = async () => {
|
|
3092
3096
|
if (!getEntry(import.meta.url)) {
|
|
3093
3097
|
return;
|
|
3094
3098
|
}
|
|
@@ -3104,7 +3108,7 @@ const main$b = async () => {
|
|
|
3104
3108
|
listenGracefulShutdown$4();
|
|
3105
3109
|
await cli.walkerMainService.connect();
|
|
3106
3110
|
};
|
|
3107
|
-
main$
|
|
3111
|
+
main$c();
|
|
3108
3112
|
|
|
3109
3113
|
const BEFORE_EXIT_FN$3 = singleshot(async () => {
|
|
3110
3114
|
process.off("SIGINT", BEFORE_EXIT_FN$3);
|
|
@@ -3125,7 +3129,7 @@ const BEFORE_EXIT_FN$3 = singleshot(async () => {
|
|
|
3125
3129
|
const listenGracefulShutdown$3 = singleshot(() => {
|
|
3126
3130
|
process.on("SIGINT", BEFORE_EXIT_FN$3);
|
|
3127
3131
|
});
|
|
3128
|
-
const main$
|
|
3132
|
+
const main$b = async () => {
|
|
3129
3133
|
if (!getEntry(import.meta.url)) {
|
|
3130
3134
|
return;
|
|
3131
3135
|
}
|
|
@@ -3136,7 +3140,7 @@ const main$a = async () => {
|
|
|
3136
3140
|
cli.paperMainService.connect();
|
|
3137
3141
|
listenGracefulShutdown$3();
|
|
3138
3142
|
};
|
|
3139
|
-
main$
|
|
3143
|
+
main$b();
|
|
3140
3144
|
|
|
3141
3145
|
const BEFORE_EXIT_FN$2 = singleshot(async () => {
|
|
3142
3146
|
process.off("SIGINT", BEFORE_EXIT_FN$2);
|
|
@@ -3157,7 +3161,7 @@ const BEFORE_EXIT_FN$2 = singleshot(async () => {
|
|
|
3157
3161
|
const listenGracefulShutdown$2 = singleshot(() => {
|
|
3158
3162
|
process.on("SIGINT", BEFORE_EXIT_FN$2);
|
|
3159
3163
|
});
|
|
3160
|
-
const main$
|
|
3164
|
+
const main$a = async () => {
|
|
3161
3165
|
if (!getEntry(import.meta.url)) {
|
|
3162
3166
|
return;
|
|
3163
3167
|
}
|
|
@@ -3168,7 +3172,7 @@ const main$9 = async () => {
|
|
|
3168
3172
|
await cli.liveMainService.connect();
|
|
3169
3173
|
listenGracefulShutdown$2();
|
|
3170
3174
|
};
|
|
3171
|
-
main$
|
|
3175
|
+
main$a();
|
|
3172
3176
|
|
|
3173
3177
|
const BEFORE_EXIT_FN$1 = singleshot(async () => {
|
|
3174
3178
|
process.off("SIGINT", BEFORE_EXIT_FN$1);
|
|
@@ -3178,7 +3182,7 @@ const BEFORE_EXIT_FN$1 = singleshot(async () => {
|
|
|
3178
3182
|
const listenGracefulShutdown$1 = singleshot(() => {
|
|
3179
3183
|
process.on("SIGINT", BEFORE_EXIT_FN$1);
|
|
3180
3184
|
});
|
|
3181
|
-
const main$
|
|
3185
|
+
const main$9 = async () => {
|
|
3182
3186
|
if (!getEntry(import.meta.url)) {
|
|
3183
3187
|
return;
|
|
3184
3188
|
}
|
|
@@ -3188,7 +3192,7 @@ const main$8 = async () => {
|
|
|
3188
3192
|
}
|
|
3189
3193
|
listenGracefulShutdown$1();
|
|
3190
3194
|
};
|
|
3191
|
-
main$
|
|
3195
|
+
main$9();
|
|
3192
3196
|
|
|
3193
3197
|
const BEFORE_EXIT_FN = singleshot(async () => {
|
|
3194
3198
|
process.off("SIGINT", BEFORE_EXIT_FN);
|
|
@@ -3198,7 +3202,7 @@ const BEFORE_EXIT_FN = singleshot(async () => {
|
|
|
3198
3202
|
const listenGracefulShutdown = singleshot(() => {
|
|
3199
3203
|
process.on("SIGINT", BEFORE_EXIT_FN);
|
|
3200
3204
|
});
|
|
3201
|
-
const main$
|
|
3205
|
+
const main$8 = async () => {
|
|
3202
3206
|
if (!getEntry(import.meta.url)) {
|
|
3203
3207
|
return;
|
|
3204
3208
|
}
|
|
@@ -3208,7 +3212,7 @@ const main$7 = async () => {
|
|
|
3208
3212
|
}
|
|
3209
3213
|
listenGracefulShutdown();
|
|
3210
3214
|
};
|
|
3211
|
-
main$
|
|
3215
|
+
main$8();
|
|
3212
3216
|
|
|
3213
3217
|
const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
3214
3218
|
const keys = Object.keys(schema);
|
|
@@ -3230,7 +3234,7 @@ const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
|
3230
3234
|
}
|
|
3231
3235
|
return rows;
|
|
3232
3236
|
};
|
|
3233
|
-
const main$
|
|
3237
|
+
const main$7 = async () => {
|
|
3234
3238
|
if (!getEntry(import.meta.url)) {
|
|
3235
3239
|
return;
|
|
3236
3240
|
}
|
|
@@ -3310,9 +3314,9 @@ const main$6 = async () => {
|
|
|
3310
3314
|
console.log(await toMarkdown(signalId, plots, signalSchema));
|
|
3311
3315
|
process.exit(0);
|
|
3312
3316
|
};
|
|
3313
|
-
main$
|
|
3317
|
+
main$7();
|
|
3314
3318
|
|
|
3315
|
-
const main$
|
|
3319
|
+
const main$6 = async () => {
|
|
3316
3320
|
if (!getEntry(import.meta.url)) {
|
|
3317
3321
|
return;
|
|
3318
3322
|
}
|
|
@@ -3347,9 +3351,9 @@ const main$5 = async () => {
|
|
|
3347
3351
|
};
|
|
3348
3352
|
process.on("SIGINT", beforeExit);
|
|
3349
3353
|
};
|
|
3350
|
-
main$
|
|
3354
|
+
main$6();
|
|
3351
3355
|
|
|
3352
|
-
const main$
|
|
3356
|
+
const main$5 = async () => {
|
|
3353
3357
|
if (!getEntry(import.meta.url)) {
|
|
3354
3358
|
return;
|
|
3355
3359
|
}
|
|
@@ -3410,9 +3414,9 @@ const main$4 = async () => {
|
|
|
3410
3414
|
console.log(JSON.stringify(candles, null, 2));
|
|
3411
3415
|
process.exit(0);
|
|
3412
3416
|
};
|
|
3413
|
-
main$
|
|
3417
|
+
main$5();
|
|
3414
3418
|
|
|
3415
|
-
const main$
|
|
3419
|
+
const main$4 = async () => {
|
|
3416
3420
|
if (!getEntry(import.meta.url)) {
|
|
3417
3421
|
return;
|
|
3418
3422
|
}
|
|
@@ -3506,16 +3510,16 @@ const main$3 = async () => {
|
|
|
3506
3510
|
}
|
|
3507
3511
|
process.exit(0);
|
|
3508
3512
|
};
|
|
3509
|
-
main$
|
|
3513
|
+
main$4();
|
|
3510
3514
|
|
|
3511
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
3512
|
-
const __dirname = dirname(__filename);
|
|
3515
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
3516
|
+
const __dirname$1 = dirname(__filename$1);
|
|
3513
3517
|
const MUSTACHE_EXT = ".mustache";
|
|
3514
3518
|
const MUSTACHE_RENAME = {
|
|
3515
3519
|
"gitignore": ".gitignore",
|
|
3516
3520
|
"package": "package.json",
|
|
3517
3521
|
};
|
|
3518
|
-
async function isDirEmpty(dirPath) {
|
|
3522
|
+
async function isDirEmpty$1(dirPath) {
|
|
3519
3523
|
try {
|
|
3520
3524
|
const files = await readdir(dirPath);
|
|
3521
3525
|
return files.length === 0;
|
|
@@ -3527,13 +3531,13 @@ async function isDirEmpty(dirPath) {
|
|
|
3527
3531
|
throw error;
|
|
3528
3532
|
}
|
|
3529
3533
|
}
|
|
3530
|
-
async function copyDir(srcDir, destDir, data) {
|
|
3534
|
+
async function copyDir$1(srcDir, destDir, data) {
|
|
3531
3535
|
await mkdir(destDir, { recursive: true });
|
|
3532
3536
|
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
3533
3537
|
for (const entry of entries) {
|
|
3534
3538
|
const srcPath = join(srcDir, entry.name);
|
|
3535
3539
|
if (entry.isDirectory()) {
|
|
3536
|
-
await copyDir(srcPath, join(destDir, entry.name), data);
|
|
3540
|
+
await copyDir$1(srcPath, join(destDir, entry.name), data);
|
|
3537
3541
|
continue;
|
|
3538
3542
|
}
|
|
3539
3543
|
if (entry.name === ".gitkeep") {
|
|
@@ -3569,7 +3573,7 @@ function runScript(scriptPath, cwd) {
|
|
|
3569
3573
|
child.on("error", reject);
|
|
3570
3574
|
});
|
|
3571
3575
|
}
|
|
3572
|
-
function runNpmInstall(cwd) {
|
|
3576
|
+
function runNpmInstall$1(cwd) {
|
|
3573
3577
|
return new Promise((resolve, reject) => {
|
|
3574
3578
|
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3575
3579
|
const child = spawn(npm, ["install"], { cwd, stdio: "inherit", shell: true });
|
|
@@ -3583,7 +3587,7 @@ function runNpmInstall(cwd) {
|
|
|
3583
3587
|
child.on("error", reject);
|
|
3584
3588
|
});
|
|
3585
3589
|
}
|
|
3586
|
-
const main$
|
|
3590
|
+
const main$3 = async () => {
|
|
3587
3591
|
if (!getEntry(import.meta.url)) {
|
|
3588
3592
|
return;
|
|
3589
3593
|
}
|
|
@@ -3593,21 +3597,95 @@ const main$2 = async () => {
|
|
|
3593
3597
|
}
|
|
3594
3598
|
const projectName = values.output || "backtest-kit-project";
|
|
3595
3599
|
const projectPath = join(process.cwd(), projectName);
|
|
3596
|
-
const templatePath = join(__dirname, "../template/project");
|
|
3597
|
-
const isEmpty = await isDirEmpty(projectPath);
|
|
3600
|
+
const templatePath = join(__dirname$1, "../template/project");
|
|
3601
|
+
const isEmpty = await isDirEmpty$1(projectPath);
|
|
3598
3602
|
if (!isEmpty) {
|
|
3599
3603
|
console.error(`Directory "${projectName}" already exists and is not empty.`);
|
|
3600
3604
|
process.exit(1);
|
|
3601
3605
|
}
|
|
3602
3606
|
console.log(`Creating project in ${projectPath}`);
|
|
3603
|
-
await copyDir(templatePath, projectPath, { PROJECT_NAME: projectName });
|
|
3607
|
+
await copyDir$1(templatePath, projectPath, { PROJECT_NAME: projectName });
|
|
3604
3608
|
console.log(`Fetching docs...`);
|
|
3605
3609
|
await runScript(join(projectPath, "scripts/fetch_docs.mjs"), projectPath);
|
|
3606
3610
|
console.log(`Installing dependencies...`);
|
|
3607
|
-
await runNpmInstall(projectPath);
|
|
3611
|
+
await runNpmInstall$1(projectPath);
|
|
3608
3612
|
console.log(`Done! Project created at ${projectPath}`);
|
|
3609
3613
|
process.exit(0);
|
|
3610
3614
|
};
|
|
3615
|
+
main$3();
|
|
3616
|
+
|
|
3617
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
3618
|
+
const __dirname = dirname(__filename);
|
|
3619
|
+
async function isDirEmpty(dirPath) {
|
|
3620
|
+
try {
|
|
3621
|
+
const files = await readdir(dirPath);
|
|
3622
|
+
return files.length === 0;
|
|
3623
|
+
}
|
|
3624
|
+
catch (error) {
|
|
3625
|
+
if (error.code === "ENOENT") {
|
|
3626
|
+
return true;
|
|
3627
|
+
}
|
|
3628
|
+
throw error;
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
async function copyDir(srcDir, destDir) {
|
|
3632
|
+
await mkdir(destDir, { recursive: true });
|
|
3633
|
+
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
3634
|
+
for (const entry of entries) {
|
|
3635
|
+
const srcPath = join(srcDir, entry.name);
|
|
3636
|
+
if (entry.isDirectory()) {
|
|
3637
|
+
await copyDir(srcPath, join(destDir, entry.name));
|
|
3638
|
+
continue;
|
|
3639
|
+
}
|
|
3640
|
+
if (entry.name === ".gitkeep") {
|
|
3641
|
+
continue;
|
|
3642
|
+
}
|
|
3643
|
+
const destPath = join(destDir, entry.name);
|
|
3644
|
+
await copyFile(srcPath, destPath);
|
|
3645
|
+
console.log(` -> ${destPath}`);
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
function runNpmInstall(cwd) {
|
|
3649
|
+
return new Promise((resolve, reject) => {
|
|
3650
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3651
|
+
const child = spawn(npm, ["install"], { cwd, stdio: "inherit", shell: true });
|
|
3652
|
+
child.on("close", (code) => {
|
|
3653
|
+
if (code !== 0) {
|
|
3654
|
+
reject(new Error(`npm install exited with code ${code}`));
|
|
3655
|
+
return;
|
|
3656
|
+
}
|
|
3657
|
+
resolve();
|
|
3658
|
+
});
|
|
3659
|
+
child.on("error", reject);
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
const main$2 = async () => {
|
|
3663
|
+
if (!getEntry(import.meta.url)) {
|
|
3664
|
+
return;
|
|
3665
|
+
}
|
|
3666
|
+
const { values } = getArgs();
|
|
3667
|
+
if (!values.docker) {
|
|
3668
|
+
return;
|
|
3669
|
+
}
|
|
3670
|
+
const projectName = values.output || "backtest-kit-docker";
|
|
3671
|
+
const projectPath = join(process.cwd(), projectName);
|
|
3672
|
+
const templatePath = join(__dirname, "../docker");
|
|
3673
|
+
const isEmpty = await isDirEmpty(projectPath);
|
|
3674
|
+
if (!isEmpty) {
|
|
3675
|
+
console.error(`Directory "${projectName}" already exists and is not empty.`);
|
|
3676
|
+
process.exit(1);
|
|
3677
|
+
}
|
|
3678
|
+
console.log(`Creating Docker workspace in ${projectPath}`);
|
|
3679
|
+
await copyDir(templatePath, projectPath);
|
|
3680
|
+
console.log(`Installing dependencies...`);
|
|
3681
|
+
await runNpmInstall(projectPath);
|
|
3682
|
+
console.log(`Done! Docker workspace created at ${projectPath}`);
|
|
3683
|
+
console.log(`Next steps:`);
|
|
3684
|
+
console.log(` cd ${projectName}`);
|
|
3685
|
+
console.log(` docker compose up -d`);
|
|
3686
|
+
console.log(` docker compose logs -f`);
|
|
3687
|
+
process.exit(0);
|
|
3688
|
+
};
|
|
3611
3689
|
main$2();
|
|
3612
3690
|
|
|
3613
3691
|
const ENTRY_PATH = "./node_modules/@backtest-kit/cli/build/index.mjs";
|
|
@@ -3628,6 +3706,7 @@ Modes:
|
|
|
3628
3706
|
--brokerdebug Fire a single broker commit against the live broker adapter
|
|
3629
3707
|
--flush <entry...> Delete report/log/markdown/agent folders from strategy dump dir
|
|
3630
3708
|
--init Scaffold a new project in the current directory
|
|
3709
|
+
--docker Scaffold a Docker workspace for running strategies in a container
|
|
3631
3710
|
--help Print this help message
|
|
3632
3711
|
|
|
3633
3712
|
Backtest flags:
|
|
@@ -3737,6 +3816,14 @@ Init flags (--init):
|
|
|
3737
3816
|
|
|
3738
3817
|
Scaffolds a project and runs scripts/fetch_docs.mjs to download library docs.
|
|
3739
3818
|
|
|
3819
|
+
Docker flags (--docker):
|
|
3820
|
+
|
|
3821
|
+
--output <string> Target directory name (default: backtest-kit-docker)
|
|
3822
|
+
|
|
3823
|
+
Scaffolds a Docker workspace: docker-compose.yaml, .env.example, package.json,
|
|
3824
|
+
tsconfig.json, and a sample strategy under content/. Run npm install then
|
|
3825
|
+
docker compose up to start the container.
|
|
3826
|
+
|
|
3740
3827
|
Module hooks (loaded automatically by each mode):
|
|
3741
3828
|
|
|
3742
3829
|
modules/backtest.module --backtest Broker adapter for backtest
|
|
@@ -3778,6 +3865,7 @@ Examples:
|
|
|
3778
3865
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts
|
|
3779
3866
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts ./content/feb_2026.strategy/feb_2026.test.ts
|
|
3780
3867
|
node ${ENTRY_PATH} --init --output my-trading-bot
|
|
3868
|
+
node ${ENTRY_PATH} --docker --output my-docker-workspace
|
|
3781
3869
|
`.trimStart();
|
|
3782
3870
|
const main$1 = async () => {
|
|
3783
3871
|
if (!getEntry(import.meta.url)) {
|
|
@@ -3787,7 +3875,7 @@ const main$1 = async () => {
|
|
|
3787
3875
|
if (!values.help) {
|
|
3788
3876
|
return;
|
|
3789
3877
|
}
|
|
3790
|
-
process.stdout.write(`@backtest-kit/cli ${"8.
|
|
3878
|
+
process.stdout.write(`@backtest-kit/cli ${"8.3.0"}\n\n`);
|
|
3791
3879
|
process.stdout.write(HELP_TEXT);
|
|
3792
3880
|
process.exit(0);
|
|
3793
3881
|
};
|
|
@@ -3801,7 +3889,7 @@ const main = async () => {
|
|
|
3801
3889
|
if (!values.version) {
|
|
3802
3890
|
return;
|
|
3803
3891
|
}
|
|
3804
|
-
process.stdout.write(`@backtest-kit/cli ${"8.
|
|
3892
|
+
process.stdout.write(`@backtest-kit/cli ${"8.3.0"}\n`);
|
|
3805
3893
|
process.exit(0);
|
|
3806
3894
|
};
|
|
3807
3895
|
main();
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { addExchangeSchema, addFrameSchema, roundTicks } from "backtest-kit";
|
|
2
|
+
import { singleshot } from "functools-kit";
|
|
3
|
+
import ccxt from "ccxt";
|
|
4
|
+
|
|
5
|
+
const getExchange = singleshot(async () => {
|
|
6
|
+
const exchange = new ccxt.binance({
|
|
7
|
+
options: {
|
|
8
|
+
defaultType: "spot",
|
|
9
|
+
adjustForTimeDifference: true,
|
|
10
|
+
recvWindow: 60000,
|
|
11
|
+
},
|
|
12
|
+
enableRateLimit: true,
|
|
13
|
+
});
|
|
14
|
+
await exchange.loadMarkets();
|
|
15
|
+
return exchange;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
addExchangeSchema({
|
|
19
|
+
exchangeName: "ccxt-exchange",
|
|
20
|
+
getCandles: async (symbol, interval, since, limit) => {
|
|
21
|
+
const exchange = await getExchange();
|
|
22
|
+
const candles = await exchange.fetchOHLCV(
|
|
23
|
+
symbol,
|
|
24
|
+
interval,
|
|
25
|
+
since.getTime(),
|
|
26
|
+
limit,
|
|
27
|
+
);
|
|
28
|
+
return candles.map(([timestamp, open, high, low, close, volume]) => ({
|
|
29
|
+
timestamp,
|
|
30
|
+
open,
|
|
31
|
+
high,
|
|
32
|
+
low,
|
|
33
|
+
close,
|
|
34
|
+
volume,
|
|
35
|
+
}));
|
|
36
|
+
},
|
|
37
|
+
getOrderBook: async (symbol, depth, _from, _to, backtest) => {
|
|
38
|
+
if (backtest) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"Order book fetching is not supported in backtest mode for the default exchange schema. Please implement it according to your needs.",
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const exchange = await getExchange();
|
|
44
|
+
const bookData = await exchange.fetchOrderBook(symbol, depth);
|
|
45
|
+
return {
|
|
46
|
+
symbol,
|
|
47
|
+
asks: bookData.asks.map(([price, quantity]) => ({
|
|
48
|
+
price: String(price),
|
|
49
|
+
quantity: String(quantity),
|
|
50
|
+
})),
|
|
51
|
+
bids: bookData.bids.map(([price, quantity]) => ({
|
|
52
|
+
price: String(price),
|
|
53
|
+
quantity: String(quantity),
|
|
54
|
+
})),
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
formatPrice: async (symbol, price) => {
|
|
58
|
+
const exchange = await getExchange();
|
|
59
|
+
const market = exchange.market(symbol);
|
|
60
|
+
const tickSize = market.limits?.price?.min || market.precision?.price;
|
|
61
|
+
if (tickSize !== undefined) {
|
|
62
|
+
return roundTicks(price, tickSize);
|
|
63
|
+
}
|
|
64
|
+
return exchange.priceToPrecision(symbol, price);
|
|
65
|
+
},
|
|
66
|
+
formatQuantity: async (symbol, quantity) => {
|
|
67
|
+
const exchange = await getExchange();
|
|
68
|
+
const market = exchange.market(symbol);
|
|
69
|
+
const stepSize = market.limits?.amount?.min || market.precision?.amount;
|
|
70
|
+
if (stepSize !== undefined) {
|
|
71
|
+
return roundTicks(quantity, stepSize);
|
|
72
|
+
}
|
|
73
|
+
return exchange.amountToPrecision(symbol, quantity);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
addFrameSchema({
|
|
78
|
+
frameName: "feb_2026_frame",
|
|
79
|
+
interval: "1m",
|
|
80
|
+
startDate: new Date("2026-02-01T00:00:00Z"),
|
|
81
|
+
endDate: new Date("2026-02-28T23:59:59Z"),
|
|
82
|
+
note: "February 2026",
|
|
83
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
version: '3.8'
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
backtest:
|
|
5
|
+
image: tripolskypetr/backtest-kit
|
|
6
|
+
network_mode: host
|
|
7
|
+
extra_hosts:
|
|
8
|
+
- "host.docker.internal:host-gateway"
|
|
9
|
+
container_name: backtest
|
|
10
|
+
ports:
|
|
11
|
+
- "60050:60050"
|
|
12
|
+
restart: unless-stopped
|
|
13
|
+
volumes:
|
|
14
|
+
- ./:/workspace
|
|
15
|
+
working_dir: /workspace
|
|
16
|
+
command:
|
|
17
|
+
- --backtest
|
|
18
|
+
- --symbol
|
|
19
|
+
- BTCUSDT
|
|
20
|
+
- --strategy
|
|
21
|
+
- feb_2026_strategy
|
|
22
|
+
- --exchange
|
|
23
|
+
- ccxt-exchange
|
|
24
|
+
- ./content/feb_2026/feb_2026.strategy.ts
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "example",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node ./node_modules/@backtest-kit/cli/build/index.mjs",
|
|
8
|
+
"start:debug": "node --inspect-brk ./node_modules/@backtest-kit/cli/build/index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [],
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"type": "commonjs",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "25.6.0"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@backtest-kit/cli": "8.3.0",
|
|
19
|
+
"@backtest-kit/graph": "8.3.0",
|
|
20
|
+
"@backtest-kit/pinets": "8.3.0",
|
|
21
|
+
"@backtest-kit/signals": "8.3.0",
|
|
22
|
+
"@backtest-kit/ui": "8.3.0",
|
|
23
|
+
"@tavily/core": "0.7.2",
|
|
24
|
+
"@tensorflow/tfjs": "4.22.0",
|
|
25
|
+
"@tensorflow/tfjs-backend-wasm": "4.22.0",
|
|
26
|
+
"@tensorflow/tfjs-core": "4.22.0",
|
|
27
|
+
"agent-swarm-kit": "2.6.0",
|
|
28
|
+
"backtest-kit": "8.3.0",
|
|
29
|
+
"dayjs": "1.11.20",
|
|
30
|
+
"functools-kit": "2.3.0",
|
|
31
|
+
"garch": "1.2.3",
|
|
32
|
+
"get-moment-stamp": "1.1.2",
|
|
33
|
+
"jsonrepair": "3.12.0",
|
|
34
|
+
"ollama": "0.6.3",
|
|
35
|
+
"slugify": "1.6.9",
|
|
36
|
+
"volume-anomaly": "1.2.3"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"ignoreDeprecations": "6.0",
|
|
4
|
+
"lib": [
|
|
5
|
+
"esnext",
|
|
6
|
+
"dom"
|
|
7
|
+
],
|
|
8
|
+
"types": [
|
|
9
|
+
"node"
|
|
10
|
+
],
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"target": "ES2020",
|
|
13
|
+
"module": "ESNext",
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"strict": false,
|
|
17
|
+
"downlevelIteration": true,
|
|
18
|
+
"noImplicitAny": false,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUnusedLocals": false,
|
|
22
|
+
"noUnusedParameters": false,
|
|
23
|
+
"noPropertyAccessFromIndexSignature": false,
|
|
24
|
+
"paths": {
|
|
25
|
+
"logic": ["./logic/index.ts"],
|
|
26
|
+
"logic/*": ["./logic/*"],
|
|
27
|
+
"utils": ["./utils/index.ts"],
|
|
28
|
+
"utils/*": ["./utils/*"]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"include": [
|
|
32
|
+
"./logic",
|
|
33
|
+
"./content",
|
|
34
|
+
"./modules",
|
|
35
|
+
],
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtest-kit/cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.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",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"types.d.ts",
|
|
36
36
|
"template",
|
|
37
37
|
"config",
|
|
38
|
+
"docker",
|
|
38
39
|
"README.md"
|
|
39
40
|
],
|
|
40
41
|
"repository": {
|
|
@@ -62,11 +63,11 @@
|
|
|
62
63
|
"devDependencies": {
|
|
63
64
|
"@babel/plugin-transform-modules-umd": "7.27.1",
|
|
64
65
|
"@babel/standalone": "7.29.1",
|
|
65
|
-
"@backtest-kit/graph": "8.
|
|
66
|
-
"@backtest-kit/ollama": "8.
|
|
67
|
-
"@backtest-kit/pinets": "8.
|
|
68
|
-
"@backtest-kit/signals": "8.
|
|
69
|
-
"@backtest-kit/ui": "8.
|
|
66
|
+
"@backtest-kit/graph": "8.3.0",
|
|
67
|
+
"@backtest-kit/ollama": "8.3.0",
|
|
68
|
+
"@backtest-kit/pinets": "8.3.0",
|
|
69
|
+
"@backtest-kit/signals": "8.3.0",
|
|
70
|
+
"@backtest-kit/ui": "8.3.0",
|
|
70
71
|
"@rollup/plugin-replace": "6.0.3",
|
|
71
72
|
"@rollup/plugin-typescript": "11.1.6",
|
|
72
73
|
"@types/image-size": "0.7.0",
|
|
@@ -74,7 +75,7 @@
|
|
|
74
75
|
"@types/mustache": "4.2.6",
|
|
75
76
|
"@types/node": "22.9.0",
|
|
76
77
|
"@types/stack-trace": "0.0.33",
|
|
77
|
-
"backtest-kit": "8.
|
|
78
|
+
"backtest-kit": "8.3.0",
|
|
78
79
|
"glob": "11.0.1",
|
|
79
80
|
"markdown-it": "14.1.1",
|
|
80
81
|
"rimraf": "6.0.1",
|
|
@@ -89,12 +90,12 @@
|
|
|
89
90
|
"peerDependencies": {
|
|
90
91
|
"@babel/plugin-transform-modules-umd": "^7.27.1",
|
|
91
92
|
"@babel/standalone": "^7.29.1",
|
|
92
|
-
"@backtest-kit/graph": "^8.
|
|
93
|
-
"@backtest-kit/ollama": "^8.
|
|
94
|
-
"@backtest-kit/pinets": "^8.
|
|
95
|
-
"@backtest-kit/signals": "^8.
|
|
96
|
-
"@backtest-kit/ui": "^8.
|
|
97
|
-
"backtest-kit": "^8.
|
|
93
|
+
"@backtest-kit/graph": "^8.3.0",
|
|
94
|
+
"@backtest-kit/ollama": "^8.3.0",
|
|
95
|
+
"@backtest-kit/pinets": "^8.3.0",
|
|
96
|
+
"@backtest-kit/signals": "^8.3.0",
|
|
97
|
+
"@backtest-kit/ui": "^8.3.0",
|
|
98
|
+
"backtest-kit": "^8.3.0",
|
|
98
99
|
"markdown-it": "^14.1.1",
|
|
99
100
|
"typescript": "^5.0.0"
|
|
100
101
|
},
|
|
@@ -117,7 +118,7 @@
|
|
|
117
118
|
"telegraf": "4.15.3"
|
|
118
119
|
},
|
|
119
120
|
"bin": {
|
|
120
|
-
"
|
|
121
|
+
"backtest-kit": "./build/index.mjs"
|
|
121
122
|
},
|
|
122
123
|
"publishConfig": {
|
|
123
124
|
"access": "public"
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"license": "ISC",
|
|
14
14
|
"type": "commonjs",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@backtest-kit/cli": "^8.
|
|
17
|
-
"@backtest-kit/graph": "^8.
|
|
18
|
-
"@backtest-kit/pinets": "^8.
|
|
19
|
-
"@backtest-kit/ui": "^8.
|
|
16
|
+
"@backtest-kit/cli": "^8.3.0",
|
|
17
|
+
"@backtest-kit/graph": "^8.3.0",
|
|
18
|
+
"@backtest-kit/pinets": "^8.3.0",
|
|
19
|
+
"@backtest-kit/ui": "^8.3.0",
|
|
20
20
|
"agent-swarm-kit": "^2.6.0",
|
|
21
|
-
"backtest-kit": "^8.
|
|
21
|
+
"backtest-kit": "^8.3.0",
|
|
22
22
|
"functools-kit": "^2.3.0",
|
|
23
23
|
"garch": "^1.2.3",
|
|
24
24
|
"get-moment-stamp": "^1.1.2",
|