@tradejs/cli 2.0.5 → 2.0.7

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.
@@ -34,9 +34,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  ));
35
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
36
 
37
- // ../../node_modules/debug/node_modules/ms/index.js
37
+ // ../../node_modules/ms/index.js
38
38
  var require_ms = __commonJS({
39
- "../../node_modules/debug/node_modules/ms/index.js"(exports2, module2) {
39
+ "../../node_modules/ms/index.js"(exports2, module2) {
40
40
  "use strict";
41
41
  var s = 1e3;
42
42
  var m = s * 60;
@@ -151,9 +151,9 @@ var require_ms = __commonJS({
151
151
  }
152
152
  });
153
153
 
154
- // ../../node_modules/debug/src/common.js
154
+ // ../../node_modules/list-it/node_modules/debug/src/common.js
155
155
  var require_common = __commonJS({
156
- "../../node_modules/debug/src/common.js"(exports2, module2) {
156
+ "../../node_modules/list-it/node_modules/debug/src/common.js"(exports2, module2) {
157
157
  "use strict";
158
158
  function setup(env) {
159
159
  createDebug.debug = createDebug;
@@ -255,50 +255,64 @@ var require_common = __commonJS({
255
255
  createDebug.namespaces = namespaces;
256
256
  createDebug.names = [];
257
257
  createDebug.skips = [];
258
- let i;
259
- const split = (typeof namespaces === "string" ? namespaces : "").split(/[\s,]+/);
260
- const len = split.length;
261
- for (i = 0; i < len; i++) {
262
- if (!split[i]) {
263
- continue;
258
+ const split = (typeof namespaces === "string" ? namespaces : "").trim().replace(/\s+/g, ",").split(",").filter(Boolean);
259
+ for (const ns of split) {
260
+ if (ns[0] === "-") {
261
+ createDebug.skips.push(ns.slice(1));
262
+ } else {
263
+ createDebug.names.push(ns);
264
264
  }
265
- namespaces = split[i].replace(/\*/g, ".*?");
266
- if (namespaces[0] === "-") {
267
- createDebug.skips.push(new RegExp("^" + namespaces.slice(1) + "$"));
265
+ }
266
+ }
267
+ function matchesTemplate(search, template) {
268
+ let searchIndex = 0;
269
+ let templateIndex = 0;
270
+ let starIndex = -1;
271
+ let matchIndex = 0;
272
+ while (searchIndex < search.length) {
273
+ if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === "*")) {
274
+ if (template[templateIndex] === "*") {
275
+ starIndex = templateIndex;
276
+ matchIndex = searchIndex;
277
+ templateIndex++;
278
+ } else {
279
+ searchIndex++;
280
+ templateIndex++;
281
+ }
282
+ } else if (starIndex !== -1) {
283
+ templateIndex = starIndex + 1;
284
+ matchIndex++;
285
+ searchIndex = matchIndex;
268
286
  } else {
269
- createDebug.names.push(new RegExp("^" + namespaces + "$"));
287
+ return false;
270
288
  }
271
289
  }
290
+ while (templateIndex < template.length && template[templateIndex] === "*") {
291
+ templateIndex++;
292
+ }
293
+ return templateIndex === template.length;
272
294
  }
273
295
  function disable() {
274
296
  const namespaces = [
275
- ...createDebug.names.map(toNamespace),
276
- ...createDebug.skips.map(toNamespace).map((namespace) => "-" + namespace)
297
+ ...createDebug.names,
298
+ ...createDebug.skips.map((namespace) => "-" + namespace)
277
299
  ].join(",");
278
300
  createDebug.enable("");
279
301
  return namespaces;
280
302
  }
281
303
  function enabled(name) {
282
- if (name[name.length - 1] === "*") {
283
- return true;
284
- }
285
- let i;
286
- let len;
287
- for (i = 0, len = createDebug.skips.length; i < len; i++) {
288
- if (createDebug.skips[i].test(name)) {
304
+ for (const skip of createDebug.skips) {
305
+ if (matchesTemplate(name, skip)) {
289
306
  return false;
290
307
  }
291
308
  }
292
- for (i = 0, len = createDebug.names.length; i < len; i++) {
293
- if (createDebug.names[i].test(name)) {
309
+ for (const ns of createDebug.names) {
310
+ if (matchesTemplate(name, ns)) {
294
311
  return true;
295
312
  }
296
313
  }
297
314
  return false;
298
315
  }
299
- function toNamespace(regexp) {
300
- return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\.\*\?$/, "*");
301
- }
302
316
  function coerce(val) {
303
317
  if (val instanceof Error) {
304
318
  return val.stack || val.message;
@@ -315,9 +329,9 @@ var require_common = __commonJS({
315
329
  }
316
330
  });
317
331
 
318
- // ../../node_modules/debug/src/browser.js
332
+ // ../../node_modules/list-it/node_modules/debug/src/browser.js
319
333
  var require_browser = __commonJS({
320
- "../../node_modules/debug/src/browser.js"(exports2, module2) {
334
+ "../../node_modules/list-it/node_modules/debug/src/browser.js"(exports2, module2) {
321
335
  "use strict";
322
336
  exports2.formatArgs = formatArgs;
323
337
  exports2.save = save;
@@ -418,10 +432,11 @@ var require_browser = __commonJS({
418
432
  if (typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
419
433
  return false;
420
434
  }
435
+ let m;
421
436
  return typeof document !== "undefined" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773
422
437
  typeof window !== "undefined" && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31?
423
438
  // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
424
- 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
439
+ typeof navigator !== "undefined" && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker
425
440
  typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
426
441
  }
427
442
  function formatArgs(args2) {
@@ -459,7 +474,7 @@ var require_browser = __commonJS({
459
474
  function load() {
460
475
  let r;
461
476
  try {
462
- r = exports2.storage.getItem("debug");
477
+ r = exports2.storage.getItem("debug") || exports2.storage.getItem("DEBUG");
463
478
  } catch (error) {
464
479
  }
465
480
  if (!r && typeof process !== "undefined" && "env" in process) {
@@ -600,9 +615,9 @@ var require_supports_color = __commonJS({
600
615
  }
601
616
  });
602
617
 
603
- // ../../node_modules/debug/src/node.js
618
+ // ../../node_modules/list-it/node_modules/debug/src/node.js
604
619
  var require_node = __commonJS({
605
- "../../node_modules/debug/src/node.js"(exports2, module2) {
620
+ "../../node_modules/list-it/node_modules/debug/src/node.js"(exports2, module2) {
606
621
  "use strict";
607
622
  var tty = require("tty");
608
623
  var util = require("util");
@@ -743,7 +758,7 @@ var require_node = __commonJS({
743
758
  return (/* @__PURE__ */ new Date()).toISOString() + " ";
744
759
  }
745
760
  function log(...args2) {
746
- return process.stderr.write(util.format(...args2) + "\n");
761
+ return process.stderr.write(util.formatWithOptions(exports2.inspectOpts, ...args2) + "\n");
747
762
  }
748
763
  function save(namespaces) {
749
764
  if (namespaces) {
@@ -775,9 +790,9 @@ var require_node = __commonJS({
775
790
  }
776
791
  });
777
792
 
778
- // ../../node_modules/debug/src/index.js
793
+ // ../../node_modules/list-it/node_modules/debug/src/index.js
779
794
  var require_src = __commonJS({
780
- "../../node_modules/debug/src/index.js"(exports2, module2) {
795
+ "../../node_modules/list-it/node_modules/debug/src/index.js"(exports2, module2) {
781
796
  "use strict";
782
797
  if (typeof process === "undefined" || process.type === "renderer" || process.browser === true || process.__nwjs) {
783
798
  module2.exports = require_browser();
@@ -2241,11 +2256,30 @@ var resolveTimeWindow = ({
2241
2256
  endTime,
2242
2257
  nowMs = Date.now(),
2243
2258
  defaultStartMs,
2244
- defaultEndMs
2259
+ defaultEndMs,
2260
+ closedIntervalMs
2245
2261
  }) => {
2246
2262
  const explicitStart = toEpochMs(startTime);
2247
2263
  const explicitEnd = toEpochMs(endTime);
2248
2264
  const resolvedDays = toPositiveNumber(days);
2265
+ const alignToLastClosedInterval = (window2, preserveDuration) => {
2266
+ if (typeof closedIntervalMs !== "number" || !Number.isFinite(closedIntervalMs) || closedIntervalMs <= 0) {
2267
+ return window2;
2268
+ }
2269
+ const alignedEnd = Math.floor(window2.end / closedIntervalMs) * closedIntervalMs - 1;
2270
+ const delta = window2.end - alignedEnd;
2271
+ const alignedStart = preserveDuration ? window2.start - delta : window2.start;
2272
+ if (alignedStart >= alignedEnd) {
2273
+ throw new Error(
2274
+ `Invalid closed-candle window: start (${alignedStart}) must be less than end (${alignedEnd})`
2275
+ );
2276
+ }
2277
+ return {
2278
+ ...window2,
2279
+ start: Math.trunc(alignedStart),
2280
+ end: Math.trunc(alignedEnd)
2281
+ };
2282
+ };
2249
2283
  if (explicitStart != null || explicitEnd != null) {
2250
2284
  const resolvedStart = explicitStart ?? (resolvedDays != null && explicitEnd != null ? explicitEnd - resolvedDays * ONE_DAY_MS : defaultStartMs);
2251
2285
  const resolvedEnd2 = explicitEnd ?? (resolvedDays != null && explicitStart != null ? explicitStart + resolvedDays * ONE_DAY_MS : defaultEndMs ?? nowMs);
@@ -2254,11 +2288,14 @@ var resolveTimeWindow = ({
2254
2288
  `Invalid time window: startTime (${resolvedStart}) must be less than endTime (${resolvedEnd2})`
2255
2289
  );
2256
2290
  }
2257
- return {
2258
- start: resolvedStart,
2259
- end: resolvedEnd2,
2260
- source: "explicit"
2261
- };
2291
+ return alignToLastClosedInterval(
2292
+ {
2293
+ start: resolvedStart,
2294
+ end: resolvedEnd2,
2295
+ source: "explicit"
2296
+ },
2297
+ explicitStart == null && resolvedDays != null
2298
+ );
2262
2299
  }
2263
2300
  if (resolvedDays != null) {
2264
2301
  const resolvedEnd2 = defaultEndMs ?? nowMs;
@@ -2268,11 +2305,14 @@ var resolveTimeWindow = ({
2268
2305
  `Invalid time window: computed start (${resolvedStart}) must be less than end (${resolvedEnd2})`
2269
2306
  );
2270
2307
  }
2271
- return {
2272
- start: Math.trunc(resolvedStart),
2273
- end: Math.trunc(resolvedEnd2),
2274
- source: "days"
2275
- };
2308
+ return alignToLastClosedInterval(
2309
+ {
2310
+ start: Math.trunc(resolvedStart),
2311
+ end: Math.trunc(resolvedEnd2),
2312
+ source: "days"
2313
+ },
2314
+ true
2315
+ );
2276
2316
  }
2277
2317
  const resolvedEnd = defaultEndMs ?? nowMs;
2278
2318
  if (defaultStartMs >= resolvedEnd) {
@@ -2280,11 +2320,14 @@ var resolveTimeWindow = ({
2280
2320
  `Invalid default time window: start (${defaultStartMs}) must be less than end (${resolvedEnd})`
2281
2321
  );
2282
2322
  }
2283
- return {
2284
- start: Math.trunc(defaultStartMs),
2285
- end: Math.trunc(resolvedEnd),
2286
- source: "default"
2287
- };
2323
+ return alignToLastClosedInterval(
2324
+ {
2325
+ start: Math.trunc(defaultStartMs),
2326
+ end: Math.trunc(resolvedEnd),
2327
+ source: "default"
2328
+ },
2329
+ true
2330
+ );
2288
2331
  };
2289
2332
 
2290
2333
  // src/lib/runFormatting.ts
@@ -2314,6 +2357,7 @@ var import_progress = __toESM(require("progress"));
2314
2357
  var import_chalk = __toESM(require("chalk"));
2315
2358
  var import_connectors = require("@tradejs/connectors");
2316
2359
  var import_connectors2 = require("@tradejs/node/connectors");
2360
+ var import_strategies = require("@tradejs/node/strategies");
2317
2361
  var import_timescale = require("@tradejs/infra/timescale");
2318
2362
 
2319
2363
  // src/lib/binanceMarketData.ts
@@ -2323,14 +2367,6 @@ var MARKET_FEATURE_INTERVAL_MS = {
2323
2367
  "15m": 9e5,
2324
2368
  "1h": 36e5
2325
2369
  };
2326
- var STABLE_QUOTE_SYMBOLS = /* @__PURE__ */ new Set([
2327
- "USDCUSDT",
2328
- "FDUSDUSDT",
2329
- "TUSDUSDT",
2330
- "BUSDUSDT",
2331
- "USDPUSDT",
2332
- "DAIUSDT"
2333
- ]);
2334
2370
  var safeDivide = (num, den) => Number.isFinite(num) && Number.isFinite(den) && den !== 0 ? num / den : null;
2335
2371
  var mean = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
2336
2372
  var standardDeviation = (values) => {
@@ -2374,9 +2410,6 @@ var classifyBtcAltRegime = ({
2374
2410
  if (btcVsAltReturn24h < -5e-3) return "alt_lead";
2375
2411
  return "neutral";
2376
2412
  };
2377
- var selectBreadthUniverseFromTickers = (tickers, limit) => tickers.filter(
2378
- (ticker) => ticker.symbol.endsWith("USDT") && ticker.symbol !== "BTCUSDT" && !STABLE_QUOTE_SYMBOLS.has(ticker.symbol) && Number.isFinite(ticker.turnover24h) && ticker.turnover24h > 0
2379
- ).sort((a, b) => b.turnover24h - a.turnover24h).slice(0, Math.max(0, limit)).map((ticker) => ticker.symbol);
2380
2413
  var aggregateAggTradesToRows = ({
2381
2414
  symbol,
2382
2415
  interval: interval2,
@@ -2858,10 +2891,6 @@ var backfillBinanceMarketContext = async (params, enabled) => {
2858
2891
  process.env.BINANCE_MARKET_CONTEXT_TRADE_FLOW_SYMBOL_LIMIT,
2859
2892
  2
2860
2893
  );
2861
- const breadthLimit = asInt(
2862
- process.env.BINANCE_MARKET_CONTEXT_BREADTH_LIMIT,
2863
- 30
2864
- );
2865
2894
  const breadthChunkDays = asFloat(
2866
2895
  process.env.BINANCE_MARKET_CONTEXT_BREADTH_CHUNK_DAYS,
2867
2896
  30
@@ -2984,88 +3013,113 @@ var backfillBinanceMarketContext = async (params, enabled) => {
2984
3013
  }
2985
3014
  }
2986
3015
  if (includeBreadth) {
2987
- const tickers = await connector.getTickers();
2988
- const breadthSymbols = selectBreadthUniverseFromTickers(
2989
- tickers,
2990
- breadthLimit
2991
- );
2992
- const universe = `binance_top${breadthSymbols.length}_usdt`;
2993
- const coverage = await (0, import_timescale.getMarketBreadthCoverage)({
2994
- universe,
2995
- interval: interval2,
2996
- startMs: breadthStartMs,
2997
- endMs
2998
- });
2999
- const hasBtcAltMetrics = (coverage?.btcAltMetricsRows ?? 0) >= Math.floor(Math.max(1, coverage?.rows ?? 0) * 0.9);
3000
- if (!hasCoverage({
3001
- coverage,
3016
+ const breadthUniverses = (0, import_strategies.getBinanceBreadthUniverses)();
3017
+ const breadthSymbols = breadthUniverses.at(-1)?.symbols ?? [];
3018
+ const connectorInterval = marketIntervalToConnectorInterval(interval2);
3019
+ const chunks = buildBreadthBackfillChunks({
3002
3020
  startMs: breadthStartMs,
3003
3021
  endMs,
3004
- intervalMs
3005
- }) || !hasBtcAltMetrics) {
3006
- const connectorInterval = marketIntervalToConnectorInterval(interval2);
3007
- const chunks = buildBreadthBackfillChunks({
3008
- startMs: breadthStartMs,
3009
- endMs,
3010
- intervalMs,
3011
- chunkDays: breadthChunkDays
3012
- });
3013
- const missingChunks = filterMissingBreadthBackfillChunks({
3014
- chunks,
3015
- coverage,
3016
- intervalMs
3017
- });
3018
- const bar = new import_progress.default(
3019
- "breadth :current/:total [:bar][:percent] :etas(s) candles=:candles skip=:skip chunk=:chunk :symbol",
3020
- {
3021
- total: Math.max(1, missingChunks.length * breadthSymbols.length),
3022
- width: 24
3023
- }
3024
- );
3025
- let candlesRead = 0;
3026
- let skippedBreadthChunks = chunks.length - missingChunks.length;
3027
- if (!missingChunks.length) {
3028
- bar.tick(1, {
3029
- candles: 0,
3030
- skip: skippedBreadthChunks,
3031
- chunk: "cached",
3032
- symbol: universe
3022
+ intervalMs,
3023
+ chunkDays: breadthChunkDays
3024
+ });
3025
+ const plans = await Promise.all(
3026
+ breadthUniverses.map(async (definition) => {
3027
+ const coverage = await (0, import_timescale.getMarketBreadthCoverage)({
3028
+ universe: definition.universe,
3029
+ interval: interval2,
3030
+ startMs: breadthStartMs,
3031
+ endMs
3033
3032
  });
3034
- }
3035
- for (let chunkIndex = 0; chunkIndex < missingChunks.length; chunkIndex += 1) {
3036
- const chunk = missingChunks[chunkIndex];
3037
- const originalChunkIndex = chunks.findIndex(
3038
- (item) => item.startMs === chunk.startMs && item.endMs === chunk.endMs
3039
- );
3040
- const candlesBySymbol = {};
3041
- for (const symbol of breadthSymbols) {
3042
- const candles = await connector.kline({
3043
- symbol,
3044
- interval: connectorInterval,
3045
- start: chunk.fetchStartMs,
3046
- end: chunk.endMs,
3047
- silent: true
3048
- });
3049
- candlesBySymbol[symbol] = candles;
3050
- candlesRead += candles.length;
3051
- bar.tick(1, {
3052
- candles: candlesRead,
3053
- skip: skippedBreadthChunks,
3054
- chunk: `${originalChunkIndex + 1}/${chunks.length}`,
3055
- symbol
3056
- });
3033
+ const hasBtcAltMetrics = (coverage?.btcAltMetricsRows ?? 0) >= Math.floor(Math.max(1, coverage?.rows ?? 0) * 0.9);
3034
+ const missingChunks2 = !hasCoverage({
3035
+ coverage,
3036
+ startMs: breadthStartMs,
3037
+ endMs,
3038
+ intervalMs
3039
+ }) || !hasBtcAltMetrics ? !hasBtcAltMetrics ? chunks : filterMissingBreadthBackfillChunks({
3040
+ chunks,
3041
+ coverage,
3042
+ intervalMs
3043
+ }) : [];
3044
+ if (!missingChunks2.length) {
3045
+ console.log(
3046
+ import_chalk.default.gray(`breadth cached: universe=${definition.universe}`)
3047
+ );
3057
3048
  }
3058
- const btcCandles = await connector.kline({
3059
- symbol: "BTCUSDT",
3049
+ return {
3050
+ definition,
3051
+ missingChunkKeys: new Set(
3052
+ missingChunks2.map((chunk) => `${chunk.startMs}:${chunk.endMs}`)
3053
+ )
3054
+ };
3055
+ })
3056
+ );
3057
+ const missingChunks = chunks.filter((chunk) => {
3058
+ const key = `${chunk.startMs}:${chunk.endMs}`;
3059
+ return plans.some((plan) => plan.missingChunkKeys.has(key));
3060
+ });
3061
+ const bar = new import_progress.default(
3062
+ "breadth :current/:total [:bar][:percent] :etas(s) candles=:candles skip=:skip chunk=:chunk :symbol",
3063
+ {
3064
+ total: Math.max(1, missingChunks.length * breadthSymbols.length),
3065
+ width: 24
3066
+ }
3067
+ );
3068
+ let candlesRead = 0;
3069
+ const skippedBreadthChunks = chunks.length - missingChunks.length;
3070
+ if (!missingChunks.length) {
3071
+ bar.tick(1, {
3072
+ candles: 0,
3073
+ skip: skippedBreadthChunks,
3074
+ chunk: "cached",
3075
+ symbol: "top5/top10/top30/top50/top100"
3076
+ });
3077
+ }
3078
+ for (let chunkIndex = 0; chunkIndex < missingChunks.length; chunkIndex += 1) {
3079
+ const chunk = missingChunks[chunkIndex];
3080
+ const originalChunkIndex = chunks.findIndex(
3081
+ (item) => item.startMs === chunk.startMs && item.endMs === chunk.endMs
3082
+ );
3083
+ const candlesBySymbol = {};
3084
+ for (const symbol of breadthSymbols) {
3085
+ const candles = await connector.kline({
3086
+ symbol,
3060
3087
  interval: connectorInterval,
3061
3088
  start: chunk.fetchStartMs,
3062
3089
  end: chunk.endMs,
3063
3090
  silent: true
3064
3091
  });
3092
+ candlesBySymbol[symbol] = candles;
3093
+ candlesRead += candles.length;
3094
+ bar.tick(1, {
3095
+ candles: candlesRead,
3096
+ skip: skippedBreadthChunks,
3097
+ chunk: `${originalChunkIndex + 1}/${chunks.length}`,
3098
+ symbol
3099
+ });
3100
+ }
3101
+ const btcCandles = await connector.kline({
3102
+ symbol: "BTCUSDT",
3103
+ interval: connectorInterval,
3104
+ start: chunk.fetchStartMs,
3105
+ end: chunk.endMs,
3106
+ silent: true
3107
+ });
3108
+ const chunkKey = `${chunk.startMs}:${chunk.endMs}`;
3109
+ for (const plan of plans) {
3110
+ if (!plan.missingChunkKeys.has(chunkKey)) {
3111
+ continue;
3112
+ }
3113
+ const symbolSet = new Set(plan.definition.symbols);
3114
+ const universeCandles = Object.fromEntries(
3115
+ Object.entries(candlesBySymbol).filter(
3116
+ ([symbol]) => symbolSet.has(symbol)
3117
+ )
3118
+ );
3065
3119
  const rows = buildMarketBreadthRows({
3066
- universe,
3120
+ universe: plan.definition.universe,
3067
3121
  interval: interval2,
3068
- candlesBySymbol,
3122
+ candlesBySymbol: universeCandles,
3069
3123
  btcCandles
3070
3124
  }).filter((row) => {
3071
3125
  const ts = row.ts.getTime();
@@ -3074,8 +3128,6 @@ var backfillBinanceMarketContext = async (params, enabled) => {
3074
3128
  await (0, import_timescale.upsertMarketBreadthRows)(rows);
3075
3129
  breadthRows += rows.length;
3076
3130
  }
3077
- } else {
3078
- console.log(import_chalk.default.gray(`breadth cached: universe=${universe}`));
3079
3131
  }
3080
3132
  }
3081
3133
  console.log(