@tradejs/cli 2.0.0 → 2.0.2
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 +384 -122
- package/dist/lib/aiTrainCharts.js +49 -2
- package/dist/lib/aiTrainMetrics.js +49 -2
- package/dist/lib/aiTrainResearch.js +58 -4
- package/dist/lib/derivativesContextBackfill.js +262 -107
- package/dist/lib/marketContextPrepare.js +256 -107
- package/dist/scripts/aiPocketSearch.js +49 -2
- package/dist/scripts/aiTrain.js +76 -4
- package/dist/scripts/backtest.js +256 -107
- package/dist/scripts/derivativesIngest.js +11 -4
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +38 -4
- package/dist/scripts/replay.js +256 -107
- package/dist/scripts/replayRunner.js +256 -107
- package/dist/scripts/runtimeParity.js +256 -107
- package/dist/scripts/signals.js +256 -107
- package/dist/scripts/signalsDaemon.js +256 -107
- package/package.json +9 -9
package/dist/cli.js
CHANGED
|
@@ -3005,7 +3005,7 @@ var init_aiTrainDataset = __esm({
|
|
|
3005
3005
|
});
|
|
3006
3006
|
|
|
3007
3007
|
// src/lib/aiTrainMetrics.ts
|
|
3008
|
-
var divideOrNull, DAY_MS, DAYS_PER_WEEK, DAYS_PER_MONTH, getEvaluationPeriodDays, qualitySortKey, emptyRiskSummary, summarizeApprovedRisk, summarizeAiTrainEvaluations, getDirectionSortKey, getMonthKey, isDirectionMatchAtThreshold, summarizeAiTrainEvaluationsByDirection, summarizeAiTrainEvaluationsByMonth, summarizeAiTrainEvaluationsByQualityThreshold;
|
|
3008
|
+
var divideOrNull, DAY_MS, DAYS_PER_WEEK, DAYS_PER_MONTH, DAYS_PER_YEAR, getEvaluationPeriodDays, qualitySortKey, calculateTradePnlRiskRatios, emptyRiskSummary, summarizeApprovedRisk, summarizeAiTrainEvaluations, getDirectionSortKey, getMonthKey, isDirectionMatchAtThreshold, summarizeAiTrainEvaluationsByDirection, summarizeAiTrainEvaluationsByMonth, summarizeAiTrainEvaluationsByQualityThreshold;
|
|
3009
3009
|
var init_aiTrainMetrics = __esm({
|
|
3010
3010
|
"src/lib/aiTrainMetrics.ts"() {
|
|
3011
3011
|
"use strict";
|
|
@@ -3018,6 +3018,7 @@ var init_aiTrainMetrics = __esm({
|
|
|
3018
3018
|
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
3019
3019
|
DAYS_PER_WEEK = 7;
|
|
3020
3020
|
DAYS_PER_MONTH = 30.4375;
|
|
3021
|
+
DAYS_PER_YEAR = 365;
|
|
3021
3022
|
getEvaluationPeriodDays = (evaluations) => {
|
|
3022
3023
|
let minTimestamp = null;
|
|
3023
3024
|
let maxTimestamp = null;
|
|
@@ -3039,6 +3040,40 @@ var init_aiTrainMetrics = __esm({
|
|
|
3039
3040
|
return Math.max((maxTimestamp - minTimestamp) / DAY_MS, 1);
|
|
3040
3041
|
};
|
|
3041
3042
|
qualitySortKey = (quality) => quality == null ? Number.POSITIVE_INFINITY : quality;
|
|
3043
|
+
calculateTradePnlRiskRatios = ({
|
|
3044
|
+
profits,
|
|
3045
|
+
totalProfit,
|
|
3046
|
+
maxDrawdown,
|
|
3047
|
+
periodDays
|
|
3048
|
+
}) => {
|
|
3049
|
+
if (!profits.length || periodDays == null || periodDays <= 0) {
|
|
3050
|
+
return {
|
|
3051
|
+
sharpeRatio: null,
|
|
3052
|
+
sortinoRatio: null,
|
|
3053
|
+
calmarRatio: null
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
3056
|
+
const meanProfit = totalProfit / profits.length;
|
|
3057
|
+
const variance = profits.reduce((sum2, profit) => {
|
|
3058
|
+
const diff = profit - meanProfit;
|
|
3059
|
+
return sum2 + diff * diff;
|
|
3060
|
+
}, 0) / profits.length;
|
|
3061
|
+
const stdDev = Math.sqrt(variance);
|
|
3062
|
+
const downsideDeviation = Math.sqrt(
|
|
3063
|
+
profits.reduce(
|
|
3064
|
+
(sum2, profit) => profit < 0 ? sum2 + profit * profit : sum2,
|
|
3065
|
+
0
|
|
3066
|
+
) / profits.length
|
|
3067
|
+
);
|
|
3068
|
+
const annualizationScale = Math.sqrt(
|
|
3069
|
+
profits.length / periodDays * DAYS_PER_YEAR
|
|
3070
|
+
);
|
|
3071
|
+
return {
|
|
3072
|
+
sharpeRatio: stdDev > 0 && annualizationScale > 0 ? meanProfit / stdDev * annualizationScale : null,
|
|
3073
|
+
sortinoRatio: downsideDeviation > 0 && annualizationScale > 0 ? meanProfit / downsideDeviation * annualizationScale : null,
|
|
3074
|
+
calmarRatio: maxDrawdown > 0 ? totalProfit / periodDays * DAYS_PER_YEAR / maxDrawdown : null
|
|
3075
|
+
};
|
|
3076
|
+
};
|
|
3042
3077
|
emptyRiskSummary = () => ({
|
|
3043
3078
|
trades: 0,
|
|
3044
3079
|
totalProfit: 0,
|
|
@@ -3054,12 +3089,15 @@ var init_aiTrainMetrics = __esm({
|
|
|
3054
3089
|
maxDrawdown: 0,
|
|
3055
3090
|
maxDrawdownPctOfGrossProfit: null,
|
|
3056
3091
|
maxDrawdownPctOfTotalProfit: null,
|
|
3092
|
+
sharpeRatio: null,
|
|
3093
|
+
sortinoRatio: null,
|
|
3094
|
+
calmarRatio: null,
|
|
3057
3095
|
recoveryFactor: null,
|
|
3058
3096
|
ulcerIndex: null,
|
|
3059
3097
|
maxConsecutiveWins: 0,
|
|
3060
3098
|
maxConsecutiveLosses: 0
|
|
3061
3099
|
});
|
|
3062
|
-
summarizeApprovedRisk = (evaluations) => {
|
|
3100
|
+
summarizeApprovedRisk = (evaluations, periodDays = getEvaluationPeriodDays(evaluations)) => {
|
|
3063
3101
|
const approvedEvaluations = evaluations.filter((evaluation) => evaluation.aiApproved).sort((left, right) => {
|
|
3064
3102
|
const leftTimestamp = typeof left.timestamp === "number" && Number.isFinite(left.timestamp) ? left.timestamp : Number.POSITIVE_INFINITY;
|
|
3065
3103
|
const rightTimestamp = typeof right.timestamp === "number" && Number.isFinite(right.timestamp) ? right.timestamp : Number.POSITIVE_INFINITY;
|
|
@@ -3082,8 +3120,10 @@ var init_aiTrainMetrics = __esm({
|
|
|
3082
3120
|
let currentLossStreak = 0;
|
|
3083
3121
|
let maxConsecutiveWins = 0;
|
|
3084
3122
|
let maxConsecutiveLosses = 0;
|
|
3123
|
+
const approvedProfits = [];
|
|
3085
3124
|
for (const evaluation of approvedEvaluations) {
|
|
3086
3125
|
const profit = evaluation.profit;
|
|
3126
|
+
approvedProfits.push(profit);
|
|
3087
3127
|
if (profit > 0) {
|
|
3088
3128
|
grossProfit += profit;
|
|
3089
3129
|
wins += 1;
|
|
@@ -3111,6 +3151,12 @@ var init_aiTrainMetrics = __esm({
|
|
|
3111
3151
|
const totalProfit = grossProfit - grossLoss;
|
|
3112
3152
|
const avgWin = divideOrNull(grossProfit, wins);
|
|
3113
3153
|
const avgLoss = divideOrNull(grossLoss, losses);
|
|
3154
|
+
const riskRatios = calculateTradePnlRiskRatios({
|
|
3155
|
+
profits: approvedProfits,
|
|
3156
|
+
totalProfit,
|
|
3157
|
+
maxDrawdown,
|
|
3158
|
+
periodDays
|
|
3159
|
+
});
|
|
3114
3160
|
return {
|
|
3115
3161
|
trades: approvedEvaluations.length,
|
|
3116
3162
|
totalProfit,
|
|
@@ -3126,6 +3172,7 @@ var init_aiTrainMetrics = __esm({
|
|
|
3126
3172
|
maxDrawdown,
|
|
3127
3173
|
maxDrawdownPctOfGrossProfit: grossProfit > 0 ? maxDrawdown / grossProfit : null,
|
|
3128
3174
|
maxDrawdownPctOfTotalProfit: totalProfit > 0 ? maxDrawdown / totalProfit : null,
|
|
3175
|
+
...riskRatios,
|
|
3129
3176
|
recoveryFactor: maxDrawdown > 0 ? totalProfit / maxDrawdown : null,
|
|
3130
3177
|
ulcerIndex: Math.sqrt(drawdownSquares / approvedEvaluations.length),
|
|
3131
3178
|
maxConsecutiveWins,
|
|
@@ -3224,7 +3271,7 @@ var init_aiTrainMetrics = __esm({
|
|
|
3224
3271
|
avgApprovedTradesPerDay,
|
|
3225
3272
|
avgApprovedTradesPerWeek,
|
|
3226
3273
|
expectancyDelta,
|
|
3227
|
-
approvedRisk: summarizeApprovedRisk(evaluations),
|
|
3274
|
+
approvedRisk: summarizeApprovedRisk(evaluations, periodDays),
|
|
3228
3275
|
qualityBuckets: [...bucketMap.values()].sort(
|
|
3229
3276
|
(a, b) => qualitySortKey(a.quality) - qualitySortKey(b.quality)
|
|
3230
3277
|
)
|
|
@@ -6135,7 +6182,7 @@ var init_aiTrainEvaluationDump = __esm({
|
|
|
6135
6182
|
});
|
|
6136
6183
|
|
|
6137
6184
|
// src/lib/aiTrainResearch.ts
|
|
6138
|
-
var import_node_child_process2, import_node_crypto2, import_promises4, import_node_path3, DAY_MS3, RESEARCH_CONTEXT_ENV_KEYS, normalizeForStableJson, fingerprintResearchValue, getTimestampRange, summarizeAiTrainCoverage, summarizeAiTrainRejectReasons, summarizeAiTrainTerminalWindows, readOptionalFile, getGitLineage, resolveGateFingerprint, buildAiTrainLineage;
|
|
6185
|
+
var import_node_child_process2, import_node_crypto2, import_promises4, import_node_path3, DAY_MS3, RESEARCH_CONTEXT_ENV_KEYS, DERIVATIVES_CONTEXT_DATA_MODEL, normalizeForStableJson, fingerprintResearchValue, getTimestampRange, summarizeAiTrainCoverage, summarizeAiTrainRejectReasons, summarizeAiTrainTerminalWindows, readOptionalFile, getGitLineage, resolveGateFingerprint, buildAiTrainLineage;
|
|
6139
6186
|
var init_aiTrainResearch = __esm({
|
|
6140
6187
|
"src/lib/aiTrainResearch.ts"() {
|
|
6141
6188
|
"use strict";
|
|
@@ -6151,7 +6198,6 @@ var init_aiTrainResearch = __esm({
|
|
|
6151
6198
|
"INTERVAL",
|
|
6152
6199
|
"DERIVATIVES_CONTEXT_ENABLED",
|
|
6153
6200
|
"DERIVATIVES_CONTEXT_TARGET_ENABLED",
|
|
6154
|
-
"DERIVATIVES_CONTEXT_INTERVALS",
|
|
6155
6201
|
"DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
|
|
6156
6202
|
"DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
|
|
6157
6203
|
"DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",
|
|
@@ -6165,6 +6211,12 @@ var init_aiTrainResearch = __esm({
|
|
|
6165
6211
|
"COINMARKETCAP_CONTEXT_BACKFILL_MAX_DAYS",
|
|
6166
6212
|
"COINMARKETCAP_CONTEXT_BACKFILL_WARMUP_DAYS"
|
|
6167
6213
|
];
|
|
6214
|
+
DERIVATIVES_CONTEXT_DATA_MODEL = {
|
|
6215
|
+
derivativesSourceIntervals: "15m",
|
|
6216
|
+
derivativesDerivedIntervals: "1h",
|
|
6217
|
+
derivativesHourlyFallback: "stored-1h",
|
|
6218
|
+
derivativesDataModelVersion: 2
|
|
6219
|
+
};
|
|
6168
6220
|
normalizeForStableJson = (value) => {
|
|
6169
6221
|
if (Array.isArray(value)) {
|
|
6170
6222
|
return value.map(normalizeForStableJson);
|
|
@@ -6277,6 +6329,7 @@ var init_aiTrainResearch = __esm({
|
|
|
6277
6329
|
const relativeCandidates = [
|
|
6278
6330
|
`packages/strategies/src/${strategyName}/adapters/ai.ts`,
|
|
6279
6331
|
`packages/strategies/src/${strategyName}/guardrails.ts`,
|
|
6332
|
+
`packages/strategies/src/${strategyName}/pockets.ts`,
|
|
6280
6333
|
`packages/strategies/src/${strategyName}/config.ts`,
|
|
6281
6334
|
"packages/node/src/ai.ts"
|
|
6282
6335
|
];
|
|
@@ -6323,7 +6376,8 @@ var init_aiTrainResearch = __esm({
|
|
|
6323
6376
|
...Object.fromEntries(
|
|
6324
6377
|
RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
|
|
6325
6378
|
),
|
|
6326
|
-
...runContext
|
|
6379
|
+
...runContext,
|
|
6380
|
+
...DERIVATIVES_CONTEXT_DATA_MODEL
|
|
6327
6381
|
};
|
|
6328
6382
|
return {
|
|
6329
6383
|
gitSha,
|
|
@@ -7403,6 +7457,9 @@ var init_aiTrain = __esm({
|
|
|
7403
7457
|
import_chalk5.default.gray("CALENDAR/D"),
|
|
7404
7458
|
import_chalk5.default.gray("WR"),
|
|
7405
7459
|
import_chalk5.default.gray("PF"),
|
|
7460
|
+
import_chalk5.default.gray("SHARPE"),
|
|
7461
|
+
import_chalk5.default.gray("SORTINO"),
|
|
7462
|
+
import_chalk5.default.gray("CALMAR"),
|
|
7406
7463
|
import_chalk5.default.gray("PNL"),
|
|
7407
7464
|
import_chalk5.default.gray("MAX_DD"),
|
|
7408
7465
|
import_chalk5.default.gray("TOP REJECT")
|
|
@@ -7417,6 +7474,9 @@ var init_aiTrain = __esm({
|
|
|
7417
7474
|
colorizeMetricNumber(window2.approvedPerCalendarDay),
|
|
7418
7475
|
colorizeRatio2(window2.outcome.approvedRisk.winRate),
|
|
7419
7476
|
colorizeMetricNumber(window2.outcome.approvedRisk.profitFactor),
|
|
7477
|
+
colorizeMetricNumber(window2.outcome.approvedRisk.sharpeRatio),
|
|
7478
|
+
colorizeMetricNumber(window2.outcome.approvedRisk.sortinoRatio),
|
|
7479
|
+
colorizeMetricNumber(window2.outcome.approvedRisk.calmarRatio),
|
|
7420
7480
|
colorizeProfit2(window2.outcome.approvedRisk.totalProfit),
|
|
7421
7481
|
colorizeProfit2(-window2.outcome.approvedRisk.maxDrawdown),
|
|
7422
7482
|
import_chalk5.default.gray(
|
|
@@ -7465,6 +7525,18 @@ var init_aiTrain = __esm({
|
|
|
7465
7525
|
"profit_factor",
|
|
7466
7526
|
colorizeMetricNumber(summary.approvedRisk.profitFactor)
|
|
7467
7527
|
],
|
|
7528
|
+
[
|
|
7529
|
+
"sharpe_ratio",
|
|
7530
|
+
colorizeMetricNumber(summary.approvedRisk.sharpeRatio)
|
|
7531
|
+
],
|
|
7532
|
+
[
|
|
7533
|
+
"sortino_ratio",
|
|
7534
|
+
colorizeMetricNumber(summary.approvedRisk.sortinoRatio)
|
|
7535
|
+
],
|
|
7536
|
+
[
|
|
7537
|
+
"calmar_ratio",
|
|
7538
|
+
colorizeMetricNumber(summary.approvedRisk.calmarRatio)
|
|
7539
|
+
],
|
|
7468
7540
|
[
|
|
7469
7541
|
"payoff_ratio",
|
|
7470
7542
|
colorizeMetricNumber(summary.approvedRisk.payoffRatio)
|
|
@@ -8591,7 +8663,7 @@ var init_binanceMarketContextBackfill = __esm({
|
|
|
8591
8663
|
});
|
|
8592
8664
|
|
|
8593
8665
|
// src/lib/derivativesContextBackfill.ts
|
|
8594
|
-
var import_chalk7, import_progress4, import_async, import_constants5, import_indicators, import_timescale2, import_userSettings2, HOUR_MS, DAY_MS6, DEFAULT_LOOKBACK_HOURS,
|
|
8666
|
+
var import_chalk7, import_progress4, import_async, import_constants5, import_indicators, import_timescale2, import_userSettings2, HOUR_MS, DAY_MS6, DEFAULT_LOOKBACK_HOURS, SOURCE_INTERVALS, coinalyzeIntervalMap, derivativesIntervalMs, lastRequestTs, asInt2, parseList, parseBooleanFlag, normalizeSymbols, isDerivativesTargetContextEnabled, resolveDerivativesContextBackfillSymbols, chunkArray, isBacktestDerivativesContextEnabled, isSignalsDerivativesContextEnabled, isDerivativesContextBackfillEnabled, shouldBackfillDerivativesContextForBacktest, shouldBackfillDerivativesContextForSignals, resolveDerivativesContextIntervals, resolveDerivativesContextLookbackMs, resolveDerivativesContextBackfillWindow, resolveDerivativesContextIntervalBackfillWindow, resolveDerivativesContextMissingFetchFromMs, resolveDerivativesContextFetchFromMs, resolveDerivativesContextRequiredFetchFromMs, countBackfillWindows, buildBackfillWindows, hasDerivativesWindowCoverage, resolveDerivativesContextMissingCoverageFetchFromMs, groupDerivativesContextMissingFetchRanges, getMissingClosedDerivativesSymbols, coverageKey, extendEdges, getCoinalyzeApiKey, getCoinalyzeBaseUrl, getRequestDelayMs, getRequestTimeoutMs, networkErrorCodes, getNestedErrorValue, getCoinalyzeErrorCause, isRetryableCoinalyzeFetchError, formatCoinalyzeRequestError, fetchJsonWithRateLimit, fetchCoinalyzeMarkets, selectBestMarket, buildMatches, normalizeMetricPoint, toSeriesMap, fetchMetricBatch, skippedBackfillResult2, backfillDerivativesContext, backfillDerivativesContextForBacktest, backfillDerivativesContextForSignals;
|
|
8595
8667
|
var init_derivativesContextBackfill = __esm({
|
|
8596
8668
|
"src/lib/derivativesContextBackfill.ts"() {
|
|
8597
8669
|
"use strict";
|
|
@@ -8605,7 +8677,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
8605
8677
|
HOUR_MS = 60 * 60 * 1e3;
|
|
8606
8678
|
DAY_MS6 = 24 * HOUR_MS;
|
|
8607
8679
|
DEFAULT_LOOKBACK_HOURS = 48;
|
|
8608
|
-
|
|
8680
|
+
SOURCE_INTERVALS = ["15m"];
|
|
8609
8681
|
coinalyzeIntervalMap = {
|
|
8610
8682
|
"15m": "15min",
|
|
8611
8683
|
"1h": "1hour"
|
|
@@ -8666,10 +8738,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
8666
8738
|
shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
|
|
8667
8739
|
shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
|
|
8668
8740
|
resolveDerivativesContextIntervals = () => {
|
|
8669
|
-
|
|
8670
|
-
process.env.DERIVATIVES_CONTEXT_INTERVALS
|
|
8671
|
-
);
|
|
8672
|
-
return intervals.length ? intervals : DEFAULT_INTERVALS;
|
|
8741
|
+
return [...SOURCE_INTERVALS];
|
|
8673
8742
|
};
|
|
8674
8743
|
resolveDerivativesContextLookbackMs = () => {
|
|
8675
8744
|
const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
|
|
@@ -8704,9 +8773,10 @@ var init_derivativesContextBackfill = __esm({
|
|
|
8704
8773
|
};
|
|
8705
8774
|
resolveDerivativesContextIntervalBackfillWindow = (params) => {
|
|
8706
8775
|
const intervalMs2 = derivativesIntervalMs(params.interval);
|
|
8776
|
+
const alignedToMs = params.closedOnly ? (0, import_indicators.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs2) * intervalMs2;
|
|
8707
8777
|
return {
|
|
8708
8778
|
fromMs: Math.floor(params.fromMs / intervalMs2) * intervalMs2,
|
|
8709
|
-
toMs:
|
|
8779
|
+
toMs: alignedToMs,
|
|
8710
8780
|
intervalMs: intervalMs2
|
|
8711
8781
|
};
|
|
8712
8782
|
};
|
|
@@ -8724,6 +8794,39 @@ var init_derivativesContextBackfill = __esm({
|
|
|
8724
8794
|
}
|
|
8725
8795
|
return null;
|
|
8726
8796
|
};
|
|
8797
|
+
resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
|
|
8798
|
+
resolveDerivativesContextRequiredFetchFromMs = (params) => {
|
|
8799
|
+
const dataCoverageFromMs = params.dataCoverageKeyExists ? null : params.mode === "signals" ? params.fromMs : resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
8800
|
+
ranges: params.dataCoverageRanges,
|
|
8801
|
+
fromMs: params.fromMs,
|
|
8802
|
+
toMs: params.toMs,
|
|
8803
|
+
intervalMs: params.intervalMs
|
|
8804
|
+
});
|
|
8805
|
+
const edgesFromMs = dataCoverageFromMs == null ? null : resolveDerivativesContextFetchFromMs({
|
|
8806
|
+
edges: params.edges,
|
|
8807
|
+
fromMs: params.fromMs,
|
|
8808
|
+
toMs: params.toMs,
|
|
8809
|
+
intervalMs: params.intervalMs,
|
|
8810
|
+
refreshClosedTail: params.mode === "signals"
|
|
8811
|
+
});
|
|
8812
|
+
const dataFetchFromMs = dataCoverageFromMs != null && edgesFromMs != null ? Math.max(dataCoverageFromMs, edgesFromMs) : null;
|
|
8813
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
8814
|
+
interval: params.interval,
|
|
8815
|
+
fromMs: params.fromMs,
|
|
8816
|
+
toMs: params.toMs,
|
|
8817
|
+
nowMs: params.nowMs
|
|
8818
|
+
});
|
|
8819
|
+
const liquidationFetchFromMs = confirmedLiquidationWindow ? resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
8820
|
+
ranges: params.liquidationCoverageRanges,
|
|
8821
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
8822
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
8823
|
+
intervalMs: params.intervalMs
|
|
8824
|
+
}) : null;
|
|
8825
|
+
const fetchStarts = [dataFetchFromMs, liquidationFetchFromMs].filter(
|
|
8826
|
+
(value) => value != null
|
|
8827
|
+
);
|
|
8828
|
+
return fetchStarts.length ? Math.min(...fetchStarts) : null;
|
|
8829
|
+
};
|
|
8727
8830
|
countBackfillWindows = (params) => {
|
|
8728
8831
|
let count = 0;
|
|
8729
8832
|
let cursor = params.fromMs;
|
|
@@ -8787,6 +8890,14 @@ var init_derivativesContextBackfill = __esm({
|
|
|
8787
8890
|
}
|
|
8788
8891
|
return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
|
|
8789
8892
|
};
|
|
8893
|
+
getMissingClosedDerivativesSymbols = (params) => {
|
|
8894
|
+
const availableSymbols = new Set(
|
|
8895
|
+
params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
|
|
8896
|
+
);
|
|
8897
|
+
return params.symbols.filter(
|
|
8898
|
+
(symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
|
|
8899
|
+
);
|
|
8900
|
+
};
|
|
8790
8901
|
coverageKey = (params) => [
|
|
8791
8902
|
params.symbol.trim().toUpperCase(),
|
|
8792
8903
|
params.interval,
|
|
@@ -9051,7 +9162,8 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9051
9162
|
mode,
|
|
9052
9163
|
startMs,
|
|
9053
9164
|
endMs,
|
|
9054
|
-
preloadStartMs: params.preloadStartMs
|
|
9165
|
+
preloadStartMs: params.preloadStartMs,
|
|
9166
|
+
nowMs: Date.now()
|
|
9055
9167
|
});
|
|
9056
9168
|
if (safeEndMs <= fromMs) {
|
|
9057
9169
|
return skippedBackfillResult2();
|
|
@@ -9066,7 +9178,8 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9066
9178
|
...resolveDerivativesContextIntervalBackfillWindow({
|
|
9067
9179
|
fromMs,
|
|
9068
9180
|
toMs: safeEndMs,
|
|
9069
|
-
interval: interval5
|
|
9181
|
+
interval: interval5,
|
|
9182
|
+
closedOnly: mode === "signals"
|
|
9070
9183
|
})
|
|
9071
9184
|
})).filter((item) => item.toMs > item.fromMs);
|
|
9072
9185
|
if (!intervalWindows.length) {
|
|
@@ -9084,15 +9197,33 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9084
9197
|
);
|
|
9085
9198
|
const coverageKeysByInterval = /* @__PURE__ */ new Map();
|
|
9086
9199
|
const coverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
9200
|
+
const liquidationCoverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
9201
|
+
const coverageNowMs = Date.now();
|
|
9087
9202
|
await Promise.all(
|
|
9088
9203
|
intervalWindows.map(async (window2) => {
|
|
9089
|
-
const
|
|
9090
|
-
source: "coinalyze",
|
|
9091
|
-
symbols,
|
|
9204
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
9092
9205
|
interval: window2.interval,
|
|
9093
9206
|
fromMs: window2.fromMs,
|
|
9094
|
-
toMs: window2.toMs
|
|
9207
|
+
toMs: window2.toMs,
|
|
9208
|
+
nowMs: coverageNowMs
|
|
9095
9209
|
});
|
|
9210
|
+
const [coverageRows, liquidationCoverageRows] = await Promise.all([
|
|
9211
|
+
(0, import_timescale2.getDerivativesBackfillCoverage)({
|
|
9212
|
+
source: "coinalyze",
|
|
9213
|
+
symbols,
|
|
9214
|
+
interval: window2.interval,
|
|
9215
|
+
fromMs: window2.fromMs,
|
|
9216
|
+
toMs: window2.toMs
|
|
9217
|
+
}),
|
|
9218
|
+
confirmedLiquidationWindow ? (0, import_timescale2.getDerivativesMetricCoverage)({
|
|
9219
|
+
source: "coinalyze",
|
|
9220
|
+
metric: "liquidation",
|
|
9221
|
+
symbols,
|
|
9222
|
+
interval: window2.interval,
|
|
9223
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
9224
|
+
toMs: confirmedLiquidationWindow.toMs
|
|
9225
|
+
}) : Promise.resolve([])
|
|
9226
|
+
]);
|
|
9096
9227
|
coverageKeysByInterval.set(
|
|
9097
9228
|
window2.interval,
|
|
9098
9229
|
new Set(
|
|
@@ -9114,6 +9245,17 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9114
9245
|
rangesBySymbol.set(symbol, ranges);
|
|
9115
9246
|
}
|
|
9116
9247
|
coverageRangesByInterval.set(window2.interval, rangesBySymbol);
|
|
9248
|
+
const liquidationRangesBySymbol = /* @__PURE__ */ new Map();
|
|
9249
|
+
for (const row of liquidationCoverageRows) {
|
|
9250
|
+
const symbol = row.symbol.toUpperCase();
|
|
9251
|
+
const ranges = liquidationRangesBySymbol.get(symbol) ?? [];
|
|
9252
|
+
ranges.push({ fromMs: row.fromMs, toMs: row.toMs });
|
|
9253
|
+
liquidationRangesBySymbol.set(symbol, ranges);
|
|
9254
|
+
}
|
|
9255
|
+
liquidationCoverageRangesByInterval.set(
|
|
9256
|
+
window2.interval,
|
|
9257
|
+
liquidationRangesBySymbol
|
|
9258
|
+
);
|
|
9117
9259
|
})
|
|
9118
9260
|
);
|
|
9119
9261
|
const cachedWindows = intervalWindows.reduce(
|
|
@@ -9125,7 +9267,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9125
9267
|
}),
|
|
9126
9268
|
0
|
|
9127
9269
|
);
|
|
9128
|
-
const allBackfillWindowsCached = intervalWindows.every((window2) => {
|
|
9270
|
+
const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
|
|
9129
9271
|
const edgesBySymbol = edgesByInterval.get(window2.interval);
|
|
9130
9272
|
const coverageKeys = coverageKeysByInterval.get(window2.interval);
|
|
9131
9273
|
const backfillWindows = buildBackfillWindows({
|
|
@@ -9138,7 +9280,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9138
9280
|
(symbol) => backfillWindows.every((backfillWindow) => {
|
|
9139
9281
|
const normalizedSymbol = symbol.toUpperCase();
|
|
9140
9282
|
const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
|
|
9141
|
-
|
|
9283
|
+
const dataCovered = hasDerivativesWindowCoverage({
|
|
9142
9284
|
edges: edgesBySymbol?.get(normalizedSymbol),
|
|
9143
9285
|
fromMs: backfillWindow.fromMs,
|
|
9144
9286
|
toMs: backfillWindow.toMs
|
|
@@ -9155,6 +9297,19 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9155
9297
|
toMs: backfillWindow.toMs
|
|
9156
9298
|
})
|
|
9157
9299
|
);
|
|
9300
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
9301
|
+
interval: window2.interval,
|
|
9302
|
+
fromMs: backfillWindow.fromMs,
|
|
9303
|
+
toMs: backfillWindow.toMs,
|
|
9304
|
+
nowMs: coverageNowMs
|
|
9305
|
+
});
|
|
9306
|
+
const liquidationCovered = confirmedLiquidationWindow == null || resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
9307
|
+
ranges: liquidationCoverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [],
|
|
9308
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
9309
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
9310
|
+
intervalMs: window2.intervalMs
|
|
9311
|
+
}) == null;
|
|
9312
|
+
return dataCovered && liquidationCovered;
|
|
9158
9313
|
})
|
|
9159
9314
|
);
|
|
9160
9315
|
});
|
|
@@ -9239,6 +9394,11 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9239
9394
|
coverageKeysByInterval.set(interval5, coverageKeys);
|
|
9240
9395
|
const coverageRangesBySymbol = coverageRangesByInterval.get(interval5) ?? /* @__PURE__ */ new Map();
|
|
9241
9396
|
coverageRangesByInterval.set(interval5, coverageRangesBySymbol);
|
|
9397
|
+
const liquidationCoverageRangesBySymbol = liquidationCoverageRangesByInterval.get(interval5) ?? /* @__PURE__ */ new Map();
|
|
9398
|
+
liquidationCoverageRangesByInterval.set(
|
|
9399
|
+
interval5,
|
|
9400
|
+
liquidationCoverageRangesBySymbol
|
|
9401
|
+
);
|
|
9242
9402
|
for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
|
|
9243
9403
|
const batch = symbolBatches[batchIdx];
|
|
9244
9404
|
let cursor = window2.fromMs;
|
|
@@ -9251,30 +9411,26 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9251
9411
|
fromMs: cursor,
|
|
9252
9412
|
toMs
|
|
9253
9413
|
});
|
|
9254
|
-
if (coverageKeys.has(key)) {
|
|
9255
|
-
return null;
|
|
9256
|
-
}
|
|
9257
9414
|
const normalizedSymbol = item.symbol.toUpperCase();
|
|
9258
|
-
const
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
}
|
|
9277
|
-
return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
|
|
9415
|
+
const requiredFromMs = resolveDerivativesContextRequiredFetchFromMs(
|
|
9416
|
+
{
|
|
9417
|
+
mode,
|
|
9418
|
+
interval: interval5,
|
|
9419
|
+
intervalMs: intervalMs2,
|
|
9420
|
+
fromMs: cursor,
|
|
9421
|
+
toMs,
|
|
9422
|
+
nowMs: coverageNowMs,
|
|
9423
|
+
dataCoverageKeyExists: coverageKeys.has(key),
|
|
9424
|
+
dataCoverageRanges: coverageRangesBySymbol.get(normalizedSymbol),
|
|
9425
|
+
liquidationCoverageRanges: liquidationCoverageRangesBySymbol.get(normalizedSymbol),
|
|
9426
|
+
edges: edgesBySymbol.get(normalizedSymbol)
|
|
9427
|
+
}
|
|
9428
|
+
);
|
|
9429
|
+
if (requiredFromMs == null) return null;
|
|
9430
|
+
return {
|
|
9431
|
+
item,
|
|
9432
|
+
fromMs: requiredFromMs
|
|
9433
|
+
};
|
|
9278
9434
|
}).filter(
|
|
9279
9435
|
(item) => item != null
|
|
9280
9436
|
);
|
|
@@ -9288,85 +9444,150 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9288
9444
|
const marketSymbols = missingBatch.map(
|
|
9289
9445
|
(item) => item.marketSymbol
|
|
9290
9446
|
);
|
|
9291
|
-
const
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
metric: "liq",
|
|
9312
|
-
marketSymbols,
|
|
9313
|
-
apiKey,
|
|
9314
|
-
interval: interval5,
|
|
9315
|
-
fromMs: group.fromMs,
|
|
9316
|
-
toMs
|
|
9317
|
-
});
|
|
9318
|
-
const rows = missingBatch.flatMap((item) => {
|
|
9319
|
-
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
9320
|
-
const points = (0, import_indicators.mergeCoinalyzeMetrics)({
|
|
9321
|
-
symbol: item.symbol,
|
|
9322
|
-
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
9323
|
-
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
9324
|
-
liqRaw: liqMap.get(marketSymbol) ?? []
|
|
9447
|
+
const maxClosedBarAttempts = mode === "signals" ? asInt2(
|
|
9448
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
|
|
9449
|
+
3
|
|
9450
|
+
) : 1;
|
|
9451
|
+
const closedBarRetryDelayMs = asInt2(
|
|
9452
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
|
|
9453
|
+
2e3
|
|
9454
|
+
);
|
|
9455
|
+
let rows = [];
|
|
9456
|
+
let missingClosedSymbols = [];
|
|
9457
|
+
let liquidationRowsByMarket = /* @__PURE__ */ new Map();
|
|
9458
|
+
for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
|
|
9459
|
+
const oiMap = await fetchMetricBatch({
|
|
9460
|
+
endpoint: oiPath,
|
|
9461
|
+
metric: "oi",
|
|
9462
|
+
marketSymbols,
|
|
9463
|
+
apiKey,
|
|
9464
|
+
interval: interval5,
|
|
9465
|
+
fromMs: group.fromMs,
|
|
9466
|
+
toMs
|
|
9325
9467
|
});
|
|
9326
|
-
|
|
9327
|
-
|
|
9468
|
+
const fundingMap = await fetchMetricBatch({
|
|
9469
|
+
endpoint: fundingPath,
|
|
9470
|
+
metric: "funding",
|
|
9471
|
+
marketSymbols,
|
|
9472
|
+
apiKey,
|
|
9473
|
+
interval: interval5,
|
|
9474
|
+
fromMs: group.fromMs,
|
|
9475
|
+
toMs
|
|
9476
|
+
});
|
|
9477
|
+
liquidationRowsByMarket = await fetchMetricBatch({
|
|
9478
|
+
endpoint: liqPath,
|
|
9479
|
+
metric: "liq",
|
|
9480
|
+
marketSymbols,
|
|
9481
|
+
apiKey,
|
|
9482
|
+
interval: interval5,
|
|
9483
|
+
fromMs: group.fromMs,
|
|
9484
|
+
toMs
|
|
9485
|
+
});
|
|
9486
|
+
rows = missingBatch.flatMap((item) => {
|
|
9487
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
9488
|
+
const points = (0, import_indicators.mergeCoinalyzeMetrics)({
|
|
9489
|
+
symbol: item.symbol,
|
|
9490
|
+
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
9491
|
+
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
9492
|
+
liqRaw: liquidationRowsByMarket.get(marketSymbol) ?? []
|
|
9493
|
+
});
|
|
9494
|
+
return (0, import_indicators.coinalyzePointsToRows)(points, interval5, "coinalyze");
|
|
9495
|
+
});
|
|
9496
|
+
missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
|
|
9497
|
+
symbols: missingBatch.map((item) => item.symbol),
|
|
9498
|
+
rows,
|
|
9499
|
+
expectedTimestamp: toMs
|
|
9500
|
+
}) : [];
|
|
9501
|
+
if (!missingClosedSymbols.length) break;
|
|
9502
|
+
if (attempt < maxClosedBarAttempts) {
|
|
9503
|
+
await (0, import_async.delay)(closedBarRetryDelayMs);
|
|
9504
|
+
}
|
|
9505
|
+
}
|
|
9506
|
+
if (missingClosedSymbols.length) {
|
|
9507
|
+
throw new Error(
|
|
9508
|
+
`Coinalyze closed ${interval5} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
|
|
9509
|
+
);
|
|
9510
|
+
}
|
|
9328
9511
|
if (rows.length) {
|
|
9329
9512
|
await (0, import_timescale2.upsertDerivatives)(rows);
|
|
9330
9513
|
totalRows += rows.length;
|
|
9331
9514
|
}
|
|
9332
|
-
const
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
9338
|
-
);
|
|
9339
|
-
}
|
|
9340
|
-
const coverageRows = missingBatch.map((item) => {
|
|
9341
|
-
const normalizedSymbol = item.symbol.toUpperCase();
|
|
9342
|
-
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
9343
|
-
return {
|
|
9344
|
-
source: "coinalyze",
|
|
9345
|
-
symbol: item.symbol,
|
|
9346
|
-
interval: interval5,
|
|
9347
|
-
fromMs: cursor,
|
|
9348
|
-
toMs,
|
|
9349
|
-
rowsCount
|
|
9350
|
-
};
|
|
9515
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
9516
|
+
interval: interval5,
|
|
9517
|
+
fromMs: group.fromMs,
|
|
9518
|
+
toMs,
|
|
9519
|
+
nowMs: coverageNowMs
|
|
9351
9520
|
});
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9521
|
+
if (confirmedLiquidationWindow) {
|
|
9522
|
+
const metricCoverageRows = missingBatch.map((item) => {
|
|
9523
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
9524
|
+
const eventRowsCount = (liquidationRowsByMarket.get(marketSymbol) ?? []).filter((point) => {
|
|
9525
|
+
const timestamp = (0, import_indicators.toCoinalyzeTimestampMs)(
|
|
9526
|
+
point.t ?? point.ts ?? point.time ?? point.timestamp
|
|
9527
|
+
);
|
|
9528
|
+
return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
|
|
9529
|
+
}).length;
|
|
9530
|
+
return {
|
|
9531
|
+
source: "coinalyze",
|
|
9532
|
+
metric: "liquidation",
|
|
9533
|
+
symbol: item.symbol,
|
|
9534
|
+
interval: interval5,
|
|
9535
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
9536
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
9537
|
+
eventRowsCount
|
|
9538
|
+
};
|
|
9539
|
+
});
|
|
9540
|
+
await (0, import_timescale2.applyDerivativesMetricCoverage)(metricCoverageRows);
|
|
9541
|
+
for (const coverageRow of metricCoverageRows) {
|
|
9542
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
9543
|
+
const ranges = liquidationCoverageRangesBySymbol.get(symbol) ?? [];
|
|
9544
|
+
ranges.push({
|
|
9545
|
+
fromMs: coverageRow.fromMs,
|
|
9546
|
+
toMs: coverageRow.toMs
|
|
9547
|
+
});
|
|
9548
|
+
liquidationCoverageRangesBySymbol.set(symbol, ranges);
|
|
9549
|
+
}
|
|
9550
|
+
}
|
|
9551
|
+
if (mode === "backtest") {
|
|
9552
|
+
const rowsCountBySymbol = /* @__PURE__ */ new Map();
|
|
9553
|
+
for (const row of rows) {
|
|
9554
|
+
const symbol = row.symbol.toUpperCase();
|
|
9555
|
+
rowsCountBySymbol.set(
|
|
9361
9556
|
symbol,
|
|
9557
|
+
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
9558
|
+
);
|
|
9559
|
+
}
|
|
9560
|
+
const coverageRows = missingBatch.map((item) => {
|
|
9561
|
+
const normalizedSymbol = item.symbol.toUpperCase();
|
|
9562
|
+
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
9563
|
+
return {
|
|
9564
|
+
source: "coinalyze",
|
|
9565
|
+
symbol: item.symbol,
|
|
9362
9566
|
interval: interval5,
|
|
9363
9567
|
fromMs: cursor,
|
|
9364
|
-
toMs
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9568
|
+
toMs,
|
|
9569
|
+
rowsCount
|
|
9570
|
+
};
|
|
9571
|
+
});
|
|
9572
|
+
await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
|
|
9573
|
+
for (const coverageRow of coverageRows) {
|
|
9574
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
9575
|
+
edgesBySymbol.set(
|
|
9576
|
+
symbol,
|
|
9577
|
+
extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
|
|
9578
|
+
);
|
|
9579
|
+
coverageKeys.add(
|
|
9580
|
+
coverageKey({
|
|
9581
|
+
symbol,
|
|
9582
|
+
interval: interval5,
|
|
9583
|
+
fromMs: cursor,
|
|
9584
|
+
toMs
|
|
9585
|
+
})
|
|
9586
|
+
);
|
|
9587
|
+
const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
|
|
9588
|
+
coverageRanges.push({ fromMs: cursor, toMs });
|
|
9589
|
+
coverageRangesBySymbol.set(symbol, coverageRanges);
|
|
9590
|
+
}
|
|
9370
9591
|
}
|
|
9371
9592
|
}
|
|
9372
9593
|
}
|
|
@@ -18915,11 +19136,11 @@ var init_derivativesIngest = __esm({
|
|
|
18915
19136
|
import_userSettings4 = require("@tradejs/infra/userSettings");
|
|
18916
19137
|
import_connectors9 = require("@tradejs/connectors");
|
|
18917
19138
|
import_args12.default.example(
|
|
18918
|
-
"yarn ts-node ./src/scripts/derivativesIngest --provider coinalyze --symbols BTCUSDT,ETHUSDT --intervals 15m
|
|
19139
|
+
"yarn ts-node ./src/scripts/derivativesIngest --provider coinalyze --symbols BTCUSDT,ETHUSDT --intervals 15m --days 120",
|
|
18919
19140
|
"Ingest market features (derivatives/spread) into Timescale by provider"
|
|
18920
19141
|
);
|
|
18921
19142
|
import_args12.default.option(["s", "symbols"], "Comma-separated symbols", "BTCUSDT,ETHUSDT");
|
|
18922
|
-
import_args12.default.option(["t", "intervals"], "Comma-separated intervals: 15m,1h", "15m
|
|
19143
|
+
import_args12.default.option(["t", "intervals"], "Comma-separated intervals: 15m,1h", "15m");
|
|
18923
19144
|
import_args12.default.option(["d", "days"], "Lookback in days", 120);
|
|
18924
19145
|
import_args12.default.option(
|
|
18925
19146
|
["p", "provider"],
|
|
@@ -18956,9 +19177,16 @@ var init_derivativesIngest = __esm({
|
|
|
18956
19177
|
let totalSpreadRows = 0;
|
|
18957
19178
|
for (const symbol of symbols) {
|
|
18958
19179
|
for (const interval5 of intervals) {
|
|
19180
|
+
const lastClosedStartMs = (0, import_indicators2.getLastClosedDerivativesBarStartMs)(
|
|
19181
|
+
now2,
|
|
19182
|
+
interval5
|
|
19183
|
+
);
|
|
18959
19184
|
let cursor = fromMs;
|
|
18960
|
-
while (cursor <
|
|
18961
|
-
const toMs = Math.min(
|
|
19185
|
+
while (cursor < lastClosedStartMs) {
|
|
19186
|
+
const toMs = Math.min(
|
|
19187
|
+
lastClosedStartMs,
|
|
19188
|
+
cursor + batchDays * 24 * 60 * 60 * 1e3
|
|
19189
|
+
);
|
|
18962
19190
|
process.stdout.write(
|
|
18963
19191
|
`\r${import_chalk20.default.cyan(providerName)} ${import_chalk20.default.yellow(symbol)} ${interval5} ${new Date(cursor).toISOString()} .. ${new Date(toMs).toISOString()} `
|
|
18964
19192
|
);
|
|
@@ -19018,7 +19246,7 @@ var init_derivativesIngestCoinalyzeAll = __esm({
|
|
|
19018
19246
|
"1h": "1hour"
|
|
19019
19247
|
};
|
|
19020
19248
|
import_args13.default.example(
|
|
19021
|
-
"yarn ts-node ./src/scripts/derivativesIngestCoinalyzeAll --days 120 --intervals 15m
|
|
19249
|
+
"yarn ts-node ./src/scripts/derivativesIngestCoinalyzeAll --days 120 --intervals 15m",
|
|
19022
19250
|
"Fetch derivatives for all getTickers symbols matched to Coinalyze markets"
|
|
19023
19251
|
);
|
|
19024
19252
|
import_args13.default.option(["U", "user"], "User settings profile name from Redis", "root");
|
|
@@ -19026,7 +19254,7 @@ var init_derivativesIngestCoinalyzeAll = __esm({
|
|
|
19026
19254
|
import_args13.default.option(["e", "exclude"], "Comma-separated exclude symbols");
|
|
19027
19255
|
import_args13.default.option(["l", "tickersLimit"], "Tickers limit");
|
|
19028
19256
|
import_args13.default.option(["c", "chunk"], "Chunk selector, e.g. 1/4");
|
|
19029
|
-
import_args13.default.option(["i", "intervals"], "Intervals: 15m,1h", "15m
|
|
19257
|
+
import_args13.default.option(["i", "intervals"], "Intervals: 15m,1h", "15m");
|
|
19030
19258
|
import_args13.default.option(["d", "days"], "Lookback in days", 120);
|
|
19031
19259
|
import_args13.default.option(["b", "batchDays"], "Request chunk size in days", 120);
|
|
19032
19260
|
import_args13.default.option(
|
|
@@ -19295,12 +19523,16 @@ var init_derivativesIngestCoinalyzeAll = __esm({
|
|
|
19295
19523
|
let totalRows = 0;
|
|
19296
19524
|
let failedWindows = 0;
|
|
19297
19525
|
for (const interval5 of intervals) {
|
|
19526
|
+
const lastClosedStartMs = (0, import_indicators3.getLastClosedDerivativesBarStartMs)(now2, interval5);
|
|
19298
19527
|
for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
|
|
19299
19528
|
const batch = symbolBatches[batchIdx];
|
|
19300
19529
|
const marketSymbols = batch.map((item) => item.marketSymbol);
|
|
19301
19530
|
let cursor = fromMs;
|
|
19302
|
-
while (cursor <
|
|
19303
|
-
const toMs = Math.min(
|
|
19531
|
+
while (cursor < lastClosedStartMs) {
|
|
19532
|
+
const toMs = Math.min(
|
|
19533
|
+
lastClosedStartMs,
|
|
19534
|
+
cursor + batchDays * 24 * 60 * 60 * 1e3
|
|
19535
|
+
);
|
|
19304
19536
|
try {
|
|
19305
19537
|
const oiMap = await fetchMetricBatch2({
|
|
19306
19538
|
endpoint: oiPath,
|
|
@@ -19343,6 +19575,36 @@ var init_derivativesIngestCoinalyzeAll = __esm({
|
|
|
19343
19575
|
await (0, import_timescale7.upsertDerivatives)(rows);
|
|
19344
19576
|
totalRows += rows.length;
|
|
19345
19577
|
}
|
|
19578
|
+
const confirmedLiquidationWindow = (0, import_indicators3.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
19579
|
+
interval: interval5,
|
|
19580
|
+
fromMs: cursor,
|
|
19581
|
+
toMs,
|
|
19582
|
+
nowMs: now2
|
|
19583
|
+
});
|
|
19584
|
+
if (confirmedLiquidationWindow) {
|
|
19585
|
+
await (0, import_timescale7.applyDerivativesMetricCoverage)(
|
|
19586
|
+
batch.map((item) => {
|
|
19587
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
19588
|
+
const eventRowsCount = (liqMap.get(marketSymbol) ?? []).filter(
|
|
19589
|
+
(point) => {
|
|
19590
|
+
const timestamp = (0, import_indicators3.toCoinalyzeTimestampMs)(
|
|
19591
|
+
point.t ?? point.ts ?? point.time ?? point.timestamp
|
|
19592
|
+
);
|
|
19593
|
+
return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
|
|
19594
|
+
}
|
|
19595
|
+
).length;
|
|
19596
|
+
return {
|
|
19597
|
+
source: "coinalyze",
|
|
19598
|
+
metric: "liquidation",
|
|
19599
|
+
symbol: item.symbol,
|
|
19600
|
+
interval: interval5,
|
|
19601
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
19602
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
19603
|
+
eventRowsCount
|
|
19604
|
+
};
|
|
19605
|
+
})
|
|
19606
|
+
);
|
|
19607
|
+
}
|
|
19346
19608
|
} catch (error) {
|
|
19347
19609
|
failedWindows += 1;
|
|
19348
19610
|
console.error(
|