@tradejs/node 3.1.27 → 3.1.28-beta.251
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 +1 -0
- package/dist/ai.mjs +1 -1
- package/dist/backtest.d.mts +3 -1
- package/dist/backtest.d.ts +3 -1
- package/dist/backtest.js +287 -39
- package/dist/backtest.mjs +30 -16
- package/dist/{chunk-NQO2MFP6.mjs → chunk-K2YQ3MQC.mjs} +58 -10
- package/dist/{chunk-FB5NUEOQ.mjs → chunk-OFVUEYUR.mjs} +4 -1
- package/dist/{chunk-IKRSNRP6.mjs → chunk-UITD6LG6.mjs} +83 -4
- package/dist/{chunk-XHNJ757K.mjs → chunk-VQSGH7YA.mjs} +341 -22
- package/dist/cli.js +2 -1
- package/dist/cli.mjs +1 -1
- package/dist/{registry-DHTLjQcr.d.mts → registry-3TsO1Ff1.d.mts} +2 -2
- package/dist/{registry-DHTLjQcr.d.ts → registry-3TsO1Ff1.d.ts} +2 -2
- package/dist/registry.d.mts +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/registry.js +260 -23
- package/dist/registry.mjs +2 -2
- package/dist/runtimeDashboard.js +378 -37
- package/dist/runtimeDashboard.mjs +54 -8
- package/dist/runtimeStrategies.d.mts +4 -1
- package/dist/runtimeStrategies.d.ts +4 -1
- package/dist/runtimeStrategies.js +327 -34
- package/dist/runtimeStrategies.mjs +3 -3
- package/dist/runtimeTrades.d.mts +2 -1
- package/dist/runtimeTrades.d.ts +2 -1
- package/dist/runtimeTrades.js +4 -1
- package/dist/runtimeTrades.mjs +1 -1
- package/dist/strategies.d.mts +14 -2
- package/dist/strategies.d.ts +14 -2
- package/dist/strategies.js +417 -24
- package/dist/strategies.mjs +4 -2
- package/package.json +5 -5
package/dist/runtimeDashboard.js
CHANGED
|
@@ -1006,7 +1006,8 @@ var buildExchangeFallbackRuntimeTrades = ({
|
|
|
1006
1006
|
openPositions,
|
|
1007
1007
|
strategyNames,
|
|
1008
1008
|
existingTrades,
|
|
1009
|
-
endTime
|
|
1009
|
+
endTime,
|
|
1010
|
+
scope
|
|
1010
1011
|
}) => {
|
|
1011
1012
|
if (!entryRows.length && !closedPnlRows.length) return [];
|
|
1012
1013
|
const strategyNameByOrderId = new Map(
|
|
@@ -1061,6 +1062,7 @@ var buildExchangeFallbackRuntimeTrades = ({
|
|
|
1061
1062
|
const entryPrice = typeof entry.entryPrice === "number" && Number.isFinite(entry.entryPrice) ? entry.entryPrice : typeof closed?.entryPrice === "number" && Number.isFinite(closed.entryPrice) ? closed.entryPrice : null;
|
|
1062
1063
|
if (entryPrice == null) return null;
|
|
1063
1064
|
return {
|
|
1065
|
+
...scope,
|
|
1064
1066
|
orderId: runtimeOrderId,
|
|
1065
1067
|
strategy,
|
|
1066
1068
|
symbol: entry.symbol,
|
|
@@ -1103,6 +1105,7 @@ var buildExchangeFallbackRuntimeTrades = ({
|
|
|
1103
1105
|
return null;
|
|
1104
1106
|
}
|
|
1105
1107
|
return {
|
|
1108
|
+
...scope,
|
|
1106
1109
|
orderId: runtimeOrderId,
|
|
1107
1110
|
strategy,
|
|
1108
1111
|
symbol: row.symbol,
|
|
@@ -1933,6 +1936,7 @@ var createStrategyRegistryState = () => ({
|
|
|
1933
1936
|
strategyManifestsMap: /* @__PURE__ */ new Map(),
|
|
1934
1937
|
strategyEntriesMap: /* @__PURE__ */ new Map(),
|
|
1935
1938
|
strategySourcesMap: /* @__PURE__ */ new Map(),
|
|
1939
|
+
strategyModuleResolutions: /* @__PURE__ */ new Map(),
|
|
1936
1940
|
pluginsLoadPromise: null
|
|
1937
1941
|
});
|
|
1938
1942
|
var registryStateByProjectRoot2 = sharedStrategyRegistry.registryStateByProjectRoot;
|
|
@@ -1994,7 +1998,7 @@ var validateStrategyEntries = (moduleName, entries, state) => {
|
|
|
1994
1998
|
const strategyName = entry?.manifest?.name;
|
|
1995
1999
|
if (typeof strategyName !== "string" || !strategyName.trim()) {
|
|
1996
2000
|
issues.push(`${entryPath}: manifest.name is required`);
|
|
1997
|
-
} else if (names.has(strategyName) || state
|
|
2001
|
+
} else if (names.has(strategyName) || state?.strategyEntriesMap.has(strategyName)) {
|
|
1998
2002
|
issues.push(`${entryPath}: duplicate strategy ${strategyName}`);
|
|
1999
2003
|
} else {
|
|
2000
2004
|
names.add(strategyName);
|
|
@@ -2056,6 +2060,72 @@ var importStrategyPluginModule = async (moduleName, cwd = getTradejsProjectCwd()
|
|
|
2056
2060
|
moduleName
|
|
2057
2061
|
);
|
|
2058
2062
|
};
|
|
2063
|
+
var resolveStrategyModuleEntry = async ({
|
|
2064
|
+
strategyName,
|
|
2065
|
+
moduleName,
|
|
2066
|
+
cwd
|
|
2067
|
+
}) => {
|
|
2068
|
+
const { projectRoot, state } = getStrategyRegistryState(cwd);
|
|
2069
|
+
const source = moduleName.trim();
|
|
2070
|
+
const resolvedModuleName = resolvePluginModuleSpecifier(source, projectRoot);
|
|
2071
|
+
const cacheKey = `${resolvedModuleName}\0${strategyName}`;
|
|
2072
|
+
const cached = state.strategyModuleResolutions.get(cacheKey);
|
|
2073
|
+
if (cached) return cached;
|
|
2074
|
+
const resolution = (async () => {
|
|
2075
|
+
const moduleExport = await importStrategyPluginModule(
|
|
2076
|
+
resolvedModuleName,
|
|
2077
|
+
projectRoot
|
|
2078
|
+
);
|
|
2079
|
+
const pluginDefinition = extractStrategyPluginDefinition(moduleExport);
|
|
2080
|
+
if (!pluginDefinition) {
|
|
2081
|
+
throw new Error(`${source}: export { strategyEntries } is missing`);
|
|
2082
|
+
}
|
|
2083
|
+
const issues = validateStrategyEntries(
|
|
2084
|
+
source,
|
|
2085
|
+
pluginDefinition.strategyEntries
|
|
2086
|
+
);
|
|
2087
|
+
if (issues.length > 0) {
|
|
2088
|
+
throw new Error(
|
|
2089
|
+
["Invalid TradeJS strategy module:", ...issues].join("\n")
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
const entry = pluginDefinition.strategyEntries.find(
|
|
2093
|
+
(candidate) => candidate.manifest.name === strategyName
|
|
2094
|
+
);
|
|
2095
|
+
if (!entry) {
|
|
2096
|
+
throw new Error(`${source}: strategy ${strategyName} is missing`);
|
|
2097
|
+
}
|
|
2098
|
+
const factory = sharedStrategyRegistry.strategyRuntimeFactory;
|
|
2099
|
+
if (!factory) {
|
|
2100
|
+
throw new Error("Strategy runtime factory is not configured");
|
|
2101
|
+
}
|
|
2102
|
+
const manifestsByName = new Map(
|
|
2103
|
+
pluginDefinition.strategyEntries.map(
|
|
2104
|
+
(candidate) => [candidate.manifest.name, candidate.manifest]
|
|
2105
|
+
)
|
|
2106
|
+
);
|
|
2107
|
+
return {
|
|
2108
|
+
entry,
|
|
2109
|
+
creator: factory({
|
|
2110
|
+
strategyName,
|
|
2111
|
+
defaults: entry.defaults,
|
|
2112
|
+
createCore: entry.createCore,
|
|
2113
|
+
manifest: entry.manifest,
|
|
2114
|
+
detectorKey: entry.detectorKey,
|
|
2115
|
+
detectorNoSignalSkipReason: entry.detectorNoSignalSkipReason,
|
|
2116
|
+
resolveRegisteredManifest: (name) => manifestsByName.get(name) ?? state.strategyManifestsMap.get(name)
|
|
2117
|
+
}),
|
|
2118
|
+
source
|
|
2119
|
+
};
|
|
2120
|
+
})();
|
|
2121
|
+
state.strategyModuleResolutions.set(cacheKey, resolution);
|
|
2122
|
+
try {
|
|
2123
|
+
return await resolution;
|
|
2124
|
+
} catch (error) {
|
|
2125
|
+
state.strategyModuleResolutions.delete(cacheKey);
|
|
2126
|
+
throw error;
|
|
2127
|
+
}
|
|
2128
|
+
};
|
|
2059
2129
|
var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
|
|
2060
2130
|
const { projectRoot, state } = getStrategyRegistryState(cwd);
|
|
2061
2131
|
if (!state.pluginsLoadPromise) {
|
|
@@ -2133,17 +2203,29 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
|
|
|
2133
2203
|
}
|
|
2134
2204
|
await state.pluginsLoadPromise;
|
|
2135
2205
|
};
|
|
2136
|
-
var getStrategyCreator = async (name, cwd = getTradejsProjectCwd()) => {
|
|
2206
|
+
var getStrategyCreator = async (name, cwd = getTradejsProjectCwd(), moduleName) => {
|
|
2207
|
+
if (moduleName?.trim()) {
|
|
2208
|
+
await ensureStrategyPluginsLoaded(cwd);
|
|
2209
|
+
return (await resolveStrategyModuleEntry({ strategyName: name, moduleName, cwd })).creator;
|
|
2210
|
+
}
|
|
2137
2211
|
await ensureStrategyPluginsLoaded(cwd);
|
|
2138
2212
|
const { state } = getStrategyRegistryState(cwd);
|
|
2139
2213
|
return state.strategyCreators.get(name);
|
|
2140
2214
|
};
|
|
2141
|
-
var getStrategyEntry = async (name, cwd = getTradejsProjectCwd()) => {
|
|
2215
|
+
var getStrategyEntry = async (name, cwd = getTradejsProjectCwd(), moduleName) => {
|
|
2216
|
+
if (moduleName?.trim()) {
|
|
2217
|
+
await ensureStrategyPluginsLoaded(cwd);
|
|
2218
|
+
return (await resolveStrategyModuleEntry({ strategyName: name, moduleName, cwd })).entry;
|
|
2219
|
+
}
|
|
2142
2220
|
await ensureStrategyPluginsLoaded(cwd);
|
|
2143
2221
|
const { state } = getStrategyRegistryState(cwd);
|
|
2144
2222
|
return state.strategyEntriesMap.get(name);
|
|
2145
2223
|
};
|
|
2146
|
-
var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd()) => {
|
|
2224
|
+
var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd(), moduleName) => {
|
|
2225
|
+
if (moduleName?.trim()) {
|
|
2226
|
+
await ensureStrategyPluginsLoaded(cwd);
|
|
2227
|
+
return (await resolveStrategyModuleEntry({ strategyName: name, moduleName, cwd })).source;
|
|
2228
|
+
}
|
|
2147
2229
|
await ensureStrategyPluginsLoaded(cwd);
|
|
2148
2230
|
const { state } = getStrategyRegistryState(cwd);
|
|
2149
2231
|
return state.strategySourcesMap.get(name);
|
|
@@ -3362,9 +3444,40 @@ var DEFAULT_MAX_AGE_BY_INTERVAL = {
|
|
|
3362
3444
|
"15m": 30 * 6e4,
|
|
3363
3445
|
"1h": 2 * 60 * 6e4
|
|
3364
3446
|
};
|
|
3447
|
+
var MARKET_CONTEXT_PRELOAD_CHUNK_MS = 7 * 24 * 60 * 6e4;
|
|
3365
3448
|
var binanceMarketContextUnavailable = false;
|
|
3366
3449
|
var referenceRowsCache = /* @__PURE__ */ new Map();
|
|
3367
3450
|
var breadthCache = /* @__PURE__ */ new Map();
|
|
3451
|
+
var BREADTH_COMMON_NUMERIC_FIELDS = [
|
|
3452
|
+
"symbolsCount",
|
|
3453
|
+
"advancers",
|
|
3454
|
+
"decliners",
|
|
3455
|
+
"unchanged",
|
|
3456
|
+
"advanceDeclineRatio",
|
|
3457
|
+
"pctAboveMa20",
|
|
3458
|
+
"pctAboveMa50",
|
|
3459
|
+
"equalWeightedReturn",
|
|
3460
|
+
"volumeWeightedReturn",
|
|
3461
|
+
"dispersion"
|
|
3462
|
+
];
|
|
3463
|
+
var BREADTH_REGIME_NUMERIC_FIELDS = [
|
|
3464
|
+
"btcReturn1h",
|
|
3465
|
+
"btcReturn4h",
|
|
3466
|
+
"btcReturn24h",
|
|
3467
|
+
"altBasketReturn1h",
|
|
3468
|
+
"altBasketReturn4h",
|
|
3469
|
+
"altBasketReturn24h",
|
|
3470
|
+
"btcVsAltReturn1h",
|
|
3471
|
+
"btcVsAltReturn4h",
|
|
3472
|
+
"btcVsAltReturn24h",
|
|
3473
|
+
"btcTurnoverShare1h",
|
|
3474
|
+
"btcTurnoverShare24h",
|
|
3475
|
+
"btcTurnoverShareChange24h",
|
|
3476
|
+
"altVolToBtcVol24h",
|
|
3477
|
+
"altDispersion24h"
|
|
3478
|
+
];
|
|
3479
|
+
var preloadedTradeFlowBySymbol = null;
|
|
3480
|
+
var preloadedBreadthByUniverse = null;
|
|
3368
3481
|
var parseEnabledFlag = (value, env) => {
|
|
3369
3482
|
const normalized = String(value ?? "").trim().toLowerCase();
|
|
3370
3483
|
if (!normalized)
|
|
@@ -3400,6 +3513,100 @@ var hasBaseContext = (signal) => Boolean(
|
|
|
3400
3513
|
signal.additionalIndicators?.baseContext && typeof signal.additionalIndicators.baseContext === "object" && !Array.isArray(signal.additionalIndicators.baseContext)
|
|
3401
3514
|
);
|
|
3402
3515
|
var isBinanceMarketContextEnabled = (env) => parseEnabledFlag(process.env.BINANCE_MARKET_CONTEXT_ENABLED, env);
|
|
3516
|
+
var latestIndexAtOrBefore = (timestamps, timestamp) => {
|
|
3517
|
+
if (!timestamps?.length) return -1;
|
|
3518
|
+
let low = 0;
|
|
3519
|
+
let high = timestamps.length - 1;
|
|
3520
|
+
let match = -1;
|
|
3521
|
+
while (low <= high) {
|
|
3522
|
+
const middle = Math.floor((low + high) / 2);
|
|
3523
|
+
const rowTimestamp = timestamps[middle];
|
|
3524
|
+
if (rowTimestamp == null) break;
|
|
3525
|
+
if (rowTimestamp <= timestamp) {
|
|
3526
|
+
match = middle;
|
|
3527
|
+
low = middle + 1;
|
|
3528
|
+
} else {
|
|
3529
|
+
high = middle - 1;
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
return match;
|
|
3533
|
+
};
|
|
3534
|
+
var latestChunkAtOrBefore = (chunks, timestamp) => {
|
|
3535
|
+
if (!chunks?.length) return null;
|
|
3536
|
+
let low = 0;
|
|
3537
|
+
let high = chunks.length - 1;
|
|
3538
|
+
let match = null;
|
|
3539
|
+
while (low <= high) {
|
|
3540
|
+
const middle = Math.floor((low + high) / 2);
|
|
3541
|
+
const chunk = chunks[middle];
|
|
3542
|
+
const firstTimestamp = chunk?.timestamps[0];
|
|
3543
|
+
if (!chunk || firstTimestamp == null) break;
|
|
3544
|
+
if (firstTimestamp <= timestamp) {
|
|
3545
|
+
match = chunk;
|
|
3546
|
+
low = middle + 1;
|
|
3547
|
+
} else {
|
|
3548
|
+
high = middle - 1;
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
return match;
|
|
3552
|
+
};
|
|
3553
|
+
var unpackedNumber = (value) => value == null || Number.isNaN(value) ? null : value;
|
|
3554
|
+
var unpackTradeFlowRow = (chunks, timestamp) => {
|
|
3555
|
+
const rows = latestChunkAtOrBefore(chunks, timestamp);
|
|
3556
|
+
const index = latestIndexAtOrBefore(rows?.timestamps, timestamp);
|
|
3557
|
+
if (!rows || index < 0) return null;
|
|
3558
|
+
return {
|
|
3559
|
+
symbol: rows.symbol,
|
|
3560
|
+
interval: rows.interval,
|
|
3561
|
+
ts: new Date(rows.timestamps[index]),
|
|
3562
|
+
trades: unpackedNumber(rows.columns.trades[index]) ?? 0,
|
|
3563
|
+
buyBaseVolume: unpackedNumber(rows.columns.buyBaseVolume[index]),
|
|
3564
|
+
sellBaseVolume: unpackedNumber(rows.columns.sellBaseVolume[index]),
|
|
3565
|
+
buyQuoteVolume: unpackedNumber(rows.columns.buyQuoteVolume[index]),
|
|
3566
|
+
sellQuoteVolume: unpackedNumber(rows.columns.sellQuoteVolume[index]),
|
|
3567
|
+
netBaseDelta: unpackedNumber(rows.columns.netBaseDelta[index]),
|
|
3568
|
+
netQuoteDelta: unpackedNumber(rows.columns.netQuoteDelta[index]),
|
|
3569
|
+
buyPressurePct: unpackedNumber(rows.columns.buyPressurePct[index])
|
|
3570
|
+
};
|
|
3571
|
+
};
|
|
3572
|
+
var unpackBreadthRow = (chunks, timestamp) => {
|
|
3573
|
+
const rows = latestChunkAtOrBefore(chunks, timestamp);
|
|
3574
|
+
const index = latestIndexAtOrBefore(rows?.timestamps, timestamp);
|
|
3575
|
+
if (!rows || index < 0) return null;
|
|
3576
|
+
const commonNumeric = Object.fromEntries(
|
|
3577
|
+
BREADTH_COMMON_NUMERIC_FIELDS.map((field) => [
|
|
3578
|
+
field,
|
|
3579
|
+
unpackedNumber(rows.commonColumns[field][index])
|
|
3580
|
+
])
|
|
3581
|
+
);
|
|
3582
|
+
const regimeNumeric = Object.fromEntries(
|
|
3583
|
+
BREADTH_REGIME_NUMERIC_FIELDS.map((field) => [
|
|
3584
|
+
field,
|
|
3585
|
+
unpackedNumber(rows.regimeColumns?.[field][index])
|
|
3586
|
+
])
|
|
3587
|
+
);
|
|
3588
|
+
return {
|
|
3589
|
+
universe: rows.universe,
|
|
3590
|
+
interval: rows.interval,
|
|
3591
|
+
ts: new Date(rows.timestamps[index]),
|
|
3592
|
+
...commonNumeric,
|
|
3593
|
+
...regimeNumeric,
|
|
3594
|
+
symbolsCount: commonNumeric.symbolsCount ?? 0,
|
|
3595
|
+
advancers: commonNumeric.advancers ?? 0,
|
|
3596
|
+
decliners: commonNumeric.decliners ?? 0,
|
|
3597
|
+
unchanged: commonNumeric.unchanged ?? 0,
|
|
3598
|
+
btcAltRegime: rows.regimes?.[index] ?? null
|
|
3599
|
+
};
|
|
3600
|
+
};
|
|
3601
|
+
var toAsOfRow = (row, timestamp, maxAgeMs) => {
|
|
3602
|
+
if (!row) return null;
|
|
3603
|
+
const ageMs = timestamp - row.ts.getTime();
|
|
3604
|
+
return {
|
|
3605
|
+
...row,
|
|
3606
|
+
ageMs: Number.isFinite(ageMs) ? ageMs : null,
|
|
3607
|
+
stale: !Number.isFinite(ageMs) || ageMs < 0 || ageMs > maxAgeMs
|
|
3608
|
+
};
|
|
3609
|
+
};
|
|
3403
3610
|
var toTradeFlowContext = (row, interval) => row ? {
|
|
3404
3611
|
source: "binance_agg_trades",
|
|
3405
3612
|
interval,
|
|
@@ -3422,6 +3629,24 @@ var getCachedReferenceRows = ({
|
|
|
3422
3629
|
maxAgeMs,
|
|
3423
3630
|
abortSignal
|
|
3424
3631
|
}) => {
|
|
3632
|
+
if (preloadedTradeFlowBySymbol) {
|
|
3633
|
+
return Promise.resolve(
|
|
3634
|
+
referenceSymbols.map((symbol) => ({
|
|
3635
|
+
symbol,
|
|
3636
|
+
tradeFlow: toTradeFlowContext(
|
|
3637
|
+
toAsOfRow(
|
|
3638
|
+
unpackTradeFlowRow(
|
|
3639
|
+
preloadedTradeFlowBySymbol?.get(symbol),
|
|
3640
|
+
timestamp
|
|
3641
|
+
),
|
|
3642
|
+
timestamp,
|
|
3643
|
+
maxAgeMs
|
|
3644
|
+
),
|
|
3645
|
+
interval
|
|
3646
|
+
)
|
|
3647
|
+
}))
|
|
3648
|
+
);
|
|
3649
|
+
}
|
|
3425
3650
|
const key = `${referenceSymbols.join(",")}:${interval}:${timestamp}:${maxAgeMs}`;
|
|
3426
3651
|
const cached = referenceRowsCache.get(key);
|
|
3427
3652
|
if (cached) return cached;
|
|
@@ -3451,6 +3676,18 @@ var getCachedBreadth = ({
|
|
|
3451
3676
|
maxAgeMs,
|
|
3452
3677
|
abortSignal
|
|
3453
3678
|
}) => {
|
|
3679
|
+
if (preloadedBreadthByUniverse) {
|
|
3680
|
+
return Promise.resolve(
|
|
3681
|
+
toAsOfRow(
|
|
3682
|
+
unpackBreadthRow(
|
|
3683
|
+
preloadedBreadthByUniverse.get(breadthUniverse),
|
|
3684
|
+
timestamp
|
|
3685
|
+
),
|
|
3686
|
+
timestamp,
|
|
3687
|
+
maxAgeMs
|
|
3688
|
+
)
|
|
3689
|
+
);
|
|
3690
|
+
}
|
|
3454
3691
|
const key = `${breadthUniverse}:${interval}:${timestamp}:${maxAgeMs}`;
|
|
3455
3692
|
const cached = breadthCache.get(key);
|
|
3456
3693
|
if (cached) return cached;
|
|
@@ -3657,12 +3894,20 @@ var SOURCE_EXCHANGE_LIQUIDITY = "coinmarketcap_exchange_liquidity";
|
|
|
3657
3894
|
var SOURCE_FEAR_GREED = "coinmarketcap_fear_greed";
|
|
3658
3895
|
var SOURCE_INDEX = "coinmarketcap_index";
|
|
3659
3896
|
var DAY_MS = 864e5;
|
|
3897
|
+
var MAX_TIMESTAMP_CACHE_ENTRIES = 512;
|
|
3660
3898
|
var coinMarketCapContextUnavailable = false;
|
|
3661
3899
|
var globalContextCache = /* @__PURE__ */ new Map();
|
|
3662
3900
|
var referenceContextCache = /* @__PURE__ */ new Map();
|
|
3663
3901
|
var exchangeLiquidityContextCache = /* @__PURE__ */ new Map();
|
|
3664
3902
|
var fearGreedContextCache = /* @__PURE__ */ new Map();
|
|
3665
3903
|
var indexContextCache = /* @__PURE__ */ new Map();
|
|
3904
|
+
var setBoundedCache = (cache, key, value) => {
|
|
3905
|
+
if (cache.size >= MAX_TIMESTAMP_CACHE_ENTRIES) {
|
|
3906
|
+
const oldestKey = cache.keys().next().value;
|
|
3907
|
+
if (oldestKey != null) cache.delete(oldestKey);
|
|
3908
|
+
}
|
|
3909
|
+
cache.set(key, value);
|
|
3910
|
+
};
|
|
3666
3911
|
var parseEnabledFlag2 = (value, env) => {
|
|
3667
3912
|
const normalized = String(value ?? "").trim().toLowerCase();
|
|
3668
3913
|
if (!normalized) {
|
|
@@ -3769,7 +4014,7 @@ var getCachedGlobalContext = ({
|
|
|
3769
4014
|
maxAgeMs,
|
|
3770
4015
|
...abortSignal ? { signal: abortSignal } : {}
|
|
3771
4016
|
});
|
|
3772
|
-
globalContextCache
|
|
4017
|
+
setBoundedCache(globalContextCache, key, promise);
|
|
3773
4018
|
void promise.catch(() => globalContextCache.delete(key));
|
|
3774
4019
|
return promise;
|
|
3775
4020
|
};
|
|
@@ -3789,7 +4034,7 @@ var getCachedReferenceContexts = ({
|
|
|
3789
4034
|
maxAgeMs,
|
|
3790
4035
|
...abortSignal ? { signal: abortSignal } : {}
|
|
3791
4036
|
});
|
|
3792
|
-
referenceContextCache
|
|
4037
|
+
setBoundedCache(referenceContextCache, key, promise);
|
|
3793
4038
|
void promise.catch(() => referenceContextCache.delete(key));
|
|
3794
4039
|
return promise;
|
|
3795
4040
|
};
|
|
@@ -3808,7 +4053,7 @@ var getCachedExchangeLiquidityContext = ({
|
|
|
3808
4053
|
maxAgeMs,
|
|
3809
4054
|
...abortSignal ? { signal: abortSignal } : {}
|
|
3810
4055
|
});
|
|
3811
|
-
exchangeLiquidityContextCache
|
|
4056
|
+
setBoundedCache(exchangeLiquidityContextCache, key, promise);
|
|
3812
4057
|
void promise.catch(() => exchangeLiquidityContextCache.delete(key));
|
|
3813
4058
|
return promise;
|
|
3814
4059
|
};
|
|
@@ -3827,7 +4072,7 @@ var getCachedFearGreedContext = ({
|
|
|
3827
4072
|
maxAgeMs,
|
|
3828
4073
|
...abortSignal ? { signal: abortSignal } : {}
|
|
3829
4074
|
});
|
|
3830
|
-
fearGreedContextCache
|
|
4075
|
+
setBoundedCache(fearGreedContextCache, key, promise);
|
|
3831
4076
|
void promise.catch(() => fearGreedContextCache.delete(key));
|
|
3832
4077
|
return promise;
|
|
3833
4078
|
};
|
|
@@ -3847,7 +4092,7 @@ var getCachedIndexContexts = ({
|
|
|
3847
4092
|
maxAgeMs,
|
|
3848
4093
|
...abortSignal ? { signal: abortSignal } : {}
|
|
3849
4094
|
});
|
|
3850
|
-
indexContextCache
|
|
4095
|
+
setBoundedCache(indexContextCache, key, promise);
|
|
3851
4096
|
void promise.catch(() => indexContextCache.delete(key));
|
|
3852
4097
|
return promise;
|
|
3853
4098
|
};
|
|
@@ -4657,7 +4902,7 @@ var signalIntervalToMarketInterval2 = (value) => {
|
|
|
4657
4902
|
var hasBaseContext3 = (signal) => Boolean(
|
|
4658
4903
|
signal.additionalIndicators?.baseContext && typeof signal.additionalIndicators.baseContext === "object" && !Array.isArray(signal.additionalIndicators.baseContext)
|
|
4659
4904
|
);
|
|
4660
|
-
var
|
|
4905
|
+
var setBoundedCache2 = (key, value) => {
|
|
4661
4906
|
if (contextCache.size >= MAX_CACHE_ENTRIES) {
|
|
4662
4907
|
const oldestKey = contextCache.keys().next().value;
|
|
4663
4908
|
if (oldestKey != null) contextCache.delete(oldestKey);
|
|
@@ -4904,7 +5149,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
|
|
|
4904
5149
|
whaleRegistryFingerprint: whales.fingerprint,
|
|
4905
5150
|
...params.abortSignal ? { signal: params.abortSignal } : {}
|
|
4906
5151
|
});
|
|
4907
|
-
|
|
5152
|
+
setBoundedCache2(cacheKey, pending);
|
|
4908
5153
|
}
|
|
4909
5154
|
row = await pending;
|
|
4910
5155
|
}
|
|
@@ -6039,20 +6284,23 @@ var buildHookCtx = ({
|
|
|
6039
6284
|
strategyConfig,
|
|
6040
6285
|
env,
|
|
6041
6286
|
isConfigFromBacktest
|
|
6042
|
-
}) =>
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6287
|
+
}) => {
|
|
6288
|
+
const context = {
|
|
6289
|
+
connector,
|
|
6290
|
+
strategyName,
|
|
6291
|
+
userName,
|
|
6292
|
+
symbol
|
|
6293
|
+
};
|
|
6294
|
+
if (universe) context.universe = universe;
|
|
6295
|
+
if (assetClass) context.assetClass = assetClass;
|
|
6296
|
+
if (accountId) context.accountId = accountId;
|
|
6297
|
+
if (deploymentId) context.deploymentId = deploymentId;
|
|
6298
|
+
if (policyProfileId) context.policyProfileId = policyProfileId;
|
|
6299
|
+
context.strategyConfig = strategyConfig;
|
|
6300
|
+
context.env = env;
|
|
6301
|
+
context.isConfigFromBacktest = isConfigFromBacktest;
|
|
6302
|
+
return context;
|
|
6303
|
+
};
|
|
6056
6304
|
var shouldRecordRuntimeJournal = ({
|
|
6057
6305
|
env,
|
|
6058
6306
|
config
|
|
@@ -7397,7 +7645,13 @@ var DEPLOYMENT_KEYS = /* @__PURE__ */ new Set([
|
|
|
7397
7645
|
"assetClasses",
|
|
7398
7646
|
"tickers"
|
|
7399
7647
|
]);
|
|
7400
|
-
var STRATEGY_KEYS = /* @__PURE__ */ new Set([
|
|
7648
|
+
var STRATEGY_KEYS = /* @__PURE__ */ new Set([
|
|
7649
|
+
"module",
|
|
7650
|
+
"generation",
|
|
7651
|
+
"enabled",
|
|
7652
|
+
"selection",
|
|
7653
|
+
"config"
|
|
7654
|
+
]);
|
|
7401
7655
|
var SELECTION_KEYS = /* @__PURE__ */ new Set(["tickers"]);
|
|
7402
7656
|
var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
7403
7657
|
"ACCOUNT_ID",
|
|
@@ -7469,6 +7723,39 @@ var readRuntimePackageManifest = async (projectRoot) => {
|
|
|
7469
7723
|
}
|
|
7470
7724
|
return value;
|
|
7471
7725
|
};
|
|
7726
|
+
var parseNpmAliasReference = (value) => {
|
|
7727
|
+
if (typeof value !== "string" || !value.startsWith("npm:")) return null;
|
|
7728
|
+
const target = value.slice("npm:".length);
|
|
7729
|
+
const versionSeparator = target.lastIndexOf("@");
|
|
7730
|
+
if (versionSeparator <= 0 || versionSeparator === target.length - 1) {
|
|
7731
|
+
return null;
|
|
7732
|
+
}
|
|
7733
|
+
return {
|
|
7734
|
+
packageName: target.slice(0, versionSeparator),
|
|
7735
|
+
version: target.slice(versionSeparator + 1)
|
|
7736
|
+
};
|
|
7737
|
+
};
|
|
7738
|
+
var verifyInstalledPackageName = async ({
|
|
7739
|
+
projectRoot,
|
|
7740
|
+
packageName,
|
|
7741
|
+
installedName,
|
|
7742
|
+
installedVersion,
|
|
7743
|
+
projectPackage
|
|
7744
|
+
}) => {
|
|
7745
|
+
if (installedName === void 0 || installedName === packageName) return;
|
|
7746
|
+
if (projectPackage || typeof installedName !== "string") {
|
|
7747
|
+
throw new Error("name is invalid");
|
|
7748
|
+
}
|
|
7749
|
+
const projectManifest = JSON.parse(
|
|
7750
|
+
await (0, import_promises.readFile)(import_node_path.default.join(projectRoot, "package.json"), "utf8")
|
|
7751
|
+
);
|
|
7752
|
+
const alias = parseNpmAliasReference(
|
|
7753
|
+
projectManifest.dependencies?.[packageName]
|
|
7754
|
+
);
|
|
7755
|
+
if (alias?.packageName !== installedName || alias.version !== installedVersion) {
|
|
7756
|
+
throw new Error("name or alias target is invalid");
|
|
7757
|
+
}
|
|
7758
|
+
};
|
|
7472
7759
|
var readInstalledPackageMetadata = async ({
|
|
7473
7760
|
projectRoot,
|
|
7474
7761
|
packageName,
|
|
@@ -7482,9 +7769,16 @@ var readInstalledPackageMetadata = async ({
|
|
|
7482
7769
|
);
|
|
7483
7770
|
try {
|
|
7484
7771
|
const packageJson = JSON.parse(await (0, import_promises.readFile)(packageJsonPath, "utf8"));
|
|
7485
|
-
if (
|
|
7486
|
-
throw new Error("
|
|
7772
|
+
if (typeof packageJson.version !== "string" || !packageJson.version.trim()) {
|
|
7773
|
+
throw new Error("version is invalid");
|
|
7487
7774
|
}
|
|
7775
|
+
await verifyInstalledPackageName({
|
|
7776
|
+
projectRoot,
|
|
7777
|
+
packageName,
|
|
7778
|
+
installedName: packageJson.name,
|
|
7779
|
+
installedVersion: packageJson.version,
|
|
7780
|
+
projectPackage
|
|
7781
|
+
});
|
|
7488
7782
|
const dependencyNames = [
|
|
7489
7783
|
...isRecord(packageJson.dependencies) ? Object.keys(packageJson.dependencies) : [],
|
|
7490
7784
|
...isRecord(packageJson.peerDependencies) ? Object.keys(packageJson.peerDependencies) : []
|
|
@@ -7579,7 +7873,7 @@ var verifyDeploymentDeclaration = (deploymentId, value) => {
|
|
|
7579
7873
|
for (const [strategyName, strategyValue] of Object.entries(
|
|
7580
7874
|
value.strategies
|
|
7581
7875
|
)) {
|
|
7582
|
-
if (!strategyName.trim() || !isRecord(strategyValue) || Object.keys(strategyValue).some((key) => !STRATEGY_KEYS.has(key)) || strategyValue.generation !== void 0 && (typeof strategyValue.generation !== "string" || !strategyValue.generation.trim()) || typeof strategyValue.enabled !== "boolean" || !verifyStrategySelection(strategyValue.selection) || !isRecord(strategyValue.config) || Object.keys(strategyValue.config).some(
|
|
7876
|
+
if (!strategyName.trim() || !isRecord(strategyValue) || Object.keys(strategyValue).some((key) => !STRATEGY_KEYS.has(key)) || strategyValue.generation !== void 0 && (typeof strategyValue.generation !== "string" || !strategyValue.generation.trim()) || strategyValue.module !== void 0 && (typeof strategyValue.module !== "string" || !strategyValue.module.trim()) || typeof strategyValue.enabled !== "boolean" || !verifyStrategySelection(strategyValue.selection) || !isRecord(strategyValue.config) || Object.keys(strategyValue.config).some(
|
|
7583
7877
|
(key) => FORBIDDEN_CONFIG_KEYS.has(key)
|
|
7584
7878
|
) || !INTERVALS.has(String(strategyValue.config.INTERVAL)) || !["crypto", "tradfi"].includes(String(strategyValue.config.UNIVERSE))) {
|
|
7585
7879
|
throw new Error(
|
|
@@ -7613,9 +7907,9 @@ var resolveStrategyComposition = async ({
|
|
|
7613
7907
|
packageManifest
|
|
7614
7908
|
}) => {
|
|
7615
7909
|
const [strategyEntry, strategyCreator, pluginSource] = await Promise.all([
|
|
7616
|
-
getStrategyEntry(strategyName, projectRoot),
|
|
7617
|
-
getStrategyCreator(strategyName, projectRoot),
|
|
7618
|
-
getStrategyPluginSource(strategyName, projectRoot)
|
|
7910
|
+
getStrategyEntry(strategyName, projectRoot, declaration.module),
|
|
7911
|
+
getStrategyCreator(strategyName, projectRoot, declaration.module),
|
|
7912
|
+
getStrategyPluginSource(strategyName, projectRoot, declaration.module)
|
|
7619
7913
|
]);
|
|
7620
7914
|
if (!strategyEntry || !strategyCreator) {
|
|
7621
7915
|
throw new Error(`Unknown strategy: ${strategyName}`);
|
|
@@ -7665,6 +7959,7 @@ var resolveStrategyComposition = async ({
|
|
|
7665
7959
|
});
|
|
7666
7960
|
return {
|
|
7667
7961
|
strategyName,
|
|
7962
|
+
strategyModule: pluginSource ?? strategyPackage.name,
|
|
7668
7963
|
strategyRevision: computeStrategyRevision({
|
|
7669
7964
|
strategyName,
|
|
7670
7965
|
strategyPackage: strategyPackage.name,
|
|
@@ -7851,6 +8146,32 @@ var MIN_HOURS = 6;
|
|
|
7851
8146
|
var MAX_HOURS = 24 * 90;
|
|
7852
8147
|
var BYBIT_MAX_TIME_RANGE_MS = 7 * 24 * 60 * 60 * 1e3 - 1e3;
|
|
7853
8148
|
var EXCHANGE_REQUEST_TIMEOUT_MS = 15e3;
|
|
8149
|
+
var groupRuntimeTradesByIdentity = (trades, identities) => {
|
|
8150
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
8151
|
+
for (const trade of trades) {
|
|
8152
|
+
const matches = [...identities.entries()].filter(([, identity]) => {
|
|
8153
|
+
if (trade.strategy !== identity.strategyName || String(trade.interval) !== String(identity.interval)) {
|
|
8154
|
+
return false;
|
|
8155
|
+
}
|
|
8156
|
+
if (trade.deploymentId && trade.deploymentId !== identity.deploymentId) {
|
|
8157
|
+
return false;
|
|
8158
|
+
}
|
|
8159
|
+
if (trade.accountId && trade.accountId !== identity.accountId) {
|
|
8160
|
+
return false;
|
|
8161
|
+
}
|
|
8162
|
+
if (trade.universe && trade.universe !== identity.universe) {
|
|
8163
|
+
return false;
|
|
8164
|
+
}
|
|
8165
|
+
return true;
|
|
8166
|
+
});
|
|
8167
|
+
if (matches.length !== 1) continue;
|
|
8168
|
+
const [runtimeKey] = matches[0];
|
|
8169
|
+
const bucket = grouped.get(runtimeKey) ?? [];
|
|
8170
|
+
bucket.push(trade);
|
|
8171
|
+
grouped.set(runtimeKey, bucket);
|
|
8172
|
+
}
|
|
8173
|
+
return grouped;
|
|
8174
|
+
};
|
|
7854
8175
|
var coerceHours = (value) => {
|
|
7855
8176
|
const parsed = Number(value ?? Number.NaN);
|
|
7856
8177
|
if (!Number.isFinite(parsed)) {
|
|
@@ -8181,6 +8502,7 @@ var loadRuntimeDashboard = async ({
|
|
|
8181
8502
|
const syncedTrades = [...unsyncedTrades, ...syncedConnectorTrades];
|
|
8182
8503
|
const fallbackTrades = [];
|
|
8183
8504
|
for (const {
|
|
8505
|
+
connector,
|
|
8184
8506
|
strategyNames,
|
|
8185
8507
|
entryRows,
|
|
8186
8508
|
closedPnlRows,
|
|
@@ -8193,7 +8515,12 @@ var loadRuntimeDashboard = async ({
|
|
|
8193
8515
|
openPositions: openPositionsSnapshot.positions,
|
|
8194
8516
|
strategyNames,
|
|
8195
8517
|
existingTrades: [...syncedTrades, ...fallbackTrades],
|
|
8196
|
-
endTime
|
|
8518
|
+
endTime,
|
|
8519
|
+
scope: {
|
|
8520
|
+
accountId: connector.accountId,
|
|
8521
|
+
deploymentId: connector.deploymentId,
|
|
8522
|
+
universe: connector.universe
|
|
8523
|
+
}
|
|
8197
8524
|
})
|
|
8198
8525
|
);
|
|
8199
8526
|
}
|
|
@@ -8236,6 +8563,9 @@ var loadRuntimeDashboard = async ({
|
|
|
8236
8563
|
});
|
|
8237
8564
|
identityByKey.set(runtimeKey, {
|
|
8238
8565
|
strategyName: resolvedStrategy.strategyName,
|
|
8566
|
+
strategyModule: resolvedStrategy.strategyModule,
|
|
8567
|
+
strategyPackage: resolvedStrategy.strategyPackage,
|
|
8568
|
+
strategyPackageVersion: resolvedStrategy.strategyPackageVersion,
|
|
8239
8569
|
configId: strategyConfigId,
|
|
8240
8570
|
strategyRevision: resolvedStrategy.strategyRevision,
|
|
8241
8571
|
controlState: resolvedStrategy.controlState,
|
|
@@ -8244,6 +8574,8 @@ var loadRuntimeDashboard = async ({
|
|
|
8244
8574
|
accountId: deployment.accountId,
|
|
8245
8575
|
accountLabel: accountsById.get(deployment.accountId)?.label,
|
|
8246
8576
|
deploymentId: deployment.id,
|
|
8577
|
+
deploymentLabel: deployment.label,
|
|
8578
|
+
...resolvedStrategy.generation ? { generation: resolvedStrategy.generation } : {},
|
|
8247
8579
|
policyProfileId: strategyPolicyProfileId,
|
|
8248
8580
|
enabled: resolvedStrategy.controlState !== "entries_paused",
|
|
8249
8581
|
config: resolvedStrategy.strategyConfig,
|
|
@@ -8252,12 +8584,16 @@ var loadRuntimeDashboard = async ({
|
|
|
8252
8584
|
});
|
|
8253
8585
|
}
|
|
8254
8586
|
}
|
|
8587
|
+
const tradesByRuntimeKey = groupRuntimeTradesByIdentity(
|
|
8588
|
+
allTrades,
|
|
8589
|
+
identityByKey
|
|
8590
|
+
);
|
|
8255
8591
|
const strategies2 = await Promise.all(
|
|
8256
8592
|
[...identityByKey.entries()].map(async ([runtimeKey, identity]) => {
|
|
8257
8593
|
const { strategyName } = identity;
|
|
8258
|
-
const strategyTrades =
|
|
8259
|
-
(
|
|
8260
|
-
)
|
|
8594
|
+
const strategyTrades = (tradesByRuntimeKey.get(runtimeKey) ?? []).sort(
|
|
8595
|
+
(left, right) => right.entryTimestamp - left.entryTimestamp
|
|
8596
|
+
);
|
|
8261
8597
|
const orders = strategyTrades.sort((left, right) => {
|
|
8262
8598
|
const leftDate = left.exitTimestamp ?? left.entryTimestamp;
|
|
8263
8599
|
const rightDate = right.exitTimestamp ?? right.entryTimestamp;
|
|
@@ -8272,14 +8608,19 @@ var loadRuntimeDashboard = async ({
|
|
|
8272
8608
|
return {
|
|
8273
8609
|
runtimeKey,
|
|
8274
8610
|
strategyName,
|
|
8611
|
+
strategyModule: identity.strategyModule,
|
|
8612
|
+
strategyPackage: identity.strategyPackage,
|
|
8613
|
+
strategyPackageVersion: identity.strategyPackageVersion,
|
|
8275
8614
|
configId: identity.configId,
|
|
8276
8615
|
strategyRevision: identity.strategyRevision,
|
|
8616
|
+
...identity.generation ? { generation: identity.generation } : {},
|
|
8277
8617
|
controlState: identity.controlState,
|
|
8278
8618
|
interval: identity.interval,
|
|
8279
8619
|
universe: identity.universe,
|
|
8280
8620
|
accountId: identity.accountId,
|
|
8281
8621
|
accountLabel: identity.accountLabel,
|
|
8282
8622
|
deploymentId: identity.deploymentId,
|
|
8623
|
+
deploymentLabel: identity.deploymentLabel,
|
|
8283
8624
|
...identity.selection ? { selection: identity.selection } : {},
|
|
8284
8625
|
policyProfileId: identity.policyProfileId,
|
|
8285
8626
|
connected: identity.connected,
|