@tradejs/cli 1.0.9 → 1.0.11
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 +13 -4
- package/dist/cli.js +29531 -13520
- package/dist/lib/aiPocketSearch.js +1316 -0
- package/dist/lib/aiTrainCharts.js +711 -0
- package/dist/lib/aiTrainDataset.js +40 -0
- package/dist/lib/aiTrainEvaluationDump.js +76 -0
- package/dist/lib/aiTrainMetrics.js +148 -8
- package/dist/lib/aiTrainOptions.js +130 -0
- package/dist/lib/aiTrainQuarantine.js +199 -0
- package/dist/lib/aiTrainResearch.js +467 -0
- package/dist/lib/binanceMarketContextBackfill.js +841 -0
- package/dist/lib/binanceMarketData.js +392 -0
- package/dist/lib/coinMarketCapContextBackfill.js +1126 -0
- package/dist/lib/continuity.js +60 -0
- package/dist/lib/derivativesContextBackfill.js +490 -77
- package/dist/lib/executionCalibration.js +705 -0
- package/dist/lib/marketContextPrepare.js +4441 -0
- package/dist/lib/paritySummary.js +101 -0
- package/dist/lib/runBot.js +1 -0
- package/dist/lib/runEnvironment.js +2259 -0
- package/dist/lib/runFormatting.js +1657 -0
- package/dist/lib/runtimeDebugEvidence.js +526 -0
- package/dist/lib/runtimeModeConfig.js +53 -0
- package/dist/lib/runtimeParity.js +88 -11
- package/dist/lib/runtimeParityDetails.js +751 -0
- package/dist/lib/runtimeRedis.js +157 -0
- package/dist/lib/runtimeSignalsLoader.js +40 -6
- package/dist/lib/runtimeSignalsStorage.js +45 -22
- package/dist/lib/runtimeStrategyBacktest.js +134 -0
- package/dist/lib/runtimeTradeSync.js +263 -0
- package/dist/lib/telegramReports.js +9 -0
- package/dist/lib/tickerUniverseCache.js +116 -0
- package/dist/lib/timeWindow.js +3 -3
- package/dist/scripts/agentRun.js +14 -8
- package/dist/scripts/aiExport.js +1721 -7
- package/dist/scripts/aiExportSelect.js +16 -4
- package/dist/scripts/aiPocketSearch.js +4190 -0
- package/dist/scripts/aiTrain.js +1866 -87
- package/dist/scripts/backtest.js +4534 -803
- package/dist/scripts/binanceMarketIngest.js +565 -0
- package/dist/scripts/bot.js +16 -2
- package/dist/scripts/candlesMigrateProvider.js +32 -22
- package/dist/scripts/cleanDir.js +15 -2
- package/dist/scripts/cleanRedis.js +15 -2
- package/dist/scripts/cleanTests.js +38 -2
- package/dist/scripts/cleanupMarketContext.js +69 -0
- package/dist/scripts/continuity.js +148 -67
- package/dist/scripts/derivativesIngest.js +14 -4
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +14 -4
- package/dist/scripts/doctor.js +14 -4
- package/dist/scripts/executionCalibration.js +792 -0
- package/dist/scripts/infraCommon.js +18 -5
- package/dist/scripts/infraDown.js +14 -4
- package/dist/scripts/infraInit.js +32 -9
- package/dist/scripts/infraUp.js +24 -6
- package/dist/scripts/marketWs.js +222 -0
- package/dist/scripts/migration.js +15 -2
- package/dist/scripts/mlExport.js +1698 -10
- package/dist/scripts/mlExportSelect.js +16 -4
- package/dist/scripts/mlInspect.js +13 -3
- package/dist/scripts/mlTrainLatestSelect.js +14 -4
- package/dist/scripts/replay.js +8867 -0
- package/dist/scripts/replayRunner.js +8870 -0
- package/dist/scripts/replayRuntimeEvidence.js +868 -0
- package/dist/scripts/researchAuto.js +286 -59
- package/dist/scripts/results.js +3 -3
- package/dist/scripts/runtimeEvidence.js +605 -0
- package/dist/scripts/runtimeParity.js +6400 -1043
- package/dist/scripts/serverHealth.js +588 -0
- package/dist/scripts/signals.js +5628 -511
- package/dist/scripts/signalsDaemon.js +6205 -0
- package/dist/scripts/signalsSummary.js +833 -248
- package/dist/scripts/test-ml.js +25 -3
- package/dist/scripts/test.js +26 -1
- package/dist/scripts/user-add.js +15 -2
- package/dist/workers/testerWorker.js +130 -21
- package/package.json +18 -12
|
@@ -0,0 +1,4190 @@
|
|
|
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 __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// ../../node_modules/debug/node_modules/ms/index.js
|
|
34
|
+
var require_ms = __commonJS({
|
|
35
|
+
"../../node_modules/debug/node_modules/ms/index.js"(exports2, module2) {
|
|
36
|
+
"use strict";
|
|
37
|
+
var s = 1e3;
|
|
38
|
+
var m = s * 60;
|
|
39
|
+
var h = m * 60;
|
|
40
|
+
var d = h * 24;
|
|
41
|
+
var w = d * 7;
|
|
42
|
+
var y = d * 365.25;
|
|
43
|
+
module2.exports = function(val, options) {
|
|
44
|
+
options = options || {};
|
|
45
|
+
var type = typeof val;
|
|
46
|
+
if (type === "string" && val.length > 0) {
|
|
47
|
+
return parse(val);
|
|
48
|
+
} else if (type === "number" && isFinite(val)) {
|
|
49
|
+
return options.long ? fmtLong(val) : fmtShort(val);
|
|
50
|
+
}
|
|
51
|
+
throw new Error(
|
|
52
|
+
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
function parse(str) {
|
|
56
|
+
str = String(str);
|
|
57
|
+
if (str.length > 100) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
|
|
61
|
+
str
|
|
62
|
+
);
|
|
63
|
+
if (!match) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
var n = parseFloat(match[1]);
|
|
67
|
+
var type = (match[2] || "ms").toLowerCase();
|
|
68
|
+
switch (type) {
|
|
69
|
+
case "years":
|
|
70
|
+
case "year":
|
|
71
|
+
case "yrs":
|
|
72
|
+
case "yr":
|
|
73
|
+
case "y":
|
|
74
|
+
return n * y;
|
|
75
|
+
case "weeks":
|
|
76
|
+
case "week":
|
|
77
|
+
case "w":
|
|
78
|
+
return n * w;
|
|
79
|
+
case "days":
|
|
80
|
+
case "day":
|
|
81
|
+
case "d":
|
|
82
|
+
return n * d;
|
|
83
|
+
case "hours":
|
|
84
|
+
case "hour":
|
|
85
|
+
case "hrs":
|
|
86
|
+
case "hr":
|
|
87
|
+
case "h":
|
|
88
|
+
return n * h;
|
|
89
|
+
case "minutes":
|
|
90
|
+
case "minute":
|
|
91
|
+
case "mins":
|
|
92
|
+
case "min":
|
|
93
|
+
case "m":
|
|
94
|
+
return n * m;
|
|
95
|
+
case "seconds":
|
|
96
|
+
case "second":
|
|
97
|
+
case "secs":
|
|
98
|
+
case "sec":
|
|
99
|
+
case "s":
|
|
100
|
+
return n * s;
|
|
101
|
+
case "milliseconds":
|
|
102
|
+
case "millisecond":
|
|
103
|
+
case "msecs":
|
|
104
|
+
case "msec":
|
|
105
|
+
case "ms":
|
|
106
|
+
return n;
|
|
107
|
+
default:
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function fmtShort(ms) {
|
|
112
|
+
var msAbs = Math.abs(ms);
|
|
113
|
+
if (msAbs >= d) {
|
|
114
|
+
return Math.round(ms / d) + "d";
|
|
115
|
+
}
|
|
116
|
+
if (msAbs >= h) {
|
|
117
|
+
return Math.round(ms / h) + "h";
|
|
118
|
+
}
|
|
119
|
+
if (msAbs >= m) {
|
|
120
|
+
return Math.round(ms / m) + "m";
|
|
121
|
+
}
|
|
122
|
+
if (msAbs >= s) {
|
|
123
|
+
return Math.round(ms / s) + "s";
|
|
124
|
+
}
|
|
125
|
+
return ms + "ms";
|
|
126
|
+
}
|
|
127
|
+
function fmtLong(ms) {
|
|
128
|
+
var msAbs = Math.abs(ms);
|
|
129
|
+
if (msAbs >= d) {
|
|
130
|
+
return plural(ms, msAbs, d, "day");
|
|
131
|
+
}
|
|
132
|
+
if (msAbs >= h) {
|
|
133
|
+
return plural(ms, msAbs, h, "hour");
|
|
134
|
+
}
|
|
135
|
+
if (msAbs >= m) {
|
|
136
|
+
return plural(ms, msAbs, m, "minute");
|
|
137
|
+
}
|
|
138
|
+
if (msAbs >= s) {
|
|
139
|
+
return plural(ms, msAbs, s, "second");
|
|
140
|
+
}
|
|
141
|
+
return ms + " ms";
|
|
142
|
+
}
|
|
143
|
+
function plural(ms, msAbs, n, name) {
|
|
144
|
+
var isPlural = msAbs >= n * 1.5;
|
|
145
|
+
return Math.round(ms / n) + " " + name + (isPlural ? "s" : "");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// ../../node_modules/debug/src/common.js
|
|
151
|
+
var require_common = __commonJS({
|
|
152
|
+
"../../node_modules/debug/src/common.js"(exports2, module2) {
|
|
153
|
+
"use strict";
|
|
154
|
+
function setup(env) {
|
|
155
|
+
createDebug.debug = createDebug;
|
|
156
|
+
createDebug.default = createDebug;
|
|
157
|
+
createDebug.coerce = coerce;
|
|
158
|
+
createDebug.disable = disable;
|
|
159
|
+
createDebug.enable = enable;
|
|
160
|
+
createDebug.enabled = enabled;
|
|
161
|
+
createDebug.humanize = require_ms();
|
|
162
|
+
createDebug.destroy = destroy;
|
|
163
|
+
Object.keys(env).forEach((key) => {
|
|
164
|
+
createDebug[key] = env[key];
|
|
165
|
+
});
|
|
166
|
+
createDebug.names = [];
|
|
167
|
+
createDebug.skips = [];
|
|
168
|
+
createDebug.formatters = {};
|
|
169
|
+
function selectColor(namespace) {
|
|
170
|
+
let hash = 0;
|
|
171
|
+
for (let i = 0; i < namespace.length; i++) {
|
|
172
|
+
hash = (hash << 5) - hash + namespace.charCodeAt(i);
|
|
173
|
+
hash |= 0;
|
|
174
|
+
}
|
|
175
|
+
return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
|
|
176
|
+
}
|
|
177
|
+
createDebug.selectColor = selectColor;
|
|
178
|
+
function createDebug(namespace) {
|
|
179
|
+
let prevTime;
|
|
180
|
+
let enableOverride = null;
|
|
181
|
+
let namespacesCache;
|
|
182
|
+
let enabledCache;
|
|
183
|
+
function debug(...args2) {
|
|
184
|
+
if (!debug.enabled) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const self = debug;
|
|
188
|
+
const curr = Number(/* @__PURE__ */ new Date());
|
|
189
|
+
const ms = curr - (prevTime || curr);
|
|
190
|
+
self.diff = ms;
|
|
191
|
+
self.prev = prevTime;
|
|
192
|
+
self.curr = curr;
|
|
193
|
+
prevTime = curr;
|
|
194
|
+
args2[0] = createDebug.coerce(args2[0]);
|
|
195
|
+
if (typeof args2[0] !== "string") {
|
|
196
|
+
args2.unshift("%O");
|
|
197
|
+
}
|
|
198
|
+
let index = 0;
|
|
199
|
+
args2[0] = args2[0].replace(/%([a-zA-Z%])/g, (match, format) => {
|
|
200
|
+
if (match === "%%") {
|
|
201
|
+
return "%";
|
|
202
|
+
}
|
|
203
|
+
index++;
|
|
204
|
+
const formatter = createDebug.formatters[format];
|
|
205
|
+
if (typeof formatter === "function") {
|
|
206
|
+
const val = args2[index];
|
|
207
|
+
match = formatter.call(self, val);
|
|
208
|
+
args2.splice(index, 1);
|
|
209
|
+
index--;
|
|
210
|
+
}
|
|
211
|
+
return match;
|
|
212
|
+
});
|
|
213
|
+
createDebug.formatArgs.call(self, args2);
|
|
214
|
+
const logFn = self.log || createDebug.log;
|
|
215
|
+
logFn.apply(self, args2);
|
|
216
|
+
}
|
|
217
|
+
debug.namespace = namespace;
|
|
218
|
+
debug.useColors = createDebug.useColors();
|
|
219
|
+
debug.color = createDebug.selectColor(namespace);
|
|
220
|
+
debug.extend = extend;
|
|
221
|
+
debug.destroy = createDebug.destroy;
|
|
222
|
+
Object.defineProperty(debug, "enabled", {
|
|
223
|
+
enumerable: true,
|
|
224
|
+
configurable: false,
|
|
225
|
+
get: () => {
|
|
226
|
+
if (enableOverride !== null) {
|
|
227
|
+
return enableOverride;
|
|
228
|
+
}
|
|
229
|
+
if (namespacesCache !== createDebug.namespaces) {
|
|
230
|
+
namespacesCache = createDebug.namespaces;
|
|
231
|
+
enabledCache = createDebug.enabled(namespace);
|
|
232
|
+
}
|
|
233
|
+
return enabledCache;
|
|
234
|
+
},
|
|
235
|
+
set: (v) => {
|
|
236
|
+
enableOverride = v;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
if (typeof createDebug.init === "function") {
|
|
240
|
+
createDebug.init(debug);
|
|
241
|
+
}
|
|
242
|
+
return debug;
|
|
243
|
+
}
|
|
244
|
+
function extend(namespace, delimiter) {
|
|
245
|
+
const newDebug = createDebug(this.namespace + (typeof delimiter === "undefined" ? ":" : delimiter) + namespace);
|
|
246
|
+
newDebug.log = this.log;
|
|
247
|
+
return newDebug;
|
|
248
|
+
}
|
|
249
|
+
function enable(namespaces) {
|
|
250
|
+
createDebug.save(namespaces);
|
|
251
|
+
createDebug.namespaces = namespaces;
|
|
252
|
+
createDebug.names = [];
|
|
253
|
+
createDebug.skips = [];
|
|
254
|
+
let i;
|
|
255
|
+
const split = (typeof namespaces === "string" ? namespaces : "").split(/[\s,]+/);
|
|
256
|
+
const len = split.length;
|
|
257
|
+
for (i = 0; i < len; i++) {
|
|
258
|
+
if (!split[i]) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
namespaces = split[i].replace(/\*/g, ".*?");
|
|
262
|
+
if (namespaces[0] === "-") {
|
|
263
|
+
createDebug.skips.push(new RegExp("^" + namespaces.slice(1) + "$"));
|
|
264
|
+
} else {
|
|
265
|
+
createDebug.names.push(new RegExp("^" + namespaces + "$"));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function disable() {
|
|
270
|
+
const namespaces = [
|
|
271
|
+
...createDebug.names.map(toNamespace),
|
|
272
|
+
...createDebug.skips.map(toNamespace).map((namespace) => "-" + namespace)
|
|
273
|
+
].join(",");
|
|
274
|
+
createDebug.enable("");
|
|
275
|
+
return namespaces;
|
|
276
|
+
}
|
|
277
|
+
function enabled(name) {
|
|
278
|
+
if (name[name.length - 1] === "*") {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
let i;
|
|
282
|
+
let len;
|
|
283
|
+
for (i = 0, len = createDebug.skips.length; i < len; i++) {
|
|
284
|
+
if (createDebug.skips[i].test(name)) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
for (i = 0, len = createDebug.names.length; i < len; i++) {
|
|
289
|
+
if (createDebug.names[i].test(name)) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
function toNamespace(regexp) {
|
|
296
|
+
return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\.\*\?$/, "*");
|
|
297
|
+
}
|
|
298
|
+
function coerce(val) {
|
|
299
|
+
if (val instanceof Error) {
|
|
300
|
+
return val.stack || val.message;
|
|
301
|
+
}
|
|
302
|
+
return val;
|
|
303
|
+
}
|
|
304
|
+
function destroy() {
|
|
305
|
+
console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
306
|
+
}
|
|
307
|
+
createDebug.enable(createDebug.load());
|
|
308
|
+
return createDebug;
|
|
309
|
+
}
|
|
310
|
+
module2.exports = setup;
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// ../../node_modules/debug/src/browser.js
|
|
315
|
+
var require_browser = __commonJS({
|
|
316
|
+
"../../node_modules/debug/src/browser.js"(exports2, module2) {
|
|
317
|
+
"use strict";
|
|
318
|
+
exports2.formatArgs = formatArgs;
|
|
319
|
+
exports2.save = save;
|
|
320
|
+
exports2.load = load;
|
|
321
|
+
exports2.useColors = useColors;
|
|
322
|
+
exports2.storage = localstorage();
|
|
323
|
+
exports2.destroy = /* @__PURE__ */ (() => {
|
|
324
|
+
let warned = false;
|
|
325
|
+
return () => {
|
|
326
|
+
if (!warned) {
|
|
327
|
+
warned = true;
|
|
328
|
+
console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
})();
|
|
332
|
+
exports2.colors = [
|
|
333
|
+
"#0000CC",
|
|
334
|
+
"#0000FF",
|
|
335
|
+
"#0033CC",
|
|
336
|
+
"#0033FF",
|
|
337
|
+
"#0066CC",
|
|
338
|
+
"#0066FF",
|
|
339
|
+
"#0099CC",
|
|
340
|
+
"#0099FF",
|
|
341
|
+
"#00CC00",
|
|
342
|
+
"#00CC33",
|
|
343
|
+
"#00CC66",
|
|
344
|
+
"#00CC99",
|
|
345
|
+
"#00CCCC",
|
|
346
|
+
"#00CCFF",
|
|
347
|
+
"#3300CC",
|
|
348
|
+
"#3300FF",
|
|
349
|
+
"#3333CC",
|
|
350
|
+
"#3333FF",
|
|
351
|
+
"#3366CC",
|
|
352
|
+
"#3366FF",
|
|
353
|
+
"#3399CC",
|
|
354
|
+
"#3399FF",
|
|
355
|
+
"#33CC00",
|
|
356
|
+
"#33CC33",
|
|
357
|
+
"#33CC66",
|
|
358
|
+
"#33CC99",
|
|
359
|
+
"#33CCCC",
|
|
360
|
+
"#33CCFF",
|
|
361
|
+
"#6600CC",
|
|
362
|
+
"#6600FF",
|
|
363
|
+
"#6633CC",
|
|
364
|
+
"#6633FF",
|
|
365
|
+
"#66CC00",
|
|
366
|
+
"#66CC33",
|
|
367
|
+
"#9900CC",
|
|
368
|
+
"#9900FF",
|
|
369
|
+
"#9933CC",
|
|
370
|
+
"#9933FF",
|
|
371
|
+
"#99CC00",
|
|
372
|
+
"#99CC33",
|
|
373
|
+
"#CC0000",
|
|
374
|
+
"#CC0033",
|
|
375
|
+
"#CC0066",
|
|
376
|
+
"#CC0099",
|
|
377
|
+
"#CC00CC",
|
|
378
|
+
"#CC00FF",
|
|
379
|
+
"#CC3300",
|
|
380
|
+
"#CC3333",
|
|
381
|
+
"#CC3366",
|
|
382
|
+
"#CC3399",
|
|
383
|
+
"#CC33CC",
|
|
384
|
+
"#CC33FF",
|
|
385
|
+
"#CC6600",
|
|
386
|
+
"#CC6633",
|
|
387
|
+
"#CC9900",
|
|
388
|
+
"#CC9933",
|
|
389
|
+
"#CCCC00",
|
|
390
|
+
"#CCCC33",
|
|
391
|
+
"#FF0000",
|
|
392
|
+
"#FF0033",
|
|
393
|
+
"#FF0066",
|
|
394
|
+
"#FF0099",
|
|
395
|
+
"#FF00CC",
|
|
396
|
+
"#FF00FF",
|
|
397
|
+
"#FF3300",
|
|
398
|
+
"#FF3333",
|
|
399
|
+
"#FF3366",
|
|
400
|
+
"#FF3399",
|
|
401
|
+
"#FF33CC",
|
|
402
|
+
"#FF33FF",
|
|
403
|
+
"#FF6600",
|
|
404
|
+
"#FF6633",
|
|
405
|
+
"#FF9900",
|
|
406
|
+
"#FF9933",
|
|
407
|
+
"#FFCC00",
|
|
408
|
+
"#FFCC33"
|
|
409
|
+
];
|
|
410
|
+
function useColors() {
|
|
411
|
+
if (typeof window !== "undefined" && window.process && (window.process.type === "renderer" || window.process.__nwjs)) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
if (typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
return typeof document !== "undefined" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773
|
|
418
|
+
typeof window !== "undefined" && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31?
|
|
419
|
+
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
|
420
|
+
typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker
|
|
421
|
+
typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
|
|
422
|
+
}
|
|
423
|
+
function formatArgs(args2) {
|
|
424
|
+
args2[0] = (this.useColors ? "%c" : "") + this.namespace + (this.useColors ? " %c" : " ") + args2[0] + (this.useColors ? "%c " : " ") + "+" + module2.exports.humanize(this.diff);
|
|
425
|
+
if (!this.useColors) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const c = "color: " + this.color;
|
|
429
|
+
args2.splice(1, 0, c, "color: inherit");
|
|
430
|
+
let index = 0;
|
|
431
|
+
let lastC = 0;
|
|
432
|
+
args2[0].replace(/%[a-zA-Z%]/g, (match) => {
|
|
433
|
+
if (match === "%%") {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
index++;
|
|
437
|
+
if (match === "%c") {
|
|
438
|
+
lastC = index;
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
args2.splice(lastC, 0, c);
|
|
442
|
+
}
|
|
443
|
+
exports2.log = console.debug || console.log || (() => {
|
|
444
|
+
});
|
|
445
|
+
function save(namespaces) {
|
|
446
|
+
try {
|
|
447
|
+
if (namespaces) {
|
|
448
|
+
exports2.storage.setItem("debug", namespaces);
|
|
449
|
+
} else {
|
|
450
|
+
exports2.storage.removeItem("debug");
|
|
451
|
+
}
|
|
452
|
+
} catch (error) {
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function load() {
|
|
456
|
+
let r;
|
|
457
|
+
try {
|
|
458
|
+
r = exports2.storage.getItem("debug");
|
|
459
|
+
} catch (error) {
|
|
460
|
+
}
|
|
461
|
+
if (!r && typeof process !== "undefined" && "env" in process) {
|
|
462
|
+
r = process.env.DEBUG;
|
|
463
|
+
}
|
|
464
|
+
return r;
|
|
465
|
+
}
|
|
466
|
+
function localstorage() {
|
|
467
|
+
try {
|
|
468
|
+
return localStorage;
|
|
469
|
+
} catch (error) {
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
module2.exports = require_common()(exports2);
|
|
473
|
+
var { formatters } = module2.exports;
|
|
474
|
+
formatters.j = function(v) {
|
|
475
|
+
try {
|
|
476
|
+
return JSON.stringify(v);
|
|
477
|
+
} catch (error) {
|
|
478
|
+
return "[UnexpectedJSONParseError]: " + error.message;
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// ../../node_modules/has-flag/index.js
|
|
485
|
+
var require_has_flag = __commonJS({
|
|
486
|
+
"../../node_modules/has-flag/index.js"(exports2, module2) {
|
|
487
|
+
"use strict";
|
|
488
|
+
module2.exports = (flag, argv = process.argv) => {
|
|
489
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
490
|
+
const position = argv.indexOf(prefix + flag);
|
|
491
|
+
const terminatorPosition = argv.indexOf("--");
|
|
492
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// ../../node_modules/supports-color/index.js
|
|
498
|
+
var require_supports_color = __commonJS({
|
|
499
|
+
"../../node_modules/supports-color/index.js"(exports2, module2) {
|
|
500
|
+
"use strict";
|
|
501
|
+
var os = require("os");
|
|
502
|
+
var tty = require("tty");
|
|
503
|
+
var hasFlag = require_has_flag();
|
|
504
|
+
var { env } = process;
|
|
505
|
+
var flagForceColor;
|
|
506
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
507
|
+
flagForceColor = 0;
|
|
508
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
509
|
+
flagForceColor = 1;
|
|
510
|
+
}
|
|
511
|
+
function envForceColor() {
|
|
512
|
+
if ("FORCE_COLOR" in env) {
|
|
513
|
+
if (env.FORCE_COLOR === "true") {
|
|
514
|
+
return 1;
|
|
515
|
+
}
|
|
516
|
+
if (env.FORCE_COLOR === "false") {
|
|
517
|
+
return 0;
|
|
518
|
+
}
|
|
519
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function translateLevel(level) {
|
|
523
|
+
if (level === 0) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
return {
|
|
527
|
+
level,
|
|
528
|
+
hasBasic: true,
|
|
529
|
+
has256: level >= 2,
|
|
530
|
+
has16m: level >= 3
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
534
|
+
const noFlagForceColor = envForceColor();
|
|
535
|
+
if (noFlagForceColor !== void 0) {
|
|
536
|
+
flagForceColor = noFlagForceColor;
|
|
537
|
+
}
|
|
538
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
539
|
+
if (forceColor === 0) {
|
|
540
|
+
return 0;
|
|
541
|
+
}
|
|
542
|
+
if (sniffFlags) {
|
|
543
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
544
|
+
return 3;
|
|
545
|
+
}
|
|
546
|
+
if (hasFlag("color=256")) {
|
|
547
|
+
return 2;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
551
|
+
return 0;
|
|
552
|
+
}
|
|
553
|
+
const min = forceColor || 0;
|
|
554
|
+
if (env.TERM === "dumb") {
|
|
555
|
+
return min;
|
|
556
|
+
}
|
|
557
|
+
if (process.platform === "win32") {
|
|
558
|
+
const osRelease = os.release().split(".");
|
|
559
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
560
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
561
|
+
}
|
|
562
|
+
return 1;
|
|
563
|
+
}
|
|
564
|
+
if ("CI" in env) {
|
|
565
|
+
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
566
|
+
return 1;
|
|
567
|
+
}
|
|
568
|
+
return min;
|
|
569
|
+
}
|
|
570
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
571
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
572
|
+
}
|
|
573
|
+
if (env.COLORTERM === "truecolor") {
|
|
574
|
+
return 3;
|
|
575
|
+
}
|
|
576
|
+
if ("TERM_PROGRAM" in env) {
|
|
577
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
578
|
+
switch (env.TERM_PROGRAM) {
|
|
579
|
+
case "iTerm.app":
|
|
580
|
+
return version >= 3 ? 3 : 2;
|
|
581
|
+
case "Apple_Terminal":
|
|
582
|
+
return 2;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
586
|
+
return 2;
|
|
587
|
+
}
|
|
588
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
589
|
+
return 1;
|
|
590
|
+
}
|
|
591
|
+
if ("COLORTERM" in env) {
|
|
592
|
+
return 1;
|
|
593
|
+
}
|
|
594
|
+
return min;
|
|
595
|
+
}
|
|
596
|
+
function getSupportLevel(stream, options = {}) {
|
|
597
|
+
const level = supportsColor(stream, {
|
|
598
|
+
streamIsTTY: stream && stream.isTTY,
|
|
599
|
+
...options
|
|
600
|
+
});
|
|
601
|
+
return translateLevel(level);
|
|
602
|
+
}
|
|
603
|
+
module2.exports = {
|
|
604
|
+
supportsColor: getSupportLevel,
|
|
605
|
+
stdout: getSupportLevel({ isTTY: tty.isatty(1) }),
|
|
606
|
+
stderr: getSupportLevel({ isTTY: tty.isatty(2) })
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// ../../node_modules/debug/src/node.js
|
|
612
|
+
var require_node = __commonJS({
|
|
613
|
+
"../../node_modules/debug/src/node.js"(exports2, module2) {
|
|
614
|
+
"use strict";
|
|
615
|
+
var tty = require("tty");
|
|
616
|
+
var util = require("util");
|
|
617
|
+
exports2.init = init;
|
|
618
|
+
exports2.log = log;
|
|
619
|
+
exports2.formatArgs = formatArgs;
|
|
620
|
+
exports2.save = save;
|
|
621
|
+
exports2.load = load;
|
|
622
|
+
exports2.useColors = useColors;
|
|
623
|
+
exports2.destroy = util.deprecate(
|
|
624
|
+
() => {
|
|
625
|
+
},
|
|
626
|
+
"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."
|
|
627
|
+
);
|
|
628
|
+
exports2.colors = [6, 2, 3, 4, 5, 1];
|
|
629
|
+
try {
|
|
630
|
+
const supportsColor = require_supports_color();
|
|
631
|
+
if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
|
|
632
|
+
exports2.colors = [
|
|
633
|
+
20,
|
|
634
|
+
21,
|
|
635
|
+
26,
|
|
636
|
+
27,
|
|
637
|
+
32,
|
|
638
|
+
33,
|
|
639
|
+
38,
|
|
640
|
+
39,
|
|
641
|
+
40,
|
|
642
|
+
41,
|
|
643
|
+
42,
|
|
644
|
+
43,
|
|
645
|
+
44,
|
|
646
|
+
45,
|
|
647
|
+
56,
|
|
648
|
+
57,
|
|
649
|
+
62,
|
|
650
|
+
63,
|
|
651
|
+
68,
|
|
652
|
+
69,
|
|
653
|
+
74,
|
|
654
|
+
75,
|
|
655
|
+
76,
|
|
656
|
+
77,
|
|
657
|
+
78,
|
|
658
|
+
79,
|
|
659
|
+
80,
|
|
660
|
+
81,
|
|
661
|
+
92,
|
|
662
|
+
93,
|
|
663
|
+
98,
|
|
664
|
+
99,
|
|
665
|
+
112,
|
|
666
|
+
113,
|
|
667
|
+
128,
|
|
668
|
+
129,
|
|
669
|
+
134,
|
|
670
|
+
135,
|
|
671
|
+
148,
|
|
672
|
+
149,
|
|
673
|
+
160,
|
|
674
|
+
161,
|
|
675
|
+
162,
|
|
676
|
+
163,
|
|
677
|
+
164,
|
|
678
|
+
165,
|
|
679
|
+
166,
|
|
680
|
+
167,
|
|
681
|
+
168,
|
|
682
|
+
169,
|
|
683
|
+
170,
|
|
684
|
+
171,
|
|
685
|
+
172,
|
|
686
|
+
173,
|
|
687
|
+
178,
|
|
688
|
+
179,
|
|
689
|
+
184,
|
|
690
|
+
185,
|
|
691
|
+
196,
|
|
692
|
+
197,
|
|
693
|
+
198,
|
|
694
|
+
199,
|
|
695
|
+
200,
|
|
696
|
+
201,
|
|
697
|
+
202,
|
|
698
|
+
203,
|
|
699
|
+
204,
|
|
700
|
+
205,
|
|
701
|
+
206,
|
|
702
|
+
207,
|
|
703
|
+
208,
|
|
704
|
+
209,
|
|
705
|
+
214,
|
|
706
|
+
215,
|
|
707
|
+
220,
|
|
708
|
+
221
|
|
709
|
+
];
|
|
710
|
+
}
|
|
711
|
+
} catch (error) {
|
|
712
|
+
}
|
|
713
|
+
exports2.inspectOpts = Object.keys(process.env).filter((key) => {
|
|
714
|
+
return /^debug_/i.test(key);
|
|
715
|
+
}).reduce((obj, key) => {
|
|
716
|
+
const prop = key.substring(6).toLowerCase().replace(/_([a-z])/g, (_, k) => {
|
|
717
|
+
return k.toUpperCase();
|
|
718
|
+
});
|
|
719
|
+
let val = process.env[key];
|
|
720
|
+
if (/^(yes|on|true|enabled)$/i.test(val)) {
|
|
721
|
+
val = true;
|
|
722
|
+
} else if (/^(no|off|false|disabled)$/i.test(val)) {
|
|
723
|
+
val = false;
|
|
724
|
+
} else if (val === "null") {
|
|
725
|
+
val = null;
|
|
726
|
+
} else {
|
|
727
|
+
val = Number(val);
|
|
728
|
+
}
|
|
729
|
+
obj[prop] = val;
|
|
730
|
+
return obj;
|
|
731
|
+
}, {});
|
|
732
|
+
function useColors() {
|
|
733
|
+
return "colors" in exports2.inspectOpts ? Boolean(exports2.inspectOpts.colors) : tty.isatty(process.stderr.fd);
|
|
734
|
+
}
|
|
735
|
+
function formatArgs(args2) {
|
|
736
|
+
const { namespace: name, useColors: useColors2 } = this;
|
|
737
|
+
if (useColors2) {
|
|
738
|
+
const c = this.color;
|
|
739
|
+
const colorCode = "\x1B[3" + (c < 8 ? c : "8;5;" + c);
|
|
740
|
+
const prefix = ` ${colorCode};1m${name} \x1B[0m`;
|
|
741
|
+
args2[0] = prefix + args2[0].split("\n").join("\n" + prefix);
|
|
742
|
+
args2.push(colorCode + "m+" + module2.exports.humanize(this.diff) + "\x1B[0m");
|
|
743
|
+
} else {
|
|
744
|
+
args2[0] = getDate() + name + " " + args2[0];
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
function getDate() {
|
|
748
|
+
if (exports2.inspectOpts.hideDate) {
|
|
749
|
+
return "";
|
|
750
|
+
}
|
|
751
|
+
return (/* @__PURE__ */ new Date()).toISOString() + " ";
|
|
752
|
+
}
|
|
753
|
+
function log(...args2) {
|
|
754
|
+
return process.stderr.write(util.format(...args2) + "\n");
|
|
755
|
+
}
|
|
756
|
+
function save(namespaces) {
|
|
757
|
+
if (namespaces) {
|
|
758
|
+
process.env.DEBUG = namespaces;
|
|
759
|
+
} else {
|
|
760
|
+
delete process.env.DEBUG;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function load() {
|
|
764
|
+
return process.env.DEBUG;
|
|
765
|
+
}
|
|
766
|
+
function init(debug) {
|
|
767
|
+
debug.inspectOpts = {};
|
|
768
|
+
const keys = Object.keys(exports2.inspectOpts);
|
|
769
|
+
for (let i = 0; i < keys.length; i++) {
|
|
770
|
+
debug.inspectOpts[keys[i]] = exports2.inspectOpts[keys[i]];
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
module2.exports = require_common()(exports2);
|
|
774
|
+
var { formatters } = module2.exports;
|
|
775
|
+
formatters.o = function(v) {
|
|
776
|
+
this.inspectOpts.colors = this.useColors;
|
|
777
|
+
return util.inspect(v, this.inspectOpts).split("\n").map((str) => str.trim()).join(" ");
|
|
778
|
+
};
|
|
779
|
+
formatters.O = function(v) {
|
|
780
|
+
this.inspectOpts.colors = this.useColors;
|
|
781
|
+
return util.inspect(v, this.inspectOpts);
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
// ../../node_modules/debug/src/index.js
|
|
787
|
+
var require_src = __commonJS({
|
|
788
|
+
"../../node_modules/debug/src/index.js"(exports2, module2) {
|
|
789
|
+
"use strict";
|
|
790
|
+
if (typeof process === "undefined" || process.type === "renderer" || process.browser === true || process.__nwjs) {
|
|
791
|
+
module2.exports = require_browser();
|
|
792
|
+
} else {
|
|
793
|
+
module2.exports = require_node();
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
// ../../node_modules/eastasianwidth/eastasianwidth.js
|
|
799
|
+
var require_eastasianwidth = __commonJS({
|
|
800
|
+
"../../node_modules/eastasianwidth/eastasianwidth.js"(exports2, module2) {
|
|
801
|
+
"use strict";
|
|
802
|
+
var eaw = {};
|
|
803
|
+
if ("undefined" == typeof module2) {
|
|
804
|
+
window.eastasianwidth = eaw;
|
|
805
|
+
} else {
|
|
806
|
+
module2.exports = eaw;
|
|
807
|
+
}
|
|
808
|
+
eaw.eastAsianWidth = function(character) {
|
|
809
|
+
var x = character.charCodeAt(0);
|
|
810
|
+
var y = character.length == 2 ? character.charCodeAt(1) : 0;
|
|
811
|
+
var codePoint = x;
|
|
812
|
+
if (55296 <= x && x <= 56319 && (56320 <= y && y <= 57343)) {
|
|
813
|
+
x &= 1023;
|
|
814
|
+
y &= 1023;
|
|
815
|
+
codePoint = x << 10 | y;
|
|
816
|
+
codePoint += 65536;
|
|
817
|
+
}
|
|
818
|
+
if (12288 == codePoint || 65281 <= codePoint && codePoint <= 65376 || 65504 <= codePoint && codePoint <= 65510) {
|
|
819
|
+
return "F";
|
|
820
|
+
}
|
|
821
|
+
if (8361 == codePoint || 65377 <= codePoint && codePoint <= 65470 || 65474 <= codePoint && codePoint <= 65479 || 65482 <= codePoint && codePoint <= 65487 || 65490 <= codePoint && codePoint <= 65495 || 65498 <= codePoint && codePoint <= 65500 || 65512 <= codePoint && codePoint <= 65518) {
|
|
822
|
+
return "H";
|
|
823
|
+
}
|
|
824
|
+
if (4352 <= codePoint && codePoint <= 4447 || 4515 <= codePoint && codePoint <= 4519 || 4602 <= codePoint && codePoint <= 4607 || 9001 <= codePoint && codePoint <= 9002 || 11904 <= codePoint && codePoint <= 11929 || 11931 <= codePoint && codePoint <= 12019 || 12032 <= codePoint && codePoint <= 12245 || 12272 <= codePoint && codePoint <= 12283 || 12289 <= codePoint && codePoint <= 12350 || 12353 <= codePoint && codePoint <= 12438 || 12441 <= codePoint && codePoint <= 12543 || 12549 <= codePoint && codePoint <= 12589 || 12593 <= codePoint && codePoint <= 12686 || 12688 <= codePoint && codePoint <= 12730 || 12736 <= codePoint && codePoint <= 12771 || 12784 <= codePoint && codePoint <= 12830 || 12832 <= codePoint && codePoint <= 12871 || 12880 <= codePoint && codePoint <= 13054 || 13056 <= codePoint && codePoint <= 19903 || 19968 <= codePoint && codePoint <= 42124 || 42128 <= codePoint && codePoint <= 42182 || 43360 <= codePoint && codePoint <= 43388 || 44032 <= codePoint && codePoint <= 55203 || 55216 <= codePoint && codePoint <= 55238 || 55243 <= codePoint && codePoint <= 55291 || 63744 <= codePoint && codePoint <= 64255 || 65040 <= codePoint && codePoint <= 65049 || 65072 <= codePoint && codePoint <= 65106 || 65108 <= codePoint && codePoint <= 65126 || 65128 <= codePoint && codePoint <= 65131 || 110592 <= codePoint && codePoint <= 110593 || 127488 <= codePoint && codePoint <= 127490 || 127504 <= codePoint && codePoint <= 127546 || 127552 <= codePoint && codePoint <= 127560 || 127568 <= codePoint && codePoint <= 127569 || 131072 <= codePoint && codePoint <= 194367 || 177984 <= codePoint && codePoint <= 196605 || 196608 <= codePoint && codePoint <= 262141) {
|
|
825
|
+
return "W";
|
|
826
|
+
}
|
|
827
|
+
if (32 <= codePoint && codePoint <= 126 || 162 <= codePoint && codePoint <= 163 || 165 <= codePoint && codePoint <= 166 || 172 == codePoint || 175 == codePoint || 10214 <= codePoint && codePoint <= 10221 || 10629 <= codePoint && codePoint <= 10630) {
|
|
828
|
+
return "Na";
|
|
829
|
+
}
|
|
830
|
+
if (161 == codePoint || 164 == codePoint || 167 <= codePoint && codePoint <= 168 || 170 == codePoint || 173 <= codePoint && codePoint <= 174 || 176 <= codePoint && codePoint <= 180 || 182 <= codePoint && codePoint <= 186 || 188 <= codePoint && codePoint <= 191 || 198 == codePoint || 208 == codePoint || 215 <= codePoint && codePoint <= 216 || 222 <= codePoint && codePoint <= 225 || 230 == codePoint || 232 <= codePoint && codePoint <= 234 || 236 <= codePoint && codePoint <= 237 || 240 == codePoint || 242 <= codePoint && codePoint <= 243 || 247 <= codePoint && codePoint <= 250 || 252 == codePoint || 254 == codePoint || 257 == codePoint || 273 == codePoint || 275 == codePoint || 283 == codePoint || 294 <= codePoint && codePoint <= 295 || 299 == codePoint || 305 <= codePoint && codePoint <= 307 || 312 == codePoint || 319 <= codePoint && codePoint <= 322 || 324 == codePoint || 328 <= codePoint && codePoint <= 331 || 333 == codePoint || 338 <= codePoint && codePoint <= 339 || 358 <= codePoint && codePoint <= 359 || 363 == codePoint || 462 == codePoint || 464 == codePoint || 466 == codePoint || 468 == codePoint || 470 == codePoint || 472 == codePoint || 474 == codePoint || 476 == codePoint || 593 == codePoint || 609 == codePoint || 708 == codePoint || 711 == codePoint || 713 <= codePoint && codePoint <= 715 || 717 == codePoint || 720 == codePoint || 728 <= codePoint && codePoint <= 731 || 733 == codePoint || 735 == codePoint || 768 <= codePoint && codePoint <= 879 || 913 <= codePoint && codePoint <= 929 || 931 <= codePoint && codePoint <= 937 || 945 <= codePoint && codePoint <= 961 || 963 <= codePoint && codePoint <= 969 || 1025 == codePoint || 1040 <= codePoint && codePoint <= 1103 || 1105 == codePoint || 8208 == codePoint || 8211 <= codePoint && codePoint <= 8214 || 8216 <= codePoint && codePoint <= 8217 || 8220 <= codePoint && codePoint <= 8221 || 8224 <= codePoint && codePoint <= 8226 || 8228 <= codePoint && codePoint <= 8231 || 8240 == codePoint || 8242 <= codePoint && codePoint <= 8243 || 8245 == codePoint || 8251 == codePoint || 8254 == codePoint || 8308 == codePoint || 8319 == codePoint || 8321 <= codePoint && codePoint <= 8324 || 8364 == codePoint || 8451 == codePoint || 8453 == codePoint || 8457 == codePoint || 8467 == codePoint || 8470 == codePoint || 8481 <= codePoint && codePoint <= 8482 || 8486 == codePoint || 8491 == codePoint || 8531 <= codePoint && codePoint <= 8532 || 8539 <= codePoint && codePoint <= 8542 || 8544 <= codePoint && codePoint <= 8555 || 8560 <= codePoint && codePoint <= 8569 || 8585 == codePoint || 8592 <= codePoint && codePoint <= 8601 || 8632 <= codePoint && codePoint <= 8633 || 8658 == codePoint || 8660 == codePoint || 8679 == codePoint || 8704 == codePoint || 8706 <= codePoint && codePoint <= 8707 || 8711 <= codePoint && codePoint <= 8712 || 8715 == codePoint || 8719 == codePoint || 8721 == codePoint || 8725 == codePoint || 8730 == codePoint || 8733 <= codePoint && codePoint <= 8736 || 8739 == codePoint || 8741 == codePoint || 8743 <= codePoint && codePoint <= 8748 || 8750 == codePoint || 8756 <= codePoint && codePoint <= 8759 || 8764 <= codePoint && codePoint <= 8765 || 8776 == codePoint || 8780 == codePoint || 8786 == codePoint || 8800 <= codePoint && codePoint <= 8801 || 8804 <= codePoint && codePoint <= 8807 || 8810 <= codePoint && codePoint <= 8811 || 8814 <= codePoint && codePoint <= 8815 || 8834 <= codePoint && codePoint <= 8835 || 8838 <= codePoint && codePoint <= 8839 || 8853 == codePoint || 8857 == codePoint || 8869 == codePoint || 8895 == codePoint || 8978 == codePoint || 9312 <= codePoint && codePoint <= 9449 || 9451 <= codePoint && codePoint <= 9547 || 9552 <= codePoint && codePoint <= 9587 || 9600 <= codePoint && codePoint <= 9615 || 9618 <= codePoint && codePoint <= 9621 || 9632 <= codePoint && codePoint <= 9633 || 9635 <= codePoint && codePoint <= 9641 || 9650 <= codePoint && codePoint <= 9651 || 9654 <= codePoint && codePoint <= 9655 || 9660 <= codePoint && codePoint <= 9661 || 9664 <= codePoint && codePoint <= 9665 || 9670 <= codePoint && codePoint <= 9672 || 9675 == codePoint || 9678 <= codePoint && codePoint <= 9681 || 9698 <= codePoint && codePoint <= 9701 || 9711 == codePoint || 9733 <= codePoint && codePoint <= 9734 || 9737 == codePoint || 9742 <= codePoint && codePoint <= 9743 || 9748 <= codePoint && codePoint <= 9749 || 9756 == codePoint || 9758 == codePoint || 9792 == codePoint || 9794 == codePoint || 9824 <= codePoint && codePoint <= 9825 || 9827 <= codePoint && codePoint <= 9829 || 9831 <= codePoint && codePoint <= 9834 || 9836 <= codePoint && codePoint <= 9837 || 9839 == codePoint || 9886 <= codePoint && codePoint <= 9887 || 9918 <= codePoint && codePoint <= 9919 || 9924 <= codePoint && codePoint <= 9933 || 9935 <= codePoint && codePoint <= 9953 || 9955 == codePoint || 9960 <= codePoint && codePoint <= 9983 || 10045 == codePoint || 10071 == codePoint || 10102 <= codePoint && codePoint <= 10111 || 11093 <= codePoint && codePoint <= 11097 || 12872 <= codePoint && codePoint <= 12879 || 57344 <= codePoint && codePoint <= 63743 || 65024 <= codePoint && codePoint <= 65039 || 65533 == codePoint || 127232 <= codePoint && codePoint <= 127242 || 127248 <= codePoint && codePoint <= 127277 || 127280 <= codePoint && codePoint <= 127337 || 127344 <= codePoint && codePoint <= 127386 || 917760 <= codePoint && codePoint <= 917999 || 983040 <= codePoint && codePoint <= 1048573 || 1048576 <= codePoint && codePoint <= 1114109) {
|
|
831
|
+
return "A";
|
|
832
|
+
}
|
|
833
|
+
return "N";
|
|
834
|
+
};
|
|
835
|
+
eaw.characterLength = function(character) {
|
|
836
|
+
var code = this.eastAsianWidth(character);
|
|
837
|
+
if (code == "F" || code == "W" || code == "A") {
|
|
838
|
+
return 2;
|
|
839
|
+
} else {
|
|
840
|
+
return 1;
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
function stringToArray(string) {
|
|
844
|
+
return string.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
|
|
845
|
+
}
|
|
846
|
+
eaw.length = function(string) {
|
|
847
|
+
var characters = stringToArray(string);
|
|
848
|
+
var len = 0;
|
|
849
|
+
for (var i = 0; i < characters.length; i++) {
|
|
850
|
+
len = len + this.characterLength(characters[i]);
|
|
851
|
+
}
|
|
852
|
+
return len;
|
|
853
|
+
};
|
|
854
|
+
eaw.slice = function(text, start, end) {
|
|
855
|
+
textLen = eaw.length(text);
|
|
856
|
+
start = start ? start : 0;
|
|
857
|
+
end = end ? end : 1;
|
|
858
|
+
if (start < 0) {
|
|
859
|
+
start = textLen + start;
|
|
860
|
+
}
|
|
861
|
+
if (end < 0) {
|
|
862
|
+
end = textLen + end;
|
|
863
|
+
}
|
|
864
|
+
var result = "";
|
|
865
|
+
var eawLen = 0;
|
|
866
|
+
var chars = stringToArray(text);
|
|
867
|
+
for (var i = 0; i < chars.length; i++) {
|
|
868
|
+
var char = chars[i];
|
|
869
|
+
var charLen = eaw.length(char);
|
|
870
|
+
if (eawLen >= start - (charLen == 2 ? 1 : 0)) {
|
|
871
|
+
if (eawLen + charLen <= end) {
|
|
872
|
+
result += char;
|
|
873
|
+
} else {
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
eawLen += charLen;
|
|
878
|
+
}
|
|
879
|
+
return result;
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
// ../../node_modules/list-it/lib/data-cell.js
|
|
885
|
+
var require_data_cell = __commonJS({
|
|
886
|
+
"../../node_modules/list-it/lib/data-cell.js"(exports2, module2) {
|
|
887
|
+
"use strict";
|
|
888
|
+
var eaw = require_eastasianwidth();
|
|
889
|
+
function DataCell() {
|
|
890
|
+
this.data = "";
|
|
891
|
+
}
|
|
892
|
+
module2.exports = DataCell;
|
|
893
|
+
DataCell.prototype.getData = function() {
|
|
894
|
+
return this.data;
|
|
895
|
+
};
|
|
896
|
+
DataCell.prototype.setData = function(data) {
|
|
897
|
+
this.data = data;
|
|
898
|
+
};
|
|
899
|
+
DataCell.prototype.visibleLength = function() {
|
|
900
|
+
if (typeof this.data != "string") {
|
|
901
|
+
return ("" + this.data).length;
|
|
902
|
+
}
|
|
903
|
+
return DataCell.visibleLength(this.data);
|
|
904
|
+
};
|
|
905
|
+
DataCell.visibleLength = function(data) {
|
|
906
|
+
const s = data.replace(/\x1b[^m]*m/g, "");
|
|
907
|
+
return eaw.length(s);
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
// ../../node_modules/list-it/lib/row.js
|
|
913
|
+
var require_row = __commonJS({
|
|
914
|
+
"../../node_modules/list-it/lib/row.js"(exports2, module2) {
|
|
915
|
+
"use strict";
|
|
916
|
+
function Row() {
|
|
917
|
+
this.cells = [];
|
|
918
|
+
this.empty = true;
|
|
919
|
+
this.fixed = false;
|
|
920
|
+
}
|
|
921
|
+
module2.exports = Row;
|
|
922
|
+
Row.prototype.getCellLength = function() {
|
|
923
|
+
return this.cells.length;
|
|
924
|
+
};
|
|
925
|
+
Row.prototype.getCell = function(idx) {
|
|
926
|
+
return this.cells[idx];
|
|
927
|
+
};
|
|
928
|
+
Row.prototype.pushCell = function(cell) {
|
|
929
|
+
if (this.isFixed()) {
|
|
930
|
+
throw "pushCell Fail, The row was already fixed.";
|
|
931
|
+
}
|
|
932
|
+
this.empty = false;
|
|
933
|
+
return this.cells.push(cell);
|
|
934
|
+
};
|
|
935
|
+
Row.prototype.fix = function() {
|
|
936
|
+
this.fixed = true;
|
|
937
|
+
};
|
|
938
|
+
Row.prototype.isEmpty = function() {
|
|
939
|
+
return this.empty;
|
|
940
|
+
};
|
|
941
|
+
Row.prototype.isFixed = function() {
|
|
942
|
+
return this.fixed;
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
// ../../node_modules/list-it/lib/column.js
|
|
948
|
+
var require_column = __commonJS({
|
|
949
|
+
"../../node_modules/list-it/lib/column.js"(exports2, module2) {
|
|
950
|
+
"use strict";
|
|
951
|
+
var DataCell = require_data_cell();
|
|
952
|
+
function Column() {
|
|
953
|
+
this.opt = {
|
|
954
|
+
"autoAlign": false
|
|
955
|
+
};
|
|
956
|
+
this.width = 0;
|
|
957
|
+
this.textWidth = null;
|
|
958
|
+
this.intLen = 0;
|
|
959
|
+
this.fracLen = 0;
|
|
960
|
+
this.expLen = 0;
|
|
961
|
+
this.cellAtRow = {};
|
|
962
|
+
this.header = null;
|
|
963
|
+
}
|
|
964
|
+
module2.exports = Column;
|
|
965
|
+
Column.prototype.getWidth = function() {
|
|
966
|
+
return this.width;
|
|
967
|
+
};
|
|
968
|
+
Column.prototype.setTextWidth = function(textWidth) {
|
|
969
|
+
this.textWidth = textWidth;
|
|
970
|
+
};
|
|
971
|
+
Column.prototype.setCellAt = function(row, cell) {
|
|
972
|
+
this.cellAtRow[row] = cell;
|
|
973
|
+
};
|
|
974
|
+
Column.prototype.setHeader = function(header) {
|
|
975
|
+
this.header = header;
|
|
976
|
+
};
|
|
977
|
+
Column.prototype.hasHeader = function() {
|
|
978
|
+
return this.header != null;
|
|
979
|
+
};
|
|
980
|
+
Column.prototype.updateWidth = function() {
|
|
981
|
+
const headerWidth = !this.hasHeader() ? 0 : DataCell.visibleLength("" + this.header);
|
|
982
|
+
this.width = headerWidth;
|
|
983
|
+
Object.keys(this.cellAtRow).forEach((key) => {
|
|
984
|
+
const cell = this.cellAtRow[key];
|
|
985
|
+
const data = cell.getData();
|
|
986
|
+
let width = cell.visibleLength();
|
|
987
|
+
if (typeof data == "number") {
|
|
988
|
+
if (this.opt.autoAlign) {
|
|
989
|
+
this.updateNumWidth(data);
|
|
990
|
+
width = this.getNumMaxWidth();
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
if (width > this.width) {
|
|
994
|
+
this.width = width;
|
|
995
|
+
}
|
|
996
|
+
if (typeof data == "string") {
|
|
997
|
+
if (this.textWidth && this.textWidth > headerWidth) {
|
|
998
|
+
if (this.width > this.textWidth) {
|
|
999
|
+
this.width = this.textWidth;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
};
|
|
1005
|
+
Column.prototype.formatColumnHeader = function() {
|
|
1006
|
+
if (!this.hasHeader()) {
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
const width = this.getWidth();
|
|
1010
|
+
const header = this.header;
|
|
1011
|
+
const headerWidth = DataCell.visibleLength("" + header);
|
|
1012
|
+
if (header.length == headerWidth && width - headerWidth <= 0) {
|
|
1013
|
+
return ("" + header).substring(0, width);
|
|
1014
|
+
}
|
|
1015
|
+
return "" + header + " ".repeat(width - headerWidth);
|
|
1016
|
+
};
|
|
1017
|
+
Column.prototype.formatCell = function(data) {
|
|
1018
|
+
const width = this.getWidth();
|
|
1019
|
+
if (this.opt.autoAlign) {
|
|
1020
|
+
if (typeof data == "number") {
|
|
1021
|
+
return this.makeAutoAlignNum(data).padStart(width, " ");
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
const dataWidth = DataCell.visibleLength("" + data);
|
|
1025
|
+
if (data.length == dataWidth && width - dataWidth <= 0) {
|
|
1026
|
+
return ("" + data).substring(0, width);
|
|
1027
|
+
}
|
|
1028
|
+
return "" + data + " ".repeat(width - dataWidth);
|
|
1029
|
+
};
|
|
1030
|
+
Column.prototype.setAutoAlign = function(autoAlign) {
|
|
1031
|
+
this.opt.autoAlign = autoAlign;
|
|
1032
|
+
};
|
|
1033
|
+
Column.prototype.updateNumWidth = function(num) {
|
|
1034
|
+
const numInfo = this.analyzeNumber(num);
|
|
1035
|
+
const intLen = numInfo.intStr.length;
|
|
1036
|
+
const fracLen = numInfo.fracStr.length;
|
|
1037
|
+
const expLen = numInfo.expStr.length;
|
|
1038
|
+
if (intLen > this.intLen) {
|
|
1039
|
+
this.intLen = intLen;
|
|
1040
|
+
}
|
|
1041
|
+
if (fracLen > this.fracLen) {
|
|
1042
|
+
this.fracLen = fracLen;
|
|
1043
|
+
}
|
|
1044
|
+
if (expLen > this.expLen) {
|
|
1045
|
+
this.expLen = expLen;
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
Column.prototype.getNumMaxWidth = function() {
|
|
1049
|
+
return this.intLen + this.fracLen + (this.fracLen > 0 ? 1 : 0) + this.expLen + (this.expLen > 0 ? 1 : 0);
|
|
1050
|
+
};
|
|
1051
|
+
Column.prototype.makeAutoAlignNum = function(num) {
|
|
1052
|
+
const numInfo = this.analyzeNumber(num);
|
|
1053
|
+
const intStr = numInfo.intStr.padStart(this.intLen, " ");
|
|
1054
|
+
const fracStr = numInfo.expStr != "" ? numInfo.fracStr.padEnd(this.fracLen, "0") : numInfo.fracStr.padEnd(this.fracLen, " ");
|
|
1055
|
+
const expStr = numInfo.expStr.padEnd(this.expLen, " ");
|
|
1056
|
+
if (numInfo.expStr != "") {
|
|
1057
|
+
return [intStr, ".", fracStr, "e", expStr].join("");
|
|
1058
|
+
}
|
|
1059
|
+
if (numInfo.pointPos >= 0) {
|
|
1060
|
+
if (this.expLen > 0) {
|
|
1061
|
+
return [intStr, ".", fracStr, " ", expStr].join("");
|
|
1062
|
+
}
|
|
1063
|
+
return [intStr, ".", fracStr].join("");
|
|
1064
|
+
} else if (this.fracLen == 0) {
|
|
1065
|
+
return intStr;
|
|
1066
|
+
}
|
|
1067
|
+
if (this.expLen > 0) {
|
|
1068
|
+
return [intStr, ".0", fracStr.substr(1), " ", expStr].join("");
|
|
1069
|
+
}
|
|
1070
|
+
return [intStr, ".0", fracStr.substr(1)].join("");
|
|
1071
|
+
};
|
|
1072
|
+
Column.prototype.analyzeNumber = function(num) {
|
|
1073
|
+
const s = "" + num;
|
|
1074
|
+
let intStr = "";
|
|
1075
|
+
let fracStr = "";
|
|
1076
|
+
const pointPos = s.indexOf(".");
|
|
1077
|
+
const expIndex = s.indexOf("e");
|
|
1078
|
+
if (expIndex >= 0) {
|
|
1079
|
+
if (pointPos < 0) {
|
|
1080
|
+
return {
|
|
1081
|
+
pointPos: expIndex,
|
|
1082
|
+
intStr: s.substr(0, expIndex),
|
|
1083
|
+
fracStr: "0",
|
|
1084
|
+
expStr: s.substr(expIndex + 1)
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
return {
|
|
1088
|
+
pointPos,
|
|
1089
|
+
intStr: s.substr(0, pointPos),
|
|
1090
|
+
fracStr: s.substring(pointPos + 1, expIndex),
|
|
1091
|
+
expStr: s.substr(expIndex + 1)
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
if (pointPos < 0) {
|
|
1095
|
+
intStr = s;
|
|
1096
|
+
} else {
|
|
1097
|
+
intStr = s.substr(0, pointPos);
|
|
1098
|
+
fracStr = s.substr(pointPos + 1);
|
|
1099
|
+
}
|
|
1100
|
+
return {
|
|
1101
|
+
"pointPos": pointPos,
|
|
1102
|
+
"intStr": intStr,
|
|
1103
|
+
"fracStr": fracStr,
|
|
1104
|
+
"expStr": ""
|
|
1105
|
+
};
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
// ../../node_modules/ansi-escape-sequences/dist/index.cjs
|
|
1111
|
+
var require_dist = __commonJS({
|
|
1112
|
+
"../../node_modules/ansi-escape-sequences/dist/index.cjs"(exports2, module2) {
|
|
1113
|
+
"use strict";
|
|
1114
|
+
function isObject(input) {
|
|
1115
|
+
return typeof input === "object" && input !== null;
|
|
1116
|
+
}
|
|
1117
|
+
function isArrayLike(input) {
|
|
1118
|
+
return isObject(input) && typeof input.length === "number";
|
|
1119
|
+
}
|
|
1120
|
+
function arrayify(input) {
|
|
1121
|
+
if (Array.isArray(input)) {
|
|
1122
|
+
return input;
|
|
1123
|
+
} else if (input === void 0) {
|
|
1124
|
+
return [];
|
|
1125
|
+
} else if (isArrayLike(input) || input instanceof Set) {
|
|
1126
|
+
return Array.from(input);
|
|
1127
|
+
} else {
|
|
1128
|
+
return [input];
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
var csi = "\x1B[";
|
|
1132
|
+
var ansi = {};
|
|
1133
|
+
ansi.style = {
|
|
1134
|
+
reset: "\x1B[0m",
|
|
1135
|
+
bold: "\x1B[1m",
|
|
1136
|
+
italic: "\x1B[3m",
|
|
1137
|
+
underline: "\x1B[4m",
|
|
1138
|
+
fontDefault: "\x1B[10m",
|
|
1139
|
+
font2: "\x1B[11m",
|
|
1140
|
+
font3: "\x1B[12m",
|
|
1141
|
+
font4: "\x1B[13m",
|
|
1142
|
+
font5: "\x1B[14m",
|
|
1143
|
+
font6: "\x1B[15m",
|
|
1144
|
+
imageNegative: "\x1B[7m",
|
|
1145
|
+
imagePositive: "\x1B[27m",
|
|
1146
|
+
black: "\x1B[30m",
|
|
1147
|
+
red: "\x1B[31m",
|
|
1148
|
+
green: "\x1B[32m",
|
|
1149
|
+
yellow: "\x1B[33m",
|
|
1150
|
+
blue: "\x1B[34m",
|
|
1151
|
+
magenta: "\x1B[35m",
|
|
1152
|
+
cyan: "\x1B[36m",
|
|
1153
|
+
white: "\x1B[37m",
|
|
1154
|
+
grey: "\x1B[90m",
|
|
1155
|
+
gray: "\x1B[90m",
|
|
1156
|
+
brightRed: "\x1B[91m",
|
|
1157
|
+
brightGreen: "\x1B[92m",
|
|
1158
|
+
brightYellow: "\x1B[93m",
|
|
1159
|
+
brightBlue: "\x1B[94m",
|
|
1160
|
+
brightMagenta: "\x1B[95m",
|
|
1161
|
+
brightCyan: "\x1B[96m",
|
|
1162
|
+
brightWhite: "\x1B[97m",
|
|
1163
|
+
"bg-black": "\x1B[40m",
|
|
1164
|
+
"bg-red": "\x1B[41m",
|
|
1165
|
+
"bg-green": "\x1B[42m",
|
|
1166
|
+
"bg-yellow": "\x1B[43m",
|
|
1167
|
+
"bg-blue": "\x1B[44m",
|
|
1168
|
+
"bg-magenta": "\x1B[45m",
|
|
1169
|
+
"bg-cyan": "\x1B[46m",
|
|
1170
|
+
"bg-white": "\x1B[47m",
|
|
1171
|
+
"bg-grey": "\x1B[100m",
|
|
1172
|
+
"bg-gray": "\x1B[100m",
|
|
1173
|
+
"bg-brightRed": "\x1B[101m",
|
|
1174
|
+
"bg-brightGreen": "\x1B[102m",
|
|
1175
|
+
"bg-brightYellow": "\x1B[103m",
|
|
1176
|
+
"bg-brightBlue": "\x1B[104m",
|
|
1177
|
+
"bg-brightMagenta": "\x1B[105m",
|
|
1178
|
+
"bg-brightCyan": "\x1B[106m",
|
|
1179
|
+
"bg-brightWhite": "\x1B[107m"
|
|
1180
|
+
};
|
|
1181
|
+
ansi.rgb = function(r, g, b) {
|
|
1182
|
+
return `\x1B[38;2;${r};${g};${b}m`;
|
|
1183
|
+
};
|
|
1184
|
+
ansi.bgRgb = function(r, g, b) {
|
|
1185
|
+
return `\x1B[48;2;${r};${g};${b}m`;
|
|
1186
|
+
};
|
|
1187
|
+
ansi.styles = function(styles) {
|
|
1188
|
+
styles = arrayify(styles);
|
|
1189
|
+
return styles.map(function(effect) {
|
|
1190
|
+
const rgbMatches = effect.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
1191
|
+
const bgRgbMatches = effect.match(/bg-rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
1192
|
+
if (bgRgbMatches) {
|
|
1193
|
+
const [full, r, g, b] = bgRgbMatches;
|
|
1194
|
+
return ansi.bgRgb(r, g, b);
|
|
1195
|
+
} else if (rgbMatches) {
|
|
1196
|
+
const [full, r, g, b] = rgbMatches;
|
|
1197
|
+
return ansi.rgb(r, g, b);
|
|
1198
|
+
} else {
|
|
1199
|
+
return ansi.style[effect];
|
|
1200
|
+
}
|
|
1201
|
+
}).join("");
|
|
1202
|
+
};
|
|
1203
|
+
ansi.format = function(str, styleArray) {
|
|
1204
|
+
const re = /\[([\w\s-\(\),]+)\]{([^]*?)}/;
|
|
1205
|
+
let matches;
|
|
1206
|
+
str = String(str);
|
|
1207
|
+
if (!str) return "";
|
|
1208
|
+
while (matches = str.match(re)) {
|
|
1209
|
+
const inlineStyles = matches[1].split(/\s+/);
|
|
1210
|
+
const inlineString = matches[2];
|
|
1211
|
+
str = str.replace(matches[0], ansi.format(inlineString, inlineStyles));
|
|
1212
|
+
}
|
|
1213
|
+
return styleArray && styleArray.length ? ansi.styles(styleArray) + str + ansi.style.reset : str;
|
|
1214
|
+
};
|
|
1215
|
+
ansi.cursor = {
|
|
1216
|
+
/**
|
|
1217
|
+
* Moves the cursor `lines` cells up. If the cursor is already at the edge of the screen, this has no effect
|
|
1218
|
+
* @param [lines=1] {number}
|
|
1219
|
+
* @return {string}
|
|
1220
|
+
*/
|
|
1221
|
+
up: function(lines) {
|
|
1222
|
+
return csi + (lines || 1) + "A";
|
|
1223
|
+
},
|
|
1224
|
+
/**
|
|
1225
|
+
* Moves the cursor `lines` cells down. If the cursor is already at the edge of the screen, this has no effect
|
|
1226
|
+
* @param [lines=1] {number}
|
|
1227
|
+
* @return {string}
|
|
1228
|
+
*/
|
|
1229
|
+
down: function(lines) {
|
|
1230
|
+
return csi + (lines || 1) + "B";
|
|
1231
|
+
},
|
|
1232
|
+
/**
|
|
1233
|
+
* Moves the cursor `lines` cells forward. If the cursor is already at the edge of the screen, this has no effect
|
|
1234
|
+
* @param [lines=1] {number}
|
|
1235
|
+
* @return {string}
|
|
1236
|
+
*/
|
|
1237
|
+
forward: function(lines) {
|
|
1238
|
+
return csi + (lines || 1) + "C";
|
|
1239
|
+
},
|
|
1240
|
+
/**
|
|
1241
|
+
* Moves the cursor `lines` cells back. If the cursor is already at the edge of the screen, this has no effect
|
|
1242
|
+
* @param [lines=1] {number}
|
|
1243
|
+
* @return {string}
|
|
1244
|
+
*/
|
|
1245
|
+
back: function(lines) {
|
|
1246
|
+
return csi + (lines || 1) + "D";
|
|
1247
|
+
},
|
|
1248
|
+
/**
|
|
1249
|
+
* Moves cursor to beginning of the line n lines down.
|
|
1250
|
+
* @param [lines=1] {number}
|
|
1251
|
+
* @return {string}
|
|
1252
|
+
*/
|
|
1253
|
+
nextLine: function(lines) {
|
|
1254
|
+
return csi + (lines || 1) + "E";
|
|
1255
|
+
},
|
|
1256
|
+
/**
|
|
1257
|
+
* Moves cursor to beginning of the line n lines up.
|
|
1258
|
+
* @param [lines=1] {number}
|
|
1259
|
+
* @return {string}
|
|
1260
|
+
*/
|
|
1261
|
+
previousLine: function(lines) {
|
|
1262
|
+
return csi + (lines || 1) + "F";
|
|
1263
|
+
},
|
|
1264
|
+
/**
|
|
1265
|
+
* Moves the cursor to column n.
|
|
1266
|
+
* @param n {number} - column number
|
|
1267
|
+
* @return {string}
|
|
1268
|
+
*/
|
|
1269
|
+
horizontalAbsolute: function(n) {
|
|
1270
|
+
return csi + n + "G";
|
|
1271
|
+
},
|
|
1272
|
+
/**
|
|
1273
|
+
* Moves the cursor to row n, column m. The values are 1-based, and default to 1 (top left corner) if omitted.
|
|
1274
|
+
* @param n {number} - row number
|
|
1275
|
+
* @param m {number} - column number
|
|
1276
|
+
* @return {string}
|
|
1277
|
+
*/
|
|
1278
|
+
position: function(n, m) {
|
|
1279
|
+
return csi + (n || 1) + ";" + (m || 1) + "H";
|
|
1280
|
+
},
|
|
1281
|
+
/**
|
|
1282
|
+
* Hides the cursor
|
|
1283
|
+
*/
|
|
1284
|
+
hide: csi + "?25l",
|
|
1285
|
+
/**
|
|
1286
|
+
* Shows the cursor
|
|
1287
|
+
*/
|
|
1288
|
+
show: csi + "?25h"
|
|
1289
|
+
};
|
|
1290
|
+
ansi.erase = {
|
|
1291
|
+
/**
|
|
1292
|
+
* Clears part of the screen. If n is 0 (or missing), clear from cursor to end of screen. If n is 1, clear from cursor to beginning of the screen. If n is 2, clear entire screen.
|
|
1293
|
+
* @param n {number}
|
|
1294
|
+
* @return {string}
|
|
1295
|
+
*/
|
|
1296
|
+
display: function(n) {
|
|
1297
|
+
return csi + (n || 0) + "J";
|
|
1298
|
+
},
|
|
1299
|
+
/**
|
|
1300
|
+
* Erases part of the line. If n is zero (or missing), clear from cursor to the end of the line. If n is one, clear from cursor to beginning of the line. If n is two, clear entire line. Cursor position does not change.
|
|
1301
|
+
* @param n {number}
|
|
1302
|
+
* @return {string}
|
|
1303
|
+
*/
|
|
1304
|
+
inLine: function(n) {
|
|
1305
|
+
return csi + (n || 0) + "K";
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
module2.exports = ansi;
|
|
1309
|
+
}
|
|
1310
|
+
});
|
|
1311
|
+
|
|
1312
|
+
// ../../node_modules/list-it/lib/list-it-buffer.js
|
|
1313
|
+
var require_list_it_buffer = __commonJS({
|
|
1314
|
+
"../../node_modules/list-it/lib/list-it-buffer.js"(exports2, module2) {
|
|
1315
|
+
"use strict";
|
|
1316
|
+
var debug = require_src()("list-it-buffer");
|
|
1317
|
+
var DataCell = require_data_cell();
|
|
1318
|
+
var Row = require_row();
|
|
1319
|
+
var Column = require_column();
|
|
1320
|
+
var ansi = require_dist();
|
|
1321
|
+
function ListItBuffer(opt) {
|
|
1322
|
+
opt = opt || {};
|
|
1323
|
+
this.opt = {
|
|
1324
|
+
"autoAlign": true,
|
|
1325
|
+
"columnWidth": null,
|
|
1326
|
+
"header": null,
|
|
1327
|
+
"headerBold": false,
|
|
1328
|
+
"headerColor": "",
|
|
1329
|
+
"headerUnderline": false
|
|
1330
|
+
};
|
|
1331
|
+
if (opt.header != null && !Array.isArray(opt.header)) {
|
|
1332
|
+
throw new Error([
|
|
1333
|
+
`Invalid header was specified. It must be an array, but (${JSON.stringify(opt.header)}):${typeof opt.header} was specified.`
|
|
1334
|
+
].join(" "));
|
|
1335
|
+
}
|
|
1336
|
+
if (opt.headerColor && !(opt.headerColor in COLORS)) {
|
|
1337
|
+
throw new Error([
|
|
1338
|
+
`Invalid color ${JSON.stringify(opt.headerColor)} was specified.`,
|
|
1339
|
+
"Available color names:",
|
|
1340
|
+
...AVAILABLE_COLORS.map((color) => `* ${JSON.stringify(color)}`)
|
|
1341
|
+
].join("\n"));
|
|
1342
|
+
}
|
|
1343
|
+
Object.keys(this.opt).forEach((key) => {
|
|
1344
|
+
if (key in opt) {
|
|
1345
|
+
this.opt[key] = opt[key];
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
this.lines = [];
|
|
1349
|
+
this.columns = [];
|
|
1350
|
+
this.columnWidth = this.opt.columnWidth;
|
|
1351
|
+
if (this.opt.header) {
|
|
1352
|
+
this.setHeaderRow(this.opt.header);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
module2.exports = ListItBuffer;
|
|
1356
|
+
ListItBuffer.prototype.nl = function() {
|
|
1357
|
+
const lastRowIndex = this.lines.length - 1;
|
|
1358
|
+
if (lastRowIndex >= 0 && !this.lines[lastRowIndex].isFixed()) {
|
|
1359
|
+
this.lines[lastRowIndex].fix();
|
|
1360
|
+
}
|
|
1361
|
+
this.pushNewRow();
|
|
1362
|
+
return this;
|
|
1363
|
+
};
|
|
1364
|
+
ListItBuffer.prototype.d = function(data) {
|
|
1365
|
+
if (arguments.length > 1) {
|
|
1366
|
+
const array = Array.apply(null, arguments);
|
|
1367
|
+
if (ListItBuffer.isMultiDimensionalArray(array)) {
|
|
1368
|
+
array.forEach((row) => this.addRow(row));
|
|
1369
|
+
} else {
|
|
1370
|
+
array.forEach((data2) => this.d(data2));
|
|
1371
|
+
}
|
|
1372
|
+
return this;
|
|
1373
|
+
}
|
|
1374
|
+
if (Array.isArray(data)) {
|
|
1375
|
+
if (ListItBuffer.isMultiDimensionalArray(data)) {
|
|
1376
|
+
data.forEach((row) => this.addRow(row));
|
|
1377
|
+
} else if (ListItBuffer.isObjectArray(data)) {
|
|
1378
|
+
data = objectArrayToTable(data);
|
|
1379
|
+
if (!this.header && (this.opt.headerBold || this.opt.headerColor || this.opt.headerUnderline)) {
|
|
1380
|
+
this.setHeaderRow(data.shift());
|
|
1381
|
+
}
|
|
1382
|
+
data.forEach((row) => this.addRow(row));
|
|
1383
|
+
} else {
|
|
1384
|
+
this.addRow(data);
|
|
1385
|
+
}
|
|
1386
|
+
return this;
|
|
1387
|
+
}
|
|
1388
|
+
const rowidx = this.lines.length - 1;
|
|
1389
|
+
if (rowidx < 0 || this.lines[rowidx].isFixed()) {
|
|
1390
|
+
this.pushNewRow();
|
|
1391
|
+
}
|
|
1392
|
+
const cell = new DataCell();
|
|
1393
|
+
cell.setData(data);
|
|
1394
|
+
const iRow = this.lines.length - 1;
|
|
1395
|
+
let iCol = this.lines[iRow].getCellLength();
|
|
1396
|
+
if (iCol >= this.columns.length) {
|
|
1397
|
+
this.addColumn();
|
|
1398
|
+
}
|
|
1399
|
+
this.columns[iCol].setCellAt(iRow, cell);
|
|
1400
|
+
this.lines[iRow].pushCell(cell);
|
|
1401
|
+
return this;
|
|
1402
|
+
};
|
|
1403
|
+
ListItBuffer.isMultiDimensionalArray = function(arr) {
|
|
1404
|
+
if (!Array.isArray(arr)) {
|
|
1405
|
+
throw Error("The parameter arr must be array");
|
|
1406
|
+
}
|
|
1407
|
+
for (let element of arr) {
|
|
1408
|
+
if (!Array.isArray(element)) {
|
|
1409
|
+
return false;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
return true;
|
|
1413
|
+
};
|
|
1414
|
+
ListItBuffer.isObjectArray = function(arr) {
|
|
1415
|
+
if (!Array.isArray(arr)) {
|
|
1416
|
+
throw Error("The parameter arr must be array");
|
|
1417
|
+
}
|
|
1418
|
+
const ctor = arr[0].constructor;
|
|
1419
|
+
for (let element of arr) {
|
|
1420
|
+
if (typeof element != "object") {
|
|
1421
|
+
return false;
|
|
1422
|
+
} else {
|
|
1423
|
+
if (element.constructor.name != ctor.name) {
|
|
1424
|
+
return false;
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
return true;
|
|
1429
|
+
};
|
|
1430
|
+
ListItBuffer.prototype.addRow = function(row) {
|
|
1431
|
+
row.forEach((col) => {
|
|
1432
|
+
switch (typeof col) {
|
|
1433
|
+
case "string":
|
|
1434
|
+
case "number":
|
|
1435
|
+
this.d(col);
|
|
1436
|
+
break;
|
|
1437
|
+
default:
|
|
1438
|
+
this.d(col != null ? col.toString() : "(null)");
|
|
1439
|
+
break;
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
this.nl();
|
|
1443
|
+
};
|
|
1444
|
+
ListItBuffer.prototype.pushNewRow = function() {
|
|
1445
|
+
this.lines.push(new Row());
|
|
1446
|
+
};
|
|
1447
|
+
ListItBuffer.prototype.toString = function() {
|
|
1448
|
+
const rows = [];
|
|
1449
|
+
this.columns.forEach((column, iCol) => {
|
|
1450
|
+
if (this.header != null) {
|
|
1451
|
+
column.setHeader(this.header[iCol] || "");
|
|
1452
|
+
}
|
|
1453
|
+
column.setTextWidth(this.getColumnWidth(iCol));
|
|
1454
|
+
column.updateWidth();
|
|
1455
|
+
});
|
|
1456
|
+
if (this.header != null) {
|
|
1457
|
+
const headerLine = this.applyHeaderStyleOption(
|
|
1458
|
+
this.columns.map((column) => column.formatColumnHeader()).join(" ")
|
|
1459
|
+
);
|
|
1460
|
+
rows.push(headerLine);
|
|
1461
|
+
const headerUnderline = this.generateHeaderUnderline();
|
|
1462
|
+
if (headerUnderline) {
|
|
1463
|
+
rows.push(headerUnderline);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
this.lines.forEach((line) => {
|
|
1467
|
+
if (line.isFixed() || !line.isEmpty()) {
|
|
1468
|
+
if (line.isEmpty()) {
|
|
1469
|
+
rows.push("\n");
|
|
1470
|
+
} else {
|
|
1471
|
+
rows.push(this.columns.map((column, iCol) => {
|
|
1472
|
+
const cell = line.getCell(iCol);
|
|
1473
|
+
const data = cell.getData();
|
|
1474
|
+
return column.formatCell(data);
|
|
1475
|
+
}).join(" "));
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
return rows.join("\n");
|
|
1480
|
+
};
|
|
1481
|
+
var COLORS = {};
|
|
1482
|
+
var BGCOLORS = {};
|
|
1483
|
+
Object.keys(ansi.style).forEach((key) => {
|
|
1484
|
+
const value = ansi.style[key];
|
|
1485
|
+
if (/^bg-/.test(key)) {
|
|
1486
|
+
BGCOLORS[key.substr(3)] = value;
|
|
1487
|
+
} else {
|
|
1488
|
+
COLORS[key] = value;
|
|
1489
|
+
debug(`COLOR-KEY: ${key}`);
|
|
1490
|
+
}
|
|
1491
|
+
});
|
|
1492
|
+
Object.keys(COLORS).forEach((key) => {
|
|
1493
|
+
if (!(key in BGCOLORS)) {
|
|
1494
|
+
delete COLORS[key];
|
|
1495
|
+
debug(`remove COLOR-KEY: ${key}`);
|
|
1496
|
+
}
|
|
1497
|
+
});
|
|
1498
|
+
var AVAILABLE_COLORS = Object.keys(COLORS);
|
|
1499
|
+
debug(`AVAILABLE_COLORS:${JSON.stringify(AVAILABLE_COLORS)}`);
|
|
1500
|
+
ListItBuffer.prototype.applyHeaderStyleOption = function(line) {
|
|
1501
|
+
if (!this.opt.headerBold && !this.opt.headerColor) {
|
|
1502
|
+
return line;
|
|
1503
|
+
}
|
|
1504
|
+
const textBuffer = [];
|
|
1505
|
+
if (this.opt.headerBold) {
|
|
1506
|
+
textBuffer.push(ansi.style.bold);
|
|
1507
|
+
}
|
|
1508
|
+
if (this.opt.headerColor) {
|
|
1509
|
+
textBuffer.push(COLORS[this.opt.headerColor]);
|
|
1510
|
+
}
|
|
1511
|
+
textBuffer.push(line);
|
|
1512
|
+
textBuffer.push(ansi.style.reset);
|
|
1513
|
+
return textBuffer.join("");
|
|
1514
|
+
};
|
|
1515
|
+
ListItBuffer.prototype.generateHeaderUnderline = function() {
|
|
1516
|
+
if (!this.opt.headerUnderline) {
|
|
1517
|
+
return null;
|
|
1518
|
+
}
|
|
1519
|
+
if (this.header == null) {
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
return this.columns.map(
|
|
1523
|
+
(column) => "-".repeat(column.getWidth())
|
|
1524
|
+
).join(" ");
|
|
1525
|
+
};
|
|
1526
|
+
function objectArrayToTable(objects) {
|
|
1527
|
+
const keys = Object.keys(objects[0]);
|
|
1528
|
+
const body = objects.map((item) => keys.map((key) => {
|
|
1529
|
+
if (item[key] != null && typeof item[key] == "object" && item[key].constructor.name == "Date") {
|
|
1530
|
+
return item[key].toISOString();
|
|
1531
|
+
}
|
|
1532
|
+
return item[key];
|
|
1533
|
+
}));
|
|
1534
|
+
return [keys, ...body];
|
|
1535
|
+
}
|
|
1536
|
+
ListItBuffer.prototype.setColumnWidth = function(indexOfColumns, width) {
|
|
1537
|
+
this.columnWidth = this.columnWidth || [];
|
|
1538
|
+
if (typeof indexOfColumns !== "number") {
|
|
1539
|
+
throw new Error("indexOfColumns must be a number");
|
|
1540
|
+
}
|
|
1541
|
+
if (!width) {
|
|
1542
|
+
delete this.columnWidth[indexOfColumns];
|
|
1543
|
+
} else {
|
|
1544
|
+
if (typeof width !== "number") {
|
|
1545
|
+
throw new Error("width must be a number");
|
|
1546
|
+
}
|
|
1547
|
+
this.columnWidth[indexOfColumns] = width;
|
|
1548
|
+
}
|
|
1549
|
+
return this;
|
|
1550
|
+
};
|
|
1551
|
+
ListItBuffer.prototype.setColumnWidthAll = function(widthForAll) {
|
|
1552
|
+
if (widthForAll != null && !Array.isArray(widthForAll) && typeof widthForAll !== "number") {
|
|
1553
|
+
throw new Error(
|
|
1554
|
+
"widthForAll must be one of a null, an Array or a number"
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1557
|
+
if (Array.isArray(widthForAll)) {
|
|
1558
|
+
for (let i = 0; i < widthForAll.length; i++) {
|
|
1559
|
+
const width = widthForAll[i];
|
|
1560
|
+
if (width != void 0 && typeof width !== "number") {
|
|
1561
|
+
throw new Error(
|
|
1562
|
+
`widthForAll[${i}] must be an undefined or a number`
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
this.columnWidth = widthForAll;
|
|
1568
|
+
return this;
|
|
1569
|
+
};
|
|
1570
|
+
ListItBuffer.prototype.getColumnWidth = function(indexOfColumns) {
|
|
1571
|
+
if (Array.isArray(this.columnWidth)) {
|
|
1572
|
+
return this.columnWidth[indexOfColumns];
|
|
1573
|
+
}
|
|
1574
|
+
return this.columnWidth;
|
|
1575
|
+
};
|
|
1576
|
+
ListItBuffer.prototype.setHeaderRow = function(header) {
|
|
1577
|
+
if (header && !Array.isArray(header)) {
|
|
1578
|
+
throw new Error([
|
|
1579
|
+
"The header must be an array,",
|
|
1580
|
+
`but ${typeof header} was specified.`,
|
|
1581
|
+
`header: ${JSON.stringify(header)}`
|
|
1582
|
+
].join(" "));
|
|
1583
|
+
}
|
|
1584
|
+
this.header = header;
|
|
1585
|
+
if (this.header == null) {
|
|
1586
|
+
this.columns.forEach((column) => column.setHeader(null));
|
|
1587
|
+
} else {
|
|
1588
|
+
this.header.forEach((headerText, iCol) => {
|
|
1589
|
+
if (iCol >= this.columns.length) {
|
|
1590
|
+
this.addColumn(headerText);
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
return this;
|
|
1595
|
+
};
|
|
1596
|
+
ListItBuffer.prototype.addColumn = function(headerText) {
|
|
1597
|
+
const column = new Column();
|
|
1598
|
+
if (headerText) {
|
|
1599
|
+
column.setHeader(headerText);
|
|
1600
|
+
}
|
|
1601
|
+
if (this.opt.autoAlign) {
|
|
1602
|
+
column.setAutoAlign(true);
|
|
1603
|
+
}
|
|
1604
|
+
this.columns.push(column);
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
// ../../node_modules/list-it/index.js
|
|
1610
|
+
var require_list_it = __commonJS({
|
|
1611
|
+
"../../node_modules/list-it/index.js"(exports2, module2) {
|
|
1612
|
+
"use strict";
|
|
1613
|
+
var ListItBuffer = require_list_it_buffer();
|
|
1614
|
+
function ListIt2(opt) {
|
|
1615
|
+
ListItBuffer.call(this, opt);
|
|
1616
|
+
}
|
|
1617
|
+
ListIt2.prototype = new ListItBuffer();
|
|
1618
|
+
ListIt2.buffer = function(opt) {
|
|
1619
|
+
opt = opt || {};
|
|
1620
|
+
if (!("autoAlign" in opt)) {
|
|
1621
|
+
opt.autoAlign = false;
|
|
1622
|
+
}
|
|
1623
|
+
return new ListIt2(opt);
|
|
1624
|
+
};
|
|
1625
|
+
module2.exports = ListIt2;
|
|
1626
|
+
}
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
// src/scripts/aiPocketSearch.ts
|
|
1630
|
+
var aiPocketSearch_exports = {};
|
|
1631
|
+
__export(aiPocketSearch_exports, {
|
|
1632
|
+
main: () => main
|
|
1633
|
+
});
|
|
1634
|
+
module.exports = __toCommonJS(aiPocketSearch_exports);
|
|
1635
|
+
var import_args = __toESM(require("args"));
|
|
1636
|
+
var import_chalk = __toESM(require("chalk"));
|
|
1637
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
1638
|
+
var import_path = __toESM(require("path"));
|
|
1639
|
+
var import_progress = __toESM(require("progress"));
|
|
1640
|
+
var import_ai = require("@tradejs/infra/ai");
|
|
1641
|
+
var import_ai2 = require("@tradejs/node/ai");
|
|
1642
|
+
|
|
1643
|
+
// src/lib/aiTrainDataset.ts
|
|
1644
|
+
var extractSignalFromAiDatasetRow = (row) => {
|
|
1645
|
+
const { payload } = row;
|
|
1646
|
+
return {
|
|
1647
|
+
...payload.signal,
|
|
1648
|
+
strategy: payload.signal.strategy,
|
|
1649
|
+
figures: payload.figures ?? {},
|
|
1650
|
+
indicators: payload.indicators ?? {},
|
|
1651
|
+
additionalIndicators: payload.additionalIndicators ?? {},
|
|
1652
|
+
prices: payload.signal.prices
|
|
1653
|
+
};
|
|
1654
|
+
};
|
|
1655
|
+
|
|
1656
|
+
// src/lib/aiTrainMetrics.ts
|
|
1657
|
+
var divideOrNull = (num, denom) => {
|
|
1658
|
+
if (denom <= 0) {
|
|
1659
|
+
return null;
|
|
1660
|
+
}
|
|
1661
|
+
return num / denom;
|
|
1662
|
+
};
|
|
1663
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
1664
|
+
var DAYS_PER_WEEK = 7;
|
|
1665
|
+
var DAYS_PER_MONTH = 30.4375;
|
|
1666
|
+
var getEvaluationPeriodDays = (evaluations) => {
|
|
1667
|
+
let minTimestamp = null;
|
|
1668
|
+
let maxTimestamp = null;
|
|
1669
|
+
for (const evaluation of evaluations) {
|
|
1670
|
+
const timestamp = typeof evaluation.timestamp === "number" && Number.isFinite(evaluation.timestamp) ? evaluation.timestamp : null;
|
|
1671
|
+
if (timestamp == null) {
|
|
1672
|
+
continue;
|
|
1673
|
+
}
|
|
1674
|
+
if (minTimestamp == null || timestamp < minTimestamp) {
|
|
1675
|
+
minTimestamp = timestamp;
|
|
1676
|
+
}
|
|
1677
|
+
if (maxTimestamp == null || timestamp > maxTimestamp) {
|
|
1678
|
+
maxTimestamp = timestamp;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
if (minTimestamp == null || maxTimestamp == null) {
|
|
1682
|
+
return null;
|
|
1683
|
+
}
|
|
1684
|
+
return Math.max((maxTimestamp - minTimestamp) / DAY_MS, 1);
|
|
1685
|
+
};
|
|
1686
|
+
var qualitySortKey = (quality) => quality == null ? Number.POSITIVE_INFINITY : quality;
|
|
1687
|
+
var emptyRiskSummary = () => ({
|
|
1688
|
+
trades: 0,
|
|
1689
|
+
totalProfit: 0,
|
|
1690
|
+
grossProfit: 0,
|
|
1691
|
+
grossLoss: 0,
|
|
1692
|
+
profitFactor: null,
|
|
1693
|
+
payoffRatio: null,
|
|
1694
|
+
avgWin: null,
|
|
1695
|
+
avgLoss: null,
|
|
1696
|
+
largestWin: null,
|
|
1697
|
+
largestLoss: null,
|
|
1698
|
+
winRate: null,
|
|
1699
|
+
maxDrawdown: 0,
|
|
1700
|
+
maxDrawdownPctOfGrossProfit: null,
|
|
1701
|
+
maxDrawdownPctOfTotalProfit: null,
|
|
1702
|
+
recoveryFactor: null,
|
|
1703
|
+
ulcerIndex: null,
|
|
1704
|
+
maxConsecutiveWins: 0,
|
|
1705
|
+
maxConsecutiveLosses: 0
|
|
1706
|
+
});
|
|
1707
|
+
var summarizeApprovedRisk = (evaluations) => {
|
|
1708
|
+
const approvedEvaluations = evaluations.filter((evaluation) => evaluation.aiApproved).sort((left, right) => {
|
|
1709
|
+
const leftTimestamp = typeof left.timestamp === "number" && Number.isFinite(left.timestamp) ? left.timestamp : Number.POSITIVE_INFINITY;
|
|
1710
|
+
const rightTimestamp = typeof right.timestamp === "number" && Number.isFinite(right.timestamp) ? right.timestamp : Number.POSITIVE_INFINITY;
|
|
1711
|
+
return leftTimestamp - rightTimestamp;
|
|
1712
|
+
});
|
|
1713
|
+
if (!approvedEvaluations.length) {
|
|
1714
|
+
return emptyRiskSummary();
|
|
1715
|
+
}
|
|
1716
|
+
let grossProfit = 0;
|
|
1717
|
+
let grossLoss = 0;
|
|
1718
|
+
let wins = 0;
|
|
1719
|
+
let losses = 0;
|
|
1720
|
+
let largestWin = null;
|
|
1721
|
+
let largestLoss = null;
|
|
1722
|
+
let equity = 0;
|
|
1723
|
+
let peakEquity = 0;
|
|
1724
|
+
let maxDrawdown = 0;
|
|
1725
|
+
let drawdownSquares = 0;
|
|
1726
|
+
let currentWinStreak = 0;
|
|
1727
|
+
let currentLossStreak = 0;
|
|
1728
|
+
let maxConsecutiveWins = 0;
|
|
1729
|
+
let maxConsecutiveLosses = 0;
|
|
1730
|
+
for (const evaluation of approvedEvaluations) {
|
|
1731
|
+
const profit = evaluation.profit;
|
|
1732
|
+
if (profit > 0) {
|
|
1733
|
+
grossProfit += profit;
|
|
1734
|
+
wins += 1;
|
|
1735
|
+
largestWin = largestWin == null ? profit : Math.max(largestWin, profit);
|
|
1736
|
+
currentWinStreak += 1;
|
|
1737
|
+
currentLossStreak = 0;
|
|
1738
|
+
} else if (profit < 0) {
|
|
1739
|
+
grossLoss += Math.abs(profit);
|
|
1740
|
+
losses += 1;
|
|
1741
|
+
largestLoss = largestLoss == null ? profit : Math.min(largestLoss, profit);
|
|
1742
|
+
currentLossStreak += 1;
|
|
1743
|
+
currentWinStreak = 0;
|
|
1744
|
+
} else {
|
|
1745
|
+
currentWinStreak = 0;
|
|
1746
|
+
currentLossStreak = 0;
|
|
1747
|
+
}
|
|
1748
|
+
maxConsecutiveWins = Math.max(maxConsecutiveWins, currentWinStreak);
|
|
1749
|
+
maxConsecutiveLosses = Math.max(maxConsecutiveLosses, currentLossStreak);
|
|
1750
|
+
equity += profit;
|
|
1751
|
+
peakEquity = Math.max(peakEquity, equity);
|
|
1752
|
+
const drawdown = Math.max(0, peakEquity - equity);
|
|
1753
|
+
maxDrawdown = Math.max(maxDrawdown, drawdown);
|
|
1754
|
+
drawdownSquares += drawdown * drawdown;
|
|
1755
|
+
}
|
|
1756
|
+
const totalProfit = grossProfit - grossLoss;
|
|
1757
|
+
const avgWin = divideOrNull(grossProfit, wins);
|
|
1758
|
+
const avgLoss = divideOrNull(grossLoss, losses);
|
|
1759
|
+
return {
|
|
1760
|
+
trades: approvedEvaluations.length,
|
|
1761
|
+
totalProfit,
|
|
1762
|
+
grossProfit,
|
|
1763
|
+
grossLoss,
|
|
1764
|
+
profitFactor: grossLoss > 0 ? grossProfit / grossLoss : null,
|
|
1765
|
+
payoffRatio: avgWin != null && avgLoss != null && avgLoss > 0 ? avgWin / avgLoss : null,
|
|
1766
|
+
avgWin,
|
|
1767
|
+
avgLoss,
|
|
1768
|
+
largestWin,
|
|
1769
|
+
largestLoss,
|
|
1770
|
+
winRate: divideOrNull(wins, approvedEvaluations.length),
|
|
1771
|
+
maxDrawdown,
|
|
1772
|
+
maxDrawdownPctOfGrossProfit: grossProfit > 0 ? maxDrawdown / grossProfit : null,
|
|
1773
|
+
maxDrawdownPctOfTotalProfit: totalProfit > 0 ? maxDrawdown / totalProfit : null,
|
|
1774
|
+
recoveryFactor: maxDrawdown > 0 ? totalProfit / maxDrawdown : null,
|
|
1775
|
+
ulcerIndex: Math.sqrt(drawdownSquares / approvedEvaluations.length),
|
|
1776
|
+
maxConsecutiveWins,
|
|
1777
|
+
maxConsecutiveLosses
|
|
1778
|
+
};
|
|
1779
|
+
};
|
|
1780
|
+
var summarizeAiTrainEvaluations = (evaluations) => {
|
|
1781
|
+
let approved = 0;
|
|
1782
|
+
let rejected = 0;
|
|
1783
|
+
let correct = 0;
|
|
1784
|
+
let incorrect = 0;
|
|
1785
|
+
let profitable = 0;
|
|
1786
|
+
let unprofitable = 0;
|
|
1787
|
+
let flat = 0;
|
|
1788
|
+
let truePositive = 0;
|
|
1789
|
+
let falsePositive = 0;
|
|
1790
|
+
let trueNegative = 0;
|
|
1791
|
+
let falseNegative = 0;
|
|
1792
|
+
let totalProfitAll = 0;
|
|
1793
|
+
let totalProfitApproved = 0;
|
|
1794
|
+
const bucketMap = /* @__PURE__ */ new Map();
|
|
1795
|
+
for (const evaluation of evaluations) {
|
|
1796
|
+
const { profit, profitableTrade, aiApproved, quality } = evaluation;
|
|
1797
|
+
totalProfitAll += profit;
|
|
1798
|
+
if (profitableTrade) {
|
|
1799
|
+
profitable += 1;
|
|
1800
|
+
} else if (profit < 0) {
|
|
1801
|
+
unprofitable += 1;
|
|
1802
|
+
} else {
|
|
1803
|
+
flat += 1;
|
|
1804
|
+
}
|
|
1805
|
+
if (aiApproved) {
|
|
1806
|
+
approved += 1;
|
|
1807
|
+
totalProfitApproved += profit;
|
|
1808
|
+
} else {
|
|
1809
|
+
rejected += 1;
|
|
1810
|
+
}
|
|
1811
|
+
const isCorrect = aiApproved === profitableTrade;
|
|
1812
|
+
if (isCorrect) {
|
|
1813
|
+
correct += 1;
|
|
1814
|
+
} else {
|
|
1815
|
+
incorrect += 1;
|
|
1816
|
+
}
|
|
1817
|
+
if (aiApproved && profitableTrade) {
|
|
1818
|
+
truePositive += 1;
|
|
1819
|
+
} else if (aiApproved && !profitableTrade) {
|
|
1820
|
+
falsePositive += 1;
|
|
1821
|
+
} else if (!aiApproved && profitableTrade) {
|
|
1822
|
+
falseNegative += 1;
|
|
1823
|
+
} else {
|
|
1824
|
+
trueNegative += 1;
|
|
1825
|
+
}
|
|
1826
|
+
const bucket = bucketMap.get(quality) ?? {
|
|
1827
|
+
quality,
|
|
1828
|
+
count: 0,
|
|
1829
|
+
approved: 0,
|
|
1830
|
+
profitable: 0,
|
|
1831
|
+
totalProfit: 0
|
|
1832
|
+
};
|
|
1833
|
+
bucket.count += 1;
|
|
1834
|
+
bucket.totalProfit += profit;
|
|
1835
|
+
if (aiApproved) {
|
|
1836
|
+
bucket.approved += 1;
|
|
1837
|
+
}
|
|
1838
|
+
if (profitableTrade) {
|
|
1839
|
+
bucket.profitable += 1;
|
|
1840
|
+
}
|
|
1841
|
+
bucketMap.set(quality, bucket);
|
|
1842
|
+
}
|
|
1843
|
+
const avgProfitAll = divideOrNull(totalProfitAll, evaluations.length);
|
|
1844
|
+
const avgProfitApproved = divideOrNull(totalProfitApproved, approved);
|
|
1845
|
+
const periodDays = getEvaluationPeriodDays(evaluations);
|
|
1846
|
+
const avgProfitApprovedPerDay = periodDays == null ? null : divideOrNull(totalProfitApproved, periodDays);
|
|
1847
|
+
const avgApprovedTradesPerDay = periodDays == null ? null : divideOrNull(approved, periodDays);
|
|
1848
|
+
const avgProfitApprovedPerMonth = avgProfitApprovedPerDay == null ? null : avgProfitApprovedPerDay * DAYS_PER_MONTH;
|
|
1849
|
+
const avgApprovedTradesPerWeek = avgApprovedTradesPerDay == null ? null : avgApprovedTradesPerDay * DAYS_PER_WEEK;
|
|
1850
|
+
const expectancyDelta = avgProfitAll == null || avgProfitApproved == null ? null : avgProfitApproved - avgProfitAll;
|
|
1851
|
+
return {
|
|
1852
|
+
approved,
|
|
1853
|
+
rejected,
|
|
1854
|
+
correct,
|
|
1855
|
+
incorrect,
|
|
1856
|
+
truePositive,
|
|
1857
|
+
falsePositive,
|
|
1858
|
+
trueNegative,
|
|
1859
|
+
falseNegative,
|
|
1860
|
+
profitable,
|
|
1861
|
+
unprofitable,
|
|
1862
|
+
flat,
|
|
1863
|
+
precisionApproved: divideOrNull(truePositive, approved),
|
|
1864
|
+
recallWinners: divideOrNull(truePositive, profitable),
|
|
1865
|
+
avgProfitAll,
|
|
1866
|
+
avgProfitApproved,
|
|
1867
|
+
avgProfitApprovedPerDay,
|
|
1868
|
+
avgProfitApprovedPerMonth,
|
|
1869
|
+
avgApprovedTradesPerDay,
|
|
1870
|
+
avgApprovedTradesPerWeek,
|
|
1871
|
+
expectancyDelta,
|
|
1872
|
+
approvedRisk: summarizeApprovedRisk(evaluations),
|
|
1873
|
+
qualityBuckets: [...bucketMap.values()].sort(
|
|
1874
|
+
(a, b) => qualitySortKey(a.quality) - qualitySortKey(b.quality)
|
|
1875
|
+
)
|
|
1876
|
+
};
|
|
1877
|
+
};
|
|
1878
|
+
var isDirectionMatchAtThreshold = (evaluation, threshold) => {
|
|
1879
|
+
const directionMatches = typeof evaluation.modelDirectionMatches === "boolean" ? evaluation.modelDirectionMatches : evaluation.aiApproved;
|
|
1880
|
+
return directionMatches === true && evaluation.quality != null && evaluation.quality >= threshold;
|
|
1881
|
+
};
|
|
1882
|
+
var summarizeAiTrainEvaluationsByQualityThreshold = (evaluations, thresholds = [3, 4, 5]) => thresholds.map((threshold) => ({
|
|
1883
|
+
threshold,
|
|
1884
|
+
label: `q${threshold}+`,
|
|
1885
|
+
summary: summarizeAiTrainEvaluations(
|
|
1886
|
+
evaluations.map((evaluation) => ({
|
|
1887
|
+
...evaluation,
|
|
1888
|
+
aiApproved: isDirectionMatchAtThreshold(evaluation, threshold)
|
|
1889
|
+
}))
|
|
1890
|
+
)
|
|
1891
|
+
}));
|
|
1892
|
+
|
|
1893
|
+
// src/lib/aiTrainOptions.ts
|
|
1894
|
+
var parseTimestampFilter = (value) => {
|
|
1895
|
+
if (value == null || String(value).trim() === "") {
|
|
1896
|
+
return null;
|
|
1897
|
+
}
|
|
1898
|
+
const text = String(value).trim();
|
|
1899
|
+
const numeric = Number(text);
|
|
1900
|
+
if (Number.isFinite(numeric)) {
|
|
1901
|
+
return numeric;
|
|
1902
|
+
}
|
|
1903
|
+
const parsed = Date.parse(text);
|
|
1904
|
+
if (Number.isFinite(parsed)) {
|
|
1905
|
+
return parsed;
|
|
1906
|
+
}
|
|
1907
|
+
throw new Error(
|
|
1908
|
+
`Invalid timestamp filter "${text}". Use an ISO date or epoch milliseconds.`
|
|
1909
|
+
);
|
|
1910
|
+
};
|
|
1911
|
+
var parseTrailingPeriodMs = (value) => {
|
|
1912
|
+
if (value == null || String(value).trim() === "") {
|
|
1913
|
+
return null;
|
|
1914
|
+
}
|
|
1915
|
+
const text = String(value).trim().toLowerCase();
|
|
1916
|
+
const match = text.match(
|
|
1917
|
+
/^(?:last)?(\d+)(d|day|days|w|week|weeks|m|month|months|y|year|years)$/
|
|
1918
|
+
);
|
|
1919
|
+
if (!match) {
|
|
1920
|
+
throw new Error(
|
|
1921
|
+
`Invalid --period value "${String(value)}". Use values like last365d, 90d, 12w, or 1y.`
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
const amount = Number(match[1]);
|
|
1925
|
+
const unit = match[2];
|
|
1926
|
+
const dayMs = 24 * 60 * 60 * 1e3;
|
|
1927
|
+
if (unit.startsWith("w")) {
|
|
1928
|
+
return amount * 7 * dayMs;
|
|
1929
|
+
}
|
|
1930
|
+
if (unit.startsWith("m")) {
|
|
1931
|
+
return amount * 30.4375 * dayMs;
|
|
1932
|
+
}
|
|
1933
|
+
if (unit.startsWith("y")) {
|
|
1934
|
+
return amount * 365 * dayMs;
|
|
1935
|
+
}
|
|
1936
|
+
return amount * dayMs;
|
|
1937
|
+
};
|
|
1938
|
+
var parseQualityThresholds = (value) => {
|
|
1939
|
+
const raw = String(value ?? "3,4,5").split(",").map((part) => Number(part.trim())).filter((part) => Number.isFinite(part)).map((part) => Math.trunc(part)).filter((part) => part > 0);
|
|
1940
|
+
return [...new Set(raw)].sort((left, right) => left - right);
|
|
1941
|
+
};
|
|
1942
|
+
var hasCliOption = ({
|
|
1943
|
+
argv,
|
|
1944
|
+
longName,
|
|
1945
|
+
shortName
|
|
1946
|
+
}) => argv.some(
|
|
1947
|
+
(arg) => arg === `--${longName}` || arg.startsWith(`--${longName}=`) || arg === `-${shortName}` || arg.startsWith(`-${shortName}=`)
|
|
1948
|
+
);
|
|
1949
|
+
var resolveAiTrainRecentLimit = ({
|
|
1950
|
+
argv,
|
|
1951
|
+
recentValue,
|
|
1952
|
+
hasDateFilter,
|
|
1953
|
+
defaultRecent = 50
|
|
1954
|
+
}) => {
|
|
1955
|
+
const hasExplicitRecent = hasCliOption({
|
|
1956
|
+
argv,
|
|
1957
|
+
longName: "recent",
|
|
1958
|
+
shortName: "n"
|
|
1959
|
+
});
|
|
1960
|
+
const selectedRecent = hasDateFilter && !hasExplicitRecent ? 0 : recentValue;
|
|
1961
|
+
const parsed = Number(selectedRecent);
|
|
1962
|
+
return Number.isFinite(parsed) ? Math.max(0, Math.trunc(parsed)) : defaultRecent;
|
|
1963
|
+
};
|
|
1964
|
+
|
|
1965
|
+
// src/lib/aiPocketSearch.ts
|
|
1966
|
+
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
1967
|
+
var DAYS_PER_WEEK2 = 7;
|
|
1968
|
+
var DAYS_PER_MONTH2 = 30.4375;
|
|
1969
|
+
var OUTCOME_SEGMENTS = /* @__PURE__ */ new Set([
|
|
1970
|
+
"actual",
|
|
1971
|
+
"aiapproved",
|
|
1972
|
+
"approvalallowednow",
|
|
1973
|
+
"backtestexecution",
|
|
1974
|
+
"closedat",
|
|
1975
|
+
"closedpnl",
|
|
1976
|
+
"deterministicquality",
|
|
1977
|
+
"entrydelaybars",
|
|
1978
|
+
"entrydelaymovebps",
|
|
1979
|
+
"executionprice",
|
|
1980
|
+
"exitprice",
|
|
1981
|
+
"exitreason",
|
|
1982
|
+
"exittimestamp",
|
|
1983
|
+
"fillprice",
|
|
1984
|
+
"future",
|
|
1985
|
+
"futuremove",
|
|
1986
|
+
"futureprofit",
|
|
1987
|
+
"hardblockreasons",
|
|
1988
|
+
"label",
|
|
1989
|
+
"maxallowedquality",
|
|
1990
|
+
"maxquality",
|
|
1991
|
+
"modeldirection",
|
|
1992
|
+
"modeldirectionmatches",
|
|
1993
|
+
"outcome",
|
|
1994
|
+
"pnl",
|
|
1995
|
+
"profit",
|
|
1996
|
+
"profitabletrade",
|
|
1997
|
+
"q4continuationrecoveryallowed",
|
|
1998
|
+
"q4continuationrecoverycandidate",
|
|
1999
|
+
"q4trendshiftgatefeaturesrecoverycandidate",
|
|
2000
|
+
"q4usclosingoiconfirmationrecoverycandidate",
|
|
2001
|
+
"quality",
|
|
2002
|
+
"rawaiapproved",
|
|
2003
|
+
"recoveryallowed",
|
|
2004
|
+
"recoverycandidate",
|
|
2005
|
+
"realized",
|
|
2006
|
+
"realizedpnl",
|
|
2007
|
+
"rejectreason",
|
|
2008
|
+
"result",
|
|
2009
|
+
"structuralhardblockreasons",
|
|
2010
|
+
"target",
|
|
2011
|
+
"traderesult"
|
|
2012
|
+
]);
|
|
2013
|
+
var isPlainRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
2014
|
+
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2015
|
+
var isFeaturePrimitive = (value) => value == null || typeof value === "string" || typeof value === "boolean" || isFiniteNumber(value);
|
|
2016
|
+
var normalizeFeaturePrimitive = (value) => {
|
|
2017
|
+
if (typeof value === "string") {
|
|
2018
|
+
const trimmed = value.trim();
|
|
2019
|
+
return trimmed ? trimmed.slice(0, 120) : void 0;
|
|
2020
|
+
}
|
|
2021
|
+
if (value == null) {
|
|
2022
|
+
return null;
|
|
2023
|
+
}
|
|
2024
|
+
return value;
|
|
2025
|
+
};
|
|
2026
|
+
var isOutcomePath = (segments) => segments.some((segment) => OUTCOME_SEGMENTS.has(segment.toLowerCase()));
|
|
2027
|
+
var isFeaturePathPrefix = (segments, prefix) => prefix.every((segment, index) => segments[index] === segment);
|
|
2028
|
+
var isCompactFeaturePathSkipped = (segments) => {
|
|
2029
|
+
if (!segments.length) {
|
|
2030
|
+
return false;
|
|
2031
|
+
}
|
|
2032
|
+
const skippedPrefixes = [
|
|
2033
|
+
["indicators"],
|
|
2034
|
+
["additionalIndicators", "marketContext"],
|
|
2035
|
+
["additionalIndicators", "baseContext", "candle"],
|
|
2036
|
+
["additionalIndicators", "baseContext", "prevCandle"],
|
|
2037
|
+
["additionalIndicators", "baseContext", "regime", "memory"],
|
|
2038
|
+
["additionalIndicators", "baseContext", "structure", "acceptance"],
|
|
2039
|
+
["additionalIndicators", "baseContext", "structure", "liquidity"],
|
|
2040
|
+
["additionalIndicators", "baseContext", "structure", "liquidityTails"],
|
|
2041
|
+
["additionalIndicators", "baseContext", "structure", "liquidityZones"],
|
|
2042
|
+
["additionalIndicators", "baseContext", "structure", "pivots"],
|
|
2043
|
+
["additionalIndicators", "baseContext", "structure", "srZones"],
|
|
2044
|
+
["additionalIndicators", "baseContext", "structure", "structureZones"],
|
|
2045
|
+
["additionalIndicators", "baseContext", "structure", "swing"],
|
|
2046
|
+
["additionalIndicators", "baseContext", "structure", "zones"],
|
|
2047
|
+
["additionalIndicators", "baseContext", "derivatives", "referenceContexts"],
|
|
2048
|
+
["additionalIndicators", "baseContext", "derivatives", "referenceSymbols"],
|
|
2049
|
+
["additionalIndicators", "baseContext", "relative", "cmcReferenceAssets"],
|
|
2050
|
+
["additionalIndicators", "baseContext", "relative", "cmcExchangeLiquidity"],
|
|
2051
|
+
["additionalIndicators", "baseContext", "relative", "referenceTradeFlow"]
|
|
2052
|
+
];
|
|
2053
|
+
if (skippedPrefixes.some((prefix) => isFeaturePathPrefix(segments, prefix))) {
|
|
2054
|
+
return true;
|
|
2055
|
+
}
|
|
2056
|
+
const leaf = segments.at(-1)?.toLowerCase() ?? "";
|
|
2057
|
+
if (leaf === "asofts" || leaf === "timestamp" || leaf.endsWith("timestamp")) {
|
|
2058
|
+
return true;
|
|
2059
|
+
}
|
|
2060
|
+
if (isFeaturePathPrefix(segments, [
|
|
2061
|
+
"additionalIndicators",
|
|
2062
|
+
"baseContext",
|
|
2063
|
+
"derivatives"
|
|
2064
|
+
]) && [
|
|
2065
|
+
"source",
|
|
2066
|
+
"symbol",
|
|
2067
|
+
"timestamp",
|
|
2068
|
+
"targetSymbol",
|
|
2069
|
+
"primaryReferenceSymbol",
|
|
2070
|
+
"secondaryReferenceSymbol"
|
|
2071
|
+
].includes(segments[3] ?? "")) {
|
|
2072
|
+
return true;
|
|
2073
|
+
}
|
|
2074
|
+
return false;
|
|
2075
|
+
};
|
|
2076
|
+
var addFlattenedFeatures = ({
|
|
2077
|
+
output,
|
|
2078
|
+
value,
|
|
2079
|
+
segments,
|
|
2080
|
+
maxDepth,
|
|
2081
|
+
shouldSkipPath = () => false
|
|
2082
|
+
}) => {
|
|
2083
|
+
if (!segments.length && !isPlainRecord(value)) {
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
if (segments.length > maxDepth || isOutcomePath(segments) || shouldSkipPath(segments)) {
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
if (Array.isArray(value)) {
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
if (isFeaturePrimitive(value)) {
|
|
2093
|
+
const normalized = normalizeFeaturePrimitive(value);
|
|
2094
|
+
if (normalized !== void 0 && segments.length) {
|
|
2095
|
+
output[segments.join(".")] = normalized;
|
|
2096
|
+
}
|
|
2097
|
+
return;
|
|
2098
|
+
}
|
|
2099
|
+
if (!isPlainRecord(value)) {
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2102
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2103
|
+
if (!key || key.startsWith("_")) {
|
|
2104
|
+
continue;
|
|
2105
|
+
}
|
|
2106
|
+
addFlattenedFeatures({
|
|
2107
|
+
output,
|
|
2108
|
+
value: child,
|
|
2109
|
+
segments: [...segments, key],
|
|
2110
|
+
maxDepth,
|
|
2111
|
+
shouldSkipPath
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
var findFeatureNumber = (features, aliases, requiredPathFragments = []) => {
|
|
2116
|
+
const normalizedAliases = new Set(
|
|
2117
|
+
aliases.map((alias) => alias.toLowerCase())
|
|
2118
|
+
);
|
|
2119
|
+
const normalizedFragments = requiredPathFragments.map(
|
|
2120
|
+
(fragment) => fragment.toLowerCase()
|
|
2121
|
+
);
|
|
2122
|
+
for (const [key, value] of Object.entries(features)) {
|
|
2123
|
+
if (!isFiniteNumber(value)) {
|
|
2124
|
+
continue;
|
|
2125
|
+
}
|
|
2126
|
+
const keyLower = key.toLowerCase();
|
|
2127
|
+
if (normalizedFragments.some((fragment) => !keyLower.includes(fragment))) {
|
|
2128
|
+
continue;
|
|
2129
|
+
}
|
|
2130
|
+
const lastSegment = keyLower.split(".").at(-1) ?? keyLower;
|
|
2131
|
+
if (normalizedAliases.has(lastSegment)) {
|
|
2132
|
+
return value;
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
return null;
|
|
2136
|
+
};
|
|
2137
|
+
var findFeatureString = (features, aliases) => {
|
|
2138
|
+
const normalizedAliases = new Set(
|
|
2139
|
+
aliases.map((alias) => alias.toLowerCase())
|
|
2140
|
+
);
|
|
2141
|
+
for (const [key, value] of Object.entries(features)) {
|
|
2142
|
+
if (typeof value !== "string") {
|
|
2143
|
+
continue;
|
|
2144
|
+
}
|
|
2145
|
+
const lastSegment = key.toLowerCase().split(".").at(-1) ?? key;
|
|
2146
|
+
if (normalizedAliases.has(lastSegment)) {
|
|
2147
|
+
return value;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
return null;
|
|
2151
|
+
};
|
|
2152
|
+
var addDirectionalDerivedFeatures = (features) => {
|
|
2153
|
+
const direction = String(features["signal.direction"] ?? "").toUpperCase();
|
|
2154
|
+
const directionSign = direction === "LONG" ? 1 : direction === "SHORT" ? -1 : null;
|
|
2155
|
+
if (directionSign == null) {
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
const currentPrice = findFeatureNumber(features, [
|
|
2159
|
+
"current",
|
|
2160
|
+
"currentprice",
|
|
2161
|
+
"close",
|
|
2162
|
+
"last",
|
|
2163
|
+
"lastprice",
|
|
2164
|
+
"price"
|
|
2165
|
+
]);
|
|
2166
|
+
const maFast = findFeatureNumber(features, [
|
|
2167
|
+
"fastma",
|
|
2168
|
+
"mafast",
|
|
2169
|
+
"ma_fast",
|
|
2170
|
+
"emafast",
|
|
2171
|
+
"emafastvalue",
|
|
2172
|
+
"smafast"
|
|
2173
|
+
]);
|
|
2174
|
+
const maSlow = findFeatureNumber(features, [
|
|
2175
|
+
"slowma",
|
|
2176
|
+
"maslow",
|
|
2177
|
+
"ma_slow",
|
|
2178
|
+
"emaslow",
|
|
2179
|
+
"emaslowvalue",
|
|
2180
|
+
"smaslow"
|
|
2181
|
+
]);
|
|
2182
|
+
const macdHistogram = findFeatureNumber(
|
|
2183
|
+
features,
|
|
2184
|
+
["histogram", "hist", "macdhistogram", "macdhist"],
|
|
2185
|
+
["macd"]
|
|
2186
|
+
);
|
|
2187
|
+
const macdHistogramSlope = findFeatureNumber(
|
|
2188
|
+
features,
|
|
2189
|
+
["histogramslope", "histogramdelta", "slope", "delta"],
|
|
2190
|
+
["macd"]
|
|
2191
|
+
);
|
|
2192
|
+
const obvSlope = findFeatureNumber(
|
|
2193
|
+
features,
|
|
2194
|
+
["slope", "delta", "change", "obvslope", "obvdelta"],
|
|
2195
|
+
["obv"]
|
|
2196
|
+
);
|
|
2197
|
+
const obvTrend = findFeatureString(features, [
|
|
2198
|
+
"obvtrend",
|
|
2199
|
+
"trend",
|
|
2200
|
+
"obvdirection"
|
|
2201
|
+
]);
|
|
2202
|
+
let supportCount = 0;
|
|
2203
|
+
if (currentPrice != null && maFast != null && currentPrice !== 0) {
|
|
2204
|
+
const signedDistanceBps = (currentPrice - maFast) / Math.abs(currentPrice) * 1e4 * directionSign;
|
|
2205
|
+
const aligned = signedDistanceBps >= 0;
|
|
2206
|
+
features["derived.maFastAligned"] = aligned;
|
|
2207
|
+
features["derived.priceMaFastDistanceBps"] = signedDistanceBps;
|
|
2208
|
+
if (aligned) {
|
|
2209
|
+
supportCount += 1;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
if (currentPrice != null && maSlow != null && currentPrice !== 0) {
|
|
2213
|
+
const signedDistanceBps = (currentPrice - maSlow) / Math.abs(currentPrice) * 1e4 * directionSign;
|
|
2214
|
+
const aligned = signedDistanceBps >= 0;
|
|
2215
|
+
features["derived.maSlowAligned"] = aligned;
|
|
2216
|
+
features["derived.priceMaSlowDistanceBps"] = signedDistanceBps;
|
|
2217
|
+
if (aligned) {
|
|
2218
|
+
supportCount += 1;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
if (maFast != null && maSlow != null) {
|
|
2222
|
+
const signedDistance = (maFast - maSlow) * directionSign;
|
|
2223
|
+
const aligned = signedDistance >= 0;
|
|
2224
|
+
features["derived.maStackAligned"] = aligned;
|
|
2225
|
+
features["derived.maFastSlowDistanceSigned"] = signedDistance;
|
|
2226
|
+
if (aligned) {
|
|
2227
|
+
supportCount += 1;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
if (macdHistogram != null) {
|
|
2231
|
+
const signedHistogram = macdHistogram * directionSign;
|
|
2232
|
+
const aligned = signedHistogram >= 0;
|
|
2233
|
+
features["derived.macdHistogramAligned"] = aligned;
|
|
2234
|
+
features["derived.macdHistogramSigned"] = signedHistogram;
|
|
2235
|
+
if (aligned) {
|
|
2236
|
+
supportCount += 1;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
if (macdHistogramSlope != null) {
|
|
2240
|
+
const signedSlope = macdHistogramSlope * directionSign;
|
|
2241
|
+
const aligned = signedSlope >= 0;
|
|
2242
|
+
features["derived.macdHistogramSlopeAligned"] = aligned;
|
|
2243
|
+
features["derived.macdHistogramSlopeSigned"] = signedSlope;
|
|
2244
|
+
if (aligned) {
|
|
2245
|
+
supportCount += 1;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (obvSlope != null) {
|
|
2249
|
+
const signedSlope = obvSlope * directionSign;
|
|
2250
|
+
const aligned = signedSlope >= 0;
|
|
2251
|
+
features["derived.obvSlopeAligned"] = aligned;
|
|
2252
|
+
features["derived.obvSlopeSigned"] = signedSlope;
|
|
2253
|
+
if (aligned) {
|
|
2254
|
+
supportCount += 1;
|
|
2255
|
+
}
|
|
2256
|
+
} else if (obvTrend) {
|
|
2257
|
+
const normalizedTrend = obvTrend.toLowerCase();
|
|
2258
|
+
const aligned = direction === "LONG" && ["up", "rising", "bullish", "positive"].includes(normalizedTrend) || direction === "SHORT" && ["down", "falling", "bearish", "negative"].includes(normalizedTrend);
|
|
2259
|
+
features["derived.obvTrendAligned"] = aligned;
|
|
2260
|
+
if (aligned) {
|
|
2261
|
+
supportCount += 1;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
features["derived.directIndicatorSupportCount"] = supportCount;
|
|
2265
|
+
};
|
|
2266
|
+
var collectAiPocketFeatures = ({
|
|
2267
|
+
payload,
|
|
2268
|
+
gateContext,
|
|
2269
|
+
includeSymbol = false,
|
|
2270
|
+
includeGateContext = false,
|
|
2271
|
+
featureProfile = "all"
|
|
2272
|
+
}) => {
|
|
2273
|
+
const features = {};
|
|
2274
|
+
const signal = payload.signal ?? {};
|
|
2275
|
+
const source = {
|
|
2276
|
+
signal: {
|
|
2277
|
+
direction: signal.direction,
|
|
2278
|
+
interval: signal.interval,
|
|
2279
|
+
strategy: signal.strategy,
|
|
2280
|
+
...includeSymbol ? { symbol: signal.symbol } : {}
|
|
2281
|
+
},
|
|
2282
|
+
indicators: payload.indicators,
|
|
2283
|
+
additionalIndicators: payload.additionalIndicators,
|
|
2284
|
+
...includeGateContext ? { gate: gateContext } : {}
|
|
2285
|
+
};
|
|
2286
|
+
addFlattenedFeatures({
|
|
2287
|
+
output: features,
|
|
2288
|
+
value: source,
|
|
2289
|
+
segments: [],
|
|
2290
|
+
maxDepth: 8,
|
|
2291
|
+
shouldSkipPath: featureProfile === "compact" ? isCompactFeaturePathSkipped : void 0
|
|
2292
|
+
});
|
|
2293
|
+
addDirectionalDerivedFeatures(features);
|
|
2294
|
+
return features;
|
|
2295
|
+
};
|
|
2296
|
+
var formatNumber = (value) => {
|
|
2297
|
+
if (Number.isInteger(value)) {
|
|
2298
|
+
return String(value);
|
|
2299
|
+
}
|
|
2300
|
+
const abs = Math.abs(value);
|
|
2301
|
+
if (abs > 0 && abs < 1e-3) {
|
|
2302
|
+
return value.toExponential(3);
|
|
2303
|
+
}
|
|
2304
|
+
return Number(value.toPrecision(6)).toString();
|
|
2305
|
+
};
|
|
2306
|
+
var formatPredicateValue = (value) => {
|
|
2307
|
+
if (typeof value === "number") {
|
|
2308
|
+
return formatNumber(value);
|
|
2309
|
+
}
|
|
2310
|
+
if (typeof value === "string") {
|
|
2311
|
+
return JSON.stringify(value);
|
|
2312
|
+
}
|
|
2313
|
+
return String(value);
|
|
2314
|
+
};
|
|
2315
|
+
var roundThreshold = (value) => Number(value.toPrecision(8));
|
|
2316
|
+
var quantileAt = (values, quantile) => {
|
|
2317
|
+
const index = Math.floor((values.length - 1) * quantile);
|
|
2318
|
+
return values[Math.max(0, Math.min(values.length - 1, index))];
|
|
2319
|
+
};
|
|
2320
|
+
var getPeriodDays = (rows) => {
|
|
2321
|
+
let minTimestamp = null;
|
|
2322
|
+
let maxTimestamp = null;
|
|
2323
|
+
for (const row of rows) {
|
|
2324
|
+
const timestamp = typeof row.timestamp === "number" && Number.isFinite(row.timestamp) ? row.timestamp : null;
|
|
2325
|
+
if (timestamp == null) {
|
|
2326
|
+
continue;
|
|
2327
|
+
}
|
|
2328
|
+
minTimestamp = minTimestamp == null ? timestamp : Math.min(minTimestamp, timestamp);
|
|
2329
|
+
maxTimestamp = maxTimestamp == null ? timestamp : Math.max(maxTimestamp, timestamp);
|
|
2330
|
+
}
|
|
2331
|
+
if (minTimestamp == null || maxTimestamp == null) {
|
|
2332
|
+
return null;
|
|
2333
|
+
}
|
|
2334
|
+
return Math.max((maxTimestamp - minTimestamp) / DAY_MS2, 1);
|
|
2335
|
+
};
|
|
2336
|
+
var createSummaryAccumulator = () => ({
|
|
2337
|
+
support: 0,
|
|
2338
|
+
grossProfit: 0,
|
|
2339
|
+
grossLoss: 0,
|
|
2340
|
+
wins: 0,
|
|
2341
|
+
directionCounts: /* @__PURE__ */ new Map(),
|
|
2342
|
+
symbolCounts: /* @__PURE__ */ new Map(),
|
|
2343
|
+
monthProfits: /* @__PURE__ */ new Map(),
|
|
2344
|
+
equityPoints: []
|
|
2345
|
+
});
|
|
2346
|
+
var addSummaryRow = (accumulator, row) => {
|
|
2347
|
+
const profit = Number(row.profit);
|
|
2348
|
+
accumulator.support += 1;
|
|
2349
|
+
if (profit > 0) {
|
|
2350
|
+
accumulator.grossProfit += profit;
|
|
2351
|
+
accumulator.wins += 1;
|
|
2352
|
+
} else if (profit < 0) {
|
|
2353
|
+
accumulator.grossLoss += Math.abs(profit);
|
|
2354
|
+
}
|
|
2355
|
+
const direction = typeof row.direction === "string" && row.direction.trim() ? row.direction : "UNKNOWN";
|
|
2356
|
+
accumulator.directionCounts.set(
|
|
2357
|
+
direction,
|
|
2358
|
+
(accumulator.directionCounts.get(direction) ?? 0) + 1
|
|
2359
|
+
);
|
|
2360
|
+
const symbol = typeof row.symbol === "string" && row.symbol.trim() ? row.symbol : "UNKNOWN";
|
|
2361
|
+
const symbolBucket = accumulator.symbolCounts.get(symbol) ?? {
|
|
2362
|
+
count: 0,
|
|
2363
|
+
totalProfit: 0
|
|
2364
|
+
};
|
|
2365
|
+
symbolBucket.count += 1;
|
|
2366
|
+
symbolBucket.totalProfit += profit;
|
|
2367
|
+
accumulator.symbolCounts.set(symbol, symbolBucket);
|
|
2368
|
+
const timestamp = typeof row.timestamp === "number" && Number.isFinite(row.timestamp) ? row.timestamp : Number.POSITIVE_INFINITY;
|
|
2369
|
+
const month = Number.isFinite(timestamp) && timestamp !== Number.POSITIVE_INFINITY ? new Date(timestamp).toISOString().slice(0, 7) : "UNKNOWN";
|
|
2370
|
+
accumulator.monthProfits.set(
|
|
2371
|
+
month,
|
|
2372
|
+
(accumulator.monthProfits.get(month) ?? 0) + profit
|
|
2373
|
+
);
|
|
2374
|
+
accumulator.equityPoints.push({ timestamp, profit });
|
|
2375
|
+
};
|
|
2376
|
+
var emptyAiPocketSummary = ({
|
|
2377
|
+
fullPeriodDays,
|
|
2378
|
+
supportRatio
|
|
2379
|
+
}) => ({
|
|
2380
|
+
support: 0,
|
|
2381
|
+
supportRatio,
|
|
2382
|
+
totalProfit: 0,
|
|
2383
|
+
grossProfit: 0,
|
|
2384
|
+
grossLoss: 0,
|
|
2385
|
+
profitFactor: null,
|
|
2386
|
+
winRate: null,
|
|
2387
|
+
avgProfit: null,
|
|
2388
|
+
maxDrawdown: 0,
|
|
2389
|
+
maxDrawdownPctOfGrossProfit: null,
|
|
2390
|
+
maxDrawdownPctOfTotalProfit: null,
|
|
2391
|
+
recoveryFactor: null,
|
|
2392
|
+
maxConsecutiveWins: 0,
|
|
2393
|
+
maxConsecutiveLosses: 0,
|
|
2394
|
+
avgTradesPerDay: fullPeriodDays == null ? null : 0,
|
|
2395
|
+
avgTradesPerWeek: fullPeriodDays == null ? null : 0,
|
|
2396
|
+
avgProfitPerDay: fullPeriodDays == null ? null : 0,
|
|
2397
|
+
avgProfitPerMonth: fullPeriodDays == null ? null : 0,
|
|
2398
|
+
losingMonths: 0,
|
|
2399
|
+
worstMonth: null,
|
|
2400
|
+
directionCounts: {},
|
|
2401
|
+
topSymbols: []
|
|
2402
|
+
});
|
|
2403
|
+
var finalizeAiPocketSummary = ({
|
|
2404
|
+
rows,
|
|
2405
|
+
accumulator
|
|
2406
|
+
}) => {
|
|
2407
|
+
const fullPeriodDays = getPeriodDays(rows);
|
|
2408
|
+
const support = accumulator.support;
|
|
2409
|
+
const supportRatio = rows.length > 0 ? support / rows.length : 0;
|
|
2410
|
+
if (support === 0) {
|
|
2411
|
+
return {
|
|
2412
|
+
...emptyAiPocketSummary({ fullPeriodDays, supportRatio })
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
let equity = 0;
|
|
2416
|
+
let peakEquity = 0;
|
|
2417
|
+
let maxDrawdown = 0;
|
|
2418
|
+
let currentWinStreak = 0;
|
|
2419
|
+
let currentLossStreak = 0;
|
|
2420
|
+
let maxConsecutiveWins = 0;
|
|
2421
|
+
let maxConsecutiveLosses = 0;
|
|
2422
|
+
accumulator.equityPoints.sort(
|
|
2423
|
+
(left, right) => left.timestamp - right.timestamp
|
|
2424
|
+
);
|
|
2425
|
+
for (const point of accumulator.equityPoints) {
|
|
2426
|
+
equity += point.profit;
|
|
2427
|
+
peakEquity = Math.max(peakEquity, equity);
|
|
2428
|
+
maxDrawdown = Math.max(maxDrawdown, Math.max(0, peakEquity - equity));
|
|
2429
|
+
if (point.profit > 0) {
|
|
2430
|
+
currentWinStreak += 1;
|
|
2431
|
+
currentLossStreak = 0;
|
|
2432
|
+
} else if (point.profit < 0) {
|
|
2433
|
+
currentLossStreak += 1;
|
|
2434
|
+
currentWinStreak = 0;
|
|
2435
|
+
} else {
|
|
2436
|
+
currentWinStreak = 0;
|
|
2437
|
+
currentLossStreak = 0;
|
|
2438
|
+
}
|
|
2439
|
+
maxConsecutiveWins = Math.max(maxConsecutiveWins, currentWinStreak);
|
|
2440
|
+
maxConsecutiveLosses = Math.max(maxConsecutiveLosses, currentLossStreak);
|
|
2441
|
+
}
|
|
2442
|
+
const grossProfit = accumulator.grossProfit;
|
|
2443
|
+
const grossLoss = accumulator.grossLoss;
|
|
2444
|
+
const totalProfit = grossProfit - grossLoss;
|
|
2445
|
+
const avgTradesPerDay = fullPeriodDays == null ? null : support / fullPeriodDays;
|
|
2446
|
+
const avgProfitPerDay = fullPeriodDays == null ? null : totalProfit / fullPeriodDays;
|
|
2447
|
+
const losingMonthEntries = [...accumulator.monthProfits.entries()].filter(
|
|
2448
|
+
([, profit]) => profit < 0
|
|
2449
|
+
);
|
|
2450
|
+
const worstMonth = [...accumulator.monthProfits.entries()].sort(
|
|
2451
|
+
(left, right) => left[1] - right[1]
|
|
2452
|
+
)[0] ?? null;
|
|
2453
|
+
return {
|
|
2454
|
+
support,
|
|
2455
|
+
supportRatio,
|
|
2456
|
+
totalProfit,
|
|
2457
|
+
grossProfit,
|
|
2458
|
+
grossLoss,
|
|
2459
|
+
profitFactor: grossLoss > 0 ? grossProfit / grossLoss : null,
|
|
2460
|
+
winRate: support > 0 ? accumulator.wins / support : null,
|
|
2461
|
+
avgProfit: support > 0 ? totalProfit / support : null,
|
|
2462
|
+
maxDrawdown,
|
|
2463
|
+
maxDrawdownPctOfGrossProfit: grossProfit > 0 ? maxDrawdown / grossProfit : null,
|
|
2464
|
+
maxDrawdownPctOfTotalProfit: totalProfit > 0 ? maxDrawdown / totalProfit : null,
|
|
2465
|
+
recoveryFactor: maxDrawdown > 0 ? totalProfit / maxDrawdown : null,
|
|
2466
|
+
maxConsecutiveWins,
|
|
2467
|
+
maxConsecutiveLosses,
|
|
2468
|
+
avgTradesPerDay,
|
|
2469
|
+
avgTradesPerWeek: avgTradesPerDay == null ? null : avgTradesPerDay * DAYS_PER_WEEK2,
|
|
2470
|
+
avgProfitPerDay,
|
|
2471
|
+
avgProfitPerMonth: avgProfitPerDay == null ? null : avgProfitPerDay * DAYS_PER_MONTH2,
|
|
2472
|
+
losingMonths: losingMonthEntries.length,
|
|
2473
|
+
worstMonth: worstMonth ? {
|
|
2474
|
+
month: worstMonth[0],
|
|
2475
|
+
totalProfit: worstMonth[1]
|
|
2476
|
+
} : null,
|
|
2477
|
+
directionCounts: Object.fromEntries(accumulator.directionCounts.entries()),
|
|
2478
|
+
topSymbols: [...accumulator.symbolCounts.entries()].map(([symbol, value]) => ({
|
|
2479
|
+
symbol,
|
|
2480
|
+
...value
|
|
2481
|
+
})).sort(
|
|
2482
|
+
(left, right) => right.count - left.count || Math.abs(right.totalProfit) - Math.abs(left.totalProfit)
|
|
2483
|
+
).slice(0, 5)
|
|
2484
|
+
};
|
|
2485
|
+
};
|
|
2486
|
+
var summarizeSelectedRows = (rows, selected) => {
|
|
2487
|
+
const accumulator = createSummaryAccumulator();
|
|
2488
|
+
for (const row of selected) {
|
|
2489
|
+
addSummaryRow(accumulator, row);
|
|
2490
|
+
}
|
|
2491
|
+
return finalizeAiPocketSummary({ rows, accumulator });
|
|
2492
|
+
};
|
|
2493
|
+
var summarizeMask = (rows, mask) => {
|
|
2494
|
+
const accumulator = createSummaryAccumulator();
|
|
2495
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
2496
|
+
if (mask[index] === 1) {
|
|
2497
|
+
addSummaryRow(accumulator, rows[index]);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
return finalizeAiPocketSummary({ rows, accumulator });
|
|
2501
|
+
};
|
|
2502
|
+
var summarizeRowIndexes = (rows, rowIndexes) => {
|
|
2503
|
+
const accumulator = createSummaryAccumulator();
|
|
2504
|
+
for (const rowIndex of rowIndexes) {
|
|
2505
|
+
addSummaryRow(accumulator, rows[rowIndex]);
|
|
2506
|
+
}
|
|
2507
|
+
return finalizeAiPocketSummary({ rows, accumulator });
|
|
2508
|
+
};
|
|
2509
|
+
var summarizeAiPocketRows = (rows) => summarizeSelectedRows(rows, rows);
|
|
2510
|
+
var matchesPredicate = (value, predicate) => {
|
|
2511
|
+
if (predicate.kind === "numeric") {
|
|
2512
|
+
if (!isFiniteNumber(value)) {
|
|
2513
|
+
return false;
|
|
2514
|
+
}
|
|
2515
|
+
return predicate.op === "<=" ? value <= predicate.threshold : value >= predicate.threshold;
|
|
2516
|
+
}
|
|
2517
|
+
return value === predicate.value;
|
|
2518
|
+
};
|
|
2519
|
+
var buildMask = (rows, predicate) => {
|
|
2520
|
+
const mask = new Uint8Array(rows.length);
|
|
2521
|
+
let support = 0;
|
|
2522
|
+
rows.forEach((row, index) => {
|
|
2523
|
+
if (matchesPredicate(row.features[predicate.featureKey], predicate)) {
|
|
2524
|
+
mask[index] = 1;
|
|
2525
|
+
support += 1;
|
|
2526
|
+
}
|
|
2527
|
+
});
|
|
2528
|
+
return { mask, support };
|
|
2529
|
+
};
|
|
2530
|
+
var intersectMasks = (left, right) => {
|
|
2531
|
+
const mask = new Uint8Array(left.length);
|
|
2532
|
+
let support = 0;
|
|
2533
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
2534
|
+
if (left[index] === 1 && right[index] === 1) {
|
|
2535
|
+
mask[index] = 1;
|
|
2536
|
+
support += 1;
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
return { mask, support };
|
|
2540
|
+
};
|
|
2541
|
+
var buildPredicateListMask = (rows, predicates) => {
|
|
2542
|
+
const mask = new Uint8Array(rows.length);
|
|
2543
|
+
let support = 0;
|
|
2544
|
+
rows.forEach((row, index) => {
|
|
2545
|
+
if (predicates.every(
|
|
2546
|
+
(predicate) => matchesPredicate(row.features[predicate.featureKey], predicate)
|
|
2547
|
+
)) {
|
|
2548
|
+
mask[index] = 1;
|
|
2549
|
+
support += 1;
|
|
2550
|
+
}
|
|
2551
|
+
});
|
|
2552
|
+
return { mask, support };
|
|
2553
|
+
};
|
|
2554
|
+
var toPublicPredicate = (predicate) => {
|
|
2555
|
+
if (predicate.kind === "numeric") {
|
|
2556
|
+
return {
|
|
2557
|
+
id: predicate.id,
|
|
2558
|
+
featureKey: predicate.featureKey,
|
|
2559
|
+
label: predicate.label,
|
|
2560
|
+
kind: predicate.kind,
|
|
2561
|
+
op: predicate.op,
|
|
2562
|
+
threshold: predicate.threshold
|
|
2563
|
+
};
|
|
2564
|
+
}
|
|
2565
|
+
return {
|
|
2566
|
+
id: predicate.id,
|
|
2567
|
+
featureKey: predicate.featureKey,
|
|
2568
|
+
label: predicate.label,
|
|
2569
|
+
kind: predicate.kind,
|
|
2570
|
+
op: predicate.op,
|
|
2571
|
+
value: predicate.value
|
|
2572
|
+
};
|
|
2573
|
+
};
|
|
2574
|
+
var buildAiPocketPredicateResult = (rows, options = {}) => {
|
|
2575
|
+
const minSupport = Math.max(1, Math.trunc(options.minSupport ?? 20));
|
|
2576
|
+
const maxCategories = Math.max(2, Math.trunc(options.maxCategories ?? 24));
|
|
2577
|
+
const progressInterval = Math.max(
|
|
2578
|
+
1,
|
|
2579
|
+
Math.trunc(options.progressInterval ?? 500)
|
|
2580
|
+
);
|
|
2581
|
+
const onProgress = options.onProgress;
|
|
2582
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
2583
|
+
let lastFeatureProgress = 0;
|
|
2584
|
+
let lastPredicateProgress = 0;
|
|
2585
|
+
const emitProgress = (phase, current, total, done = false) => {
|
|
2586
|
+
if (!onProgress) {
|
|
2587
|
+
return;
|
|
2588
|
+
}
|
|
2589
|
+
const lastProgress = phase === "features" ? lastFeatureProgress : lastPredicateProgress;
|
|
2590
|
+
if (!done && current - lastProgress < progressInterval) {
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2593
|
+
if (phase === "features") {
|
|
2594
|
+
lastFeatureProgress = current;
|
|
2595
|
+
} else if (phase === "predicates") {
|
|
2596
|
+
lastPredicateProgress = current;
|
|
2597
|
+
}
|
|
2598
|
+
onProgress({
|
|
2599
|
+
phase,
|
|
2600
|
+
current,
|
|
2601
|
+
total,
|
|
2602
|
+
done,
|
|
2603
|
+
truncated: false
|
|
2604
|
+
});
|
|
2605
|
+
};
|
|
2606
|
+
rows.forEach((row, rowIndex) => {
|
|
2607
|
+
for (const [key, value] of Object.entries(row.features)) {
|
|
2608
|
+
if (value === void 0) {
|
|
2609
|
+
continue;
|
|
2610
|
+
}
|
|
2611
|
+
const bucket = buckets.get(key) ?? {
|
|
2612
|
+
key,
|
|
2613
|
+
count: 0,
|
|
2614
|
+
numericValues: [],
|
|
2615
|
+
numericRowIndexes: [],
|
|
2616
|
+
categoryCounts: /* @__PURE__ */ new Map()
|
|
2617
|
+
};
|
|
2618
|
+
bucket.count += 1;
|
|
2619
|
+
if (isFiniteNumber(value)) {
|
|
2620
|
+
bucket.numericValues.push(value);
|
|
2621
|
+
bucket.numericRowIndexes.push(rowIndex);
|
|
2622
|
+
}
|
|
2623
|
+
if (typeof value === "string" || typeof value === "boolean" || value === null) {
|
|
2624
|
+
const serialized = JSON.stringify(value);
|
|
2625
|
+
const categoryBucket = bucket.categoryCounts.get(serialized) ?? {
|
|
2626
|
+
value,
|
|
2627
|
+
count: 0,
|
|
2628
|
+
rowIndexes: []
|
|
2629
|
+
};
|
|
2630
|
+
categoryBucket.count += 1;
|
|
2631
|
+
categoryBucket.rowIndexes.push(rowIndex);
|
|
2632
|
+
bucket.categoryCounts.set(serialized, categoryBucket);
|
|
2633
|
+
}
|
|
2634
|
+
buckets.set(key, bucket);
|
|
2635
|
+
}
|
|
2636
|
+
emitProgress("features", rowIndex + 1, rows.length);
|
|
2637
|
+
});
|
|
2638
|
+
emitProgress("features", rows.length, rows.length, true);
|
|
2639
|
+
const bucketList = [...buckets.values()].sort(
|
|
2640
|
+
(left, right) => left.key.localeCompare(right.key)
|
|
2641
|
+
);
|
|
2642
|
+
const predicates = [];
|
|
2643
|
+
for (let bucketIndex = 0; bucketIndex < bucketList.length; bucketIndex += 1) {
|
|
2644
|
+
const bucket = bucketList[bucketIndex];
|
|
2645
|
+
const key = bucket.key;
|
|
2646
|
+
if (bucket.count < minSupport) {
|
|
2647
|
+
emitProgress("predicates", bucketIndex + 1, bucketList.length);
|
|
2648
|
+
continue;
|
|
2649
|
+
}
|
|
2650
|
+
const numericEntries = bucket.numericValues.map((value, index) => ({
|
|
2651
|
+
value,
|
|
2652
|
+
rowIndex: bucket.numericRowIndexes[index]
|
|
2653
|
+
})).sort((left, right) => left.value - right.value);
|
|
2654
|
+
const numericValues = numericEntries.map((entry) => entry.value);
|
|
2655
|
+
if (numericValues.length >= minSupport) {
|
|
2656
|
+
const uniqueValues = [...new Set(numericValues.map(roundThreshold))];
|
|
2657
|
+
if (uniqueValues.length > 1) {
|
|
2658
|
+
const thresholdSet = /* @__PURE__ */ new Set();
|
|
2659
|
+
[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9].forEach(
|
|
2660
|
+
(quantile) => thresholdSet.add(roundThreshold(quantileAt(numericValues, quantile)))
|
|
2661
|
+
);
|
|
2662
|
+
if (numericValues[0] < 0 && numericValues.at(-1) > 0) {
|
|
2663
|
+
thresholdSet.add(0);
|
|
2664
|
+
}
|
|
2665
|
+
const thresholds = [...thresholdSet].sort((left, right) => {
|
|
2666
|
+
return left - right;
|
|
2667
|
+
});
|
|
2668
|
+
const summaryByPredicate = /* @__PURE__ */ new Map();
|
|
2669
|
+
const lessOrEqualAccumulator = createSummaryAccumulator();
|
|
2670
|
+
let lessOrEqualIndex = 0;
|
|
2671
|
+
for (const threshold of thresholds) {
|
|
2672
|
+
while (lessOrEqualIndex < numericEntries.length && numericEntries[lessOrEqualIndex].value <= threshold) {
|
|
2673
|
+
addSummaryRow(
|
|
2674
|
+
lessOrEqualAccumulator,
|
|
2675
|
+
rows[numericEntries[lessOrEqualIndex].rowIndex]
|
|
2676
|
+
);
|
|
2677
|
+
lessOrEqualIndex += 1;
|
|
2678
|
+
}
|
|
2679
|
+
const support = lessOrEqualAccumulator.support;
|
|
2680
|
+
if (support >= minSupport && support < rows.length) {
|
|
2681
|
+
summaryByPredicate.set(`<=:${threshold}`, {
|
|
2682
|
+
support,
|
|
2683
|
+
summary: finalizeAiPocketSummary({
|
|
2684
|
+
rows,
|
|
2685
|
+
accumulator: lessOrEqualAccumulator
|
|
2686
|
+
})
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
const greaterOrEqualAccumulator = createSummaryAccumulator();
|
|
2691
|
+
let greaterOrEqualIndex = numericEntries.length - 1;
|
|
2692
|
+
for (const threshold of [...thresholds].reverse()) {
|
|
2693
|
+
while (greaterOrEqualIndex >= 0 && numericEntries[greaterOrEqualIndex].value >= threshold) {
|
|
2694
|
+
addSummaryRow(
|
|
2695
|
+
greaterOrEqualAccumulator,
|
|
2696
|
+
rows[numericEntries[greaterOrEqualIndex].rowIndex]
|
|
2697
|
+
);
|
|
2698
|
+
greaterOrEqualIndex -= 1;
|
|
2699
|
+
}
|
|
2700
|
+
const support = greaterOrEqualAccumulator.support;
|
|
2701
|
+
if (support >= minSupport && support < rows.length) {
|
|
2702
|
+
summaryByPredicate.set(`>=:${threshold}`, {
|
|
2703
|
+
support,
|
|
2704
|
+
summary: finalizeAiPocketSummary({
|
|
2705
|
+
rows,
|
|
2706
|
+
accumulator: greaterOrEqualAccumulator
|
|
2707
|
+
})
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
for (const threshold of thresholds) {
|
|
2712
|
+
for (const op of ["<=", ">="]) {
|
|
2713
|
+
const scored = summaryByPredicate.get(`${op}:${threshold}`);
|
|
2714
|
+
if (!scored) {
|
|
2715
|
+
continue;
|
|
2716
|
+
}
|
|
2717
|
+
predicates.push({
|
|
2718
|
+
id: `${key}${op}${formatNumber(threshold)}`,
|
|
2719
|
+
featureKey: key,
|
|
2720
|
+
label: `${key} ${op} ${formatNumber(threshold)}`,
|
|
2721
|
+
kind: "numeric",
|
|
2722
|
+
op,
|
|
2723
|
+
threshold,
|
|
2724
|
+
support: scored.support,
|
|
2725
|
+
atomSummary: scored.summary
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
emitProgress("predicates", bucketIndex + 1, bucketList.length);
|
|
2731
|
+
continue;
|
|
2732
|
+
}
|
|
2733
|
+
if (!bucket.categoryCounts.size || bucket.categoryCounts.size > maxCategories) {
|
|
2734
|
+
emitProgress("predicates", bucketIndex + 1, bucketList.length);
|
|
2735
|
+
continue;
|
|
2736
|
+
}
|
|
2737
|
+
for (const { value, count, rowIndexes } of bucket.categoryCounts.values()) {
|
|
2738
|
+
if (count < minSupport || count >= rows.length) {
|
|
2739
|
+
continue;
|
|
2740
|
+
}
|
|
2741
|
+
predicates.push({
|
|
2742
|
+
id: `${key}==${formatPredicateValue(value)}`,
|
|
2743
|
+
featureKey: key,
|
|
2744
|
+
label: `${key} == ${formatPredicateValue(value)}`,
|
|
2745
|
+
kind: "category",
|
|
2746
|
+
op: "==",
|
|
2747
|
+
value,
|
|
2748
|
+
support: count,
|
|
2749
|
+
atomSummary: summarizeRowIndexes(rows, rowIndexes)
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
emitProgress("predicates", bucketIndex + 1, bucketList.length);
|
|
2753
|
+
}
|
|
2754
|
+
emitProgress("predicates", bucketList.length, bucketList.length, true);
|
|
2755
|
+
return { featureKeys: buckets.size, predicates };
|
|
2756
|
+
};
|
|
2757
|
+
var scorePositivePocket = (summary) => {
|
|
2758
|
+
const profitFactor = summary.profitFactor ?? (summary.grossLoss === 0 ? 8 : 0);
|
|
2759
|
+
const winRate = summary.winRate ?? 0;
|
|
2760
|
+
return summary.totalProfit - summary.maxDrawdown * 0.6 + Math.min(profitFactor, 8) * 12 + winRate * 30 + Math.log10(summary.support + 1) * 6;
|
|
2761
|
+
};
|
|
2762
|
+
var scoreNegativePocket = (summary) => -summary.totalProfit + summary.maxDrawdown * 0.4 + summary.grossLoss * 0.2 + summary.maxConsecutiveLosses * 3;
|
|
2763
|
+
var comparePositivePockets = (left, right) => (right.validationScore ?? right.score) - (left.validationScore ?? left.score) || right.score - left.score || (right.validationSummary?.totalProfit ?? right.summary.totalProfit) - (left.validationSummary?.totalProfit ?? left.summary.totalProfit) || right.summary.totalProfit - left.summary.totalProfit || (right.summary.profitFactor ?? 999) - (left.summary.profitFactor ?? 999) || right.summary.support - left.summary.support;
|
|
2764
|
+
var compareNegativePockets = (left, right) => (right.validationScore ?? right.score) - (left.validationScore ?? left.score) || right.score - left.score || (left.validationSummary?.totalProfit ?? left.summary.totalProfit) - (right.validationSummary?.totalProfit ?? right.summary.totalProfit) || left.summary.totalProfit - right.summary.totalProfit || right.summary.grossLoss - left.summary.grossLoss || right.summary.support - left.summary.support;
|
|
2765
|
+
var createPocketResult = (rows, predicates, mask, validationRows) => {
|
|
2766
|
+
const publicPredicates = predicates.map(toPublicPredicate);
|
|
2767
|
+
const summary = summarizeMask(rows, mask);
|
|
2768
|
+
const validationMask = validationRows.length ? buildPredicateListMask(validationRows, publicPredicates).mask : null;
|
|
2769
|
+
const validationSummary = validationMask == null ? void 0 : summarizeMask(validationRows, validationMask);
|
|
2770
|
+
const condition = publicPredicates.map((predicate) => predicate.label).join(" AND ");
|
|
2771
|
+
const validationScore = validationSummary == null ? void 0 : validationSummary.support > 0 ? scorePositivePocket(validationSummary) : Number.NEGATIVE_INFINITY;
|
|
2772
|
+
return {
|
|
2773
|
+
id: publicPredicates.map((predicate) => predicate.id).join("&&"),
|
|
2774
|
+
depth: publicPredicates.length,
|
|
2775
|
+
predicates: publicPredicates,
|
|
2776
|
+
condition,
|
|
2777
|
+
summary,
|
|
2778
|
+
...validationSummary ? { validationSummary } : {},
|
|
2779
|
+
...validationScore != null ? { validationScore } : {},
|
|
2780
|
+
score: scorePositivePocket(summary)
|
|
2781
|
+
};
|
|
2782
|
+
};
|
|
2783
|
+
var hashMask = (mask) => {
|
|
2784
|
+
let hash = 2166136261;
|
|
2785
|
+
for (let index = 0; index < mask.length; index += 1) {
|
|
2786
|
+
if (mask[index] !== 1) {
|
|
2787
|
+
continue;
|
|
2788
|
+
}
|
|
2789
|
+
hash ^= index + 1;
|
|
2790
|
+
hash = Math.imul(hash, 16777619);
|
|
2791
|
+
}
|
|
2792
|
+
return (hash >>> 0).toString(36);
|
|
2793
|
+
};
|
|
2794
|
+
var isBetterRepresentativePocket = (candidate, existing, compare) => candidate.depth < existing.depth || candidate.depth === existing.depth && candidate.condition.length < existing.condition.length || candidate.depth === existing.depth && candidate.condition.length === existing.condition.length && compare(candidate, existing) < 0;
|
|
2795
|
+
var estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
|
|
2796
|
+
if (poolSize <= 0 || maxCombinations <= 0) {
|
|
2797
|
+
return 0;
|
|
2798
|
+
}
|
|
2799
|
+
let total = 0;
|
|
2800
|
+
let combinationsAtDepth = 1;
|
|
2801
|
+
const depthLimit = Math.min(poolSize, maxDepth);
|
|
2802
|
+
for (let depth = 1; depth <= depthLimit; depth += 1) {
|
|
2803
|
+
combinationsAtDepth = combinationsAtDepth * (poolSize - depth + 1) / depth;
|
|
2804
|
+
total += combinationsAtDepth;
|
|
2805
|
+
if (total >= maxCombinations) {
|
|
2806
|
+
return maxCombinations;
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
return Math.min(Math.trunc(total), maxCombinations);
|
|
2810
|
+
};
|
|
2811
|
+
var searchAiPockets = (rows, options = {}) => {
|
|
2812
|
+
const minSupport = Math.max(1, Math.trunc(options.minSupport ?? 20));
|
|
2813
|
+
const minProfitFactor = Math.max(0, options.minProfitFactor ?? 1.2);
|
|
2814
|
+
const minTotalProfit = options.minTotalProfit ?? 0;
|
|
2815
|
+
const minWinRate = Math.max(0, options.minWinRate ?? 0);
|
|
2816
|
+
const maxDepth = Math.max(1, Math.trunc(options.maxDepth ?? 2));
|
|
2817
|
+
const maxAtomicPredicates = Math.max(
|
|
2818
|
+
1,
|
|
2819
|
+
Math.trunc(options.maxAtomicPredicates ?? 180)
|
|
2820
|
+
);
|
|
2821
|
+
const maxCombinations = Math.max(
|
|
2822
|
+
0,
|
|
2823
|
+
Math.trunc(options.maxCombinations ?? 6e4)
|
|
2824
|
+
);
|
|
2825
|
+
const top = Math.max(1, Math.trunc(options.top ?? 50));
|
|
2826
|
+
const validationRows = options.validationRows ?? [];
|
|
2827
|
+
const minValidationSupport = Math.max(
|
|
2828
|
+
0,
|
|
2829
|
+
Math.trunc(options.minValidationSupport ?? 0)
|
|
2830
|
+
);
|
|
2831
|
+
const dedupeEquivalentSelections = options.dedupeEquivalentSelections !== false;
|
|
2832
|
+
const progressInterval = Math.max(
|
|
2833
|
+
1,
|
|
2834
|
+
Math.trunc(options.progressInterval ?? 500)
|
|
2835
|
+
);
|
|
2836
|
+
const onProgress = options.onProgress;
|
|
2837
|
+
const predicateResult = buildAiPocketPredicateResult(rows, {
|
|
2838
|
+
minSupport,
|
|
2839
|
+
maxCategories: options.maxCategories,
|
|
2840
|
+
progressInterval,
|
|
2841
|
+
onProgress
|
|
2842
|
+
});
|
|
2843
|
+
const { predicates } = predicateResult;
|
|
2844
|
+
let lastMaskProgress = 0;
|
|
2845
|
+
const emitMaskProgress = (current, done = false) => {
|
|
2846
|
+
if (!onProgress) {
|
|
2847
|
+
return;
|
|
2848
|
+
}
|
|
2849
|
+
if (!done && current - lastMaskProgress < progressInterval) {
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
lastMaskProgress = current;
|
|
2853
|
+
onProgress({
|
|
2854
|
+
phase: "masks",
|
|
2855
|
+
current,
|
|
2856
|
+
total: predicates.length,
|
|
2857
|
+
done,
|
|
2858
|
+
truncated: false
|
|
2859
|
+
});
|
|
2860
|
+
};
|
|
2861
|
+
predicates.forEach((_, index) => emitMaskProgress(index + 1));
|
|
2862
|
+
const scoredPredicates = predicates;
|
|
2863
|
+
emitMaskProgress(predicates.length, true);
|
|
2864
|
+
const predicatePool = [...scoredPredicates].sort(
|
|
2865
|
+
(left, right) => scorePositivePocket(right.atomSummary) - scorePositivePocket(left.atomSummary)
|
|
2866
|
+
).slice(0, Math.ceil(maxAtomicPredicates * 0.55));
|
|
2867
|
+
const negativePool = [...scoredPredicates].sort(
|
|
2868
|
+
(left, right) => scoreNegativePocket(right.atomSummary) - scoreNegativePocket(left.atomSummary)
|
|
2869
|
+
).slice(0, Math.ceil(maxAtomicPredicates * 0.3));
|
|
2870
|
+
const supportPool = [...scoredPredicates].sort((left, right) => right.support - left.support).slice(0, Math.ceil(maxAtomicPredicates * 0.2));
|
|
2871
|
+
const predicatePoolById = /* @__PURE__ */ new Map();
|
|
2872
|
+
[...predicatePool, ...negativePool, ...supportPool].forEach((predicate) => {
|
|
2873
|
+
if (predicatePoolById.size < maxAtomicPredicates) {
|
|
2874
|
+
predicatePoolById.set(predicate.id, predicate);
|
|
2875
|
+
}
|
|
2876
|
+
});
|
|
2877
|
+
const selectedPredicatePool = [...predicatePoolById.values()].map(
|
|
2878
|
+
(predicate) => {
|
|
2879
|
+
const { mask, support } = buildMask(rows, predicate);
|
|
2880
|
+
return {
|
|
2881
|
+
...predicate,
|
|
2882
|
+
mask,
|
|
2883
|
+
support
|
|
2884
|
+
};
|
|
2885
|
+
}
|
|
2886
|
+
);
|
|
2887
|
+
const estimatedCombinations = estimateCombinationCount(
|
|
2888
|
+
selectedPredicatePool.length,
|
|
2889
|
+
maxDepth,
|
|
2890
|
+
maxCombinations
|
|
2891
|
+
);
|
|
2892
|
+
const positivePockets = /* @__PURE__ */ new Map();
|
|
2893
|
+
const negativePockets = /* @__PURE__ */ new Map();
|
|
2894
|
+
const positiveSelectionKeys = /* @__PURE__ */ new Map();
|
|
2895
|
+
const negativeSelectionKeys = /* @__PURE__ */ new Map();
|
|
2896
|
+
let combinationsEvaluated = 0;
|
|
2897
|
+
let duplicatePocketsSkipped = 0;
|
|
2898
|
+
let truncated = false;
|
|
2899
|
+
let lastProgressCombinations = 0;
|
|
2900
|
+
const emitProgress = (done = false) => {
|
|
2901
|
+
if (!onProgress) {
|
|
2902
|
+
return;
|
|
2903
|
+
}
|
|
2904
|
+
if (!done && combinationsEvaluated - lastProgressCombinations < progressInterval) {
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2907
|
+
lastProgressCombinations = combinationsEvaluated;
|
|
2908
|
+
onProgress({
|
|
2909
|
+
phase: "combinations",
|
|
2910
|
+
current: Math.min(combinationsEvaluated, estimatedCombinations),
|
|
2911
|
+
total: estimatedCombinations,
|
|
2912
|
+
done,
|
|
2913
|
+
truncated
|
|
2914
|
+
});
|
|
2915
|
+
};
|
|
2916
|
+
const addPocket = (pocketPredicates, mask) => {
|
|
2917
|
+
const pocket = createPocketResult(
|
|
2918
|
+
rows,
|
|
2919
|
+
pocketPredicates,
|
|
2920
|
+
mask,
|
|
2921
|
+
validationRows
|
|
2922
|
+
);
|
|
2923
|
+
const { summary } = pocket;
|
|
2924
|
+
const profitFactor = summary.profitFactor ?? (summary.grossLoss === 0 && summary.totalProfit > 0 ? Number.POSITIVE_INFINITY : 0);
|
|
2925
|
+
const winRate = summary.winRate ?? 0;
|
|
2926
|
+
const validationSupport = pocket.validationSummary?.support ?? 0;
|
|
2927
|
+
const validationEligible = !validationRows.length || validationSupport >= minValidationSupport;
|
|
2928
|
+
if (summary.support >= minSupport && summary.totalProfit >= minTotalProfit && profitFactor >= minProfitFactor && winRate >= minWinRate && validationEligible) {
|
|
2929
|
+
const selectionKey = `${summary.support}:${hashMask(mask)}`;
|
|
2930
|
+
const mapKey = dedupeEquivalentSelections ? selectionKey : pocket.id;
|
|
2931
|
+
const existing = dedupeEquivalentSelections ? positiveSelectionKeys.get(mapKey) : positivePockets.get(mapKey);
|
|
2932
|
+
if (!existing || isBetterRepresentativePocket(pocket, existing, comparePositivePockets)) {
|
|
2933
|
+
positivePockets.delete(existing?.id ?? "");
|
|
2934
|
+
positivePockets.set(pocket.id, pocket);
|
|
2935
|
+
positiveSelectionKeys.set(mapKey, pocket);
|
|
2936
|
+
} else {
|
|
2937
|
+
duplicatePocketsSkipped += 1;
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
if (summary.support >= minSupport && summary.totalProfit < 0) {
|
|
2941
|
+
const negativePocket = {
|
|
2942
|
+
...pocket,
|
|
2943
|
+
score: scoreNegativePocket(summary),
|
|
2944
|
+
...pocket.validationSummary ? { validationScore: scoreNegativePocket(pocket.validationSummary) } : {}
|
|
2945
|
+
};
|
|
2946
|
+
const selectionKey = `${summary.support}:${hashMask(mask)}`;
|
|
2947
|
+
const mapKey = dedupeEquivalentSelections ? selectionKey : pocket.id;
|
|
2948
|
+
const existing = dedupeEquivalentSelections ? negativeSelectionKeys.get(mapKey) : negativePockets.get(mapKey);
|
|
2949
|
+
if (!existing || isBetterRepresentativePocket(
|
|
2950
|
+
negativePocket,
|
|
2951
|
+
existing,
|
|
2952
|
+
compareNegativePockets
|
|
2953
|
+
)) {
|
|
2954
|
+
negativePockets.delete(existing?.id ?? "");
|
|
2955
|
+
negativePockets.set(negativePocket.id, negativePocket);
|
|
2956
|
+
negativeSelectionKeys.set(mapKey, negativePocket);
|
|
2957
|
+
} else {
|
|
2958
|
+
duplicatePocketsSkipped += 1;
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
};
|
|
2962
|
+
const visit = ({
|
|
2963
|
+
startIndex,
|
|
2964
|
+
chosen,
|
|
2965
|
+
mask,
|
|
2966
|
+
usedFeatureKeys
|
|
2967
|
+
}) => {
|
|
2968
|
+
if (truncated) {
|
|
2969
|
+
return;
|
|
2970
|
+
}
|
|
2971
|
+
for (let index = startIndex; index < selectedPredicatePool.length; index += 1) {
|
|
2972
|
+
if (combinationsEvaluated >= maxCombinations) {
|
|
2973
|
+
truncated = true;
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
const predicate = selectedPredicatePool[index];
|
|
2977
|
+
if (usedFeatureKeys.has(predicate.featureKey)) {
|
|
2978
|
+
continue;
|
|
2979
|
+
}
|
|
2980
|
+
const intersection = mask == null ? { mask: predicate.mask, support: predicate.support } : intersectMasks(mask, predicate.mask);
|
|
2981
|
+
const nextMask = intersection.mask;
|
|
2982
|
+
combinationsEvaluated += 1;
|
|
2983
|
+
emitProgress();
|
|
2984
|
+
const support = intersection.support;
|
|
2985
|
+
if (support < minSupport) {
|
|
2986
|
+
continue;
|
|
2987
|
+
}
|
|
2988
|
+
const nextChosen = [...chosen, predicate];
|
|
2989
|
+
addPocket(nextChosen, nextMask);
|
|
2990
|
+
if (nextChosen.length >= maxDepth) {
|
|
2991
|
+
continue;
|
|
2992
|
+
}
|
|
2993
|
+
const nextUsedFeatureKeys = new Set(usedFeatureKeys);
|
|
2994
|
+
nextUsedFeatureKeys.add(predicate.featureKey);
|
|
2995
|
+
visit({
|
|
2996
|
+
startIndex: index + 1,
|
|
2997
|
+
chosen: nextChosen,
|
|
2998
|
+
mask: nextMask,
|
|
2999
|
+
usedFeatureKeys: nextUsedFeatureKeys
|
|
3000
|
+
});
|
|
3001
|
+
}
|
|
3002
|
+
};
|
|
3003
|
+
visit({
|
|
3004
|
+
startIndex: 0,
|
|
3005
|
+
chosen: [],
|
|
3006
|
+
mask: null,
|
|
3007
|
+
usedFeatureKeys: /* @__PURE__ */ new Set()
|
|
3008
|
+
});
|
|
3009
|
+
emitProgress(true);
|
|
3010
|
+
return {
|
|
3011
|
+
baseline: summarizeAiPocketRows(rows),
|
|
3012
|
+
...validationRows.length ? { validationBaseline: summarizeAiPocketRows(validationRows) } : {},
|
|
3013
|
+
predicates: predicates.map(toPublicPredicate),
|
|
3014
|
+
positivePockets: [...positivePockets.values()].sort(comparePositivePockets).slice(0, top),
|
|
3015
|
+
negativePockets: [...negativePockets.values()].sort(compareNegativePockets).slice(0, top),
|
|
3016
|
+
stats: {
|
|
3017
|
+
rows: rows.length,
|
|
3018
|
+
featureKeys: predicateResult.featureKeys,
|
|
3019
|
+
predicates: predicates.length,
|
|
3020
|
+
atomicPredicatesUsed: selectedPredicatePool.length,
|
|
3021
|
+
estimatedCombinations,
|
|
3022
|
+
combinationsEvaluated,
|
|
3023
|
+
validationRows: validationRows.length,
|
|
3024
|
+
duplicatePocketsSkipped,
|
|
3025
|
+
truncated
|
|
3026
|
+
}
|
|
3027
|
+
};
|
|
3028
|
+
};
|
|
3029
|
+
var formatMdNumber = (value, digits = 2) => value == null || !Number.isFinite(value) ? "n/a" : value.toFixed(digits);
|
|
3030
|
+
var formatMdPercent = (value) => value == null || !Number.isFinite(value) ? "n/a" : `${(value * 100).toFixed(1)}%`;
|
|
3031
|
+
var escapeMarkdownCell = (value) => String(value ?? "n/a").replace(/\|/g, "\\|").replace(/\n/g, "<br>");
|
|
3032
|
+
var markdownTable = (headers, rows) => {
|
|
3033
|
+
const header = `| ${headers.map(escapeMarkdownCell).join(" | ")} |`;
|
|
3034
|
+
const divider = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
3035
|
+
const body = rows.map(
|
|
3036
|
+
(row) => `| ${row.map(escapeMarkdownCell).join(" | ")} |`
|
|
3037
|
+
);
|
|
3038
|
+
return [header, divider, ...body].join("\n");
|
|
3039
|
+
};
|
|
3040
|
+
var summaryMetricRows = (summary) => [
|
|
3041
|
+
["rows", summary.support],
|
|
3042
|
+
["win_rate", formatMdPercent(summary.winRate)],
|
|
3043
|
+
["total_profit", formatMdNumber(summary.totalProfit)],
|
|
3044
|
+
["gross_profit", formatMdNumber(summary.grossProfit)],
|
|
3045
|
+
["gross_loss", formatMdNumber(-summary.grossLoss)],
|
|
3046
|
+
["profit_factor", formatMdNumber(summary.profitFactor)],
|
|
3047
|
+
["max_drawdown", formatMdNumber(summary.maxDrawdown)],
|
|
3048
|
+
[
|
|
3049
|
+
"max_drawdown_pct_of_gross_profit",
|
|
3050
|
+
formatMdPercent(summary.maxDrawdownPctOfGrossProfit)
|
|
3051
|
+
],
|
|
3052
|
+
[
|
|
3053
|
+
"max_drawdown_pct_of_total_profit",
|
|
3054
|
+
formatMdPercent(summary.maxDrawdownPctOfTotalProfit)
|
|
3055
|
+
],
|
|
3056
|
+
["max_consecutive_losses", summary.maxConsecutiveLosses],
|
|
3057
|
+
["avg_trades_per_day", formatMdNumber(summary.avgTradesPerDay)],
|
|
3058
|
+
["avg_trades_per_week", formatMdNumber(summary.avgTradesPerWeek)],
|
|
3059
|
+
["avg_profit_per_day", formatMdNumber(summary.avgProfitPerDay)],
|
|
3060
|
+
["avg_profit_per_month", formatMdNumber(summary.avgProfitPerMonth)],
|
|
3061
|
+
["losing_months", summary.losingMonths],
|
|
3062
|
+
[
|
|
3063
|
+
"worst_month",
|
|
3064
|
+
summary.worstMonth ? `${summary.worstMonth.month} ${formatMdNumber(summary.worstMonth.totalProfit)}` : "n/a"
|
|
3065
|
+
]
|
|
3066
|
+
];
|
|
3067
|
+
var pocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
3068
|
+
index + 1,
|
|
3069
|
+
pocket.summary.support,
|
|
3070
|
+
formatMdPercent(pocket.summary.supportRatio),
|
|
3071
|
+
formatMdPercent(pocket.summary.winRate),
|
|
3072
|
+
formatMdNumber(pocket.summary.profitFactor),
|
|
3073
|
+
formatMdNumber(pocket.summary.totalProfit),
|
|
3074
|
+
formatMdNumber(pocket.summary.maxDrawdown),
|
|
3075
|
+
pocket.validationSummary?.support ?? "n/a",
|
|
3076
|
+
pocket.validationSummary ? formatMdPercent(pocket.validationSummary.winRate) : "n/a",
|
|
3077
|
+
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.profitFactor) : "n/a",
|
|
3078
|
+
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.totalProfit) : "n/a",
|
|
3079
|
+
formatMdNumber(pocket.summary.avgTradesPerDay),
|
|
3080
|
+
pocket.summary.losingMonths,
|
|
3081
|
+
formatMdNumber(pocket.score),
|
|
3082
|
+
pocket.condition
|
|
3083
|
+
]);
|
|
3084
|
+
var buildAiPocketMarkdownReport = ({
|
|
3085
|
+
generatedAt,
|
|
3086
|
+
run,
|
|
3087
|
+
currentGate,
|
|
3088
|
+
pocketSearch,
|
|
3089
|
+
errors
|
|
3090
|
+
}) => {
|
|
3091
|
+
const generatedIso = new Date(generatedAt).toISOString();
|
|
3092
|
+
const lines = [
|
|
3093
|
+
"# AI Pocket Search Report",
|
|
3094
|
+
"",
|
|
3095
|
+
`Generated: ${generatedIso}`,
|
|
3096
|
+
"",
|
|
3097
|
+
"## Run",
|
|
3098
|
+
"",
|
|
3099
|
+
markdownTable(
|
|
3100
|
+
["Field", "Value"],
|
|
3101
|
+
[
|
|
3102
|
+
["strategy", run.strategy],
|
|
3103
|
+
["source_rows", run.sourceRows],
|
|
3104
|
+
["selected_rows", run.selectedRows],
|
|
3105
|
+
["evaluated_rows", run.evaluatedRows],
|
|
3106
|
+
["scope", run.scope],
|
|
3107
|
+
["scope_rows", run.scopeRows],
|
|
3108
|
+
["train_rows", run.trainRows],
|
|
3109
|
+
["validation_rows", run.validationRows],
|
|
3110
|
+
["validation_split", formatMdPercent(run.validationSplit)],
|
|
3111
|
+
["min_validation_support", run.minValidationSupport],
|
|
3112
|
+
["failed", run.failed],
|
|
3113
|
+
["recent", run.recent === 0 ? "all" : run.recent],
|
|
3114
|
+
["skip", run.skip],
|
|
3115
|
+
[
|
|
3116
|
+
"since",
|
|
3117
|
+
run.since == null ? "n/a" : new Date(run.since).toISOString()
|
|
3118
|
+
],
|
|
3119
|
+
[
|
|
3120
|
+
"until",
|
|
3121
|
+
run.until == null ? "n/a" : new Date(run.until).toISOString()
|
|
3122
|
+
],
|
|
3123
|
+
["period", run.period ?? "n/a"],
|
|
3124
|
+
["min_quality", run.minQuality],
|
|
3125
|
+
["max_depth", run.search.maxDepth],
|
|
3126
|
+
["min_support", run.search.minSupport],
|
|
3127
|
+
["max_atomic_predicates", run.search.maxAtomicPredicates],
|
|
3128
|
+
["max_combinations", run.search.maxCombinations],
|
|
3129
|
+
["include_symbol", run.includeSymbol ? "on" : "off"],
|
|
3130
|
+
["include_gate_context", run.includeGateContext ? "on" : "off"],
|
|
3131
|
+
["feature_profile", run.featureProfile ?? "all"],
|
|
3132
|
+
["report_path", run.reportPath]
|
|
3133
|
+
]
|
|
3134
|
+
),
|
|
3135
|
+
"",
|
|
3136
|
+
"## Dataset Files",
|
|
3137
|
+
"",
|
|
3138
|
+
...run.filePaths.map((filePath) => `- \`${filePath}\``),
|
|
3139
|
+
"",
|
|
3140
|
+
"## Current Gate qN+ Baseline",
|
|
3141
|
+
"",
|
|
3142
|
+
markdownTable(
|
|
3143
|
+
["Q", "Approved", "WR", "PF", "PNL", "Max DD", "Trades/Day", "PNL/Day"],
|
|
3144
|
+
currentGate.qualityThresholds.map(({ label, summary }) => [
|
|
3145
|
+
label,
|
|
3146
|
+
summary.approved,
|
|
3147
|
+
formatMdPercent(summary.approvedRisk.winRate),
|
|
3148
|
+
formatMdNumber(summary.approvedRisk.profitFactor),
|
|
3149
|
+
formatMdNumber(summary.approvedRisk.totalProfit),
|
|
3150
|
+
formatMdNumber(summary.approvedRisk.maxDrawdown),
|
|
3151
|
+
formatMdNumber(summary.avgApprovedTradesPerDay),
|
|
3152
|
+
formatMdNumber(summary.avgProfitApprovedPerDay)
|
|
3153
|
+
])
|
|
3154
|
+
),
|
|
3155
|
+
"",
|
|
3156
|
+
"## Train Baseline",
|
|
3157
|
+
"",
|
|
3158
|
+
markdownTable(
|
|
3159
|
+
["Metric", "Value"],
|
|
3160
|
+
summaryMetricRows(pocketSearch.baseline)
|
|
3161
|
+
),
|
|
3162
|
+
"",
|
|
3163
|
+
...pocketSearch.validationBaseline ? [
|
|
3164
|
+
"## Validation Baseline",
|
|
3165
|
+
"",
|
|
3166
|
+
markdownTable(
|
|
3167
|
+
["Metric", "Value"],
|
|
3168
|
+
summaryMetricRows(pocketSearch.validationBaseline)
|
|
3169
|
+
),
|
|
3170
|
+
""
|
|
3171
|
+
] : [],
|
|
3172
|
+
"## Search Stats",
|
|
3173
|
+
"",
|
|
3174
|
+
markdownTable(
|
|
3175
|
+
["Field", "Value"],
|
|
3176
|
+
[
|
|
3177
|
+
["feature_keys", pocketSearch.stats.featureKeys],
|
|
3178
|
+
["predicates", pocketSearch.stats.predicates],
|
|
3179
|
+
["atomic_used", pocketSearch.stats.atomicPredicatesUsed],
|
|
3180
|
+
["estimated_combinations", pocketSearch.stats.estimatedCombinations],
|
|
3181
|
+
["combinations_evaluated", pocketSearch.stats.combinationsEvaluated],
|
|
3182
|
+
["validation_rows", pocketSearch.stats.validationRows],
|
|
3183
|
+
[
|
|
3184
|
+
"duplicate_pockets_skipped",
|
|
3185
|
+
pocketSearch.stats.duplicatePocketsSkipped
|
|
3186
|
+
],
|
|
3187
|
+
["truncated", pocketSearch.stats.truncated ? "yes" : "no"]
|
|
3188
|
+
]
|
|
3189
|
+
),
|
|
3190
|
+
"",
|
|
3191
|
+
"## Top Positive Pockets",
|
|
3192
|
+
"",
|
|
3193
|
+
markdownTable(
|
|
3194
|
+
[
|
|
3195
|
+
"#",
|
|
3196
|
+
"N",
|
|
3197
|
+
"Support",
|
|
3198
|
+
"WR",
|
|
3199
|
+
"PF",
|
|
3200
|
+
"PNL",
|
|
3201
|
+
"Max DD",
|
|
3202
|
+
"Val N",
|
|
3203
|
+
"Val WR",
|
|
3204
|
+
"Val PF",
|
|
3205
|
+
"Val PNL",
|
|
3206
|
+
"Trades/Day",
|
|
3207
|
+
"Losing Months",
|
|
3208
|
+
"Score",
|
|
3209
|
+
"Pocket"
|
|
3210
|
+
],
|
|
3211
|
+
pocketRows(pocketSearch.positivePockets)
|
|
3212
|
+
),
|
|
3213
|
+
"",
|
|
3214
|
+
"## Top Loss Pockets",
|
|
3215
|
+
"",
|
|
3216
|
+
markdownTable(
|
|
3217
|
+
[
|
|
3218
|
+
"#",
|
|
3219
|
+
"N",
|
|
3220
|
+
"Support",
|
|
3221
|
+
"WR",
|
|
3222
|
+
"PF",
|
|
3223
|
+
"PNL",
|
|
3224
|
+
"Max DD",
|
|
3225
|
+
"Val N",
|
|
3226
|
+
"Val WR",
|
|
3227
|
+
"Val PF",
|
|
3228
|
+
"Val PNL",
|
|
3229
|
+
"Trades/Day",
|
|
3230
|
+
"Losing Months",
|
|
3231
|
+
"Score",
|
|
3232
|
+
"Pocket"
|
|
3233
|
+
],
|
|
3234
|
+
pocketRows(pocketSearch.negativePockets)
|
|
3235
|
+
),
|
|
3236
|
+
""
|
|
3237
|
+
];
|
|
3238
|
+
if (errors.length) {
|
|
3239
|
+
lines.push("## Errors", "", ...errors.map((error) => `- ${error}`), "");
|
|
3240
|
+
}
|
|
3241
|
+
return `${lines.join("\n")}
|
|
3242
|
+
`;
|
|
3243
|
+
};
|
|
3244
|
+
|
|
3245
|
+
// src/scripts/aiPocketSearch.ts
|
|
3246
|
+
var ListIt = require_list_it();
|
|
3247
|
+
import_args.default.example(
|
|
3248
|
+
"yarn ai-pocket-search --strategy LiquidityZones -n 0 --maxDepth 2 --minSupport 25",
|
|
3249
|
+
"Search deterministic AI-gate pockets over the latest LiquidityZones AI export"
|
|
3250
|
+
);
|
|
3251
|
+
import_args.default.option(["o", "outDir"], "Dataset directory", "data/ai/export");
|
|
3252
|
+
import_args.default.option(["s", "strategy"], "Strategy name filter for merged file", "");
|
|
3253
|
+
import_args.default.option(["f", "file"], "Explicit merged dataset file path", "");
|
|
3254
|
+
import_args.default.option(
|
|
3255
|
+
["n", "recent"],
|
|
3256
|
+
"How many recent trades to evaluate from the end (0 = all)",
|
|
3257
|
+
50
|
|
3258
|
+
);
|
|
3259
|
+
import_args.default.option(
|
|
3260
|
+
["k", "skip"],
|
|
3261
|
+
"How many recent trades to skip from the end before selecting replay rows",
|
|
3262
|
+
0
|
|
3263
|
+
);
|
|
3264
|
+
import_args.default.option(
|
|
3265
|
+
["M", "minQuality"],
|
|
3266
|
+
"Minimum deterministic gate quality used for current qN+ baseline",
|
|
3267
|
+
4
|
|
3268
|
+
);
|
|
3269
|
+
import_args.default.option(
|
|
3270
|
+
["S", "since"],
|
|
3271
|
+
"Only evaluate rows at or after this timestamp (ISO date or epoch ms)",
|
|
3272
|
+
""
|
|
3273
|
+
);
|
|
3274
|
+
import_args.default.option(
|
|
3275
|
+
["u", "until"],
|
|
3276
|
+
"Only evaluate rows at or before this timestamp (ISO date or epoch ms)",
|
|
3277
|
+
""
|
|
3278
|
+
);
|
|
3279
|
+
import_args.default.option(
|
|
3280
|
+
["P", "period"],
|
|
3281
|
+
"Evaluate a trailing selected-row period such as last365d, last90d, or last30d",
|
|
3282
|
+
""
|
|
3283
|
+
);
|
|
3284
|
+
import_args.default.option(
|
|
3285
|
+
["q", "qualityThresholds"],
|
|
3286
|
+
"Comma-separated qN+ thresholds for current-gate baseline",
|
|
3287
|
+
"3,4,5"
|
|
3288
|
+
);
|
|
3289
|
+
import_args.default.option(
|
|
3290
|
+
["g", "scope"],
|
|
3291
|
+
"Search scope: all, approved, rejected, or candidates",
|
|
3292
|
+
"all"
|
|
3293
|
+
);
|
|
3294
|
+
import_args.default.option(["d", "maxDepth"], "Maximum predicate-combination depth", 2);
|
|
3295
|
+
import_args.default.option(["m", "minSupport"], "Minimum rows required for a pocket", 20);
|
|
3296
|
+
import_args.default.option(
|
|
3297
|
+
["F", "minProfitFactor"],
|
|
3298
|
+
"Minimum profit factor required for positive pockets",
|
|
3299
|
+
1.2
|
|
3300
|
+
);
|
|
3301
|
+
import_args.default.option(
|
|
3302
|
+
["W", "minWinRate"],
|
|
3303
|
+
"Minimum win rate required for positive pockets",
|
|
3304
|
+
0
|
|
3305
|
+
);
|
|
3306
|
+
import_args.default.option(
|
|
3307
|
+
["R", "minTotalProfit"],
|
|
3308
|
+
"Minimum total PnL required for positive pockets",
|
|
3309
|
+
0
|
|
3310
|
+
);
|
|
3311
|
+
import_args.default.option(
|
|
3312
|
+
["a", "maxAtomicPredicates"],
|
|
3313
|
+
"Maximum strongest atomic predicates used for combinations",
|
|
3314
|
+
180
|
|
3315
|
+
);
|
|
3316
|
+
import_args.default.option(
|
|
3317
|
+
["C", "maxCombinations"],
|
|
3318
|
+
"Maximum predicate combinations to evaluate",
|
|
3319
|
+
6e4
|
|
3320
|
+
);
|
|
3321
|
+
import_args.default.option(
|
|
3322
|
+
["V", "validationSplit"],
|
|
3323
|
+
"Trailing time-ordered scope share reserved for validation (0 disables)",
|
|
3324
|
+
0.25
|
|
3325
|
+
);
|
|
3326
|
+
import_args.default.option(
|
|
3327
|
+
["N", "minValidationSupport"],
|
|
3328
|
+
"Minimum validation rows required for positive pockets (0 = auto)",
|
|
3329
|
+
0
|
|
3330
|
+
);
|
|
3331
|
+
import_args.default.option(
|
|
3332
|
+
["D", "dedupeEquivalentSelections"],
|
|
3333
|
+
"Collapse pockets that select the same train rows",
|
|
3334
|
+
true
|
|
3335
|
+
);
|
|
3336
|
+
import_args.default.option(["t", "top"], "Top pockets to print in each section", 30);
|
|
3337
|
+
import_args.default.option(["Y", "includeSymbol"], "Allow symbol as a pocket feature", false);
|
|
3338
|
+
import_args.default.option(
|
|
3339
|
+
["E", "includeGateContext"],
|
|
3340
|
+
"Allow current deterministic gate output fields as pocket features",
|
|
3341
|
+
false
|
|
3342
|
+
);
|
|
3343
|
+
import_args.default.option(
|
|
3344
|
+
["p", "featureProfile"],
|
|
3345
|
+
"Feature extraction profile: compact or all",
|
|
3346
|
+
"all"
|
|
3347
|
+
);
|
|
3348
|
+
import_args.default.option(
|
|
3349
|
+
["r", "reportDir"],
|
|
3350
|
+
"Directory for generated Markdown reports",
|
|
3351
|
+
"data/ai/output"
|
|
3352
|
+
);
|
|
3353
|
+
import_args.default.option(["B", "reportFile"], "Explicit Markdown report file path", "");
|
|
3354
|
+
import_args.default.option(["j", "json"], "Print structured JSON summary", false);
|
|
3355
|
+
import_args.default.option(["O", "output"], "Write structured JSON summary to file", "");
|
|
3356
|
+
var flags = import_args.default.parse(process.argv);
|
|
3357
|
+
var createListIt = () => new ListIt({
|
|
3358
|
+
autoAlign: true,
|
|
3359
|
+
headerUnderline: true
|
|
3360
|
+
});
|
|
3361
|
+
var createTable = (headers, rows) => createListIt().setHeaderRow(headers).d(rows).toString();
|
|
3362
|
+
var formatRatio = (value) => value == null ? "n/a" : `${(value * 100).toFixed(1)}%`;
|
|
3363
|
+
var formatProfit = (value) => value == null ? "n/a" : value.toFixed(2);
|
|
3364
|
+
var formatNumber2 = (value) => value == null ? "n/a" : value.toFixed(2);
|
|
3365
|
+
var colorizeRatio = (value) => {
|
|
3366
|
+
const text = formatRatio(value);
|
|
3367
|
+
if (value == null) {
|
|
3368
|
+
return import_chalk.default.gray(text);
|
|
3369
|
+
}
|
|
3370
|
+
if (value >= 0.55) {
|
|
3371
|
+
return import_chalk.default.green(text);
|
|
3372
|
+
}
|
|
3373
|
+
if (value >= 0.45) {
|
|
3374
|
+
return import_chalk.default.yellow(text);
|
|
3375
|
+
}
|
|
3376
|
+
return import_chalk.default.red(text);
|
|
3377
|
+
};
|
|
3378
|
+
var colorizeProfit = (value) => {
|
|
3379
|
+
const text = formatProfit(value);
|
|
3380
|
+
if (value == null) {
|
|
3381
|
+
return import_chalk.default.gray(text);
|
|
3382
|
+
}
|
|
3383
|
+
if (value > 0) {
|
|
3384
|
+
return import_chalk.default.green(text);
|
|
3385
|
+
}
|
|
3386
|
+
if (value < 0) {
|
|
3387
|
+
return import_chalk.default.red(text);
|
|
3388
|
+
}
|
|
3389
|
+
return import_chalk.default.yellow(text);
|
|
3390
|
+
};
|
|
3391
|
+
var colorizeNumber = (value) => value == null ? import_chalk.default.gray("n/a") : import_chalk.default.cyan(formatNumber2(value));
|
|
3392
|
+
var toReportTimestamp = (timestamp) => new Date(timestamp).toISOString().replace(/\.\d{3}Z$/, "Z").replace(/[:]/g, "-");
|
|
3393
|
+
var markdownPlainTable = (headers, rows) => {
|
|
3394
|
+
const escapeCell = (value) => value.replace(/\|/g, "\\|");
|
|
3395
|
+
return [
|
|
3396
|
+
`| ${headers.map(escapeCell).join(" | ")} |`,
|
|
3397
|
+
`| ${headers.map(() => "---").join(" | ")} |`,
|
|
3398
|
+
...rows.map((row) => `| ${row.map(escapeCell).join(" | ")} |`)
|
|
3399
|
+
].join("\n");
|
|
3400
|
+
};
|
|
3401
|
+
var buildPendingMarkdownReport = ({
|
|
3402
|
+
generatedAt,
|
|
3403
|
+
strategy,
|
|
3404
|
+
filePaths,
|
|
3405
|
+
selectedRows,
|
|
3406
|
+
reportPath
|
|
3407
|
+
}) => [
|
|
3408
|
+
"# AI Pocket Search Report",
|
|
3409
|
+
"",
|
|
3410
|
+
"Status: running",
|
|
3411
|
+
"",
|
|
3412
|
+
`Generated at: ${new Date(generatedAt).toISOString()}`,
|
|
3413
|
+
"",
|
|
3414
|
+
markdownPlainTable(
|
|
3415
|
+
["Field", "Value"],
|
|
3416
|
+
[
|
|
3417
|
+
["strategy", strategy],
|
|
3418
|
+
["selected_rows", String(selectedRows)],
|
|
3419
|
+
["report", reportPath]
|
|
3420
|
+
]
|
|
3421
|
+
),
|
|
3422
|
+
"",
|
|
3423
|
+
"## Source Files",
|
|
3424
|
+
"",
|
|
3425
|
+
...filePaths.map((filePath) => `- \`${filePath}\``),
|
|
3426
|
+
"",
|
|
3427
|
+
"Final metrics and pockets will be written when the search finishes.",
|
|
3428
|
+
""
|
|
3429
|
+
].join("\n");
|
|
3430
|
+
var normalizeInt = (value, fallback) => {
|
|
3431
|
+
const parsed = Number(value);
|
|
3432
|
+
return Number.isFinite(parsed) ? Math.max(0, Math.trunc(parsed)) : fallback;
|
|
3433
|
+
};
|
|
3434
|
+
var normalizePositiveInt = (value, fallback) => {
|
|
3435
|
+
const parsed = Number(value);
|
|
3436
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.trunc(parsed) : fallback;
|
|
3437
|
+
};
|
|
3438
|
+
var normalizeNonNegativeNumber = (value, fallback) => {
|
|
3439
|
+
const parsed = Number(value);
|
|
3440
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
3441
|
+
};
|
|
3442
|
+
var normalizeRatio = (value, fallback) => {
|
|
3443
|
+
if (typeof value === "boolean") {
|
|
3444
|
+
return fallback;
|
|
3445
|
+
}
|
|
3446
|
+
const parsed = Number(value);
|
|
3447
|
+
if (!Number.isFinite(parsed)) {
|
|
3448
|
+
return fallback;
|
|
3449
|
+
}
|
|
3450
|
+
return Math.max(0, Math.min(0.9, parsed));
|
|
3451
|
+
};
|
|
3452
|
+
var normalizeFeatureProfile = (value) => {
|
|
3453
|
+
const normalized = String(value || "all").trim().toLowerCase();
|
|
3454
|
+
return normalized === "compact" ? "compact" : "all";
|
|
3455
|
+
};
|
|
3456
|
+
var normalizeQuality = (analysis) => {
|
|
3457
|
+
const quality = Number(analysis?.quality);
|
|
3458
|
+
return Number.isFinite(quality) ? Math.round(quality) : null;
|
|
3459
|
+
};
|
|
3460
|
+
var isAiApproval = (row, analysis, minQuality) => {
|
|
3461
|
+
const quality = normalizeQuality(analysis);
|
|
3462
|
+
return analysis.direction === row.direction && quality != null && quality >= minQuality;
|
|
3463
|
+
};
|
|
3464
|
+
var listMergedFiles = async (params) => {
|
|
3465
|
+
const { outDir, strategyName } = params;
|
|
3466
|
+
let entries = [];
|
|
3467
|
+
try {
|
|
3468
|
+
entries = await import_promises.default.readdir(outDir);
|
|
3469
|
+
} catch {
|
|
3470
|
+
return [];
|
|
3471
|
+
}
|
|
3472
|
+
const prefix = strategyName ? `ai-dataset-${(0, import_ai.toFileToken)(strategyName)}-merged-` : "ai-dataset-";
|
|
3473
|
+
return entries.filter((name) => name.startsWith(prefix)).filter((name) => {
|
|
3474
|
+
if (!name.endsWith(".jsonl") || !name.includes("-merged-")) {
|
|
3475
|
+
return false;
|
|
3476
|
+
}
|
|
3477
|
+
return /-merged-\d+\.jsonl$/.test(name) || /-merged-\d+-part\d+\.jsonl$/.test(name);
|
|
3478
|
+
}).sort().map((name) => import_path.default.join(outDir, name));
|
|
3479
|
+
};
|
|
3480
|
+
var deriveStrategyNameFromFile = (filePath) => {
|
|
3481
|
+
const match = import_path.default.basename(filePath).match(/^ai-dataset-(.+)-merged-\d+(?:-part\d+)?\.jsonl$/);
|
|
3482
|
+
return match?.[1] ? match[1] : "unknown";
|
|
3483
|
+
};
|
|
3484
|
+
var getMergedGroupId = (filePath) => {
|
|
3485
|
+
const match = import_path.default.basename(filePath).match(/^ai-dataset-(.+)-merged-(\d+)(?:-part(\d+))?\.jsonl$/);
|
|
3486
|
+
if (!match) {
|
|
3487
|
+
return null;
|
|
3488
|
+
}
|
|
3489
|
+
return {
|
|
3490
|
+
strategyToken: match[1],
|
|
3491
|
+
mergeId: match[2]
|
|
3492
|
+
};
|
|
3493
|
+
};
|
|
3494
|
+
var resolveMarkdownReportPath = ({
|
|
3495
|
+
explicitReportFile,
|
|
3496
|
+
reportDir,
|
|
3497
|
+
strategyName,
|
|
3498
|
+
filePath,
|
|
3499
|
+
scope,
|
|
3500
|
+
generatedAt
|
|
3501
|
+
}) => {
|
|
3502
|
+
if (explicitReportFile) {
|
|
3503
|
+
return explicitReportFile;
|
|
3504
|
+
}
|
|
3505
|
+
const groupId = getMergedGroupId(filePath);
|
|
3506
|
+
const strategyToken = groupId?.strategyToken ?? (0, import_ai.toFileToken)(strategyName);
|
|
3507
|
+
const mergeToken = groupId?.mergeId ? `merged-${groupId.mergeId}` : "merged";
|
|
3508
|
+
return import_path.default.join(
|
|
3509
|
+
reportDir,
|
|
3510
|
+
`ai-pocket-search-${strategyToken}-${mergeToken}-${scope}-${toReportTimestamp(generatedAt)}.md`
|
|
3511
|
+
);
|
|
3512
|
+
};
|
|
3513
|
+
var sortDatasetPartPaths = (filePaths) => [...filePaths].sort((left, right) => {
|
|
3514
|
+
const leftMatch = import_path.default.basename(left).match(/-part(\d+)\.jsonl$/);
|
|
3515
|
+
const rightMatch = import_path.default.basename(right).match(/-part(\d+)\.jsonl$/);
|
|
3516
|
+
const leftPart = leftMatch ? Number(leftMatch[1]) : 0;
|
|
3517
|
+
const rightPart = rightMatch ? Number(rightMatch[1]) : 0;
|
|
3518
|
+
return leftPart - rightPart || left.localeCompare(right);
|
|
3519
|
+
});
|
|
3520
|
+
var resolveMergedDatasetFiles = async ({
|
|
3521
|
+
outDir,
|
|
3522
|
+
strategyName,
|
|
3523
|
+
explicitFile
|
|
3524
|
+
}) => {
|
|
3525
|
+
const mergedFiles = await listMergedFiles({
|
|
3526
|
+
outDir,
|
|
3527
|
+
strategyName
|
|
3528
|
+
});
|
|
3529
|
+
if (!mergedFiles.length) {
|
|
3530
|
+
throw new Error(
|
|
3531
|
+
strategyName ? `No merged AI dataset found for strategy "${strategyName}" in ${outDir}. Run yarn ai-export first.` : `No merged AI dataset found in ${outDir}. Run yarn ai-export first.`
|
|
3532
|
+
);
|
|
3533
|
+
}
|
|
3534
|
+
const resolvedExplicitFile = explicitFile ? import_path.default.resolve(explicitFile) : null;
|
|
3535
|
+
if (resolvedExplicitFile) {
|
|
3536
|
+
const groupId = getMergedGroupId(resolvedExplicitFile);
|
|
3537
|
+
if (!groupId) {
|
|
3538
|
+
return [resolvedExplicitFile];
|
|
3539
|
+
}
|
|
3540
|
+
const groupedFiles = sortDatasetPartPaths(
|
|
3541
|
+
mergedFiles.filter((candidate) => {
|
|
3542
|
+
const candidateGroup = getMergedGroupId(candidate);
|
|
3543
|
+
return candidateGroup?.strategyToken === groupId.strategyToken && candidateGroup?.mergeId === groupId.mergeId;
|
|
3544
|
+
})
|
|
3545
|
+
);
|
|
3546
|
+
return groupedFiles.length ? groupedFiles : [resolvedExplicitFile];
|
|
3547
|
+
}
|
|
3548
|
+
const latestFile = mergedFiles[mergedFiles.length - 1];
|
|
3549
|
+
const latestGroupId = getMergedGroupId(latestFile);
|
|
3550
|
+
if (!latestGroupId) {
|
|
3551
|
+
return [latestFile];
|
|
3552
|
+
}
|
|
3553
|
+
return sortDatasetPartPaths(
|
|
3554
|
+
mergedFiles.filter((candidate) => {
|
|
3555
|
+
const candidateGroup = getMergedGroupId(candidate);
|
|
3556
|
+
return candidateGroup?.strategyToken === latestGroupId.strategyToken && candidateGroup?.mergeId === latestGroupId.mergeId;
|
|
3557
|
+
})
|
|
3558
|
+
);
|
|
3559
|
+
};
|
|
3560
|
+
var getDatasetRowTimestamp = (row) => {
|
|
3561
|
+
const timestamp = Number(row.timestamp);
|
|
3562
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
3563
|
+
};
|
|
3564
|
+
var findMaxSelectedTimestamp = async ({
|
|
3565
|
+
filePaths,
|
|
3566
|
+
recent,
|
|
3567
|
+
skip
|
|
3568
|
+
}) => {
|
|
3569
|
+
let maxTimestamp = null;
|
|
3570
|
+
await (0, import_ai.streamAiDatasetRows)({
|
|
3571
|
+
filePaths,
|
|
3572
|
+
limitFromEnd: recent,
|
|
3573
|
+
skipFromEnd: skip,
|
|
3574
|
+
onRow: async (row) => {
|
|
3575
|
+
const timestamp = getDatasetRowTimestamp(row);
|
|
3576
|
+
if (timestamp != null) {
|
|
3577
|
+
maxTimestamp = maxTimestamp == null ? timestamp : Math.max(maxTimestamp, timestamp);
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
});
|
|
3581
|
+
return maxTimestamp;
|
|
3582
|
+
};
|
|
3583
|
+
var getDeterministicModelCandidate = (signal) => {
|
|
3584
|
+
if (!signal) {
|
|
3585
|
+
return false;
|
|
3586
|
+
}
|
|
3587
|
+
const payload = (0, import_ai2.buildAiPayload)(signal);
|
|
3588
|
+
const gateContext = (0, import_ai2.getDeterministicAiGateContext)(payload);
|
|
3589
|
+
const structuralHardBlockReasons = Array.isArray(
|
|
3590
|
+
gateContext?.structuralHardBlockReasons
|
|
3591
|
+
) ? gateContext.structuralHardBlockReasons.filter(
|
|
3592
|
+
(reason) => typeof reason === "string" && reason.trim().length > 0
|
|
3593
|
+
) : [];
|
|
3594
|
+
if (structuralHardBlockReasons.length) {
|
|
3595
|
+
return false;
|
|
3596
|
+
}
|
|
3597
|
+
if (typeof gateContext?.approvalAllowedNow === "boolean") {
|
|
3598
|
+
return gateContext.approvalAllowedNow;
|
|
3599
|
+
}
|
|
3600
|
+
return true;
|
|
3601
|
+
};
|
|
3602
|
+
var resolveScopeRows = (rows, scope) => {
|
|
3603
|
+
if (scope === "approved") {
|
|
3604
|
+
return rows.filter((row) => row.aiApproved);
|
|
3605
|
+
}
|
|
3606
|
+
if (scope === "rejected") {
|
|
3607
|
+
return rows.filter((row) => !row.aiApproved);
|
|
3608
|
+
}
|
|
3609
|
+
if (scope === "candidates") {
|
|
3610
|
+
return rows.filter((row) => row.modelCandidate);
|
|
3611
|
+
}
|
|
3612
|
+
return rows;
|
|
3613
|
+
};
|
|
3614
|
+
var splitValidationRows = (rows, validationSplit) => {
|
|
3615
|
+
if (validationSplit <= 0 || rows.length < 2) {
|
|
3616
|
+
return {
|
|
3617
|
+
trainRows: rows,
|
|
3618
|
+
validationRows: []
|
|
3619
|
+
};
|
|
3620
|
+
}
|
|
3621
|
+
const sortedRows = [...rows].sort((left, right) => {
|
|
3622
|
+
const leftTimestamp = typeof left.timestamp === "number" && Number.isFinite(left.timestamp) ? left.timestamp : Number.POSITIVE_INFINITY;
|
|
3623
|
+
const rightTimestamp = typeof right.timestamp === "number" && Number.isFinite(right.timestamp) ? right.timestamp : Number.POSITIVE_INFINITY;
|
|
3624
|
+
return leftTimestamp - rightTimestamp;
|
|
3625
|
+
});
|
|
3626
|
+
const validationCount = Math.max(
|
|
3627
|
+
1,
|
|
3628
|
+
Math.min(
|
|
3629
|
+
sortedRows.length - 1,
|
|
3630
|
+
Math.floor(sortedRows.length * validationSplit)
|
|
3631
|
+
)
|
|
3632
|
+
);
|
|
3633
|
+
const splitIndex = sortedRows.length - validationCount;
|
|
3634
|
+
return {
|
|
3635
|
+
trainRows: sortedRows.slice(0, splitIndex),
|
|
3636
|
+
validationRows: sortedRows.slice(splitIndex)
|
|
3637
|
+
};
|
|
3638
|
+
};
|
|
3639
|
+
var printSection = (title, table) => {
|
|
3640
|
+
console.log(import_chalk.default.gray(`${title}:`));
|
|
3641
|
+
console.log(table);
|
|
3642
|
+
console.log("");
|
|
3643
|
+
};
|
|
3644
|
+
var buildSummaryRows = (summary) => [
|
|
3645
|
+
["rows", import_chalk.default.cyan(String(summary.support))],
|
|
3646
|
+
["win_rate", colorizeRatio(summary.winRate)],
|
|
3647
|
+
["total_profit", colorizeProfit(summary.totalProfit)],
|
|
3648
|
+
["gross_profit", colorizeProfit(summary.grossProfit)],
|
|
3649
|
+
["gross_loss", colorizeProfit(-summary.grossLoss)],
|
|
3650
|
+
["profit_factor", colorizeNumber(summary.profitFactor)],
|
|
3651
|
+
["max_drawdown", colorizeProfit(-summary.maxDrawdown)],
|
|
3652
|
+
[
|
|
3653
|
+
"max_drawdown_pct_of_gross_profit",
|
|
3654
|
+
colorizeRatio(summary.maxDrawdownPctOfGrossProfit)
|
|
3655
|
+
],
|
|
3656
|
+
[
|
|
3657
|
+
"max_drawdown_pct_of_total_profit",
|
|
3658
|
+
colorizeRatio(summary.maxDrawdownPctOfTotalProfit)
|
|
3659
|
+
],
|
|
3660
|
+
["max_consecutive_losses", import_chalk.default.red(String(summary.maxConsecutiveLosses))],
|
|
3661
|
+
["avg_trades_per_day", colorizeNumber(summary.avgTradesPerDay)],
|
|
3662
|
+
["avg_trades_per_week", colorizeNumber(summary.avgTradesPerWeek)],
|
|
3663
|
+
["avg_profit_per_day", colorizeProfit(summary.avgProfitPerDay)],
|
|
3664
|
+
["avg_profit_per_month", colorizeProfit(summary.avgProfitPerMonth)],
|
|
3665
|
+
["losing_months", import_chalk.default.yellow(String(summary.losingMonths))],
|
|
3666
|
+
[
|
|
3667
|
+
"worst_month",
|
|
3668
|
+
summary.worstMonth ? `${summary.worstMonth.month} ${formatProfit(summary.worstMonth.totalProfit)}` : import_chalk.default.gray("n/a")
|
|
3669
|
+
]
|
|
3670
|
+
];
|
|
3671
|
+
var buildPocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
3672
|
+
import_chalk.default.gray(String(index + 1)),
|
|
3673
|
+
import_chalk.default.cyan(String(pocket.summary.support)),
|
|
3674
|
+
colorizeRatio(pocket.summary.supportRatio),
|
|
3675
|
+
colorizeRatio(pocket.summary.winRate),
|
|
3676
|
+
colorizeNumber(pocket.summary.profitFactor),
|
|
3677
|
+
colorizeProfit(pocket.summary.totalProfit),
|
|
3678
|
+
colorizeProfit(-pocket.summary.maxDrawdown),
|
|
3679
|
+
pocket.validationSummary ? import_chalk.default.cyan(String(pocket.validationSummary.support)) : import_chalk.default.gray("n/a"),
|
|
3680
|
+
pocket.validationSummary ? colorizeRatio(pocket.validationSummary.winRate) : import_chalk.default.gray("n/a"),
|
|
3681
|
+
pocket.validationSummary ? colorizeNumber(pocket.validationSummary.profitFactor) : import_chalk.default.gray("n/a"),
|
|
3682
|
+
pocket.validationSummary ? colorizeProfit(pocket.validationSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
3683
|
+
colorizeNumber(pocket.summary.avgTradesPerDay),
|
|
3684
|
+
import_chalk.default.yellow(String(pocket.summary.losingMonths)),
|
|
3685
|
+
colorizeNumber(pocket.score),
|
|
3686
|
+
pocket.condition
|
|
3687
|
+
]);
|
|
3688
|
+
var buildQualityRows = (qualityThresholds) => qualityThresholds.map(({ label, summary }) => [
|
|
3689
|
+
import_chalk.default.magenta(label),
|
|
3690
|
+
import_chalk.default.cyan(String(summary.approved)),
|
|
3691
|
+
colorizeRatio(summary.approvedRisk.winRate),
|
|
3692
|
+
colorizeNumber(summary.approvedRisk.profitFactor),
|
|
3693
|
+
colorizeProfit(summary.approvedRisk.totalProfit),
|
|
3694
|
+
colorizeProfit(-summary.approvedRisk.maxDrawdown),
|
|
3695
|
+
colorizeNumber(summary.avgApprovedTradesPerDay),
|
|
3696
|
+
colorizeProfit(summary.avgProfitApprovedPerDay)
|
|
3697
|
+
]);
|
|
3698
|
+
var tickProgressBarTo = (bar, target, tokens) => {
|
|
3699
|
+
const current = Number(bar.curr ?? 0);
|
|
3700
|
+
const next = Math.max(current, Math.min(target, bar.total));
|
|
3701
|
+
const delta = next - current;
|
|
3702
|
+
if (delta > 0) {
|
|
3703
|
+
bar.tick(delta, tokens);
|
|
3704
|
+
}
|
|
3705
|
+
};
|
|
3706
|
+
var searchPhaseLabels = {
|
|
3707
|
+
features: "features",
|
|
3708
|
+
predicates: "preds",
|
|
3709
|
+
masks: "masks",
|
|
3710
|
+
combinations: "search"
|
|
3711
|
+
};
|
|
3712
|
+
var hasCliOption2 = (longName, shortName) => process.argv.some(
|
|
3713
|
+
(arg) => arg === `--${longName}` || arg.startsWith(`--${longName}=`) || (shortName ? arg === `-${shortName}` : false)
|
|
3714
|
+
);
|
|
3715
|
+
var main = async () => {
|
|
3716
|
+
const outDir = String(flags.outDir || "data/ai/export");
|
|
3717
|
+
const strategyName = String(flags.strategy || "").trim() || void 0;
|
|
3718
|
+
const explicitFile = String(flags.file || "").trim();
|
|
3719
|
+
const skip = normalizeInt(flags.skip, 0);
|
|
3720
|
+
const minQuality = normalizeInt(flags.minQuality, 4);
|
|
3721
|
+
const sinceInput = parseTimestampFilter(flags.since);
|
|
3722
|
+
const untilTimestamp = parseTimestampFilter(flags.until);
|
|
3723
|
+
const trailingPeriodMs = parseTrailingPeriodMs(flags.period);
|
|
3724
|
+
const periodLabel = String(flags.period || "").trim() || null;
|
|
3725
|
+
const hasDateFilter = trailingPeriodMs != null || sinceInput != null || untilTimestamp != null;
|
|
3726
|
+
const recent = resolveAiTrainRecentLimit({
|
|
3727
|
+
argv: process.argv,
|
|
3728
|
+
recentValue: flags.recent,
|
|
3729
|
+
hasDateFilter
|
|
3730
|
+
});
|
|
3731
|
+
const qualityThresholds = parseQualityThresholds(flags.qualityThresholds);
|
|
3732
|
+
const scope = String(flags.scope || "all").trim().toLowerCase();
|
|
3733
|
+
if (!["all", "approved", "rejected", "candidates"].includes(scope)) {
|
|
3734
|
+
throw new Error(
|
|
3735
|
+
`Unsupported --scope "${scope}". Use all, approved, rejected, or candidates.`
|
|
3736
|
+
);
|
|
3737
|
+
}
|
|
3738
|
+
const maxDepth = normalizePositiveInt(flags.maxDepth, 2);
|
|
3739
|
+
const minSupport = normalizePositiveInt(flags.minSupport, 20);
|
|
3740
|
+
const minProfitFactor = normalizeNonNegativeNumber(
|
|
3741
|
+
flags.minProfitFactor,
|
|
3742
|
+
1.2
|
|
3743
|
+
);
|
|
3744
|
+
const minWinRate = normalizeNonNegativeNumber(flags.minWinRate, 0);
|
|
3745
|
+
const minTotalProfit = Number.isFinite(Number(flags.minTotalProfit)) ? Number(flags.minTotalProfit) : 0;
|
|
3746
|
+
const maxAtomicPredicates = normalizePositiveInt(
|
|
3747
|
+
flags.maxAtomicPredicates,
|
|
3748
|
+
180
|
|
3749
|
+
);
|
|
3750
|
+
const maxCombinations = normalizePositiveInt(flags.maxCombinations, 6e4);
|
|
3751
|
+
const validationSplit = hasCliOption2("validationSplit", "V") ? normalizeRatio(flags.validationSplit, 0.25) : 0.25;
|
|
3752
|
+
const explicitMinValidationSupport = normalizeInt(
|
|
3753
|
+
flags.minValidationSupport,
|
|
3754
|
+
0
|
|
3755
|
+
);
|
|
3756
|
+
const dedupeEquivalentSelections = Boolean(flags.dedupeEquivalentSelections);
|
|
3757
|
+
const top = normalizePositiveInt(flags.top, 30);
|
|
3758
|
+
const includeSymbol = Boolean(flags.includeSymbol);
|
|
3759
|
+
const includeGateContext = Boolean(flags.includeGateContext);
|
|
3760
|
+
const featureProfile = normalizeFeatureProfile(flags.featureProfile);
|
|
3761
|
+
const jsonOutput = Boolean(flags.json);
|
|
3762
|
+
const outputPath = String(flags.output || "").trim();
|
|
3763
|
+
const reportDir = String(flags.reportDir || "data/ai/output").trim();
|
|
3764
|
+
const explicitReportFile = String(flags.reportFile || "").trim();
|
|
3765
|
+
const generatedAt = Date.now();
|
|
3766
|
+
await (0, import_ai2.ensureAiStrategyPluginsLoaded)();
|
|
3767
|
+
const filePaths = await resolveMergedDatasetFiles({
|
|
3768
|
+
outDir,
|
|
3769
|
+
strategyName,
|
|
3770
|
+
explicitFile
|
|
3771
|
+
});
|
|
3772
|
+
const { totalRows, selectedRows } = await (0, import_ai.countAiDatasetRows)({
|
|
3773
|
+
filePaths,
|
|
3774
|
+
limitFromEnd: recent,
|
|
3775
|
+
skipFromEnd: skip
|
|
3776
|
+
});
|
|
3777
|
+
const maxSelectedTimestamp = trailingPeriodMs == null ? null : await findMaxSelectedTimestamp({ filePaths, recent, skip });
|
|
3778
|
+
const sinceTimestamp = trailingPeriodMs != null && maxSelectedTimestamp != null ? maxSelectedTimestamp - trailingPeriodMs : sinceInput;
|
|
3779
|
+
if (!selectedRows) {
|
|
3780
|
+
console.log(
|
|
3781
|
+
import_chalk.default.yellow(
|
|
3782
|
+
`No AI prompt rows selected in ${filePaths.join(", ")} (recent=${recent || "all"}, skip=${skip})`
|
|
3783
|
+
)
|
|
3784
|
+
);
|
|
3785
|
+
process.exit(0);
|
|
3786
|
+
}
|
|
3787
|
+
let resolvedStrategyName = deriveStrategyNameFromFile(filePaths[0] || "");
|
|
3788
|
+
const reportPath = resolveMarkdownReportPath({
|
|
3789
|
+
explicitReportFile,
|
|
3790
|
+
reportDir,
|
|
3791
|
+
strategyName: resolvedStrategyName,
|
|
3792
|
+
filePath: filePaths[0] || "",
|
|
3793
|
+
scope,
|
|
3794
|
+
generatedAt
|
|
3795
|
+
});
|
|
3796
|
+
await import_promises.default.mkdir(import_path.default.dirname(import_path.default.resolve(reportPath)), {
|
|
3797
|
+
recursive: true
|
|
3798
|
+
});
|
|
3799
|
+
await import_promises.default.writeFile(
|
|
3800
|
+
reportPath,
|
|
3801
|
+
buildPendingMarkdownReport({
|
|
3802
|
+
generatedAt,
|
|
3803
|
+
strategy: resolvedStrategyName,
|
|
3804
|
+
filePaths,
|
|
3805
|
+
selectedRows,
|
|
3806
|
+
reportPath
|
|
3807
|
+
}),
|
|
3808
|
+
"utf8"
|
|
3809
|
+
);
|
|
3810
|
+
console.error(
|
|
3811
|
+
import_chalk.default.gray(`report: ${reportPath} (pending; final report after search)`)
|
|
3812
|
+
);
|
|
3813
|
+
let scanned = 0;
|
|
3814
|
+
let dateSkipped = 0;
|
|
3815
|
+
let failed = 0;
|
|
3816
|
+
const errors = [];
|
|
3817
|
+
const rows = [];
|
|
3818
|
+
const bar = new import_progress.default(
|
|
3819
|
+
"eval :current/:total [:bar] :percent :symbol :status",
|
|
3820
|
+
{
|
|
3821
|
+
total: selectedRows,
|
|
3822
|
+
width: 20,
|
|
3823
|
+
stream: process.stderr
|
|
3824
|
+
}
|
|
3825
|
+
);
|
|
3826
|
+
await (0, import_ai.streamAiDatasetRows)({
|
|
3827
|
+
filePaths,
|
|
3828
|
+
limitFromEnd: recent,
|
|
3829
|
+
skipFromEnd: skip,
|
|
3830
|
+
onRow: async (row) => {
|
|
3831
|
+
scanned += 1;
|
|
3832
|
+
if (resolvedStrategyName === "unknown" && typeof row.strategyName === "string" && row.strategyName.trim()) {
|
|
3833
|
+
resolvedStrategyName = row.strategyName.trim();
|
|
3834
|
+
}
|
|
3835
|
+
const timestamp = getDatasetRowTimestamp(row);
|
|
3836
|
+
if (sinceTimestamp != null && (timestamp == null || timestamp < sinceTimestamp) || untilTimestamp != null && (timestamp == null || timestamp > untilTimestamp)) {
|
|
3837
|
+
dateSkipped += 1;
|
|
3838
|
+
bar?.tick(1, {
|
|
3839
|
+
symbol: import_chalk.default.gray(row.symbol),
|
|
3840
|
+
status: import_chalk.default.gray("date-skip")
|
|
3841
|
+
});
|
|
3842
|
+
return;
|
|
3843
|
+
}
|
|
3844
|
+
try {
|
|
3845
|
+
const signal = extractSignalFromAiDatasetRow(row);
|
|
3846
|
+
const payload = (0, import_ai2.buildAiPayload)(signal);
|
|
3847
|
+
const gateContext = (0, import_ai2.getDeterministicAiGateContext)(payload);
|
|
3848
|
+
const analysis = await (0, import_ai2.runAiPromptLocal)(signal, { payload });
|
|
3849
|
+
const quality = normalizeQuality(analysis);
|
|
3850
|
+
const modelDirection = typeof analysis.direction === "string" && analysis.direction.trim() ? analysis.direction : null;
|
|
3851
|
+
const modelDirectionMatches = modelDirection === row.direction;
|
|
3852
|
+
const profit = Number(row.profit);
|
|
3853
|
+
rows.push({
|
|
3854
|
+
signalId: row.signalId,
|
|
3855
|
+
strategy: row.strategyName,
|
|
3856
|
+
symbol: row.symbol,
|
|
3857
|
+
direction: row.direction,
|
|
3858
|
+
timestamp,
|
|
3859
|
+
profit,
|
|
3860
|
+
profitableTrade: profit > 0,
|
|
3861
|
+
aiApproved: isAiApproval(row, analysis, minQuality),
|
|
3862
|
+
quality,
|
|
3863
|
+
modelDirectionMatches,
|
|
3864
|
+
modelCandidate: getDeterministicModelCandidate(signal),
|
|
3865
|
+
features: collectAiPocketFeatures({
|
|
3866
|
+
payload,
|
|
3867
|
+
gateContext,
|
|
3868
|
+
includeSymbol,
|
|
3869
|
+
includeGateContext,
|
|
3870
|
+
featureProfile
|
|
3871
|
+
})
|
|
3872
|
+
});
|
|
3873
|
+
bar?.tick(1, {
|
|
3874
|
+
symbol: import_chalk.default.gray(row.symbol),
|
|
3875
|
+
status: import_chalk.default.green("ok")
|
|
3876
|
+
});
|
|
3877
|
+
} catch (error) {
|
|
3878
|
+
failed += 1;
|
|
3879
|
+
if (errors.length < 5) {
|
|
3880
|
+
errors.push(
|
|
3881
|
+
`[${row.symbol}/${row.signalId}] ${error instanceof Error ? error.message : String(error)}`
|
|
3882
|
+
);
|
|
3883
|
+
}
|
|
3884
|
+
bar?.tick(1, {
|
|
3885
|
+
symbol: import_chalk.default.gray(row.symbol),
|
|
3886
|
+
status: import_chalk.default.yellow("error")
|
|
3887
|
+
});
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
});
|
|
3891
|
+
const scopeRows = resolveScopeRows(rows, scope);
|
|
3892
|
+
const { trainRows, validationRows } = splitValidationRows(
|
|
3893
|
+
scopeRows,
|
|
3894
|
+
validationSplit
|
|
3895
|
+
);
|
|
3896
|
+
const minValidationSupport = explicitMinValidationSupport > 0 ? explicitMinValidationSupport : validationRows.length ? Math.max(3, Math.ceil(minSupport * validationSplit * 0.5)) : 0;
|
|
3897
|
+
const currentGateSummary = summarizeAiTrainEvaluations(rows);
|
|
3898
|
+
const currentGateQualityThresholds = summarizeAiTrainEvaluationsByQualityThreshold(rows, qualityThresholds);
|
|
3899
|
+
let searchBar = null;
|
|
3900
|
+
let searchBarPhase = null;
|
|
3901
|
+
const search = searchAiPockets(trainRows, {
|
|
3902
|
+
minSupport,
|
|
3903
|
+
minProfitFactor,
|
|
3904
|
+
minTotalProfit,
|
|
3905
|
+
minWinRate,
|
|
3906
|
+
maxDepth,
|
|
3907
|
+
maxAtomicPredicates,
|
|
3908
|
+
maxCombinations,
|
|
3909
|
+
top,
|
|
3910
|
+
validationRows,
|
|
3911
|
+
minValidationSupport,
|
|
3912
|
+
dedupeEquivalentSelections,
|
|
3913
|
+
progressInterval: 250,
|
|
3914
|
+
onProgress: (progress) => {
|
|
3915
|
+
if (searchBar && searchBarPhase !== progress.phase) {
|
|
3916
|
+
tickProgressBarTo(searchBar, searchBar.total, {
|
|
3917
|
+
status: import_chalk.default.gray("done")
|
|
3918
|
+
});
|
|
3919
|
+
searchBar = null;
|
|
3920
|
+
}
|
|
3921
|
+
if (!searchBar) {
|
|
3922
|
+
searchBarPhase = progress.phase;
|
|
3923
|
+
const label = searchPhaseLabels[progress.phase].padEnd(8, " ");
|
|
3924
|
+
console.error(
|
|
3925
|
+
import_chalk.default.gray(
|
|
3926
|
+
`stage: ${searchPhaseLabels[progress.phase]} (${progress.total})`
|
|
3927
|
+
)
|
|
3928
|
+
);
|
|
3929
|
+
searchBar = new import_progress.default(
|
|
3930
|
+
`${label} :current/:total [:bar] :percent :status`,
|
|
3931
|
+
{
|
|
3932
|
+
total: Math.max(progress.total, 1),
|
|
3933
|
+
width: 20,
|
|
3934
|
+
stream: process.stderr
|
|
3935
|
+
}
|
|
3936
|
+
);
|
|
3937
|
+
}
|
|
3938
|
+
tickProgressBarTo(searchBar, progress.current, {
|
|
3939
|
+
status: progress.truncated ? import_chalk.default.yellow("truncated") : "running"
|
|
3940
|
+
});
|
|
3941
|
+
if (progress.done) {
|
|
3942
|
+
tickProgressBarTo(searchBar, searchBar.total, {
|
|
3943
|
+
status: progress.truncated ? import_chalk.default.yellow("truncated") : "done"
|
|
3944
|
+
});
|
|
3945
|
+
searchBar = null;
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
});
|
|
3949
|
+
const result = {
|
|
3950
|
+
generatedAt,
|
|
3951
|
+
run: {
|
|
3952
|
+
strategy: resolvedStrategyName,
|
|
3953
|
+
filePaths,
|
|
3954
|
+
sourceRows: totalRows,
|
|
3955
|
+
selectedRows,
|
|
3956
|
+
evaluatedRows: rows.length,
|
|
3957
|
+
scope,
|
|
3958
|
+
scopeRows: scopeRows.length,
|
|
3959
|
+
trainRows: trainRows.length,
|
|
3960
|
+
validationRows: validationRows.length,
|
|
3961
|
+
scanned,
|
|
3962
|
+
dateSkipped,
|
|
3963
|
+
failed,
|
|
3964
|
+
recent,
|
|
3965
|
+
skip,
|
|
3966
|
+
since: sinceTimestamp,
|
|
3967
|
+
until: untilTimestamp,
|
|
3968
|
+
period: periodLabel,
|
|
3969
|
+
minQuality,
|
|
3970
|
+
qualityThresholds,
|
|
3971
|
+
includeSymbol,
|
|
3972
|
+
includeGateContext,
|
|
3973
|
+
featureProfile,
|
|
3974
|
+
validationSplit,
|
|
3975
|
+
minValidationSupport,
|
|
3976
|
+
reportPath,
|
|
3977
|
+
search: {
|
|
3978
|
+
maxDepth,
|
|
3979
|
+
minSupport,
|
|
3980
|
+
minProfitFactor,
|
|
3981
|
+
minWinRate,
|
|
3982
|
+
minTotalProfit,
|
|
3983
|
+
maxAtomicPredicates,
|
|
3984
|
+
maxCombinations,
|
|
3985
|
+
validationSplit,
|
|
3986
|
+
minValidationSupport,
|
|
3987
|
+
dedupeEquivalentSelections,
|
|
3988
|
+
top
|
|
3989
|
+
}
|
|
3990
|
+
},
|
|
3991
|
+
currentGate: {
|
|
3992
|
+
summary: currentGateSummary,
|
|
3993
|
+
qualityThresholds: currentGateQualityThresholds
|
|
3994
|
+
},
|
|
3995
|
+
pocketSearch: search,
|
|
3996
|
+
errors
|
|
3997
|
+
};
|
|
3998
|
+
const markdownReport = buildAiPocketMarkdownReport(result);
|
|
3999
|
+
await import_promises.default.mkdir(import_path.default.dirname(import_path.default.resolve(reportPath)), {
|
|
4000
|
+
recursive: true
|
|
4001
|
+
});
|
|
4002
|
+
await import_promises.default.writeFile(reportPath, markdownReport, "utf8");
|
|
4003
|
+
if (outputPath) {
|
|
4004
|
+
await import_promises.default.mkdir(import_path.default.dirname(import_path.default.resolve(outputPath)), {
|
|
4005
|
+
recursive: true
|
|
4006
|
+
});
|
|
4007
|
+
await import_promises.default.writeFile(outputPath, `${JSON.stringify(result, null, 2)}
|
|
4008
|
+
`);
|
|
4009
|
+
}
|
|
4010
|
+
if (jsonOutput) {
|
|
4011
|
+
console.log(JSON.stringify(result));
|
|
4012
|
+
process.exit(failed === selectedRows ? 1 : 0);
|
|
4013
|
+
}
|
|
4014
|
+
console.log("");
|
|
4015
|
+
console.log(import_chalk.default.green("AI pocket search finished"));
|
|
4016
|
+
filePaths.forEach((filePath) => console.log(import_chalk.default.gray(filePath)));
|
|
4017
|
+
console.log("");
|
|
4018
|
+
printSection(
|
|
4019
|
+
"RUN",
|
|
4020
|
+
createTable(
|
|
4021
|
+
[import_chalk.default.gray("FIELD"), import_chalk.default.gray("VALUE")],
|
|
4022
|
+
[
|
|
4023
|
+
["strategy", import_chalk.default.yellow(resolvedStrategyName)],
|
|
4024
|
+
["selected", import_chalk.default.blue(String(selectedRows))],
|
|
4025
|
+
["evaluated", import_chalk.default.blue(String(rows.length))],
|
|
4026
|
+
["scope", import_chalk.default.yellow(scope)],
|
|
4027
|
+
["scope_rows", import_chalk.default.blue(String(scopeRows.length))],
|
|
4028
|
+
["train_rows", import_chalk.default.blue(String(trainRows.length))],
|
|
4029
|
+
["validation_rows", import_chalk.default.blue(String(validationRows.length))],
|
|
4030
|
+
["source_rows", import_chalk.default.blue(String(totalRows))],
|
|
4031
|
+
["date_skipped", import_chalk.default.blue(String(dateSkipped))],
|
|
4032
|
+
[
|
|
4033
|
+
"failed",
|
|
4034
|
+
failed > 0 ? import_chalk.default.yellow(String(failed)) : import_chalk.default.green("0")
|
|
4035
|
+
],
|
|
4036
|
+
["recent", import_chalk.default.blue(recent === 0 ? "all" : String(recent))],
|
|
4037
|
+
["skip", import_chalk.default.blue(String(skip))],
|
|
4038
|
+
[
|
|
4039
|
+
"since",
|
|
4040
|
+
sinceTimestamp == null ? import_chalk.default.gray("n/a") : import_chalk.default.gray(new Date(sinceTimestamp).toISOString())
|
|
4041
|
+
],
|
|
4042
|
+
[
|
|
4043
|
+
"until",
|
|
4044
|
+
untilTimestamp == null ? import_chalk.default.gray("n/a") : import_chalk.default.gray(new Date(untilTimestamp).toISOString())
|
|
4045
|
+
],
|
|
4046
|
+
[
|
|
4047
|
+
"period",
|
|
4048
|
+
periodLabel == null ? import_chalk.default.gray("n/a") : import_chalk.default.gray(periodLabel)
|
|
4049
|
+
],
|
|
4050
|
+
["min_quality", import_chalk.default.magenta(String(minQuality))],
|
|
4051
|
+
["max_depth", import_chalk.default.magenta(String(maxDepth))],
|
|
4052
|
+
["min_support", import_chalk.default.magenta(String(minSupport))],
|
|
4053
|
+
["max_atomic_predicates", import_chalk.default.magenta(String(maxAtomicPredicates))],
|
|
4054
|
+
["max_combinations", import_chalk.default.magenta(String(maxCombinations))],
|
|
4055
|
+
["validation_split", import_chalk.default.magenta(formatRatio(validationSplit))],
|
|
4056
|
+
["min_validation_support", import_chalk.default.magenta(String(minValidationSupport))],
|
|
4057
|
+
[
|
|
4058
|
+
"dedupe_equivalent",
|
|
4059
|
+
dedupeEquivalentSelections ? import_chalk.default.green("on") : import_chalk.default.gray("off")
|
|
4060
|
+
],
|
|
4061
|
+
[
|
|
4062
|
+
"include_symbol",
|
|
4063
|
+
includeSymbol ? import_chalk.default.yellow("on") : import_chalk.default.gray("off")
|
|
4064
|
+
],
|
|
4065
|
+
[
|
|
4066
|
+
"include_gate_context",
|
|
4067
|
+
includeGateContext ? import_chalk.default.yellow("on") : import_chalk.default.gray("off")
|
|
4068
|
+
],
|
|
4069
|
+
["feature_profile", import_chalk.default.magenta(featureProfile)],
|
|
4070
|
+
["report", import_chalk.default.gray(reportPath)],
|
|
4071
|
+
["output", outputPath ? import_chalk.default.gray(outputPath) : import_chalk.default.gray("off")]
|
|
4072
|
+
]
|
|
4073
|
+
)
|
|
4074
|
+
);
|
|
4075
|
+
printSection(
|
|
4076
|
+
"CURRENT GATE QN+ BASELINE",
|
|
4077
|
+
createTable(
|
|
4078
|
+
[
|
|
4079
|
+
import_chalk.default.gray("Q"),
|
|
4080
|
+
import_chalk.default.gray("APPROVED"),
|
|
4081
|
+
import_chalk.default.gray("WR"),
|
|
4082
|
+
import_chalk.default.gray("PF"),
|
|
4083
|
+
import_chalk.default.gray("PNL"),
|
|
4084
|
+
import_chalk.default.gray("MAX_DD"),
|
|
4085
|
+
import_chalk.default.gray("TRADES/D"),
|
|
4086
|
+
import_chalk.default.gray("PNL/D")
|
|
4087
|
+
],
|
|
4088
|
+
buildQualityRows(currentGateQualityThresholds)
|
|
4089
|
+
)
|
|
4090
|
+
);
|
|
4091
|
+
printSection(
|
|
4092
|
+
"TRAIN BASELINE",
|
|
4093
|
+
createTable(
|
|
4094
|
+
[import_chalk.default.gray("METRIC"), import_chalk.default.gray("VALUE")],
|
|
4095
|
+
buildSummaryRows(search.baseline)
|
|
4096
|
+
)
|
|
4097
|
+
);
|
|
4098
|
+
if (search.validationBaseline) {
|
|
4099
|
+
printSection(
|
|
4100
|
+
"VALIDATION BASELINE",
|
|
4101
|
+
createTable(
|
|
4102
|
+
[import_chalk.default.gray("METRIC"), import_chalk.default.gray("VALUE")],
|
|
4103
|
+
buildSummaryRows(search.validationBaseline)
|
|
4104
|
+
)
|
|
4105
|
+
);
|
|
4106
|
+
}
|
|
4107
|
+
printSection(
|
|
4108
|
+
"SEARCH STATS",
|
|
4109
|
+
createTable(
|
|
4110
|
+
[import_chalk.default.gray("FIELD"), import_chalk.default.gray("VALUE")],
|
|
4111
|
+
[
|
|
4112
|
+
["feature_keys", import_chalk.default.cyan(String(search.stats.featureKeys))],
|
|
4113
|
+
["predicates", import_chalk.default.cyan(String(search.stats.predicates))],
|
|
4114
|
+
["atomic_used", import_chalk.default.cyan(String(search.stats.atomicPredicatesUsed))],
|
|
4115
|
+
[
|
|
4116
|
+
"estimated_combinations",
|
|
4117
|
+
import_chalk.default.cyan(String(search.stats.estimatedCombinations))
|
|
4118
|
+
],
|
|
4119
|
+
[
|
|
4120
|
+
"combinations_evaluated",
|
|
4121
|
+
import_chalk.default.cyan(String(search.stats.combinationsEvaluated))
|
|
4122
|
+
],
|
|
4123
|
+
["validation_rows", import_chalk.default.cyan(String(search.stats.validationRows))],
|
|
4124
|
+
[
|
|
4125
|
+
"duplicate_pockets_skipped",
|
|
4126
|
+
import_chalk.default.cyan(String(search.stats.duplicatePocketsSkipped))
|
|
4127
|
+
],
|
|
4128
|
+
[
|
|
4129
|
+
"truncated",
|
|
4130
|
+
search.stats.truncated ? import_chalk.default.yellow("yes") : import_chalk.default.green("no")
|
|
4131
|
+
]
|
|
4132
|
+
]
|
|
4133
|
+
)
|
|
4134
|
+
);
|
|
4135
|
+
printSection(
|
|
4136
|
+
"TOP POSITIVE POCKETS",
|
|
4137
|
+
createTable(
|
|
4138
|
+
[
|
|
4139
|
+
import_chalk.default.gray("#"),
|
|
4140
|
+
import_chalk.default.gray("N"),
|
|
4141
|
+
import_chalk.default.gray("SUP"),
|
|
4142
|
+
import_chalk.default.gray("WR"),
|
|
4143
|
+
import_chalk.default.gray("PF"),
|
|
4144
|
+
import_chalk.default.gray("PNL"),
|
|
4145
|
+
import_chalk.default.gray("MAX_DD"),
|
|
4146
|
+
import_chalk.default.gray("VAL_N"),
|
|
4147
|
+
import_chalk.default.gray("VAL_WR"),
|
|
4148
|
+
import_chalk.default.gray("VAL_PF"),
|
|
4149
|
+
import_chalk.default.gray("VAL_PNL"),
|
|
4150
|
+
import_chalk.default.gray("TR/D"),
|
|
4151
|
+
import_chalk.default.gray("LOSS_M"),
|
|
4152
|
+
import_chalk.default.gray("SCORE"),
|
|
4153
|
+
import_chalk.default.gray("POCKET")
|
|
4154
|
+
],
|
|
4155
|
+
buildPocketRows(search.positivePockets)
|
|
4156
|
+
)
|
|
4157
|
+
);
|
|
4158
|
+
printSection(
|
|
4159
|
+
"TOP LOSS POCKETS",
|
|
4160
|
+
createTable(
|
|
4161
|
+
[
|
|
4162
|
+
import_chalk.default.gray("#"),
|
|
4163
|
+
import_chalk.default.gray("N"),
|
|
4164
|
+
import_chalk.default.gray("SUP"),
|
|
4165
|
+
import_chalk.default.gray("WR"),
|
|
4166
|
+
import_chalk.default.gray("PF"),
|
|
4167
|
+
import_chalk.default.gray("PNL"),
|
|
4168
|
+
import_chalk.default.gray("MAX_DD"),
|
|
4169
|
+
import_chalk.default.gray("VAL_N"),
|
|
4170
|
+
import_chalk.default.gray("VAL_WR"),
|
|
4171
|
+
import_chalk.default.gray("VAL_PF"),
|
|
4172
|
+
import_chalk.default.gray("VAL_PNL"),
|
|
4173
|
+
import_chalk.default.gray("TR/D"),
|
|
4174
|
+
import_chalk.default.gray("LOSS_M"),
|
|
4175
|
+
import_chalk.default.gray("SCORE"),
|
|
4176
|
+
import_chalk.default.gray("POCKET")
|
|
4177
|
+
],
|
|
4178
|
+
buildPocketRows(search.negativePockets)
|
|
4179
|
+
)
|
|
4180
|
+
);
|
|
4181
|
+
if (errors.length) {
|
|
4182
|
+
console.log(import_chalk.default.yellow("Errors:"));
|
|
4183
|
+
errors.forEach((error) => console.log(import_chalk.default.yellow(`- ${error}`)));
|
|
4184
|
+
}
|
|
4185
|
+
process.exit(failed === selectedRows ? 1 : 0);
|
|
4186
|
+
};
|
|
4187
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4188
|
+
0 && (module.exports = {
|
|
4189
|
+
main
|
|
4190
|
+
});
|