@tradejs/cli 2.0.1 → 2.0.3
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 +293 -58
- package/dist/lib/aiPocketSearch.js +18 -0
- package/dist/lib/aiTrainCharts.js +49 -2
- package/dist/lib/aiTrainMetrics.js +49 -2
- package/dist/lib/aiTrainResearch.js +58 -3
- package/dist/lib/derivativesContextBackfill.js +143 -32
- package/dist/lib/marketContextPrepare.js +141 -32
- package/dist/lib/runtimeTradeSync.js +22 -15
- package/dist/scripts/aiExport.js +2 -1
- package/dist/scripts/aiExportSelect.js +2 -1
- package/dist/scripts/aiPocketSearch.js +67 -2
- package/dist/scripts/aiTrain.js +76 -3
- package/dist/scripts/backtest.js +141 -32
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +30 -0
- package/dist/scripts/mlExport.js +2 -1
- package/dist/scripts/mlExportSelect.js +2 -1
- package/dist/scripts/mlTrainLatestSelect.js +2 -1
- package/dist/scripts/replay.js +161 -47
- package/dist/scripts/replayRunner.js +161 -47
- package/dist/scripts/resolveExportStrategy.js +2 -1
- package/dist/scripts/runtimeParity.js +141 -32
- package/dist/scripts/selectStrategy.js +2 -1
- package/dist/scripts/signals.js +141 -32
- package/dist/scripts/signalsDaemon.js +141 -32
- package/dist/scripts/signalsSummary.js +21 -17
- package/package.json +9 -9
package/dist/cli.js
CHANGED
|
@@ -2755,7 +2755,8 @@ var init_selectStrategy = __esm({
|
|
|
2755
2755
|
"MaStrategy",
|
|
2756
2756
|
"AdaptiveMomentumRibbon",
|
|
2757
2757
|
"TrendLine",
|
|
2758
|
-
"VolumeDivergence"
|
|
2758
|
+
"VolumeDivergence",
|
|
2759
|
+
"Grid"
|
|
2759
2760
|
];
|
|
2760
2761
|
};
|
|
2761
2762
|
selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
@@ -3005,7 +3006,7 @@ var init_aiTrainDataset = __esm({
|
|
|
3005
3006
|
});
|
|
3006
3007
|
|
|
3007
3008
|
// 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;
|
|
3009
|
+
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
3010
|
var init_aiTrainMetrics = __esm({
|
|
3010
3011
|
"src/lib/aiTrainMetrics.ts"() {
|
|
3011
3012
|
"use strict";
|
|
@@ -3018,6 +3019,7 @@ var init_aiTrainMetrics = __esm({
|
|
|
3018
3019
|
DAY_MS = 24 * 60 * 60 * 1e3;
|
|
3019
3020
|
DAYS_PER_WEEK = 7;
|
|
3020
3021
|
DAYS_PER_MONTH = 30.4375;
|
|
3022
|
+
DAYS_PER_YEAR = 365;
|
|
3021
3023
|
getEvaluationPeriodDays = (evaluations) => {
|
|
3022
3024
|
let minTimestamp = null;
|
|
3023
3025
|
let maxTimestamp = null;
|
|
@@ -3039,6 +3041,40 @@ var init_aiTrainMetrics = __esm({
|
|
|
3039
3041
|
return Math.max((maxTimestamp - minTimestamp) / DAY_MS, 1);
|
|
3040
3042
|
};
|
|
3041
3043
|
qualitySortKey = (quality) => quality == null ? Number.POSITIVE_INFINITY : quality;
|
|
3044
|
+
calculateTradePnlRiskRatios = ({
|
|
3045
|
+
profits,
|
|
3046
|
+
totalProfit,
|
|
3047
|
+
maxDrawdown,
|
|
3048
|
+
periodDays
|
|
3049
|
+
}) => {
|
|
3050
|
+
if (!profits.length || periodDays == null || periodDays <= 0) {
|
|
3051
|
+
return {
|
|
3052
|
+
sharpeRatio: null,
|
|
3053
|
+
sortinoRatio: null,
|
|
3054
|
+
calmarRatio: null
|
|
3055
|
+
};
|
|
3056
|
+
}
|
|
3057
|
+
const meanProfit = totalProfit / profits.length;
|
|
3058
|
+
const variance = profits.reduce((sum2, profit) => {
|
|
3059
|
+
const diff = profit - meanProfit;
|
|
3060
|
+
return sum2 + diff * diff;
|
|
3061
|
+
}, 0) / profits.length;
|
|
3062
|
+
const stdDev = Math.sqrt(variance);
|
|
3063
|
+
const downsideDeviation = Math.sqrt(
|
|
3064
|
+
profits.reduce(
|
|
3065
|
+
(sum2, profit) => profit < 0 ? sum2 + profit * profit : sum2,
|
|
3066
|
+
0
|
|
3067
|
+
) / profits.length
|
|
3068
|
+
);
|
|
3069
|
+
const annualizationScale = Math.sqrt(
|
|
3070
|
+
profits.length / periodDays * DAYS_PER_YEAR
|
|
3071
|
+
);
|
|
3072
|
+
return {
|
|
3073
|
+
sharpeRatio: stdDev > 0 && annualizationScale > 0 ? meanProfit / stdDev * annualizationScale : null,
|
|
3074
|
+
sortinoRatio: downsideDeviation > 0 && annualizationScale > 0 ? meanProfit / downsideDeviation * annualizationScale : null,
|
|
3075
|
+
calmarRatio: maxDrawdown > 0 ? totalProfit / periodDays * DAYS_PER_YEAR / maxDrawdown : null
|
|
3076
|
+
};
|
|
3077
|
+
};
|
|
3042
3078
|
emptyRiskSummary = () => ({
|
|
3043
3079
|
trades: 0,
|
|
3044
3080
|
totalProfit: 0,
|
|
@@ -3054,12 +3090,15 @@ var init_aiTrainMetrics = __esm({
|
|
|
3054
3090
|
maxDrawdown: 0,
|
|
3055
3091
|
maxDrawdownPctOfGrossProfit: null,
|
|
3056
3092
|
maxDrawdownPctOfTotalProfit: null,
|
|
3093
|
+
sharpeRatio: null,
|
|
3094
|
+
sortinoRatio: null,
|
|
3095
|
+
calmarRatio: null,
|
|
3057
3096
|
recoveryFactor: null,
|
|
3058
3097
|
ulcerIndex: null,
|
|
3059
3098
|
maxConsecutiveWins: 0,
|
|
3060
3099
|
maxConsecutiveLosses: 0
|
|
3061
3100
|
});
|
|
3062
|
-
summarizeApprovedRisk = (evaluations) => {
|
|
3101
|
+
summarizeApprovedRisk = (evaluations, periodDays = getEvaluationPeriodDays(evaluations)) => {
|
|
3063
3102
|
const approvedEvaluations = evaluations.filter((evaluation) => evaluation.aiApproved).sort((left, right) => {
|
|
3064
3103
|
const leftTimestamp = typeof left.timestamp === "number" && Number.isFinite(left.timestamp) ? left.timestamp : Number.POSITIVE_INFINITY;
|
|
3065
3104
|
const rightTimestamp = typeof right.timestamp === "number" && Number.isFinite(right.timestamp) ? right.timestamp : Number.POSITIVE_INFINITY;
|
|
@@ -3082,8 +3121,10 @@ var init_aiTrainMetrics = __esm({
|
|
|
3082
3121
|
let currentLossStreak = 0;
|
|
3083
3122
|
let maxConsecutiveWins = 0;
|
|
3084
3123
|
let maxConsecutiveLosses = 0;
|
|
3124
|
+
const approvedProfits = [];
|
|
3085
3125
|
for (const evaluation of approvedEvaluations) {
|
|
3086
3126
|
const profit = evaluation.profit;
|
|
3127
|
+
approvedProfits.push(profit);
|
|
3087
3128
|
if (profit > 0) {
|
|
3088
3129
|
grossProfit += profit;
|
|
3089
3130
|
wins += 1;
|
|
@@ -3111,6 +3152,12 @@ var init_aiTrainMetrics = __esm({
|
|
|
3111
3152
|
const totalProfit = grossProfit - grossLoss;
|
|
3112
3153
|
const avgWin = divideOrNull(grossProfit, wins);
|
|
3113
3154
|
const avgLoss = divideOrNull(grossLoss, losses);
|
|
3155
|
+
const riskRatios = calculateTradePnlRiskRatios({
|
|
3156
|
+
profits: approvedProfits,
|
|
3157
|
+
totalProfit,
|
|
3158
|
+
maxDrawdown,
|
|
3159
|
+
periodDays
|
|
3160
|
+
});
|
|
3114
3161
|
return {
|
|
3115
3162
|
trades: approvedEvaluations.length,
|
|
3116
3163
|
totalProfit,
|
|
@@ -3126,6 +3173,7 @@ var init_aiTrainMetrics = __esm({
|
|
|
3126
3173
|
maxDrawdown,
|
|
3127
3174
|
maxDrawdownPctOfGrossProfit: grossProfit > 0 ? maxDrawdown / grossProfit : null,
|
|
3128
3175
|
maxDrawdownPctOfTotalProfit: totalProfit > 0 ? maxDrawdown / totalProfit : null,
|
|
3176
|
+
...riskRatios,
|
|
3129
3177
|
recoveryFactor: maxDrawdown > 0 ? totalProfit / maxDrawdown : null,
|
|
3130
3178
|
ulcerIndex: Math.sqrt(drawdownSquares / approvedEvaluations.length),
|
|
3131
3179
|
maxConsecutiveWins,
|
|
@@ -3224,7 +3272,7 @@ var init_aiTrainMetrics = __esm({
|
|
|
3224
3272
|
avgApprovedTradesPerDay,
|
|
3225
3273
|
avgApprovedTradesPerWeek,
|
|
3226
3274
|
expectancyDelta,
|
|
3227
|
-
approvedRisk: summarizeApprovedRisk(evaluations),
|
|
3275
|
+
approvedRisk: summarizeApprovedRisk(evaluations, periodDays),
|
|
3228
3276
|
qualityBuckets: [...bucketMap.values()].sort(
|
|
3229
3277
|
(a, b) => qualitySortKey(a.quality) - qualitySortKey(b.quality)
|
|
3230
3278
|
)
|
|
@@ -3388,7 +3436,7 @@ var init_aiTrainOptions = __esm({
|
|
|
3388
3436
|
});
|
|
3389
3437
|
|
|
3390
3438
|
// src/lib/aiPocketSearch.ts
|
|
3391
|
-
var DAY_MS2, DAYS_PER_WEEK2, DAYS_PER_MONTH2, OUTCOME_SEGMENTS, isPlainRecord, isFiniteNumber, isFeaturePrimitive, normalizeFeaturePrimitive, isOutcomePath, isFeaturePathPrefix, isCompactFeaturePathSkipped, addFlattenedFeatures, findFeatureNumber, findFeatureString, addDirectionalDerivedFeatures, collectAiPocketFeatures, formatNumber, formatPredicateValue, roundThreshold, quantileAt, getPeriodDays, createSummaryAccumulator, addSummaryRow, emptyAiPocketSummary, finalizeAiPocketSummary, summarizeSelectedRows, summarizeMask, summarizeRowIndexes, summarizeAiPocketRows, matchesPredicate, buildMask, intersectMasks, buildPredicateListMask, toPublicPredicate, buildAiPocketPredicateResult, scorePositivePocket, scoreNegativePocket, comparePositivePockets, compareNegativePockets, createPocketResult, hashMask, isBetterRepresentativePocket, estimateCombinationCount, searchAiPockets, formatMdNumber, formatMdPercent, escapeMarkdownCell, markdownTable, summaryMetricRows, pocketRows, buildAiPocketMarkdownReport;
|
|
3439
|
+
var DAY_MS2, DAYS_PER_WEEK2, DAYS_PER_MONTH2, OUTCOME_SEGMENTS, isPlainRecord, isFiniteNumber, isFeaturePrimitive, normalizeFeaturePrimitive, isOutcomePath, isFeaturePathPrefix, isCompactFeaturePathSkipped, addFlattenedFeatures, findFeatureNumber, findFeatureString, addDirectionalDerivedFeatures, addSignalRiskDistanceFeatures, collectAiPocketFeatures, formatNumber, formatPredicateValue, roundThreshold, quantileAt, getPeriodDays, createSummaryAccumulator, addSummaryRow, emptyAiPocketSummary, finalizeAiPocketSummary, summarizeSelectedRows, summarizeMask, summarizeRowIndexes, summarizeAiPocketRows, matchesPredicate, buildMask, intersectMasks, buildPredicateListMask, toPublicPredicate, buildAiPocketPredicateResult, scorePositivePocket, scoreNegativePocket, comparePositivePockets, compareNegativePockets, createPocketResult, hashMask, isBetterRepresentativePocket, estimateCombinationCount, searchAiPockets, formatMdNumber, formatMdPercent, escapeMarkdownCell, markdownTable, summaryMetricRows, pocketRows, buildAiPocketMarkdownReport;
|
|
3392
3440
|
var init_aiPocketSearch = __esm({
|
|
3393
3441
|
"src/lib/aiPocketSearch.ts"() {
|
|
3394
3442
|
"use strict";
|
|
@@ -3692,6 +3740,23 @@ var init_aiPocketSearch = __esm({
|
|
|
3692
3740
|
}
|
|
3693
3741
|
features["derived.directIndicatorSupportCount"] = supportCount;
|
|
3694
3742
|
};
|
|
3743
|
+
addSignalRiskDistanceFeatures = ({
|
|
3744
|
+
features,
|
|
3745
|
+
signal
|
|
3746
|
+
}) => {
|
|
3747
|
+
const currentPrice = isFiniteNumber(signal.prices?.currentPrice) ? signal.prices.currentPrice : null;
|
|
3748
|
+
const stopLossPrice = isFiniteNumber(signal.prices?.stopLossPrice) ? signal.prices.stopLossPrice : null;
|
|
3749
|
+
const takeProfitPrice = isFiniteNumber(signal.prices?.takeProfitPrice) ? signal.prices.takeProfitPrice : null;
|
|
3750
|
+
if (currentPrice == null || currentPrice === 0) {
|
|
3751
|
+
return;
|
|
3752
|
+
}
|
|
3753
|
+
if (stopLossPrice != null) {
|
|
3754
|
+
features["derived.stopDistanceBps"] = Math.abs(currentPrice - stopLossPrice) / Math.abs(currentPrice) * 1e4;
|
|
3755
|
+
}
|
|
3756
|
+
if (takeProfitPrice != null) {
|
|
3757
|
+
features["derived.takeProfitDistanceBps"] = Math.abs(takeProfitPrice - currentPrice) / Math.abs(currentPrice) * 1e4;
|
|
3758
|
+
}
|
|
3759
|
+
};
|
|
3695
3760
|
collectAiPocketFeatures = ({
|
|
3696
3761
|
payload,
|
|
3697
3762
|
gateContext,
|
|
@@ -3719,6 +3784,7 @@ var init_aiPocketSearch = __esm({
|
|
|
3719
3784
|
maxDepth: 8,
|
|
3720
3785
|
shouldSkipPath: featureProfile === "compact" ? isCompactFeaturePathSkipped : void 0
|
|
3721
3786
|
});
|
|
3787
|
+
addSignalRiskDistanceFeatures({ features, signal });
|
|
3722
3788
|
addDirectionalDerivedFeatures(features);
|
|
3723
3789
|
return features;
|
|
3724
3790
|
};
|
|
@@ -6135,7 +6201,7 @@ var init_aiTrainEvaluationDump = __esm({
|
|
|
6135
6201
|
});
|
|
6136
6202
|
|
|
6137
6203
|
// 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;
|
|
6204
|
+
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
6205
|
var init_aiTrainResearch = __esm({
|
|
6140
6206
|
"src/lib/aiTrainResearch.ts"() {
|
|
6141
6207
|
"use strict";
|
|
@@ -6164,6 +6230,12 @@ var init_aiTrainResearch = __esm({
|
|
|
6164
6230
|
"COINMARKETCAP_CONTEXT_BACKFILL_MAX_DAYS",
|
|
6165
6231
|
"COINMARKETCAP_CONTEXT_BACKFILL_WARMUP_DAYS"
|
|
6166
6232
|
];
|
|
6233
|
+
DERIVATIVES_CONTEXT_DATA_MODEL = {
|
|
6234
|
+
derivativesSourceIntervals: "15m",
|
|
6235
|
+
derivativesDerivedIntervals: "1h",
|
|
6236
|
+
derivativesHourlyFallback: "stored-1h",
|
|
6237
|
+
derivativesDataModelVersion: 2
|
|
6238
|
+
};
|
|
6167
6239
|
normalizeForStableJson = (value) => {
|
|
6168
6240
|
if (Array.isArray(value)) {
|
|
6169
6241
|
return value.map(normalizeForStableJson);
|
|
@@ -6276,6 +6348,7 @@ var init_aiTrainResearch = __esm({
|
|
|
6276
6348
|
const relativeCandidates = [
|
|
6277
6349
|
`packages/strategies/src/${strategyName}/adapters/ai.ts`,
|
|
6278
6350
|
`packages/strategies/src/${strategyName}/guardrails.ts`,
|
|
6351
|
+
`packages/strategies/src/${strategyName}/pockets.ts`,
|
|
6279
6352
|
`packages/strategies/src/${strategyName}/config.ts`,
|
|
6280
6353
|
"packages/node/src/ai.ts"
|
|
6281
6354
|
];
|
|
@@ -6322,7 +6395,8 @@ var init_aiTrainResearch = __esm({
|
|
|
6322
6395
|
...Object.fromEntries(
|
|
6323
6396
|
RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
|
|
6324
6397
|
),
|
|
6325
|
-
...runContext
|
|
6398
|
+
...runContext,
|
|
6399
|
+
...DERIVATIVES_CONTEXT_DATA_MODEL
|
|
6326
6400
|
};
|
|
6327
6401
|
return {
|
|
6328
6402
|
gitSha,
|
|
@@ -7402,6 +7476,9 @@ var init_aiTrain = __esm({
|
|
|
7402
7476
|
import_chalk5.default.gray("CALENDAR/D"),
|
|
7403
7477
|
import_chalk5.default.gray("WR"),
|
|
7404
7478
|
import_chalk5.default.gray("PF"),
|
|
7479
|
+
import_chalk5.default.gray("SHARPE"),
|
|
7480
|
+
import_chalk5.default.gray("SORTINO"),
|
|
7481
|
+
import_chalk5.default.gray("CALMAR"),
|
|
7405
7482
|
import_chalk5.default.gray("PNL"),
|
|
7406
7483
|
import_chalk5.default.gray("MAX_DD"),
|
|
7407
7484
|
import_chalk5.default.gray("TOP REJECT")
|
|
@@ -7416,6 +7493,9 @@ var init_aiTrain = __esm({
|
|
|
7416
7493
|
colorizeMetricNumber(window2.approvedPerCalendarDay),
|
|
7417
7494
|
colorizeRatio2(window2.outcome.approvedRisk.winRate),
|
|
7418
7495
|
colorizeMetricNumber(window2.outcome.approvedRisk.profitFactor),
|
|
7496
|
+
colorizeMetricNumber(window2.outcome.approvedRisk.sharpeRatio),
|
|
7497
|
+
colorizeMetricNumber(window2.outcome.approvedRisk.sortinoRatio),
|
|
7498
|
+
colorizeMetricNumber(window2.outcome.approvedRisk.calmarRatio),
|
|
7419
7499
|
colorizeProfit2(window2.outcome.approvedRisk.totalProfit),
|
|
7420
7500
|
colorizeProfit2(-window2.outcome.approvedRisk.maxDrawdown),
|
|
7421
7501
|
import_chalk5.default.gray(
|
|
@@ -7464,6 +7544,18 @@ var init_aiTrain = __esm({
|
|
|
7464
7544
|
"profit_factor",
|
|
7465
7545
|
colorizeMetricNumber(summary.approvedRisk.profitFactor)
|
|
7466
7546
|
],
|
|
7547
|
+
[
|
|
7548
|
+
"sharpe_ratio",
|
|
7549
|
+
colorizeMetricNumber(summary.approvedRisk.sharpeRatio)
|
|
7550
|
+
],
|
|
7551
|
+
[
|
|
7552
|
+
"sortino_ratio",
|
|
7553
|
+
colorizeMetricNumber(summary.approvedRisk.sortinoRatio)
|
|
7554
|
+
],
|
|
7555
|
+
[
|
|
7556
|
+
"calmar_ratio",
|
|
7557
|
+
colorizeMetricNumber(summary.approvedRisk.calmarRatio)
|
|
7558
|
+
],
|
|
7467
7559
|
[
|
|
7468
7560
|
"payoff_ratio",
|
|
7469
7561
|
colorizeMetricNumber(summary.approvedRisk.payoffRatio)
|
|
@@ -8590,7 +8682,7 @@ var init_binanceMarketContextBackfill = __esm({
|
|
|
8590
8682
|
});
|
|
8591
8683
|
|
|
8592
8684
|
// src/lib/derivativesContextBackfill.ts
|
|
8593
|
-
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, 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;
|
|
8685
|
+
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;
|
|
8594
8686
|
var init_derivativesContextBackfill = __esm({
|
|
8595
8687
|
"src/lib/derivativesContextBackfill.ts"() {
|
|
8596
8688
|
"use strict";
|
|
@@ -8722,6 +8814,38 @@ var init_derivativesContextBackfill = __esm({
|
|
|
8722
8814
|
return null;
|
|
8723
8815
|
};
|
|
8724
8816
|
resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
|
|
8817
|
+
resolveDerivativesContextRequiredFetchFromMs = (params) => {
|
|
8818
|
+
const dataCoverageFromMs = params.dataCoverageKeyExists ? null : params.mode === "signals" ? params.fromMs : resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
8819
|
+
ranges: params.dataCoverageRanges,
|
|
8820
|
+
fromMs: params.fromMs,
|
|
8821
|
+
toMs: params.toMs,
|
|
8822
|
+
intervalMs: params.intervalMs
|
|
8823
|
+
});
|
|
8824
|
+
const edgesFromMs = dataCoverageFromMs == null ? null : resolveDerivativesContextFetchFromMs({
|
|
8825
|
+
edges: params.edges,
|
|
8826
|
+
fromMs: params.fromMs,
|
|
8827
|
+
toMs: params.toMs,
|
|
8828
|
+
intervalMs: params.intervalMs,
|
|
8829
|
+
refreshClosedTail: params.mode === "signals"
|
|
8830
|
+
});
|
|
8831
|
+
const dataFetchFromMs = dataCoverageFromMs != null && edgesFromMs != null ? Math.max(dataCoverageFromMs, edgesFromMs) : null;
|
|
8832
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
8833
|
+
interval: params.interval,
|
|
8834
|
+
fromMs: params.fromMs,
|
|
8835
|
+
toMs: params.toMs,
|
|
8836
|
+
nowMs: params.nowMs
|
|
8837
|
+
});
|
|
8838
|
+
const liquidationFetchFromMs = confirmedLiquidationWindow ? resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
8839
|
+
ranges: params.liquidationCoverageRanges,
|
|
8840
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
8841
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
8842
|
+
intervalMs: params.intervalMs
|
|
8843
|
+
}) : null;
|
|
8844
|
+
const fetchStarts = [dataFetchFromMs, liquidationFetchFromMs].filter(
|
|
8845
|
+
(value) => value != null
|
|
8846
|
+
);
|
|
8847
|
+
return fetchStarts.length ? Math.min(...fetchStarts) : null;
|
|
8848
|
+
};
|
|
8725
8849
|
countBackfillWindows = (params) => {
|
|
8726
8850
|
let count = 0;
|
|
8727
8851
|
let cursor = params.fromMs;
|
|
@@ -9057,7 +9181,8 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9057
9181
|
mode,
|
|
9058
9182
|
startMs,
|
|
9059
9183
|
endMs,
|
|
9060
|
-
preloadStartMs: params.preloadStartMs
|
|
9184
|
+
preloadStartMs: params.preloadStartMs,
|
|
9185
|
+
nowMs: Date.now()
|
|
9061
9186
|
});
|
|
9062
9187
|
if (safeEndMs <= fromMs) {
|
|
9063
9188
|
return skippedBackfillResult2();
|
|
@@ -9091,15 +9216,33 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9091
9216
|
);
|
|
9092
9217
|
const coverageKeysByInterval = /* @__PURE__ */ new Map();
|
|
9093
9218
|
const coverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
9219
|
+
const liquidationCoverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
9220
|
+
const coverageNowMs = Date.now();
|
|
9094
9221
|
await Promise.all(
|
|
9095
9222
|
intervalWindows.map(async (window2) => {
|
|
9096
|
-
const
|
|
9097
|
-
source: "coinalyze",
|
|
9098
|
-
symbols,
|
|
9223
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
9099
9224
|
interval: window2.interval,
|
|
9100
9225
|
fromMs: window2.fromMs,
|
|
9101
|
-
toMs: window2.toMs
|
|
9226
|
+
toMs: window2.toMs,
|
|
9227
|
+
nowMs: coverageNowMs
|
|
9102
9228
|
});
|
|
9229
|
+
const [coverageRows, liquidationCoverageRows] = await Promise.all([
|
|
9230
|
+
(0, import_timescale2.getDerivativesBackfillCoverage)({
|
|
9231
|
+
source: "coinalyze",
|
|
9232
|
+
symbols,
|
|
9233
|
+
interval: window2.interval,
|
|
9234
|
+
fromMs: window2.fromMs,
|
|
9235
|
+
toMs: window2.toMs
|
|
9236
|
+
}),
|
|
9237
|
+
confirmedLiquidationWindow ? (0, import_timescale2.getDerivativesMetricCoverage)({
|
|
9238
|
+
source: "coinalyze",
|
|
9239
|
+
metric: "liquidation",
|
|
9240
|
+
symbols,
|
|
9241
|
+
interval: window2.interval,
|
|
9242
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
9243
|
+
toMs: confirmedLiquidationWindow.toMs
|
|
9244
|
+
}) : Promise.resolve([])
|
|
9245
|
+
]);
|
|
9103
9246
|
coverageKeysByInterval.set(
|
|
9104
9247
|
window2.interval,
|
|
9105
9248
|
new Set(
|
|
@@ -9121,6 +9264,17 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9121
9264
|
rangesBySymbol.set(symbol, ranges);
|
|
9122
9265
|
}
|
|
9123
9266
|
coverageRangesByInterval.set(window2.interval, rangesBySymbol);
|
|
9267
|
+
const liquidationRangesBySymbol = /* @__PURE__ */ new Map();
|
|
9268
|
+
for (const row of liquidationCoverageRows) {
|
|
9269
|
+
const symbol = row.symbol.toUpperCase();
|
|
9270
|
+
const ranges = liquidationRangesBySymbol.get(symbol) ?? [];
|
|
9271
|
+
ranges.push({ fromMs: row.fromMs, toMs: row.toMs });
|
|
9272
|
+
liquidationRangesBySymbol.set(symbol, ranges);
|
|
9273
|
+
}
|
|
9274
|
+
liquidationCoverageRangesByInterval.set(
|
|
9275
|
+
window2.interval,
|
|
9276
|
+
liquidationRangesBySymbol
|
|
9277
|
+
);
|
|
9124
9278
|
})
|
|
9125
9279
|
);
|
|
9126
9280
|
const cachedWindows = intervalWindows.reduce(
|
|
@@ -9145,7 +9299,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9145
9299
|
(symbol) => backfillWindows.every((backfillWindow) => {
|
|
9146
9300
|
const normalizedSymbol = symbol.toUpperCase();
|
|
9147
9301
|
const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
|
|
9148
|
-
|
|
9302
|
+
const dataCovered = hasDerivativesWindowCoverage({
|
|
9149
9303
|
edges: edgesBySymbol?.get(normalizedSymbol),
|
|
9150
9304
|
fromMs: backfillWindow.fromMs,
|
|
9151
9305
|
toMs: backfillWindow.toMs
|
|
@@ -9162,6 +9316,19 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9162
9316
|
toMs: backfillWindow.toMs
|
|
9163
9317
|
})
|
|
9164
9318
|
);
|
|
9319
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
9320
|
+
interval: window2.interval,
|
|
9321
|
+
fromMs: backfillWindow.fromMs,
|
|
9322
|
+
toMs: backfillWindow.toMs,
|
|
9323
|
+
nowMs: coverageNowMs
|
|
9324
|
+
});
|
|
9325
|
+
const liquidationCovered = confirmedLiquidationWindow == null || resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
9326
|
+
ranges: liquidationCoverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [],
|
|
9327
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
9328
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
9329
|
+
intervalMs: window2.intervalMs
|
|
9330
|
+
}) == null;
|
|
9331
|
+
return dataCovered && liquidationCovered;
|
|
9165
9332
|
})
|
|
9166
9333
|
);
|
|
9167
9334
|
});
|
|
@@ -9246,6 +9413,11 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9246
9413
|
coverageKeysByInterval.set(interval5, coverageKeys);
|
|
9247
9414
|
const coverageRangesBySymbol = coverageRangesByInterval.get(interval5) ?? /* @__PURE__ */ new Map();
|
|
9248
9415
|
coverageRangesByInterval.set(interval5, coverageRangesBySymbol);
|
|
9416
|
+
const liquidationCoverageRangesBySymbol = liquidationCoverageRangesByInterval.get(interval5) ?? /* @__PURE__ */ new Map();
|
|
9417
|
+
liquidationCoverageRangesByInterval.set(
|
|
9418
|
+
interval5,
|
|
9419
|
+
liquidationCoverageRangesBySymbol
|
|
9420
|
+
);
|
|
9249
9421
|
for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
|
|
9250
9422
|
const batch = symbolBatches[batchIdx];
|
|
9251
9423
|
let cursor = window2.fromMs;
|
|
@@ -9258,33 +9430,25 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9258
9430
|
fromMs: cursor,
|
|
9259
9431
|
toMs
|
|
9260
9432
|
});
|
|
9261
|
-
if (coverageKeys.has(key)) {
|
|
9262
|
-
return null;
|
|
9263
|
-
}
|
|
9264
9433
|
const normalizedSymbol = item.symbol.toUpperCase();
|
|
9265
|
-
const
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
refreshClosedTail: mode === "signals"
|
|
9281
|
-
});
|
|
9282
|
-
if (edgesFromMs == null) {
|
|
9283
|
-
return null;
|
|
9284
|
-
}
|
|
9434
|
+
const requiredFromMs = resolveDerivativesContextRequiredFetchFromMs(
|
|
9435
|
+
{
|
|
9436
|
+
mode,
|
|
9437
|
+
interval: interval5,
|
|
9438
|
+
intervalMs: intervalMs2,
|
|
9439
|
+
fromMs: cursor,
|
|
9440
|
+
toMs,
|
|
9441
|
+
nowMs: coverageNowMs,
|
|
9442
|
+
dataCoverageKeyExists: coverageKeys.has(key),
|
|
9443
|
+
dataCoverageRanges: coverageRangesBySymbol.get(normalizedSymbol),
|
|
9444
|
+
liquidationCoverageRanges: liquidationCoverageRangesBySymbol.get(normalizedSymbol),
|
|
9445
|
+
edges: edgesBySymbol.get(normalizedSymbol)
|
|
9446
|
+
}
|
|
9447
|
+
);
|
|
9448
|
+
if (requiredFromMs == null) return null;
|
|
9285
9449
|
return {
|
|
9286
9450
|
item,
|
|
9287
|
-
fromMs:
|
|
9451
|
+
fromMs: requiredFromMs
|
|
9288
9452
|
};
|
|
9289
9453
|
}).filter(
|
|
9290
9454
|
(item) => item != null
|
|
@@ -9309,6 +9473,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9309
9473
|
);
|
|
9310
9474
|
let rows = [];
|
|
9311
9475
|
let missingClosedSymbols = [];
|
|
9476
|
+
let liquidationRowsByMarket = /* @__PURE__ */ new Map();
|
|
9312
9477
|
for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
|
|
9313
9478
|
const oiMap = await fetchMetricBatch({
|
|
9314
9479
|
endpoint: oiPath,
|
|
@@ -9328,7 +9493,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9328
9493
|
fromMs: group.fromMs,
|
|
9329
9494
|
toMs
|
|
9330
9495
|
});
|
|
9331
|
-
|
|
9496
|
+
liquidationRowsByMarket = await fetchMetricBatch({
|
|
9332
9497
|
endpoint: liqPath,
|
|
9333
9498
|
metric: "liq",
|
|
9334
9499
|
marketSymbols,
|
|
@@ -9343,7 +9508,7 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9343
9508
|
symbol: item.symbol,
|
|
9344
9509
|
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
9345
9510
|
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
9346
|
-
liqRaw:
|
|
9511
|
+
liqRaw: liquidationRowsByMarket.get(marketSymbol) ?? []
|
|
9347
9512
|
});
|
|
9348
9513
|
return (0, import_indicators.coinalyzePointsToRows)(points, interval5, "coinalyze");
|
|
9349
9514
|
});
|
|
@@ -9366,6 +9531,42 @@ var init_derivativesContextBackfill = __esm({
|
|
|
9366
9531
|
await (0, import_timescale2.upsertDerivatives)(rows);
|
|
9367
9532
|
totalRows += rows.length;
|
|
9368
9533
|
}
|
|
9534
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
9535
|
+
interval: interval5,
|
|
9536
|
+
fromMs: group.fromMs,
|
|
9537
|
+
toMs,
|
|
9538
|
+
nowMs: coverageNowMs
|
|
9539
|
+
});
|
|
9540
|
+
if (confirmedLiquidationWindow) {
|
|
9541
|
+
const metricCoverageRows = missingBatch.map((item) => {
|
|
9542
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
9543
|
+
const eventRowsCount = (liquidationRowsByMarket.get(marketSymbol) ?? []).filter((point) => {
|
|
9544
|
+
const timestamp = (0, import_indicators.toCoinalyzeTimestampMs)(
|
|
9545
|
+
point.t ?? point.ts ?? point.time ?? point.timestamp
|
|
9546
|
+
);
|
|
9547
|
+
return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
|
|
9548
|
+
}).length;
|
|
9549
|
+
return {
|
|
9550
|
+
source: "coinalyze",
|
|
9551
|
+
metric: "liquidation",
|
|
9552
|
+
symbol: item.symbol,
|
|
9553
|
+
interval: interval5,
|
|
9554
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
9555
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
9556
|
+
eventRowsCount
|
|
9557
|
+
};
|
|
9558
|
+
});
|
|
9559
|
+
await (0, import_timescale2.applyDerivativesMetricCoverage)(metricCoverageRows);
|
|
9560
|
+
for (const coverageRow of metricCoverageRows) {
|
|
9561
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
9562
|
+
const ranges = liquidationCoverageRangesBySymbol.get(symbol) ?? [];
|
|
9563
|
+
ranges.push({
|
|
9564
|
+
fromMs: coverageRow.fromMs,
|
|
9565
|
+
toMs: coverageRow.toMs
|
|
9566
|
+
});
|
|
9567
|
+
liquidationCoverageRangesBySymbol.set(symbol, ranges);
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9369
9570
|
if (mode === "backtest") {
|
|
9370
9571
|
const rowsCountBySymbol = /* @__PURE__ */ new Map();
|
|
9371
9572
|
for (const row of rows) {
|
|
@@ -19393,6 +19594,36 @@ var init_derivativesIngestCoinalyzeAll = __esm({
|
|
|
19393
19594
|
await (0, import_timescale7.upsertDerivatives)(rows);
|
|
19394
19595
|
totalRows += rows.length;
|
|
19395
19596
|
}
|
|
19597
|
+
const confirmedLiquidationWindow = (0, import_indicators3.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
19598
|
+
interval: interval5,
|
|
19599
|
+
fromMs: cursor,
|
|
19600
|
+
toMs,
|
|
19601
|
+
nowMs: now2
|
|
19602
|
+
});
|
|
19603
|
+
if (confirmedLiquidationWindow) {
|
|
19604
|
+
await (0, import_timescale7.applyDerivativesMetricCoverage)(
|
|
19605
|
+
batch.map((item) => {
|
|
19606
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
19607
|
+
const eventRowsCount = (liqMap.get(marketSymbol) ?? []).filter(
|
|
19608
|
+
(point) => {
|
|
19609
|
+
const timestamp = (0, import_indicators3.toCoinalyzeTimestampMs)(
|
|
19610
|
+
point.t ?? point.ts ?? point.time ?? point.timestamp
|
|
19611
|
+
);
|
|
19612
|
+
return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
|
|
19613
|
+
}
|
|
19614
|
+
).length;
|
|
19615
|
+
return {
|
|
19616
|
+
source: "coinalyze",
|
|
19617
|
+
metric: "liquidation",
|
|
19618
|
+
symbol: item.symbol,
|
|
19619
|
+
interval: interval5,
|
|
19620
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
19621
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
19622
|
+
eventRowsCount
|
|
19623
|
+
};
|
|
19624
|
+
})
|
|
19625
|
+
);
|
|
19626
|
+
}
|
|
19396
19627
|
} catch (error) {
|
|
19397
19628
|
failedWindows += 1;
|
|
19398
19629
|
console.error(
|
|
@@ -30079,7 +30310,7 @@ var init_resultsReporting = __esm({
|
|
|
30079
30310
|
});
|
|
30080
30311
|
|
|
30081
30312
|
// src/lib/runtimeTradeSync.ts
|
|
30082
|
-
var import_constants18, import_time10, import_redis21, CLOSED_PNL_LIMIT, EXCHANGE_HISTORY_MAX_RANGE_MS, splitExchangeHistoryTimeRange, formatRuntimeTradeSyncError, loadClosedPnlRows, consumeClosedPnlMatch, syncRuntimeTrades;
|
|
30313
|
+
var import_constants18, import_time10, import_redis21, CLOSED_PNL_LIMIT, CLOSED_PNL_RECONCILIATION_LOOKBACK_MS, EXCHANGE_HISTORY_MAX_RANGE_MS, isRuntimeTradeSyncFallbackClose, splitExchangeHistoryTimeRange, formatRuntimeTradeSyncError, loadClosedPnlRows, consumeClosedPnlMatch, syncRuntimeTrades;
|
|
30083
30314
|
var init_runtimeTradeSync = __esm({
|
|
30084
30315
|
"src/lib/runtimeTradeSync.ts"() {
|
|
30085
30316
|
"use strict";
|
|
@@ -30087,7 +30318,9 @@ var init_runtimeTradeSync = __esm({
|
|
|
30087
30318
|
import_time10 = require("@tradejs/core/time");
|
|
30088
30319
|
import_redis21 = require("@tradejs/infra/redis");
|
|
30089
30320
|
CLOSED_PNL_LIMIT = 100;
|
|
30321
|
+
CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
|
|
30090
30322
|
EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
30323
|
+
isRuntimeTradeSyncFallbackClose = (trade) => trade.status === "closed" && trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null;
|
|
30091
30324
|
splitExchangeHistoryTimeRange = ({
|
|
30092
30325
|
startTime,
|
|
30093
30326
|
endTime,
|
|
@@ -30216,7 +30449,7 @@ var init_runtimeTradeSync = __esm({
|
|
|
30216
30449
|
);
|
|
30217
30450
|
const closedPnlRows = await loadClosedPnlRows({
|
|
30218
30451
|
connector,
|
|
30219
|
-
startTime,
|
|
30452
|
+
startTime: Math.max(0, startTime - CLOSED_PNL_RECONCILIATION_LOOKBACK_MS),
|
|
30220
30453
|
endTime,
|
|
30221
30454
|
callbacks: closedPnlCallbacks
|
|
30222
30455
|
});
|
|
@@ -30228,14 +30461,14 @@ var init_runtimeTradeSync = __esm({
|
|
|
30228
30461
|
}
|
|
30229
30462
|
const syncedTrades = [];
|
|
30230
30463
|
for (const trade of trades) {
|
|
30231
|
-
if (trade.status !== "active") {
|
|
30464
|
+
if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
|
|
30232
30465
|
syncedTrades.push(trade);
|
|
30233
30466
|
continue;
|
|
30234
30467
|
}
|
|
30235
30468
|
const openPosition = openPositionsBySymbol.get(trade.symbol);
|
|
30236
30469
|
const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
|
|
30237
30470
|
const isCurrentActiveTrade = activeOrderId === trade.orderId;
|
|
30238
|
-
if (!openPositionsReliable) {
|
|
30471
|
+
if (trade.status === "active" && !openPositionsReliable) {
|
|
30239
30472
|
syncedTrades.push({
|
|
30240
30473
|
...trade,
|
|
30241
30474
|
status: "active",
|
|
@@ -30243,7 +30476,7 @@ var init_runtimeTradeSync = __esm({
|
|
|
30243
30476
|
});
|
|
30244
30477
|
continue;
|
|
30245
30478
|
}
|
|
30246
|
-
if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
|
|
30479
|
+
if (trade.status === "active" && isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
|
|
30247
30480
|
const nextTrade2 = {
|
|
30248
30481
|
...trade,
|
|
30249
30482
|
status: "active",
|
|
@@ -30271,21 +30504,24 @@ var init_runtimeTradeSync = __esm({
|
|
|
30271
30504
|
continue;
|
|
30272
30505
|
}
|
|
30273
30506
|
const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
|
|
30507
|
+
if (!matchedClosedPnl) {
|
|
30508
|
+
continue;
|
|
30509
|
+
}
|
|
30274
30510
|
const nextTrade = {
|
|
30275
30511
|
...trade,
|
|
30276
30512
|
status: "closed",
|
|
30277
|
-
currentPrice: matchedClosedPnl
|
|
30278
|
-
currentPnl: matchedClosedPnl
|
|
30279
|
-
closedPnl: matchedClosedPnl
|
|
30280
|
-
actualEntryPrice: matchedClosedPnl
|
|
30281
|
-
exitPrice: matchedClosedPnl
|
|
30282
|
-
actualExitPrice: matchedClosedPnl
|
|
30283
|
-
exitTimestamp: matchedClosedPnl
|
|
30513
|
+
currentPrice: matchedClosedPnl.exitPrice ?? trade.currentPrice ?? null,
|
|
30514
|
+
currentPnl: matchedClosedPnl.closedPnl,
|
|
30515
|
+
closedPnl: matchedClosedPnl.closedPnl,
|
|
30516
|
+
actualEntryPrice: matchedClosedPnl.entryPrice ?? trade.actualEntryPrice ?? null,
|
|
30517
|
+
exitPrice: matchedClosedPnl.exitPrice ?? trade.exitPrice ?? null,
|
|
30518
|
+
actualExitPrice: matchedClosedPnl.exitPrice ?? trade.actualExitPrice ?? null,
|
|
30519
|
+
exitTimestamp: matchedClosedPnl.closedAt,
|
|
30284
30520
|
exitType: trade.exitType ?? null,
|
|
30285
|
-
openFee: matchedClosedPnl
|
|
30286
|
-
closeFee: matchedClosedPnl
|
|
30287
|
-
fundingFee: matchedClosedPnl
|
|
30288
|
-
totalFee: matchedClosedPnl
|
|
30521
|
+
openFee: matchedClosedPnl.openFee ?? trade.openFee ?? null,
|
|
30522
|
+
closeFee: matchedClosedPnl.closeFee ?? trade.closeFee ?? null,
|
|
30523
|
+
fundingFee: matchedClosedPnl.fundingFee ?? trade.fundingFee ?? null,
|
|
30524
|
+
totalFee: matchedClosedPnl.totalFee ?? trade.totalFee ?? null,
|
|
30289
30525
|
lastSyncedAt: endTime
|
|
30290
30526
|
};
|
|
30291
30527
|
await Promise.all([
|
|
@@ -32443,8 +32679,7 @@ var init_signalsSummary = __esm({
|
|
|
32443
32679
|
if (trade.status !== "closed" || !isTimestampInWindow(trade.exitTimestamp, startTime, endTime)) {
|
|
32444
32680
|
return false;
|
|
32445
32681
|
}
|
|
32446
|
-
|
|
32447
|
-
return !looksLikeSyncFallbackClose;
|
|
32682
|
+
return !isRuntimeTradeSyncFallbackClose(trade);
|
|
32448
32683
|
};
|
|
32449
32684
|
buildSummaryMessages = ({
|
|
32450
32685
|
hours,
|