@backtest-kit/cli 6.15.0 → 7.0.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 +68 -1
- package/build/index.cjs +66 -21
- package/build/index.mjs +66 -21
- package/package.json +15 -14
- package/template/project/package.mustache +8 -7
package/README.md
CHANGED
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
Point the CLI at your strategy file, choose a mode, and it handles exchange connectivity, candle caching, UI dashboard, and Telegram notifications for you.
|
|
14
14
|
|
|
15
|
-
📚 **[Backtest Kit Docs](https://backtest-kit.github.io/documents/
|
|
15
|
+
📚 **[Backtest Kit Docs](https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html)** | 🌟 **[GitHub](https://github.com/tripolskypetr/backtest-kit)**
|
|
16
|
+
|
|
17
|
+
> **New to backtest-kit?** The fastest way to get a real, production-ready setup is to clone the [reference implementation](https://github.com/tripolskypetr/backtest-kit/tree/master/example) — a fully working news-sentiment AI trading system with LLM forecasting, multi-timeframe data, and a documented February 2026 backtest. Start there instead of from scratch.
|
|
16
18
|
|
|
17
19
|
## ✨ Features
|
|
18
20
|
|
|
@@ -40,6 +42,7 @@ Point the CLI at your strategy file, choose a mode, and it handles exchange conn
|
|
|
40
42
|
| **UI Dashboard** | `--ui` | Web dashboard at `http://localhost:60050` |
|
|
41
43
|
| **Telegram** | `--telegram` | Trade notifications with price charts |
|
|
42
44
|
| **PineScript** | `--pine` | Run a local `.pine` indicator against exchange data |
|
|
45
|
+
| **Pine Editor** | `--editor` | Open the visual Pine Script editor in the browser |
|
|
43
46
|
| **Candle Dump** | `--dump` | Fetch and save raw OHLCV candles to a file |
|
|
44
47
|
| **Flush** | `--flush` | Delete report/log/markdown/agent folders from strategy dump dir |
|
|
45
48
|
| **Init Project** | `--init` | Scaffold a new backtest-kit project |
|
|
@@ -739,6 +742,70 @@ Print to stdout (no flag):
|
|
|
739
742
|
npx @backtest-kit/cli --pine ./math/impulse_trend_15m.pine
|
|
740
743
|
```
|
|
741
744
|
|
|
745
|
+
## 🎨 Visual Pine Script Editor
|
|
746
|
+
|
|
747
|
+

|
|
748
|
+
|
|
749
|
+
`@backtest-kit/cli` ships a browser-based Pine Script editor powered by `@backtest-kit/ui`. It lets you write, run, and iterate on indicators interactively — with a live chart that updates as you hit **▶ Run**
|
|
750
|
+
|
|
751
|
+
### Usage
|
|
752
|
+
|
|
753
|
+
```bash
|
|
754
|
+
npx @backtest-kit/cli --editor
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
The CLI will:
|
|
758
|
+
|
|
759
|
+
1. Load `./modules/editor.module` (if it exists) — use it to register your exchange schema, identical to `pine.module`
|
|
760
|
+
2. Start the `@backtest-kit/ui` server on `http://localhost:60050` (or `CC_WWWROOT_PORT`)
|
|
761
|
+
3. Open `http://localhost:{CC_WWWROOT_PORT}?pine=1` automatically in your default browser
|
|
762
|
+
|
|
763
|
+
Press **Ctrl+C** to stop the server.
|
|
764
|
+
|
|
765
|
+
### Exchange via `editor.module`
|
|
766
|
+
|
|
767
|
+
Drop a `modules/editor.module.ts` next to your project to register the exchange that the editor's candle provider will use:
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
// modules/editor.module.ts
|
|
771
|
+
import { addExchangeSchema } from "backtest-kit";
|
|
772
|
+
import ccxt from "ccxt";
|
|
773
|
+
|
|
774
|
+
addExchangeSchema({
|
|
775
|
+
exchangeName: "my-exchange",
|
|
776
|
+
getCandles: async (symbol, interval, since, limit) => {
|
|
777
|
+
const exchange = new ccxt.bybit({ enableRateLimit: true });
|
|
778
|
+
const ohlcv = await exchange.fetchOHLCV(symbol, interval, since.getTime(), limit);
|
|
779
|
+
return ohlcv.map(([timestamp, open, high, low, close, volume]) => ({
|
|
780
|
+
timestamp, open, high, low, close, volume,
|
|
781
|
+
}));
|
|
782
|
+
},
|
|
783
|
+
formatPrice: (symbol, price) => price.toFixed(2),
|
|
784
|
+
formatQuantity: (symbol, quantity) => quantity.toFixed(8),
|
|
785
|
+
});
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
### Environment Variables
|
|
789
|
+
|
|
790
|
+
| Variable | Default | Description |
|
|
791
|
+
|-------------------|-----------|----------------------------------|
|
|
792
|
+
| `CC_WWWROOT_HOST` | `0.0.0.0` | UI server bind address |
|
|
793
|
+
| `CC_WWWROOT_PORT` | `60050` | UI server port |
|
|
794
|
+
|
|
795
|
+
### `package.json` script
|
|
796
|
+
|
|
797
|
+
```json
|
|
798
|
+
{
|
|
799
|
+
"scripts": {
|
|
800
|
+
"editor": "npx @backtest-kit/cli --editor"
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
```bash
|
|
806
|
+
npm run editor
|
|
807
|
+
```
|
|
808
|
+
|
|
742
809
|
## 💾 Dumping Raw Candles
|
|
743
810
|
|
|
744
811
|
`@backtest-kit/cli` can fetch raw OHLCV candles from any registered exchange and save them to a file — no strategy file required.
|
package/build/index.cjs
CHANGED
|
@@ -29,6 +29,7 @@ var BacktestKitGraph = require('@backtest-kit/graph');
|
|
|
29
29
|
var BacktestKitOllama = require('@backtest-kit/ollama');
|
|
30
30
|
var BacktestKitPinets = require('@backtest-kit/pinets');
|
|
31
31
|
var BacktestKitSignals = require('@backtest-kit/signals');
|
|
32
|
+
var open = require('open');
|
|
32
33
|
var child_process = require('child_process');
|
|
33
34
|
|
|
34
35
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -482,6 +483,10 @@ const getArgs = functoolsKit.singleshot(() => {
|
|
|
482
483
|
default: "1m, 15m, 30m, 4h",
|
|
483
484
|
},
|
|
484
485
|
// pinescript entry
|
|
486
|
+
editor: {
|
|
487
|
+
type: "boolean",
|
|
488
|
+
default: false,
|
|
489
|
+
},
|
|
485
490
|
pine: {
|
|
486
491
|
type: "boolean",
|
|
487
492
|
default: false,
|
|
@@ -2611,14 +2616,14 @@ BacktestKit.setConfig({
|
|
|
2611
2616
|
CC_WALKER_MARKDOWN_TOP_N: 10,
|
|
2612
2617
|
});
|
|
2613
2618
|
|
|
2614
|
-
const MODES = ["backtest", "walker", "paper", "live", "pine", "dump", "flush", "init", "help", "version"];
|
|
2619
|
+
const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "flush", "init", "help", "version"];
|
|
2615
2620
|
const ENTRY_PATH$1 = "./node_modules/@backtest-kit/cli/build/index.mjs";
|
|
2616
2621
|
const HELP_TEXT$1 = `
|
|
2617
2622
|
Example:
|
|
2618
2623
|
|
|
2619
2624
|
node ${ENTRY_PATH$1} --help
|
|
2620
2625
|
`.trimStart();
|
|
2621
|
-
const main$
|
|
2626
|
+
const main$d = async () => {
|
|
2622
2627
|
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)))) {
|
|
2623
2628
|
return;
|
|
2624
2629
|
}
|
|
@@ -2626,14 +2631,14 @@ const main$c = async () => {
|
|
|
2626
2631
|
if (MODES.some((mode) => values[mode])) {
|
|
2627
2632
|
return;
|
|
2628
2633
|
}
|
|
2629
|
-
process.stdout.write(`@backtest-kit/cli ${"
|
|
2634
|
+
process.stdout.write(`@backtest-kit/cli ${"7.0.0"}\n`);
|
|
2630
2635
|
process.stdout.write("\n");
|
|
2631
2636
|
process.stdout.write(`Run with --help to see available commands.\n`);
|
|
2632
2637
|
process.stdout.write("\n");
|
|
2633
2638
|
process.stdout.write(HELP_TEXT$1);
|
|
2634
2639
|
process.exit(0);
|
|
2635
2640
|
};
|
|
2636
|
-
main$
|
|
2641
|
+
main$d();
|
|
2637
2642
|
|
|
2638
2643
|
const notifyShutdown = functoolsKit.singleshot(async () => {
|
|
2639
2644
|
console.log("Graceful shutdown initiated. Press Ctrl+C again to force quit.");
|
|
@@ -2649,7 +2654,7 @@ const flush = async (entryPoint) => {
|
|
|
2649
2654
|
console.log(`Removed: ${target}`);
|
|
2650
2655
|
}
|
|
2651
2656
|
};
|
|
2652
|
-
const main$
|
|
2657
|
+
const main$c = async () => {
|
|
2653
2658
|
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)))) {
|
|
2654
2659
|
return;
|
|
2655
2660
|
}
|
|
@@ -2666,7 +2671,7 @@ const main$b = async () => {
|
|
|
2666
2671
|
}
|
|
2667
2672
|
process.exit(0);
|
|
2668
2673
|
};
|
|
2669
|
-
main$
|
|
2674
|
+
main$c();
|
|
2670
2675
|
|
|
2671
2676
|
const BEFORE_EXIT_FN$5 = functoolsKit.singleshot(async () => {
|
|
2672
2677
|
process.off("SIGINT", BEFORE_EXIT_FN$5);
|
|
@@ -2688,7 +2693,7 @@ const BEFORE_EXIT_FN$5 = functoolsKit.singleshot(async () => {
|
|
|
2688
2693
|
const listenGracefulShutdown$5 = functoolsKit.singleshot(() => {
|
|
2689
2694
|
process.on("SIGINT", BEFORE_EXIT_FN$5);
|
|
2690
2695
|
});
|
|
2691
|
-
const main$
|
|
2696
|
+
const main$b = async () => {
|
|
2692
2697
|
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)))) {
|
|
2693
2698
|
return;
|
|
2694
2699
|
}
|
|
@@ -2703,7 +2708,7 @@ const main$a = async () => {
|
|
|
2703
2708
|
await cli.backtestMainService.connect();
|
|
2704
2709
|
listenGracefulShutdown$5();
|
|
2705
2710
|
};
|
|
2706
|
-
main$
|
|
2711
|
+
main$b();
|
|
2707
2712
|
|
|
2708
2713
|
const BEFORE_EXIT_FN$4 = functoolsKit.singleshot(async () => {
|
|
2709
2714
|
process.off("SIGINT", BEFORE_EXIT_FN$4);
|
|
@@ -2721,7 +2726,7 @@ const BEFORE_EXIT_FN$4 = functoolsKit.singleshot(async () => {
|
|
|
2721
2726
|
const listenGracefulShutdown$4 = functoolsKit.singleshot(() => {
|
|
2722
2727
|
process.on("SIGINT", BEFORE_EXIT_FN$4);
|
|
2723
2728
|
});
|
|
2724
|
-
const main$
|
|
2729
|
+
const main$a = async () => {
|
|
2725
2730
|
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)))) {
|
|
2726
2731
|
return;
|
|
2727
2732
|
}
|
|
@@ -2737,7 +2742,7 @@ const main$9 = async () => {
|
|
|
2737
2742
|
listenGracefulShutdown$4();
|
|
2738
2743
|
await cli.walkerMainService.connect();
|
|
2739
2744
|
};
|
|
2740
|
-
main$
|
|
2745
|
+
main$a();
|
|
2741
2746
|
|
|
2742
2747
|
const BEFORE_EXIT_FN$3 = functoolsKit.singleshot(async () => {
|
|
2743
2748
|
process.off("SIGINT", BEFORE_EXIT_FN$3);
|
|
@@ -2758,7 +2763,7 @@ const BEFORE_EXIT_FN$3 = functoolsKit.singleshot(async () => {
|
|
|
2758
2763
|
const listenGracefulShutdown$3 = functoolsKit.singleshot(() => {
|
|
2759
2764
|
process.on("SIGINT", BEFORE_EXIT_FN$3);
|
|
2760
2765
|
});
|
|
2761
|
-
const main$
|
|
2766
|
+
const main$9 = async () => {
|
|
2762
2767
|
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)))) {
|
|
2763
2768
|
return;
|
|
2764
2769
|
}
|
|
@@ -2769,7 +2774,7 @@ const main$8 = async () => {
|
|
|
2769
2774
|
cli.paperMainService.connect();
|
|
2770
2775
|
listenGracefulShutdown$3();
|
|
2771
2776
|
};
|
|
2772
|
-
main$
|
|
2777
|
+
main$9();
|
|
2773
2778
|
|
|
2774
2779
|
const BEFORE_EXIT_FN$2 = functoolsKit.singleshot(async () => {
|
|
2775
2780
|
process.off("SIGINT", BEFORE_EXIT_FN$2);
|
|
@@ -2790,7 +2795,7 @@ const BEFORE_EXIT_FN$2 = functoolsKit.singleshot(async () => {
|
|
|
2790
2795
|
const listenGracefulShutdown$2 = functoolsKit.singleshot(() => {
|
|
2791
2796
|
process.on("SIGINT", BEFORE_EXIT_FN$2);
|
|
2792
2797
|
});
|
|
2793
|
-
const main$
|
|
2798
|
+
const main$8 = async () => {
|
|
2794
2799
|
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)))) {
|
|
2795
2800
|
return;
|
|
2796
2801
|
}
|
|
@@ -2801,7 +2806,7 @@ const main$7 = async () => {
|
|
|
2801
2806
|
await cli.liveMainService.connect();
|
|
2802
2807
|
listenGracefulShutdown$2();
|
|
2803
2808
|
};
|
|
2804
|
-
main$
|
|
2809
|
+
main$8();
|
|
2805
2810
|
|
|
2806
2811
|
const BEFORE_EXIT_FN$1 = functoolsKit.singleshot(async () => {
|
|
2807
2812
|
process.off("SIGINT", BEFORE_EXIT_FN$1);
|
|
@@ -2811,7 +2816,7 @@ const BEFORE_EXIT_FN$1 = functoolsKit.singleshot(async () => {
|
|
|
2811
2816
|
const listenGracefulShutdown$1 = functoolsKit.singleshot(() => {
|
|
2812
2817
|
process.on("SIGINT", BEFORE_EXIT_FN$1);
|
|
2813
2818
|
});
|
|
2814
|
-
const main$
|
|
2819
|
+
const main$7 = async () => {
|
|
2815
2820
|
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)))) {
|
|
2816
2821
|
return;
|
|
2817
2822
|
}
|
|
@@ -2821,7 +2826,7 @@ const main$6 = async () => {
|
|
|
2821
2826
|
}
|
|
2822
2827
|
listenGracefulShutdown$1();
|
|
2823
2828
|
};
|
|
2824
|
-
main$
|
|
2829
|
+
main$7();
|
|
2825
2830
|
|
|
2826
2831
|
const BEFORE_EXIT_FN = functoolsKit.singleshot(async () => {
|
|
2827
2832
|
process.off("SIGINT", BEFORE_EXIT_FN);
|
|
@@ -2831,7 +2836,7 @@ const BEFORE_EXIT_FN = functoolsKit.singleshot(async () => {
|
|
|
2831
2836
|
const listenGracefulShutdown = functoolsKit.singleshot(() => {
|
|
2832
2837
|
process.on("SIGINT", BEFORE_EXIT_FN);
|
|
2833
2838
|
});
|
|
2834
|
-
const main$
|
|
2839
|
+
const main$6 = async () => {
|
|
2835
2840
|
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)))) {
|
|
2836
2841
|
return;
|
|
2837
2842
|
}
|
|
@@ -2841,7 +2846,7 @@ const main$5 = async () => {
|
|
|
2841
2846
|
}
|
|
2842
2847
|
listenGracefulShutdown();
|
|
2843
2848
|
};
|
|
2844
|
-
main$
|
|
2849
|
+
main$6();
|
|
2845
2850
|
|
|
2846
2851
|
const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
2847
2852
|
const keys = Object.keys(schema);
|
|
@@ -2863,7 +2868,7 @@ const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
|
2863
2868
|
}
|
|
2864
2869
|
return rows;
|
|
2865
2870
|
};
|
|
2866
|
-
const main$
|
|
2871
|
+
const main$5 = async () => {
|
|
2867
2872
|
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)))) {
|
|
2868
2873
|
return;
|
|
2869
2874
|
}
|
|
@@ -2871,6 +2876,10 @@ const main$4 = async () => {
|
|
|
2871
2876
|
if (!values.pine) {
|
|
2872
2877
|
return;
|
|
2873
2878
|
}
|
|
2879
|
+
if (values.editor) {
|
|
2880
|
+
console.warn("--pine and --editor are mutually exclusive. Use one at a time.");
|
|
2881
|
+
process.exit(1);
|
|
2882
|
+
}
|
|
2874
2883
|
const [entryPoint = null] = getPositionals();
|
|
2875
2884
|
if (!entryPoint) {
|
|
2876
2885
|
return;
|
|
@@ -2939,6 +2948,39 @@ const main$4 = async () => {
|
|
|
2939
2948
|
console.log(await BacktestKitPinets.toMarkdown(signalId, plots, signalSchema));
|
|
2940
2949
|
process.exit(0);
|
|
2941
2950
|
};
|
|
2951
|
+
main$5();
|
|
2952
|
+
|
|
2953
|
+
const main$4 = async () => {
|
|
2954
|
+
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)))) {
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2957
|
+
const { values } = getArgs();
|
|
2958
|
+
if (!values.editor) {
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2961
|
+
if (values.pine) {
|
|
2962
|
+
console.warn("--editor and --pine are mutually exclusive. Use one at a time.");
|
|
2963
|
+
process.exit(1);
|
|
2964
|
+
}
|
|
2965
|
+
await cli.moduleConnectionService.loadModule("./editor.module");
|
|
2966
|
+
{
|
|
2967
|
+
await cli.exchangeSchemaService.addSchema();
|
|
2968
|
+
}
|
|
2969
|
+
const { CC_WWWROOT_HOST, CC_WWWROOT_PORT } = getEnv();
|
|
2970
|
+
const unServer = BacktestKitUi.serve(CC_WWWROOT_HOST, CC_WWWROOT_PORT, cli.resolveService.PROJECT_ROOT_DIR);
|
|
2971
|
+
try {
|
|
2972
|
+
await open(`http://localhost:${CC_WWWROOT_PORT}?pine=1`);
|
|
2973
|
+
}
|
|
2974
|
+
finally {
|
|
2975
|
+
console.log(`Editor launched: http://localhost:${CC_WWWROOT_PORT}?pine=1`);
|
|
2976
|
+
}
|
|
2977
|
+
const beforeExit = () => {
|
|
2978
|
+
process.off("SIGINT", beforeExit);
|
|
2979
|
+
unServer();
|
|
2980
|
+
process.exit(0);
|
|
2981
|
+
};
|
|
2982
|
+
process.on("SIGINT", beforeExit);
|
|
2983
|
+
};
|
|
2942
2984
|
main$4();
|
|
2943
2985
|
|
|
2944
2986
|
const main$3 = async () => {
|
|
@@ -3118,6 +3160,7 @@ Modes:
|
|
|
3118
3160
|
--paper <entry> Paper trading (live prices, no real orders)
|
|
3119
3161
|
--live <entry> Live trading with real orders
|
|
3120
3162
|
--pine <entry> Execute a local .pine indicator file
|
|
3163
|
+
--editor Open the Pine Script visual editor in the browser
|
|
3121
3164
|
--dump Fetch and save raw OHLCV candles
|
|
3122
3165
|
--flush <entry...> Delete report/log/markdown/agent folders from strategy dump dir
|
|
3123
3166
|
--init Scaffold a new project in the current directory
|
|
@@ -3211,6 +3254,7 @@ Module hooks (loaded automatically by each mode):
|
|
|
3211
3254
|
modules/paper.module --paper Broker adapter for paper trading
|
|
3212
3255
|
modules/live.module --live Broker adapter for live trading
|
|
3213
3256
|
modules/pine.module --pine Exchange schema for PineScript runs
|
|
3257
|
+
modules/editor.module --editor Exchange schema for the visual Pine editor
|
|
3214
3258
|
modules/dump.module --dump Exchange schema for candle dumps
|
|
3215
3259
|
|
|
3216
3260
|
--flush has no associated module. It only removes dump subdirectories.
|
|
@@ -3233,6 +3277,7 @@ Examples:
|
|
|
3233
3277
|
node ${ENTRY_PATH} --paper --symbol ETHUSDT ./content/feb_2026.strategy.ts
|
|
3234
3278
|
node ${ENTRY_PATH} --live --ui --telegram ./content/feb_2026.strategy.ts
|
|
3235
3279
|
node ${ENTRY_PATH} --pine ./math/feb_2026.pine --timeframe 15m --limit 500 --jsonl
|
|
3280
|
+
node ${ENTRY_PATH} --editor
|
|
3236
3281
|
node ${ENTRY_PATH} --dump --symbol BTCUSDT --timeframe 15m --limit 500 --jsonl
|
|
3237
3282
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts
|
|
3238
3283
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts ./content/feb_2026.strategy/feb_2026.test.ts
|
|
@@ -3246,7 +3291,7 @@ const main$1 = async () => {
|
|
|
3246
3291
|
if (!values.help) {
|
|
3247
3292
|
return;
|
|
3248
3293
|
}
|
|
3249
|
-
process.stdout.write(`@backtest-kit/cli ${"
|
|
3294
|
+
process.stdout.write(`@backtest-kit/cli ${"7.0.0"}\n\n`);
|
|
3250
3295
|
process.stdout.write(HELP_TEXT);
|
|
3251
3296
|
process.exit(0);
|
|
3252
3297
|
};
|
|
@@ -3260,7 +3305,7 @@ const main = async () => {
|
|
|
3260
3305
|
if (!values.version) {
|
|
3261
3306
|
return;
|
|
3262
3307
|
}
|
|
3263
|
-
process.stdout.write(`@backtest-kit/cli ${"
|
|
3308
|
+
process.stdout.write(`@backtest-kit/cli ${"7.0.0"}\n`);
|
|
3264
3309
|
process.exit(0);
|
|
3265
3310
|
};
|
|
3266
3311
|
main();
|
package/build/index.mjs
CHANGED
|
@@ -30,6 +30,7 @@ import * as BacktestKitOllama from '@backtest-kit/ollama';
|
|
|
30
30
|
import * as BacktestKitPinets from '@backtest-kit/pinets';
|
|
31
31
|
import { run as run$1, Code, toMarkdown } from '@backtest-kit/pinets';
|
|
32
32
|
import * as BacktestKitSignals from '@backtest-kit/signals';
|
|
33
|
+
import open from 'open';
|
|
33
34
|
import { spawn } from 'child_process';
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -457,6 +458,10 @@ const getArgs = singleshot(() => {
|
|
|
457
458
|
default: "1m, 15m, 30m, 4h",
|
|
458
459
|
},
|
|
459
460
|
// pinescript entry
|
|
461
|
+
editor: {
|
|
462
|
+
type: "boolean",
|
|
463
|
+
default: false,
|
|
464
|
+
},
|
|
460
465
|
pine: {
|
|
461
466
|
type: "boolean",
|
|
462
467
|
default: false,
|
|
@@ -2582,14 +2587,14 @@ setConfig({
|
|
|
2582
2587
|
CC_WALKER_MARKDOWN_TOP_N: 10,
|
|
2583
2588
|
});
|
|
2584
2589
|
|
|
2585
|
-
const MODES = ["backtest", "walker", "paper", "live", "pine", "dump", "flush", "init", "help", "version"];
|
|
2590
|
+
const MODES = ["backtest", "walker", "paper", "live", "pine", "editor", "dump", "flush", "init", "help", "version"];
|
|
2586
2591
|
const ENTRY_PATH$1 = "./node_modules/@backtest-kit/cli/build/index.mjs";
|
|
2587
2592
|
const HELP_TEXT$1 = `
|
|
2588
2593
|
Example:
|
|
2589
2594
|
|
|
2590
2595
|
node ${ENTRY_PATH$1} --help
|
|
2591
2596
|
`.trimStart();
|
|
2592
|
-
const main$
|
|
2597
|
+
const main$d = async () => {
|
|
2593
2598
|
if (!getEntry(import.meta.url)) {
|
|
2594
2599
|
return;
|
|
2595
2600
|
}
|
|
@@ -2597,14 +2602,14 @@ const main$c = async () => {
|
|
|
2597
2602
|
if (MODES.some((mode) => values[mode])) {
|
|
2598
2603
|
return;
|
|
2599
2604
|
}
|
|
2600
|
-
process.stdout.write(`@backtest-kit/cli ${"
|
|
2605
|
+
process.stdout.write(`@backtest-kit/cli ${"7.0.0"}\n`);
|
|
2601
2606
|
process.stdout.write("\n");
|
|
2602
2607
|
process.stdout.write(`Run with --help to see available commands.\n`);
|
|
2603
2608
|
process.stdout.write("\n");
|
|
2604
2609
|
process.stdout.write(HELP_TEXT$1);
|
|
2605
2610
|
process.exit(0);
|
|
2606
2611
|
};
|
|
2607
|
-
main$
|
|
2612
|
+
main$d();
|
|
2608
2613
|
|
|
2609
2614
|
const notifyShutdown = singleshot(async () => {
|
|
2610
2615
|
console.log("Graceful shutdown initiated. Press Ctrl+C again to force quit.");
|
|
@@ -2620,7 +2625,7 @@ const flush = async (entryPoint) => {
|
|
|
2620
2625
|
console.log(`Removed: ${target}`);
|
|
2621
2626
|
}
|
|
2622
2627
|
};
|
|
2623
|
-
const main$
|
|
2628
|
+
const main$c = async () => {
|
|
2624
2629
|
if (!getEntry(import.meta.url)) {
|
|
2625
2630
|
return;
|
|
2626
2631
|
}
|
|
@@ -2637,7 +2642,7 @@ const main$b = async () => {
|
|
|
2637
2642
|
}
|
|
2638
2643
|
process.exit(0);
|
|
2639
2644
|
};
|
|
2640
|
-
main$
|
|
2645
|
+
main$c();
|
|
2641
2646
|
|
|
2642
2647
|
const BEFORE_EXIT_FN$5 = singleshot(async () => {
|
|
2643
2648
|
process.off("SIGINT", BEFORE_EXIT_FN$5);
|
|
@@ -2659,7 +2664,7 @@ const BEFORE_EXIT_FN$5 = singleshot(async () => {
|
|
|
2659
2664
|
const listenGracefulShutdown$5 = singleshot(() => {
|
|
2660
2665
|
process.on("SIGINT", BEFORE_EXIT_FN$5);
|
|
2661
2666
|
});
|
|
2662
|
-
const main$
|
|
2667
|
+
const main$b = async () => {
|
|
2663
2668
|
if (!getEntry(import.meta.url)) {
|
|
2664
2669
|
return;
|
|
2665
2670
|
}
|
|
@@ -2674,7 +2679,7 @@ const main$a = async () => {
|
|
|
2674
2679
|
await cli.backtestMainService.connect();
|
|
2675
2680
|
listenGracefulShutdown$5();
|
|
2676
2681
|
};
|
|
2677
|
-
main$
|
|
2682
|
+
main$b();
|
|
2678
2683
|
|
|
2679
2684
|
const BEFORE_EXIT_FN$4 = singleshot(async () => {
|
|
2680
2685
|
process.off("SIGINT", BEFORE_EXIT_FN$4);
|
|
@@ -2692,7 +2697,7 @@ const BEFORE_EXIT_FN$4 = singleshot(async () => {
|
|
|
2692
2697
|
const listenGracefulShutdown$4 = singleshot(() => {
|
|
2693
2698
|
process.on("SIGINT", BEFORE_EXIT_FN$4);
|
|
2694
2699
|
});
|
|
2695
|
-
const main$
|
|
2700
|
+
const main$a = async () => {
|
|
2696
2701
|
if (!getEntry(import.meta.url)) {
|
|
2697
2702
|
return;
|
|
2698
2703
|
}
|
|
@@ -2708,7 +2713,7 @@ const main$9 = async () => {
|
|
|
2708
2713
|
listenGracefulShutdown$4();
|
|
2709
2714
|
await cli.walkerMainService.connect();
|
|
2710
2715
|
};
|
|
2711
|
-
main$
|
|
2716
|
+
main$a();
|
|
2712
2717
|
|
|
2713
2718
|
const BEFORE_EXIT_FN$3 = singleshot(async () => {
|
|
2714
2719
|
process.off("SIGINT", BEFORE_EXIT_FN$3);
|
|
@@ -2729,7 +2734,7 @@ const BEFORE_EXIT_FN$3 = singleshot(async () => {
|
|
|
2729
2734
|
const listenGracefulShutdown$3 = singleshot(() => {
|
|
2730
2735
|
process.on("SIGINT", BEFORE_EXIT_FN$3);
|
|
2731
2736
|
});
|
|
2732
|
-
const main$
|
|
2737
|
+
const main$9 = async () => {
|
|
2733
2738
|
if (!getEntry(import.meta.url)) {
|
|
2734
2739
|
return;
|
|
2735
2740
|
}
|
|
@@ -2740,7 +2745,7 @@ const main$8 = async () => {
|
|
|
2740
2745
|
cli.paperMainService.connect();
|
|
2741
2746
|
listenGracefulShutdown$3();
|
|
2742
2747
|
};
|
|
2743
|
-
main$
|
|
2748
|
+
main$9();
|
|
2744
2749
|
|
|
2745
2750
|
const BEFORE_EXIT_FN$2 = singleshot(async () => {
|
|
2746
2751
|
process.off("SIGINT", BEFORE_EXIT_FN$2);
|
|
@@ -2761,7 +2766,7 @@ const BEFORE_EXIT_FN$2 = singleshot(async () => {
|
|
|
2761
2766
|
const listenGracefulShutdown$2 = singleshot(() => {
|
|
2762
2767
|
process.on("SIGINT", BEFORE_EXIT_FN$2);
|
|
2763
2768
|
});
|
|
2764
|
-
const main$
|
|
2769
|
+
const main$8 = async () => {
|
|
2765
2770
|
if (!getEntry(import.meta.url)) {
|
|
2766
2771
|
return;
|
|
2767
2772
|
}
|
|
@@ -2772,7 +2777,7 @@ const main$7 = async () => {
|
|
|
2772
2777
|
await cli.liveMainService.connect();
|
|
2773
2778
|
listenGracefulShutdown$2();
|
|
2774
2779
|
};
|
|
2775
|
-
main$
|
|
2780
|
+
main$8();
|
|
2776
2781
|
|
|
2777
2782
|
const BEFORE_EXIT_FN$1 = singleshot(async () => {
|
|
2778
2783
|
process.off("SIGINT", BEFORE_EXIT_FN$1);
|
|
@@ -2782,7 +2787,7 @@ const BEFORE_EXIT_FN$1 = singleshot(async () => {
|
|
|
2782
2787
|
const listenGracefulShutdown$1 = singleshot(() => {
|
|
2783
2788
|
process.on("SIGINT", BEFORE_EXIT_FN$1);
|
|
2784
2789
|
});
|
|
2785
|
-
const main$
|
|
2790
|
+
const main$7 = async () => {
|
|
2786
2791
|
if (!getEntry(import.meta.url)) {
|
|
2787
2792
|
return;
|
|
2788
2793
|
}
|
|
@@ -2792,7 +2797,7 @@ const main$6 = async () => {
|
|
|
2792
2797
|
}
|
|
2793
2798
|
listenGracefulShutdown$1();
|
|
2794
2799
|
};
|
|
2795
|
-
main$
|
|
2800
|
+
main$7();
|
|
2796
2801
|
|
|
2797
2802
|
const BEFORE_EXIT_FN = singleshot(async () => {
|
|
2798
2803
|
process.off("SIGINT", BEFORE_EXIT_FN);
|
|
@@ -2802,7 +2807,7 @@ const BEFORE_EXIT_FN = singleshot(async () => {
|
|
|
2802
2807
|
const listenGracefulShutdown = singleshot(() => {
|
|
2803
2808
|
process.on("SIGINT", BEFORE_EXIT_FN);
|
|
2804
2809
|
});
|
|
2805
|
-
const main$
|
|
2810
|
+
const main$6 = async () => {
|
|
2806
2811
|
if (!getEntry(import.meta.url)) {
|
|
2807
2812
|
return;
|
|
2808
2813
|
}
|
|
@@ -2812,7 +2817,7 @@ const main$5 = async () => {
|
|
|
2812
2817
|
}
|
|
2813
2818
|
listenGracefulShutdown();
|
|
2814
2819
|
};
|
|
2815
|
-
main$
|
|
2820
|
+
main$6();
|
|
2816
2821
|
|
|
2817
2822
|
const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
2818
2823
|
const keys = Object.keys(schema);
|
|
@@ -2834,7 +2839,7 @@ const EXTRACT_ROWS_FN = (plots, schema) => {
|
|
|
2834
2839
|
}
|
|
2835
2840
|
return rows;
|
|
2836
2841
|
};
|
|
2837
|
-
const main$
|
|
2842
|
+
const main$5 = async () => {
|
|
2838
2843
|
if (!getEntry(import.meta.url)) {
|
|
2839
2844
|
return;
|
|
2840
2845
|
}
|
|
@@ -2842,6 +2847,10 @@ const main$4 = async () => {
|
|
|
2842
2847
|
if (!values.pine) {
|
|
2843
2848
|
return;
|
|
2844
2849
|
}
|
|
2850
|
+
if (values.editor) {
|
|
2851
|
+
console.warn("--pine and --editor are mutually exclusive. Use one at a time.");
|
|
2852
|
+
process.exit(1);
|
|
2853
|
+
}
|
|
2845
2854
|
const [entryPoint = null] = getPositionals();
|
|
2846
2855
|
if (!entryPoint) {
|
|
2847
2856
|
return;
|
|
@@ -2910,6 +2919,39 @@ const main$4 = async () => {
|
|
|
2910
2919
|
console.log(await toMarkdown(signalId, plots, signalSchema));
|
|
2911
2920
|
process.exit(0);
|
|
2912
2921
|
};
|
|
2922
|
+
main$5();
|
|
2923
|
+
|
|
2924
|
+
const main$4 = async () => {
|
|
2925
|
+
if (!getEntry(import.meta.url)) {
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
2928
|
+
const { values } = getArgs();
|
|
2929
|
+
if (!values.editor) {
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
if (values.pine) {
|
|
2933
|
+
console.warn("--editor and --pine are mutually exclusive. Use one at a time.");
|
|
2934
|
+
process.exit(1);
|
|
2935
|
+
}
|
|
2936
|
+
await cli.moduleConnectionService.loadModule("./editor.module");
|
|
2937
|
+
{
|
|
2938
|
+
await cli.exchangeSchemaService.addSchema();
|
|
2939
|
+
}
|
|
2940
|
+
const { CC_WWWROOT_HOST, CC_WWWROOT_PORT } = getEnv();
|
|
2941
|
+
const unServer = serve(CC_WWWROOT_HOST, CC_WWWROOT_PORT, cli.resolveService.PROJECT_ROOT_DIR);
|
|
2942
|
+
try {
|
|
2943
|
+
await open(`http://localhost:${CC_WWWROOT_PORT}?pine=1`);
|
|
2944
|
+
}
|
|
2945
|
+
finally {
|
|
2946
|
+
console.log(`Editor launched: http://localhost:${CC_WWWROOT_PORT}?pine=1`);
|
|
2947
|
+
}
|
|
2948
|
+
const beforeExit = () => {
|
|
2949
|
+
process.off("SIGINT", beforeExit);
|
|
2950
|
+
unServer();
|
|
2951
|
+
process.exit(0);
|
|
2952
|
+
};
|
|
2953
|
+
process.on("SIGINT", beforeExit);
|
|
2954
|
+
};
|
|
2913
2955
|
main$4();
|
|
2914
2956
|
|
|
2915
2957
|
const main$3 = async () => {
|
|
@@ -3089,6 +3131,7 @@ Modes:
|
|
|
3089
3131
|
--paper <entry> Paper trading (live prices, no real orders)
|
|
3090
3132
|
--live <entry> Live trading with real orders
|
|
3091
3133
|
--pine <entry> Execute a local .pine indicator file
|
|
3134
|
+
--editor Open the Pine Script visual editor in the browser
|
|
3092
3135
|
--dump Fetch and save raw OHLCV candles
|
|
3093
3136
|
--flush <entry...> Delete report/log/markdown/agent folders from strategy dump dir
|
|
3094
3137
|
--init Scaffold a new project in the current directory
|
|
@@ -3182,6 +3225,7 @@ Module hooks (loaded automatically by each mode):
|
|
|
3182
3225
|
modules/paper.module --paper Broker adapter for paper trading
|
|
3183
3226
|
modules/live.module --live Broker adapter for live trading
|
|
3184
3227
|
modules/pine.module --pine Exchange schema for PineScript runs
|
|
3228
|
+
modules/editor.module --editor Exchange schema for the visual Pine editor
|
|
3185
3229
|
modules/dump.module --dump Exchange schema for candle dumps
|
|
3186
3230
|
|
|
3187
3231
|
--flush has no associated module. It only removes dump subdirectories.
|
|
@@ -3204,6 +3248,7 @@ Examples:
|
|
|
3204
3248
|
node ${ENTRY_PATH} --paper --symbol ETHUSDT ./content/feb_2026.strategy.ts
|
|
3205
3249
|
node ${ENTRY_PATH} --live --ui --telegram ./content/feb_2026.strategy.ts
|
|
3206
3250
|
node ${ENTRY_PATH} --pine ./math/feb_2026.pine --timeframe 15m --limit 500 --jsonl
|
|
3251
|
+
node ${ENTRY_PATH} --editor
|
|
3207
3252
|
node ${ENTRY_PATH} --dump --symbol BTCUSDT --timeframe 15m --limit 500 --jsonl
|
|
3208
3253
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts
|
|
3209
3254
|
node ${ENTRY_PATH} --flush ./content/feb_2026.strategy/feb_2026.strategy.ts ./content/feb_2026.strategy/feb_2026.test.ts
|
|
@@ -3217,7 +3262,7 @@ const main$1 = async () => {
|
|
|
3217
3262
|
if (!values.help) {
|
|
3218
3263
|
return;
|
|
3219
3264
|
}
|
|
3220
|
-
process.stdout.write(`@backtest-kit/cli ${"
|
|
3265
|
+
process.stdout.write(`@backtest-kit/cli ${"7.0.0"}\n\n`);
|
|
3221
3266
|
process.stdout.write(HELP_TEXT);
|
|
3222
3267
|
process.exit(0);
|
|
3223
3268
|
};
|
|
@@ -3231,7 +3276,7 @@ const main = async () => {
|
|
|
3231
3276
|
if (!values.version) {
|
|
3232
3277
|
return;
|
|
3233
3278
|
}
|
|
3234
|
-
process.stdout.write(`@backtest-kit/cli ${"
|
|
3279
|
+
process.stdout.write(`@backtest-kit/cli ${"7.0.0"}\n`);
|
|
3235
3280
|
process.exit(0);
|
|
3236
3281
|
};
|
|
3237
3282
|
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtest-kit/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.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",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"url": "http://paypal.me/tripolskypetr"
|
|
13
13
|
},
|
|
14
14
|
"license": "MIT",
|
|
15
|
-
"homepage": "https://backtest-kit.github.io/documents/
|
|
15
|
+
"homepage": "https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html",
|
|
16
16
|
"keywords": [
|
|
17
17
|
"backtest",
|
|
18
18
|
"backtesting",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@babel/plugin-transform-modules-umd": "7.27.1",
|
|
63
63
|
"@babel/standalone": "7.29.1",
|
|
64
|
-
"@backtest-kit/
|
|
65
|
-
"@backtest-kit/
|
|
66
|
-
"@backtest-kit/
|
|
67
|
-
"@backtest-kit/
|
|
68
|
-
"@backtest-kit/
|
|
64
|
+
"@backtest-kit/graph": "7.0.0",
|
|
65
|
+
"@backtest-kit/ollama": "7.0.0",
|
|
66
|
+
"@backtest-kit/pinets": "7.0.0",
|
|
67
|
+
"@backtest-kit/signals": "7.0.0",
|
|
68
|
+
"@backtest-kit/ui": "7.0.0",
|
|
69
69
|
"@rollup/plugin-replace": "6.0.3",
|
|
70
70
|
"@rollup/plugin-typescript": "11.1.6",
|
|
71
71
|
"@types/image-size": "0.7.0",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@types/mustache": "4.2.6",
|
|
74
74
|
"@types/node": "22.9.0",
|
|
75
75
|
"@types/stack-trace": "0.0.33",
|
|
76
|
-
"backtest-kit": "
|
|
76
|
+
"backtest-kit": "7.0.0",
|
|
77
77
|
"glob": "11.0.1",
|
|
78
78
|
"markdown-it": "14.1.1",
|
|
79
79
|
"rimraf": "6.0.1",
|
|
@@ -88,12 +88,12 @@
|
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"@babel/plugin-transform-modules-umd": "^7.27.1",
|
|
90
90
|
"@babel/standalone": "^7.29.1",
|
|
91
|
-
"@backtest-kit/
|
|
92
|
-
"@backtest-kit/
|
|
93
|
-
"@backtest-kit/
|
|
94
|
-
"@backtest-kit/
|
|
95
|
-
"@backtest-kit/
|
|
96
|
-
"backtest-kit": "^
|
|
91
|
+
"@backtest-kit/graph": "^7.0.0",
|
|
92
|
+
"@backtest-kit/ollama": "^7.0.0",
|
|
93
|
+
"@backtest-kit/pinets": "^7.0.0",
|
|
94
|
+
"@backtest-kit/signals": "^7.0.0",
|
|
95
|
+
"@backtest-kit/ui": "^7.0.0",
|
|
96
|
+
"backtest-kit": "^7.0.0",
|
|
97
97
|
"markdown-it": "^14.1.1",
|
|
98
98
|
"typescript": "^5.0.0"
|
|
99
99
|
},
|
|
@@ -108,6 +108,7 @@
|
|
|
108
108
|
"jsdom": "26.1.0",
|
|
109
109
|
"markdownlint": "0.38.0",
|
|
110
110
|
"mustache": "4.2.0",
|
|
111
|
+
"open": "11.0.0",
|
|
111
112
|
"quickchart-js": "3.1.3",
|
|
112
113
|
"resize-image-buffer": "1.0.0",
|
|
113
114
|
"sanitize-html": "2.17.0",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{PROJECT_NAME}}",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"description": "",
|
|
4
|
+
"description": "Backtest Kit trading bot project",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"homepage": "https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"start": "node ./node_modules/@backtest-kit/cli/build/index.mjs",
|
|
8
9
|
"sync:lib": "node ./scripts/fetch_docs.mjs"
|
|
@@ -12,12 +13,12 @@
|
|
|
12
13
|
"license": "ISC",
|
|
13
14
|
"type": "commonjs",
|
|
14
15
|
"dependencies": {
|
|
15
|
-
"@backtest-kit/cli": "^
|
|
16
|
-
"@backtest-kit/graph": "^
|
|
17
|
-
"@backtest-kit/pinets": "^
|
|
18
|
-
"@backtest-kit/ui": "^
|
|
19
|
-
"agent-swarm-kit": "^2.5.
|
|
20
|
-
"backtest-kit": "^
|
|
16
|
+
"@backtest-kit/cli": "^7.0.0",
|
|
17
|
+
"@backtest-kit/graph": "^7.0.0",
|
|
18
|
+
"@backtest-kit/pinets": "^7.0.0",
|
|
19
|
+
"@backtest-kit/ui": "^7.0.0",
|
|
20
|
+
"agent-swarm-kit": "^2.5.1",
|
|
21
|
+
"backtest-kit": "^7.0.0",
|
|
21
22
|
"functools-kit": "^2.2.0",
|
|
22
23
|
"garch": "^1.2.3",
|
|
23
24
|
"get-moment-stamp": "^1.1.2",
|