@tradejs/node 2.0.15 → 2.0.16
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/ai.js +11 -2
- package/dist/ai.mjs +1 -1
- package/dist/backtest.js +236 -97
- package/dist/backtest.mjs +21 -64
- package/dist/{chunk-FEQR4XGR.mjs → chunk-3BP3ETAD.mjs} +213 -32
- package/dist/{chunk-DPHKRDD5.mjs → chunk-WK5EUCX5.mjs} +11 -2
- package/dist/cli.js +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/strategies.d.mts +3 -0
- package/dist/strategies.d.ts +3 -0
- package/dist/strategies.js +770 -564
- package/dist/strategies.mjs +42 -24
- package/package.json +4 -4
package/dist/ai.js
CHANGED
|
@@ -1147,6 +1147,15 @@ var postProcessAiAnalysisByStrategy = (signal, analysis, payload = buildAiPayloa
|
|
|
1147
1147
|
payload,
|
|
1148
1148
|
analysis
|
|
1149
1149
|
}) ?? analysis;
|
|
1150
|
+
var postProcessLocalAiAnalysisByStrategy = (signal, analysis, payload = buildAiPayloadByStrategy(signal)) => {
|
|
1151
|
+
const adapter = getSignalAiAdapter(signal);
|
|
1152
|
+
const strategyAnalysis = adapter.postProcessAnalysis?.({ signal, payload, analysis }) ?? analysis;
|
|
1153
|
+
return adapter.postProcessLocalAnalysis?.({
|
|
1154
|
+
signal,
|
|
1155
|
+
payload,
|
|
1156
|
+
analysis: strategyAnalysis
|
|
1157
|
+
}) ?? strategyAnalysis;
|
|
1158
|
+
};
|
|
1150
1159
|
|
|
1151
1160
|
// src/ai.ts
|
|
1152
1161
|
var parseAIResponse = (input) => {
|
|
@@ -1295,7 +1304,7 @@ Input payload structure:
|
|
|
1295
1304
|
\u2022 \`baseContext.relative\`: BTC/ETH relative-strength, benchmark MA bias context, Binance alt-basket breadth, and CoinMarketCap historical global/exchange/index context when available.
|
|
1296
1305
|
\u2022 \`baseContext.derivatives\`: Coinalyze-aligned derivatives summary when available.
|
|
1297
1306
|
\u2022 \`baseContext.mtf\`: compact multi-timeframe summary plus only the latest few candles for each timeframe.
|
|
1298
|
-
\u2022 \`baseContext.gateFeatures\`: direction-aware
|
|
1307
|
+
\u2022 \`baseContext.gateFeatures\`: compact direction-aware fields derived from baseContext; prefer \`setup\`, \`scores\`, \`conflicts\`, \`risk\`, \`decisionHints\`, \`mtf\`, \`volatility\`, \`participation\`, and \`relative\` for quick gate checks before inspecting raw nested context.
|
|
1299
1308
|
Always inspect \`payload.additionalIndicators.marketContext\` when present:
|
|
1300
1309
|
\u2022 \`marketContext.execution.binanceCoinbaseSpread\`: AI-friendly BTC spread view projected from \`payload.additionalIndicators.baseContext.relative.execution.venueSpread\`; \`value=(Coinbase-Binance)/Binance\`, \`bps=value*10000\`.
|
|
1301
1310
|
\u2022 \`marketContext.participation.trueDelta\`: Binance taker buy/sell volume delta from kline payload when \`source=kline_taker_volume\`; otherwise absent/unavailable.
|
|
@@ -1577,7 +1586,7 @@ var runAiPromptLocal = async (signal, options = {}) => {
|
|
|
1577
1586
|
const signalDirection = getSignalDirection(signal);
|
|
1578
1587
|
const deterministicQuality = getDeterministicQuality(gateContext);
|
|
1579
1588
|
const approvalAllowedNow = typeof gateContext?.approvalAllowedNow === "boolean" ? gateContext.approvalAllowedNow : deterministicQuality >= 4;
|
|
1580
|
-
return
|
|
1589
|
+
return postProcessLocalAiAnalysisByStrategy(
|
|
1581
1590
|
signal,
|
|
1582
1591
|
{
|
|
1583
1592
|
direction: approvalAllowedNow ? signalDirection : null,
|
package/dist/ai.mjs
CHANGED
package/dist/backtest.js
CHANGED
|
@@ -50,7 +50,7 @@ var import_strategies5 = require("@tradejs/core/strategies");
|
|
|
50
50
|
var import_time = require("@tradejs/core/time");
|
|
51
51
|
var import_ai2 = require("@tradejs/infra/ai");
|
|
52
52
|
var import_ml2 = require("@tradejs/infra/ml");
|
|
53
|
-
var
|
|
53
|
+
var import_logger9 = require("@tradejs/infra/logger");
|
|
54
54
|
|
|
55
55
|
// src/ai.ts
|
|
56
56
|
var import_aiLanguages = require("@tradejs/infra/aiLanguages");
|
|
@@ -1153,6 +1153,9 @@ var buildAiPayloadByStrategy = (signal) => {
|
|
|
1153
1153
|
// src/ai.ts
|
|
1154
1154
|
var buildAiPayload = (signal) => buildAiPayloadByStrategy(signal);
|
|
1155
1155
|
|
|
1156
|
+
// src/strategyHelpers/marketContextStages.ts
|
|
1157
|
+
var import_logger7 = require("@tradejs/infra/logger");
|
|
1158
|
+
|
|
1156
1159
|
// src/strategyHelpers/binanceMarketContext.ts
|
|
1157
1160
|
var import_timescale = require("@tradejs/infra/timescale");
|
|
1158
1161
|
var import_logger3 = require("@tradejs/infra/logger");
|
|
@@ -1461,6 +1464,13 @@ var getBinanceBreadthUniverses = () => BINANCE_BREADTH_UNIVERSE_KEYS.map((key) =
|
|
|
1461
1464
|
};
|
|
1462
1465
|
});
|
|
1463
1466
|
|
|
1467
|
+
// src/strategyHelpers/marketContextErrors.ts
|
|
1468
|
+
var MARKET_CONTEXT_CANCELLATION_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
1469
|
+
"AbortError",
|
|
1470
|
+
"TimescaleQueryTimeoutError"
|
|
1471
|
+
]);
|
|
1472
|
+
var isMarketContextCancellationError = (error, abortSignal) => abortSignal?.aborted === true || error instanceof Error && MARKET_CONTEXT_CANCELLATION_ERROR_NAMES.has(error.name);
|
|
1473
|
+
|
|
1464
1474
|
// src/strategyHelpers/binanceMarketContext.ts
|
|
1465
1475
|
var DEFAULT_MAX_AGE_BY_INTERVAL = {
|
|
1466
1476
|
"1m": 3 * 6e4,
|
|
@@ -1525,7 +1535,8 @@ var getCachedReferenceRows = ({
|
|
|
1525
1535
|
referenceSymbols,
|
|
1526
1536
|
interval,
|
|
1527
1537
|
timestamp,
|
|
1528
|
-
maxAgeMs
|
|
1538
|
+
maxAgeMs,
|
|
1539
|
+
abortSignal
|
|
1529
1540
|
}) => {
|
|
1530
1541
|
const key = `${referenceSymbols.join(",")}:${interval}:${timestamp}:${maxAgeMs}`;
|
|
1531
1542
|
const cached = referenceRowsCache.get(key);
|
|
@@ -1536,7 +1547,8 @@ var getCachedReferenceRows = ({
|
|
|
1536
1547
|
symbol,
|
|
1537
1548
|
interval,
|
|
1538
1549
|
atMs: timestamp,
|
|
1539
|
-
maxAgeMs
|
|
1550
|
+
maxAgeMs,
|
|
1551
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
1540
1552
|
});
|
|
1541
1553
|
return {
|
|
1542
1554
|
symbol,
|
|
@@ -1545,13 +1557,15 @@ var getCachedReferenceRows = ({
|
|
|
1545
1557
|
})
|
|
1546
1558
|
);
|
|
1547
1559
|
referenceRowsCache.set(key, promise);
|
|
1560
|
+
void promise.catch(() => referenceRowsCache.delete(key));
|
|
1548
1561
|
return promise;
|
|
1549
1562
|
};
|
|
1550
1563
|
var getCachedBreadth = ({
|
|
1551
1564
|
breadthUniverse,
|
|
1552
1565
|
interval,
|
|
1553
1566
|
timestamp,
|
|
1554
|
-
maxAgeMs
|
|
1567
|
+
maxAgeMs,
|
|
1568
|
+
abortSignal
|
|
1555
1569
|
}) => {
|
|
1556
1570
|
const key = `${breadthUniverse}:${interval}:${timestamp}:${maxAgeMs}`;
|
|
1557
1571
|
const cached = breadthCache.get(key);
|
|
@@ -1560,9 +1574,11 @@ var getCachedBreadth = ({
|
|
|
1560
1574
|
universe: breadthUniverse,
|
|
1561
1575
|
interval,
|
|
1562
1576
|
atMs: timestamp,
|
|
1563
|
-
maxAgeMs
|
|
1577
|
+
maxAgeMs,
|
|
1578
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
1564
1579
|
});
|
|
1565
1580
|
breadthCache.set(key, promise);
|
|
1581
|
+
void promise.catch(() => breadthCache.delete(key));
|
|
1566
1582
|
return promise;
|
|
1567
1583
|
};
|
|
1568
1584
|
var toMarketBreadthContext = (breadth, interval) => ({
|
|
@@ -1608,7 +1624,8 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
1608
1624
|
referenceSymbols,
|
|
1609
1625
|
interval,
|
|
1610
1626
|
timestamp: signal.timestamp,
|
|
1611
|
-
maxAgeMs
|
|
1627
|
+
maxAgeMs,
|
|
1628
|
+
abortSignal: params.abortSignal
|
|
1612
1629
|
}),
|
|
1613
1630
|
Promise.all(
|
|
1614
1631
|
breadthUniverses.map(async ({ key, universe }) => ({
|
|
@@ -1617,7 +1634,8 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
1617
1634
|
breadthUniverse: universe,
|
|
1618
1635
|
interval,
|
|
1619
1636
|
timestamp: signal.timestamp,
|
|
1620
|
-
maxAgeMs
|
|
1637
|
+
maxAgeMs,
|
|
1638
|
+
abortSignal: params.abortSignal
|
|
1621
1639
|
})
|
|
1622
1640
|
}))
|
|
1623
1641
|
)
|
|
@@ -1732,6 +1750,9 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
|
|
|
1732
1750
|
(0, import_strategies.refreshSignalBaseContextGateFeatures)(signal);
|
|
1733
1751
|
return true;
|
|
1734
1752
|
} catch (error) {
|
|
1753
|
+
if (isMarketContextCancellationError(error, params.abortSignal)) {
|
|
1754
|
+
throw error;
|
|
1755
|
+
}
|
|
1735
1756
|
binanceMarketContextUnavailable = true;
|
|
1736
1757
|
import_logger3.logger.warn(
|
|
1737
1758
|
"Binance market context disabled after Timescale read failure: %s",
|
|
@@ -1852,7 +1873,8 @@ var toIndexRegime = ({
|
|
|
1852
1873
|
};
|
|
1853
1874
|
var getCachedGlobalContext = ({
|
|
1854
1875
|
timestamp,
|
|
1855
|
-
maxAgeMs
|
|
1876
|
+
maxAgeMs,
|
|
1877
|
+
abortSignal
|
|
1856
1878
|
}) => {
|
|
1857
1879
|
const key = `${SOURCE_GLOBAL_DAILY}:${timestamp}:${maxAgeMs}`;
|
|
1858
1880
|
const cached = globalContextCache.get(key);
|
|
@@ -1860,14 +1882,17 @@ var getCachedGlobalContext = ({
|
|
|
1860
1882
|
const promise = (0, import_timescale2.getLatestMarketGlobalContext)({
|
|
1861
1883
|
source: SOURCE_GLOBAL_DAILY,
|
|
1862
1884
|
atMs: timestamp,
|
|
1863
|
-
maxAgeMs
|
|
1885
|
+
maxAgeMs,
|
|
1886
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
1864
1887
|
});
|
|
1865
1888
|
globalContextCache.set(key, promise);
|
|
1889
|
+
void promise.catch(() => globalContextCache.delete(key));
|
|
1866
1890
|
return promise;
|
|
1867
1891
|
};
|
|
1868
1892
|
var getCachedReferenceContexts = ({
|
|
1869
1893
|
timestamp,
|
|
1870
|
-
maxAgeMs
|
|
1894
|
+
maxAgeMs,
|
|
1895
|
+
abortSignal
|
|
1871
1896
|
}) => {
|
|
1872
1897
|
const key = `${SOURCE_REFERENCE}:1d:${timestamp}:${maxAgeMs}`;
|
|
1873
1898
|
const cached = referenceContextCache.get(key);
|
|
@@ -1877,14 +1902,17 @@ var getCachedReferenceContexts = ({
|
|
|
1877
1902
|
symbols: ["BTCUSDT", "ETHUSDT"],
|
|
1878
1903
|
interval: "1d",
|
|
1879
1904
|
atMs: timestamp,
|
|
1880
|
-
maxAgeMs
|
|
1905
|
+
maxAgeMs,
|
|
1906
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
1881
1907
|
});
|
|
1882
1908
|
referenceContextCache.set(key, promise);
|
|
1909
|
+
void promise.catch(() => referenceContextCache.delete(key));
|
|
1883
1910
|
return promise;
|
|
1884
1911
|
};
|
|
1885
1912
|
var getCachedExchangeLiquidityContext = ({
|
|
1886
1913
|
timestamp,
|
|
1887
|
-
maxAgeMs
|
|
1914
|
+
maxAgeMs,
|
|
1915
|
+
abortSignal
|
|
1888
1916
|
}) => {
|
|
1889
1917
|
const key = `${SOURCE_EXCHANGE_LIQUIDITY}:1d:${timestamp}:${maxAgeMs}`;
|
|
1890
1918
|
const cached = exchangeLiquidityContextCache.get(key);
|
|
@@ -1893,14 +1921,17 @@ var getCachedExchangeLiquidityContext = ({
|
|
|
1893
1921
|
source: SOURCE_EXCHANGE_LIQUIDITY,
|
|
1894
1922
|
interval: "1d",
|
|
1895
1923
|
atMs: timestamp,
|
|
1896
|
-
maxAgeMs
|
|
1924
|
+
maxAgeMs,
|
|
1925
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
1897
1926
|
});
|
|
1898
1927
|
exchangeLiquidityContextCache.set(key, promise);
|
|
1928
|
+
void promise.catch(() => exchangeLiquidityContextCache.delete(key));
|
|
1899
1929
|
return promise;
|
|
1900
1930
|
};
|
|
1901
1931
|
var getCachedFearGreedContext = ({
|
|
1902
1932
|
timestamp,
|
|
1903
|
-
maxAgeMs
|
|
1933
|
+
maxAgeMs,
|
|
1934
|
+
abortSignal
|
|
1904
1935
|
}) => {
|
|
1905
1936
|
const key = `${SOURCE_FEAR_GREED}:1d:${timestamp}:${maxAgeMs}`;
|
|
1906
1937
|
const cached = fearGreedContextCache.get(key);
|
|
@@ -1909,14 +1940,17 @@ var getCachedFearGreedContext = ({
|
|
|
1909
1940
|
source: SOURCE_FEAR_GREED,
|
|
1910
1941
|
interval: "1d",
|
|
1911
1942
|
atMs: timestamp,
|
|
1912
|
-
maxAgeMs
|
|
1943
|
+
maxAgeMs,
|
|
1944
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
1913
1945
|
});
|
|
1914
1946
|
fearGreedContextCache.set(key, promise);
|
|
1947
|
+
void promise.catch(() => fearGreedContextCache.delete(key));
|
|
1915
1948
|
return promise;
|
|
1916
1949
|
};
|
|
1917
1950
|
var getCachedIndexContexts = ({
|
|
1918
1951
|
timestamp,
|
|
1919
|
-
maxAgeMs
|
|
1952
|
+
maxAgeMs,
|
|
1953
|
+
abortSignal
|
|
1920
1954
|
}) => {
|
|
1921
1955
|
const key = `${SOURCE_INDEX}:1d:${timestamp}:${maxAgeMs}`;
|
|
1922
1956
|
const cached = indexContextCache.get(key);
|
|
@@ -1926,9 +1960,11 @@ var getCachedIndexContexts = ({
|
|
|
1926
1960
|
indexSlugs: ["cmc100", "cmc20"],
|
|
1927
1961
|
interval: "1d",
|
|
1928
1962
|
atMs: timestamp,
|
|
1929
|
-
maxAgeMs
|
|
1963
|
+
maxAgeMs,
|
|
1964
|
+
...abortSignal ? { signal: abortSignal } : {}
|
|
1930
1965
|
});
|
|
1931
1966
|
indexContextCache.set(key, promise);
|
|
1967
|
+
void promise.catch(() => indexContextCache.delete(key));
|
|
1932
1968
|
return promise;
|
|
1933
1969
|
};
|
|
1934
1970
|
var isCoinMarketCapContextEnabled = (env) => parseEnabledFlag2(process.env.COINMARKETCAP_CONTEXT_ENABLED, env);
|
|
@@ -1953,27 +1989,33 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
1953
1989
|
] = await Promise.all([
|
|
1954
1990
|
getCachedGlobalContext({
|
|
1955
1991
|
timestamp: signal.timestamp,
|
|
1956
|
-
maxAgeMs
|
|
1992
|
+
maxAgeMs,
|
|
1993
|
+
abortSignal: params.abortSignal
|
|
1957
1994
|
}),
|
|
1958
1995
|
getCachedReferenceContexts({
|
|
1959
1996
|
timestamp: signal.timestamp,
|
|
1960
|
-
maxAgeMs
|
|
1997
|
+
maxAgeMs,
|
|
1998
|
+
abortSignal: params.abortSignal
|
|
1961
1999
|
}),
|
|
1962
2000
|
getCachedReferenceContexts({
|
|
1963
2001
|
timestamp: signal.timestamp - DAY_MS,
|
|
1964
|
-
maxAgeMs: maxAgeMs + DAY_MS
|
|
2002
|
+
maxAgeMs: maxAgeMs + DAY_MS,
|
|
2003
|
+
abortSignal: params.abortSignal
|
|
1965
2004
|
}),
|
|
1966
2005
|
getCachedExchangeLiquidityContext({
|
|
1967
2006
|
timestamp: signal.timestamp,
|
|
1968
|
-
maxAgeMs
|
|
2007
|
+
maxAgeMs,
|
|
2008
|
+
abortSignal: params.abortSignal
|
|
1969
2009
|
}),
|
|
1970
2010
|
getCachedFearGreedContext({
|
|
1971
2011
|
timestamp: signal.timestamp,
|
|
1972
|
-
maxAgeMs
|
|
2012
|
+
maxAgeMs,
|
|
2013
|
+
abortSignal: params.abortSignal
|
|
1973
2014
|
}),
|
|
1974
2015
|
getCachedIndexContexts({
|
|
1975
2016
|
timestamp: signal.timestamp,
|
|
1976
|
-
maxAgeMs
|
|
2017
|
+
maxAgeMs,
|
|
2018
|
+
abortSignal: params.abortSignal
|
|
1977
2019
|
})
|
|
1978
2020
|
]);
|
|
1979
2021
|
const globalRow = globalDailyRow;
|
|
@@ -2207,6 +2249,9 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
2207
2249
|
(0, import_strategies2.refreshSignalBaseContextGateFeatures)(signal);
|
|
2208
2250
|
return true;
|
|
2209
2251
|
} catch (error) {
|
|
2252
|
+
if (isMarketContextCancellationError(error, params.abortSignal)) {
|
|
2253
|
+
throw error;
|
|
2254
|
+
}
|
|
2210
2255
|
coinMarketCapContextUnavailable = true;
|
|
2211
2256
|
import_logger4.logger.warn(
|
|
2212
2257
|
"CoinMarketCap context disabled after Timescale read failure: %s",
|
|
@@ -2389,7 +2434,8 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
2389
2434
|
symbol,
|
|
2390
2435
|
intervals: STORED_INTERVALS,
|
|
2391
2436
|
endMs: derivativesEndMs,
|
|
2392
|
-
lookbackMs
|
|
2437
|
+
lookbackMs,
|
|
2438
|
+
...params.abortSignal ? { signal: params.abortSignal } : {}
|
|
2393
2439
|
});
|
|
2394
2440
|
return [
|
|
2395
2441
|
symbol,
|
|
@@ -2417,7 +2463,8 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
2417
2463
|
symbol: targetSymbol,
|
|
2418
2464
|
intervals: STORED_INTERVALS,
|
|
2419
2465
|
endMs: derivativesEndMs,
|
|
2420
|
-
lookbackMs
|
|
2466
|
+
lookbackMs,
|
|
2467
|
+
...params.abortSignal ? { signal: params.abortSignal } : {}
|
|
2421
2468
|
});
|
|
2422
2469
|
const context = (0, import_indicators2.buildDerivativesContext)({
|
|
2423
2470
|
symbol: targetSymbol,
|
|
@@ -2448,6 +2495,9 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
2448
2495
|
(0, import_strategies3.refreshSignalBaseContextGateFeatures)(signal);
|
|
2449
2496
|
return true;
|
|
2450
2497
|
} catch (error) {
|
|
2498
|
+
if (isMarketContextCancellationError(error, params.abortSignal)) {
|
|
2499
|
+
throw error;
|
|
2500
|
+
}
|
|
2451
2501
|
derivativesContextUnavailable = true;
|
|
2452
2502
|
import_logger5.logger.warn(
|
|
2453
2503
|
"Derivatives context disabled after Timescale read failure: %s",
|
|
@@ -2681,7 +2731,7 @@ var resolveHyperliquidPerpFromSignalSymbol = (symbol) => {
|
|
|
2681
2731
|
var MAX_CACHE_ENTRIES = 2048;
|
|
2682
2732
|
var MAX_COVERAGE_SERIES_CACHE_ENTRIES = 20;
|
|
2683
2733
|
var MAX_FLOW_SERIES_CACHE_ENTRIES = 64;
|
|
2684
|
-
var SERIES_CHUNK_MS =
|
|
2734
|
+
var SERIES_CHUNK_MS = 90 * 24 * 60 * 6e4;
|
|
2685
2735
|
var MAX_SERIES_LOOKBACK_MS = 60 * 6e4;
|
|
2686
2736
|
var DEFAULT_MIN_COVERAGE_PCT = 0.8;
|
|
2687
2737
|
var INTERVAL_MS = {
|
|
@@ -2729,6 +2779,7 @@ var setBoundedCache = (key, value) => {
|
|
|
2729
2779
|
if (oldestKey != null) contextCache.delete(oldestKey);
|
|
2730
2780
|
}
|
|
2731
2781
|
contextCache.set(key, value);
|
|
2782
|
+
void value.catch(() => contextCache.delete(key));
|
|
2732
2783
|
};
|
|
2733
2784
|
var setBoundedSeriesCache = (cache, maxEntries, key, value) => {
|
|
2734
2785
|
if (cache.size >= maxEntries) {
|
|
@@ -2736,6 +2787,7 @@ var setBoundedSeriesCache = (cache, maxEntries, key, value) => {
|
|
|
2736
2787
|
if (oldestKey != null) cache.delete(oldestKey);
|
|
2737
2788
|
}
|
|
2738
2789
|
cache.set(key, value);
|
|
2790
|
+
void value.catch(() => cache.delete(key));
|
|
2739
2791
|
};
|
|
2740
2792
|
var uniqueAddressCount = (rows, field) => {
|
|
2741
2793
|
const addresses = /* @__PURE__ */ new Set();
|
|
@@ -2850,7 +2902,8 @@ var loadHyperliquidWhaleFlowAggregateFromSeries = async (params) => {
|
|
|
2850
2902
|
fromMs,
|
|
2851
2903
|
toMs,
|
|
2852
2904
|
universeFingerprint: params.universeFingerprint,
|
|
2853
|
-
whaleRegistryFingerprint: params.whaleRegistryFingerprint
|
|
2905
|
+
whaleRegistryFingerprint: params.whaleRegistryFingerprint,
|
|
2906
|
+
...params.abortSignal ? { signal: params.abortSignal } : {}
|
|
2854
2907
|
});
|
|
2855
2908
|
setBoundedSeriesCache(
|
|
2856
2909
|
coverageSeriesCache,
|
|
@@ -2867,7 +2920,8 @@ var loadHyperliquidWhaleFlowAggregateFromSeries = async (params) => {
|
|
|
2867
2920
|
fromMs,
|
|
2868
2921
|
toMs,
|
|
2869
2922
|
universeFingerprint: params.universeFingerprint,
|
|
2870
|
-
whaleRegistryFingerprint: params.whaleRegistryFingerprint
|
|
2923
|
+
whaleRegistryFingerprint: params.whaleRegistryFingerprint,
|
|
2924
|
+
...params.abortSignal ? { signal: params.abortSignal } : {}
|
|
2871
2925
|
});
|
|
2872
2926
|
setBoundedSeriesCache(
|
|
2873
2927
|
flowSeriesCache,
|
|
@@ -2951,7 +3005,8 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
2951
3005
|
decisionTimeMs,
|
|
2952
3006
|
maxAgeMs,
|
|
2953
3007
|
universeFingerprint: universe.fingerprint,
|
|
2954
|
-
whaleRegistryFingerprint: whales.fingerprint
|
|
3008
|
+
whaleRegistryFingerprint: whales.fingerprint,
|
|
3009
|
+
abortSignal: params.abortSignal
|
|
2955
3010
|
});
|
|
2956
3011
|
} else {
|
|
2957
3012
|
let pending = contextCache.get(cacheKey);
|
|
@@ -2962,7 +3017,8 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
2962
3017
|
decisionTimeMs,
|
|
2963
3018
|
maxAgeMs,
|
|
2964
3019
|
universeFingerprint: universe.fingerprint,
|
|
2965
|
-
whaleRegistryFingerprint: whales.fingerprint
|
|
3020
|
+
whaleRegistryFingerprint: whales.fingerprint,
|
|
3021
|
+
...params.abortSignal ? { signal: params.abortSignal } : {}
|
|
2966
3022
|
});
|
|
2967
3023
|
setBoundedCache(cacheKey, pending);
|
|
2968
3024
|
}
|
|
@@ -2971,6 +3027,9 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
2971
3027
|
if (!row) return null;
|
|
2972
3028
|
return toBaseHyperliquidWhaleFlowContext(row, minimumCoveragePct);
|
|
2973
3029
|
} catch (error) {
|
|
3030
|
+
if (isMarketContextCancellationError(error, params.abortSignal)) {
|
|
3031
|
+
throw error;
|
|
3032
|
+
}
|
|
2974
3033
|
hyperliquidWhaleContextUnavailable = true;
|
|
2975
3034
|
import_logger6.logger.warn(
|
|
2976
3035
|
"Hyperliquid whale context disabled after Timescale read failure: %s",
|
|
@@ -2991,7 +3050,8 @@ var enrichSignalWithHyperliquidWhaleContext = async (params) => {
|
|
|
2991
3050
|
env,
|
|
2992
3051
|
enabled: params.enabled,
|
|
2993
3052
|
marketInterval: params.interval,
|
|
2994
|
-
maxAgeMs: params.maxAgeMs
|
|
3053
|
+
maxAgeMs: params.maxAgeMs,
|
|
3054
|
+
abortSignal: params.abortSignal
|
|
2995
3055
|
});
|
|
2996
3056
|
if (!hyperliquidWhales) return false;
|
|
2997
3057
|
const baseContext = signal.additionalIndicators.baseContext;
|
|
@@ -3009,6 +3069,125 @@ var enrichSignalWithHyperliquidWhaleContext = async (params) => {
|
|
|
3009
3069
|
return true;
|
|
3010
3070
|
};
|
|
3011
3071
|
|
|
3072
|
+
// src/strategyHelpers/marketContextStages.ts
|
|
3073
|
+
var STAGE_ENV_KEYS = {
|
|
3074
|
+
binance: "BINANCE_MARKET_CONTEXT_STAGE_TIMEOUT_MS",
|
|
3075
|
+
coinmarketcap: "COINMARKETCAP_CONTEXT_STAGE_TIMEOUT_MS",
|
|
3076
|
+
derivatives: "DERIVATIVES_CONTEXT_STAGE_TIMEOUT_MS",
|
|
3077
|
+
hyperliquidWhales: "HYPERLIQUID_WHALE_CONTEXT_STAGE_TIMEOUT_MS"
|
|
3078
|
+
};
|
|
3079
|
+
var parsePositiveInt = (value) => {
|
|
3080
|
+
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
3081
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
3082
|
+
};
|
|
3083
|
+
var resolveMarketContextStageTimeoutMs = (stage) => parsePositiveInt(process.env[STAGE_ENV_KEYS[stage]]) ?? parsePositiveInt(process.env.MARKET_CONTEXT_STAGE_TIMEOUT_MS) ?? 35e3;
|
|
3084
|
+
var runMarketContextStage = async ({
|
|
3085
|
+
stage,
|
|
3086
|
+
parentSignal,
|
|
3087
|
+
operation,
|
|
3088
|
+
onStart,
|
|
3089
|
+
onComplete
|
|
3090
|
+
}) => {
|
|
3091
|
+
const controller = new AbortController();
|
|
3092
|
+
const timeoutMs = resolveMarketContextStageTimeoutMs(stage);
|
|
3093
|
+
const startedAt = Date.now();
|
|
3094
|
+
const onParentAbort = () => controller.abort(parentSignal?.reason);
|
|
3095
|
+
parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
3096
|
+
if (parentSignal?.aborted) onParentAbort();
|
|
3097
|
+
onStart?.(stage);
|
|
3098
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3099
|
+
timer.unref?.();
|
|
3100
|
+
try {
|
|
3101
|
+
let available = false;
|
|
3102
|
+
try {
|
|
3103
|
+
available = await operation(controller.signal);
|
|
3104
|
+
} catch (error) {
|
|
3105
|
+
if (isMarketContextCancellationError(error)) {
|
|
3106
|
+
controller.abort(error);
|
|
3107
|
+
}
|
|
3108
|
+
if (!controller.signal.aborted) throw error;
|
|
3109
|
+
}
|
|
3110
|
+
const status = controller.signal.aborted ? "timed_out" : available ? "available" : "absent";
|
|
3111
|
+
const result = {
|
|
3112
|
+
stage,
|
|
3113
|
+
status,
|
|
3114
|
+
elapsedMs: Date.now() - startedAt
|
|
3115
|
+
};
|
|
3116
|
+
if (status === "timed_out") {
|
|
3117
|
+
import_logger7.logger.warn(
|
|
3118
|
+
"Market context stage timed out: %s after %sms",
|
|
3119
|
+
stage,
|
|
3120
|
+
result.elapsedMs
|
|
3121
|
+
);
|
|
3122
|
+
}
|
|
3123
|
+
onComplete?.(result);
|
|
3124
|
+
return result;
|
|
3125
|
+
} finally {
|
|
3126
|
+
clearTimeout(timer);
|
|
3127
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
3128
|
+
}
|
|
3129
|
+
};
|
|
3130
|
+
var enrichSignalWithMarketContextStages = async ({
|
|
3131
|
+
signal,
|
|
3132
|
+
env,
|
|
3133
|
+
coinMarketCapEnabled,
|
|
3134
|
+
includeHyperliquidWhales = true,
|
|
3135
|
+
abortSignal,
|
|
3136
|
+
onStageStart,
|
|
3137
|
+
onStageComplete
|
|
3138
|
+
}) => {
|
|
3139
|
+
const stages = [
|
|
3140
|
+
{
|
|
3141
|
+
stage: "binance",
|
|
3142
|
+
operation: (stageSignal) => enrichSignalWithBinanceMarketContext({
|
|
3143
|
+
signal,
|
|
3144
|
+
env,
|
|
3145
|
+
abortSignal: stageSignal
|
|
3146
|
+
})
|
|
3147
|
+
},
|
|
3148
|
+
{
|
|
3149
|
+
stage: "coinmarketcap",
|
|
3150
|
+
operation: (stageSignal) => enrichSignalWithCoinMarketCapContext({
|
|
3151
|
+
signal,
|
|
3152
|
+
env,
|
|
3153
|
+
enabled: coinMarketCapEnabled,
|
|
3154
|
+
abortSignal: stageSignal
|
|
3155
|
+
})
|
|
3156
|
+
},
|
|
3157
|
+
{
|
|
3158
|
+
stage: "derivatives",
|
|
3159
|
+
operation: (stageSignal) => enrichSignalWithDerivativesContext({
|
|
3160
|
+
signal,
|
|
3161
|
+
env,
|
|
3162
|
+
abortSignal: stageSignal
|
|
3163
|
+
})
|
|
3164
|
+
}
|
|
3165
|
+
];
|
|
3166
|
+
if (includeHyperliquidWhales) {
|
|
3167
|
+
stages.push({
|
|
3168
|
+
stage: "hyperliquidWhales",
|
|
3169
|
+
operation: (stageSignal) => enrichSignalWithHyperliquidWhaleContext({
|
|
3170
|
+
signal,
|
|
3171
|
+
env,
|
|
3172
|
+
abortSignal: stageSignal
|
|
3173
|
+
})
|
|
3174
|
+
});
|
|
3175
|
+
}
|
|
3176
|
+
const results = [];
|
|
3177
|
+
for (const stage of stages) {
|
|
3178
|
+
if (abortSignal?.aborted) break;
|
|
3179
|
+
results.push(
|
|
3180
|
+
await runMarketContextStage({
|
|
3181
|
+
...stage,
|
|
3182
|
+
parentSignal: abortSignal,
|
|
3183
|
+
onStart: onStageStart,
|
|
3184
|
+
onComplete: onStageComplete
|
|
3185
|
+
})
|
|
3186
|
+
);
|
|
3187
|
+
}
|
|
3188
|
+
return results;
|
|
3189
|
+
};
|
|
3190
|
+
|
|
3012
3191
|
// src/strategyAdapters/ml.ts
|
|
3013
3192
|
var defaultMlAdapter = {
|
|
3014
3193
|
normalizeStrategyConfig: (strategyConfig) => strategyConfig
|
|
@@ -3058,7 +3237,7 @@ var buildMlPayload = (payload) => {
|
|
|
3058
3237
|
};
|
|
3059
3238
|
|
|
3060
3239
|
// src/connectorsRegistry.ts
|
|
3061
|
-
var
|
|
3240
|
+
var import_logger8 = require("@tradejs/infra/logger");
|
|
3062
3241
|
var createConnectorRegistryState = () => ({
|
|
3063
3242
|
connectorCreators: /* @__PURE__ */ new Map(),
|
|
3064
3243
|
providerToConnectorName: /* @__PURE__ */ new Map(),
|
|
@@ -3110,7 +3289,7 @@ var normalizeProviders = (providers, connectorName) => {
|
|
|
3110
3289
|
var registerProvider = (provider, connectorName, source, providerToConnectorName) => {
|
|
3111
3290
|
const existing = providerToConnectorName.get(provider);
|
|
3112
3291
|
if (existing && existing !== connectorName) {
|
|
3113
|
-
|
|
3292
|
+
import_logger8.logger.warn(
|
|
3114
3293
|
'Skip duplicate connector provider "%s" from %s: already mapped to %s',
|
|
3115
3294
|
provider,
|
|
3116
3295
|
source,
|
|
@@ -3123,11 +3302,11 @@ var registerProvider = (provider, connectorName, source, providerToConnectorName
|
|
|
3123
3302
|
var registerEntry = (entry, source, state) => {
|
|
3124
3303
|
const connectorName = String(entry?.name ?? "").trim();
|
|
3125
3304
|
if (!connectorName) {
|
|
3126
|
-
|
|
3305
|
+
import_logger8.logger.warn("Skip connector entry without name from %s", source);
|
|
3127
3306
|
return;
|
|
3128
3307
|
}
|
|
3129
3308
|
if (typeof entry.creator !== "function") {
|
|
3130
|
-
|
|
3309
|
+
import_logger8.logger.warn(
|
|
3131
3310
|
'Skip connector entry "%s" from %s: creator must be a function',
|
|
3132
3311
|
connectorName,
|
|
3133
3312
|
source
|
|
@@ -3139,7 +3318,7 @@ var registerEntry = (entry, source, state) => {
|
|
|
3139
3318
|
state.connectorCreators
|
|
3140
3319
|
);
|
|
3141
3320
|
if (existingByName) {
|
|
3142
|
-
|
|
3321
|
+
import_logger8.logger.warn(
|
|
3143
3322
|
'Skip duplicate connector "%s" from %s: already registered as %s',
|
|
3144
3323
|
connectorName,
|
|
3145
3324
|
source,
|
|
@@ -3211,7 +3390,7 @@ var ensureConnectorPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
|
|
|
3211
3390
|
);
|
|
3212
3391
|
const pluginDefinition = extractConnectorPluginDefinition(moduleExport);
|
|
3213
3392
|
if (!pluginDefinition) {
|
|
3214
|
-
|
|
3393
|
+
import_logger8.logger.warn(
|
|
3215
3394
|
'Skip connector plugin "%s": export { connectorEntries } is missing',
|
|
3216
3395
|
moduleName
|
|
3217
3396
|
);
|
|
@@ -3219,7 +3398,7 @@ var ensureConnectorPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
|
|
|
3219
3398
|
}
|
|
3220
3399
|
registerEntries2(pluginDefinition.connectorEntries, moduleName, state);
|
|
3221
3400
|
} catch (error) {
|
|
3222
|
-
|
|
3401
|
+
import_logger8.logger.warn(
|
|
3223
3402
|
'Failed to load connector plugin "%s": %s',
|
|
3224
3403
|
moduleName,
|
|
3225
3404
|
String(error)
|
|
@@ -4692,7 +4871,7 @@ var prepareTestingData = async (params) => {
|
|
|
4692
4871
|
throw new Error(`Unknown connector: ${connectorName}`);
|
|
4693
4872
|
}
|
|
4694
4873
|
if (!binanceConnector || !coinbaseConnector) {
|
|
4695
|
-
|
|
4874
|
+
import_logger9.logger.warn(
|
|
4696
4875
|
"Binance/Coinbase connectors are unavailable. Reusing %s for BTC references.",
|
|
4697
4876
|
connectorName
|
|
4698
4877
|
);
|
|
@@ -5257,35 +5436,15 @@ var testing = async ({
|
|
|
5257
5436
|
}
|
|
5258
5437
|
const shouldCapturePayload = signal && typeof signal !== "string" && signal.signalId && (ml || ai);
|
|
5259
5438
|
if (shouldCapturePayload) {
|
|
5260
|
-
await
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
enrichSignalWithCoinMarketCapContext({
|
|
5270
|
-
signal,
|
|
5271
|
-
env: "BACKTEST",
|
|
5272
|
-
enabled: Boolean(ml || ai)
|
|
5273
|
-
})
|
|
5274
|
-
);
|
|
5275
|
-
await withTimeout(
|
|
5276
|
-
"derivatives context",
|
|
5277
|
-
enrichSignalWithDerivativesContext({
|
|
5278
|
-
signal,
|
|
5279
|
-
env: "BACKTEST"
|
|
5280
|
-
})
|
|
5281
|
-
);
|
|
5282
|
-
await withTimeout(
|
|
5283
|
-
"hyperliquid whale context",
|
|
5284
|
-
enrichSignalWithHyperliquidWhaleContext({
|
|
5285
|
-
signal,
|
|
5286
|
-
env: "BACKTEST"
|
|
5287
|
-
})
|
|
5288
|
-
);
|
|
5439
|
+
await enrichSignalWithMarketContextStages({
|
|
5440
|
+
signal,
|
|
5441
|
+
env: "BACKTEST",
|
|
5442
|
+
coinMarketCapEnabled: true,
|
|
5443
|
+
onStageStart: (stage) => {
|
|
5444
|
+
activeStageStartedAt = Date.now();
|
|
5445
|
+
emitProgress(`${stage} context`, { force: true });
|
|
5446
|
+
}
|
|
5447
|
+
});
|
|
5289
5448
|
}
|
|
5290
5449
|
if (ml && signal && typeof signal !== "string" && signal.signalId) {
|
|
5291
5450
|
const payload = buildMlPayload({
|
|
@@ -5689,35 +5848,15 @@ var testingGroupInSharedCandleLoop = async (tests) => {
|
|
|
5689
5848
|
}
|
|
5690
5849
|
const shouldCapturePayload = signal && typeof signal !== "string" && signal.signalId && (test.ml || test.ai);
|
|
5691
5850
|
if (shouldCapturePayload) {
|
|
5692
|
-
await
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
enrichSignalWithCoinMarketCapContext({
|
|
5702
|
-
signal,
|
|
5703
|
-
env: "BACKTEST",
|
|
5704
|
-
enabled: Boolean(test.ml || test.ai)
|
|
5705
|
-
})
|
|
5706
|
-
);
|
|
5707
|
-
await withTimeout(
|
|
5708
|
-
"derivatives context",
|
|
5709
|
-
enrichSignalWithDerivativesContext({
|
|
5710
|
-
signal,
|
|
5711
|
-
env: "BACKTEST"
|
|
5712
|
-
})
|
|
5713
|
-
);
|
|
5714
|
-
await withTimeout(
|
|
5715
|
-
"hyperliquid whale context",
|
|
5716
|
-
enrichSignalWithHyperliquidWhaleContext({
|
|
5717
|
-
signal,
|
|
5718
|
-
env: "BACKTEST"
|
|
5719
|
-
})
|
|
5720
|
-
);
|
|
5851
|
+
await enrichSignalWithMarketContextStages({
|
|
5852
|
+
signal,
|
|
5853
|
+
env: "BACKTEST",
|
|
5854
|
+
coinMarketCapEnabled: true,
|
|
5855
|
+
onStageStart: (stage) => {
|
|
5856
|
+
activeStageStartedAt = Date.now();
|
|
5857
|
+
emitProgress(`${stage} context`, { force: true });
|
|
5858
|
+
}
|
|
5859
|
+
});
|
|
5721
5860
|
}
|
|
5722
5861
|
if (test.ml && signal && typeof signal !== "string" && signal.signalId) {
|
|
5723
5862
|
const payload = buildMlPayload({
|