@tradejs/cli 1.0.8 → 1.0.10
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/dist/cli.js +29748 -13641
- 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 +1088 -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 +4403 -0
- package/dist/lib/paritySummary.js +101 -0
- package/dist/lib/runBot.js +1 -0
- package/dist/lib/runEnvironment.js +2254 -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 +187 -0
- package/dist/lib/runtimeSignalsStorage.js +185 -0
- 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 +28 -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 +4509 -818
- 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 +10 -0
- package/dist/scripts/infraDown.js +14 -4
- package/dist/scripts/infraInit.js +24 -4
- package/dist/scripts/infraUp.js +14 -4
- 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 +8824 -0
- package/dist/scripts/replayRunner.js +8827 -0
- package/dist/scripts/replayRuntimeEvidence.js +868 -0
- package/dist/scripts/researchAuto.js +289 -60
- package/dist/scripts/results.js +3 -3
- package/dist/scripts/runtimeEvidence.js +605 -0
- package/dist/scripts/runtimeParity.js +6360 -1004
- package/dist/scripts/serverHealth.js +588 -0
- package/dist/scripts/signals.js +5623 -486
- package/dist/scripts/signalsDaemon.js +6167 -0
- package/dist/scripts/signalsSummary.js +954 -312
- 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,4403 @@
|
|
|
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(...args) {
|
|
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
|
+
args[0] = createDebug.coerce(args[0]);
|
|
195
|
+
if (typeof args[0] !== "string") {
|
|
196
|
+
args.unshift("%O");
|
|
197
|
+
}
|
|
198
|
+
let index = 0;
|
|
199
|
+
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format2) => {
|
|
200
|
+
if (match === "%%") {
|
|
201
|
+
return "%";
|
|
202
|
+
}
|
|
203
|
+
index++;
|
|
204
|
+
const formatter = createDebug.formatters[format2];
|
|
205
|
+
if (typeof formatter === "function") {
|
|
206
|
+
const val = args[index];
|
|
207
|
+
match = formatter.call(self, val);
|
|
208
|
+
args.splice(index, 1);
|
|
209
|
+
index--;
|
|
210
|
+
}
|
|
211
|
+
return match;
|
|
212
|
+
});
|
|
213
|
+
createDebug.formatArgs.call(self, args);
|
|
214
|
+
const logFn = self.log || createDebug.log;
|
|
215
|
+
logFn.apply(self, args);
|
|
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(args) {
|
|
424
|
+
args[0] = (this.useColors ? "%c" : "") + this.namespace + (this.useColors ? " %c" : " ") + args[0] + (this.useColors ? "%c " : " ") + "+" + module2.exports.humanize(this.diff);
|
|
425
|
+
if (!this.useColors) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const c = "color: " + this.color;
|
|
429
|
+
args.splice(1, 0, c, "color: inherit");
|
|
430
|
+
let index = 0;
|
|
431
|
+
let lastC = 0;
|
|
432
|
+
args[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
|
+
args.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(args) {
|
|
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
|
+
args[0] = prefix + args[0].split("\n").join("\n" + prefix);
|
|
742
|
+
args.push(colorCode + "m+" + module2.exports.humanize(this.diff) + "\x1B[0m");
|
|
743
|
+
} else {
|
|
744
|
+
args[0] = getDate() + name + " " + args[0];
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
function getDate() {
|
|
748
|
+
if (exports2.inspectOpts.hideDate) {
|
|
749
|
+
return "";
|
|
750
|
+
}
|
|
751
|
+
return (/* @__PURE__ */ new Date()).toISOString() + " ";
|
|
752
|
+
}
|
|
753
|
+
function log(...args) {
|
|
754
|
+
return process.stderr.write(util.format(...args) + "\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/lib/marketContextPrepare.ts
|
|
1630
|
+
var marketContextPrepare_exports = {};
|
|
1631
|
+
__export(marketContextPrepare_exports, {
|
|
1632
|
+
prepareMarketContextForRun: () => prepareMarketContextForRun,
|
|
1633
|
+
shouldPrepareBinanceMarketContextForRun: () => shouldPrepareBinanceMarketContextForRun,
|
|
1634
|
+
shouldPrepareCoinMarketCapContextForRun: () => shouldPrepareCoinMarketCapContextForRun,
|
|
1635
|
+
shouldPrepareDerivativesContextForRun: () => shouldPrepareDerivativesContextForRun
|
|
1636
|
+
});
|
|
1637
|
+
module.exports = __toCommonJS(marketContextPrepare_exports);
|
|
1638
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
1639
|
+
|
|
1640
|
+
// src/lib/binanceMarketContextBackfill.ts
|
|
1641
|
+
var import_progress = __toESM(require("progress"));
|
|
1642
|
+
var import_chalk = __toESM(require("chalk"));
|
|
1643
|
+
var import_connectors = require("@tradejs/connectors");
|
|
1644
|
+
var import_connectors2 = require("@tradejs/node/connectors");
|
|
1645
|
+
var import_timescale = require("@tradejs/infra/timescale");
|
|
1646
|
+
|
|
1647
|
+
// src/lib/binanceMarketData.ts
|
|
1648
|
+
var MARKET_FEATURE_INTERVAL_MS = {
|
|
1649
|
+
"1m": 6e4,
|
|
1650
|
+
"5m": 3e5,
|
|
1651
|
+
"15m": 9e5,
|
|
1652
|
+
"1h": 36e5
|
|
1653
|
+
};
|
|
1654
|
+
var STABLE_QUOTE_SYMBOLS = /* @__PURE__ */ new Set([
|
|
1655
|
+
"USDCUSDT",
|
|
1656
|
+
"FDUSDUSDT",
|
|
1657
|
+
"TUSDUSDT",
|
|
1658
|
+
"BUSDUSDT",
|
|
1659
|
+
"USDPUSDT",
|
|
1660
|
+
"DAIUSDT"
|
|
1661
|
+
]);
|
|
1662
|
+
var safeDivide = (num, den) => Number.isFinite(num) && Number.isFinite(den) && den !== 0 ? num / den : null;
|
|
1663
|
+
var mean = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
|
|
1664
|
+
var standardDeviation = (values) => {
|
|
1665
|
+
const avg = mean(values);
|
|
1666
|
+
if (avg == null || values.length < 2) return null;
|
|
1667
|
+
const variance = values.reduce((sum, value) => sum + (value - avg) ** 2, 0) / values.length;
|
|
1668
|
+
return Math.sqrt(variance);
|
|
1669
|
+
};
|
|
1670
|
+
var buildPrefixSum = (values) => {
|
|
1671
|
+
const prefix = [0];
|
|
1672
|
+
for (const value of values) prefix.push(prefix[prefix.length - 1] + value);
|
|
1673
|
+
return prefix;
|
|
1674
|
+
};
|
|
1675
|
+
var sumPrefixRange = (prefix, startIndex, endIndexInclusive) => {
|
|
1676
|
+
if (endIndexInclusive < startIndex) return 0;
|
|
1677
|
+
const start = Math.max(0, startIndex);
|
|
1678
|
+
const end = Math.min(prefix.length - 2, endIndexInclusive);
|
|
1679
|
+
if (end < start) return 0;
|
|
1680
|
+
return prefix[end + 1] - prefix[start];
|
|
1681
|
+
};
|
|
1682
|
+
var windowReturn = (candles, index, lookbackBars) => {
|
|
1683
|
+
const previous = candles[index - lookbackBars];
|
|
1684
|
+
const current = candles[index];
|
|
1685
|
+
return previous && previous.close > 0 ? (current.close - previous.close) / previous.close : null;
|
|
1686
|
+
};
|
|
1687
|
+
var classifyBtcAltRegime = ({
|
|
1688
|
+
btcReturn24h,
|
|
1689
|
+
altBasketReturn24h,
|
|
1690
|
+
btcVsAltReturn24h
|
|
1691
|
+
}) => {
|
|
1692
|
+
if (btcReturn24h == null || altBasketReturn24h == null || btcVsAltReturn24h == null) {
|
|
1693
|
+
return "unknown";
|
|
1694
|
+
}
|
|
1695
|
+
if (btcReturn24h < -0.015 && altBasketReturn24h < -0.025) {
|
|
1696
|
+
return "risk_off";
|
|
1697
|
+
}
|
|
1698
|
+
if (btcReturn24h > 5e-3 && altBasketReturn24h > 5e-3 && altBasketReturn24h > btcReturn24h) {
|
|
1699
|
+
return "risk_on";
|
|
1700
|
+
}
|
|
1701
|
+
if (btcVsAltReturn24h > 5e-3) return "btc_lead";
|
|
1702
|
+
if (btcVsAltReturn24h < -5e-3) return "alt_lead";
|
|
1703
|
+
return "neutral";
|
|
1704
|
+
};
|
|
1705
|
+
var selectBreadthUniverseFromTickers = (tickers, limit) => tickers.filter(
|
|
1706
|
+
(ticker) => ticker.symbol.endsWith("USDT") && ticker.symbol !== "BTCUSDT" && !STABLE_QUOTE_SYMBOLS.has(ticker.symbol) && Number.isFinite(ticker.turnover24h) && ticker.turnover24h > 0
|
|
1707
|
+
).sort((a, b) => b.turnover24h - a.turnover24h).slice(0, Math.max(0, limit)).map((ticker) => ticker.symbol);
|
|
1708
|
+
var aggregateAggTradesToRows = ({
|
|
1709
|
+
symbol,
|
|
1710
|
+
interval,
|
|
1711
|
+
trades,
|
|
1712
|
+
source = "binance_agg_trades"
|
|
1713
|
+
}) => {
|
|
1714
|
+
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
1715
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1716
|
+
for (const trade of trades) {
|
|
1717
|
+
const bucketTs = Math.floor(trade.timestamp / intervalMs) * intervalMs;
|
|
1718
|
+
const row = buckets.get(bucketTs) ?? {
|
|
1719
|
+
symbol,
|
|
1720
|
+
interval,
|
|
1721
|
+
ts: new Date(bucketTs),
|
|
1722
|
+
trades: 0,
|
|
1723
|
+
buyBaseVolume: 0,
|
|
1724
|
+
sellBaseVolume: 0,
|
|
1725
|
+
buyQuoteVolume: 0,
|
|
1726
|
+
sellQuoteVolume: 0,
|
|
1727
|
+
netBaseDelta: 0,
|
|
1728
|
+
netQuoteDelta: 0,
|
|
1729
|
+
buyPressurePct: null,
|
|
1730
|
+
source
|
|
1731
|
+
};
|
|
1732
|
+
const quote = trade.price * trade.quantity;
|
|
1733
|
+
const isAggressiveSell = trade.isBuyerMaker;
|
|
1734
|
+
row.trades += 1;
|
|
1735
|
+
if (isAggressiveSell) {
|
|
1736
|
+
row.sellBaseVolume = (row.sellBaseVolume ?? 0) + trade.quantity;
|
|
1737
|
+
row.sellQuoteVolume = (row.sellQuoteVolume ?? 0) + quote;
|
|
1738
|
+
} else {
|
|
1739
|
+
row.buyBaseVolume = (row.buyBaseVolume ?? 0) + trade.quantity;
|
|
1740
|
+
row.buyQuoteVolume = (row.buyQuoteVolume ?? 0) + quote;
|
|
1741
|
+
}
|
|
1742
|
+
row.netBaseDelta = (row.buyBaseVolume ?? 0) - (row.sellBaseVolume ?? 0);
|
|
1743
|
+
row.netQuoteDelta = (row.buyQuoteVolume ?? 0) - (row.sellQuoteVolume ?? 0);
|
|
1744
|
+
row.buyPressurePct = safeDivide(
|
|
1745
|
+
row.buyBaseVolume ?? 0,
|
|
1746
|
+
(row.buyBaseVolume ?? 0) + (row.sellBaseVolume ?? 0)
|
|
1747
|
+
);
|
|
1748
|
+
buckets.set(bucketTs, row);
|
|
1749
|
+
}
|
|
1750
|
+
return [...buckets.values()].sort((a, b) => a.ts.getTime() - b.ts.getTime());
|
|
1751
|
+
};
|
|
1752
|
+
var buildKlineTradeFlowRows = ({
|
|
1753
|
+
symbol,
|
|
1754
|
+
interval,
|
|
1755
|
+
candles,
|
|
1756
|
+
source = "binance_klines"
|
|
1757
|
+
}) => candles.map((candle) => {
|
|
1758
|
+
const buyBaseVolume = candle.takerBuyBaseVolume;
|
|
1759
|
+
const buyQuoteVolume = candle.takerBuyQuoteVolume;
|
|
1760
|
+
if (buyBaseVolume == null || buyQuoteVolume == null || !Number.isFinite(buyBaseVolume) || !Number.isFinite(buyQuoteVolume)) {
|
|
1761
|
+
return null;
|
|
1762
|
+
}
|
|
1763
|
+
const sellBaseVolume = candle.takerSellBaseVolume != null && Number.isFinite(candle.takerSellBaseVolume) ? candle.takerSellBaseVolume : Math.max(0, candle.volume - buyBaseVolume);
|
|
1764
|
+
const sellQuoteVolume = candle.takerSellQuoteVolume != null && Number.isFinite(candle.takerSellQuoteVolume) ? candle.takerSellQuoteVolume : Math.max(0, candle.turnover - buyQuoteVolume);
|
|
1765
|
+
const trades = candle.trades != null && Number.isFinite(candle.trades) ? Math.max(0, Math.trunc(candle.trades)) : 0;
|
|
1766
|
+
return {
|
|
1767
|
+
symbol,
|
|
1768
|
+
interval,
|
|
1769
|
+
ts: new Date(candle.timestamp),
|
|
1770
|
+
trades,
|
|
1771
|
+
buyBaseVolume,
|
|
1772
|
+
sellBaseVolume,
|
|
1773
|
+
buyQuoteVolume,
|
|
1774
|
+
sellQuoteVolume,
|
|
1775
|
+
netBaseDelta: buyBaseVolume - sellBaseVolume,
|
|
1776
|
+
netQuoteDelta: buyQuoteVolume - sellQuoteVolume,
|
|
1777
|
+
buyPressurePct: safeDivide(
|
|
1778
|
+
buyBaseVolume,
|
|
1779
|
+
buyBaseVolume + sellBaseVolume
|
|
1780
|
+
),
|
|
1781
|
+
source
|
|
1782
|
+
};
|
|
1783
|
+
}).filter((row) => row != null);
|
|
1784
|
+
var buildMarketBreadthRows = ({
|
|
1785
|
+
universe,
|
|
1786
|
+
interval,
|
|
1787
|
+
candlesBySymbol,
|
|
1788
|
+
btcCandles,
|
|
1789
|
+
source = "binance_klines"
|
|
1790
|
+
}) => {
|
|
1791
|
+
const timestamps = /* @__PURE__ */ new Set();
|
|
1792
|
+
const indexedSymbols = Object.values(candlesBySymbol).map((candles) => ({
|
|
1793
|
+
candles,
|
|
1794
|
+
byTimestamp: new Map(
|
|
1795
|
+
candles.map((candle, index) => [candle.timestamp, index])
|
|
1796
|
+
),
|
|
1797
|
+
turnoverPrefix: buildPrefixSum(
|
|
1798
|
+
candles.map((candle) => Math.max(0, candle.turnover ?? 0))
|
|
1799
|
+
),
|
|
1800
|
+
closePrefix: buildPrefixSum(candles.map((candle) => candle.close))
|
|
1801
|
+
}));
|
|
1802
|
+
const btcIndexed = btcCandles ? {
|
|
1803
|
+
candles: btcCandles,
|
|
1804
|
+
byTimestamp: new Map(
|
|
1805
|
+
btcCandles.map((candle, index) => [candle.timestamp, index])
|
|
1806
|
+
),
|
|
1807
|
+
turnoverPrefix: buildPrefixSum(
|
|
1808
|
+
btcCandles.map((candle) => Math.max(0, candle.turnover ?? 0))
|
|
1809
|
+
)
|
|
1810
|
+
} : null;
|
|
1811
|
+
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
1812
|
+
const bars1h = Math.max(1, Math.round(36e5 / intervalMs));
|
|
1813
|
+
const bars4h = Math.max(1, Math.round(144e5 / intervalMs));
|
|
1814
|
+
const bars24h = Math.max(1, Math.round(864e5 / intervalMs));
|
|
1815
|
+
for (const candles of Object.values(candlesBySymbol)) {
|
|
1816
|
+
for (const candle of candles) timestamps.add(candle.timestamp);
|
|
1817
|
+
}
|
|
1818
|
+
return [...timestamps].sort((a, b) => a - b).map((timestamp) => {
|
|
1819
|
+
const returns = [];
|
|
1820
|
+
const weightedReturns = [];
|
|
1821
|
+
let advancers = 0;
|
|
1822
|
+
let decliners = 0;
|
|
1823
|
+
let unchanged = 0;
|
|
1824
|
+
let aboveMa20 = 0;
|
|
1825
|
+
let aboveMa20Eligible = 0;
|
|
1826
|
+
let aboveMa50 = 0;
|
|
1827
|
+
let aboveMa50Eligible = 0;
|
|
1828
|
+
const altReturns1h = [];
|
|
1829
|
+
const altReturns4h = [];
|
|
1830
|
+
const altReturns24h = [];
|
|
1831
|
+
let altTurnover1h = 0;
|
|
1832
|
+
let altTurnover24h = 0;
|
|
1833
|
+
let previousAltTurnover24h = 0;
|
|
1834
|
+
for (const indexed of indexedSymbols) {
|
|
1835
|
+
const { candles, byTimestamp, turnoverPrefix, closePrefix } = indexed;
|
|
1836
|
+
const index = byTimestamp.get(timestamp);
|
|
1837
|
+
if (index == null) continue;
|
|
1838
|
+
const candle = candles[index];
|
|
1839
|
+
const previous = candles[index - 1];
|
|
1840
|
+
const ret = previous && previous.close > 0 ? (candle.close - previous.close) / previous.close : 0;
|
|
1841
|
+
if (ret > 0) advancers += 1;
|
|
1842
|
+
else if (ret < 0) decliners += 1;
|
|
1843
|
+
else unchanged += 1;
|
|
1844
|
+
returns.push(ret);
|
|
1845
|
+
weightedReturns.push({
|
|
1846
|
+
value: ret,
|
|
1847
|
+
weight: Math.max(0, candle.turnover ?? 0)
|
|
1848
|
+
});
|
|
1849
|
+
const ma20Start = index - 19;
|
|
1850
|
+
if (ma20Start >= 0) {
|
|
1851
|
+
aboveMa20Eligible += 1;
|
|
1852
|
+
const ma20 = sumPrefixRange(closePrefix, ma20Start, index) / 20;
|
|
1853
|
+
if (candle.close > ma20) aboveMa20 += 1;
|
|
1854
|
+
}
|
|
1855
|
+
const ma50Start = index - 49;
|
|
1856
|
+
if (ma50Start >= 0) {
|
|
1857
|
+
aboveMa50Eligible += 1;
|
|
1858
|
+
const ma50 = sumPrefixRange(closePrefix, ma50Start, index) / 50;
|
|
1859
|
+
if (candle.close > ma50) aboveMa50 += 1;
|
|
1860
|
+
}
|
|
1861
|
+
const altReturn1h = windowReturn(candles, index, bars1h);
|
|
1862
|
+
const altReturn4h = windowReturn(candles, index, bars4h);
|
|
1863
|
+
const altReturn24h = windowReturn(candles, index, bars24h);
|
|
1864
|
+
if (altReturn1h != null) altReturns1h.push(altReturn1h);
|
|
1865
|
+
if (altReturn4h != null) altReturns4h.push(altReturn4h);
|
|
1866
|
+
if (altReturn24h != null) altReturns24h.push(altReturn24h);
|
|
1867
|
+
altTurnover1h += sumPrefixRange(
|
|
1868
|
+
turnoverPrefix,
|
|
1869
|
+
index - bars1h + 1,
|
|
1870
|
+
index
|
|
1871
|
+
);
|
|
1872
|
+
altTurnover24h += sumPrefixRange(
|
|
1873
|
+
turnoverPrefix,
|
|
1874
|
+
index - bars24h + 1,
|
|
1875
|
+
index
|
|
1876
|
+
);
|
|
1877
|
+
previousAltTurnover24h += sumPrefixRange(
|
|
1878
|
+
turnoverPrefix,
|
|
1879
|
+
index - bars24h * 2 + 1,
|
|
1880
|
+
index - bars24h
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
const weightSum = weightedReturns.reduce(
|
|
1884
|
+
(sum, item) => sum + item.weight,
|
|
1885
|
+
0
|
|
1886
|
+
);
|
|
1887
|
+
const volumeWeightedReturn = weightSum > 0 ? weightedReturns.reduce(
|
|
1888
|
+
(sum, item) => sum + item.value * item.weight,
|
|
1889
|
+
0
|
|
1890
|
+
) / weightSum : null;
|
|
1891
|
+
const btcIndex = btcIndexed?.byTimestamp.get(timestamp);
|
|
1892
|
+
const btcReturn1h = btcIndexed && btcIndex != null ? windowReturn(btcIndexed.candles, btcIndex, bars1h) : null;
|
|
1893
|
+
const btcReturn4h = btcIndexed && btcIndex != null ? windowReturn(btcIndexed.candles, btcIndex, bars4h) : null;
|
|
1894
|
+
const btcReturn24h = btcIndexed && btcIndex != null ? windowReturn(btcIndexed.candles, btcIndex, bars24h) : null;
|
|
1895
|
+
const btcTurnover1h = btcIndexed && btcIndex != null ? sumPrefixRange(
|
|
1896
|
+
btcIndexed.turnoverPrefix,
|
|
1897
|
+
btcIndex - bars1h + 1,
|
|
1898
|
+
btcIndex
|
|
1899
|
+
) : null;
|
|
1900
|
+
const btcTurnover24h = btcIndexed && btcIndex != null ? sumPrefixRange(
|
|
1901
|
+
btcIndexed.turnoverPrefix,
|
|
1902
|
+
btcIndex - bars24h + 1,
|
|
1903
|
+
btcIndex
|
|
1904
|
+
) : null;
|
|
1905
|
+
const previousBtcTurnover24h = btcIndexed && btcIndex != null ? sumPrefixRange(
|
|
1906
|
+
btcIndexed.turnoverPrefix,
|
|
1907
|
+
btcIndex - bars24h * 2 + 1,
|
|
1908
|
+
btcIndex - bars24h
|
|
1909
|
+
) : null;
|
|
1910
|
+
const altBasketReturn1h = mean(altReturns1h);
|
|
1911
|
+
const altBasketReturn4h = mean(altReturns4h);
|
|
1912
|
+
const altBasketReturn24h = mean(altReturns24h);
|
|
1913
|
+
const btcVsAltReturn1h = btcReturn1h == null || altBasketReturn1h == null ? null : btcReturn1h - altBasketReturn1h;
|
|
1914
|
+
const btcVsAltReturn4h = btcReturn4h == null || altBasketReturn4h == null ? null : btcReturn4h - altBasketReturn4h;
|
|
1915
|
+
const btcVsAltReturn24h = btcReturn24h == null || altBasketReturn24h == null ? null : btcReturn24h - altBasketReturn24h;
|
|
1916
|
+
const btcTurnoverShare1h = btcTurnover1h == null ? null : safeDivide(btcTurnover1h, btcTurnover1h + altTurnover1h);
|
|
1917
|
+
const btcTurnoverShare24h = btcTurnover24h == null ? null : safeDivide(btcTurnover24h, btcTurnover24h + altTurnover24h);
|
|
1918
|
+
const previousBtcTurnoverShare24h = previousBtcTurnover24h == null ? null : safeDivide(
|
|
1919
|
+
previousBtcTurnover24h,
|
|
1920
|
+
previousBtcTurnover24h + previousAltTurnover24h
|
|
1921
|
+
);
|
|
1922
|
+
const btcTurnoverShareChange24h = btcTurnoverShare24h == null || previousBtcTurnoverShare24h == null ? null : btcTurnoverShare24h - previousBtcTurnoverShare24h;
|
|
1923
|
+
return {
|
|
1924
|
+
universe,
|
|
1925
|
+
interval,
|
|
1926
|
+
ts: new Date(timestamp),
|
|
1927
|
+
symbolsCount: returns.length,
|
|
1928
|
+
advancers,
|
|
1929
|
+
decliners,
|
|
1930
|
+
unchanged,
|
|
1931
|
+
advanceDeclineRatio: safeDivide(advancers, decliners || 1),
|
|
1932
|
+
pctAboveMa20: safeDivide(aboveMa20, aboveMa20Eligible),
|
|
1933
|
+
pctAboveMa50: safeDivide(aboveMa50, aboveMa50Eligible),
|
|
1934
|
+
equalWeightedReturn: mean(returns),
|
|
1935
|
+
volumeWeightedReturn,
|
|
1936
|
+
dispersion: standardDeviation(returns),
|
|
1937
|
+
btcReturn1h,
|
|
1938
|
+
btcReturn4h,
|
|
1939
|
+
btcReturn24h,
|
|
1940
|
+
altBasketReturn1h,
|
|
1941
|
+
altBasketReturn4h,
|
|
1942
|
+
altBasketReturn24h,
|
|
1943
|
+
btcVsAltReturn1h,
|
|
1944
|
+
btcVsAltReturn4h,
|
|
1945
|
+
btcVsAltReturn24h,
|
|
1946
|
+
btcTurnoverShare1h,
|
|
1947
|
+
btcTurnoverShare24h,
|
|
1948
|
+
btcTurnoverShareChange24h,
|
|
1949
|
+
altVolToBtcVol24h: btcTurnover24h == null ? null : safeDivide(altTurnover24h, btcTurnover24h),
|
|
1950
|
+
altDispersion24h: standardDeviation(altReturns24h),
|
|
1951
|
+
btcAltRegime: classifyBtcAltRegime({
|
|
1952
|
+
btcReturn24h,
|
|
1953
|
+
altBasketReturn24h,
|
|
1954
|
+
btcVsAltReturn24h
|
|
1955
|
+
}),
|
|
1956
|
+
source
|
|
1957
|
+
};
|
|
1958
|
+
}).filter((row) => row.symbolsCount > 0);
|
|
1959
|
+
};
|
|
1960
|
+
|
|
1961
|
+
// src/lib/binanceMarketContextBackfill.ts
|
|
1962
|
+
var DAY_MS = 864e5;
|
|
1963
|
+
var sleep = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
|
|
1964
|
+
var asInt = (value, fallback) => {
|
|
1965
|
+
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
1966
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
1967
|
+
};
|
|
1968
|
+
var asFloat = (value, fallback) => {
|
|
1969
|
+
const parsed = Number.parseFloat(String(value ?? ""));
|
|
1970
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
1971
|
+
};
|
|
1972
|
+
var parseEnabledFlag = (value, defaultValue) => {
|
|
1973
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
1974
|
+
if (!normalized) return defaultValue;
|
|
1975
|
+
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
1976
|
+
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
|
1977
|
+
return defaultValue;
|
|
1978
|
+
};
|
|
1979
|
+
var uniqueSymbols = (symbols) => [
|
|
1980
|
+
...new Set(symbols.map((item) => item.trim().toUpperCase()).filter(Boolean))
|
|
1981
|
+
];
|
|
1982
|
+
var getReferenceSymbols = () => {
|
|
1983
|
+
const symbols = (process.env.BINANCE_MARKET_CONTEXT_REFERENCE_SYMBOLS || "BTCUSDT,ETHUSDT").split(",").map((item) => item.trim().toUpperCase()).filter(Boolean);
|
|
1984
|
+
return symbols.length ? [...new Set(symbols)] : ["BTCUSDT", "ETHUSDT"];
|
|
1985
|
+
};
|
|
1986
|
+
var intervalToMarketFeatureInterval = (interval) => {
|
|
1987
|
+
const normalized = String(interval).trim().toLowerCase();
|
|
1988
|
+
if (normalized === "1" || normalized === "1m") return "1m";
|
|
1989
|
+
if (normalized === "5" || normalized === "5m") return "5m";
|
|
1990
|
+
if (normalized === "60" || normalized === "1h") return "1h";
|
|
1991
|
+
return "15m";
|
|
1992
|
+
};
|
|
1993
|
+
var marketIntervalToConnectorInterval = (interval) => {
|
|
1994
|
+
if (interval === "1m") return "1";
|
|
1995
|
+
if (interval === "5m") return "5";
|
|
1996
|
+
if (interval === "1h") return "60";
|
|
1997
|
+
return "15";
|
|
1998
|
+
};
|
|
1999
|
+
var resolveBinanceMarketContextBackfillWindow = ({
|
|
2000
|
+
startMs,
|
|
2001
|
+
endMs,
|
|
2002
|
+
preloadStartMs
|
|
2003
|
+
}) => {
|
|
2004
|
+
const breadthLookbackDays = asFloat(
|
|
2005
|
+
process.env.BINANCE_MARKET_CONTEXT_BREADTH_BACKFILL_LOOKBACK_DAYS,
|
|
2006
|
+
3
|
|
2007
|
+
);
|
|
2008
|
+
const breadthWarmupStartMs = startMs - breadthLookbackDays * DAY_MS;
|
|
2009
|
+
return {
|
|
2010
|
+
breadthStartMs: preloadStartMs ?? breadthWarmupStartMs,
|
|
2011
|
+
tradeFlowStartMs: preloadStartMs ?? startMs,
|
|
2012
|
+
endMs
|
|
2013
|
+
};
|
|
2014
|
+
};
|
|
2015
|
+
var hasCoverage = ({
|
|
2016
|
+
coverage,
|
|
2017
|
+
startMs,
|
|
2018
|
+
endMs,
|
|
2019
|
+
intervalMs
|
|
2020
|
+
}) => {
|
|
2021
|
+
if (!coverage) return false;
|
|
2022
|
+
const expectedRows = Math.max(1, Math.floor((endMs - startMs) / intervalMs));
|
|
2023
|
+
return coverage.firstMs <= startMs + intervalMs && coverage.lastMs >= endMs - intervalMs && coverage.rows >= Math.floor(expectedRows * 0.9);
|
|
2024
|
+
};
|
|
2025
|
+
var buildBreadthBackfillChunks = ({
|
|
2026
|
+
startMs,
|
|
2027
|
+
endMs,
|
|
2028
|
+
intervalMs,
|
|
2029
|
+
chunkDays
|
|
2030
|
+
}) => {
|
|
2031
|
+
const chunkMs = Math.max(intervalMs, chunkDays * DAY_MS);
|
|
2032
|
+
const warmupBars = Math.max(50, Math.ceil(DAY_MS * 2 / intervalMs));
|
|
2033
|
+
const warmupMs = warmupBars * intervalMs;
|
|
2034
|
+
const chunks = [];
|
|
2035
|
+
let cursor = startMs;
|
|
2036
|
+
while (cursor <= endMs) {
|
|
2037
|
+
const chunkEndMs = Math.min(endMs, cursor + chunkMs - 1);
|
|
2038
|
+
chunks.push({
|
|
2039
|
+
startMs: cursor,
|
|
2040
|
+
endMs: chunkEndMs,
|
|
2041
|
+
fetchStartMs: Math.max(startMs, cursor - warmupMs)
|
|
2042
|
+
});
|
|
2043
|
+
cursor = chunkEndMs + 1;
|
|
2044
|
+
}
|
|
2045
|
+
return chunks;
|
|
2046
|
+
};
|
|
2047
|
+
var buildTradeFlowBackfillChunks = ({
|
|
2048
|
+
startMs,
|
|
2049
|
+
endMs,
|
|
2050
|
+
intervalMs,
|
|
2051
|
+
chunkDays
|
|
2052
|
+
}) => {
|
|
2053
|
+
const chunkMs = Math.max(intervalMs, chunkDays * DAY_MS);
|
|
2054
|
+
const chunks = [];
|
|
2055
|
+
let cursor = startMs;
|
|
2056
|
+
while (cursor <= endMs) {
|
|
2057
|
+
const chunkEndMs = Math.min(endMs, cursor + chunkMs - 1);
|
|
2058
|
+
chunks.push({ startMs: cursor, endMs: chunkEndMs });
|
|
2059
|
+
cursor = chunkEndMs + 1;
|
|
2060
|
+
}
|
|
2061
|
+
return chunks;
|
|
2062
|
+
};
|
|
2063
|
+
var filterMissingBreadthBackfillChunks = ({
|
|
2064
|
+
chunks,
|
|
2065
|
+
coverage,
|
|
2066
|
+
intervalMs
|
|
2067
|
+
}) => chunks.filter(
|
|
2068
|
+
(chunk) => !hasCoverage({
|
|
2069
|
+
coverage,
|
|
2070
|
+
startMs: chunk.startMs,
|
|
2071
|
+
endMs: chunk.endMs,
|
|
2072
|
+
intervalMs
|
|
2073
|
+
})
|
|
2074
|
+
);
|
|
2075
|
+
var fetchAggTradesForWindow = async ({
|
|
2076
|
+
connector,
|
|
2077
|
+
symbol,
|
|
2078
|
+
fromMs,
|
|
2079
|
+
toMs,
|
|
2080
|
+
batchMinutes,
|
|
2081
|
+
requestDelayMs
|
|
2082
|
+
}) => {
|
|
2083
|
+
if (!connector.getAggTrades) return [];
|
|
2084
|
+
const rows = [];
|
|
2085
|
+
const batchMs = Math.max(1, batchMinutes) * 6e4;
|
|
2086
|
+
let cursor = fromMs;
|
|
2087
|
+
while (cursor <= toMs) {
|
|
2088
|
+
const endTime = Math.min(toMs, cursor + batchMs - 1);
|
|
2089
|
+
let pageCursor = cursor;
|
|
2090
|
+
while (pageCursor <= endTime) {
|
|
2091
|
+
const page = await connector.getAggTrades({
|
|
2092
|
+
symbol,
|
|
2093
|
+
startTime: pageCursor,
|
|
2094
|
+
endTime,
|
|
2095
|
+
limit: 1e3
|
|
2096
|
+
});
|
|
2097
|
+
if (!page.length) break;
|
|
2098
|
+
rows.push(...page);
|
|
2099
|
+
const lastTs = page[page.length - 1]?.timestamp;
|
|
2100
|
+
if (page.length < 1e3 || !Number.isFinite(lastTs)) break;
|
|
2101
|
+
const nextCursor = Math.max(pageCursor + 1, Number(lastTs) + 1);
|
|
2102
|
+
if (nextCursor > endTime) break;
|
|
2103
|
+
pageCursor = nextCursor;
|
|
2104
|
+
await sleep(requestDelayMs);
|
|
2105
|
+
}
|
|
2106
|
+
cursor = endTime + 1;
|
|
2107
|
+
await sleep(requestDelayMs);
|
|
2108
|
+
}
|
|
2109
|
+
return rows;
|
|
2110
|
+
};
|
|
2111
|
+
var getBinanceConnector = async ({
|
|
2112
|
+
projectRoot,
|
|
2113
|
+
userName
|
|
2114
|
+
}) => {
|
|
2115
|
+
const creator = await (0, import_connectors2.getConnectorCreatorByName)(
|
|
2116
|
+
import_connectors.ConnectorNames.Binance,
|
|
2117
|
+
projectRoot
|
|
2118
|
+
);
|
|
2119
|
+
if (!creator) {
|
|
2120
|
+
throw new Error(
|
|
2121
|
+
"Binance connector is required for market context backfill"
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
return creator({ userName });
|
|
2125
|
+
};
|
|
2126
|
+
var shouldBackfillBinanceMarketContextForBacktest = ({
|
|
2127
|
+
aiEnabled,
|
|
2128
|
+
cacheOnly,
|
|
2129
|
+
mlEnabled
|
|
2130
|
+
}) => parseEnabledFlag(
|
|
2131
|
+
process.env.BINANCE_MARKET_CONTEXT_BACKFILL_ENABLED,
|
|
2132
|
+
(aiEnabled || mlEnabled) && !cacheOnly
|
|
2133
|
+
);
|
|
2134
|
+
var shouldBackfillBinanceMarketContextForSignals = ({
|
|
2135
|
+
cacheOnly
|
|
2136
|
+
}) => parseEnabledFlag(
|
|
2137
|
+
process.env.BINANCE_MARKET_CONTEXT_BACKFILL_ENABLED,
|
|
2138
|
+
!cacheOnly
|
|
2139
|
+
);
|
|
2140
|
+
var shouldBackfillBinanceMarketContextForReplay = ({
|
|
2141
|
+
cacheOnly
|
|
2142
|
+
}) => parseEnabledFlag(
|
|
2143
|
+
process.env.BINANCE_MARKET_CONTEXT_BACKFILL_ENABLED,
|
|
2144
|
+
!cacheOnly
|
|
2145
|
+
);
|
|
2146
|
+
var skippedBackfillResult = () => ({
|
|
2147
|
+
skipped: true,
|
|
2148
|
+
tradeFlowRows: 0,
|
|
2149
|
+
depthRows: 0,
|
|
2150
|
+
breadthRows: 0,
|
|
2151
|
+
skippedSymbols: 0
|
|
2152
|
+
});
|
|
2153
|
+
var backfillBinanceMarketContext = async (params, enabled) => {
|
|
2154
|
+
const symbols = uniqueSymbols(params.symbols);
|
|
2155
|
+
if (!enabled || !symbols.length) {
|
|
2156
|
+
return skippedBackfillResult();
|
|
2157
|
+
}
|
|
2158
|
+
const interval = intervalToMarketFeatureInterval(params.interval);
|
|
2159
|
+
const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
|
|
2160
|
+
const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
|
|
2161
|
+
if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
|
|
2162
|
+
return skippedBackfillResult();
|
|
2163
|
+
}
|
|
2164
|
+
await (0, import_timescale.waitForDbReady)();
|
|
2165
|
+
const connector = await getBinanceConnector({
|
|
2166
|
+
projectRoot: params.projectRoot,
|
|
2167
|
+
userName: params.userName
|
|
2168
|
+
});
|
|
2169
|
+
const includeTradeFlow = parseEnabledFlag(
|
|
2170
|
+
process.env.BINANCE_MARKET_CONTEXT_BACKFILL_TRADE_FLOW,
|
|
2171
|
+
true
|
|
2172
|
+
);
|
|
2173
|
+
const includeBreadth = parseEnabledFlag(
|
|
2174
|
+
process.env.BINANCE_MARKET_CONTEXT_BACKFILL_BREADTH,
|
|
2175
|
+
true
|
|
2176
|
+
);
|
|
2177
|
+
const requestDelayMs = asInt(
|
|
2178
|
+
process.env.BINANCE_MARKET_CONTEXT_BACKFILL_REQUEST_DELAY_MS,
|
|
2179
|
+
75
|
|
2180
|
+
);
|
|
2181
|
+
const batchMinutes = asInt(
|
|
2182
|
+
process.env.BINANCE_MARKET_CONTEXT_BACKFILL_BATCH_MINUTES,
|
|
2183
|
+
60
|
|
2184
|
+
);
|
|
2185
|
+
const symbolLimit = asInt(
|
|
2186
|
+
process.env.BINANCE_MARKET_CONTEXT_TRADE_FLOW_SYMBOL_LIMIT,
|
|
2187
|
+
2
|
|
2188
|
+
);
|
|
2189
|
+
const breadthLimit = asInt(
|
|
2190
|
+
process.env.BINANCE_MARKET_CONTEXT_BREADTH_LIMIT,
|
|
2191
|
+
30
|
|
2192
|
+
);
|
|
2193
|
+
const breadthChunkDays = asFloat(
|
|
2194
|
+
process.env.BINANCE_MARKET_CONTEXT_BREADTH_CHUNK_DAYS,
|
|
2195
|
+
30
|
|
2196
|
+
);
|
|
2197
|
+
const tradeFlowChunkDays = asFloat(
|
|
2198
|
+
process.env.BINANCE_MARKET_CONTEXT_TRADE_FLOW_CHUNK_DAYS,
|
|
2199
|
+
30
|
|
2200
|
+
);
|
|
2201
|
+
const tradeFlowSource = String(
|
|
2202
|
+
process.env.BINANCE_MARKET_CONTEXT_TRADE_FLOW_SOURCE || "klines"
|
|
2203
|
+
).trim().toLowerCase();
|
|
2204
|
+
const referenceSymbols = getReferenceSymbols().slice(0, symbolLimit);
|
|
2205
|
+
const skippedSymbols = Math.max(0, symbols.length - referenceSymbols.length);
|
|
2206
|
+
let tradeFlowRows = 0;
|
|
2207
|
+
let breadthRows = 0;
|
|
2208
|
+
console.log(
|
|
2209
|
+
import_chalk.default.cyan(
|
|
2210
|
+
`binance market context backfill: requestedSymbols=${symbols.length}, referenceSymbols=${referenceSymbols.length}, interval=${interval}, tradeFlowWindow=${new Date(tradeFlowStartMs).toISOString()}..${new Date(endMs).toISOString()}, breadthWindow=${new Date(breadthStartMs).toISOString()}..${new Date(endMs).toISOString()}`
|
|
2211
|
+
)
|
|
2212
|
+
);
|
|
2213
|
+
if (includeTradeFlow && referenceSymbols.length) {
|
|
2214
|
+
const coverage = await (0, import_timescale.getMarketTradeFlowCoverage)({
|
|
2215
|
+
symbols: referenceSymbols,
|
|
2216
|
+
interval,
|
|
2217
|
+
startMs: tradeFlowStartMs,
|
|
2218
|
+
endMs
|
|
2219
|
+
});
|
|
2220
|
+
const missingSymbols = referenceSymbols.filter(
|
|
2221
|
+
(symbol) => !hasCoverage({
|
|
2222
|
+
coverage: coverage.get(symbol),
|
|
2223
|
+
startMs: tradeFlowStartMs,
|
|
2224
|
+
endMs,
|
|
2225
|
+
intervalMs
|
|
2226
|
+
})
|
|
2227
|
+
);
|
|
2228
|
+
const bar = new import_progress.default(
|
|
2229
|
+
"tradeFlow :current/:total [:bar][:percent] :etas(s) rows=:rows skip=:skip :symbol",
|
|
2230
|
+
{
|
|
2231
|
+
total: Math.max(1, missingSymbols.length),
|
|
2232
|
+
width: 24
|
|
2233
|
+
}
|
|
2234
|
+
);
|
|
2235
|
+
if (!missingSymbols.length) {
|
|
2236
|
+
bar.tick(1, { rows: 0, skip: referenceSymbols.length, symbol: "cached" });
|
|
2237
|
+
}
|
|
2238
|
+
const connectorInterval = marketIntervalToConnectorInterval(interval);
|
|
2239
|
+
const chunks = buildTradeFlowBackfillChunks({
|
|
2240
|
+
startMs: tradeFlowStartMs,
|
|
2241
|
+
endMs,
|
|
2242
|
+
intervalMs,
|
|
2243
|
+
chunkDays: tradeFlowChunkDays
|
|
2244
|
+
});
|
|
2245
|
+
const chunkBar = missingSymbols.length ? new import_progress.default(
|
|
2246
|
+
"tradeFlow chunks :current/:total [:bar][:percent] :etas(s) rows=:rows skip=:skip chunk=:chunk :symbol",
|
|
2247
|
+
{
|
|
2248
|
+
total: Math.max(1, chunks.length * missingSymbols.length),
|
|
2249
|
+
width: 24
|
|
2250
|
+
}
|
|
2251
|
+
) : null;
|
|
2252
|
+
let skippedTradeFlowChunks = 0;
|
|
2253
|
+
for (const symbol of missingSymbols) {
|
|
2254
|
+
const symbolCoverage = coverage.get(symbol);
|
|
2255
|
+
for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex += 1) {
|
|
2256
|
+
const chunk = chunks[chunkIndex];
|
|
2257
|
+
if (hasCoverage({
|
|
2258
|
+
coverage: symbolCoverage,
|
|
2259
|
+
startMs: chunk.startMs,
|
|
2260
|
+
endMs: chunk.endMs,
|
|
2261
|
+
intervalMs
|
|
2262
|
+
})) {
|
|
2263
|
+
skippedTradeFlowChunks += 1;
|
|
2264
|
+
chunkBar?.tick(1, {
|
|
2265
|
+
rows: tradeFlowRows,
|
|
2266
|
+
skip: skippedTradeFlowChunks,
|
|
2267
|
+
chunk: `${chunkIndex + 1}/${chunks.length}`,
|
|
2268
|
+
symbol
|
|
2269
|
+
});
|
|
2270
|
+
continue;
|
|
2271
|
+
}
|
|
2272
|
+
const rows = tradeFlowSource === "agg_trades" ? aggregateAggTradesToRows({
|
|
2273
|
+
symbol,
|
|
2274
|
+
interval,
|
|
2275
|
+
trades: await fetchAggTradesForWindow({
|
|
2276
|
+
connector,
|
|
2277
|
+
symbol,
|
|
2278
|
+
fromMs: chunk.startMs,
|
|
2279
|
+
toMs: chunk.endMs,
|
|
2280
|
+
batchMinutes,
|
|
2281
|
+
requestDelayMs
|
|
2282
|
+
})
|
|
2283
|
+
}) : buildKlineTradeFlowRows({
|
|
2284
|
+
symbol,
|
|
2285
|
+
interval,
|
|
2286
|
+
candles: await connector.kline({
|
|
2287
|
+
symbol,
|
|
2288
|
+
interval: connectorInterval,
|
|
2289
|
+
start: chunk.startMs,
|
|
2290
|
+
end: chunk.endMs,
|
|
2291
|
+
silent: true
|
|
2292
|
+
})
|
|
2293
|
+
});
|
|
2294
|
+
const boundedRows = rows.filter((row) => {
|
|
2295
|
+
const ts = row.ts.getTime();
|
|
2296
|
+
return ts >= chunk.startMs && ts <= chunk.endMs;
|
|
2297
|
+
});
|
|
2298
|
+
await (0, import_timescale.upsertMarketTradeFlowRows)(boundedRows);
|
|
2299
|
+
tradeFlowRows += boundedRows.length;
|
|
2300
|
+
chunkBar?.tick(1, {
|
|
2301
|
+
rows: tradeFlowRows,
|
|
2302
|
+
skip: skippedTradeFlowChunks,
|
|
2303
|
+
chunk: `${chunkIndex + 1}/${chunks.length}`,
|
|
2304
|
+
symbol
|
|
2305
|
+
});
|
|
2306
|
+
}
|
|
2307
|
+
bar.tick(1, {
|
|
2308
|
+
rows: tradeFlowRows,
|
|
2309
|
+
skip: referenceSymbols.length - missingSymbols.length + skippedSymbols,
|
|
2310
|
+
symbol
|
|
2311
|
+
});
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
if (includeBreadth) {
|
|
2315
|
+
const tickers = await connector.getTickers();
|
|
2316
|
+
const breadthSymbols = selectBreadthUniverseFromTickers(
|
|
2317
|
+
tickers,
|
|
2318
|
+
breadthLimit
|
|
2319
|
+
);
|
|
2320
|
+
const universe = `binance_top${breadthSymbols.length}_usdt`;
|
|
2321
|
+
const coverage = await (0, import_timescale.getMarketBreadthCoverage)({
|
|
2322
|
+
universe,
|
|
2323
|
+
interval,
|
|
2324
|
+
startMs: breadthStartMs,
|
|
2325
|
+
endMs
|
|
2326
|
+
});
|
|
2327
|
+
const hasBtcAltMetrics = (coverage?.btcAltMetricsRows ?? 0) >= Math.floor(Math.max(1, coverage?.rows ?? 0) * 0.9);
|
|
2328
|
+
if (!hasCoverage({
|
|
2329
|
+
coverage,
|
|
2330
|
+
startMs: breadthStartMs,
|
|
2331
|
+
endMs,
|
|
2332
|
+
intervalMs
|
|
2333
|
+
}) || !hasBtcAltMetrics) {
|
|
2334
|
+
const connectorInterval = marketIntervalToConnectorInterval(interval);
|
|
2335
|
+
const chunks = buildBreadthBackfillChunks({
|
|
2336
|
+
startMs: breadthStartMs,
|
|
2337
|
+
endMs,
|
|
2338
|
+
intervalMs,
|
|
2339
|
+
chunkDays: breadthChunkDays
|
|
2340
|
+
});
|
|
2341
|
+
const missingChunks = filterMissingBreadthBackfillChunks({
|
|
2342
|
+
chunks,
|
|
2343
|
+
coverage,
|
|
2344
|
+
intervalMs
|
|
2345
|
+
});
|
|
2346
|
+
const bar = new import_progress.default(
|
|
2347
|
+
"breadth :current/:total [:bar][:percent] :etas(s) candles=:candles skip=:skip chunk=:chunk :symbol",
|
|
2348
|
+
{
|
|
2349
|
+
total: Math.max(1, missingChunks.length * breadthSymbols.length),
|
|
2350
|
+
width: 24
|
|
2351
|
+
}
|
|
2352
|
+
);
|
|
2353
|
+
let candlesRead = 0;
|
|
2354
|
+
let skippedBreadthChunks = chunks.length - missingChunks.length;
|
|
2355
|
+
if (!missingChunks.length) {
|
|
2356
|
+
bar.tick(1, {
|
|
2357
|
+
candles: 0,
|
|
2358
|
+
skip: skippedBreadthChunks,
|
|
2359
|
+
chunk: "cached",
|
|
2360
|
+
symbol: universe
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2363
|
+
for (let chunkIndex = 0; chunkIndex < missingChunks.length; chunkIndex += 1) {
|
|
2364
|
+
const chunk = missingChunks[chunkIndex];
|
|
2365
|
+
const originalChunkIndex = chunks.findIndex(
|
|
2366
|
+
(item) => item.startMs === chunk.startMs && item.endMs === chunk.endMs
|
|
2367
|
+
);
|
|
2368
|
+
const candlesBySymbol = {};
|
|
2369
|
+
for (const symbol of breadthSymbols) {
|
|
2370
|
+
const candles = await connector.kline({
|
|
2371
|
+
symbol,
|
|
2372
|
+
interval: connectorInterval,
|
|
2373
|
+
start: chunk.fetchStartMs,
|
|
2374
|
+
end: chunk.endMs,
|
|
2375
|
+
silent: true
|
|
2376
|
+
});
|
|
2377
|
+
candlesBySymbol[symbol] = candles;
|
|
2378
|
+
candlesRead += candles.length;
|
|
2379
|
+
bar.tick(1, {
|
|
2380
|
+
candles: candlesRead,
|
|
2381
|
+
skip: skippedBreadthChunks,
|
|
2382
|
+
chunk: `${originalChunkIndex + 1}/${chunks.length}`,
|
|
2383
|
+
symbol
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
const btcCandles = await connector.kline({
|
|
2387
|
+
symbol: "BTCUSDT",
|
|
2388
|
+
interval: connectorInterval,
|
|
2389
|
+
start: chunk.fetchStartMs,
|
|
2390
|
+
end: chunk.endMs,
|
|
2391
|
+
silent: true
|
|
2392
|
+
});
|
|
2393
|
+
const rows = buildMarketBreadthRows({
|
|
2394
|
+
universe,
|
|
2395
|
+
interval,
|
|
2396
|
+
candlesBySymbol,
|
|
2397
|
+
btcCandles
|
|
2398
|
+
}).filter((row) => {
|
|
2399
|
+
const ts = row.ts.getTime();
|
|
2400
|
+
return ts >= chunk.startMs && ts <= chunk.endMs;
|
|
2401
|
+
});
|
|
2402
|
+
await (0, import_timescale.upsertMarketBreadthRows)(rows);
|
|
2403
|
+
breadthRows += rows.length;
|
|
2404
|
+
}
|
|
2405
|
+
} else {
|
|
2406
|
+
console.log(import_chalk.default.gray(`breadth cached: universe=${universe}`));
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
console.log(
|
|
2410
|
+
import_chalk.default.green(
|
|
2411
|
+
`binance market context backfill done: tradeFlowRows=${tradeFlowRows}, depthRows=0, breadthRows=${breadthRows}, skippedSymbols=${skippedSymbols}`
|
|
2412
|
+
)
|
|
2413
|
+
);
|
|
2414
|
+
return {
|
|
2415
|
+
skipped: false,
|
|
2416
|
+
tradeFlowRows,
|
|
2417
|
+
depthRows: 0,
|
|
2418
|
+
breadthRows,
|
|
2419
|
+
skippedSymbols
|
|
2420
|
+
};
|
|
2421
|
+
};
|
|
2422
|
+
var backfillBinanceMarketContextForBacktest = (params) => backfillBinanceMarketContext(params, true);
|
|
2423
|
+
var backfillBinanceMarketContextForSignals = (params) => backfillBinanceMarketContext(params, true);
|
|
2424
|
+
var backfillBinanceMarketContextForReplay = (params) => backfillBinanceMarketContext(params, true);
|
|
2425
|
+
|
|
2426
|
+
// src/lib/derivativesContextBackfill.ts
|
|
2427
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
2428
|
+
var import_progress2 = __toESM(require("progress"));
|
|
2429
|
+
var import_async = require("@tradejs/core/async");
|
|
2430
|
+
var import_constants = require("@tradejs/core/constants");
|
|
2431
|
+
var import_indicators = require("@tradejs/core/indicators");
|
|
2432
|
+
var import_timescale2 = require("@tradejs/infra/timescale");
|
|
2433
|
+
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
2434
|
+
var HOUR_MS = 60 * 60 * 1e3;
|
|
2435
|
+
var DAY_MS2 = 24 * HOUR_MS;
|
|
2436
|
+
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
2437
|
+
var DEFAULT_INTERVALS = ["15m", "1h"];
|
|
2438
|
+
var coinalyzeIntervalMap = {
|
|
2439
|
+
"15m": "15min",
|
|
2440
|
+
"1h": "1hour"
|
|
2441
|
+
};
|
|
2442
|
+
var derivativesIntervalMs = (interval) => interval === "1h" ? HOUR_MS : 15 * 60 * 1e3;
|
|
2443
|
+
var lastRequestTs = 0;
|
|
2444
|
+
var asInt2 = (value, fallback) => {
|
|
2445
|
+
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
2446
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
2447
|
+
};
|
|
2448
|
+
var parseList = (value) => String(value ?? "").split(",").map((item) => item.trim().toUpperCase()).filter(Boolean);
|
|
2449
|
+
var parseBooleanFlag = (value, fallback = false) => {
|
|
2450
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
2451
|
+
if (!normalized) return fallback;
|
|
2452
|
+
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
2453
|
+
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
|
2454
|
+
return fallback;
|
|
2455
|
+
};
|
|
2456
|
+
var normalizeSymbols = (symbols) => [
|
|
2457
|
+
...new Set(
|
|
2458
|
+
symbols.map(
|
|
2459
|
+
(symbol) => String(symbol || "").trim().toUpperCase()
|
|
2460
|
+
).filter(Boolean)
|
|
2461
|
+
)
|
|
2462
|
+
];
|
|
2463
|
+
var isDerivativesTargetContextEnabled = () => parseBooleanFlag(process.env.DERIVATIVES_CONTEXT_TARGET_ENABLED, false);
|
|
2464
|
+
var resolveDerivativesContextBackfillSymbols = (requestedSymbols = []) => {
|
|
2465
|
+
const referenceSymbols = (0, import_constants.resolveDerivativesContextReferenceSymbols)(
|
|
2466
|
+
process.env.DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS
|
|
2467
|
+
);
|
|
2468
|
+
return isDerivativesTargetContextEnabled() ? normalizeSymbols([...referenceSymbols, ...requestedSymbols]) : referenceSymbols;
|
|
2469
|
+
};
|
|
2470
|
+
var chunkArray = (items, size) => {
|
|
2471
|
+
const chunks = [];
|
|
2472
|
+
for (let i = 0; i < items.length; i += size) {
|
|
2473
|
+
chunks.push(items.slice(i, i + size));
|
|
2474
|
+
}
|
|
2475
|
+
return chunks;
|
|
2476
|
+
};
|
|
2477
|
+
var isBacktestDerivativesContextEnabled = () => {
|
|
2478
|
+
return isDerivativesContextBackfillEnabled("BACKTEST");
|
|
2479
|
+
};
|
|
2480
|
+
var isSignalsDerivativesContextEnabled = () => isDerivativesContextBackfillEnabled("CRON");
|
|
2481
|
+
var isDerivativesContextBackfillEnabled = (env) => {
|
|
2482
|
+
const normalized = String(process.env.DERIVATIVES_CONTEXT_ENABLED ?? "").trim().toLowerCase();
|
|
2483
|
+
if (!normalized) return true;
|
|
2484
|
+
if (["1", "true", "yes", "on"].includes(normalized)) {
|
|
2485
|
+
return true;
|
|
2486
|
+
}
|
|
2487
|
+
if (normalized === "backtest") {
|
|
2488
|
+
return env === "BACKTEST";
|
|
2489
|
+
}
|
|
2490
|
+
if (normalized === "live") {
|
|
2491
|
+
return env !== "BACKTEST";
|
|
2492
|
+
}
|
|
2493
|
+
return false;
|
|
2494
|
+
};
|
|
2495
|
+
var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
|
|
2496
|
+
var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
|
|
2497
|
+
var resolveDerivativesContextIntervals = () => {
|
|
2498
|
+
const intervals = (0, import_indicators.normalizeDerivativesIntervals)(
|
|
2499
|
+
process.env.DERIVATIVES_CONTEXT_INTERVALS
|
|
2500
|
+
);
|
|
2501
|
+
return intervals.length ? intervals : DEFAULT_INTERVALS;
|
|
2502
|
+
};
|
|
2503
|
+
var resolveDerivativesContextLookbackMs = () => {
|
|
2504
|
+
const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
|
|
2505
|
+
const normalizedHours = Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_LOOKBACK_HOURS;
|
|
2506
|
+
return normalizedHours * HOUR_MS;
|
|
2507
|
+
};
|
|
2508
|
+
var resolveDerivativesContextBackfillWindow = (params) => {
|
|
2509
|
+
const {
|
|
2510
|
+
mode = "signals",
|
|
2511
|
+
startMs,
|
|
2512
|
+
endMs,
|
|
2513
|
+
preloadStartMs,
|
|
2514
|
+
nowMs = Date.now()
|
|
2515
|
+
} = params;
|
|
2516
|
+
const safeEndMs = Math.min(endMs, nowMs);
|
|
2517
|
+
const safeStartMs = Math.max(0, Math.min(startMs, safeEndMs));
|
|
2518
|
+
const lookbackFromMs = safeStartMs - resolveDerivativesContextLookbackMs();
|
|
2519
|
+
const defaultFromMs = mode === "backtest" ? safeStartMs : lookbackFromMs;
|
|
2520
|
+
const requestedFromMs = mode === "signals" ? defaultFromMs : preloadStartMs ?? defaultFromMs;
|
|
2521
|
+
const fromMs = Math.max(
|
|
2522
|
+
0,
|
|
2523
|
+
Math.min(
|
|
2524
|
+
Number.isFinite(requestedFromMs) ? requestedFromMs : safeStartMs,
|
|
2525
|
+
safeStartMs
|
|
2526
|
+
)
|
|
2527
|
+
);
|
|
2528
|
+
return {
|
|
2529
|
+
fromMs: Math.trunc(fromMs),
|
|
2530
|
+
toMs: Math.trunc(safeEndMs),
|
|
2531
|
+
testStartMs: Math.trunc(safeStartMs)
|
|
2532
|
+
};
|
|
2533
|
+
};
|
|
2534
|
+
var resolveDerivativesContextIntervalBackfillWindow = (params) => {
|
|
2535
|
+
const intervalMs = derivativesIntervalMs(params.interval);
|
|
2536
|
+
return {
|
|
2537
|
+
fromMs: Math.floor(params.fromMs / intervalMs) * intervalMs,
|
|
2538
|
+
toMs: Math.floor(params.toMs / intervalMs) * intervalMs,
|
|
2539
|
+
intervalMs
|
|
2540
|
+
};
|
|
2541
|
+
};
|
|
2542
|
+
var resolveDerivativesContextMissingFetchFromMs = (params) => {
|
|
2543
|
+
const min = params.edges?.min;
|
|
2544
|
+
const max = params.edges?.max;
|
|
2545
|
+
if (min == null || max == null) {
|
|
2546
|
+
return params.fromMs;
|
|
2547
|
+
}
|
|
2548
|
+
if (min > params.fromMs) {
|
|
2549
|
+
return params.fromMs;
|
|
2550
|
+
}
|
|
2551
|
+
if (max < params.toMs) {
|
|
2552
|
+
return Math.max(params.fromMs, max + params.intervalMs);
|
|
2553
|
+
}
|
|
2554
|
+
return null;
|
|
2555
|
+
};
|
|
2556
|
+
var countBackfillWindows = (params) => {
|
|
2557
|
+
let count = 0;
|
|
2558
|
+
let cursor = params.fromMs;
|
|
2559
|
+
while (cursor < params.toMs) {
|
|
2560
|
+
const toMs = Math.min(params.toMs, cursor + params.batchMs);
|
|
2561
|
+
count += 1;
|
|
2562
|
+
cursor = toMs + params.intervalMs;
|
|
2563
|
+
}
|
|
2564
|
+
return count;
|
|
2565
|
+
};
|
|
2566
|
+
var buildBackfillWindows = (params) => {
|
|
2567
|
+
const windows = [];
|
|
2568
|
+
let cursor = params.fromMs;
|
|
2569
|
+
while (cursor < params.toMs) {
|
|
2570
|
+
const toMs = Math.min(params.toMs, cursor + params.batchMs);
|
|
2571
|
+
windows.push({ fromMs: cursor, toMs });
|
|
2572
|
+
cursor = toMs + params.intervalMs;
|
|
2573
|
+
}
|
|
2574
|
+
return windows;
|
|
2575
|
+
};
|
|
2576
|
+
var hasDerivativesWindowCoverage = (params) => params.edges?.min != null && params.edges?.max != null && params.edges.min <= params.fromMs && params.edges.max >= params.toMs;
|
|
2577
|
+
var resolveDerivativesContextMissingCoverageFetchFromMs = (params) => {
|
|
2578
|
+
const ranges = (params.ranges ?? []).filter(
|
|
2579
|
+
(range) => Number.isFinite(range.fromMs) && Number.isFinite(range.toMs)
|
|
2580
|
+
).sort((a, b) => a.fromMs - b.fromMs);
|
|
2581
|
+
let coveredUntil;
|
|
2582
|
+
for (const range of ranges) {
|
|
2583
|
+
if (range.toMs < params.fromMs) {
|
|
2584
|
+
continue;
|
|
2585
|
+
}
|
|
2586
|
+
if (coveredUntil == null) {
|
|
2587
|
+
if (range.fromMs > params.fromMs) {
|
|
2588
|
+
return params.fromMs;
|
|
2589
|
+
}
|
|
2590
|
+
coveredUntil = range.toMs;
|
|
2591
|
+
if (coveredUntil >= params.toMs) {
|
|
2592
|
+
return null;
|
|
2593
|
+
}
|
|
2594
|
+
continue;
|
|
2595
|
+
}
|
|
2596
|
+
if (range.fromMs > coveredUntil + params.intervalMs) {
|
|
2597
|
+
break;
|
|
2598
|
+
}
|
|
2599
|
+
coveredUntil = Math.max(coveredUntil, range.toMs);
|
|
2600
|
+
if (coveredUntil >= params.toMs) {
|
|
2601
|
+
return null;
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
if (coveredUntil == null) {
|
|
2605
|
+
return params.fromMs;
|
|
2606
|
+
}
|
|
2607
|
+
return Math.max(params.fromMs, coveredUntil + params.intervalMs);
|
|
2608
|
+
};
|
|
2609
|
+
var groupDerivativesContextMissingFetchRanges = (ranges) => {
|
|
2610
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2611
|
+
for (const range of ranges) {
|
|
2612
|
+
const fromMs = Math.trunc(range.fromMs);
|
|
2613
|
+
const items = groups.get(fromMs) ?? [];
|
|
2614
|
+
items.push(range.item);
|
|
2615
|
+
groups.set(fromMs, items);
|
|
2616
|
+
}
|
|
2617
|
+
return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
|
|
2618
|
+
};
|
|
2619
|
+
var coverageKey = (params) => [
|
|
2620
|
+
params.symbol.trim().toUpperCase(),
|
|
2621
|
+
params.interval,
|
|
2622
|
+
Math.trunc(params.fromMs),
|
|
2623
|
+
Math.trunc(params.toMs)
|
|
2624
|
+
].join(":");
|
|
2625
|
+
var extendEdges = (current, fromMs, toMs) => ({
|
|
2626
|
+
min: current?.min == null ? fromMs : Math.min(current.min, Math.trunc(fromMs)),
|
|
2627
|
+
max: current?.max == null ? toMs : Math.max(current.max, Math.trunc(toMs))
|
|
2628
|
+
});
|
|
2629
|
+
var getCoinalyzeApiKey = async (userName) => {
|
|
2630
|
+
const settings = await (0, import_userSettings.getUserSettings)(userName);
|
|
2631
|
+
return settings.COINALYZE_API_KEY.trim() || String(process.env.COINALYZE_API_KEY ?? "").trim();
|
|
2632
|
+
};
|
|
2633
|
+
var getCoinalyzeBaseUrl = () => process.env.COINALYZE_BASE_URL?.trim() || "https://api.coinalyze.net/v1";
|
|
2634
|
+
var getRequestDelayMs = () => Math.max(
|
|
2635
|
+
100,
|
|
2636
|
+
asInt2(
|
|
2637
|
+
process.env.DERIVATIVES_CONTEXT_BACKFILL_REQUEST_DELAY_MS ?? process.env.COINALYZE_MIN_REQUEST_DELAY_MS,
|
|
2638
|
+
200
|
|
2639
|
+
)
|
|
2640
|
+
);
|
|
2641
|
+
var getRequestTimeoutMs = () => Math.max(5e3, asInt2(process.env.COINALYZE_REQUEST_TIMEOUT_MS, 45e3));
|
|
2642
|
+
var networkErrorCodes = /* @__PURE__ */ new Set([
|
|
2643
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
2644
|
+
"ETIMEDOUT",
|
|
2645
|
+
"ECONNRESET",
|
|
2646
|
+
"ECONNREFUSED",
|
|
2647
|
+
"ENOTFOUND",
|
|
2648
|
+
"EAI_AGAIN",
|
|
2649
|
+
"EHOSTUNREACH"
|
|
2650
|
+
]);
|
|
2651
|
+
var getNestedErrorValue = (error, key) => {
|
|
2652
|
+
let current = error;
|
|
2653
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2654
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
2655
|
+
seen.add(current);
|
|
2656
|
+
const record = current;
|
|
2657
|
+
const value = record[key];
|
|
2658
|
+
if (typeof value === "string" && value.trim()) {
|
|
2659
|
+
return value.trim();
|
|
2660
|
+
}
|
|
2661
|
+
current = record.cause;
|
|
2662
|
+
}
|
|
2663
|
+
return null;
|
|
2664
|
+
};
|
|
2665
|
+
var getCoinalyzeErrorCause = (error) => {
|
|
2666
|
+
const code = getNestedErrorValue(error, "code");
|
|
2667
|
+
const message = getNestedErrorValue(error, "message") ?? String(error || "unknown error");
|
|
2668
|
+
return code ? `${code}: ${message}` : message;
|
|
2669
|
+
};
|
|
2670
|
+
var isRetryableCoinalyzeFetchError = (error) => {
|
|
2671
|
+
const name = getNestedErrorValue(error, "name");
|
|
2672
|
+
const code = getNestedErrorValue(error, "code");
|
|
2673
|
+
const message = getNestedErrorValue(error, "message")?.toLowerCase() ?? "";
|
|
2674
|
+
return name === "AbortError" || code != null && networkErrorCodes.has(code) || message.includes("aborted") || message.includes("fetch failed");
|
|
2675
|
+
};
|
|
2676
|
+
var formatCoinalyzeRequestError = ({
|
|
2677
|
+
url,
|
|
2678
|
+
error,
|
|
2679
|
+
attempts,
|
|
2680
|
+
timeoutMs
|
|
2681
|
+
}) => {
|
|
2682
|
+
const endpoint = (() => {
|
|
2683
|
+
try {
|
|
2684
|
+
const parsed = new URL(url);
|
|
2685
|
+
return `${parsed.origin}${parsed.pathname}`;
|
|
2686
|
+
} catch {
|
|
2687
|
+
return url;
|
|
2688
|
+
}
|
|
2689
|
+
})();
|
|
2690
|
+
return [
|
|
2691
|
+
`Coinalyze request failed: ${endpoint}`,
|
|
2692
|
+
`cause=${getCoinalyzeErrorCause(error)}`,
|
|
2693
|
+
`attempts=${attempts}`,
|
|
2694
|
+
`timeout=${timeoutMs}ms`,
|
|
2695
|
+
"Set COINALYZE_REQUEST_TIMEOUT_MS/COINALYZE_MAX_RETRIES to retry longer, or DERIVATIVES_CONTEXT_ENABLED=live to skip derivatives backfill during backtests."
|
|
2696
|
+
].join("; ");
|
|
2697
|
+
};
|
|
2698
|
+
var fetchJsonWithRateLimit = async (url, apiKey) => {
|
|
2699
|
+
const requestDelayMs = getRequestDelayMs();
|
|
2700
|
+
const requestTimeoutMs = getRequestTimeoutMs();
|
|
2701
|
+
const maxRetries = asInt2(process.env.COINALYZE_MAX_RETRIES, 4);
|
|
2702
|
+
let lastError = null;
|
|
2703
|
+
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
2704
|
+
const waitMs = Math.max(0, lastRequestTs + requestDelayMs - Date.now());
|
|
2705
|
+
if (waitMs > 0) {
|
|
2706
|
+
await (0, import_async.delay)(waitMs);
|
|
2707
|
+
}
|
|
2708
|
+
lastRequestTs = Date.now();
|
|
2709
|
+
const controller = new AbortController();
|
|
2710
|
+
const timer = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
2711
|
+
let response;
|
|
2712
|
+
try {
|
|
2713
|
+
response = await fetch(url, {
|
|
2714
|
+
headers: {
|
|
2715
|
+
api_key: apiKey,
|
|
2716
|
+
"x-api-key": apiKey,
|
|
2717
|
+
Authorization: `Bearer ${apiKey}`
|
|
2718
|
+
},
|
|
2719
|
+
signal: controller.signal
|
|
2720
|
+
});
|
|
2721
|
+
} catch (error) {
|
|
2722
|
+
clearTimeout(timer);
|
|
2723
|
+
lastError = error;
|
|
2724
|
+
if (attempt < maxRetries && isRetryableCoinalyzeFetchError(error)) {
|
|
2725
|
+
await (0, import_async.delay)(Math.min(12e3, 800 * 2 ** attempt));
|
|
2726
|
+
continue;
|
|
2727
|
+
}
|
|
2728
|
+
throw new Error(
|
|
2729
|
+
formatCoinalyzeRequestError({
|
|
2730
|
+
url,
|
|
2731
|
+
error,
|
|
2732
|
+
attempts: attempt + 1,
|
|
2733
|
+
timeoutMs: requestTimeoutMs
|
|
2734
|
+
})
|
|
2735
|
+
);
|
|
2736
|
+
} finally {
|
|
2737
|
+
clearTimeout(timer);
|
|
2738
|
+
}
|
|
2739
|
+
if (response.ok) {
|
|
2740
|
+
return response.json();
|
|
2741
|
+
}
|
|
2742
|
+
const text = await response.text();
|
|
2743
|
+
const retryAfterRaw = Number(response.headers.get("retry-after") ?? "");
|
|
2744
|
+
const retryAfterMs = Number.isFinite(retryAfterRaw) && retryAfterRaw > 0 ? retryAfterRaw * 1e3 : null;
|
|
2745
|
+
const transient = response.status === 429 || response.status >= 500;
|
|
2746
|
+
if (attempt < maxRetries && transient) {
|
|
2747
|
+
await (0, import_async.delay)(retryAfterMs ?? Math.min(12e3, 800 * 2 ** attempt));
|
|
2748
|
+
continue;
|
|
2749
|
+
}
|
|
2750
|
+
throw new Error(`Coinalyze ${response.status}: ${text}`);
|
|
2751
|
+
}
|
|
2752
|
+
throw new Error(
|
|
2753
|
+
formatCoinalyzeRequestError({
|
|
2754
|
+
url,
|
|
2755
|
+
error: lastError,
|
|
2756
|
+
attempts: maxRetries + 1,
|
|
2757
|
+
timeoutMs: requestTimeoutMs
|
|
2758
|
+
})
|
|
2759
|
+
);
|
|
2760
|
+
};
|
|
2761
|
+
var fetchCoinalyzeMarkets = async (apiKey) => {
|
|
2762
|
+
const raw = await fetchJsonWithRateLimit(
|
|
2763
|
+
`${getCoinalyzeBaseUrl()}/future-markets`,
|
|
2764
|
+
apiKey
|
|
2765
|
+
);
|
|
2766
|
+
return Array.isArray(raw) ? raw : [];
|
|
2767
|
+
};
|
|
2768
|
+
var selectBestMarket = (candidates, exchangePriority) => {
|
|
2769
|
+
const scored = candidates.map((item) => {
|
|
2770
|
+
let score = 0;
|
|
2771
|
+
if (item.is_perpetual) score += 50;
|
|
2772
|
+
if (String(item.quote_asset || "").toUpperCase() === "USDT") score += 25;
|
|
2773
|
+
if (item.symbol.includes("_PERP")) score += 10;
|
|
2774
|
+
const exchange = String(item.exchange || "").toUpperCase();
|
|
2775
|
+
const idx = exchangePriority.indexOf(exchange);
|
|
2776
|
+
if (idx >= 0) {
|
|
2777
|
+
score += (exchangePriority.length - idx) * 10;
|
|
2778
|
+
}
|
|
2779
|
+
return { item, score };
|
|
2780
|
+
});
|
|
2781
|
+
scored.sort((a, b) => {
|
|
2782
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
2783
|
+
return a.item.symbol.localeCompare(b.item.symbol);
|
|
2784
|
+
});
|
|
2785
|
+
return scored[0]?.item ?? null;
|
|
2786
|
+
};
|
|
2787
|
+
var buildMatches = (tickers, markets, exchangePriority) => {
|
|
2788
|
+
const marketByTicker = /* @__PURE__ */ new Map();
|
|
2789
|
+
for (const market of markets) {
|
|
2790
|
+
const key = String(market.symbol_on_exchange || "").trim().toUpperCase();
|
|
2791
|
+
if (!key) continue;
|
|
2792
|
+
const list = marketByTicker.get(key) ?? [];
|
|
2793
|
+
list.push(market);
|
|
2794
|
+
marketByTicker.set(key, list);
|
|
2795
|
+
}
|
|
2796
|
+
const matches = [];
|
|
2797
|
+
const unmatched = [];
|
|
2798
|
+
for (const ticker of tickers) {
|
|
2799
|
+
const candidates = marketByTicker.get(ticker) ?? [];
|
|
2800
|
+
const selected = selectBestMarket(candidates, exchangePriority);
|
|
2801
|
+
if (!selected) {
|
|
2802
|
+
unmatched.push(ticker);
|
|
2803
|
+
continue;
|
|
2804
|
+
}
|
|
2805
|
+
matches.push({
|
|
2806
|
+
symbol: ticker,
|
|
2807
|
+
marketSymbol: selected.symbol,
|
|
2808
|
+
exchange: selected.exchange
|
|
2809
|
+
});
|
|
2810
|
+
}
|
|
2811
|
+
return { matches, unmatched };
|
|
2812
|
+
};
|
|
2813
|
+
var normalizeMetricPoint = (metric, point) => {
|
|
2814
|
+
if (metric === "oi") {
|
|
2815
|
+
return {
|
|
2816
|
+
...point,
|
|
2817
|
+
open_interest: point.open_interest ?? point.openInterest ?? point.oi ?? point.c
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
if (metric === "funding") {
|
|
2821
|
+
return {
|
|
2822
|
+
...point,
|
|
2823
|
+
funding_rate: point.funding_rate ?? point.fundingRate ?? point.rate ?? point.c
|
|
2824
|
+
};
|
|
2825
|
+
}
|
|
2826
|
+
return {
|
|
2827
|
+
...point,
|
|
2828
|
+
liq_long: point.liq_long ?? point.long_liq ?? point.long ?? point.l,
|
|
2829
|
+
liq_short: point.liq_short ?? point.short_liq ?? point.short ?? point.s
|
|
2830
|
+
};
|
|
2831
|
+
};
|
|
2832
|
+
var toSeriesMap = (raw, metric) => {
|
|
2833
|
+
const out = /* @__PURE__ */ new Map();
|
|
2834
|
+
if (!Array.isArray(raw)) return out;
|
|
2835
|
+
for (const item of raw) {
|
|
2836
|
+
const symbol = String(item.symbol || "").trim().toUpperCase();
|
|
2837
|
+
const history = Array.isArray(item.history) ? item.history : [];
|
|
2838
|
+
if (!symbol) continue;
|
|
2839
|
+
out.set(
|
|
2840
|
+
symbol,
|
|
2841
|
+
history.filter((point) => point && typeof point === "object").map((point) => normalizeMetricPoint(metric, point))
|
|
2842
|
+
);
|
|
2843
|
+
}
|
|
2844
|
+
return out;
|
|
2845
|
+
};
|
|
2846
|
+
var fetchMetricBatch = async (params) => {
|
|
2847
|
+
const { endpoint, metric, marketSymbols, apiKey, interval, fromMs, toMs } = params;
|
|
2848
|
+
const url = new URL(`${getCoinalyzeBaseUrl()}${endpoint}`);
|
|
2849
|
+
url.searchParams.set("symbols", marketSymbols.join(","));
|
|
2850
|
+
url.searchParams.set("interval", coinalyzeIntervalMap[interval] || interval);
|
|
2851
|
+
url.searchParams.set("from", String(Math.floor(fromMs / 1e3)));
|
|
2852
|
+
url.searchParams.set("to", String(Math.floor(toMs / 1e3)));
|
|
2853
|
+
const raw = await fetchJsonWithRateLimit(url.toString(), apiKey);
|
|
2854
|
+
return toSeriesMap(raw, metric);
|
|
2855
|
+
};
|
|
2856
|
+
var skippedBackfillResult2 = () => ({
|
|
2857
|
+
skipped: true,
|
|
2858
|
+
rows: 0,
|
|
2859
|
+
matchedSymbols: 0,
|
|
2860
|
+
unmatchedSymbols: 0,
|
|
2861
|
+
failedWindows: 0,
|
|
2862
|
+
skippedWindows: 0
|
|
2863
|
+
});
|
|
2864
|
+
var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
2865
|
+
const { userName, startMs, endMs } = params;
|
|
2866
|
+
const requestedSymbols = normalizeSymbols(params.symbols);
|
|
2867
|
+
const symbols = resolveDerivativesContextBackfillSymbols(requestedSymbols);
|
|
2868
|
+
if (!enabled || !requestedSymbols.length || !symbols.length) {
|
|
2869
|
+
return skippedBackfillResult2();
|
|
2870
|
+
}
|
|
2871
|
+
const intervals = resolveDerivativesContextIntervals();
|
|
2872
|
+
if (!intervals.length) {
|
|
2873
|
+
return skippedBackfillResult2();
|
|
2874
|
+
}
|
|
2875
|
+
const {
|
|
2876
|
+
fromMs,
|
|
2877
|
+
toMs: safeEndMs,
|
|
2878
|
+
testStartMs: safeStartMs
|
|
2879
|
+
} = resolveDerivativesContextBackfillWindow({
|
|
2880
|
+
mode,
|
|
2881
|
+
startMs,
|
|
2882
|
+
endMs,
|
|
2883
|
+
preloadStartMs: params.preloadStartMs
|
|
2884
|
+
});
|
|
2885
|
+
if (safeEndMs <= fromMs) {
|
|
2886
|
+
return skippedBackfillResult2();
|
|
2887
|
+
}
|
|
2888
|
+
const batchDays = asInt2(
|
|
2889
|
+
process.env.DERIVATIVES_CONTEXT_BACKFILL_BATCH_DAYS,
|
|
2890
|
+
30
|
|
2891
|
+
);
|
|
2892
|
+
const batchMs = batchDays * DAY_MS2;
|
|
2893
|
+
const intervalWindows = intervals.map((interval) => ({
|
|
2894
|
+
interval,
|
|
2895
|
+
...resolveDerivativesContextIntervalBackfillWindow({
|
|
2896
|
+
fromMs,
|
|
2897
|
+
toMs: safeEndMs,
|
|
2898
|
+
interval
|
|
2899
|
+
})
|
|
2900
|
+
})).filter((item) => item.toMs > item.fromMs);
|
|
2901
|
+
if (!intervalWindows.length) {
|
|
2902
|
+
return skippedBackfillResult2();
|
|
2903
|
+
}
|
|
2904
|
+
await (0, import_timescale2.waitForDbReady)();
|
|
2905
|
+
const edgesByInterval = /* @__PURE__ */ new Map();
|
|
2906
|
+
await Promise.all(
|
|
2907
|
+
intervalWindows.map(async ({ interval }) => {
|
|
2908
|
+
edgesByInterval.set(
|
|
2909
|
+
interval,
|
|
2910
|
+
await (0, import_timescale2.getDerivativesDataEdgesForSymbols)(symbols, interval)
|
|
2911
|
+
);
|
|
2912
|
+
})
|
|
2913
|
+
);
|
|
2914
|
+
const coverageKeysByInterval = /* @__PURE__ */ new Map();
|
|
2915
|
+
const coverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
2916
|
+
await Promise.all(
|
|
2917
|
+
intervalWindows.map(async (window2) => {
|
|
2918
|
+
const coverageRows = await (0, import_timescale2.getDerivativesBackfillCoverage)({
|
|
2919
|
+
source: "coinalyze",
|
|
2920
|
+
symbols,
|
|
2921
|
+
interval: window2.interval,
|
|
2922
|
+
fromMs: window2.fromMs,
|
|
2923
|
+
toMs: window2.toMs
|
|
2924
|
+
});
|
|
2925
|
+
coverageKeysByInterval.set(
|
|
2926
|
+
window2.interval,
|
|
2927
|
+
new Set(
|
|
2928
|
+
coverageRows.map(
|
|
2929
|
+
(row) => coverageKey({
|
|
2930
|
+
symbol: row.symbol,
|
|
2931
|
+
interval: row.interval,
|
|
2932
|
+
fromMs: row.fromMs,
|
|
2933
|
+
toMs: row.toMs
|
|
2934
|
+
})
|
|
2935
|
+
)
|
|
2936
|
+
)
|
|
2937
|
+
);
|
|
2938
|
+
const rangesBySymbol = /* @__PURE__ */ new Map();
|
|
2939
|
+
for (const row of coverageRows) {
|
|
2940
|
+
const symbol = row.symbol.toUpperCase();
|
|
2941
|
+
const ranges = rangesBySymbol.get(symbol) ?? [];
|
|
2942
|
+
ranges.push({ fromMs: row.fromMs, toMs: row.toMs });
|
|
2943
|
+
rangesBySymbol.set(symbol, ranges);
|
|
2944
|
+
}
|
|
2945
|
+
coverageRangesByInterval.set(window2.interval, rangesBySymbol);
|
|
2946
|
+
})
|
|
2947
|
+
);
|
|
2948
|
+
const cachedWindows = intervalWindows.reduce(
|
|
2949
|
+
(sum, window2) => sum + countBackfillWindows({
|
|
2950
|
+
fromMs: window2.fromMs,
|
|
2951
|
+
toMs: window2.toMs,
|
|
2952
|
+
batchMs,
|
|
2953
|
+
intervalMs: window2.intervalMs
|
|
2954
|
+
}),
|
|
2955
|
+
0
|
|
2956
|
+
);
|
|
2957
|
+
const allBackfillWindowsCached = intervalWindows.every((window2) => {
|
|
2958
|
+
const edgesBySymbol = edgesByInterval.get(window2.interval);
|
|
2959
|
+
const coverageKeys = coverageKeysByInterval.get(window2.interval);
|
|
2960
|
+
const backfillWindows = buildBackfillWindows({
|
|
2961
|
+
fromMs: window2.fromMs,
|
|
2962
|
+
toMs: window2.toMs,
|
|
2963
|
+
batchMs,
|
|
2964
|
+
intervalMs: window2.intervalMs
|
|
2965
|
+
});
|
|
2966
|
+
return symbols.every(
|
|
2967
|
+
(symbol) => backfillWindows.every((backfillWindow) => {
|
|
2968
|
+
const normalizedSymbol = symbol.toUpperCase();
|
|
2969
|
+
const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
|
|
2970
|
+
return hasDerivativesWindowCoverage({
|
|
2971
|
+
edges: edgesBySymbol?.get(normalizedSymbol),
|
|
2972
|
+
fromMs: backfillWindow.fromMs,
|
|
2973
|
+
toMs: backfillWindow.toMs
|
|
2974
|
+
}) || resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
2975
|
+
ranges: coverageRanges,
|
|
2976
|
+
fromMs: backfillWindow.fromMs,
|
|
2977
|
+
toMs: backfillWindow.toMs,
|
|
2978
|
+
intervalMs: window2.intervalMs
|
|
2979
|
+
}) == null || coverageKeys?.has(
|
|
2980
|
+
coverageKey({
|
|
2981
|
+
symbol: normalizedSymbol,
|
|
2982
|
+
interval: window2.interval,
|
|
2983
|
+
fromMs: backfillWindow.fromMs,
|
|
2984
|
+
toMs: backfillWindow.toMs
|
|
2985
|
+
})
|
|
2986
|
+
);
|
|
2987
|
+
})
|
|
2988
|
+
);
|
|
2989
|
+
});
|
|
2990
|
+
if (allBackfillWindowsCached) {
|
|
2991
|
+
console.log(
|
|
2992
|
+
import_chalk2.default.gray(
|
|
2993
|
+
`derivatives context backfill: cached symbols=${symbols.length}, requestedSymbols=${requestedSymbols.length}, intervals=${intervals.join(",")}, window=${new Date(fromMs).toISOString()}..${new Date(safeEndMs).toISOString()}`
|
|
2994
|
+
)
|
|
2995
|
+
);
|
|
2996
|
+
return {
|
|
2997
|
+
skipped: false,
|
|
2998
|
+
rows: 0,
|
|
2999
|
+
matchedSymbols: symbols.length,
|
|
3000
|
+
unmatchedSymbols: 0,
|
|
3001
|
+
failedWindows: 0,
|
|
3002
|
+
skippedWindows: cachedWindows
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
const apiKey = await getCoinalyzeApiKey(userName);
|
|
3006
|
+
if (!apiKey) {
|
|
3007
|
+
throw new Error(
|
|
3008
|
+
`Missing COINALYZE_API_KEY for derivatives context backfill (user=${userName})`
|
|
3009
|
+
);
|
|
3010
|
+
}
|
|
3011
|
+
const exchangePriority = parseList(
|
|
3012
|
+
process.env.COINALYZE_EXCHANGE_PRIORITY || process.env.DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY || "A,6,0"
|
|
3013
|
+
);
|
|
3014
|
+
const markets = await fetchCoinalyzeMarkets(apiKey);
|
|
3015
|
+
if (!markets.length) {
|
|
3016
|
+
throw new Error("No markets returned by Coinalyze /future-markets");
|
|
3017
|
+
}
|
|
3018
|
+
const { matches, unmatched } = buildMatches(
|
|
3019
|
+
symbols,
|
|
3020
|
+
markets,
|
|
3021
|
+
exchangePriority
|
|
3022
|
+
);
|
|
3023
|
+
if (!matches.length) {
|
|
3024
|
+
throw new Error(
|
|
3025
|
+
"No matched derivatives context symbols between requested symbols and Coinalyze"
|
|
3026
|
+
);
|
|
3027
|
+
}
|
|
3028
|
+
const symbolBatchSize = asInt2(
|
|
3029
|
+
process.env.DERIVATIVES_CONTEXT_BACKFILL_SYMBOL_BATCH_SIZE,
|
|
3030
|
+
8
|
|
3031
|
+
);
|
|
3032
|
+
const symbolBatches = chunkArray(matches, symbolBatchSize);
|
|
3033
|
+
const windowsPerPair = intervalWindows.reduce(
|
|
3034
|
+
(sum, window2) => sum + countBackfillWindows({
|
|
3035
|
+
fromMs: window2.fromMs,
|
|
3036
|
+
toMs: window2.toMs,
|
|
3037
|
+
batchMs,
|
|
3038
|
+
intervalMs: window2.intervalMs
|
|
3039
|
+
}),
|
|
3040
|
+
0
|
|
3041
|
+
);
|
|
3042
|
+
const totalWindows = symbolBatches.length * windowsPerPair;
|
|
3043
|
+
const bar = new import_progress2.default(
|
|
3044
|
+
":current/:total [:bar][:percent] :eta(s) :batch rows=:rows fail=:fail skip=:skip",
|
|
3045
|
+
{
|
|
3046
|
+
total: Math.max(1, totalWindows),
|
|
3047
|
+
width: 24
|
|
3048
|
+
}
|
|
3049
|
+
);
|
|
3050
|
+
const oiPath = process.env.COINALYZE_OI_PATH?.trim() || "/open-interest-history";
|
|
3051
|
+
const fundingPath = process.env.COINALYZE_FUNDING_PATH?.trim() || "/funding-rate-history";
|
|
3052
|
+
const liqPath = process.env.COINALYZE_LIQ_PATH?.trim() || "/liquidation-history";
|
|
3053
|
+
let totalRows = 0;
|
|
3054
|
+
let failedWindows = 0;
|
|
3055
|
+
let skippedWindows = 0;
|
|
3056
|
+
console.log(
|
|
3057
|
+
import_chalk2.default.cyan(
|
|
3058
|
+
`derivatives context backfill: symbols=${matches.length}, requestedSymbols=${requestedSymbols.length}, unmatched=${unmatched.length}, intervals=${intervals.join(",")}, window=${new Date(fromMs).toISOString()}..${new Date(safeEndMs).toISOString()}, testStart=${new Date(safeStartMs).toISOString()}`
|
|
3059
|
+
)
|
|
3060
|
+
);
|
|
3061
|
+
for (const window2 of intervalWindows) {
|
|
3062
|
+
const { interval, intervalMs } = window2;
|
|
3063
|
+
const edgesBySymbol = edgesByInterval.get(interval) ?? await (0, import_timescale2.getDerivativesDataEdgesForSymbols)(
|
|
3064
|
+
matches.map((item) => item.symbol),
|
|
3065
|
+
interval
|
|
3066
|
+
);
|
|
3067
|
+
const coverageKeys = coverageKeysByInterval.get(interval) ?? /* @__PURE__ */ new Set();
|
|
3068
|
+
coverageKeysByInterval.set(interval, coverageKeys);
|
|
3069
|
+
const coverageRangesBySymbol = coverageRangesByInterval.get(interval) ?? /* @__PURE__ */ new Map();
|
|
3070
|
+
coverageRangesByInterval.set(interval, coverageRangesBySymbol);
|
|
3071
|
+
for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
|
|
3072
|
+
const batch = symbolBatches[batchIdx];
|
|
3073
|
+
let cursor = window2.fromMs;
|
|
3074
|
+
while (cursor < window2.toMs) {
|
|
3075
|
+
const toMs = Math.min(window2.toMs, cursor + batchMs);
|
|
3076
|
+
const missingRanges = batch.map((item) => {
|
|
3077
|
+
const key = coverageKey({
|
|
3078
|
+
symbol: item.symbol,
|
|
3079
|
+
interval,
|
|
3080
|
+
fromMs: cursor,
|
|
3081
|
+
toMs
|
|
3082
|
+
});
|
|
3083
|
+
if (coverageKeys.has(key)) {
|
|
3084
|
+
return null;
|
|
3085
|
+
}
|
|
3086
|
+
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3087
|
+
const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3088
|
+
ranges: coverageRangesBySymbol.get(normalizedSymbol),
|
|
3089
|
+
fromMs: cursor,
|
|
3090
|
+
toMs,
|
|
3091
|
+
intervalMs
|
|
3092
|
+
});
|
|
3093
|
+
if (coverageFromMs == null) {
|
|
3094
|
+
return null;
|
|
3095
|
+
}
|
|
3096
|
+
const edges = edgesBySymbol.get(normalizedSymbol);
|
|
3097
|
+
const edgesFromMs = resolveDerivativesContextMissingFetchFromMs({
|
|
3098
|
+
edges,
|
|
3099
|
+
fromMs: cursor,
|
|
3100
|
+
toMs,
|
|
3101
|
+
intervalMs
|
|
3102
|
+
});
|
|
3103
|
+
if (edgesFromMs == null) {
|
|
3104
|
+
return null;
|
|
3105
|
+
}
|
|
3106
|
+
return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
|
|
3107
|
+
}).filter(
|
|
3108
|
+
(item) => item != null
|
|
3109
|
+
);
|
|
3110
|
+
try {
|
|
3111
|
+
if (!missingRanges.length) {
|
|
3112
|
+
skippedWindows += 1;
|
|
3113
|
+
} else {
|
|
3114
|
+
const groupedMissingRanges = groupDerivativesContextMissingFetchRanges(missingRanges);
|
|
3115
|
+
for (const group of groupedMissingRanges) {
|
|
3116
|
+
const missingBatch = group.items;
|
|
3117
|
+
const marketSymbols = missingBatch.map(
|
|
3118
|
+
(item) => item.marketSymbol
|
|
3119
|
+
);
|
|
3120
|
+
const oiMap = await fetchMetricBatch({
|
|
3121
|
+
endpoint: oiPath,
|
|
3122
|
+
metric: "oi",
|
|
3123
|
+
marketSymbols,
|
|
3124
|
+
apiKey,
|
|
3125
|
+
interval,
|
|
3126
|
+
fromMs: group.fromMs,
|
|
3127
|
+
toMs
|
|
3128
|
+
});
|
|
3129
|
+
const fundingMap = await fetchMetricBatch({
|
|
3130
|
+
endpoint: fundingPath,
|
|
3131
|
+
metric: "funding",
|
|
3132
|
+
marketSymbols,
|
|
3133
|
+
apiKey,
|
|
3134
|
+
interval,
|
|
3135
|
+
fromMs: group.fromMs,
|
|
3136
|
+
toMs
|
|
3137
|
+
});
|
|
3138
|
+
const liqMap = await fetchMetricBatch({
|
|
3139
|
+
endpoint: liqPath,
|
|
3140
|
+
metric: "liq",
|
|
3141
|
+
marketSymbols,
|
|
3142
|
+
apiKey,
|
|
3143
|
+
interval,
|
|
3144
|
+
fromMs: group.fromMs,
|
|
3145
|
+
toMs
|
|
3146
|
+
});
|
|
3147
|
+
const rows = missingBatch.flatMap((item) => {
|
|
3148
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3149
|
+
const points = (0, import_indicators.mergeCoinalyzeMetrics)({
|
|
3150
|
+
symbol: item.symbol,
|
|
3151
|
+
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3152
|
+
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3153
|
+
liqRaw: liqMap.get(marketSymbol) ?? []
|
|
3154
|
+
});
|
|
3155
|
+
return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
|
|
3156
|
+
});
|
|
3157
|
+
if (rows.length) {
|
|
3158
|
+
await (0, import_timescale2.upsertDerivatives)(rows);
|
|
3159
|
+
totalRows += rows.length;
|
|
3160
|
+
}
|
|
3161
|
+
const rowsCountBySymbol = /* @__PURE__ */ new Map();
|
|
3162
|
+
for (const row of rows) {
|
|
3163
|
+
const symbol = row.symbol.toUpperCase();
|
|
3164
|
+
rowsCountBySymbol.set(
|
|
3165
|
+
symbol,
|
|
3166
|
+
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
3167
|
+
);
|
|
3168
|
+
}
|
|
3169
|
+
const coverageRows = missingBatch.map((item) => {
|
|
3170
|
+
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3171
|
+
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
3172
|
+
return {
|
|
3173
|
+
source: "coinalyze",
|
|
3174
|
+
symbol: item.symbol,
|
|
3175
|
+
interval,
|
|
3176
|
+
fromMs: cursor,
|
|
3177
|
+
toMs,
|
|
3178
|
+
rowsCount
|
|
3179
|
+
};
|
|
3180
|
+
});
|
|
3181
|
+
await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
|
|
3182
|
+
for (const coverageRow of coverageRows) {
|
|
3183
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
3184
|
+
edgesBySymbol.set(
|
|
3185
|
+
symbol,
|
|
3186
|
+
extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
|
|
3187
|
+
);
|
|
3188
|
+
coverageKeys.add(
|
|
3189
|
+
coverageKey({
|
|
3190
|
+
symbol,
|
|
3191
|
+
interval,
|
|
3192
|
+
fromMs: cursor,
|
|
3193
|
+
toMs
|
|
3194
|
+
})
|
|
3195
|
+
);
|
|
3196
|
+
const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
|
|
3197
|
+
coverageRanges.push({ fromMs: cursor, toMs });
|
|
3198
|
+
coverageRangesBySymbol.set(symbol, coverageRanges);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
} catch (error) {
|
|
3203
|
+
failedWindows += 1;
|
|
3204
|
+
console.error(
|
|
3205
|
+
import_chalk2.default.red(
|
|
3206
|
+
`derivatives context backfill window failed batch=${batchIdx + 1}/${symbolBatches.length} interval=${interval} ${new Date(cursor).toISOString()}..${new Date(toMs).toISOString()}: ${error}`
|
|
3207
|
+
)
|
|
3208
|
+
);
|
|
3209
|
+
} finally {
|
|
3210
|
+
bar.tick(1, {
|
|
3211
|
+
batch: import_chalk2.default.gray(
|
|
3212
|
+
`${batchIdx + 1}/${symbolBatches.length} ${interval}`
|
|
3213
|
+
),
|
|
3214
|
+
rows: totalRows,
|
|
3215
|
+
fail: failedWindows,
|
|
3216
|
+
skip: skippedWindows
|
|
3217
|
+
});
|
|
3218
|
+
}
|
|
3219
|
+
cursor = toMs + intervalMs;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
console.log("");
|
|
3224
|
+
console.log(
|
|
3225
|
+
import_chalk2.default.green(
|
|
3226
|
+
`derivatives context backfill done: rows=${totalRows}, failed_windows=${failedWindows}, skipped_windows=${skippedWindows}`
|
|
3227
|
+
)
|
|
3228
|
+
);
|
|
3229
|
+
if (failedWindows > 0) {
|
|
3230
|
+
throw new Error(
|
|
3231
|
+
`Derivatives context backfill failed for ${failedWindows} window(s)`
|
|
3232
|
+
);
|
|
3233
|
+
}
|
|
3234
|
+
return {
|
|
3235
|
+
skipped: false,
|
|
3236
|
+
rows: totalRows,
|
|
3237
|
+
matchedSymbols: matches.length,
|
|
3238
|
+
unmatchedSymbols: unmatched.length,
|
|
3239
|
+
failedWindows,
|
|
3240
|
+
skippedWindows
|
|
3241
|
+
};
|
|
3242
|
+
};
|
|
3243
|
+
var backfillDerivativesContextForBacktest = async (params) => backfillDerivativesContext(
|
|
3244
|
+
params,
|
|
3245
|
+
isBacktestDerivativesContextEnabled(),
|
|
3246
|
+
"backtest"
|
|
3247
|
+
);
|
|
3248
|
+
var backfillDerivativesContextForSignals = async (params) => backfillDerivativesContext(
|
|
3249
|
+
params,
|
|
3250
|
+
isSignalsDerivativesContextEnabled(),
|
|
3251
|
+
"signals"
|
|
3252
|
+
);
|
|
3253
|
+
|
|
3254
|
+
// src/lib/coinMarketCapContextBackfill.ts
|
|
3255
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
3256
|
+
var import_async2 = require("@tradejs/core/async");
|
|
3257
|
+
var import_timescale3 = require("@tradejs/infra/timescale");
|
|
3258
|
+
var import_userSettings2 = require("@tradejs/infra/userSettings");
|
|
3259
|
+
var DAY_MS3 = 864e5;
|
|
3260
|
+
var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
|
|
3261
|
+
var SOURCE_REFERENCE = "coinmarketcap_reference_asset";
|
|
3262
|
+
var SOURCE_EXCHANGE_LIQUIDITY = "coinmarketcap_exchange_liquidity";
|
|
3263
|
+
var SOURCE_FEAR_GREED = "coinmarketcap_fear_greed";
|
|
3264
|
+
var SOURCE_INDEX = "coinmarketcap_index";
|
|
3265
|
+
var COVERAGE_SCOPE_ALL = "all";
|
|
3266
|
+
var REFERENCE_ASSETS = [
|
|
3267
|
+
{ symbol: "BTCUSDT", cmcId: 1 },
|
|
3268
|
+
{ symbol: "ETHUSDT", cmcId: 1027 }
|
|
3269
|
+
];
|
|
3270
|
+
var CMC_INDEXES = [
|
|
3271
|
+
{ slug: "cmc100", path: "/v3/index/cmc100-historical" },
|
|
3272
|
+
{ slug: "cmc20", path: "/v3/index/cmc20-historical" }
|
|
3273
|
+
];
|
|
3274
|
+
var DEFAULT_EXCHANGE_SLUGS = [
|
|
3275
|
+
"binance",
|
|
3276
|
+
"coinbase-exchange",
|
|
3277
|
+
"okx",
|
|
3278
|
+
"bybit",
|
|
3279
|
+
"kraken"
|
|
3280
|
+
];
|
|
3281
|
+
var lastRequestTs2 = 0;
|
|
3282
|
+
var asInt3 = (value, fallback) => {
|
|
3283
|
+
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
3284
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
3285
|
+
};
|
|
3286
|
+
var parseEnabledFlag2 = (value, defaultValue) => {
|
|
3287
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
3288
|
+
if (!normalized) return defaultValue;
|
|
3289
|
+
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
3290
|
+
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
|
3291
|
+
return defaultValue;
|
|
3292
|
+
};
|
|
3293
|
+
var getBaseUrl = () => process.env.COINMARKETCAP_BASE_URL?.trim() || "https://pro-api.coinmarketcap.com";
|
|
3294
|
+
var getRequestDelayMs2 = () => asInt3(process.env.COINMARKETCAP_MIN_REQUEST_DELAY_MS, 2100);
|
|
3295
|
+
var getMaxRetries = () => asInt3(process.env.COINMARKETCAP_MAX_RETRIES, 4);
|
|
3296
|
+
var getMaxBackfillDays = () => asInt3(process.env.COINMARKETCAP_CONTEXT_BACKFILL_MAX_DAYS, 1098);
|
|
3297
|
+
var getHistoricalAccessMonths = () => asInt3(process.env.COINMARKETCAP_CONTEXT_HISTORICAL_ACCESS_MONTHS, 36);
|
|
3298
|
+
var isExchangeLiquidityBackfillEnabled = () => parseEnabledFlag2(
|
|
3299
|
+
process.env.COINMARKETCAP_CONTEXT_EXCHANGE_LIQUIDITY_ENABLED,
|
|
3300
|
+
true
|
|
3301
|
+
);
|
|
3302
|
+
var isFearGreedBackfillEnabled = () => parseEnabledFlag2(process.env.COINMARKETCAP_CONTEXT_FEAR_GREED_ENABLED, true);
|
|
3303
|
+
var isVerboseRequestLoggingEnabled = () => parseEnabledFlag2(process.env.COINMARKETCAP_CONTEXT_VERBOSE_REQUESTS, false);
|
|
3304
|
+
var getFearGreedPageSize = () => asInt3(process.env.COINMARKETCAP_CONTEXT_FEAR_GREED_PAGE_SIZE, 500);
|
|
3305
|
+
var getExchangeSlugs = () => {
|
|
3306
|
+
const raw = process.env.COINMARKETCAP_CONTEXT_EXCHANGE_SLUGS;
|
|
3307
|
+
const values = String(raw ?? "").split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
|
|
3308
|
+
return values.length ? [...new Set(values)] : [...DEFAULT_EXCHANGE_SLUGS];
|
|
3309
|
+
};
|
|
3310
|
+
var toFiniteNumberOrNull = (value) => {
|
|
3311
|
+
const numeric = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
|
|
3312
|
+
return Number.isFinite(numeric) ? numeric : null;
|
|
3313
|
+
};
|
|
3314
|
+
var toIntOrNull = (value) => {
|
|
3315
|
+
const numeric = toFiniteNumberOrNull(value);
|
|
3316
|
+
return numeric == null ? null : Math.trunc(numeric);
|
|
3317
|
+
};
|
|
3318
|
+
var getRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3319
|
+
var getNestedRecord = (value, key) => getRecord(value[key]);
|
|
3320
|
+
var safeDivide2 = (numerator, denominator) => numerator != null && denominator != null && denominator > 0 ? numerator / denominator : null;
|
|
3321
|
+
var sumFinite = (values) => values.reduce((sum, value) => sum + (value ?? 0), 0);
|
|
3322
|
+
var toExchangeLiquidityRegime = ({
|
|
3323
|
+
binanceVolumeShare,
|
|
3324
|
+
topExchangeVolumeShare
|
|
3325
|
+
}) => {
|
|
3326
|
+
if (binanceVolumeShare == null && topExchangeVolumeShare == null) {
|
|
3327
|
+
return "unknown";
|
|
3328
|
+
}
|
|
3329
|
+
if ((binanceVolumeShare ?? 0) >= 0.55) return "binance_led";
|
|
3330
|
+
if ((topExchangeVolumeShare ?? 0) >= 0.6) return "concentrated";
|
|
3331
|
+
return "balanced";
|
|
3332
|
+
};
|
|
3333
|
+
var normalizeFearGreedClassification = (value) => {
|
|
3334
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
3335
|
+
if (normalized === "extreme fear") return "Extreme Fear";
|
|
3336
|
+
if (normalized === "fear") return "Fear";
|
|
3337
|
+
if (normalized === "neutral") return "Neutral";
|
|
3338
|
+
if (normalized === "greed") return "Greed";
|
|
3339
|
+
if (normalized === "extreme greed") return "Extreme Greed";
|
|
3340
|
+
return "Unknown";
|
|
3341
|
+
};
|
|
3342
|
+
var toFearGreedRegime = ({
|
|
3343
|
+
value,
|
|
3344
|
+
classification
|
|
3345
|
+
}) => {
|
|
3346
|
+
if (value == null) return "unknown";
|
|
3347
|
+
if (classification === "Extreme Fear" || value <= 24) return "capitulation";
|
|
3348
|
+
if (classification === "Fear" || value <= 44) return "risk_off";
|
|
3349
|
+
if (classification === "Extreme Greed" || value >= 75) return "euphoric";
|
|
3350
|
+
if (classification === "Greed" || value >= 55) return "risk_on";
|
|
3351
|
+
if (classification === "Neutral" || value >= 45 && value <= 54) {
|
|
3352
|
+
return "neutral";
|
|
3353
|
+
}
|
|
3354
|
+
return "unknown";
|
|
3355
|
+
};
|
|
3356
|
+
var dayStartUtc = (ms) => {
|
|
3357
|
+
const date = new Date(ms);
|
|
3358
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
3359
|
+
};
|
|
3360
|
+
var toIsoDate = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
3361
|
+
var subtractUtcMonths = (ms, months) => {
|
|
3362
|
+
const date = new Date(ms);
|
|
3363
|
+
const targetMonthIndex = date.getUTCMonth() - months;
|
|
3364
|
+
const targetMonthStart = new Date(
|
|
3365
|
+
Date.UTC(
|
|
3366
|
+
date.getUTCFullYear(),
|
|
3367
|
+
targetMonthIndex,
|
|
3368
|
+
1,
|
|
3369
|
+
date.getUTCHours(),
|
|
3370
|
+
date.getUTCMinutes(),
|
|
3371
|
+
date.getUTCSeconds(),
|
|
3372
|
+
date.getUTCMilliseconds()
|
|
3373
|
+
)
|
|
3374
|
+
);
|
|
3375
|
+
const daysInTargetMonth = new Date(
|
|
3376
|
+
Date.UTC(
|
|
3377
|
+
targetMonthStart.getUTCFullYear(),
|
|
3378
|
+
targetMonthStart.getUTCMonth() + 1,
|
|
3379
|
+
0
|
|
3380
|
+
)
|
|
3381
|
+
).getUTCDate();
|
|
3382
|
+
targetMonthStart.setUTCDate(Math.min(date.getUTCDate(), daysInTargetMonth));
|
|
3383
|
+
return targetMonthStart.getTime();
|
|
3384
|
+
};
|
|
3385
|
+
var nextUtcDayStart = (ms) => dayStartUtc(ms) + DAY_MS3;
|
|
3386
|
+
var resolveCoinMarketCapBackfillWindow = (params) => {
|
|
3387
|
+
const warmupMs = asInt3(process.env.COINMARKETCAP_CONTEXT_BACKFILL_WARMUP_DAYS, 35) * DAY_MS3;
|
|
3388
|
+
const maxWindowMs = getMaxBackfillDays() * DAY_MS3;
|
|
3389
|
+
const requestedStart = params.preloadStartMs ?? params.startMs - warmupMs;
|
|
3390
|
+
const cappedStart = Math.max(requestedStart, params.endMs - maxWindowMs);
|
|
3391
|
+
const accessFloorMs = nextUtcDayStart(
|
|
3392
|
+
subtractUtcMonths(params.nowMs ?? Date.now(), getHistoricalAccessMonths())
|
|
3393
|
+
);
|
|
3394
|
+
return {
|
|
3395
|
+
fromMs: dayStartUtc(Math.max(cappedStart, accessFloorMs)),
|
|
3396
|
+
toMs: dayStartUtc(params.endMs)
|
|
3397
|
+
};
|
|
3398
|
+
};
|
|
3399
|
+
var hasIntervalCoverage = (coverage, fromMs, toMs, intervalMs) => {
|
|
3400
|
+
if (!coverage) return false;
|
|
3401
|
+
const expectedRows = Math.max(1, Math.floor((toMs - fromMs) / intervalMs));
|
|
3402
|
+
return coverage.firstMs <= fromMs + intervalMs && coverage.lastMs >= toMs - intervalMs && coverage.rows >= Math.floor(expectedRows * 0.9);
|
|
3403
|
+
};
|
|
3404
|
+
var hasDailyCoverage = (coverage, fromMs, toMs) => hasIntervalCoverage(coverage, fromMs, toMs, DAY_MS3);
|
|
3405
|
+
var coverageKey2 = (params) => [
|
|
3406
|
+
params.source.trim().toLowerCase(),
|
|
3407
|
+
params.scope.trim().toLowerCase(),
|
|
3408
|
+
params.interval.trim().toLowerCase(),
|
|
3409
|
+
Math.trunc(params.fromMs),
|
|
3410
|
+
Math.trunc(params.toMs)
|
|
3411
|
+
].join(":");
|
|
3412
|
+
var isMarketContextBackfillCoverageDataBearing = (row) => Number(row.rowsCount ?? 0) > 0;
|
|
3413
|
+
var coverageRowsToKeySet = (rows) => new Set(
|
|
3414
|
+
rows.filter(isMarketContextBackfillCoverageDataBearing).map(
|
|
3415
|
+
(row) => coverageKey2({
|
|
3416
|
+
source: row.source,
|
|
3417
|
+
scope: row.scope,
|
|
3418
|
+
interval: row.interval,
|
|
3419
|
+
fromMs: row.fromMs,
|
|
3420
|
+
toMs: row.toMs
|
|
3421
|
+
})
|
|
3422
|
+
)
|
|
3423
|
+
);
|
|
3424
|
+
var hasBackfillCoverage = (coverageKeys, params) => coverageKeys.has(coverageKey2(params));
|
|
3425
|
+
var formatCoverageRange = (coverage) => {
|
|
3426
|
+
if (!coverage) return "coverage=none";
|
|
3427
|
+
return `coverage=${new Date(coverage.firstMs).toISOString()}..${new Date(
|
|
3428
|
+
coverage.lastMs
|
|
3429
|
+
).toISOString()} rows=${coverage.rows}`;
|
|
3430
|
+
};
|
|
3431
|
+
var formatReferenceCoverage = (coverage) => REFERENCE_ASSETS.map(
|
|
3432
|
+
(asset) => `${asset.symbol}:${formatCoverageRange(coverage.get(asset.symbol))}`
|
|
3433
|
+
).join(" ");
|
|
3434
|
+
var resolveBackfillStatus = ({
|
|
3435
|
+
enabled = true,
|
|
3436
|
+
cached,
|
|
3437
|
+
covered
|
|
3438
|
+
}) => {
|
|
3439
|
+
if (!enabled) return "disabled";
|
|
3440
|
+
if (cached) return "cached";
|
|
3441
|
+
if (covered) return "backfill_covered";
|
|
3442
|
+
return "fetch_pending";
|
|
3443
|
+
};
|
|
3444
|
+
var formatSourceStatus = ({
|
|
3445
|
+
name,
|
|
3446
|
+
status,
|
|
3447
|
+
rows,
|
|
3448
|
+
coverage
|
|
3449
|
+
}) => `${name}=${status}${rows == null ? "" : ` rows=${rows}`} ${coverage}`;
|
|
3450
|
+
var createCoinMarketCapFetchStats = () => ({
|
|
3451
|
+
requests: 0,
|
|
3452
|
+
totalCredits: 0,
|
|
3453
|
+
byPath: /* @__PURE__ */ new Map()
|
|
3454
|
+
});
|
|
3455
|
+
var getCoinMarketCapPathLabel = (path) => {
|
|
3456
|
+
if (path.includes("global-metrics")) return "global";
|
|
3457
|
+
if (path.includes("cryptocurrency/quotes")) return "reference";
|
|
3458
|
+
if (path.includes("exchange/quotes")) return "exchangeLiquidity";
|
|
3459
|
+
if (path.includes("fear-and-greed")) return "fearGreed";
|
|
3460
|
+
if (path.includes("cmc100")) return "cmc100";
|
|
3461
|
+
if (path.includes("cmc20")) return "cmc20";
|
|
3462
|
+
return path;
|
|
3463
|
+
};
|
|
3464
|
+
var recordCoinMarketCapFetchStats = (stats, path, creditCount) => {
|
|
3465
|
+
if (!stats) return;
|
|
3466
|
+
const existing = stats.byPath.get(path) ?? { requests: 0, credits: 0 };
|
|
3467
|
+
existing.requests += 1;
|
|
3468
|
+
existing.credits += creditCount ?? 0;
|
|
3469
|
+
stats.requests += 1;
|
|
3470
|
+
stats.totalCredits += creditCount ?? 0;
|
|
3471
|
+
stats.byPath.set(path, existing);
|
|
3472
|
+
};
|
|
3473
|
+
var formatCoinMarketCapFetchStats = (stats) => {
|
|
3474
|
+
const byPath = [...stats.byPath.entries()].map(
|
|
3475
|
+
([path, item]) => `${getCoinMarketCapPathLabel(path)}=${item.requests}req/${item.credits}cr`
|
|
3476
|
+
).join(" ");
|
|
3477
|
+
return `apiRequests=${stats.requests} apiCredits=${stats.totalCredits}${byPath ? ` ${byPath}` : ""}`;
|
|
3478
|
+
};
|
|
3479
|
+
var formatRowTimeRange = (rows) => {
|
|
3480
|
+
if (!rows.length) return "range=none";
|
|
3481
|
+
const times = rows.map((row) => row.ts.getTime()).filter((value) => Number.isFinite(value));
|
|
3482
|
+
if (!times.length) return "range=none";
|
|
3483
|
+
return `range=${new Date(Math.min(...times)).toISOString()}..${new Date(
|
|
3484
|
+
Math.max(...times)
|
|
3485
|
+
).toISOString()}`;
|
|
3486
|
+
};
|
|
3487
|
+
var logBackfillSourceDone = (params) => {
|
|
3488
|
+
console.log(
|
|
3489
|
+
import_chalk3.default.gray(
|
|
3490
|
+
`coinmarketcap context source done: ${params.name}=${params.status} rows=${params.rows}${params.details ? ` ${params.details}` : ""}`
|
|
3491
|
+
)
|
|
3492
|
+
);
|
|
3493
|
+
};
|
|
3494
|
+
var markBackfillCoverage = (rows) => (0, import_timescale3.upsertMarketContextBackfillCoverage)(rows);
|
|
3495
|
+
var coinMarketCapFetch = async (params) => {
|
|
3496
|
+
const url = new URL(`${getBaseUrl()}${params.path}`);
|
|
3497
|
+
for (const [key, value] of Object.entries(params.searchParams)) {
|
|
3498
|
+
url.searchParams.set(key, value);
|
|
3499
|
+
}
|
|
3500
|
+
for (let attempt = 0; attempt <= getMaxRetries(); attempt += 1) {
|
|
3501
|
+
const waitMs = Math.max(
|
|
3502
|
+
0,
|
|
3503
|
+
lastRequestTs2 + getRequestDelayMs2() - Date.now()
|
|
3504
|
+
);
|
|
3505
|
+
if (waitMs > 0) {
|
|
3506
|
+
await (0, import_async2.delay)(waitMs);
|
|
3507
|
+
}
|
|
3508
|
+
lastRequestTs2 = Date.now();
|
|
3509
|
+
const response = await fetch(url.toString(), {
|
|
3510
|
+
headers: {
|
|
3511
|
+
accept: "application/json",
|
|
3512
|
+
"X-CMC_PRO_API_KEY": params.apiKey
|
|
3513
|
+
}
|
|
3514
|
+
});
|
|
3515
|
+
if (response.ok) {
|
|
3516
|
+
const payload = await response.json();
|
|
3517
|
+
const creditCount = toFiniteNumberOrNull(
|
|
3518
|
+
getRecord(getRecord(payload).status).credit_count
|
|
3519
|
+
);
|
|
3520
|
+
recordCoinMarketCapFetchStats(params.stats, params.path, creditCount);
|
|
3521
|
+
if (creditCount != null && isVerboseRequestLoggingEnabled()) {
|
|
3522
|
+
console.log(
|
|
3523
|
+
import_chalk3.default.gray(`coinmarketcap ${params.path}: credits=${creditCount}`)
|
|
3524
|
+
);
|
|
3525
|
+
}
|
|
3526
|
+
return payload;
|
|
3527
|
+
}
|
|
3528
|
+
const text = await response.text();
|
|
3529
|
+
const retryAfterRaw = Number(response.headers.get("retry-after") ?? "");
|
|
3530
|
+
const retryAfterMs = Number.isFinite(retryAfterRaw) && retryAfterRaw > 0 ? retryAfterRaw * 1e3 : null;
|
|
3531
|
+
const transient = response.status === 429 || response.status >= 500;
|
|
3532
|
+
if (attempt < getMaxRetries() && transient) {
|
|
3533
|
+
await (0, import_async2.delay)(retryAfterMs ?? Math.min(3e4, 1e3 * 2 ** attempt));
|
|
3534
|
+
continue;
|
|
3535
|
+
}
|
|
3536
|
+
throw new Error(`CoinMarketCap ${params.path} ${response.status}: ${text}`);
|
|
3537
|
+
}
|
|
3538
|
+
return null;
|
|
3539
|
+
};
|
|
3540
|
+
var fetchCoinMarketCapIndexRows = async (params) => {
|
|
3541
|
+
const rows = [];
|
|
3542
|
+
const maxChunkDays = 9;
|
|
3543
|
+
const totalChunks = Math.max(
|
|
3544
|
+
1,
|
|
3545
|
+
Math.ceil(
|
|
3546
|
+
(params.toMs - params.fromMs + DAY_MS3) / ((maxChunkDays + 1) * DAY_MS3)
|
|
3547
|
+
)
|
|
3548
|
+
);
|
|
3549
|
+
let chunk = 0;
|
|
3550
|
+
for (let cursorMs = params.fromMs; cursorMs <= params.toMs; cursorMs += (maxChunkDays + 1) * DAY_MS3) {
|
|
3551
|
+
chunk += 1;
|
|
3552
|
+
const chunkEndMs = Math.min(params.toMs, cursorMs + maxChunkDays * DAY_MS3);
|
|
3553
|
+
const payload = await coinMarketCapFetch({
|
|
3554
|
+
path: params.index.path,
|
|
3555
|
+
apiKey: params.apiKey,
|
|
3556
|
+
stats: params.stats,
|
|
3557
|
+
searchParams: {
|
|
3558
|
+
time_start: new Date(cursorMs).toISOString(),
|
|
3559
|
+
time_end: new Date(chunkEndMs).toISOString(),
|
|
3560
|
+
interval: "daily"
|
|
3561
|
+
}
|
|
3562
|
+
});
|
|
3563
|
+
rows.push(
|
|
3564
|
+
...coinMarketCapIndexPayloadToRows(payload, params.index.slug, "1d")
|
|
3565
|
+
);
|
|
3566
|
+
if (chunk === 1 || chunk === totalChunks || chunk % 25 === 0) {
|
|
3567
|
+
console.log(
|
|
3568
|
+
import_chalk3.default.gray(
|
|
3569
|
+
`coinmarketcap index backfill progress: ${params.index.slug} chunk=${chunk}/${totalChunks} rows=${rows.length} chunkRange=${new Date(cursorMs).toISOString()}..${new Date(chunkEndMs).toISOString()}`
|
|
3570
|
+
)
|
|
3571
|
+
);
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
return { rows, chunks: chunk };
|
|
3575
|
+
};
|
|
3576
|
+
var coinMarketCapGlobalPayloadToRows = (payload, source = SOURCE_GLOBAL_DAILY) => {
|
|
3577
|
+
const quotes = getRecord(getRecord(payload).data).quotes;
|
|
3578
|
+
if (!Array.isArray(quotes)) return [];
|
|
3579
|
+
return quotes.map((item) => {
|
|
3580
|
+
const record = getRecord(item);
|
|
3581
|
+
const quote = getRecord(getRecord(record.quote).USD);
|
|
3582
|
+
const tsRaw = record.timestamp ?? quote.timestamp;
|
|
3583
|
+
const ts = typeof tsRaw === "string" ? new Date(tsRaw) : null;
|
|
3584
|
+
if (!ts || Number.isNaN(ts.getTime())) return null;
|
|
3585
|
+
const totalMarketCapUsd = toFiniteNumberOrNull(quote.total_market_cap);
|
|
3586
|
+
const altMarketCapUsd = toFiniteNumberOrNull(quote.altcoin_market_cap);
|
|
3587
|
+
const btcToAltMarketCapRatio = totalMarketCapUsd != null && altMarketCapUsd != null && altMarketCapUsd > 0 ? Math.max(0, totalMarketCapUsd - altMarketCapUsd) / altMarketCapUsd : null;
|
|
3588
|
+
return {
|
|
3589
|
+
source,
|
|
3590
|
+
ts,
|
|
3591
|
+
updatedAt: ts,
|
|
3592
|
+
activeCryptocurrencies: toIntOrNull(record.active_cryptocurrencies),
|
|
3593
|
+
activeExchanges: toIntOrNull(record.active_exchanges),
|
|
3594
|
+
activeMarketPairs: toIntOrNull(record.active_market_pairs),
|
|
3595
|
+
markets: toIntOrNull(record.active_exchanges),
|
|
3596
|
+
totalMarketCapUsd,
|
|
3597
|
+
totalVolumeUsd: toFiniteNumberOrNull(quote.total_volume_24h),
|
|
3598
|
+
totalVolumeReportedUsd: toFiniteNumberOrNull(
|
|
3599
|
+
quote.total_volume_24h_reported
|
|
3600
|
+
),
|
|
3601
|
+
btcDominancePct: toFiniteNumberOrNull(record.btc_dominance),
|
|
3602
|
+
ethDominancePct: toFiniteNumberOrNull(record.eth_dominance),
|
|
3603
|
+
altMarketCapUsd,
|
|
3604
|
+
altVolumeUsd: toFiniteNumberOrNull(quote.altcoin_volume_24h),
|
|
3605
|
+
altVolumeReportedUsd: toFiniteNumberOrNull(
|
|
3606
|
+
quote.altcoin_volume_24h_reported
|
|
3607
|
+
),
|
|
3608
|
+
btcToAltMarketCapRatio,
|
|
3609
|
+
marketCapChangePct24hUsd: null
|
|
3610
|
+
};
|
|
3611
|
+
}).filter((row) => row != null);
|
|
3612
|
+
};
|
|
3613
|
+
var normalizeAssetDataItems = (payload) => {
|
|
3614
|
+
const data = getRecord(payload).data;
|
|
3615
|
+
if (!data) return [];
|
|
3616
|
+
if (Array.isArray(data)) {
|
|
3617
|
+
return data.filter(
|
|
3618
|
+
(item) => item != null && typeof item === "object" && !Array.isArray(item)
|
|
3619
|
+
);
|
|
3620
|
+
}
|
|
3621
|
+
if (typeof data === "object" && !Array.isArray(data)) {
|
|
3622
|
+
const record = data;
|
|
3623
|
+
if (Array.isArray(record.quotes)) return [record];
|
|
3624
|
+
return Object.values(record).filter(
|
|
3625
|
+
(item) => item != null && typeof item === "object" && !Array.isArray(item)
|
|
3626
|
+
);
|
|
3627
|
+
}
|
|
3628
|
+
return [];
|
|
3629
|
+
};
|
|
3630
|
+
var coinMarketCapHistoricalQuotesPayloadToRows = (payload, interval = "1d") => {
|
|
3631
|
+
return normalizeAssetDataItems(payload).flatMap((asset) => {
|
|
3632
|
+
const cmcId = toIntOrNull(asset.id);
|
|
3633
|
+
const symbolRaw = String(asset.symbol ?? "").trim().toUpperCase();
|
|
3634
|
+
const target = REFERENCE_ASSETS.find(
|
|
3635
|
+
(item) => item.cmcId === cmcId || item.symbol.replace("USDT", "") === symbolRaw
|
|
3636
|
+
);
|
|
3637
|
+
const quotes = Array.isArray(asset.quotes) ? asset.quotes : Object.values(getRecord(asset.quotes));
|
|
3638
|
+
if (!target || !cmcId || !quotes.length) return [];
|
|
3639
|
+
return quotes.map((item) => {
|
|
3640
|
+
const record = getRecord(item);
|
|
3641
|
+
const quote = getNestedRecord(getRecord(record.quote), "USD");
|
|
3642
|
+
const tsRaw = record.timestamp ?? quote.timestamp ?? quote.last_updated;
|
|
3643
|
+
const ts = typeof tsRaw === "string" ? new Date(tsRaw) : null;
|
|
3644
|
+
if (!ts || Number.isNaN(ts.getTime())) return null;
|
|
3645
|
+
return {
|
|
3646
|
+
source: SOURCE_REFERENCE,
|
|
3647
|
+
symbol: target.symbol,
|
|
3648
|
+
cmcId,
|
|
3649
|
+
interval,
|
|
3650
|
+
ts,
|
|
3651
|
+
openUsd: null,
|
|
3652
|
+
highUsd: null,
|
|
3653
|
+
lowUsd: null,
|
|
3654
|
+
closeUsd: toFiniteNumberOrNull(quote.price),
|
|
3655
|
+
volumeUsd: toFiniteNumberOrNull(quote.volume_24h),
|
|
3656
|
+
marketCapUsd: toFiniteNumberOrNull(quote.market_cap)
|
|
3657
|
+
};
|
|
3658
|
+
}).filter((row) => row != null);
|
|
3659
|
+
});
|
|
3660
|
+
};
|
|
3661
|
+
var coinMarketCapExchangeQuotesPayloadToLiquidityRows = (payload, interval = "1d") => {
|
|
3662
|
+
const data = getRecord(payload).data;
|
|
3663
|
+
const exchangeItems = Array.isArray(data) ? data : Object.values(getRecord(data));
|
|
3664
|
+
const rowsByTs = /* @__PURE__ */ new Map();
|
|
3665
|
+
for (const item of exchangeItems) {
|
|
3666
|
+
const exchange = getRecord(item);
|
|
3667
|
+
const slug = String(exchange.slug ?? "").trim().toLowerCase();
|
|
3668
|
+
const name = String(exchange.name ?? "").trim().toLowerCase();
|
|
3669
|
+
const quotes = Array.isArray(exchange.quotes) ? exchange.quotes : Array.isArray(exchange.quote) ? exchange.quote : [exchange];
|
|
3670
|
+
for (const quoteItem of quotes) {
|
|
3671
|
+
const record = getRecord(quoteItem);
|
|
3672
|
+
const quote = getNestedRecord(getNestedRecord(record, "quote"), "USD");
|
|
3673
|
+
const fallbackQuote = getNestedRecord(exchange, "quote");
|
|
3674
|
+
const usd = Object.keys(quote).length ? quote : getNestedRecord(fallbackQuote, "USD");
|
|
3675
|
+
const tsRaw = record.timestamp ?? usd.timestamp ?? usd.last_updated ?? exchange.last_updated;
|
|
3676
|
+
const ts = typeof tsRaw === "string" ? new Date(tsRaw) : null;
|
|
3677
|
+
if (!ts || Number.isNaN(ts.getTime())) continue;
|
|
3678
|
+
const volumeUsd = toFiniteNumberOrNull(usd.volume_24h) ?? toFiniteNumberOrNull(usd.volume_24h_adjusted) ?? toFiniteNumberOrNull(usd.spot_volume_usd) ?? toFiniteNumberOrNull(usd.reported_volume_24h);
|
|
3679
|
+
const key = ts.getTime();
|
|
3680
|
+
const rows = rowsByTs.get(key) ?? [];
|
|
3681
|
+
rows.push({ slug, name, volumeUsd });
|
|
3682
|
+
rowsByTs.set(key, rows);
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
return [...rowsByTs.entries()].sort(([left], [right]) => left - right).map(([ts, exchanges]) => {
|
|
3686
|
+
const volumes = exchanges.map((exchange) => exchange.volumeUsd);
|
|
3687
|
+
const totalVolumeUsd = sumFinite(volumes);
|
|
3688
|
+
const binanceVolumeUsd = exchanges.find(
|
|
3689
|
+
(exchange) => exchange.slug === "binance" || exchange.name.includes("binance")
|
|
3690
|
+
)?.volumeUsd ?? null;
|
|
3691
|
+
const topExchangeVolume = Math.max(
|
|
3692
|
+
...volumes.map((value) => value ?? 0),
|
|
3693
|
+
0
|
|
3694
|
+
);
|
|
3695
|
+
const binanceVolumeShare = safeDivide2(binanceVolumeUsd, totalVolumeUsd);
|
|
3696
|
+
const topExchangeVolumeShare = safeDivide2(
|
|
3697
|
+
topExchangeVolume,
|
|
3698
|
+
totalVolumeUsd
|
|
3699
|
+
);
|
|
3700
|
+
return {
|
|
3701
|
+
source: SOURCE_EXCHANGE_LIQUIDITY,
|
|
3702
|
+
interval,
|
|
3703
|
+
ts: new Date(ts),
|
|
3704
|
+
exchangesCount: exchanges.length,
|
|
3705
|
+
totalVolumeUsd,
|
|
3706
|
+
binanceVolumeUsd,
|
|
3707
|
+
binanceVolumeShare,
|
|
3708
|
+
topExchangeVolumeShare,
|
|
3709
|
+
liquidityRegime: toExchangeLiquidityRegime({
|
|
3710
|
+
binanceVolumeShare,
|
|
3711
|
+
topExchangeVolumeShare
|
|
3712
|
+
})
|
|
3713
|
+
};
|
|
3714
|
+
});
|
|
3715
|
+
};
|
|
3716
|
+
var coinMarketCapFearGreedPayloadToRows = (payload) => {
|
|
3717
|
+
const data = getRecord(payload).data;
|
|
3718
|
+
const items = Array.isArray(data) ? data : [];
|
|
3719
|
+
return items.map((item) => {
|
|
3720
|
+
const record = getRecord(item);
|
|
3721
|
+
const timestampValue = toFiniteNumberOrNull(record.timestamp);
|
|
3722
|
+
const value = toIntOrNull(record.value);
|
|
3723
|
+
if (timestampValue == null || value == null) return null;
|
|
3724
|
+
const ts = new Date(timestampValue * 1e3);
|
|
3725
|
+
if (Number.isNaN(ts.getTime())) return null;
|
|
3726
|
+
const classification = normalizeFearGreedClassification(
|
|
3727
|
+
record.value_classification
|
|
3728
|
+
);
|
|
3729
|
+
return {
|
|
3730
|
+
source: SOURCE_FEAR_GREED,
|
|
3731
|
+
interval: "1d",
|
|
3732
|
+
ts,
|
|
3733
|
+
value,
|
|
3734
|
+
classification,
|
|
3735
|
+
sentimentRegime: toFearGreedRegime({ value, classification })
|
|
3736
|
+
};
|
|
3737
|
+
}).filter((row) => row != null);
|
|
3738
|
+
};
|
|
3739
|
+
var toCmcIndexWeightPct = (value) => {
|
|
3740
|
+
if (typeof value === "string") {
|
|
3741
|
+
return toFiniteNumberOrNull(value.replace("%", ""));
|
|
3742
|
+
}
|
|
3743
|
+
return toFiniteNumberOrNull(value);
|
|
3744
|
+
};
|
|
3745
|
+
var coinMarketCapIndexPayloadToRows = (payload, indexSlug, interval = "1d") => {
|
|
3746
|
+
const data = getRecord(payload).data;
|
|
3747
|
+
const items = Array.isArray(data) ? data : [];
|
|
3748
|
+
return items.map((item) => {
|
|
3749
|
+
const record = getRecord(item);
|
|
3750
|
+
const tsRaw = record.update_time ?? record.timestamp;
|
|
3751
|
+
const ts = typeof tsRaw === "string" ? new Date(tsRaw) : null;
|
|
3752
|
+
const value = toFiniteNumberOrNull(record.value);
|
|
3753
|
+
if (!ts || Number.isNaN(ts.getTime()) || value == null) return null;
|
|
3754
|
+
const constituentsRaw = Array.isArray(record.constituents) ? record.constituents : [];
|
|
3755
|
+
const constituents = constituentsRaw.map((constituent) => {
|
|
3756
|
+
const constituentRecord = getRecord(constituent);
|
|
3757
|
+
return {
|
|
3758
|
+
id: toIntOrNull(constituentRecord.id),
|
|
3759
|
+
name: typeof constituentRecord.name === "string" ? constituentRecord.name : null,
|
|
3760
|
+
symbol: typeof constituentRecord.symbol === "string" ? constituentRecord.symbol : null,
|
|
3761
|
+
url: typeof constituentRecord.url === "string" ? constituentRecord.url : null,
|
|
3762
|
+
weightPct: toCmcIndexWeightPct(constituentRecord.weight),
|
|
3763
|
+
priceUsd: toFiniteNumberOrNull(constituentRecord.priceUsd),
|
|
3764
|
+
units: toFiniteNumberOrNull(constituentRecord.units)
|
|
3765
|
+
};
|
|
3766
|
+
});
|
|
3767
|
+
const topConstituent = constituents.reduce((top, constituent) => {
|
|
3768
|
+
if (top == null) return constituent;
|
|
3769
|
+
return (constituent.weightPct ?? Number.NEGATIVE_INFINITY) > (top.weightPct ?? Number.NEGATIVE_INFINITY) ? constituent : top;
|
|
3770
|
+
}, null);
|
|
3771
|
+
return {
|
|
3772
|
+
source: SOURCE_INDEX,
|
|
3773
|
+
indexSlug,
|
|
3774
|
+
interval,
|
|
3775
|
+
ts,
|
|
3776
|
+
value,
|
|
3777
|
+
constituentsCount: constituents.length,
|
|
3778
|
+
topConstituentSymbol: topConstituent?.symbol ?? null,
|
|
3779
|
+
topConstituentWeightPct: topConstituent?.weightPct ?? null,
|
|
3780
|
+
constituents
|
|
3781
|
+
};
|
|
3782
|
+
}).filter((row) => row != null);
|
|
3783
|
+
};
|
|
3784
|
+
var shouldBackfillCoinMarketCapContextForMode = ({
|
|
3785
|
+
mode,
|
|
3786
|
+
aiEnabled,
|
|
3787
|
+
cacheOnly,
|
|
3788
|
+
mlEnabled
|
|
3789
|
+
}) => parseEnabledFlag2(
|
|
3790
|
+
process.env.COINMARKETCAP_CONTEXT_BACKFILL_ENABLED,
|
|
3791
|
+
mode === "backtest" ? (Boolean(aiEnabled) || Boolean(mlEnabled)) && !cacheOnly : !cacheOnly
|
|
3792
|
+
);
|
|
3793
|
+
var shouldBackfillCoinMarketCapContextForBacktest = (params) => shouldBackfillCoinMarketCapContextForMode({
|
|
3794
|
+
mode: "backtest",
|
|
3795
|
+
...params
|
|
3796
|
+
});
|
|
3797
|
+
var shouldBackfillCoinMarketCapContextForReplay = (params) => shouldBackfillCoinMarketCapContextForMode({
|
|
3798
|
+
mode: "replay",
|
|
3799
|
+
...params
|
|
3800
|
+
});
|
|
3801
|
+
var shouldBackfillCoinMarketCapContextForSignals = (params) => shouldBackfillCoinMarketCapContextForMode({
|
|
3802
|
+
mode: "signals",
|
|
3803
|
+
...params
|
|
3804
|
+
});
|
|
3805
|
+
var skippedResult = (cached = false) => ({
|
|
3806
|
+
skipped: true,
|
|
3807
|
+
globalRows: 0,
|
|
3808
|
+
referenceRows: 0,
|
|
3809
|
+
breadthRows: 0,
|
|
3810
|
+
exchangeLiquidityRows: 0,
|
|
3811
|
+
fearGreedRows: 0,
|
|
3812
|
+
indexRows: 0,
|
|
3813
|
+
cached
|
|
3814
|
+
});
|
|
3815
|
+
var backfillCoinMarketCapContext = async (params) => {
|
|
3816
|
+
if (!Number.isFinite(params.startMs) || !Number.isFinite(params.endMs)) {
|
|
3817
|
+
return skippedResult();
|
|
3818
|
+
}
|
|
3819
|
+
const { fromMs, toMs } = resolveCoinMarketCapBackfillWindow(params);
|
|
3820
|
+
if (toMs <= fromMs) return skippedResult();
|
|
3821
|
+
const exchangeLiquidityEnabled = isExchangeLiquidityBackfillEnabled();
|
|
3822
|
+
const fearGreedEnabled = isFearGreedBackfillEnabled();
|
|
3823
|
+
await (0, import_timescale3.waitForDbReady)();
|
|
3824
|
+
const [
|
|
3825
|
+
globalDailyCoverage,
|
|
3826
|
+
referenceDailyCoverage,
|
|
3827
|
+
exchangeLiquidityCoverage,
|
|
3828
|
+
fearGreedCoverage,
|
|
3829
|
+
indexCoverage,
|
|
3830
|
+
globalDailyBackfillCoverage,
|
|
3831
|
+
referenceDailyBackfillCoverage,
|
|
3832
|
+
exchangeLiquidityBackfillCoverage,
|
|
3833
|
+
fearGreedBackfillCoverage,
|
|
3834
|
+
indexBackfillCoverage
|
|
3835
|
+
] = await Promise.all([
|
|
3836
|
+
(0, import_timescale3.getMarketGlobalContextCoverage)({
|
|
3837
|
+
source: SOURCE_GLOBAL_DAILY,
|
|
3838
|
+
startMs: fromMs,
|
|
3839
|
+
endMs: toMs
|
|
3840
|
+
}),
|
|
3841
|
+
(0, import_timescale3.getMarketReferenceAssetContextCoverage)({
|
|
3842
|
+
source: SOURCE_REFERENCE,
|
|
3843
|
+
symbols: REFERENCE_ASSETS.map((item) => item.symbol),
|
|
3844
|
+
interval: "1d",
|
|
3845
|
+
startMs: fromMs,
|
|
3846
|
+
endMs: toMs
|
|
3847
|
+
}),
|
|
3848
|
+
exchangeLiquidityEnabled ? (0, import_timescale3.getMarketCmcExchangeLiquidityContextCoverage)({
|
|
3849
|
+
source: SOURCE_EXCHANGE_LIQUIDITY,
|
|
3850
|
+
interval: "1d",
|
|
3851
|
+
startMs: fromMs,
|
|
3852
|
+
endMs: toMs
|
|
3853
|
+
}) : Promise.resolve(null),
|
|
3854
|
+
fearGreedEnabled ? (0, import_timescale3.getMarketCmcFearGreedContextCoverage)({
|
|
3855
|
+
source: SOURCE_FEAR_GREED,
|
|
3856
|
+
interval: "1d",
|
|
3857
|
+
startMs: fromMs,
|
|
3858
|
+
endMs: toMs
|
|
3859
|
+
}) : Promise.resolve(null),
|
|
3860
|
+
(0, import_timescale3.getMarketCmcIndexContextCoverage)({
|
|
3861
|
+
source: SOURCE_INDEX,
|
|
3862
|
+
indexSlugs: CMC_INDEXES.map((index) => index.slug),
|
|
3863
|
+
interval: "1d",
|
|
3864
|
+
startMs: fromMs,
|
|
3865
|
+
endMs: toMs
|
|
3866
|
+
}),
|
|
3867
|
+
(0, import_timescale3.getMarketContextBackfillCoverage)({
|
|
3868
|
+
source: SOURCE_GLOBAL_DAILY,
|
|
3869
|
+
scopes: [COVERAGE_SCOPE_ALL],
|
|
3870
|
+
interval: "1d",
|
|
3871
|
+
fromMs,
|
|
3872
|
+
toMs
|
|
3873
|
+
}),
|
|
3874
|
+
(0, import_timescale3.getMarketContextBackfillCoverage)({
|
|
3875
|
+
source: SOURCE_REFERENCE,
|
|
3876
|
+
scopes: REFERENCE_ASSETS.map((item) => item.symbol),
|
|
3877
|
+
interval: "1d",
|
|
3878
|
+
fromMs,
|
|
3879
|
+
toMs
|
|
3880
|
+
}),
|
|
3881
|
+
exchangeLiquidityEnabled ? (0, import_timescale3.getMarketContextBackfillCoverage)({
|
|
3882
|
+
source: SOURCE_EXCHANGE_LIQUIDITY,
|
|
3883
|
+
scopes: [COVERAGE_SCOPE_ALL],
|
|
3884
|
+
interval: "1d",
|
|
3885
|
+
fromMs,
|
|
3886
|
+
toMs
|
|
3887
|
+
}) : Promise.resolve([]),
|
|
3888
|
+
fearGreedEnabled ? (0, import_timescale3.getMarketContextBackfillCoverage)({
|
|
3889
|
+
source: SOURCE_FEAR_GREED,
|
|
3890
|
+
scopes: [COVERAGE_SCOPE_ALL],
|
|
3891
|
+
interval: "1d",
|
|
3892
|
+
fromMs,
|
|
3893
|
+
toMs
|
|
3894
|
+
}) : Promise.resolve([]),
|
|
3895
|
+
(0, import_timescale3.getMarketContextBackfillCoverage)({
|
|
3896
|
+
source: SOURCE_INDEX,
|
|
3897
|
+
scopes: CMC_INDEXES.map((index) => index.slug),
|
|
3898
|
+
interval: "1d",
|
|
3899
|
+
fromMs,
|
|
3900
|
+
toMs
|
|
3901
|
+
})
|
|
3902
|
+
]);
|
|
3903
|
+
const globalDailyBackfillKeys = coverageRowsToKeySet(
|
|
3904
|
+
globalDailyBackfillCoverage
|
|
3905
|
+
);
|
|
3906
|
+
const referenceDailyBackfillKeys = coverageRowsToKeySet(
|
|
3907
|
+
referenceDailyBackfillCoverage
|
|
3908
|
+
);
|
|
3909
|
+
const exchangeLiquidityBackfillKeys = coverageRowsToKeySet(
|
|
3910
|
+
exchangeLiquidityBackfillCoverage
|
|
3911
|
+
);
|
|
3912
|
+
const fearGreedBackfillKeys = coverageRowsToKeySet(fearGreedBackfillCoverage);
|
|
3913
|
+
const indexBackfillKeys = coverageRowsToKeySet(indexBackfillCoverage);
|
|
3914
|
+
const globalDailyCached = hasDailyCoverage(globalDailyCoverage, fromMs, toMs);
|
|
3915
|
+
const referencesDailyCached = REFERENCE_ASSETS.every(
|
|
3916
|
+
(asset) => hasDailyCoverage(referenceDailyCoverage.get(asset.symbol), fromMs, toMs)
|
|
3917
|
+
);
|
|
3918
|
+
const exchangeLiquidityCached = !exchangeLiquidityEnabled || hasDailyCoverage(exchangeLiquidityCoverage, fromMs, toMs);
|
|
3919
|
+
const fearGreedCached = !fearGreedEnabled || hasDailyCoverage(fearGreedCoverage, fromMs, toMs);
|
|
3920
|
+
const indexesCached = CMC_INDEXES.every(
|
|
3921
|
+
(index) => hasDailyCoverage(indexCoverage.get(index.slug), fromMs, toMs)
|
|
3922
|
+
);
|
|
3923
|
+
const globalDailyBackfillCovered = hasBackfillCoverage(
|
|
3924
|
+
globalDailyBackfillKeys,
|
|
3925
|
+
{
|
|
3926
|
+
source: SOURCE_GLOBAL_DAILY,
|
|
3927
|
+
scope: COVERAGE_SCOPE_ALL,
|
|
3928
|
+
interval: "1d",
|
|
3929
|
+
fromMs,
|
|
3930
|
+
toMs
|
|
3931
|
+
}
|
|
3932
|
+
);
|
|
3933
|
+
const referencesDailyBackfillCovered = REFERENCE_ASSETS.every(
|
|
3934
|
+
(asset) => hasBackfillCoverage(referenceDailyBackfillKeys, {
|
|
3935
|
+
source: SOURCE_REFERENCE,
|
|
3936
|
+
scope: asset.symbol,
|
|
3937
|
+
interval: "1d",
|
|
3938
|
+
fromMs,
|
|
3939
|
+
toMs
|
|
3940
|
+
})
|
|
3941
|
+
);
|
|
3942
|
+
const exchangeLiquidityBackfillCovered = hasBackfillCoverage(
|
|
3943
|
+
exchangeLiquidityBackfillKeys,
|
|
3944
|
+
{
|
|
3945
|
+
source: SOURCE_EXCHANGE_LIQUIDITY,
|
|
3946
|
+
scope: COVERAGE_SCOPE_ALL,
|
|
3947
|
+
interval: "1d",
|
|
3948
|
+
fromMs,
|
|
3949
|
+
toMs
|
|
3950
|
+
}
|
|
3951
|
+
);
|
|
3952
|
+
const fearGreedBackfillCovered = hasBackfillCoverage(fearGreedBackfillKeys, {
|
|
3953
|
+
source: SOURCE_FEAR_GREED,
|
|
3954
|
+
scope: COVERAGE_SCOPE_ALL,
|
|
3955
|
+
interval: "1d",
|
|
3956
|
+
fromMs,
|
|
3957
|
+
toMs
|
|
3958
|
+
});
|
|
3959
|
+
const indexesBackfillCovered = CMC_INDEXES.every(
|
|
3960
|
+
(index) => hasBackfillCoverage(indexBackfillKeys, {
|
|
3961
|
+
source: SOURCE_INDEX,
|
|
3962
|
+
scope: index.slug,
|
|
3963
|
+
interval: "1d",
|
|
3964
|
+
fromMs,
|
|
3965
|
+
toMs
|
|
3966
|
+
})
|
|
3967
|
+
);
|
|
3968
|
+
const globalDailyReady = globalDailyCached || globalDailyBackfillCovered;
|
|
3969
|
+
const referencesDailyReady = referencesDailyCached || referencesDailyBackfillCovered;
|
|
3970
|
+
const exchangeLiquidityReady = exchangeLiquidityCached || !exchangeLiquidityEnabled || exchangeLiquidityBackfillCovered;
|
|
3971
|
+
const fearGreedReady = fearGreedCached || !fearGreedEnabled || fearGreedBackfillCovered;
|
|
3972
|
+
const indexesReady = indexesCached || indexesBackfillCovered;
|
|
3973
|
+
let globalStatus = resolveBackfillStatus({
|
|
3974
|
+
cached: globalDailyCached,
|
|
3975
|
+
covered: globalDailyBackfillCovered
|
|
3976
|
+
});
|
|
3977
|
+
let referenceStatus = resolveBackfillStatus({
|
|
3978
|
+
cached: referencesDailyCached,
|
|
3979
|
+
covered: referencesDailyBackfillCovered
|
|
3980
|
+
});
|
|
3981
|
+
let exchangeLiquidityStatus = resolveBackfillStatus({
|
|
3982
|
+
enabled: exchangeLiquidityEnabled,
|
|
3983
|
+
cached: exchangeLiquidityCached,
|
|
3984
|
+
covered: exchangeLiquidityBackfillCovered
|
|
3985
|
+
});
|
|
3986
|
+
let fearGreedStatus = resolveBackfillStatus({
|
|
3987
|
+
enabled: fearGreedEnabled,
|
|
3988
|
+
cached: fearGreedCached,
|
|
3989
|
+
covered: fearGreedBackfillCovered
|
|
3990
|
+
});
|
|
3991
|
+
let indexStatus = resolveBackfillStatus({
|
|
3992
|
+
cached: indexesCached,
|
|
3993
|
+
covered: indexesBackfillCovered
|
|
3994
|
+
});
|
|
3995
|
+
console.log(
|
|
3996
|
+
import_chalk3.default.gray(
|
|
3997
|
+
[
|
|
3998
|
+
"coinmarketcap context status:",
|
|
3999
|
+
formatSourceStatus({
|
|
4000
|
+
name: "global",
|
|
4001
|
+
status: globalStatus,
|
|
4002
|
+
coverage: formatCoverageRange(globalDailyCoverage)
|
|
4003
|
+
}),
|
|
4004
|
+
formatSourceStatus({
|
|
4005
|
+
name: "reference",
|
|
4006
|
+
status: referenceStatus,
|
|
4007
|
+
coverage: formatReferenceCoverage(referenceDailyCoverage)
|
|
4008
|
+
}),
|
|
4009
|
+
formatSourceStatus({
|
|
4010
|
+
name: "exchangeLiquidity",
|
|
4011
|
+
status: exchangeLiquidityStatus,
|
|
4012
|
+
coverage: formatCoverageRange(exchangeLiquidityCoverage)
|
|
4013
|
+
}),
|
|
4014
|
+
formatSourceStatus({
|
|
4015
|
+
name: "fearGreed",
|
|
4016
|
+
status: fearGreedStatus,
|
|
4017
|
+
coverage: formatCoverageRange(fearGreedCoverage)
|
|
4018
|
+
}),
|
|
4019
|
+
formatSourceStatus({
|
|
4020
|
+
name: "indexes",
|
|
4021
|
+
status: indexStatus,
|
|
4022
|
+
coverage: CMC_INDEXES.map(
|
|
4023
|
+
(index) => `${index.slug}:${formatCoverageRange(indexCoverage.get(index.slug))}`
|
|
4024
|
+
).join(" ")
|
|
4025
|
+
})
|
|
4026
|
+
].join(" ")
|
|
4027
|
+
)
|
|
4028
|
+
);
|
|
4029
|
+
if (globalDailyReady && referencesDailyReady && exchangeLiquidityReady && fearGreedReady && indexesReady) {
|
|
4030
|
+
console.log(
|
|
4031
|
+
import_chalk3.default.gray(
|
|
4032
|
+
`coinmarketcap context cached: ${new Date(fromMs).toISOString()}..${new Date(toMs).toISOString()}`
|
|
4033
|
+
)
|
|
4034
|
+
);
|
|
4035
|
+
return skippedResult(true);
|
|
4036
|
+
}
|
|
4037
|
+
const settings = await (0, import_userSettings2.getUserSettings)(params.userName);
|
|
4038
|
+
const apiKey = settings.COINMARKETCAP_API_KEY.trim();
|
|
4039
|
+
if (!apiKey) {
|
|
4040
|
+
throw new Error(
|
|
4041
|
+
`Missing COINMARKETCAP_API_KEY for historical context backfill (user=${params.userName})`
|
|
4042
|
+
);
|
|
4043
|
+
}
|
|
4044
|
+
let globalRows = 0;
|
|
4045
|
+
let referenceRows = 0;
|
|
4046
|
+
let exchangeLiquidityRows = 0;
|
|
4047
|
+
let fearGreedRows = 0;
|
|
4048
|
+
let indexRows = 0;
|
|
4049
|
+
const fetchStats = createCoinMarketCapFetchStats();
|
|
4050
|
+
const pendingSources = [
|
|
4051
|
+
!globalDailyReady ? "global" : null,
|
|
4052
|
+
!referencesDailyReady ? "reference" : null,
|
|
4053
|
+
exchangeLiquidityEnabled && !exchangeLiquidityReady ? "exchangeLiquidity" : null,
|
|
4054
|
+
fearGreedEnabled && !fearGreedReady ? "fearGreed" : null,
|
|
4055
|
+
!indexesReady ? "indexes" : null
|
|
4056
|
+
].filter((source) => source != null);
|
|
4057
|
+
console.log(
|
|
4058
|
+
import_chalk3.default.cyan(
|
|
4059
|
+
`coinmarketcap context backfill: window=${new Date(fromMs).toISOString()}..${new Date(toMs).toISOString()} days=${Math.floor((toMs - fromMs) / DAY_MS3) + 1} fetch=${pendingSources.join(",")}`
|
|
4060
|
+
)
|
|
4061
|
+
);
|
|
4062
|
+
if (!globalDailyReady) {
|
|
4063
|
+
const payload = await coinMarketCapFetch({
|
|
4064
|
+
path: "/v1/global-metrics/quotes/historical",
|
|
4065
|
+
apiKey,
|
|
4066
|
+
stats: fetchStats,
|
|
4067
|
+
searchParams: {
|
|
4068
|
+
time_start: toIsoDate(fromMs),
|
|
4069
|
+
time_end: toIsoDate(toMs),
|
|
4070
|
+
interval: "1d",
|
|
4071
|
+
convert: "USD"
|
|
4072
|
+
}
|
|
4073
|
+
});
|
|
4074
|
+
const rows = coinMarketCapGlobalPayloadToRows(payload, SOURCE_GLOBAL_DAILY);
|
|
4075
|
+
await (0, import_timescale3.upsertMarketGlobalContextRows)(rows);
|
|
4076
|
+
await markBackfillCoverage([
|
|
4077
|
+
{
|
|
4078
|
+
source: SOURCE_GLOBAL_DAILY,
|
|
4079
|
+
scope: COVERAGE_SCOPE_ALL,
|
|
4080
|
+
interval: "1d",
|
|
4081
|
+
fromMs,
|
|
4082
|
+
toMs,
|
|
4083
|
+
rowsCount: rows.length
|
|
4084
|
+
}
|
|
4085
|
+
]);
|
|
4086
|
+
globalRows += rows.length;
|
|
4087
|
+
globalStatus = "fetched";
|
|
4088
|
+
logBackfillSourceDone({
|
|
4089
|
+
name: "global",
|
|
4090
|
+
status: globalStatus,
|
|
4091
|
+
rows: rows.length,
|
|
4092
|
+
details: formatRowTimeRange(rows)
|
|
4093
|
+
});
|
|
4094
|
+
}
|
|
4095
|
+
if (!referencesDailyReady) {
|
|
4096
|
+
const payload = await coinMarketCapFetch({
|
|
4097
|
+
path: "/v3/cryptocurrency/quotes/historical",
|
|
4098
|
+
apiKey,
|
|
4099
|
+
stats: fetchStats,
|
|
4100
|
+
searchParams: {
|
|
4101
|
+
id: REFERENCE_ASSETS.map((item) => item.cmcId).join(","),
|
|
4102
|
+
time_start: toIsoDate(fromMs),
|
|
4103
|
+
time_end: toIsoDate(toMs),
|
|
4104
|
+
interval: "1d",
|
|
4105
|
+
convert: "USD"
|
|
4106
|
+
}
|
|
4107
|
+
});
|
|
4108
|
+
const rows = coinMarketCapHistoricalQuotesPayloadToRows(payload, "1d");
|
|
4109
|
+
await (0, import_timescale3.upsertMarketReferenceAssetContextRows)(rows);
|
|
4110
|
+
await markBackfillCoverage(
|
|
4111
|
+
REFERENCE_ASSETS.map((asset) => ({
|
|
4112
|
+
source: SOURCE_REFERENCE,
|
|
4113
|
+
scope: asset.symbol,
|
|
4114
|
+
interval: "1d",
|
|
4115
|
+
fromMs,
|
|
4116
|
+
toMs,
|
|
4117
|
+
rowsCount: rows.filter((row) => row.symbol === asset.symbol).length
|
|
4118
|
+
}))
|
|
4119
|
+
);
|
|
4120
|
+
referenceRows += rows.length;
|
|
4121
|
+
referenceStatus = "fetched";
|
|
4122
|
+
logBackfillSourceDone({
|
|
4123
|
+
name: "reference",
|
|
4124
|
+
status: referenceStatus,
|
|
4125
|
+
rows: rows.length,
|
|
4126
|
+
details: `${REFERENCE_ASSETS.map(
|
|
4127
|
+
(asset) => `${asset.symbol}:${rows.filter((row) => row.symbol === asset.symbol).length}`
|
|
4128
|
+
).join(" ")} ${formatRowTimeRange(rows)}`
|
|
4129
|
+
});
|
|
4130
|
+
}
|
|
4131
|
+
if (exchangeLiquidityEnabled && !exchangeLiquidityReady) {
|
|
4132
|
+
const payload = await coinMarketCapFetch({
|
|
4133
|
+
path: "/v1/exchange/quotes/historical",
|
|
4134
|
+
apiKey,
|
|
4135
|
+
stats: fetchStats,
|
|
4136
|
+
searchParams: {
|
|
4137
|
+
slug: getExchangeSlugs().join(","),
|
|
4138
|
+
time_start: toIsoDate(fromMs),
|
|
4139
|
+
time_end: toIsoDate(toMs),
|
|
4140
|
+
interval: "1d",
|
|
4141
|
+
convert: "USD"
|
|
4142
|
+
}
|
|
4143
|
+
});
|
|
4144
|
+
const rows = coinMarketCapExchangeQuotesPayloadToLiquidityRows(
|
|
4145
|
+
payload,
|
|
4146
|
+
"1d"
|
|
4147
|
+
);
|
|
4148
|
+
await (0, import_timescale3.upsertMarketCmcExchangeLiquidityContextRows)(rows);
|
|
4149
|
+
await markBackfillCoverage([
|
|
4150
|
+
{
|
|
4151
|
+
source: SOURCE_EXCHANGE_LIQUIDITY,
|
|
4152
|
+
scope: COVERAGE_SCOPE_ALL,
|
|
4153
|
+
interval: "1d",
|
|
4154
|
+
fromMs,
|
|
4155
|
+
toMs,
|
|
4156
|
+
rowsCount: rows.length
|
|
4157
|
+
}
|
|
4158
|
+
]);
|
|
4159
|
+
exchangeLiquidityRows = rows.length;
|
|
4160
|
+
exchangeLiquidityStatus = "fetched";
|
|
4161
|
+
logBackfillSourceDone({
|
|
4162
|
+
name: "exchangeLiquidity",
|
|
4163
|
+
status: exchangeLiquidityStatus,
|
|
4164
|
+
rows: rows.length,
|
|
4165
|
+
details: formatRowTimeRange(rows)
|
|
4166
|
+
});
|
|
4167
|
+
}
|
|
4168
|
+
if (fearGreedEnabled && !fearGreedReady) {
|
|
4169
|
+
const rows = [];
|
|
4170
|
+
const pageSize = getFearGreedPageSize();
|
|
4171
|
+
let pages = 0;
|
|
4172
|
+
for (let start = 1; ; start += pageSize) {
|
|
4173
|
+
const payload = await coinMarketCapFetch({
|
|
4174
|
+
path: "/v3/fear-and-greed/historical",
|
|
4175
|
+
apiKey,
|
|
4176
|
+
stats: fetchStats,
|
|
4177
|
+
searchParams: {
|
|
4178
|
+
start: String(start),
|
|
4179
|
+
limit: String(pageSize)
|
|
4180
|
+
}
|
|
4181
|
+
});
|
|
4182
|
+
pages += 1;
|
|
4183
|
+
const pageRows = coinMarketCapFearGreedPayloadToRows(payload);
|
|
4184
|
+
if (!pageRows.length) break;
|
|
4185
|
+
const matchingRows = pageRows.filter((row) => {
|
|
4186
|
+
const ts = row.ts.getTime();
|
|
4187
|
+
return ts >= fromMs && ts <= toMs;
|
|
4188
|
+
});
|
|
4189
|
+
rows.push(...matchingRows);
|
|
4190
|
+
const oldestPageTs = Math.min(...pageRows.map((row) => row.ts.getTime()));
|
|
4191
|
+
if (oldestPageTs < fromMs || pageRows.length < pageSize) break;
|
|
4192
|
+
}
|
|
4193
|
+
await (0, import_timescale3.upsertMarketCmcFearGreedContextRows)(rows);
|
|
4194
|
+
await markBackfillCoverage([
|
|
4195
|
+
{
|
|
4196
|
+
source: SOURCE_FEAR_GREED,
|
|
4197
|
+
scope: COVERAGE_SCOPE_ALL,
|
|
4198
|
+
interval: "1d",
|
|
4199
|
+
fromMs,
|
|
4200
|
+
toMs,
|
|
4201
|
+
rowsCount: rows.length
|
|
4202
|
+
}
|
|
4203
|
+
]);
|
|
4204
|
+
fearGreedRows = rows.length;
|
|
4205
|
+
fearGreedStatus = "fetched";
|
|
4206
|
+
logBackfillSourceDone({
|
|
4207
|
+
name: "fearGreed",
|
|
4208
|
+
status: fearGreedStatus,
|
|
4209
|
+
rows: rows.length,
|
|
4210
|
+
details: `pages=${pages} ${formatRowTimeRange(rows)}`
|
|
4211
|
+
});
|
|
4212
|
+
}
|
|
4213
|
+
if (!indexesReady) {
|
|
4214
|
+
const rowsByIndex = await Promise.all(
|
|
4215
|
+
CMC_INDEXES.map(async (index) => ({
|
|
4216
|
+
index,
|
|
4217
|
+
result: await fetchCoinMarketCapIndexRows({
|
|
4218
|
+
apiKey,
|
|
4219
|
+
index,
|
|
4220
|
+
fromMs,
|
|
4221
|
+
toMs,
|
|
4222
|
+
stats: fetchStats
|
|
4223
|
+
})
|
|
4224
|
+
}))
|
|
4225
|
+
);
|
|
4226
|
+
const rows = rowsByIndex.flatMap((item) => item.result.rows);
|
|
4227
|
+
await (0, import_timescale3.upsertMarketCmcIndexContextRows)(rows);
|
|
4228
|
+
await markBackfillCoverage(
|
|
4229
|
+
rowsByIndex.map(({ index, result }) => ({
|
|
4230
|
+
source: SOURCE_INDEX,
|
|
4231
|
+
scope: index.slug,
|
|
4232
|
+
interval: "1d",
|
|
4233
|
+
fromMs,
|
|
4234
|
+
toMs,
|
|
4235
|
+
rowsCount: result.rows.length
|
|
4236
|
+
}))
|
|
4237
|
+
);
|
|
4238
|
+
indexRows = rows.length;
|
|
4239
|
+
indexStatus = "fetched";
|
|
4240
|
+
logBackfillSourceDone({
|
|
4241
|
+
name: "indexes",
|
|
4242
|
+
status: indexStatus,
|
|
4243
|
+
rows: rows.length,
|
|
4244
|
+
details: `${rowsByIndex.map(
|
|
4245
|
+
({ index, result }) => `${index.slug}:${result.rows.length} rows/${result.chunks} chunks`
|
|
4246
|
+
).join(" ")} ${formatRowTimeRange(rows)}`
|
|
4247
|
+
});
|
|
4248
|
+
}
|
|
4249
|
+
console.log(
|
|
4250
|
+
import_chalk3.default.green(
|
|
4251
|
+
[
|
|
4252
|
+
"coinmarketcap context backfill done:",
|
|
4253
|
+
`global=${globalStatus} rows=${globalRows}`,
|
|
4254
|
+
`reference=${referenceStatus} rows=${referenceRows}`,
|
|
4255
|
+
`exchangeLiquidity=${exchangeLiquidityStatus} rows=${exchangeLiquidityRows}`,
|
|
4256
|
+
`fearGreed=${fearGreedStatus} rows=${fearGreedRows}`,
|
|
4257
|
+
`indexes=${indexStatus} rows=${indexRows}`,
|
|
4258
|
+
formatCoinMarketCapFetchStats(fetchStats)
|
|
4259
|
+
].join(" ")
|
|
4260
|
+
)
|
|
4261
|
+
);
|
|
4262
|
+
return {
|
|
4263
|
+
skipped: false,
|
|
4264
|
+
globalRows,
|
|
4265
|
+
referenceRows,
|
|
4266
|
+
breadthRows: 0,
|
|
4267
|
+
exchangeLiquidityRows,
|
|
4268
|
+
fearGreedRows,
|
|
4269
|
+
indexRows,
|
|
4270
|
+
cached: false
|
|
4271
|
+
};
|
|
4272
|
+
};
|
|
4273
|
+
var backfillCoinMarketCapContextForBacktest = backfillCoinMarketCapContext;
|
|
4274
|
+
var backfillCoinMarketCapContextForReplay = backfillCoinMarketCapContext;
|
|
4275
|
+
var backfillCoinMarketCapContextForSignals = backfillCoinMarketCapContext;
|
|
4276
|
+
|
|
4277
|
+
// src/lib/runFormatting.ts
|
|
4278
|
+
var import_date_fns = require("date-fns");
|
|
4279
|
+
var ListIt = require_list_it();
|
|
4280
|
+
var formatDuration = (startedAt) => {
|
|
4281
|
+
const seconds = Math.max(0, (Date.now() - startedAt) / 1e3);
|
|
4282
|
+
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
4283
|
+
const minutes = Math.floor(seconds / 60);
|
|
4284
|
+
const restSeconds = Math.round(seconds % 60);
|
|
4285
|
+
return `${minutes}m ${restSeconds}s`;
|
|
4286
|
+
};
|
|
4287
|
+
var timeOperation = async (label, operation, log = console.log) => {
|
|
4288
|
+
const startedAt = Date.now();
|
|
4289
|
+
try {
|
|
4290
|
+
return await operation();
|
|
4291
|
+
} finally {
|
|
4292
|
+
log(`${label}: done in ${formatDuration(startedAt)}`);
|
|
4293
|
+
}
|
|
4294
|
+
};
|
|
4295
|
+
|
|
4296
|
+
// src/lib/marketContextPrepare.ts
|
|
4297
|
+
var shouldPrepareDerivativesContextForRun = (params) => {
|
|
4298
|
+
if (params.universe === "tradfi") return false;
|
|
4299
|
+
if (params.mode === "signals") {
|
|
4300
|
+
return shouldBackfillDerivativesContextForSignals({
|
|
4301
|
+
cacheOnly: params.cacheOnly
|
|
4302
|
+
});
|
|
4303
|
+
}
|
|
4304
|
+
return shouldBackfillDerivativesContextForBacktest({
|
|
4305
|
+
aiEnabled: Boolean(params.aiEnabled),
|
|
4306
|
+
cacheOnly: params.cacheOnly,
|
|
4307
|
+
mlEnabled: Boolean(params.mlEnabled)
|
|
4308
|
+
});
|
|
4309
|
+
};
|
|
4310
|
+
var shouldPrepareBinanceMarketContextForRun = (params) => {
|
|
4311
|
+
if (params.universe === "tradfi") return false;
|
|
4312
|
+
if (params.mode === "backtest") {
|
|
4313
|
+
return shouldBackfillBinanceMarketContextForBacktest({
|
|
4314
|
+
aiEnabled: Boolean(params.aiEnabled),
|
|
4315
|
+
cacheOnly: params.cacheOnly,
|
|
4316
|
+
mlEnabled: Boolean(params.mlEnabled)
|
|
4317
|
+
});
|
|
4318
|
+
}
|
|
4319
|
+
if (params.mode === "signals") {
|
|
4320
|
+
return shouldBackfillBinanceMarketContextForSignals({
|
|
4321
|
+
cacheOnly: params.cacheOnly
|
|
4322
|
+
});
|
|
4323
|
+
}
|
|
4324
|
+
return shouldBackfillBinanceMarketContextForReplay({
|
|
4325
|
+
cacheOnly: params.cacheOnly
|
|
4326
|
+
});
|
|
4327
|
+
};
|
|
4328
|
+
var shouldPrepareCoinMarketCapContextForRun = (params) => {
|
|
4329
|
+
if (params.universe === "tradfi") return false;
|
|
4330
|
+
if (params.mode === "backtest") {
|
|
4331
|
+
return shouldBackfillCoinMarketCapContextForBacktest({
|
|
4332
|
+
aiEnabled: Boolean(params.aiEnabled),
|
|
4333
|
+
cacheOnly: params.cacheOnly,
|
|
4334
|
+
mlEnabled: Boolean(params.mlEnabled)
|
|
4335
|
+
});
|
|
4336
|
+
}
|
|
4337
|
+
if (params.mode === "signals") {
|
|
4338
|
+
return shouldBackfillCoinMarketCapContextForSignals({
|
|
4339
|
+
cacheOnly: params.cacheOnly
|
|
4340
|
+
});
|
|
4341
|
+
}
|
|
4342
|
+
return shouldBackfillCoinMarketCapContextForReplay({
|
|
4343
|
+
cacheOnly: params.cacheOnly
|
|
4344
|
+
});
|
|
4345
|
+
};
|
|
4346
|
+
var resolveCoinMarketCapBackfillForMode = (mode) => mode === "backtest" ? backfillCoinMarketCapContextForBacktest : mode === "signals" ? backfillCoinMarketCapContextForSignals : backfillCoinMarketCapContextForReplay;
|
|
4347
|
+
var buildCoinMarketCapBackfillParams = (params) => ({
|
|
4348
|
+
userName: params.userName,
|
|
4349
|
+
startMs: params.startMs,
|
|
4350
|
+
endMs: params.endMs,
|
|
4351
|
+
preloadStartMs: params.preloadStartMs
|
|
4352
|
+
});
|
|
4353
|
+
var buildBinanceMarketBackfillParams = (params) => ({
|
|
4354
|
+
userName: params.userName,
|
|
4355
|
+
projectRoot: params.projectRoot,
|
|
4356
|
+
symbols: params.symbols,
|
|
4357
|
+
interval: params.interval,
|
|
4358
|
+
startMs: params.startMs,
|
|
4359
|
+
endMs: params.endMs,
|
|
4360
|
+
preloadStartMs: params.preloadStartMs
|
|
4361
|
+
});
|
|
4362
|
+
var buildDerivativesBackfillParams = (params) => ({
|
|
4363
|
+
userName: params.userName,
|
|
4364
|
+
symbols: params.symbols,
|
|
4365
|
+
startMs: params.startMs,
|
|
4366
|
+
endMs: params.endMs,
|
|
4367
|
+
preloadStartMs: params.mode === "signals" ? void 0 : params.preloadStartMs
|
|
4368
|
+
});
|
|
4369
|
+
var prepareMarketContextForRun = async (params) => {
|
|
4370
|
+
const log = params.log ?? ((message) => {
|
|
4371
|
+
console.log(import_chalk4.default.gray(message));
|
|
4372
|
+
});
|
|
4373
|
+
const timeOperation2 = (label, operation) => timeOperation(label, operation, log);
|
|
4374
|
+
if (shouldPrepareDerivativesContextForRun(params)) {
|
|
4375
|
+
await timeOperation2(
|
|
4376
|
+
"derivatives context backfill",
|
|
4377
|
+
() => (params.mode === "signals" ? backfillDerivativesContextForSignals : backfillDerivativesContextForBacktest)(
|
|
4378
|
+
buildDerivativesBackfillParams(params)
|
|
4379
|
+
)
|
|
4380
|
+
);
|
|
4381
|
+
}
|
|
4382
|
+
if (shouldPrepareBinanceMarketContextForRun(params)) {
|
|
4383
|
+
await timeOperation2("binance market context backfill", () => {
|
|
4384
|
+
const backfill = params.mode === "backtest" ? backfillBinanceMarketContextForBacktest : params.mode === "signals" ? backfillBinanceMarketContextForSignals : backfillBinanceMarketContextForReplay;
|
|
4385
|
+
return backfill(buildBinanceMarketBackfillParams(params));
|
|
4386
|
+
});
|
|
4387
|
+
}
|
|
4388
|
+
if (shouldPrepareCoinMarketCapContextForRun(params)) {
|
|
4389
|
+
await timeOperation2(
|
|
4390
|
+
"coinmarketcap historical context backfill",
|
|
4391
|
+
() => resolveCoinMarketCapBackfillForMode(params.mode)(
|
|
4392
|
+
buildCoinMarketCapBackfillParams(params)
|
|
4393
|
+
)
|
|
4394
|
+
);
|
|
4395
|
+
}
|
|
4396
|
+
};
|
|
4397
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4398
|
+
0 && (module.exports = {
|
|
4399
|
+
prepareMarketContextForRun,
|
|
4400
|
+
shouldPrepareBinanceMarketContextForRun,
|
|
4401
|
+
shouldPrepareCoinMarketCapContextForRun,
|
|
4402
|
+
shouldPrepareDerivativesContextForRun
|
|
4403
|
+
});
|