@tradejs/cli 2.0.6 → 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.
- package/dist/cli.js +2448 -1374
- package/dist/lib/aiExport.js +1822 -0
- package/dist/lib/binanceMarketContextBackfill.js +97 -88
- package/dist/lib/binanceMarketData.js +6 -3
- package/dist/lib/marketContextPrepare.js +97 -88
- package/dist/lib/runEnvironment.js +48 -18
- package/dist/lib/runtimeLineage.js +255 -0
- package/dist/lib/runtimeParityDetails.js +24 -1
- package/dist/lib/runtimeSignalsLoader.js +19 -0
- package/dist/lib/runtimeSignalsStorage.js +3 -0
- package/dist/lib/runtimeTradeSync.js +40 -11
- package/dist/lib/timeWindow.js +44 -16
- package/dist/scripts/aiExport.js +200 -88
- package/dist/scripts/backtest.js +170 -107
- package/dist/scripts/binanceBreadthUniversesUpdate.js +120 -0
- package/dist/scripts/binanceMarketIngest.js +32 -33
- package/dist/scripts/mlExport.js +5 -2
- package/dist/scripts/replay.js +988 -218
- package/dist/scripts/replayRunner.js +988 -218
- package/dist/scripts/replayRuntimeEvidence.js +3 -1
- package/dist/scripts/resolveExportStrategy.js +7 -2
- package/dist/scripts/runtimeParity.js +141 -104
- package/dist/scripts/signals.js +381 -107
- package/dist/scripts/signalsDaemon.js +381 -107
- package/dist/scripts/signalsSummary.js +40 -11
- package/package.json +10 -9
|
@@ -520,8 +520,10 @@ var REPLAY_RUNTIME_COMPARISON_HEADERS = [
|
|
|
520
520
|
import_chalk.default.yellow("RT TRADES"),
|
|
521
521
|
import_chalk.default.yellow("RT PNL"),
|
|
522
522
|
import_chalk.default.green("MATCHED"),
|
|
523
|
+
import_chalk.default.red("ORDER FAILED"),
|
|
523
524
|
import_chalk.default.yellow("RT ONLY"),
|
|
524
|
-
import_chalk.default.magenta("BT ONLY")
|
|
525
|
+
import_chalk.default.magenta("BT ONLY"),
|
|
526
|
+
import_chalk.default.red("UNMATCHED")
|
|
525
527
|
];
|
|
526
528
|
var REPLAY_RESULTS_CONFIG = "replay";
|
|
527
529
|
var REPLAY_RUNTIME_COMPARE_TOLERANCE_BARS = 1;
|
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/scripts/resolveExportStrategy.ts
|
|
31
31
|
var resolveExportStrategy_exports = {};
|
|
32
32
|
__export(resolveExportStrategy_exports, {
|
|
33
|
+
ALL_EXPORT_STRATEGIES: () => ALL_EXPORT_STRATEGIES,
|
|
33
34
|
resolveExportStrategy: () => resolveExportStrategy
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(resolveExportStrategy_exports);
|
|
@@ -100,12 +101,14 @@ var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
|
100
101
|
};
|
|
101
102
|
|
|
102
103
|
// src/scripts/resolveExportStrategy.ts
|
|
104
|
+
var ALL_EXPORT_STRATEGIES = "all";
|
|
103
105
|
var resolveExportStrategy = async ({
|
|
104
106
|
explicitStrategy,
|
|
105
107
|
outDir,
|
|
106
108
|
datasetLabel,
|
|
107
109
|
promptLabel,
|
|
108
|
-
listStrategies
|
|
110
|
+
listStrategies,
|
|
111
|
+
includeAllOption = false
|
|
109
112
|
}) => {
|
|
110
113
|
const raw = String(explicitStrategy || "").trim();
|
|
111
114
|
if (raw) {
|
|
@@ -123,12 +126,14 @@ var resolveExportStrategy = async ({
|
|
|
123
126
|
`Multiple ${datasetLabel} chunk strategies found in ${outDir}: ${availableStrategies.join(", ")}. Pass --strategy.`
|
|
124
127
|
);
|
|
125
128
|
}
|
|
129
|
+
const promptStrategies = includeAllOption ? [...availableStrategies, ALL_EXPORT_STRATEGIES] : availableStrategies;
|
|
126
130
|
return selectStrategy(promptLabel, {
|
|
127
|
-
strategies:
|
|
131
|
+
strategies: promptStrategies,
|
|
128
132
|
defaultStrategy: availableStrategies[0]
|
|
129
133
|
});
|
|
130
134
|
};
|
|
131
135
|
// Annotate the CommonJS export names for ESM import in node:
|
|
132
136
|
0 && (module.exports = {
|
|
137
|
+
ALL_EXPORT_STRATEGIES,
|
|
133
138
|
resolveExportStrategy
|
|
134
139
|
});
|
|
@@ -2256,11 +2256,30 @@ var resolveTimeWindow = ({
|
|
|
2256
2256
|
endTime,
|
|
2257
2257
|
nowMs = Date.now(),
|
|
2258
2258
|
defaultStartMs,
|
|
2259
|
-
defaultEndMs
|
|
2259
|
+
defaultEndMs,
|
|
2260
|
+
closedIntervalMs
|
|
2260
2261
|
}) => {
|
|
2261
2262
|
const explicitStart = toEpochMs(startTime);
|
|
2262
2263
|
const explicitEnd = toEpochMs(endTime);
|
|
2263
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
|
+
};
|
|
2264
2283
|
if (explicitStart != null || explicitEnd != null) {
|
|
2265
2284
|
const resolvedStart = explicitStart ?? (resolvedDays != null && explicitEnd != null ? explicitEnd - resolvedDays * ONE_DAY_MS : defaultStartMs);
|
|
2266
2285
|
const resolvedEnd2 = explicitEnd ?? (resolvedDays != null && explicitStart != null ? explicitStart + resolvedDays * ONE_DAY_MS : defaultEndMs ?? nowMs);
|
|
@@ -2269,11 +2288,14 @@ var resolveTimeWindow = ({
|
|
|
2269
2288
|
`Invalid time window: startTime (${resolvedStart}) must be less than endTime (${resolvedEnd2})`
|
|
2270
2289
|
);
|
|
2271
2290
|
}
|
|
2272
|
-
return
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2291
|
+
return alignToLastClosedInterval(
|
|
2292
|
+
{
|
|
2293
|
+
start: resolvedStart,
|
|
2294
|
+
end: resolvedEnd2,
|
|
2295
|
+
source: "explicit"
|
|
2296
|
+
},
|
|
2297
|
+
explicitStart == null && resolvedDays != null
|
|
2298
|
+
);
|
|
2277
2299
|
}
|
|
2278
2300
|
if (resolvedDays != null) {
|
|
2279
2301
|
const resolvedEnd2 = defaultEndMs ?? nowMs;
|
|
@@ -2283,11 +2305,14 @@ var resolveTimeWindow = ({
|
|
|
2283
2305
|
`Invalid time window: computed start (${resolvedStart}) must be less than end (${resolvedEnd2})`
|
|
2284
2306
|
);
|
|
2285
2307
|
}
|
|
2286
|
-
return
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2308
|
+
return alignToLastClosedInterval(
|
|
2309
|
+
{
|
|
2310
|
+
start: Math.trunc(resolvedStart),
|
|
2311
|
+
end: Math.trunc(resolvedEnd2),
|
|
2312
|
+
source: "days"
|
|
2313
|
+
},
|
|
2314
|
+
true
|
|
2315
|
+
);
|
|
2291
2316
|
}
|
|
2292
2317
|
const resolvedEnd = defaultEndMs ?? nowMs;
|
|
2293
2318
|
if (defaultStartMs >= resolvedEnd) {
|
|
@@ -2295,11 +2320,14 @@ var resolveTimeWindow = ({
|
|
|
2295
2320
|
`Invalid default time window: start (${defaultStartMs}) must be less than end (${resolvedEnd})`
|
|
2296
2321
|
);
|
|
2297
2322
|
}
|
|
2298
|
-
return
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2323
|
+
return alignToLastClosedInterval(
|
|
2324
|
+
{
|
|
2325
|
+
start: Math.trunc(defaultStartMs),
|
|
2326
|
+
end: Math.trunc(resolvedEnd),
|
|
2327
|
+
source: "default"
|
|
2328
|
+
},
|
|
2329
|
+
true
|
|
2330
|
+
);
|
|
2303
2331
|
};
|
|
2304
2332
|
|
|
2305
2333
|
// src/lib/runFormatting.ts
|
|
@@ -2329,6 +2357,7 @@ var import_progress = __toESM(require("progress"));
|
|
|
2329
2357
|
var import_chalk = __toESM(require("chalk"));
|
|
2330
2358
|
var import_connectors = require("@tradejs/connectors");
|
|
2331
2359
|
var import_connectors2 = require("@tradejs/node/connectors");
|
|
2360
|
+
var import_strategies = require("@tradejs/node/strategies");
|
|
2332
2361
|
var import_timescale = require("@tradejs/infra/timescale");
|
|
2333
2362
|
|
|
2334
2363
|
// src/lib/binanceMarketData.ts
|
|
@@ -2338,14 +2367,6 @@ var MARKET_FEATURE_INTERVAL_MS = {
|
|
|
2338
2367
|
"15m": 9e5,
|
|
2339
2368
|
"1h": 36e5
|
|
2340
2369
|
};
|
|
2341
|
-
var STABLE_QUOTE_SYMBOLS = /* @__PURE__ */ new Set([
|
|
2342
|
-
"USDCUSDT",
|
|
2343
|
-
"FDUSDUSDT",
|
|
2344
|
-
"TUSDUSDT",
|
|
2345
|
-
"BUSDUSDT",
|
|
2346
|
-
"USDPUSDT",
|
|
2347
|
-
"DAIUSDT"
|
|
2348
|
-
]);
|
|
2349
2370
|
var safeDivide = (num, den) => Number.isFinite(num) && Number.isFinite(den) && den !== 0 ? num / den : null;
|
|
2350
2371
|
var mean = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
|
|
2351
2372
|
var standardDeviation = (values) => {
|
|
@@ -2389,9 +2410,6 @@ var classifyBtcAltRegime = ({
|
|
|
2389
2410
|
if (btcVsAltReturn24h < -5e-3) return "alt_lead";
|
|
2390
2411
|
return "neutral";
|
|
2391
2412
|
};
|
|
2392
|
-
var selectBreadthUniverseFromTickers = (tickers, limit) => tickers.filter(
|
|
2393
|
-
(ticker) => ticker.symbol.endsWith("USDT") && ticker.symbol !== "BTCUSDT" && !STABLE_QUOTE_SYMBOLS.has(ticker.symbol) && Number.isFinite(ticker.turnover24h) && ticker.turnover24h > 0
|
|
2394
|
-
).sort((a, b) => b.turnover24h - a.turnover24h).slice(0, Math.max(0, limit)).map((ticker) => ticker.symbol);
|
|
2395
2413
|
var aggregateAggTradesToRows = ({
|
|
2396
2414
|
symbol,
|
|
2397
2415
|
interval: interval2,
|
|
@@ -2873,10 +2891,6 @@ var backfillBinanceMarketContext = async (params, enabled) => {
|
|
|
2873
2891
|
process.env.BINANCE_MARKET_CONTEXT_TRADE_FLOW_SYMBOL_LIMIT,
|
|
2874
2892
|
2
|
|
2875
2893
|
);
|
|
2876
|
-
const breadthLimit = asInt(
|
|
2877
|
-
process.env.BINANCE_MARKET_CONTEXT_BREADTH_LIMIT,
|
|
2878
|
-
30
|
|
2879
|
-
);
|
|
2880
2894
|
const breadthChunkDays = asFloat(
|
|
2881
2895
|
process.env.BINANCE_MARKET_CONTEXT_BREADTH_CHUNK_DAYS,
|
|
2882
2896
|
30
|
|
@@ -2999,88 +3013,113 @@ var backfillBinanceMarketContext = async (params, enabled) => {
|
|
|
2999
3013
|
}
|
|
3000
3014
|
}
|
|
3001
3015
|
if (includeBreadth) {
|
|
3002
|
-
const
|
|
3003
|
-
const breadthSymbols =
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
);
|
|
3007
|
-
const universe = `binance_top${breadthSymbols.length}_usdt`;
|
|
3008
|
-
const coverage = await (0, import_timescale.getMarketBreadthCoverage)({
|
|
3009
|
-
universe,
|
|
3010
|
-
interval: interval2,
|
|
3011
|
-
startMs: breadthStartMs,
|
|
3012
|
-
endMs
|
|
3013
|
-
});
|
|
3014
|
-
const hasBtcAltMetrics = (coverage?.btcAltMetricsRows ?? 0) >= Math.floor(Math.max(1, coverage?.rows ?? 0) * 0.9);
|
|
3015
|
-
if (!hasCoverage({
|
|
3016
|
-
coverage,
|
|
3016
|
+
const breadthUniverses = (0, import_strategies.getBinanceBreadthUniverses)();
|
|
3017
|
+
const breadthSymbols = breadthUniverses.at(-1)?.symbols ?? [];
|
|
3018
|
+
const connectorInterval = marketIntervalToConnectorInterval(interval2);
|
|
3019
|
+
const chunks = buildBreadthBackfillChunks({
|
|
3017
3020
|
startMs: breadthStartMs,
|
|
3018
3021
|
endMs,
|
|
3019
|
-
intervalMs
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
chunks,
|
|
3030
|
-
coverage,
|
|
3031
|
-
intervalMs
|
|
3032
|
-
});
|
|
3033
|
-
const bar = new import_progress.default(
|
|
3034
|
-
"breadth :current/:total [:bar][:percent] :etas(s) candles=:candles skip=:skip chunk=:chunk :symbol",
|
|
3035
|
-
{
|
|
3036
|
-
total: Math.max(1, missingChunks.length * breadthSymbols.length),
|
|
3037
|
-
width: 24
|
|
3038
|
-
}
|
|
3039
|
-
);
|
|
3040
|
-
let candlesRead = 0;
|
|
3041
|
-
let skippedBreadthChunks = chunks.length - missingChunks.length;
|
|
3042
|
-
if (!missingChunks.length) {
|
|
3043
|
-
bar.tick(1, {
|
|
3044
|
-
candles: 0,
|
|
3045
|
-
skip: skippedBreadthChunks,
|
|
3046
|
-
chunk: "cached",
|
|
3047
|
-
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
|
|
3048
3032
|
});
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
candlesBySymbol[symbol] = candles;
|
|
3065
|
-
candlesRead += candles.length;
|
|
3066
|
-
bar.tick(1, {
|
|
3067
|
-
candles: candlesRead,
|
|
3068
|
-
skip: skippedBreadthChunks,
|
|
3069
|
-
chunk: `${originalChunkIndex + 1}/${chunks.length}`,
|
|
3070
|
-
symbol
|
|
3071
|
-
});
|
|
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
|
+
);
|
|
3072
3048
|
}
|
|
3073
|
-
|
|
3074
|
-
|
|
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,
|
|
3075
3087
|
interval: connectorInterval,
|
|
3076
3088
|
start: chunk.fetchStartMs,
|
|
3077
3089
|
end: chunk.endMs,
|
|
3078
3090
|
silent: true
|
|
3079
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
|
+
);
|
|
3080
3119
|
const rows = buildMarketBreadthRows({
|
|
3081
|
-
universe,
|
|
3120
|
+
universe: plan.definition.universe,
|
|
3082
3121
|
interval: interval2,
|
|
3083
|
-
candlesBySymbol,
|
|
3122
|
+
candlesBySymbol: universeCandles,
|
|
3084
3123
|
btcCandles
|
|
3085
3124
|
}).filter((row) => {
|
|
3086
3125
|
const ts = row.ts.getTime();
|
|
@@ -3089,8 +3128,6 @@ var backfillBinanceMarketContext = async (params, enabled) => {
|
|
|
3089
3128
|
await (0, import_timescale.upsertMarketBreadthRows)(rows);
|
|
3090
3129
|
breadthRows += rows.length;
|
|
3091
3130
|
}
|
|
3092
|
-
} else {
|
|
3093
|
-
console.log(import_chalk.default.gray(`breadth cached: universe=${universe}`));
|
|
3094
3131
|
}
|
|
3095
3132
|
}
|
|
3096
3133
|
console.log(
|