@tradejs/cli 2.0.15 → 2.0.17
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 +2982 -994
- package/dist/lib/aiPocketSearch.js +493 -24
- package/dist/lib/aiTrainResearch.js +19 -2
- package/dist/lib/hyperliquidWhaleBackfill.js +37 -1
- package/dist/lib/marketContextPrepare.js +112 -9
- package/dist/lib/researchAgent.js +3 -30
- package/dist/lib/runtimeDebugEvidence.js +76 -1
- package/dist/lib/runtimeEvidenceArtifacts.js +255 -0
- package/dist/lib/runtimeEvidenceSync.js +308 -0
- package/dist/lib/runtimeRedis.js +25 -0
- package/dist/lib/runtimeScorecard.js +442 -0
- package/dist/lib/runtimeTradeSync.js +9 -0
- package/dist/scripts/agentRun.js +16 -31
- package/dist/scripts/aiPocketSearch.js +717 -29
- package/dist/scripts/aiTrain.js +32 -2
- package/dist/scripts/backtest.js +136 -11
- package/dist/scripts/hyperliquidWhaleBackfill.js +27 -1
- package/dist/scripts/hyperliquidWhalesUpdate.js +1 -0
- package/dist/scripts/replay.js +122 -12
- package/dist/scripts/replayRunner.js +122 -12
- package/dist/scripts/replayRuntimeEvidence.js +68 -161
- package/dist/scripts/runtimeEvidence.js +316 -161
- package/dist/scripts/runtimeEvidenceSync.js +335 -0
- package/dist/scripts/runtimeParity.js +110 -9
- package/dist/scripts/runtimeScorecard.js +731 -0
- package/dist/scripts/signals.js +263 -145
- package/dist/scripts/signalsDaemon.js +263 -145
- package/dist/scripts/signalsSummary.js +9 -0
- package/dist/workers/testerWorker.js +2 -0
- package/package.json +11 -9
package/dist/scripts/signals.js
CHANGED
|
@@ -1645,7 +1645,7 @@ __export(signals_exports, {
|
|
|
1645
1645
|
module.exports = __toCommonJS(signals_exports);
|
|
1646
1646
|
var import_config = require("dotenv/config");
|
|
1647
1647
|
var import_args = __toESM(require("args"));
|
|
1648
|
-
var
|
|
1648
|
+
var import_progress4 = __toESM(require("progress"));
|
|
1649
1649
|
var import_chalk7 = __toESM(require("chalk"));
|
|
1650
1650
|
var import_connectors6 = require("@tradejs/node/connectors");
|
|
1651
1651
|
var import_cli2 = require("@tradejs/node/cli");
|
|
@@ -1655,112 +1655,8 @@ var import_constants3 = require("@tradejs/core/constants");
|
|
|
1655
1655
|
var import_strategies6 = require("@tradejs/node/strategies");
|
|
1656
1656
|
var import_time3 = require("@tradejs/core/time");
|
|
1657
1657
|
var import_logger4 = require("@tradejs/infra/logger");
|
|
1658
|
-
var import_redis5 = require("@tradejs/infra/redis");
|
|
1659
1658
|
var import_tradingAccounts2 = require("@tradejs/infra/tradingAccounts");
|
|
1660
1659
|
|
|
1661
|
-
// src/lib/runtimeSignalsStorage.ts
|
|
1662
|
-
var import_constants = require("@tradejs/core/constants");
|
|
1663
|
-
var import_time = require("@tradejs/core/time");
|
|
1664
|
-
var SECONDS_PER_DAY = 86400;
|
|
1665
|
-
var RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
|
|
1666
|
-
var DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants.TTL_3D;
|
|
1667
|
-
var RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS = import_constants.TTL_1M;
|
|
1668
|
-
var parsePositiveNumber = (value) => {
|
|
1669
|
-
if (value == null || value === "") {
|
|
1670
|
-
return null;
|
|
1671
|
-
}
|
|
1672
|
-
const parsed = Number(value);
|
|
1673
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
1674
|
-
};
|
|
1675
|
-
var getRuntimeSignalRetentionTtlSeconds = () => {
|
|
1676
|
-
const explicitDays = parsePositiveNumber(
|
|
1677
|
-
process.env[RUNTIME_SIGNAL_RETENTION_DAYS_ENV]
|
|
1678
|
-
);
|
|
1679
|
-
if (explicitDays != null) {
|
|
1680
|
-
return Math.ceil(explicitDays * SECONDS_PER_DAY);
|
|
1681
|
-
}
|
|
1682
|
-
return DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS;
|
|
1683
|
-
};
|
|
1684
|
-
var toRuntimeSignalBucketRef = (signal) => ({
|
|
1685
|
-
signalId: signal.signalId,
|
|
1686
|
-
symbol: signal.symbol,
|
|
1687
|
-
strategy: signal.strategy,
|
|
1688
|
-
timestamp: signal.timestamp,
|
|
1689
|
-
...signal.runtimeConfigId && signal.runtimeConfigId !== "config" ? { runtimeConfigId: signal.runtimeConfigId } : {}
|
|
1690
|
-
});
|
|
1691
|
-
var shouldStoreRuntimeSignalDiagnostics = (signal) => signal.orderStatus === "completed" || signal.orderStatus === "failed";
|
|
1692
|
-
var toStoredRuntimeSignal = (signal) => {
|
|
1693
|
-
if (shouldStoreRuntimeSignalDiagnostics(signal)) {
|
|
1694
|
-
return signal;
|
|
1695
|
-
}
|
|
1696
|
-
const stored = { ...signal };
|
|
1697
|
-
delete stored.figures;
|
|
1698
|
-
delete stored.indicators;
|
|
1699
|
-
delete stored.additionalIndicators;
|
|
1700
|
-
return stored;
|
|
1701
|
-
};
|
|
1702
|
-
var normalizeRuntimeSignalSkipReason = (reason, fallbackSource) => {
|
|
1703
|
-
let source = fallbackSource;
|
|
1704
|
-
let normalizedReason = reason;
|
|
1705
|
-
if (reason.startsWith("AI_QUALITY_BELOW_MIN")) {
|
|
1706
|
-
source = "AI";
|
|
1707
|
-
normalizedReason = "MIN_AI_QUALITY";
|
|
1708
|
-
} else if (reason === "AI_QUALITY_UNAVAILABLE") {
|
|
1709
|
-
source = "AI";
|
|
1710
|
-
normalizedReason = "QUALITY_UNAVAILABLE";
|
|
1711
|
-
} else if (reason === "ML_RESULT_UNAVAILABLE") {
|
|
1712
|
-
source = "ML";
|
|
1713
|
-
normalizedReason = "RESULT_UNAVAILABLE";
|
|
1714
|
-
} else if (reason.startsWith("ML_THRESHOLD_NOT_MET")) {
|
|
1715
|
-
source = "ML";
|
|
1716
|
-
normalizedReason = "ML_THRESHOLD";
|
|
1717
|
-
} else if (reason.startsWith("HOOK_BEFORE_ENTRY_GATE:")) {
|
|
1718
|
-
source = "hook";
|
|
1719
|
-
normalizedReason = `BEFORE_ENTRY_GATE:${reason.slice(
|
|
1720
|
-
"HOOK_BEFORE_ENTRY_GATE:".length
|
|
1721
|
-
)}`;
|
|
1722
|
-
} else if (reason === "HOOK_BEFORE_ENTRY_GATE") {
|
|
1723
|
-
source = "hook";
|
|
1724
|
-
normalizedReason = "BEFORE_ENTRY_GATE";
|
|
1725
|
-
} else if (reason === "MAKE_ORDERS_DISABLED" || reason === "ENTRY_POLICY_BLOCKED") {
|
|
1726
|
-
source = "policy";
|
|
1727
|
-
}
|
|
1728
|
-
return {
|
|
1729
|
-
source: `skip from ${source}`,
|
|
1730
|
-
reason: normalizedReason
|
|
1731
|
-
};
|
|
1732
|
-
};
|
|
1733
|
-
var buildStatsReasonField = (source, reason) => `reason:${source}:${reason}`;
|
|
1734
|
-
var buildRuntimeSignalStatsIncrements = (evaluation) => {
|
|
1735
|
-
const increments = {
|
|
1736
|
-
evaluated: 1
|
|
1737
|
-
};
|
|
1738
|
-
if (evaluation.status === "signal") {
|
|
1739
|
-
increments.signals = 1;
|
|
1740
|
-
}
|
|
1741
|
-
let skipReason = null;
|
|
1742
|
-
let fallbackSource = "core";
|
|
1743
|
-
if (evaluation.status === "skip") {
|
|
1744
|
-
skipReason = evaluation.reason || "NO_SIGNAL";
|
|
1745
|
-
fallbackSource = "core";
|
|
1746
|
-
} else if (evaluation.status === "signal" && (evaluation.orderStatus === "skipped" || evaluation.orderStatus === "canceled")) {
|
|
1747
|
-
skipReason = evaluation.orderSkipReason || evaluation.reason || `orderStatus=${evaluation.orderStatus}`;
|
|
1748
|
-
fallbackSource = "runtime";
|
|
1749
|
-
} else if (evaluation.status === "error") {
|
|
1750
|
-
skipReason = evaluation.reason || "EVALUATION_ERROR";
|
|
1751
|
-
fallbackSource = "runtime";
|
|
1752
|
-
}
|
|
1753
|
-
if (skipReason) {
|
|
1754
|
-
const normalized = normalizeRuntimeSignalSkipReason(
|
|
1755
|
-
skipReason,
|
|
1756
|
-
fallbackSource
|
|
1757
|
-
);
|
|
1758
|
-
increments[buildStatsReasonField(normalized.source, normalized.reason)] = 1;
|
|
1759
|
-
}
|
|
1760
|
-
return increments;
|
|
1761
|
-
};
|
|
1762
|
-
var shouldStoreDetailedRuntimeSignalEvaluation = (evaluation) => evaluation.status !== "skip";
|
|
1763
|
-
|
|
1764
1660
|
// src/lib/marketData/windows.ts
|
|
1765
1661
|
var import_indicators = require("@tradejs/core/indicators");
|
|
1766
1662
|
var resolveOpenTimestamp = (timestamp, intervalMs2) => Number.isFinite(intervalMs2) && intervalMs2 > 0 ? Math.floor(timestamp / intervalMs2) * intervalMs2 : timestamp;
|
|
@@ -1820,6 +1716,8 @@ var invokeAfterSignalsHooks = async (hooks, params) => {
|
|
|
1820
1716
|
|
|
1821
1717
|
// src/lib/marketContextPrepare.ts
|
|
1822
1718
|
var import_chalk4 = __toESM(require("chalk"));
|
|
1719
|
+
var import_timescale5 = require("@tradejs/infra/timescale");
|
|
1720
|
+
var import_registry = require("@tradejs/node/registry");
|
|
1823
1721
|
|
|
1824
1722
|
// src/lib/binanceMarketContextBackfill.ts
|
|
1825
1723
|
var import_progress = __toESM(require("progress"));
|
|
@@ -2620,7 +2518,7 @@ var backfillBinanceMarketContextForReplay = (params) => backfillBinanceMarketCon
|
|
|
2620
2518
|
var import_chalk2 = __toESM(require("chalk"));
|
|
2621
2519
|
var import_progress2 = __toESM(require("progress"));
|
|
2622
2520
|
var import_async = require("@tradejs/core/async");
|
|
2623
|
-
var
|
|
2521
|
+
var import_constants = require("@tradejs/core/constants");
|
|
2624
2522
|
var import_indicators2 = require("@tradejs/core/indicators");
|
|
2625
2523
|
var import_timescale2 = require("@tradejs/infra/timescale");
|
|
2626
2524
|
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
@@ -2655,7 +2553,7 @@ var normalizeSymbols = (symbols) => [
|
|
|
2655
2553
|
];
|
|
2656
2554
|
var isDerivativesTargetContextEnabled = () => parseBooleanFlag(process.env.DERIVATIVES_CONTEXT_TARGET_ENABLED, false);
|
|
2657
2555
|
var resolveDerivativesContextBackfillSymbols = (requestedSymbols = []) => {
|
|
2658
|
-
const referenceSymbols = (0,
|
|
2556
|
+
const referenceSymbols = (0, import_constants.resolveDerivativesContextReferenceSymbols)(
|
|
2659
2557
|
process.env.DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS
|
|
2660
2558
|
);
|
|
2661
2559
|
return isDerivativesTargetContextEnabled() ? normalizeSymbols([...referenceSymbols, ...requestedSymbols]) : referenceSymbols;
|
|
@@ -4655,6 +4553,7 @@ var backfillCoinMarketCapContextForReplay = backfillCoinMarketCapContext;
|
|
|
4655
4553
|
var backfillCoinMarketCapContextForSignals = (params) => backfillCoinMarketCapContext({ ...params, refreshStaleFearGreed: true });
|
|
4656
4554
|
|
|
4657
4555
|
// src/lib/hyperliquidWhaleBackfill.ts
|
|
4556
|
+
var import_progress3 = __toESM(require("progress"));
|
|
4658
4557
|
var import_timescale4 = require("@tradejs/infra/timescale");
|
|
4659
4558
|
var import_strategies2 = require("@tradejs/node/strategies");
|
|
4660
4559
|
|
|
@@ -5029,11 +4928,36 @@ var backfillHyperliquidWhaleContext = async (params) => {
|
|
|
5029
4928
|
toMs,
|
|
5030
4929
|
...identity
|
|
5031
4930
|
});
|
|
4931
|
+
const totalCoverageBuckets = Math.ceil(
|
|
4932
|
+
(toMs - fromMs) / HYPERLIQUID_WHALE_BUCKET_MS
|
|
4933
|
+
);
|
|
4934
|
+
const coverageBar = new import_progress3.default(
|
|
4935
|
+
"Hyperliquid coverage :current/:total [:bar][:percent] :eta(s) rows=:rows chunk=:chunk",
|
|
4936
|
+
{
|
|
4937
|
+
total: Math.max(1, totalCoverageBuckets),
|
|
4938
|
+
width: 24
|
|
4939
|
+
}
|
|
4940
|
+
);
|
|
4941
|
+
let displayedCoverageBuckets = 0;
|
|
5032
4942
|
const coverageBuckets = await (0, import_timescale4.rebuildHyperliquidWhaleCoverageRows)({
|
|
5033
4943
|
fromMs,
|
|
5034
4944
|
toMs,
|
|
5035
4945
|
expectedWhales: whales.addresses.length,
|
|
5036
|
-
...identity
|
|
4946
|
+
...identity,
|
|
4947
|
+
onProgress: (progress) => {
|
|
4948
|
+
const next = Math.max(
|
|
4949
|
+
displayedCoverageBuckets,
|
|
4950
|
+
Math.min(progress.completedBuckets, coverageBar.total)
|
|
4951
|
+
);
|
|
4952
|
+
const delta = next - displayedCoverageBuckets;
|
|
4953
|
+
if (delta > 0) {
|
|
4954
|
+
coverageBar.tick(delta, {
|
|
4955
|
+
rows: progress.rows,
|
|
4956
|
+
chunk: `${progress.chunkIndex}/${progress.totalChunks}`
|
|
4957
|
+
});
|
|
4958
|
+
displayedCoverageBuckets = next;
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
5037
4961
|
});
|
|
5038
4962
|
const result = {
|
|
5039
4963
|
cached: false,
|
|
@@ -5061,6 +4985,9 @@ var backfillHyperliquidWhaleContext = async (params) => {
|
|
|
5061
4985
|
};
|
|
5062
4986
|
|
|
5063
4987
|
// src/lib/marketContextPrepare.ts
|
|
4988
|
+
var uniqueReasons = (reasons) => [
|
|
4989
|
+
...new Set(reasons)
|
|
4990
|
+
];
|
|
5064
4991
|
var shouldPrepareDerivativesContextForRun = (params) => {
|
|
5065
4992
|
if (params.universe === "tradfi") return false;
|
|
5066
4993
|
if (params.mode === "signals") {
|
|
@@ -5068,6 +4995,9 @@ var shouldPrepareDerivativesContextForRun = (params) => {
|
|
|
5068
4995
|
cacheOnly: params.cacheOnly
|
|
5069
4996
|
});
|
|
5070
4997
|
}
|
|
4998
|
+
if (params.mode === "backtest" && !params.aiEnabled && !params.mlEnabled) {
|
|
4999
|
+
return false;
|
|
5000
|
+
}
|
|
5071
5001
|
return shouldBackfillDerivativesContextForBacktest({
|
|
5072
5002
|
aiEnabled: Boolean(params.aiEnabled),
|
|
5073
5003
|
cacheOnly: params.cacheOnly,
|
|
@@ -5077,6 +5007,7 @@ var shouldPrepareDerivativesContextForRun = (params) => {
|
|
|
5077
5007
|
var shouldPrepareBinanceMarketContextForRun = (params) => {
|
|
5078
5008
|
if (params.universe === "tradfi") return false;
|
|
5079
5009
|
if (params.mode === "backtest") {
|
|
5010
|
+
if (!params.aiEnabled && !params.mlEnabled) return false;
|
|
5080
5011
|
return shouldBackfillBinanceMarketContextForBacktest({
|
|
5081
5012
|
aiEnabled: Boolean(params.aiEnabled),
|
|
5082
5013
|
cacheOnly: params.cacheOnly,
|
|
@@ -5095,6 +5026,7 @@ var shouldPrepareBinanceMarketContextForRun = (params) => {
|
|
|
5095
5026
|
var shouldPrepareCoinMarketCapContextForRun = (params) => {
|
|
5096
5027
|
if (params.universe === "tradfi") return false;
|
|
5097
5028
|
if (params.mode === "backtest") {
|
|
5029
|
+
if (!params.aiEnabled && !params.mlEnabled) return false;
|
|
5098
5030
|
return shouldBackfillCoinMarketCapContextForBacktest({
|
|
5099
5031
|
aiEnabled: Boolean(params.aiEnabled),
|
|
5100
5032
|
cacheOnly: params.cacheOnly,
|
|
@@ -5110,10 +5042,8 @@ var shouldPrepareCoinMarketCapContextForRun = (params) => {
|
|
|
5110
5042
|
cacheOnly: params.cacheOnly
|
|
5111
5043
|
});
|
|
5112
5044
|
};
|
|
5113
|
-
var shouldPrepareHyperliquidWhaleContextForRun = (params) => {
|
|
5114
|
-
const strategyRequiresContext =
|
|
5115
|
-
"HyperliquidConsensus"
|
|
5116
|
-
);
|
|
5045
|
+
var shouldPrepareHyperliquidWhaleContextForRun = (params, coreContextSources = []) => {
|
|
5046
|
+
const strategyRequiresContext = coreContextSources.includes("hyperliquidWhales");
|
|
5117
5047
|
if (params.universe === "tradfi" || params.mode === "signals" || params.cacheOnly || !params.aiEnabled && !params.mlEnabled && !strategyRequiresContext) {
|
|
5118
5048
|
return false;
|
|
5119
5049
|
}
|
|
@@ -5124,6 +5054,64 @@ var shouldPrepareHyperliquidWhaleContextForRun = (params) => {
|
|
|
5124
5054
|
if (strategyRequiresContext) return true;
|
|
5125
5055
|
return ["1", "true", "yes", "on"].includes(configured);
|
|
5126
5056
|
};
|
|
5057
|
+
var resolveCoreContextSources = async (params) => {
|
|
5058
|
+
const strategyNames = [...new Set(params.strategyNames ?? [])];
|
|
5059
|
+
if (!strategyNames.length) return [];
|
|
5060
|
+
await (0, import_registry.ensureStrategyPluginsLoaded)(params.projectRoot);
|
|
5061
|
+
return [
|
|
5062
|
+
...new Set(
|
|
5063
|
+
strategyNames.flatMap(
|
|
5064
|
+
(strategyName) => (0, import_registry.getStrategyManifest)(strategyName, params.projectRoot)?.contextRequirements?.core ?? []
|
|
5065
|
+
)
|
|
5066
|
+
)
|
|
5067
|
+
];
|
|
5068
|
+
};
|
|
5069
|
+
var resolveMarketContextRunRequirements = async (params) => {
|
|
5070
|
+
const coreContextSources = await resolveCoreContextSources(params);
|
|
5071
|
+
const paramsWithCoreDemand = (source) => coreContextSources.includes(source) ? { ...params, aiEnabled: true } : params;
|
|
5072
|
+
const isCrypto = params.universe !== "tradfi";
|
|
5073
|
+
const capturesPayload = Boolean(params.aiEnabled || params.mlEnabled);
|
|
5074
|
+
const runtimeReadsContext = params.mode !== "backtest";
|
|
5075
|
+
const reasonsFor = (source) => uniqueReasons([
|
|
5076
|
+
...coreContextSources.includes(source) ? ["core"] : [],
|
|
5077
|
+
...params.aiEnabled ? ["ai"] : [],
|
|
5078
|
+
...params.mlEnabled ? ["ml"] : [],
|
|
5079
|
+
...runtimeReadsContext ? ["runtime"] : []
|
|
5080
|
+
]);
|
|
5081
|
+
const readsStandardContext = isCrypto && (capturesPayload || runtimeReadsContext);
|
|
5082
|
+
const readsHyperliquid = isCrypto && (readsStandardContext || coreContextSources.includes("hyperliquidWhales"));
|
|
5083
|
+
return {
|
|
5084
|
+
binance: {
|
|
5085
|
+
read: readsStandardContext || coreContextSources.includes("binance"),
|
|
5086
|
+
backfill: shouldPrepareBinanceMarketContextForRun(
|
|
5087
|
+
paramsWithCoreDemand("binance")
|
|
5088
|
+
),
|
|
5089
|
+
requiredBy: reasonsFor("binance")
|
|
5090
|
+
},
|
|
5091
|
+
coinmarketcap: {
|
|
5092
|
+
read: readsStandardContext || coreContextSources.includes("coinmarketcap"),
|
|
5093
|
+
backfill: shouldPrepareCoinMarketCapContextForRun(
|
|
5094
|
+
paramsWithCoreDemand("coinmarketcap")
|
|
5095
|
+
),
|
|
5096
|
+
requiredBy: reasonsFor("coinmarketcap")
|
|
5097
|
+
},
|
|
5098
|
+
derivatives: {
|
|
5099
|
+
read: readsStandardContext || coreContextSources.includes("derivatives"),
|
|
5100
|
+
backfill: shouldPrepareDerivativesContextForRun(
|
|
5101
|
+
paramsWithCoreDemand("derivatives")
|
|
5102
|
+
),
|
|
5103
|
+
requiredBy: reasonsFor("derivatives")
|
|
5104
|
+
},
|
|
5105
|
+
hyperliquidWhales: {
|
|
5106
|
+
read: readsHyperliquid,
|
|
5107
|
+
backfill: shouldPrepareHyperliquidWhaleContextForRun(
|
|
5108
|
+
params,
|
|
5109
|
+
coreContextSources
|
|
5110
|
+
),
|
|
5111
|
+
requiredBy: reasonsFor("hyperliquidWhales")
|
|
5112
|
+
}
|
|
5113
|
+
};
|
|
5114
|
+
};
|
|
5127
5115
|
var resolveCoinMarketCapBackfillForMode = (mode) => mode === "backtest" ? backfillCoinMarketCapContextForBacktest : mode === "signals" ? backfillCoinMarketCapContextForSignals : backfillCoinMarketCapContextForReplay;
|
|
5128
5116
|
var buildCoinMarketCapBackfillParams = (params) => ({
|
|
5129
5117
|
userName: params.userName,
|
|
@@ -5152,7 +5140,15 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
5152
5140
|
console.log(import_chalk4.default.gray(message));
|
|
5153
5141
|
});
|
|
5154
5142
|
const timeOperation3 = (label, operation) => timeOperation(label, operation, log);
|
|
5155
|
-
|
|
5143
|
+
const requirements = await resolveMarketContextRunRequirements(params);
|
|
5144
|
+
const readableSources = Object.entries(requirements).filter(([, requirement]) => requirement.read).map(([source]) => source);
|
|
5145
|
+
if (readableSources.length) {
|
|
5146
|
+
await timeOperation3(
|
|
5147
|
+
"market context schema ensure",
|
|
5148
|
+
() => (0, import_timescale5.ensureMarketContextSchemas)(readableSources)
|
|
5149
|
+
);
|
|
5150
|
+
}
|
|
5151
|
+
if (requirements.derivatives.backfill) {
|
|
5156
5152
|
await timeOperation3(
|
|
5157
5153
|
"derivatives context backfill",
|
|
5158
5154
|
() => (params.mode === "signals" ? backfillDerivativesContextForSignals : backfillDerivativesContextForBacktest)(
|
|
@@ -5160,7 +5156,7 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
5160
5156
|
)
|
|
5161
5157
|
);
|
|
5162
5158
|
}
|
|
5163
|
-
if (
|
|
5159
|
+
if (requirements.hyperliquidWhales.backfill) {
|
|
5164
5160
|
await timeOperation3(
|
|
5165
5161
|
"hyperliquid whale context backfill",
|
|
5166
5162
|
() => backfillHyperliquidWhaleContext({
|
|
@@ -5172,13 +5168,13 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
5172
5168
|
})
|
|
5173
5169
|
);
|
|
5174
5170
|
}
|
|
5175
|
-
if (
|
|
5171
|
+
if (requirements.binance.backfill) {
|
|
5176
5172
|
await timeOperation3("binance market context backfill", () => {
|
|
5177
5173
|
const backfill = params.mode === "backtest" ? backfillBinanceMarketContextForBacktest : params.mode === "signals" ? backfillBinanceMarketContextForSignals : backfillBinanceMarketContextForReplay;
|
|
5178
5174
|
return backfill(buildBinanceMarketBackfillParams(params));
|
|
5179
5175
|
});
|
|
5180
5176
|
}
|
|
5181
|
-
if (
|
|
5177
|
+
if (requirements.coinmarketcap.backfill) {
|
|
5182
5178
|
await timeOperation3(
|
|
5183
5179
|
"coinmarketcap historical context backfill",
|
|
5184
5180
|
() => resolveCoinMarketCapBackfillForMode(params.mode)(
|
|
@@ -5186,6 +5182,7 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
5186
5182
|
)
|
|
5187
5183
|
);
|
|
5188
5184
|
}
|
|
5185
|
+
return requirements;
|
|
5189
5186
|
};
|
|
5190
5187
|
|
|
5191
5188
|
// src/lib/marketData/historyPrepare.ts
|
|
@@ -5349,7 +5346,7 @@ var import_strategies3 = require("@tradejs/node/strategies");
|
|
|
5349
5346
|
|
|
5350
5347
|
// src/lib/runtimeRedis.ts
|
|
5351
5348
|
var import_redis = require("@tradejs/infra/redis");
|
|
5352
|
-
var
|
|
5349
|
+
var import_time = require("@tradejs/core/time");
|
|
5353
5350
|
var RESERVED_STRATEGY_NAMES = /* @__PURE__ */ new Set(["charts"]);
|
|
5354
5351
|
var RESERVED_CONFIG_IDS = /* @__PURE__ */ new Set(["results"]);
|
|
5355
5352
|
var resolveStrategyConfigIdentityByKey = (userName, key) => {
|
|
@@ -5493,6 +5490,111 @@ var loadRuntimeStrategies = async ({
|
|
|
5493
5490
|
// src/lib/signals/skipStats.ts
|
|
5494
5491
|
var import_chalk6 = __toESM(require("chalk"));
|
|
5495
5492
|
var import_logger2 = require("@tradejs/infra/logger");
|
|
5493
|
+
|
|
5494
|
+
// src/lib/runtimeSignalsStorage.ts
|
|
5495
|
+
var import_constants2 = require("@tradejs/core/constants");
|
|
5496
|
+
var import_time2 = require("@tradejs/core/time");
|
|
5497
|
+
var SECONDS_PER_DAY = 86400;
|
|
5498
|
+
var RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
|
|
5499
|
+
var DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants2.TTL_3D;
|
|
5500
|
+
var RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS = import_constants2.TTL_1M;
|
|
5501
|
+
var parsePositiveNumber = (value) => {
|
|
5502
|
+
if (value == null || value === "") {
|
|
5503
|
+
return null;
|
|
5504
|
+
}
|
|
5505
|
+
const parsed = Number(value);
|
|
5506
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
5507
|
+
};
|
|
5508
|
+
var getRuntimeSignalRetentionTtlSeconds = () => {
|
|
5509
|
+
const explicitDays = parsePositiveNumber(
|
|
5510
|
+
process.env[RUNTIME_SIGNAL_RETENTION_DAYS_ENV]
|
|
5511
|
+
);
|
|
5512
|
+
if (explicitDays != null) {
|
|
5513
|
+
return Math.ceil(explicitDays * SECONDS_PER_DAY);
|
|
5514
|
+
}
|
|
5515
|
+
return DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS;
|
|
5516
|
+
};
|
|
5517
|
+
var toRuntimeSignalBucketRef = (signal) => ({
|
|
5518
|
+
signalId: signal.signalId,
|
|
5519
|
+
symbol: signal.symbol,
|
|
5520
|
+
strategy: signal.strategy,
|
|
5521
|
+
timestamp: signal.timestamp,
|
|
5522
|
+
...signal.runtimeConfigId && signal.runtimeConfigId !== "config" ? { runtimeConfigId: signal.runtimeConfigId } : {}
|
|
5523
|
+
});
|
|
5524
|
+
var shouldStoreRuntimeSignalDiagnostics = (signal) => signal.orderStatus === "completed" || signal.orderStatus === "failed";
|
|
5525
|
+
var toStoredRuntimeSignal = (signal) => {
|
|
5526
|
+
if (shouldStoreRuntimeSignalDiagnostics(signal)) {
|
|
5527
|
+
return signal;
|
|
5528
|
+
}
|
|
5529
|
+
const stored = { ...signal };
|
|
5530
|
+
delete stored.figures;
|
|
5531
|
+
delete stored.indicators;
|
|
5532
|
+
delete stored.additionalIndicators;
|
|
5533
|
+
return stored;
|
|
5534
|
+
};
|
|
5535
|
+
var normalizeRuntimeSignalSkipReason = (reason, fallbackSource) => {
|
|
5536
|
+
let source = fallbackSource;
|
|
5537
|
+
let normalizedReason = reason;
|
|
5538
|
+
if (reason.startsWith("AI_QUALITY_BELOW_MIN")) {
|
|
5539
|
+
source = "AI";
|
|
5540
|
+
normalizedReason = "MIN_AI_QUALITY";
|
|
5541
|
+
} else if (reason === "AI_QUALITY_UNAVAILABLE") {
|
|
5542
|
+
source = "AI";
|
|
5543
|
+
normalizedReason = "QUALITY_UNAVAILABLE";
|
|
5544
|
+
} else if (reason === "ML_RESULT_UNAVAILABLE") {
|
|
5545
|
+
source = "ML";
|
|
5546
|
+
normalizedReason = "RESULT_UNAVAILABLE";
|
|
5547
|
+
} else if (reason.startsWith("ML_THRESHOLD_NOT_MET")) {
|
|
5548
|
+
source = "ML";
|
|
5549
|
+
normalizedReason = "ML_THRESHOLD";
|
|
5550
|
+
} else if (reason.startsWith("HOOK_BEFORE_ENTRY_GATE:")) {
|
|
5551
|
+
source = "hook";
|
|
5552
|
+
normalizedReason = `BEFORE_ENTRY_GATE:${reason.slice(
|
|
5553
|
+
"HOOK_BEFORE_ENTRY_GATE:".length
|
|
5554
|
+
)}`;
|
|
5555
|
+
} else if (reason === "HOOK_BEFORE_ENTRY_GATE") {
|
|
5556
|
+
source = "hook";
|
|
5557
|
+
normalizedReason = "BEFORE_ENTRY_GATE";
|
|
5558
|
+
} else if (reason === "MAKE_ORDERS_DISABLED" || reason === "ENTRY_POLICY_BLOCKED") {
|
|
5559
|
+
source = "policy";
|
|
5560
|
+
}
|
|
5561
|
+
return {
|
|
5562
|
+
source: `skip from ${source}`,
|
|
5563
|
+
reason: normalizedReason
|
|
5564
|
+
};
|
|
5565
|
+
};
|
|
5566
|
+
var buildStatsReasonField = (source, reason) => `reason:${source}:${reason}`;
|
|
5567
|
+
var buildRuntimeSignalStatsIncrements = (evaluation) => {
|
|
5568
|
+
const increments = {
|
|
5569
|
+
evaluated: 1
|
|
5570
|
+
};
|
|
5571
|
+
if (evaluation.status === "signal") {
|
|
5572
|
+
increments.signals = 1;
|
|
5573
|
+
}
|
|
5574
|
+
let skipReason = null;
|
|
5575
|
+
let fallbackSource = "core";
|
|
5576
|
+
if (evaluation.status === "skip") {
|
|
5577
|
+
skipReason = evaluation.reason || "NO_SIGNAL";
|
|
5578
|
+
fallbackSource = "core";
|
|
5579
|
+
} else if (evaluation.status === "signal" && (evaluation.orderStatus === "skipped" || evaluation.orderStatus === "canceled")) {
|
|
5580
|
+
skipReason = evaluation.orderSkipReason || evaluation.reason || `orderStatus=${evaluation.orderStatus}`;
|
|
5581
|
+
fallbackSource = "runtime";
|
|
5582
|
+
} else if (evaluation.status === "error") {
|
|
5583
|
+
skipReason = evaluation.reason || "EVALUATION_ERROR";
|
|
5584
|
+
fallbackSource = "runtime";
|
|
5585
|
+
}
|
|
5586
|
+
if (skipReason) {
|
|
5587
|
+
const normalized = normalizeRuntimeSignalSkipReason(
|
|
5588
|
+
skipReason,
|
|
5589
|
+
fallbackSource
|
|
5590
|
+
);
|
|
5591
|
+
increments[buildStatsReasonField(normalized.source, normalized.reason)] = 1;
|
|
5592
|
+
}
|
|
5593
|
+
return increments;
|
|
5594
|
+
};
|
|
5595
|
+
var shouldStoreDetailedRuntimeSignalEvaluation = (evaluation) => evaluation.status !== "skip";
|
|
5596
|
+
|
|
5597
|
+
// src/lib/signals/skipStats.ts
|
|
5496
5598
|
var createStrategySkipStats = (runtimeStrategies) => new Map(
|
|
5497
5599
|
runtimeStrategies.map(({ strategyName }) => [
|
|
5498
5600
|
strategyName,
|
|
@@ -5820,7 +5922,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
5820
5922
|
if (evaluations.length === 0) return;
|
|
5821
5923
|
const evaluationsByDay = /* @__PURE__ */ new Map();
|
|
5822
5924
|
for (const evaluation of evaluations) {
|
|
5823
|
-
const dayKey = (0,
|
|
5925
|
+
const dayKey = (0, import_time2.getRuntimeStorageDayKey)(evaluation.timestamp);
|
|
5824
5926
|
const dayEvaluations = evaluationsByDay.get(dayKey) ?? [];
|
|
5825
5927
|
dayEvaluations.push(evaluation);
|
|
5826
5928
|
evaluationsByDay.set(dayKey, dayEvaluations);
|
|
@@ -5928,13 +6030,47 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
|
|
|
5928
6030
|
};
|
|
5929
6031
|
var createRuntimeSignalEvaluationBuffer = () => {
|
|
5930
6032
|
const evaluations = [];
|
|
6033
|
+
const signals2 = [];
|
|
5931
6034
|
return {
|
|
5932
6035
|
save: async (evaluation) => {
|
|
5933
6036
|
evaluations.push(evaluation);
|
|
5934
6037
|
},
|
|
6038
|
+
saveSignal: (userName, signal) => {
|
|
6039
|
+
signals2.push({ userName, signal });
|
|
6040
|
+
},
|
|
5935
6041
|
flush: async () => {
|
|
5936
6042
|
const pending = evaluations.splice(0);
|
|
5937
|
-
|
|
6043
|
+
const pendingSignals = signals2.splice(0);
|
|
6044
|
+
const runtimeSignalRetentionTtl = getRuntimeSignalRetentionTtlSeconds();
|
|
6045
|
+
const signalRefsByBucket = /* @__PURE__ */ new Map();
|
|
6046
|
+
for (const { userName, signal } of pendingSignals) {
|
|
6047
|
+
const bucket = import_redis3.redisKeys.runtimeSignalBucket(
|
|
6048
|
+
userName,
|
|
6049
|
+
(0, import_time2.getRuntimeStorageDayKey)(signal.timestamp),
|
|
6050
|
+
signal.strategy
|
|
6051
|
+
);
|
|
6052
|
+
const entries = signalRefsByBucket.get(bucket) ?? [];
|
|
6053
|
+
entries.push({
|
|
6054
|
+
field: signal.signalId,
|
|
6055
|
+
data: toRuntimeSignalBucketRef(signal)
|
|
6056
|
+
});
|
|
6057
|
+
signalRefsByBucket.set(bucket, entries);
|
|
6058
|
+
}
|
|
6059
|
+
await Promise.all([
|
|
6060
|
+
flushRuntimeSignalEvaluations(pending),
|
|
6061
|
+
...pendingSignals.map(
|
|
6062
|
+
({ signal }) => (0, import_redis3.setData)(
|
|
6063
|
+
import_redis3.redisKeys.storeSignal(signal.symbol, signal.signalId),
|
|
6064
|
+
toStoredRuntimeSignal(signal),
|
|
6065
|
+
{ expire: runtimeSignalRetentionTtl }
|
|
6066
|
+
)
|
|
6067
|
+
),
|
|
6068
|
+
...[...signalRefsByBucket].map(
|
|
6069
|
+
([bucket, entries]) => (0, import_redis3.setHashJsonFields)(bucket, entries, {
|
|
6070
|
+
expire: runtimeSignalRetentionTtl
|
|
6071
|
+
})
|
|
6072
|
+
)
|
|
6073
|
+
]);
|
|
5938
6074
|
}
|
|
5939
6075
|
};
|
|
5940
6076
|
};
|
|
@@ -6167,7 +6303,7 @@ var runSignalsDaemon = async ({
|
|
|
6167
6303
|
// src/lib/signals/klineFeed.ts
|
|
6168
6304
|
var import_connectors5 = require("@tradejs/connectors");
|
|
6169
6305
|
var import_logger3 = require("@tradejs/infra/logger");
|
|
6170
|
-
var
|
|
6306
|
+
var import_timescale6 = require("@tradejs/infra/timescale");
|
|
6171
6307
|
|
|
6172
6308
|
// src/lib/marketData/klineEvents.ts
|
|
6173
6309
|
var import_ioredis = __toESM(require("ioredis"));
|
|
@@ -6187,9 +6323,9 @@ var createSignalsKlineFeed = async ({
|
|
|
6187
6323
|
publish = publishMarketKlineEvent,
|
|
6188
6324
|
persist = async (rows) => {
|
|
6189
6325
|
const intervalMinutes = Number(interval2);
|
|
6190
|
-
await (0,
|
|
6326
|
+
await (0, import_timescale6.upsertCandles)(
|
|
6191
6327
|
rows.flatMap(
|
|
6192
|
-
({ symbol, candle }) => (0,
|
|
6328
|
+
({ symbol, candle }) => (0, import_timescale6.toRows)("bybit", symbol, intervalMinutes, [candle])
|
|
6193
6329
|
)
|
|
6194
6330
|
);
|
|
6195
6331
|
},
|
|
@@ -6455,7 +6591,7 @@ var createSignalsSession = async (lifecycle, scope = {}) => {
|
|
|
6455
6591
|
lifecycle
|
|
6456
6592
|
};
|
|
6457
6593
|
};
|
|
6458
|
-
var findSignals = async (symbol, connectorName, connector, btcBinanceData, btcCoinbaseData, primaryBtcClosedData, primaryEthClosedData, primaryEthByTimestamp, runtimeStrategies, strategyStats, runtimeCloseNotifications, lifecycle, preloadStart, currentTimestamp, persistStrategyState, universe, interval2, intervalMs2, accountId, deploymentId, instrument, runtimeScopeUniverse, saveRuntimeSignalEvaluation) => {
|
|
6594
|
+
var findSignals = async (symbol, connectorName, connector, btcBinanceData, btcCoinbaseData, primaryBtcClosedData, primaryEthClosedData, primaryEthByTimestamp, runtimeStrategies, strategyStats, runtimeCloseNotifications, lifecycle, preloadStart, currentTimestamp, persistStrategyState, universe, interval2, intervalMs2, accountId, deploymentId, instrument, runtimeScopeUniverse, saveRuntimeSignalEvaluation, saveRuntimeSignal) => {
|
|
6459
6595
|
const strategySignals = [];
|
|
6460
6596
|
const loadCached = (cachedSymbol) => connector.kline({
|
|
6461
6597
|
symbol: cachedSymbol,
|
|
@@ -6648,26 +6784,7 @@ var findSignals = async (symbol, connectorName, connector, btcBinanceData, btcCo
|
|
|
6648
6784
|
);
|
|
6649
6785
|
}
|
|
6650
6786
|
strategySignals.push(signal);
|
|
6651
|
-
|
|
6652
|
-
await (0, import_redis5.setData)(
|
|
6653
|
-
import_redis5.redisKeys.storeSignal(symbol, signal.signalId),
|
|
6654
|
-
toStoredRuntimeSignal(signal),
|
|
6655
|
-
{
|
|
6656
|
-
expire: runtimeSignalRetentionTtl
|
|
6657
|
-
}
|
|
6658
|
-
);
|
|
6659
|
-
await (0, import_redis5.setHashJsonField)(
|
|
6660
|
-
import_redis5.redisKeys.runtimeSignalBucket(
|
|
6661
|
-
flags.user,
|
|
6662
|
-
(0, import_time.getRuntimeStorageDayKey)(signal.timestamp),
|
|
6663
|
-
signal.strategy
|
|
6664
|
-
),
|
|
6665
|
-
signal.signalId,
|
|
6666
|
-
toRuntimeSignalBucketRef(signal),
|
|
6667
|
-
{
|
|
6668
|
-
expire: runtimeSignalRetentionTtl
|
|
6669
|
-
}
|
|
6670
|
-
);
|
|
6787
|
+
saveRuntimeSignal?.(flags.user, signal);
|
|
6671
6788
|
await saveRuntimeSignalEvaluation?.({
|
|
6672
6789
|
evaluationId: buildRuntimeSignalEvaluationId({
|
|
6673
6790
|
strategyName,
|
|
@@ -6938,7 +7055,7 @@ var signals = async (options = {}) => {
|
|
|
6938
7055
|
return;
|
|
6939
7056
|
}
|
|
6940
7057
|
const strategyStats = createStrategySkipStats(runtimeStrategies);
|
|
6941
|
-
const bar = new
|
|
7058
|
+
const bar = new import_progress4.default(
|
|
6942
7059
|
":current/:total [:bar][:percent] :found :eta(s) :symbol",
|
|
6943
7060
|
{
|
|
6944
7061
|
total: tickers.length,
|
|
@@ -6973,7 +7090,8 @@ var signals = async (options = {}) => {
|
|
|
6973
7090
|
deployment?.id,
|
|
6974
7091
|
instrumentsBySymbol.get(symbol),
|
|
6975
7092
|
sessionUniverse,
|
|
6976
|
-
runtimeSignalEvaluations.save
|
|
7093
|
+
runtimeSignalEvaluations.save,
|
|
7094
|
+
runtimeSignalEvaluations.saveSignal
|
|
6977
7095
|
);
|
|
6978
7096
|
if (strategySignals.length > 0) {
|
|
6979
7097
|
signals2.push(...strategySignals);
|