@tradejs/cli 1.0.5 → 1.0.6
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 +4 -1
- package/dist/cli.js +1910 -813
- package/dist/lib/aiTrainMetrics.js +150 -0
- package/dist/scripts/aiExport.js +192 -0
- package/dist/scripts/aiExportSelect.js +135 -0
- package/dist/scripts/aiTrain.js +2239 -0
- package/dist/scripts/backtest.js +218 -32
- package/dist/scripts/derivativesIngest.js +5 -0
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +21 -12
- package/dist/scripts/mlExport.js +112 -13
- package/dist/scripts/mlExportSelect.js +43 -9
- package/dist/scripts/mlTrainLatestSelect.js +4 -3
- package/dist/scripts/resolveExportStrategy.js +133 -0
- package/dist/scripts/selectStrategy.js +4 -3
- package/dist/scripts/signals.js +109 -25
- package/dist/scripts/spawnSiblingScript.js +71 -0
- package/dist/workers/testerWorker.js +13 -2
- package/package.json +11 -9
|
@@ -22,9 +22,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
24
|
|
|
25
|
-
// src/scripts/mlExportSelect.ts
|
|
26
|
-
var import_child_process = require("child_process");
|
|
27
|
-
|
|
28
25
|
// src/scripts/selectStrategy.ts
|
|
29
26
|
var import_readline = __toESM(require("readline"));
|
|
30
27
|
var import_chalk = __toESM(require("chalk"));
|
|
@@ -48,9 +45,10 @@ var getStrategyChoices = async () => {
|
|
|
48
45
|
"VolumeDivergence"
|
|
49
46
|
];
|
|
50
47
|
};
|
|
51
|
-
var selectStrategy = async (promptLabel = "Select strategy") => {
|
|
52
|
-
const strategies = await getStrategyChoices();
|
|
53
|
-
const
|
|
48
|
+
var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
49
|
+
const strategies = options?.strategies && options.strategies.length ? options.strategies : await getStrategyChoices();
|
|
50
|
+
const preferredDefault = options?.defaultStrategy || defaultStrategy;
|
|
51
|
+
const fallbackStrategy = strategies.includes(preferredDefault) ? preferredDefault : strategies[0];
|
|
54
52
|
if (!process.stdin.isTTY) {
|
|
55
53
|
return fallbackStrategy;
|
|
56
54
|
}
|
|
@@ -88,12 +86,48 @@ var selectStrategy = async (promptLabel = "Select strategy") => {
|
|
|
88
86
|
return fallbackStrategy;
|
|
89
87
|
};
|
|
90
88
|
|
|
89
|
+
// src/scripts/spawnSiblingScript.ts
|
|
90
|
+
var import_fs = __toESM(require("fs"));
|
|
91
|
+
var import_path = __toESM(require("path"));
|
|
92
|
+
var import_child_process = require("child_process");
|
|
93
|
+
var spawnSiblingScript = (currentDir, scriptBaseName, extraArgs) => {
|
|
94
|
+
const searchDirs = [currentDir, import_path.default.resolve(currentDir, "scripts")];
|
|
95
|
+
const candidates = searchDirs.flatMap((dir) => [
|
|
96
|
+
import_path.default.resolve(dir, `${scriptBaseName}.js`),
|
|
97
|
+
import_path.default.resolve(dir, `${scriptBaseName}.ts`)
|
|
98
|
+
]);
|
|
99
|
+
const scriptPath = candidates.find((candidate) => import_fs.default.existsSync(candidate));
|
|
100
|
+
if (!scriptPath) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Script "${scriptBaseName}" not found. Checked: ${candidates.join(", ")}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const commandArgs = scriptPath.endsWith(".ts") ? [
|
|
106
|
+
"-r",
|
|
107
|
+
"ts-node/register",
|
|
108
|
+
"-r",
|
|
109
|
+
"tsconfig-paths/register",
|
|
110
|
+
scriptPath,
|
|
111
|
+
...extraArgs
|
|
112
|
+
] : [scriptPath, ...extraArgs];
|
|
113
|
+
const result = (0, import_child_process.spawnSync)(process.execPath, commandArgs, {
|
|
114
|
+
env: process.env,
|
|
115
|
+
stdio: "inherit"
|
|
116
|
+
});
|
|
117
|
+
if (result.error) {
|
|
118
|
+
throw result.error;
|
|
119
|
+
}
|
|
120
|
+
return result.status ?? 1;
|
|
121
|
+
};
|
|
122
|
+
|
|
91
123
|
// src/scripts/mlExportSelect.ts
|
|
92
124
|
var run = async () => {
|
|
93
125
|
const selected = await selectStrategy();
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
126
|
+
const status = spawnSiblingScript(__dirname, "mlExport", [
|
|
127
|
+
"--strategy",
|
|
128
|
+
selected
|
|
129
|
+
]);
|
|
130
|
+
process.exit(status);
|
|
97
131
|
};
|
|
98
132
|
run().catch((err) => {
|
|
99
133
|
console.error("Failed to select strategy:", err);
|
|
@@ -56,9 +56,10 @@ var getStrategyChoices = async () => {
|
|
|
56
56
|
"VolumeDivergence"
|
|
57
57
|
];
|
|
58
58
|
};
|
|
59
|
-
var selectStrategy = async (promptLabel = "Select strategy") => {
|
|
60
|
-
const strategies = await getStrategyChoices();
|
|
61
|
-
const
|
|
59
|
+
var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
60
|
+
const strategies = options?.strategies && options.strategies.length ? options.strategies : await getStrategyChoices();
|
|
61
|
+
const preferredDefault = options?.defaultStrategy || defaultStrategy;
|
|
62
|
+
const fallbackStrategy = strategies.includes(preferredDefault) ? preferredDefault : strategies[0];
|
|
62
63
|
if (!process.stdin.isTTY) {
|
|
63
64
|
return fallbackStrategy;
|
|
64
65
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/scripts/resolveExportStrategy.ts
|
|
31
|
+
var resolveExportStrategy_exports = {};
|
|
32
|
+
__export(resolveExportStrategy_exports, {
|
|
33
|
+
resolveExportStrategy: () => resolveExportStrategy
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(resolveExportStrategy_exports);
|
|
36
|
+
|
|
37
|
+
// src/scripts/selectStrategy.ts
|
|
38
|
+
var import_readline = __toESM(require("readline"));
|
|
39
|
+
var import_chalk = __toESM(require("chalk"));
|
|
40
|
+
var import_strategies = require("@tradejs/node/strategies");
|
|
41
|
+
var defaultStrategy = "TrendLine";
|
|
42
|
+
var projectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
43
|
+
var getStrategyChoices = async () => {
|
|
44
|
+
try {
|
|
45
|
+
const loaded = await (0, import_strategies.getAvailableStrategyNames)(projectRoot);
|
|
46
|
+
if (loaded.length) {
|
|
47
|
+
return loaded;
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.warn(`Failed to load strategy list: ${String(error)}`);
|
|
51
|
+
}
|
|
52
|
+
return [
|
|
53
|
+
"Breakout",
|
|
54
|
+
"MaStrategy",
|
|
55
|
+
"AdaptiveMomentumRibbon",
|
|
56
|
+
"TrendLine",
|
|
57
|
+
"VolumeDivergence"
|
|
58
|
+
];
|
|
59
|
+
};
|
|
60
|
+
var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
61
|
+
const strategies = options?.strategies && options.strategies.length ? options.strategies : await getStrategyChoices();
|
|
62
|
+
const preferredDefault = options?.defaultStrategy || defaultStrategy;
|
|
63
|
+
const fallbackStrategy = strategies.includes(preferredDefault) ? preferredDefault : strategies[0];
|
|
64
|
+
if (!process.stdin.isTTY) {
|
|
65
|
+
return fallbackStrategy;
|
|
66
|
+
}
|
|
67
|
+
console.log(import_chalk.default.cyan("Available strategies:"));
|
|
68
|
+
strategies.forEach((name, index) => {
|
|
69
|
+
const isDefault = name === defaultStrategy;
|
|
70
|
+
const label = isDefault ? import_chalk.default.green(name) : name;
|
|
71
|
+
const suffix = isDefault ? import_chalk.default.gray(" (default)") : "";
|
|
72
|
+
console.log(` ${import_chalk.default.yellow(String(index + 1))}) ${label}${suffix}`);
|
|
73
|
+
});
|
|
74
|
+
const rl = import_readline.default.createInterface({
|
|
75
|
+
input: process.stdin,
|
|
76
|
+
output: process.stdout
|
|
77
|
+
});
|
|
78
|
+
const question = (text) => new Promise((resolve) => rl.question(text, resolve));
|
|
79
|
+
const answer = await question(
|
|
80
|
+
`${promptLabel} [${import_chalk.default.green(fallbackStrategy)}]: `
|
|
81
|
+
);
|
|
82
|
+
rl.close();
|
|
83
|
+
const trimmed = answer.trim();
|
|
84
|
+
if (!trimmed) {
|
|
85
|
+
return fallbackStrategy;
|
|
86
|
+
}
|
|
87
|
+
const asNumber = Number(trimmed);
|
|
88
|
+
if (Number.isFinite(asNumber) && asNumber >= 1 && asNumber <= strategies.length) {
|
|
89
|
+
return strategies[asNumber - 1];
|
|
90
|
+
}
|
|
91
|
+
const byName = strategies.find(
|
|
92
|
+
(name) => name.toLowerCase() === trimmed.toLowerCase()
|
|
93
|
+
);
|
|
94
|
+
if (byName) {
|
|
95
|
+
return byName;
|
|
96
|
+
}
|
|
97
|
+
console.warn(`Unknown strategy "${trimmed}", using ${fallbackStrategy}.`);
|
|
98
|
+
return fallbackStrategy;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/scripts/resolveExportStrategy.ts
|
|
102
|
+
var resolveExportStrategy = async ({
|
|
103
|
+
explicitStrategy,
|
|
104
|
+
outDir,
|
|
105
|
+
datasetLabel,
|
|
106
|
+
promptLabel,
|
|
107
|
+
listStrategies
|
|
108
|
+
}) => {
|
|
109
|
+
const raw = String(explicitStrategy || "").trim();
|
|
110
|
+
if (raw) {
|
|
111
|
+
return raw;
|
|
112
|
+
}
|
|
113
|
+
const availableStrategies = await listStrategies({ outDir });
|
|
114
|
+
if (!availableStrategies.length) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
if (availableStrategies.length === 1) {
|
|
118
|
+
return availableStrategies[0];
|
|
119
|
+
}
|
|
120
|
+
if (!process.stdin.isTTY) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Multiple ${datasetLabel} chunk strategies found in ${outDir}: ${availableStrategies.join(", ")}. Pass --strategy.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return selectStrategy(promptLabel, {
|
|
126
|
+
strategies: availableStrategies,
|
|
127
|
+
defaultStrategy: availableStrategies[0]
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
131
|
+
0 && (module.exports = {
|
|
132
|
+
resolveExportStrategy
|
|
133
|
+
});
|
|
@@ -55,9 +55,10 @@ var getStrategyChoices = async () => {
|
|
|
55
55
|
"VolumeDivergence"
|
|
56
56
|
];
|
|
57
57
|
};
|
|
58
|
-
var selectStrategy = async (promptLabel = "Select strategy") => {
|
|
59
|
-
const strategies = await getStrategyChoices();
|
|
60
|
-
const
|
|
58
|
+
var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
59
|
+
const strategies = options?.strategies && options.strategies.length ? options.strategies : await getStrategyChoices();
|
|
60
|
+
const preferredDefault = options?.defaultStrategy || defaultStrategy;
|
|
61
|
+
const fallbackStrategy = strategies.includes(preferredDefault) ? preferredDefault : strategies[0];
|
|
61
62
|
if (!process.stdin.isTTY) {
|
|
62
63
|
return fallbackStrategy;
|
|
63
64
|
}
|
package/dist/scripts/signals.js
CHANGED
|
@@ -5,6 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
8
12
|
var __copyProps = (to, from, except, desc) => {
|
|
9
13
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
14
|
for (let key of __getOwnPropNames(from))
|
|
@@ -21,8 +25,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
26
|
mod
|
|
23
27
|
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
24
29
|
|
|
25
30
|
// src/scripts/signals.ts
|
|
31
|
+
var signals_exports = {};
|
|
32
|
+
__export(signals_exports, {
|
|
33
|
+
signals: () => signals
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(signals_exports);
|
|
26
36
|
var import_config = require("dotenv/config");
|
|
27
37
|
var import_args = __toESM(require("args"));
|
|
28
38
|
var import_progress = __toESM(require("progress"));
|
|
@@ -46,6 +56,11 @@ import_args.default.option(["S", "skipScreenshots"], "Skip screenshot generation
|
|
|
46
56
|
import_args.default.option(["u", "updateOnly"], "Only update tickers history", false);
|
|
47
57
|
import_args.default.option(["C", "cacheOnly"], "Do not update tickers history", false);
|
|
48
58
|
import_args.default.option(["L", "showTickersList"], "Just show only ticker list", false);
|
|
59
|
+
import_args.default.option(
|
|
60
|
+
["R", "showSkipStats"],
|
|
61
|
+
"Show aggregated skip stats by strategy",
|
|
62
|
+
false
|
|
63
|
+
);
|
|
49
64
|
import_args.default.option(["c", "chunk"], "Split by chunks, ex. 1/3");
|
|
50
65
|
import_args.default.option(["U", "user"], "Use user confg", "root");
|
|
51
66
|
import_args.default.option(
|
|
@@ -53,11 +68,9 @@ import_args.default.option(
|
|
|
53
68
|
"Connector provider or name for signals (e.g. bybit, binance, coinbase, custom)",
|
|
54
69
|
"bybit"
|
|
55
70
|
);
|
|
56
|
-
var PRELOAD_START = (0, import_time.getTimestamp)(import_constants.
|
|
71
|
+
var PRELOAD_START = (0, import_time.getTimestamp)(import_constants.SIGNALS_CLI_PRELOAD_DAYS);
|
|
57
72
|
var projectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
58
73
|
var flags = import_args.default.parse(process.argv);
|
|
59
|
-
var minTouches = parseInt(flags.points);
|
|
60
|
-
var offset = parseInt(flags.offset);
|
|
61
74
|
var interval = flags.timeframe.toString();
|
|
62
75
|
var formatElapsed = (startedAt) => `${((Date.now() - startedAt) / 1e3).toFixed(1)}s`;
|
|
63
76
|
var resolveStrategyNameByConfigKey = (userName, key) => {
|
|
@@ -98,6 +111,45 @@ var loadRuntimeStrategies = async (userName) => {
|
|
|
98
111
|
);
|
|
99
112
|
return strategyConfigs.filter(Boolean);
|
|
100
113
|
};
|
|
114
|
+
var createStrategySkipStats = (runtimeStrategies) => new Map(
|
|
115
|
+
runtimeStrategies.map(({ strategyName }) => [
|
|
116
|
+
strategyName,
|
|
117
|
+
{
|
|
118
|
+
evaluated: 0,
|
|
119
|
+
signals: 0,
|
|
120
|
+
reasons: /* @__PURE__ */ new Map()
|
|
121
|
+
}
|
|
122
|
+
])
|
|
123
|
+
);
|
|
124
|
+
var recordStrategyReason = (strategyStats, strategyName, reason) => {
|
|
125
|
+
const stats = strategyStats.get(strategyName);
|
|
126
|
+
if (!stats) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
stats.reasons.set(reason, (stats.reasons.get(reason) ?? 0) + 1);
|
|
130
|
+
};
|
|
131
|
+
var logStrategySkipStats = (runtimeStrategies, strategyStats) => {
|
|
132
|
+
import_logger.logger.info(import_chalk.default.yellow("skip stats:"));
|
|
133
|
+
for (const { strategyName } of runtimeStrategies) {
|
|
134
|
+
const stats = strategyStats.get(strategyName);
|
|
135
|
+
if (!stats) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
import_logger.logger.info(
|
|
139
|
+
`${strategyName}: evaluated=${stats.evaluated}, signals=${stats.signals}`
|
|
140
|
+
);
|
|
141
|
+
const sortedReasons = [...stats.reasons.entries()].sort(
|
|
142
|
+
(left, right) => right[1] - left[1] || left[0].localeCompare(right[0])
|
|
143
|
+
);
|
|
144
|
+
if (!sortedReasons.length) {
|
|
145
|
+
import_logger.logger.info(" none");
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
for (const [reason, count] of sortedReasons) {
|
|
149
|
+
import_logger.logger.info(` ${reason}: ${count}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
101
153
|
var resolveSignalsConnectorName = async (value) => {
|
|
102
154
|
const connectorName = await (0, import_connectors2.resolveConnectorName)(value, projectRoot);
|
|
103
155
|
if (connectorName) {
|
|
@@ -110,13 +162,9 @@ var resolveSignalsConnectorName = async (value) => {
|
|
|
110
162
|
);
|
|
111
163
|
return import_connectors2.DEFAULT_CONNECTOR_NAME;
|
|
112
164
|
};
|
|
113
|
-
var findSignals = async (symbol, connector, btcBinanceData, btcCoinbaseData, runtimeStrategies) => {
|
|
114
|
-
const prevSignals = await (0, import_redis.getKeys)(import_redis.redisKeys.signalsBySymbol(symbol));
|
|
115
|
-
if (prevSignals.length) {
|
|
116
|
-
import_logger.logger.info("Exit by signal exists %s", symbol);
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
165
|
+
var findSignals = async (symbol, connector, btcBinanceData, btcCoinbaseData, runtimeStrategies, strategyStats) => {
|
|
119
166
|
const currentTimestamp = (0, import_time.getTimestamp)();
|
|
167
|
+
const strategySignals = [];
|
|
120
168
|
const [cachedData, btcCachedData] = await Promise.all([
|
|
121
169
|
connector.kline({
|
|
122
170
|
symbol,
|
|
@@ -136,10 +184,14 @@ var findSignals = async (symbol, connector, btcBinanceData, btcCoinbaseData, run
|
|
|
136
184
|
const lastCandle = cachedData.pop();
|
|
137
185
|
const btcLastCandle = btcCachedData.pop();
|
|
138
186
|
if (!lastCandle || !btcLastCandle) {
|
|
139
|
-
return;
|
|
187
|
+
return strategySignals;
|
|
140
188
|
}
|
|
141
189
|
for (const runtimeStrategy of runtimeStrategies) {
|
|
142
190
|
const { strategyName, strategyCreator, strategyConfig } = runtimeStrategy;
|
|
191
|
+
const stats = strategyStats.get(strategyName);
|
|
192
|
+
if (stats) {
|
|
193
|
+
stats.evaluated += 1;
|
|
194
|
+
}
|
|
143
195
|
const strategy = await strategyCreator({
|
|
144
196
|
userName: flags.user,
|
|
145
197
|
connector,
|
|
@@ -157,8 +209,15 @@ var findSignals = async (symbol, connector, btcBinanceData, btcCoinbaseData, run
|
|
|
157
209
|
});
|
|
158
210
|
const signal = await strategy(lastCandle, btcLastCandle);
|
|
159
211
|
if (!signal || typeof signal === "string") {
|
|
212
|
+
if (typeof signal === "string") {
|
|
213
|
+
recordStrategyReason(strategyStats, strategyName, signal);
|
|
214
|
+
}
|
|
160
215
|
continue;
|
|
161
216
|
}
|
|
217
|
+
if (stats) {
|
|
218
|
+
stats.signals += 1;
|
|
219
|
+
}
|
|
220
|
+
strategySignals.push(signal);
|
|
162
221
|
await (0, import_redis.setData)(import_redis.redisKeys.signal(symbol, signal.signalId), signal, {
|
|
163
222
|
expire: import_constants.TTL_1D
|
|
164
223
|
});
|
|
@@ -166,8 +225,8 @@ var findSignals = async (symbol, connector, btcBinanceData, btcCoinbaseData, run
|
|
|
166
225
|
expire: import_constants.TTL_3M
|
|
167
226
|
});
|
|
168
227
|
import_logger.logger.info("Signal found %s by strategy %s", symbol, strategyName);
|
|
169
|
-
return signal;
|
|
170
228
|
}
|
|
229
|
+
return strategySignals;
|
|
171
230
|
};
|
|
172
231
|
var signals = async () => {
|
|
173
232
|
const startedAt = Date.now();
|
|
@@ -229,12 +288,27 @@ var signals = async () => {
|
|
|
229
288
|
return;
|
|
230
289
|
}
|
|
231
290
|
if (!flags.cacheOnly) {
|
|
232
|
-
await (0, import_cli.update)(
|
|
291
|
+
await (0, import_cli.update)(
|
|
292
|
+
marketConnector,
|
|
293
|
+
interval,
|
|
294
|
+
tickers,
|
|
295
|
+
import_constants.SIGNALS_CLI_PRELOAD_DAYS
|
|
296
|
+
);
|
|
233
297
|
if (btcBinanceConnector !== marketConnector) {
|
|
234
|
-
await (0, import_cli.update)(
|
|
298
|
+
await (0, import_cli.update)(
|
|
299
|
+
btcBinanceConnector,
|
|
300
|
+
interval,
|
|
301
|
+
["BTCUSDT"],
|
|
302
|
+
import_constants.SIGNALS_CLI_PRELOAD_DAYS
|
|
303
|
+
);
|
|
235
304
|
}
|
|
236
305
|
if (btcCoinbaseConnector !== marketConnector) {
|
|
237
|
-
await (0, import_cli.update)(
|
|
306
|
+
await (0, import_cli.update)(
|
|
307
|
+
btcCoinbaseConnector,
|
|
308
|
+
interval,
|
|
309
|
+
["BTCUSDT"],
|
|
310
|
+
import_constants.SIGNALS_CLI_PRELOAD_DAYS
|
|
311
|
+
);
|
|
238
312
|
}
|
|
239
313
|
}
|
|
240
314
|
const currentTimestamp = (0, import_time.getTimestamp)();
|
|
@@ -270,6 +344,7 @@ var signals = async () => {
|
|
|
270
344
|
`loaded strategies: ${runtimeStrategies.map((s) => s.strategyName).join(", ")}`
|
|
271
345
|
)
|
|
272
346
|
);
|
|
347
|
+
const strategyStats = createStrategySkipStats(runtimeStrategies);
|
|
273
348
|
const bar = new import_progress.default(
|
|
274
349
|
":current/:total [:bar][:percent] :found :eta(s) :symbol",
|
|
275
350
|
{
|
|
@@ -279,15 +354,16 @@ var signals = async () => {
|
|
|
279
354
|
);
|
|
280
355
|
import_logger.logger.info(import_chalk.default.yellow(`tickers: ${tickers.length}`));
|
|
281
356
|
await (0, import_async.runWithConcurrency)(tickers, 5, async (symbol) => {
|
|
282
|
-
const
|
|
357
|
+
const strategySignals = await findSignals(
|
|
283
358
|
symbol,
|
|
284
359
|
marketConnector,
|
|
285
360
|
btcBinanceData,
|
|
286
361
|
btcCoinbaseData,
|
|
287
|
-
runtimeStrategies
|
|
362
|
+
runtimeStrategies,
|
|
363
|
+
strategyStats
|
|
288
364
|
);
|
|
289
|
-
if (
|
|
290
|
-
signals2.push(
|
|
365
|
+
if (strategySignals.length > 0) {
|
|
366
|
+
signals2.push(...strategySignals);
|
|
291
367
|
}
|
|
292
368
|
bar.tick(1, {
|
|
293
369
|
found: import_chalk.default.cyan(signals2.length),
|
|
@@ -295,11 +371,10 @@ var signals = async () => {
|
|
|
295
371
|
});
|
|
296
372
|
});
|
|
297
373
|
if (!flags.skipScreenshots) {
|
|
298
|
-
await (0, import_cli.makeScreenshots)(signals2, "15");
|
|
299
|
-
await (0, import_cli.makeScreenshots)(signals2, "60");
|
|
374
|
+
await (0, import_cli.makeScreenshots)(signals2, "15", flags.user);
|
|
300
375
|
}
|
|
301
376
|
if (flags.notify) {
|
|
302
|
-
await (0, import_cli.sendToTG)(signals2, "15");
|
|
377
|
+
await (0, import_cli.sendToTG)(signals2, "15", flags.user);
|
|
303
378
|
}
|
|
304
379
|
import_logger.logger.info(
|
|
305
380
|
JSON.stringify(
|
|
@@ -308,6 +383,9 @@ var signals = async () => {
|
|
|
308
383
|
2
|
|
309
384
|
)
|
|
310
385
|
);
|
|
386
|
+
if (flags.showSkipStats) {
|
|
387
|
+
logStrategySkipStats(runtimeStrategies, strategyStats);
|
|
388
|
+
}
|
|
311
389
|
} catch (error) {
|
|
312
390
|
status = "failed";
|
|
313
391
|
import_logger.logger.error(
|
|
@@ -323,8 +401,14 @@ var signals = async () => {
|
|
|
323
401
|
);
|
|
324
402
|
}
|
|
325
403
|
};
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
404
|
+
if (process.env.NODE_ENV !== "test") {
|
|
405
|
+
signals().then(() => {
|
|
406
|
+
process.exit(0);
|
|
407
|
+
}).catch(() => {
|
|
408
|
+
process.exit(1);
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
412
|
+
0 && (module.exports = {
|
|
413
|
+
signals
|
|
330
414
|
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/scripts/spawnSiblingScript.ts
|
|
31
|
+
var spawnSiblingScript_exports = {};
|
|
32
|
+
__export(spawnSiblingScript_exports, {
|
|
33
|
+
spawnSiblingScript: () => spawnSiblingScript
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(spawnSiblingScript_exports);
|
|
36
|
+
var import_fs = __toESM(require("fs"));
|
|
37
|
+
var import_path = __toESM(require("path"));
|
|
38
|
+
var import_child_process = require("child_process");
|
|
39
|
+
var spawnSiblingScript = (currentDir, scriptBaseName, extraArgs) => {
|
|
40
|
+
const searchDirs = [currentDir, import_path.default.resolve(currentDir, "scripts")];
|
|
41
|
+
const candidates = searchDirs.flatMap((dir) => [
|
|
42
|
+
import_path.default.resolve(dir, `${scriptBaseName}.js`),
|
|
43
|
+
import_path.default.resolve(dir, `${scriptBaseName}.ts`)
|
|
44
|
+
]);
|
|
45
|
+
const scriptPath = candidates.find((candidate) => import_fs.default.existsSync(candidate));
|
|
46
|
+
if (!scriptPath) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Script "${scriptBaseName}" not found. Checked: ${candidates.join(", ")}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const commandArgs = scriptPath.endsWith(".ts") ? [
|
|
52
|
+
"-r",
|
|
53
|
+
"ts-node/register",
|
|
54
|
+
"-r",
|
|
55
|
+
"tsconfig-paths/register",
|
|
56
|
+
scriptPath,
|
|
57
|
+
...extraArgs
|
|
58
|
+
] : [scriptPath, ...extraArgs];
|
|
59
|
+
const result = (0, import_child_process.spawnSync)(process.execPath, commandArgs, {
|
|
60
|
+
env: process.env,
|
|
61
|
+
stdio: "inherit"
|
|
62
|
+
});
|
|
63
|
+
if (result.error) {
|
|
64
|
+
throw result.error;
|
|
65
|
+
}
|
|
66
|
+
return result.status ?? 1;
|
|
67
|
+
};
|
|
68
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
69
|
+
0 && (module.exports = {
|
|
70
|
+
spawnSiblingScript
|
|
71
|
+
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/workers/testerWorker.ts
|
|
4
4
|
var import_backtest = require("@tradejs/node/backtest");
|
|
5
|
+
var import_ai = require("@tradejs/infra/ai");
|
|
5
6
|
var import_logger = require("@tradejs/infra/logger");
|
|
6
7
|
var import_ml = require("@tradejs/infra/ml");
|
|
7
8
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -23,10 +24,12 @@ process.on(
|
|
|
23
24
|
if (!testResult) {
|
|
24
25
|
throw new Error("No result");
|
|
25
26
|
}
|
|
26
|
-
const { stat, orderLogId } = testResult;
|
|
27
|
+
const { stat, orderLogId, inlineOrderLog, inlinePositionLog } = testResult;
|
|
27
28
|
process.send?.({
|
|
28
29
|
stat,
|
|
29
30
|
orderLogId,
|
|
31
|
+
inlineOrderLog,
|
|
32
|
+
inlinePositionLog,
|
|
30
33
|
test
|
|
31
34
|
});
|
|
32
35
|
} catch (error) {
|
|
@@ -36,6 +39,7 @@ process.on(
|
|
|
36
39
|
process.send?.({
|
|
37
40
|
error: true,
|
|
38
41
|
id: test.name,
|
|
42
|
+
symbol: test.symbol,
|
|
39
43
|
msg: {
|
|
40
44
|
message: errorMessage,
|
|
41
45
|
stack: errorStack
|
|
@@ -44,10 +48,17 @@ process.on(
|
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
} finally {
|
|
51
|
+
await (0, import_ai.closeAllAiDatasetWriters)();
|
|
47
52
|
await (0, import_ml.closeAllMlDatasetWriters)();
|
|
48
53
|
(0, import_backtest.resetTestingKlineCache)();
|
|
49
54
|
}
|
|
50
|
-
process.send
|
|
55
|
+
if (process.send) {
|
|
56
|
+
process.send({ done: true }, () => {
|
|
57
|
+
process.disconnect?.();
|
|
58
|
+
process.exit(0);
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
51
62
|
process.disconnect?.();
|
|
52
63
|
process.exit(0);
|
|
53
64
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Official CLI for the TradeJS open-source framework: infra setup, backtests, signals, bots, and ML workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"tradejs": "dist/cli.js"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@tradejs/base": "^1.0.
|
|
33
|
-
"@tradejs/connectors": "^1.0.
|
|
34
|
-
"@tradejs/core": "^1.0.
|
|
35
|
-
"@tradejs/indicators": "^1.0.
|
|
36
|
-
"@tradejs/infra": "^1.0.
|
|
37
|
-
"@tradejs/node": "^1.0.
|
|
38
|
-
"@tradejs/strategies": "^1.0.
|
|
39
|
-
"@tradejs/types": "^1.0.
|
|
32
|
+
"@tradejs/base": "^1.0.6",
|
|
33
|
+
"@tradejs/connectors": "^1.0.6",
|
|
34
|
+
"@tradejs/core": "^1.0.6",
|
|
35
|
+
"@tradejs/indicators": "^1.0.6",
|
|
36
|
+
"@tradejs/infra": "^1.0.6",
|
|
37
|
+
"@tradejs/node": "^1.0.6",
|
|
38
|
+
"@tradejs/strategies": "^1.0.6",
|
|
39
|
+
"@tradejs/types": "^1.0.6",
|
|
40
40
|
"args": "^5.0.3",
|
|
41
41
|
"bcryptjs": "^2.4.3",
|
|
42
42
|
"chalk": "4.1.2",
|
|
@@ -63,6 +63,8 @@
|
|
|
63
63
|
"clean-redis": "yarn run run:dist clean-redis",
|
|
64
64
|
"clean-tests": "yarn run run:dist clean-tests",
|
|
65
65
|
"doctor": "yarn run run:dist doctor",
|
|
66
|
+
"ai-export": "yarn run run:dist ai-export",
|
|
67
|
+
"ai-train": "yarn run run:dist ai-train",
|
|
66
68
|
"backtest": "yarn run run:dist backtest",
|
|
67
69
|
"bot": "yarn run run:dist bot",
|
|
68
70
|
"signals": "yarn run run:dist signals",
|