@backtest-kit/cli 15.5.0 → 16.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/build/index.cjs CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  var BacktestKit = require('backtest-kit');
5
5
  var functoolsKit = require('functools-kit');
6
+ var child_process = require('child_process');
6
7
  var fs = require('fs');
7
8
  var stackTrace = require('stack-trace');
8
9
  var path = require('path');
@@ -11,7 +12,6 @@ var dotenv = require('dotenv');
11
12
  var diKit = require('di-kit');
12
13
  var url = require('url');
13
14
  var util = require('util');
14
- var child_process = require('child_process');
15
15
  var BacktestKitUi = require('@backtest-kit/ui');
16
16
  var QuickChart = require('quickchart-js');
17
17
  var telegraf = require('telegraf');
@@ -57,6 +57,129 @@ var BacktestKitOllama__namespace = /*#__PURE__*/_interopNamespaceDefault(Backtes
57
57
  var BacktestKitPinets__namespace = /*#__PURE__*/_interopNamespaceDefault(BacktestKitPinets);
58
58
  var BacktestKitSignals__namespace = /*#__PURE__*/_interopNamespaceDefault(BacktestKitSignals);
59
59
 
60
+ function killPid(pid, signal) {
61
+ try {
62
+ process.kill(pid, signal);
63
+ }
64
+ catch (err) {
65
+ if (err.code !== "ESRCH")
66
+ throw err;
67
+ }
68
+ }
69
+ function killAll(tree, signal, callback) {
70
+ const killed = {};
71
+ try {
72
+ for (const pid of Object.keys(tree).map(Number)) {
73
+ for (const child of tree[pid]) {
74
+ if (!killed[child]) {
75
+ killPid(child, signal);
76
+ killed[child] = true;
77
+ }
78
+ }
79
+ if (!killed[pid]) {
80
+ killPid(pid, signal);
81
+ killed[pid] = true;
82
+ }
83
+ }
84
+ }
85
+ catch (err) {
86
+ if (callback)
87
+ return callback(err);
88
+ throw err;
89
+ }
90
+ callback?.();
91
+ }
92
+ function buildProcessTree(parentPid, tree, pidsToProcess, spawnList, cb) {
93
+ const ps = spawnList(parentPid);
94
+ let allData = "";
95
+ ps.stdout.on("data", (data) => {
96
+ allData += data.toString("ascii");
97
+ });
98
+ ps.on("close", (code) => {
99
+ delete pidsToProcess[parentPid];
100
+ if (code !== 0) {
101
+ if (Object.keys(pidsToProcess).length === 0)
102
+ cb();
103
+ return;
104
+ }
105
+ const matches = allData.match(/\d+/g);
106
+ if (matches) {
107
+ for (const pidStr of matches) {
108
+ const pid = parseInt(pidStr, 10);
109
+ tree[parentPid].push(pid);
110
+ tree[pid] = [];
111
+ pidsToProcess[pid] = 1;
112
+ buildProcessTree(pid, tree, pidsToProcess, spawnList, cb);
113
+ }
114
+ }
115
+ });
116
+ }
117
+ function treeKill(pid, signalOrCallback, callback) {
118
+ let signal;
119
+ if (typeof signalOrCallback === "function") {
120
+ callback = signalOrCallback;
121
+ signal = undefined;
122
+ }
123
+ else {
124
+ signal = signalOrCallback;
125
+ }
126
+ pid = parseInt(pid, 10);
127
+ if (Number.isNaN(pid)) {
128
+ const err = new Error("pid must be a number");
129
+ if (callback)
130
+ return callback(err);
131
+ throw err;
132
+ }
133
+ const tree = { [pid]: [] };
134
+ const pidsToProcess = { [pid]: 1 };
135
+ switch (process.platform) {
136
+ case "win32":
137
+ child_process.exec(`taskkill /pid ${pid} /T /F`, (err) => callback?.(err ?? undefined));
138
+ break;
139
+ case "darwin":
140
+ buildProcessTree(pid, tree, pidsToProcess, (parentPid) => child_process.spawn("pgrep", ["-P", String(parentPid)]), () => killAll(tree, signal, callback));
141
+ break;
142
+ default: // Linux
143
+ buildProcessTree(pid, tree, pidsToProcess, (parentPid) => child_process.spawn("ps", ["-o", "pid", "--no-headers", "--ppid", String(parentPid)]), () => killAll(tree, signal, callback));
144
+ break;
145
+ }
146
+ }
147
+
148
+ const DRAIN_MAX_AWAIT = 250;
149
+ const drainStream = (stream) => new Promise((resolve) => {
150
+ if (stream.writableLength === 0) {
151
+ stream.write("", () => resolve());
152
+ return;
153
+ }
154
+ stream.once("drain", () => {
155
+ stream.write("", () => resolve());
156
+ });
157
+ });
158
+ const flushStream = (stream) => {
159
+ const handle = stream._handle;
160
+ if (handle && typeof handle.setBlocking === "function") {
161
+ handle.setBlocking(true);
162
+ return new Promise((resolve) => stream.write("", () => resolve()));
163
+ }
164
+ return drainStream(stream);
165
+ };
166
+ const kill = functoolsKit.singleshot(async (code = -1) => {
167
+ await Promise.race([
168
+ Promise.all([
169
+ flushStream(process.stdout),
170
+ flushStream(process.stderr)
171
+ ]),
172
+ functoolsKit.sleep(DRAIN_MAX_AWAIT),
173
+ ]);
174
+ treeKill(process.pid, "SIGKILL", () => {
175
+ process.exit(code);
176
+ });
177
+ });
178
+ const notifyKill = functoolsKit.singleshot(() => {
179
+ console.log("Press Ctrl+C again to force quit.");
180
+ process.on("SIGINT", () => kill());
181
+ });
182
+
60
183
  BacktestKit.setConfig({
61
184
  CC_MAX_NOTIFICATIONS: 5000,
62
185
  CC_MAX_SIGNALS: 750,
@@ -91,6 +214,13 @@ BacktestKit.setConfig({
91
214
  BacktestKit.setConfig({
92
215
  CC_WALKER_MARKDOWN_TOP_N: 10,
93
216
  });
217
+ BacktestKit.listenExit((error) => {
218
+ console.error("Exiting due to error:", {
219
+ errorMessage: functoolsKit.getErrorMessage(error),
220
+ errorData: functoolsKit.errorData(error),
221
+ });
222
+ kill();
223
+ });
94
224
 
95
225
  const getEntrySubject = functoolsKit.singleshot(() => {
96
226
  const entrySubject = BacktestKit.emitters["entrySubject"];
@@ -903,129 +1033,6 @@ const notifyVerbose = functoolsKit.singleshot(() => {
903
1033
  });
904
1034
  });
905
1035
 
906
- function killPid(pid, signal) {
907
- try {
908
- process.kill(pid, signal);
909
- }
910
- catch (err) {
911
- if (err.code !== "ESRCH")
912
- throw err;
913
- }
914
- }
915
- function killAll(tree, signal, callback) {
916
- const killed = {};
917
- try {
918
- for (const pid of Object.keys(tree).map(Number)) {
919
- for (const child of tree[pid]) {
920
- if (!killed[child]) {
921
- killPid(child, signal);
922
- killed[child] = true;
923
- }
924
- }
925
- if (!killed[pid]) {
926
- killPid(pid, signal);
927
- killed[pid] = true;
928
- }
929
- }
930
- }
931
- catch (err) {
932
- if (callback)
933
- return callback(err);
934
- throw err;
935
- }
936
- callback?.();
937
- }
938
- function buildProcessTree(parentPid, tree, pidsToProcess, spawnList, cb) {
939
- const ps = spawnList(parentPid);
940
- let allData = "";
941
- ps.stdout.on("data", (data) => {
942
- allData += data.toString("ascii");
943
- });
944
- ps.on("close", (code) => {
945
- delete pidsToProcess[parentPid];
946
- if (code !== 0) {
947
- if (Object.keys(pidsToProcess).length === 0)
948
- cb();
949
- return;
950
- }
951
- const matches = allData.match(/\d+/g);
952
- if (matches) {
953
- for (const pidStr of matches) {
954
- const pid = parseInt(pidStr, 10);
955
- tree[parentPid].push(pid);
956
- tree[pid] = [];
957
- pidsToProcess[pid] = 1;
958
- buildProcessTree(pid, tree, pidsToProcess, spawnList, cb);
959
- }
960
- }
961
- });
962
- }
963
- function treeKill(pid, signalOrCallback, callback) {
964
- let signal;
965
- if (typeof signalOrCallback === "function") {
966
- callback = signalOrCallback;
967
- signal = undefined;
968
- }
969
- else {
970
- signal = signalOrCallback;
971
- }
972
- pid = parseInt(pid, 10);
973
- if (Number.isNaN(pid)) {
974
- const err = new Error("pid must be a number");
975
- if (callback)
976
- return callback(err);
977
- throw err;
978
- }
979
- const tree = { [pid]: [] };
980
- const pidsToProcess = { [pid]: 1 };
981
- switch (process.platform) {
982
- case "win32":
983
- child_process.exec(`taskkill /pid ${pid} /T /F`, (err) => callback?.(err ?? undefined));
984
- break;
985
- case "darwin":
986
- buildProcessTree(pid, tree, pidsToProcess, (parentPid) => child_process.spawn("pgrep", ["-P", String(parentPid)]), () => killAll(tree, signal, callback));
987
- break;
988
- default: // Linux
989
- buildProcessTree(pid, tree, pidsToProcess, (parentPid) => child_process.spawn("ps", ["-o", "pid", "--no-headers", "--ppid", String(parentPid)]), () => killAll(tree, signal, callback));
990
- break;
991
- }
992
- }
993
-
994
- const DRAIN_MAX_AWAIT = 250;
995
- const drainStream = (stream) => new Promise((resolve) => {
996
- if (stream.writableLength === 0) {
997
- stream.write("", () => resolve());
998
- return;
999
- }
1000
- stream.once("drain", () => {
1001
- stream.write("", () => resolve());
1002
- });
1003
- });
1004
- const flushStream = (stream) => {
1005
- const handle = stream._handle;
1006
- if (handle && typeof handle.setBlocking === "function") {
1007
- handle.setBlocking(true);
1008
- return new Promise((resolve) => stream.write("", () => resolve()));
1009
- }
1010
- return drainStream(stream);
1011
- };
1012
- const kill = functoolsKit.singleshot(async (code = -1) => {
1013
- await Promise.race([
1014
- Promise.all([
1015
- flushStream(process.stdout),
1016
- flushStream(process.stderr)
1017
- ]),
1018
- functoolsKit.sleep(DRAIN_MAX_AWAIT),
1019
- ]);
1020
- treeKill(process.pid, "SIGKILL", () => {
1021
- process.exit(code);
1022
- });
1023
- });
1024
- const notifyKill = functoolsKit.singleshot(() => {
1025
- console.log("Press Ctrl+C again to force quit.");
1026
- process.on("SIGINT", () => kill());
1027
- });
1028
-
1029
1036
  // Must match the getArgs --cacheInterval default ("1m, 15m, 30m, 1h, 4h"):
1030
1037
  // this fallback is only reachable with an explicit --cacheInterval ""
1031
1038
  const DEFAULT_CACHE_LIST$1 = ["1m", "15m", "30m", "1h", "4h"];
@@ -3542,7 +3549,7 @@ const main$h = async () => {
3542
3549
  if (MODES.some((mode) => values[mode])) {
3543
3550
  return;
3544
3551
  }
3545
- process.stdout.write(`@backtest-kit/cli ${"15.5.0"}\n`);
3552
+ process.stdout.write(`@backtest-kit/cli ${"16.0.0"}\n`);
3546
3553
  process.stdout.write("\n");
3547
3554
  process.stdout.write(`Run with --help to see available commands.\n`);
3548
3555
  process.stdout.write("\n");
@@ -4852,7 +4859,7 @@ const main$1 = async () => {
4852
4859
  if (!values.help) {
4853
4860
  return;
4854
4861
  }
4855
- process.stdout.write(`@backtest-kit/cli ${"15.5.0"}\n\n`);
4862
+ process.stdout.write(`@backtest-kit/cli ${"16.0.0"}\n\n`);
4856
4863
  process.stdout.write(HELP_TEXT);
4857
4864
  process.exit(0);
4858
4865
  };
@@ -4866,7 +4873,7 @@ const main = async () => {
4866
4873
  if (!values.version) {
4867
4874
  return;
4868
4875
  }
4869
- process.stdout.write(`@backtest-kit/cli ${"15.5.0"}\n`);
4876
+ process.stdout.write(`@backtest-kit/cli ${"16.0.0"}\n`);
4870
4877
  process.exit(0);
4871
4878
  };
4872
4879
  main();
package/build/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import * as BacktestKit from 'backtest-kit';
3
- import { setConfig, emitters, Notification, Cron, Recent, Storage, Markdown, Report, Dump, State, Memory, MarkdownWriter, ReportWriter, PersistSignalAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistPartialAdapter, PersistBreakevenAdapter, PersistCandleAdapter, PersistStorageAdapter, PersistNotificationAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistIntervalAdapter, PersistMemoryAdapter, PersistRecentAdapter, PersistStateAdapter, PersistSessionAdapter, PersistStrategyAdapter, Log, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, RecentLive, RecentBacktest, Broker, SessionLive, SessionBacktest, MemoryLive, MemoryBacktest, StateLive, StateBacktest, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, System, Cache, Interval, alignToInterval, addWalkerSchema, overrideWalkerSchema, Walker, listenDoneWalker, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync, listenSignalNotify, Exchange } from 'backtest-kit';
4
- import { singleshot, BehaviorSubject, Subject, getErrorMessage, errorData, str, compose, sleep, createAwaiter, execpool, queued, randomString, TIMEOUT_SYMBOL, typo, retry, trycatch, memoize, isObject } from 'functools-kit';
3
+ import { setConfig, listenExit, emitters, Notification, Cron, Recent, Storage, Markdown, Report, Dump, State, Memory, MarkdownWriter, ReportWriter, PersistSignalAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistPartialAdapter, PersistBreakevenAdapter, PersistCandleAdapter, PersistStorageAdapter, PersistNotificationAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistIntervalAdapter, PersistMemoryAdapter, PersistRecentAdapter, PersistStateAdapter, PersistSessionAdapter, PersistStrategyAdapter, Log, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, RecentLive, RecentBacktest, Broker, SessionLive, SessionBacktest, MemoryLive, MemoryBacktest, StateLive, StateBacktest, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, shutdown, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, System, Cache, Interval, alignToInterval, addWalkerSchema, overrideWalkerSchema, Walker, listenDoneWalker, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit, listenSync, listenSignalNotify, Exchange } from 'backtest-kit';
4
+ import { singleshot, sleep, getErrorMessage, errorData, BehaviorSubject, Subject, str, compose, createAwaiter, execpool, queued, randomString, TIMEOUT_SYMBOL, typo, retry, trycatch, memoize, isObject } from 'functools-kit';
5
+ import { exec, spawn } from 'child_process';
5
6
  import fs, { constants, realpathSync } from 'fs';
6
7
  import * as stackTrace from 'stack-trace';
7
8
  import path, { join, resolve, dirname, basename, extname } from 'path';
@@ -10,7 +11,6 @@ import dotenv from 'dotenv';
10
11
  import { createActivator } from 'di-kit';
11
12
  import { fileURLToPath } from 'url';
12
13
  import { parseArgs } from 'util';
13
- import { exec, spawn } from 'child_process';
14
14
  import * as BacktestKitUi from '@backtest-kit/ui';
15
15
  import { lib, serve } from '@backtest-kit/ui';
16
16
  import QuickChart from 'quickchart-js';
@@ -32,6 +32,129 @@ import { run as run$1, Code, toMarkdown } from '@backtest-kit/pinets';
32
32
  import * as BacktestKitSignals from '@backtest-kit/signals';
33
33
  import open from 'open';
34
34
 
35
+ function killPid(pid, signal) {
36
+ try {
37
+ process.kill(pid, signal);
38
+ }
39
+ catch (err) {
40
+ if (err.code !== "ESRCH")
41
+ throw err;
42
+ }
43
+ }
44
+ function killAll(tree, signal, callback) {
45
+ const killed = {};
46
+ try {
47
+ for (const pid of Object.keys(tree).map(Number)) {
48
+ for (const child of tree[pid]) {
49
+ if (!killed[child]) {
50
+ killPid(child, signal);
51
+ killed[child] = true;
52
+ }
53
+ }
54
+ if (!killed[pid]) {
55
+ killPid(pid, signal);
56
+ killed[pid] = true;
57
+ }
58
+ }
59
+ }
60
+ catch (err) {
61
+ if (callback)
62
+ return callback(err);
63
+ throw err;
64
+ }
65
+ callback?.();
66
+ }
67
+ function buildProcessTree(parentPid, tree, pidsToProcess, spawnList, cb) {
68
+ const ps = spawnList(parentPid);
69
+ let allData = "";
70
+ ps.stdout.on("data", (data) => {
71
+ allData += data.toString("ascii");
72
+ });
73
+ ps.on("close", (code) => {
74
+ delete pidsToProcess[parentPid];
75
+ if (code !== 0) {
76
+ if (Object.keys(pidsToProcess).length === 0)
77
+ cb();
78
+ return;
79
+ }
80
+ const matches = allData.match(/\d+/g);
81
+ if (matches) {
82
+ for (const pidStr of matches) {
83
+ const pid = parseInt(pidStr, 10);
84
+ tree[parentPid].push(pid);
85
+ tree[pid] = [];
86
+ pidsToProcess[pid] = 1;
87
+ buildProcessTree(pid, tree, pidsToProcess, spawnList, cb);
88
+ }
89
+ }
90
+ });
91
+ }
92
+ function treeKill(pid, signalOrCallback, callback) {
93
+ let signal;
94
+ if (typeof signalOrCallback === "function") {
95
+ callback = signalOrCallback;
96
+ signal = undefined;
97
+ }
98
+ else {
99
+ signal = signalOrCallback;
100
+ }
101
+ pid = parseInt(pid, 10);
102
+ if (Number.isNaN(pid)) {
103
+ const err = new Error("pid must be a number");
104
+ if (callback)
105
+ return callback(err);
106
+ throw err;
107
+ }
108
+ const tree = { [pid]: [] };
109
+ const pidsToProcess = { [pid]: 1 };
110
+ switch (process.platform) {
111
+ case "win32":
112
+ exec(`taskkill /pid ${pid} /T /F`, (err) => callback?.(err ?? undefined));
113
+ break;
114
+ case "darwin":
115
+ buildProcessTree(pid, tree, pidsToProcess, (parentPid) => spawn("pgrep", ["-P", String(parentPid)]), () => killAll(tree, signal, callback));
116
+ break;
117
+ default: // Linux
118
+ buildProcessTree(pid, tree, pidsToProcess, (parentPid) => spawn("ps", ["-o", "pid", "--no-headers", "--ppid", String(parentPid)]), () => killAll(tree, signal, callback));
119
+ break;
120
+ }
121
+ }
122
+
123
+ const DRAIN_MAX_AWAIT = 250;
124
+ const drainStream = (stream) => new Promise((resolve) => {
125
+ if (stream.writableLength === 0) {
126
+ stream.write("", () => resolve());
127
+ return;
128
+ }
129
+ stream.once("drain", () => {
130
+ stream.write("", () => resolve());
131
+ });
132
+ });
133
+ const flushStream = (stream) => {
134
+ const handle = stream._handle;
135
+ if (handle && typeof handle.setBlocking === "function") {
136
+ handle.setBlocking(true);
137
+ return new Promise((resolve) => stream.write("", () => resolve()));
138
+ }
139
+ return drainStream(stream);
140
+ };
141
+ const kill = singleshot(async (code = -1) => {
142
+ await Promise.race([
143
+ Promise.all([
144
+ flushStream(process.stdout),
145
+ flushStream(process.stderr)
146
+ ]),
147
+ sleep(DRAIN_MAX_AWAIT),
148
+ ]);
149
+ treeKill(process.pid, "SIGKILL", () => {
150
+ process.exit(code);
151
+ });
152
+ });
153
+ const notifyKill = singleshot(() => {
154
+ console.log("Press Ctrl+C again to force quit.");
155
+ process.on("SIGINT", () => kill());
156
+ });
157
+
35
158
  setConfig({
36
159
  CC_MAX_NOTIFICATIONS: 5000,
37
160
  CC_MAX_SIGNALS: 750,
@@ -66,6 +189,13 @@ setConfig({
66
189
  setConfig({
67
190
  CC_WALKER_MARKDOWN_TOP_N: 10,
68
191
  });
192
+ listenExit((error) => {
193
+ console.error("Exiting due to error:", {
194
+ errorMessage: getErrorMessage(error),
195
+ errorData: errorData(error),
196
+ });
197
+ kill();
198
+ });
69
199
 
70
200
  const getEntrySubject = singleshot(() => {
71
201
  const entrySubject = emitters["entrySubject"];
@@ -878,129 +1008,6 @@ const notifyVerbose = singleshot(() => {
878
1008
  });
879
1009
  });
880
1010
 
881
- function killPid(pid, signal) {
882
- try {
883
- process.kill(pid, signal);
884
- }
885
- catch (err) {
886
- if (err.code !== "ESRCH")
887
- throw err;
888
- }
889
- }
890
- function killAll(tree, signal, callback) {
891
- const killed = {};
892
- try {
893
- for (const pid of Object.keys(tree).map(Number)) {
894
- for (const child of tree[pid]) {
895
- if (!killed[child]) {
896
- killPid(child, signal);
897
- killed[child] = true;
898
- }
899
- }
900
- if (!killed[pid]) {
901
- killPid(pid, signal);
902
- killed[pid] = true;
903
- }
904
- }
905
- }
906
- catch (err) {
907
- if (callback)
908
- return callback(err);
909
- throw err;
910
- }
911
- callback?.();
912
- }
913
- function buildProcessTree(parentPid, tree, pidsToProcess, spawnList, cb) {
914
- const ps = spawnList(parentPid);
915
- let allData = "";
916
- ps.stdout.on("data", (data) => {
917
- allData += data.toString("ascii");
918
- });
919
- ps.on("close", (code) => {
920
- delete pidsToProcess[parentPid];
921
- if (code !== 0) {
922
- if (Object.keys(pidsToProcess).length === 0)
923
- cb();
924
- return;
925
- }
926
- const matches = allData.match(/\d+/g);
927
- if (matches) {
928
- for (const pidStr of matches) {
929
- const pid = parseInt(pidStr, 10);
930
- tree[parentPid].push(pid);
931
- tree[pid] = [];
932
- pidsToProcess[pid] = 1;
933
- buildProcessTree(pid, tree, pidsToProcess, spawnList, cb);
934
- }
935
- }
936
- });
937
- }
938
- function treeKill(pid, signalOrCallback, callback) {
939
- let signal;
940
- if (typeof signalOrCallback === "function") {
941
- callback = signalOrCallback;
942
- signal = undefined;
943
- }
944
- else {
945
- signal = signalOrCallback;
946
- }
947
- pid = parseInt(pid, 10);
948
- if (Number.isNaN(pid)) {
949
- const err = new Error("pid must be a number");
950
- if (callback)
951
- return callback(err);
952
- throw err;
953
- }
954
- const tree = { [pid]: [] };
955
- const pidsToProcess = { [pid]: 1 };
956
- switch (process.platform) {
957
- case "win32":
958
- exec(`taskkill /pid ${pid} /T /F`, (err) => callback?.(err ?? undefined));
959
- break;
960
- case "darwin":
961
- buildProcessTree(pid, tree, pidsToProcess, (parentPid) => spawn("pgrep", ["-P", String(parentPid)]), () => killAll(tree, signal, callback));
962
- break;
963
- default: // Linux
964
- buildProcessTree(pid, tree, pidsToProcess, (parentPid) => spawn("ps", ["-o", "pid", "--no-headers", "--ppid", String(parentPid)]), () => killAll(tree, signal, callback));
965
- break;
966
- }
967
- }
968
-
969
- const DRAIN_MAX_AWAIT = 250;
970
- const drainStream = (stream) => new Promise((resolve) => {
971
- if (stream.writableLength === 0) {
972
- stream.write("", () => resolve());
973
- return;
974
- }
975
- stream.once("drain", () => {
976
- stream.write("", () => resolve());
977
- });
978
- });
979
- const flushStream = (stream) => {
980
- const handle = stream._handle;
981
- if (handle && typeof handle.setBlocking === "function") {
982
- handle.setBlocking(true);
983
- return new Promise((resolve) => stream.write("", () => resolve()));
984
- }
985
- return drainStream(stream);
986
- };
987
- const kill = singleshot(async (code = -1) => {
988
- await Promise.race([
989
- Promise.all([
990
- flushStream(process.stdout),
991
- flushStream(process.stderr)
992
- ]),
993
- sleep(DRAIN_MAX_AWAIT),
994
- ]);
995
- treeKill(process.pid, "SIGKILL", () => {
996
- process.exit(code);
997
- });
998
- });
999
- const notifyKill = singleshot(() => {
1000
- console.log("Press Ctrl+C again to force quit.");
1001
- process.on("SIGINT", () => kill());
1002
- });
1003
-
1004
1011
  // Must match the getArgs --cacheInterval default ("1m, 15m, 30m, 1h, 4h"):
1005
1012
  // this fallback is only reachable with an explicit --cacheInterval ""
1006
1013
  const DEFAULT_CACHE_LIST$1 = ["1m", "15m", "30m", "1h", "4h"];
@@ -3510,7 +3517,7 @@ const main$h = async () => {
3510
3517
  if (MODES.some((mode) => values[mode])) {
3511
3518
  return;
3512
3519
  }
3513
- process.stdout.write(`@backtest-kit/cli ${"15.5.0"}\n`);
3520
+ process.stdout.write(`@backtest-kit/cli ${"16.0.0"}\n`);
3514
3521
  process.stdout.write("\n");
3515
3522
  process.stdout.write(`Run with --help to see available commands.\n`);
3516
3523
  process.stdout.write("\n");
@@ -4820,7 +4827,7 @@ const main$1 = async () => {
4820
4827
  if (!values.help) {
4821
4828
  return;
4822
4829
  }
4823
- process.stdout.write(`@backtest-kit/cli ${"15.5.0"}\n\n`);
4830
+ process.stdout.write(`@backtest-kit/cli ${"16.0.0"}\n\n`);
4824
4831
  process.stdout.write(HELP_TEXT);
4825
4832
  process.exit(0);
4826
4833
  };
@@ -4834,7 +4841,7 @@ const main = async () => {
4834
4841
  if (!values.version) {
4835
4842
  return;
4836
4843
  }
4837
- process.stdout.write(`@backtest-kit/cli ${"15.5.0"}\n`);
4844
+ process.stdout.write(`@backtest-kit/cli ${"16.0.0"}\n`);
4838
4845
  process.exit(0);
4839
4846
  };
4840
4847
  main();
@@ -15,17 +15,17 @@
15
15
  "@types/node": "25.6.0"
16
16
  },
17
17
  "dependencies": {
18
- "@backtest-kit/cli": "15.5.0",
19
- "@backtest-kit/graph": "15.5.0",
20
- "@backtest-kit/pinets": "15.5.0",
21
- "@backtest-kit/signals": "15.5.0",
22
- "@backtest-kit/ui": "15.5.0",
18
+ "@backtest-kit/cli": "16.0.0",
19
+ "@backtest-kit/graph": "16.0.0",
20
+ "@backtest-kit/pinets": "16.0.0",
21
+ "@backtest-kit/signals": "16.0.0",
22
+ "@backtest-kit/ui": "16.0.0",
23
23
  "@tavily/core": "0.7.2",
24
24
  "@tensorflow/tfjs": "4.22.0",
25
25
  "@tensorflow/tfjs-backend-wasm": "4.22.0",
26
26
  "@tensorflow/tfjs-core": "4.22.0",
27
27
  "agent-swarm-kit": "5.1.0",
28
- "backtest-kit": "15.5.0",
28
+ "backtest-kit": "16.0.0",
29
29
  "dayjs": "1.11.20",
30
30
  "functools-kit": "4.0.0",
31
31
  "garch": "2.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtest-kit/cli",
3
- "version": "15.5.0",
3
+ "version": "16.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",
@@ -63,11 +63,11 @@
63
63
  "devDependencies": {
64
64
  "@babel/plugin-transform-modules-umd": "7.27.1",
65
65
  "@babel/standalone": "7.29.1",
66
- "@backtest-kit/graph": "15.5.0",
67
- "@backtest-kit/ollama": "15.5.0",
68
- "@backtest-kit/pinets": "15.5.0",
69
- "@backtest-kit/signals": "15.5.0",
70
- "@backtest-kit/ui": "15.5.0",
66
+ "@backtest-kit/graph": "16.0.0",
67
+ "@backtest-kit/ollama": "16.0.0",
68
+ "@backtest-kit/pinets": "16.0.0",
69
+ "@backtest-kit/signals": "16.0.0",
70
+ "@backtest-kit/ui": "16.0.0",
71
71
  "@rollup/plugin-replace": "6.0.3",
72
72
  "@rollup/plugin-typescript": "11.1.6",
73
73
  "@types/image-size": "0.7.0",
@@ -75,7 +75,7 @@
75
75
  "@types/mustache": "4.2.6",
76
76
  "@types/node": "22.9.0",
77
77
  "@types/stack-trace": "0.0.33",
78
- "backtest-kit": "15.5.0",
78
+ "backtest-kit": "16.0.0",
79
79
  "glob": "11.0.1",
80
80
  "markdown-it": "14.1.1",
81
81
  "rimraf": "6.0.1",
@@ -92,14 +92,14 @@
92
92
  "peerDependencies": {
93
93
  "@babel/plugin-transform-modules-umd": "^7.27.1",
94
94
  "@babel/standalone": "^7.29.1",
95
- "@backtest-kit/graph": "^15.5.0",
96
- "@backtest-kit/ollama": "^15.5.0",
97
- "@backtest-kit/pinets": "^15.5.0",
98
- "@backtest-kit/signals": "^15.5.0",
99
- "@backtest-kit/ui": "^15.5.0",
95
+ "@backtest-kit/graph": "^16.0.0",
96
+ "@backtest-kit/ollama": "^16.0.0",
97
+ "@backtest-kit/pinets": "^16.0.0",
98
+ "@backtest-kit/signals": "^16.0.0",
99
+ "@backtest-kit/ui": "^16.0.0",
100
100
  "pinets": "^0.9.29",
101
101
  "ccxt": "^4.5.39",
102
- "backtest-kit": "^15.5.0",
102
+ "backtest-kit": "^16.0.0",
103
103
  "markdown-it": "^14.1.1",
104
104
  "typescript": "^5.0.0"
105
105
  },
@@ -13,12 +13,12 @@
13
13
  "license": "ISC",
14
14
  "type": "commonjs",
15
15
  "dependencies": {
16
- "@backtest-kit/cli": "^15.5.0",
17
- "@backtest-kit/graph": "^15.5.0",
18
- "@backtest-kit/pinets": "^15.5.0",
19
- "@backtest-kit/ui": "^15.5.0",
16
+ "@backtest-kit/cli": "^16.0.0",
17
+ "@backtest-kit/graph": "^16.0.0",
18
+ "@backtest-kit/pinets": "^16.0.0",
19
+ "@backtest-kit/ui": "^16.0.0",
20
20
  "agent-swarm-kit": "^5.1.0",
21
- "backtest-kit": "^15.5.0",
21
+ "backtest-kit": "^16.0.0",
22
22
  "functools-kit": "^4.0.0",
23
23
  "garch": "^2.0.0",
24
24
  "get-moment-stamp": "^3.0.0",