@tradejs/node 3.1.27 → 3.1.28-beta.252

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.
@@ -934,6 +934,7 @@ var createStrategyRegistryState = () => ({
934
934
  strategyManifestsMap: /* @__PURE__ */ new Map(),
935
935
  strategyEntriesMap: /* @__PURE__ */ new Map(),
936
936
  strategySourcesMap: /* @__PURE__ */ new Map(),
937
+ strategyModuleResolutions: /* @__PURE__ */ new Map(),
937
938
  pluginsLoadPromise: null
938
939
  });
939
940
  var registryStateByProjectRoot = sharedStrategyRegistry.registryStateByProjectRoot;
@@ -995,7 +996,7 @@ var validateStrategyEntries = (moduleName, entries, state) => {
995
996
  const strategyName = entry?.manifest?.name;
996
997
  if (typeof strategyName !== "string" || !strategyName.trim()) {
997
998
  issues.push(`${entryPath}: manifest.name is required`);
998
- } else if (names.has(strategyName) || state.strategyEntriesMap.has(strategyName)) {
999
+ } else if (names.has(strategyName) || state?.strategyEntriesMap.has(strategyName)) {
999
1000
  issues.push(`${entryPath}: duplicate strategy ${strategyName}`);
1000
1001
  } else {
1001
1002
  names.add(strategyName);
@@ -1057,6 +1058,72 @@ var importStrategyPluginModule = async (moduleName, cwd = getTradejsProjectCwd()
1057
1058
  moduleName
1058
1059
  );
1059
1060
  };
1061
+ var resolveStrategyModuleEntry = async ({
1062
+ strategyName,
1063
+ moduleName,
1064
+ cwd
1065
+ }) => {
1066
+ const { projectRoot, state } = getStrategyRegistryState(cwd);
1067
+ const source = moduleName.trim();
1068
+ const resolvedModuleName = resolvePluginModuleSpecifier(source, projectRoot);
1069
+ const cacheKey = `${resolvedModuleName}\0${strategyName}`;
1070
+ const cached = state.strategyModuleResolutions.get(cacheKey);
1071
+ if (cached) return cached;
1072
+ const resolution = (async () => {
1073
+ const moduleExport = await importStrategyPluginModule(
1074
+ resolvedModuleName,
1075
+ projectRoot
1076
+ );
1077
+ const pluginDefinition = extractStrategyPluginDefinition(moduleExport);
1078
+ if (!pluginDefinition) {
1079
+ throw new Error(`${source}: export { strategyEntries } is missing`);
1080
+ }
1081
+ const issues = validateStrategyEntries(
1082
+ source,
1083
+ pluginDefinition.strategyEntries
1084
+ );
1085
+ if (issues.length > 0) {
1086
+ throw new Error(
1087
+ ["Invalid TradeJS strategy module:", ...issues].join("\n")
1088
+ );
1089
+ }
1090
+ const entry = pluginDefinition.strategyEntries.find(
1091
+ (candidate) => candidate.manifest.name === strategyName
1092
+ );
1093
+ if (!entry) {
1094
+ throw new Error(`${source}: strategy ${strategyName} is missing`);
1095
+ }
1096
+ const factory = sharedStrategyRegistry.strategyRuntimeFactory;
1097
+ if (!factory) {
1098
+ throw new Error("Strategy runtime factory is not configured");
1099
+ }
1100
+ const manifestsByName = new Map(
1101
+ pluginDefinition.strategyEntries.map(
1102
+ (candidate) => [candidate.manifest.name, candidate.manifest]
1103
+ )
1104
+ );
1105
+ return {
1106
+ entry,
1107
+ creator: factory({
1108
+ strategyName,
1109
+ defaults: entry.defaults,
1110
+ createCore: entry.createCore,
1111
+ manifest: entry.manifest,
1112
+ detectorKey: entry.detectorKey,
1113
+ detectorNoSignalSkipReason: entry.detectorNoSignalSkipReason,
1114
+ resolveRegisteredManifest: (name) => manifestsByName.get(name) ?? state.strategyManifestsMap.get(name)
1115
+ }),
1116
+ source
1117
+ };
1118
+ })();
1119
+ state.strategyModuleResolutions.set(cacheKey, resolution);
1120
+ try {
1121
+ return await resolution;
1122
+ } catch (error) {
1123
+ state.strategyModuleResolutions.delete(cacheKey);
1124
+ throw error;
1125
+ }
1126
+ };
1060
1127
  var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
1061
1128
  const { projectRoot, state } = getStrategyRegistryState(cwd);
1062
1129
  if (!state.pluginsLoadPromise) {
@@ -1134,17 +1201,29 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
1134
1201
  }
1135
1202
  await state.pluginsLoadPromise;
1136
1203
  };
1137
- var getStrategyCreator = async (name, cwd = getTradejsProjectCwd()) => {
1204
+ var getStrategyCreator = async (name, cwd = getTradejsProjectCwd(), moduleName) => {
1205
+ if (moduleName?.trim()) {
1206
+ await ensureStrategyPluginsLoaded(cwd);
1207
+ return (await resolveStrategyModuleEntry({ strategyName: name, moduleName, cwd })).creator;
1208
+ }
1138
1209
  await ensureStrategyPluginsLoaded(cwd);
1139
1210
  const { state } = getStrategyRegistryState(cwd);
1140
1211
  return state.strategyCreators.get(name);
1141
1212
  };
1142
- var getStrategyEntry = async (name, cwd = getTradejsProjectCwd()) => {
1213
+ var getStrategyEntry = async (name, cwd = getTradejsProjectCwd(), moduleName) => {
1214
+ if (moduleName?.trim()) {
1215
+ await ensureStrategyPluginsLoaded(cwd);
1216
+ return (await resolveStrategyModuleEntry({ strategyName: name, moduleName, cwd })).entry;
1217
+ }
1143
1218
  await ensureStrategyPluginsLoaded(cwd);
1144
1219
  const { state } = getStrategyRegistryState(cwd);
1145
1220
  return state.strategyEntriesMap.get(name);
1146
1221
  };
1147
- var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd()) => {
1222
+ var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd(), moduleName) => {
1223
+ if (moduleName?.trim()) {
1224
+ await ensureStrategyPluginsLoaded(cwd);
1225
+ return (await resolveStrategyModuleEntry({ strategyName: name, moduleName, cwd })).source;
1226
+ }
1148
1227
  await ensureStrategyPluginsLoaded(cwd);
1149
1228
  const { state } = getStrategyRegistryState(cwd);
1150
1229
  return state.strategySourcesMap.get(name);
@@ -2363,9 +2442,40 @@ var DEFAULT_MAX_AGE_BY_INTERVAL = {
2363
2442
  "15m": 30 * 6e4,
2364
2443
  "1h": 2 * 60 * 6e4
2365
2444
  };
2445
+ var MARKET_CONTEXT_PRELOAD_CHUNK_MS = 7 * 24 * 60 * 6e4;
2366
2446
  var binanceMarketContextUnavailable = false;
2367
2447
  var referenceRowsCache = /* @__PURE__ */ new Map();
2368
2448
  var breadthCache = /* @__PURE__ */ new Map();
2449
+ var BREADTH_COMMON_NUMERIC_FIELDS = [
2450
+ "symbolsCount",
2451
+ "advancers",
2452
+ "decliners",
2453
+ "unchanged",
2454
+ "advanceDeclineRatio",
2455
+ "pctAboveMa20",
2456
+ "pctAboveMa50",
2457
+ "equalWeightedReturn",
2458
+ "volumeWeightedReturn",
2459
+ "dispersion"
2460
+ ];
2461
+ var BREADTH_REGIME_NUMERIC_FIELDS = [
2462
+ "btcReturn1h",
2463
+ "btcReturn4h",
2464
+ "btcReturn24h",
2465
+ "altBasketReturn1h",
2466
+ "altBasketReturn4h",
2467
+ "altBasketReturn24h",
2468
+ "btcVsAltReturn1h",
2469
+ "btcVsAltReturn4h",
2470
+ "btcVsAltReturn24h",
2471
+ "btcTurnoverShare1h",
2472
+ "btcTurnoverShare24h",
2473
+ "btcTurnoverShareChange24h",
2474
+ "altVolToBtcVol24h",
2475
+ "altDispersion24h"
2476
+ ];
2477
+ var preloadedTradeFlowBySymbol = null;
2478
+ var preloadedBreadthByUniverse = null;
2369
2479
  var parseEnabledFlag = (value, env) => {
2370
2480
  const normalized = String(value ?? "").trim().toLowerCase();
2371
2481
  if (!normalized)
@@ -2401,6 +2511,100 @@ var hasBaseContext = (signal) => Boolean(
2401
2511
  signal.additionalIndicators?.baseContext && typeof signal.additionalIndicators.baseContext === "object" && !Array.isArray(signal.additionalIndicators.baseContext)
2402
2512
  );
2403
2513
  var isBinanceMarketContextEnabled = (env) => parseEnabledFlag(process.env.BINANCE_MARKET_CONTEXT_ENABLED, env);
2514
+ var latestIndexAtOrBefore = (timestamps, timestamp) => {
2515
+ if (!timestamps?.length) return -1;
2516
+ let low = 0;
2517
+ let high = timestamps.length - 1;
2518
+ let match = -1;
2519
+ while (low <= high) {
2520
+ const middle = Math.floor((low + high) / 2);
2521
+ const rowTimestamp = timestamps[middle];
2522
+ if (rowTimestamp == null) break;
2523
+ if (rowTimestamp <= timestamp) {
2524
+ match = middle;
2525
+ low = middle + 1;
2526
+ } else {
2527
+ high = middle - 1;
2528
+ }
2529
+ }
2530
+ return match;
2531
+ };
2532
+ var latestChunkAtOrBefore = (chunks, timestamp) => {
2533
+ if (!chunks?.length) return null;
2534
+ let low = 0;
2535
+ let high = chunks.length - 1;
2536
+ let match = null;
2537
+ while (low <= high) {
2538
+ const middle = Math.floor((low + high) / 2);
2539
+ const chunk = chunks[middle];
2540
+ const firstTimestamp = chunk?.timestamps[0];
2541
+ if (!chunk || firstTimestamp == null) break;
2542
+ if (firstTimestamp <= timestamp) {
2543
+ match = chunk;
2544
+ low = middle + 1;
2545
+ } else {
2546
+ high = middle - 1;
2547
+ }
2548
+ }
2549
+ return match;
2550
+ };
2551
+ var unpackedNumber = (value) => value == null || Number.isNaN(value) ? null : value;
2552
+ var unpackTradeFlowRow = (chunks, timestamp) => {
2553
+ const rows = latestChunkAtOrBefore(chunks, timestamp);
2554
+ const index = latestIndexAtOrBefore(rows?.timestamps, timestamp);
2555
+ if (!rows || index < 0) return null;
2556
+ return {
2557
+ symbol: rows.symbol,
2558
+ interval: rows.interval,
2559
+ ts: new Date(rows.timestamps[index]),
2560
+ trades: unpackedNumber(rows.columns.trades[index]) ?? 0,
2561
+ buyBaseVolume: unpackedNumber(rows.columns.buyBaseVolume[index]),
2562
+ sellBaseVolume: unpackedNumber(rows.columns.sellBaseVolume[index]),
2563
+ buyQuoteVolume: unpackedNumber(rows.columns.buyQuoteVolume[index]),
2564
+ sellQuoteVolume: unpackedNumber(rows.columns.sellQuoteVolume[index]),
2565
+ netBaseDelta: unpackedNumber(rows.columns.netBaseDelta[index]),
2566
+ netQuoteDelta: unpackedNumber(rows.columns.netQuoteDelta[index]),
2567
+ buyPressurePct: unpackedNumber(rows.columns.buyPressurePct[index])
2568
+ };
2569
+ };
2570
+ var unpackBreadthRow = (chunks, timestamp) => {
2571
+ const rows = latestChunkAtOrBefore(chunks, timestamp);
2572
+ const index = latestIndexAtOrBefore(rows?.timestamps, timestamp);
2573
+ if (!rows || index < 0) return null;
2574
+ const commonNumeric = Object.fromEntries(
2575
+ BREADTH_COMMON_NUMERIC_FIELDS.map((field) => [
2576
+ field,
2577
+ unpackedNumber(rows.commonColumns[field][index])
2578
+ ])
2579
+ );
2580
+ const regimeNumeric = Object.fromEntries(
2581
+ BREADTH_REGIME_NUMERIC_FIELDS.map((field) => [
2582
+ field,
2583
+ unpackedNumber(rows.regimeColumns?.[field][index])
2584
+ ])
2585
+ );
2586
+ return {
2587
+ universe: rows.universe,
2588
+ interval: rows.interval,
2589
+ ts: new Date(rows.timestamps[index]),
2590
+ ...commonNumeric,
2591
+ ...regimeNumeric,
2592
+ symbolsCount: commonNumeric.symbolsCount ?? 0,
2593
+ advancers: commonNumeric.advancers ?? 0,
2594
+ decliners: commonNumeric.decliners ?? 0,
2595
+ unchanged: commonNumeric.unchanged ?? 0,
2596
+ btcAltRegime: rows.regimes?.[index] ?? null
2597
+ };
2598
+ };
2599
+ var toAsOfRow = (row, timestamp, maxAgeMs) => {
2600
+ if (!row) return null;
2601
+ const ageMs = timestamp - row.ts.getTime();
2602
+ return {
2603
+ ...row,
2604
+ ageMs: Number.isFinite(ageMs) ? ageMs : null,
2605
+ stale: !Number.isFinite(ageMs) || ageMs < 0 || ageMs > maxAgeMs
2606
+ };
2607
+ };
2404
2608
  var toTradeFlowContext = (row, interval) => row ? {
2405
2609
  source: "binance_agg_trades",
2406
2610
  interval,
@@ -2423,6 +2627,24 @@ var getCachedReferenceRows = ({
2423
2627
  maxAgeMs,
2424
2628
  abortSignal
2425
2629
  }) => {
2630
+ if (preloadedTradeFlowBySymbol) {
2631
+ return Promise.resolve(
2632
+ referenceSymbols.map((symbol) => ({
2633
+ symbol,
2634
+ tradeFlow: toTradeFlowContext(
2635
+ toAsOfRow(
2636
+ unpackTradeFlowRow(
2637
+ preloadedTradeFlowBySymbol?.get(symbol),
2638
+ timestamp
2639
+ ),
2640
+ timestamp,
2641
+ maxAgeMs
2642
+ ),
2643
+ interval
2644
+ )
2645
+ }))
2646
+ );
2647
+ }
2426
2648
  const key = `${referenceSymbols.join(",")}:${interval}:${timestamp}:${maxAgeMs}`;
2427
2649
  const cached = referenceRowsCache.get(key);
2428
2650
  if (cached) return cached;
@@ -2452,6 +2674,18 @@ var getCachedBreadth = ({
2452
2674
  maxAgeMs,
2453
2675
  abortSignal
2454
2676
  }) => {
2677
+ if (preloadedBreadthByUniverse) {
2678
+ return Promise.resolve(
2679
+ toAsOfRow(
2680
+ unpackBreadthRow(
2681
+ preloadedBreadthByUniverse.get(breadthUniverse),
2682
+ timestamp
2683
+ ),
2684
+ timestamp,
2685
+ maxAgeMs
2686
+ )
2687
+ );
2688
+ }
2455
2689
  const key = `${breadthUniverse}:${interval}:${timestamp}:${maxAgeMs}`;
2456
2690
  const cached = breadthCache.get(key);
2457
2691
  if (cached) return cached;
@@ -2658,12 +2892,20 @@ var SOURCE_EXCHANGE_LIQUIDITY = "coinmarketcap_exchange_liquidity";
2658
2892
  var SOURCE_FEAR_GREED = "coinmarketcap_fear_greed";
2659
2893
  var SOURCE_INDEX = "coinmarketcap_index";
2660
2894
  var DAY_MS = 864e5;
2895
+ var MAX_TIMESTAMP_CACHE_ENTRIES = 512;
2661
2896
  var coinMarketCapContextUnavailable = false;
2662
2897
  var globalContextCache = /* @__PURE__ */ new Map();
2663
2898
  var referenceContextCache = /* @__PURE__ */ new Map();
2664
2899
  var exchangeLiquidityContextCache = /* @__PURE__ */ new Map();
2665
2900
  var fearGreedContextCache = /* @__PURE__ */ new Map();
2666
2901
  var indexContextCache = /* @__PURE__ */ new Map();
2902
+ var setBoundedCache = (cache, key, value) => {
2903
+ if (cache.size >= MAX_TIMESTAMP_CACHE_ENTRIES) {
2904
+ const oldestKey = cache.keys().next().value;
2905
+ if (oldestKey != null) cache.delete(oldestKey);
2906
+ }
2907
+ cache.set(key, value);
2908
+ };
2667
2909
  var parseEnabledFlag2 = (value, env) => {
2668
2910
  const normalized = String(value ?? "").trim().toLowerCase();
2669
2911
  if (!normalized) {
@@ -2770,7 +3012,7 @@ var getCachedGlobalContext = ({
2770
3012
  maxAgeMs,
2771
3013
  ...abortSignal ? { signal: abortSignal } : {}
2772
3014
  });
2773
- globalContextCache.set(key, promise);
3015
+ setBoundedCache(globalContextCache, key, promise);
2774
3016
  void promise.catch(() => globalContextCache.delete(key));
2775
3017
  return promise;
2776
3018
  };
@@ -2790,7 +3032,7 @@ var getCachedReferenceContexts = ({
2790
3032
  maxAgeMs,
2791
3033
  ...abortSignal ? { signal: abortSignal } : {}
2792
3034
  });
2793
- referenceContextCache.set(key, promise);
3035
+ setBoundedCache(referenceContextCache, key, promise);
2794
3036
  void promise.catch(() => referenceContextCache.delete(key));
2795
3037
  return promise;
2796
3038
  };
@@ -2809,7 +3051,7 @@ var getCachedExchangeLiquidityContext = ({
2809
3051
  maxAgeMs,
2810
3052
  ...abortSignal ? { signal: abortSignal } : {}
2811
3053
  });
2812
- exchangeLiquidityContextCache.set(key, promise);
3054
+ setBoundedCache(exchangeLiquidityContextCache, key, promise);
2813
3055
  void promise.catch(() => exchangeLiquidityContextCache.delete(key));
2814
3056
  return promise;
2815
3057
  };
@@ -2828,7 +3070,7 @@ var getCachedFearGreedContext = ({
2828
3070
  maxAgeMs,
2829
3071
  ...abortSignal ? { signal: abortSignal } : {}
2830
3072
  });
2831
- fearGreedContextCache.set(key, promise);
3073
+ setBoundedCache(fearGreedContextCache, key, promise);
2832
3074
  void promise.catch(() => fearGreedContextCache.delete(key));
2833
3075
  return promise;
2834
3076
  };
@@ -2848,7 +3090,7 @@ var getCachedIndexContexts = ({
2848
3090
  maxAgeMs,
2849
3091
  ...abortSignal ? { signal: abortSignal } : {}
2850
3092
  });
2851
- indexContextCache.set(key, promise);
3093
+ setBoundedCache(indexContextCache, key, promise);
2852
3094
  void promise.catch(() => indexContextCache.delete(key));
2853
3095
  return promise;
2854
3096
  };
@@ -3658,7 +3900,7 @@ var signalIntervalToMarketInterval2 = (value) => {
3658
3900
  var hasBaseContext3 = (signal) => Boolean(
3659
3901
  signal.additionalIndicators?.baseContext && typeof signal.additionalIndicators.baseContext === "object" && !Array.isArray(signal.additionalIndicators.baseContext)
3660
3902
  );
3661
- var setBoundedCache = (key, value) => {
3903
+ var setBoundedCache2 = (key, value) => {
3662
3904
  if (contextCache.size >= MAX_CACHE_ENTRIES) {
3663
3905
  const oldestKey = contextCache.keys().next().value;
3664
3906
  if (oldestKey != null) contextCache.delete(oldestKey);
@@ -3905,7 +4147,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
3905
4147
  whaleRegistryFingerprint: whales.fingerprint,
3906
4148
  ...params.abortSignal ? { signal: params.abortSignal } : {}
3907
4149
  });
3908
- setBoundedCache(cacheKey, pending);
4150
+ setBoundedCache2(cacheKey, pending);
3909
4151
  }
3910
4152
  row = await pending;
3911
4153
  }
@@ -5040,20 +5282,23 @@ var buildHookCtx = ({
5040
5282
  strategyConfig,
5041
5283
  env,
5042
5284
  isConfigFromBacktest
5043
- }) => ({
5044
- connector,
5045
- strategyName,
5046
- userName,
5047
- symbol,
5048
- ...universe ? { universe } : {},
5049
- ...assetClass ? { assetClass } : {},
5050
- ...accountId ? { accountId } : {},
5051
- ...deploymentId ? { deploymentId } : {},
5052
- ...policyProfileId ? { policyProfileId } : {},
5053
- strategyConfig,
5054
- env,
5055
- isConfigFromBacktest
5056
- });
5285
+ }) => {
5286
+ const context = {
5287
+ connector,
5288
+ strategyName,
5289
+ userName,
5290
+ symbol
5291
+ };
5292
+ if (universe) context.universe = universe;
5293
+ if (assetClass) context.assetClass = assetClass;
5294
+ if (accountId) context.accountId = accountId;
5295
+ if (deploymentId) context.deploymentId = deploymentId;
5296
+ if (policyProfileId) context.policyProfileId = policyProfileId;
5297
+ context.strategyConfig = strategyConfig;
5298
+ context.env = env;
5299
+ context.isConfigFromBacktest = isConfigFromBacktest;
5300
+ return context;
5301
+ };
5057
5302
  var shouldRecordRuntimeJournal = ({
5058
5303
  env,
5059
5304
  config
@@ -6398,7 +6643,13 @@ var DEPLOYMENT_KEYS = /* @__PURE__ */ new Set([
6398
6643
  "assetClasses",
6399
6644
  "tickers"
6400
6645
  ]);
6401
- var STRATEGY_KEYS = /* @__PURE__ */ new Set(["generation", "enabled", "selection", "config"]);
6646
+ var STRATEGY_KEYS = /* @__PURE__ */ new Set([
6647
+ "module",
6648
+ "generation",
6649
+ "enabled",
6650
+ "selection",
6651
+ "config"
6652
+ ]);
6402
6653
  var SELECTION_KEYS = /* @__PURE__ */ new Set(["tickers"]);
6403
6654
  var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
6404
6655
  "ACCOUNT_ID",
@@ -6470,6 +6721,39 @@ var readRuntimePackageManifest = async (projectRoot) => {
6470
6721
  }
6471
6722
  return value;
6472
6723
  };
6724
+ var parseNpmAliasReference = (value) => {
6725
+ if (typeof value !== "string" || !value.startsWith("npm:")) return null;
6726
+ const target = value.slice("npm:".length);
6727
+ const versionSeparator = target.lastIndexOf("@");
6728
+ if (versionSeparator <= 0 || versionSeparator === target.length - 1) {
6729
+ return null;
6730
+ }
6731
+ return {
6732
+ packageName: target.slice(0, versionSeparator),
6733
+ version: target.slice(versionSeparator + 1)
6734
+ };
6735
+ };
6736
+ var verifyInstalledPackageName = async ({
6737
+ projectRoot,
6738
+ packageName,
6739
+ installedName,
6740
+ installedVersion,
6741
+ projectPackage
6742
+ }) => {
6743
+ if (installedName === void 0 || installedName === packageName) return;
6744
+ if (projectPackage || typeof installedName !== "string") {
6745
+ throw new Error("name is invalid");
6746
+ }
6747
+ const projectManifest = JSON.parse(
6748
+ await (0, import_promises.readFile)(import_node_path.default.join(projectRoot, "package.json"), "utf8")
6749
+ );
6750
+ const alias = parseNpmAliasReference(
6751
+ projectManifest.dependencies?.[packageName]
6752
+ );
6753
+ if (alias?.packageName !== installedName || alias.version !== installedVersion) {
6754
+ throw new Error("name or alias target is invalid");
6755
+ }
6756
+ };
6473
6757
  var readInstalledPackageMetadata = async ({
6474
6758
  projectRoot,
6475
6759
  packageName,
@@ -6483,9 +6767,16 @@ var readInstalledPackageMetadata = async ({
6483
6767
  );
6484
6768
  try {
6485
6769
  const packageJson = JSON.parse(await (0, import_promises.readFile)(packageJsonPath, "utf8"));
6486
- if (packageJson.name !== void 0 && packageJson.name !== packageName || typeof packageJson.version !== "string" || !packageJson.version.trim()) {
6487
- throw new Error("name or version is invalid");
6770
+ if (typeof packageJson.version !== "string" || !packageJson.version.trim()) {
6771
+ throw new Error("version is invalid");
6488
6772
  }
6773
+ await verifyInstalledPackageName({
6774
+ projectRoot,
6775
+ packageName,
6776
+ installedName: packageJson.name,
6777
+ installedVersion: packageJson.version,
6778
+ projectPackage
6779
+ });
6489
6780
  const dependencyNames = [
6490
6781
  ...isRecord(packageJson.dependencies) ? Object.keys(packageJson.dependencies) : [],
6491
6782
  ...isRecord(packageJson.peerDependencies) ? Object.keys(packageJson.peerDependencies) : []
@@ -6580,7 +6871,7 @@ var verifyDeploymentDeclaration = (deploymentId, value) => {
6580
6871
  for (const [strategyName, strategyValue] of Object.entries(
6581
6872
  value.strategies
6582
6873
  )) {
6583
- 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(
6874
+ 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(
6584
6875
  (key) => FORBIDDEN_CONFIG_KEYS.has(key)
6585
6876
  ) || !INTERVALS.has(String(strategyValue.config.INTERVAL)) || !["crypto", "tradfi"].includes(String(strategyValue.config.UNIVERSE))) {
6586
6877
  throw new Error(
@@ -6614,9 +6905,9 @@ var resolveStrategyComposition = async ({
6614
6905
  packageManifest
6615
6906
  }) => {
6616
6907
  const [strategyEntry, strategyCreator, pluginSource] = await Promise.all([
6617
- getStrategyEntry(strategyName, projectRoot),
6618
- getStrategyCreator(strategyName, projectRoot),
6619
- getStrategyPluginSource(strategyName, projectRoot)
6908
+ getStrategyEntry(strategyName, projectRoot, declaration.module),
6909
+ getStrategyCreator(strategyName, projectRoot, declaration.module),
6910
+ getStrategyPluginSource(strategyName, projectRoot, declaration.module)
6620
6911
  ]);
6621
6912
  if (!strategyEntry || !strategyCreator) {
6622
6913
  throw new Error(`Unknown strategy: ${strategyName}`);
@@ -6666,6 +6957,7 @@ var resolveStrategyComposition = async ({
6666
6957
  });
6667
6958
  return {
6668
6959
  strategyName,
6960
+ strategyModule: pluginSource ?? strategyPackage.name,
6669
6961
  strategyRevision: computeStrategyRevision({
6670
6962
  strategyName,
6671
6963
  strategyPackage: strategyPackage.name,
@@ -6854,11 +7146,12 @@ var loadResolvedRuntimeStrategies = async ({
6854
7146
  };
6855
7147
  var getRuntimeStrategyPackageMetadata = async ({
6856
7148
  strategyName,
6857
- projectRoot
7149
+ projectRoot,
7150
+ strategyModule
6858
7151
  }) => {
6859
7152
  const [packageManifest, pluginSource] = await Promise.all([
6860
7153
  readRuntimePackageManifest(projectRoot),
6861
- getStrategyPluginSource(strategyName, projectRoot)
7154
+ getStrategyPluginSource(strategyName, projectRoot, strategyModule)
6862
7155
  ]);
6863
7156
  const strategyPackage = await resolveStrategyPackage({
6864
7157
  pluginSource: pluginSource ?? null,
@@ -8,9 +8,9 @@ import {
8
8
  loadResolvedRuntimeStrategies,
9
9
  resolveRuntimeComposition,
10
10
  verifyRuntimeDeclaration
11
- } from "./chunk-NQO2MFP6.mjs";
12
- import "./chunk-XHNJ757K.mjs";
13
- import "./chunk-IKRSNRP6.mjs";
11
+ } from "./chunk-K2YQ3MQC.mjs";
12
+ import "./chunk-VQSGH7YA.mjs";
13
+ import "./chunk-UITD6LG6.mjs";
14
14
  import "./chunk-LZDXRXIU.mjs";
15
15
  import "./chunk-Y6FXYEAI.mjs";
16
16
  export {
@@ -19,13 +19,14 @@ declare const takeClosedPnlMatch: ({ exactByOrderLinkId, exactByOrderId, symbolB
19
19
  trade: RuntimeTradeRecord;
20
20
  }) => ClosedPnlRecordWithOrderLinkId | null;
21
21
 
22
- declare const buildExchangeFallbackRuntimeTrades: ({ entryRows, closedPnlRows, openPositions, strategyNames, existingTrades, endTime, }: {
22
+ declare const buildExchangeFallbackRuntimeTrades: ({ entryRows, closedPnlRows, openPositions, strategyNames, existingTrades, endTime, scope, }: {
23
23
  entryRows: ExchangeEntryRecord[];
24
24
  closedPnlRows: ClosedPnlRecordWithOrderLinkId[];
25
25
  openPositions: PositionPnlSnapshot[];
26
26
  strategyNames: string[];
27
27
  existingTrades: RuntimeTradeRecord[];
28
28
  endTime: number;
29
+ scope?: Pick<RuntimeTradeRecord, "accountId" | "deploymentId" | "universe">;
29
30
  }) => RuntimeTradeRecord[];
30
31
 
31
32
  export { type ClosedPnlRecordWithOrderLinkId, buildExchangeFallbackRuntimeTrades, takeClosedPnlMatch, takeExactClosedPnlMatch };
@@ -19,13 +19,14 @@ declare const takeClosedPnlMatch: ({ exactByOrderLinkId, exactByOrderId, symbolB
19
19
  trade: RuntimeTradeRecord;
20
20
  }) => ClosedPnlRecordWithOrderLinkId | null;
21
21
 
22
- declare const buildExchangeFallbackRuntimeTrades: ({ entryRows, closedPnlRows, openPositions, strategyNames, existingTrades, endTime, }: {
22
+ declare const buildExchangeFallbackRuntimeTrades: ({ entryRows, closedPnlRows, openPositions, strategyNames, existingTrades, endTime, scope, }: {
23
23
  entryRows: ExchangeEntryRecord[];
24
24
  closedPnlRows: ClosedPnlRecordWithOrderLinkId[];
25
25
  openPositions: PositionPnlSnapshot[];
26
26
  strategyNames: string[];
27
27
  existingTrades: RuntimeTradeRecord[];
28
28
  endTime: number;
29
+ scope?: Pick<RuntimeTradeRecord, "accountId" | "deploymentId" | "universe">;
29
30
  }) => RuntimeTradeRecord[];
30
31
 
31
32
  export { type ClosedPnlRecordWithOrderLinkId, buildExchangeFallbackRuntimeTrades, takeClosedPnlMatch, takeExactClosedPnlMatch };
@@ -190,7 +190,8 @@ var buildExchangeFallbackRuntimeTrades = ({
190
190
  openPositions,
191
191
  strategyNames,
192
192
  existingTrades,
193
- endTime
193
+ endTime,
194
+ scope
194
195
  }) => {
195
196
  if (!entryRows.length && !closedPnlRows.length) return [];
196
197
  const strategyNameByOrderId = new Map(
@@ -245,6 +246,7 @@ var buildExchangeFallbackRuntimeTrades = ({
245
246
  const entryPrice = typeof entry.entryPrice === "number" && Number.isFinite(entry.entryPrice) ? entry.entryPrice : typeof closed?.entryPrice === "number" && Number.isFinite(closed.entryPrice) ? closed.entryPrice : null;
246
247
  if (entryPrice == null) return null;
247
248
  return {
249
+ ...scope,
248
250
  orderId: runtimeOrderId,
249
251
  strategy,
250
252
  symbol: entry.symbol,
@@ -287,6 +289,7 @@ var buildExchangeFallbackRuntimeTrades = ({
287
289
  return null;
288
290
  }
289
291
  return {
292
+ ...scope,
290
293
  orderId: runtimeOrderId,
291
294
  strategy,
292
295
  symbol: row.symbol,
@@ -2,7 +2,7 @@ import {
2
2
  buildExchangeFallbackRuntimeTrades,
3
3
  takeClosedPnlMatch,
4
4
  takeExactClosedPnlMatch
5
- } from "./chunk-FB5NUEOQ.mjs";
5
+ } from "./chunk-OFVUEYUR.mjs";
6
6
  import "./chunk-Y6FXYEAI.mjs";
7
7
  export {
8
8
  buildExchangeFallbackRuntimeTrades,
@@ -1,6 +1,6 @@
1
1
  export * from '@tradejs/core/strategies';
2
2
  export { AiChatMessage, DEFAULT_AI_MODEL, InvokeAiChatOptions, MAX_AI_SERIES_POINTS, askAI, buildAiHumanPrompt, buildAiPayload, buildAiPrompts, buildAiSystemPrompt, buildCompactAiIndicatorsSnapshot, getDeterministicAiGateContext, getOpenRouterModelKwargs, invokeAiChat, resetAiRuntimeCache, runAiPrompt, runAiPromptLocal, trimSeriesDeep } from './ai.mjs';
3
- export { e as ensureIndicatorPluginsLoaded, a as ensureStrategyPluginsLoaded, g as getAvailableStrategyNames, b as getRegisteredManifests, c as getRegisteredStrategies, d as getStrategyCreator, f as getStrategyDefaults, h as getStrategyManifest, i as getStrategyPluginSource, j as isKnownStrategy, r as registerStrategyEntries, k as resetStrategyRegistryCache, s as strategies } from './registry-DHTLjQcr.mjs';
3
+ export { e as ensureIndicatorPluginsLoaded, a as ensureStrategyPluginsLoaded, g as getAvailableStrategyNames, b as getRegisteredManifests, c as getRegisteredStrategies, d as getStrategyCreator, f as getStrategyDefaults, h as getStrategyManifest, i as getStrategyPluginSource, j as isKnownStrategy, r as registerStrategyEntries, k as resetStrategyRegistryCache, s as strategies } from './registry-3TsO1Ff1.mjs';
4
4
  import { StrategyConfig, CreateStrategyCore, StrategyManifest, StrategyCreator, RuntimeStrategyConfigSnapshot, Signal, Direction, StrategyRuntimeMlOptions, StrategyRuntimeAiOptions, Connector, Tp, MarketFeatureInterval, StrategyEntrySignalContext } from '@tradejs/types';
5
5
  import { TradejsConfigOnBarHook, TradejsConfigBeforeSignalsHook } from '@tradejs/core/config';
6
6
 
@@ -79,6 +79,18 @@ declare const validateEntryProtectionAtArrival: ({ direction, signalPrice, bid,
79
79
  }) => void;
80
80
  declare const executeEntryOrder: ({ connector, userName, symbol, direction, qty, currentPrice, timestamp, takeProfits, stopLossPrice, positionIntent, signal, beforePlaceOrder, recordRuntimeTrade, leverage, }: ExecuteEntryOrderParams) => Promise<number>;
81
81
 
82
+ declare const preloadBinanceMarketContextForWindow: (params: {
83
+ startMs: number;
84
+ endMs: number;
85
+ interval: MarketFeatureInterval;
86
+ maxAgeMs?: number;
87
+ timeoutMs?: number;
88
+ chunkMs?: number;
89
+ abortSignal?: AbortSignal;
90
+ }) => Promise<{
91
+ tradeFlowRows: number;
92
+ breadthRows: number;
93
+ }>;
82
94
  declare const enrichSignalWithBinanceMarketContext: (params: {
83
95
  signal: Signal;
84
96
  env: string;
@@ -200,4 +212,4 @@ interface CreateCloseAllOnGlobalProfitBeforeSignalsHookParams {
200
212
  }
201
213
  declare const createCloseAllOnGlobalProfitBeforeSignalsHook: ({ getStrategyDefaultConfig, profitRiskMultiplier, }?: CreateCloseAllOnGlobalProfitBeforeSignalsHookParams) => TradejsConfigBeforeSignalsHook;
202
214
 
203
- export { BINANCE_BREADTH_UNIVERSE_KEYS, type BinanceBreadthUniverseDefinition, type BinanceBreadthUniverseKey, type BinanceBreadthUniverseSnapshot, type HyperliquidPerpUniverseSnapshot, type HyperliquidWhaleRegistrySnapshot, buildBinanceBreadthUniverseSnapshot, closeOppositePositionsBeforeOpen, createCloseAllOnGlobalProfitBeforeSignalsHook, createCloseOppositeBeforePlaceOrderHook, createMoveStopToBreakEvenAfterCoreDecisionHook, createMoveStopToBreakEvenOnBarHook, createStrategyRuntime, enrichSignalWithAi, enrichSignalWithBinanceMarketContext, enrichSignalWithCoinMarketCapContext, enrichSignalWithHyperliquidWhaleContext, enrichSignalWithMl, enrichSignalWithMlAi, executeEntryOrder, getBinanceBreadthUniverseSnapshot, getBinanceBreadthUniverses, getHyperliquidPerpSymbols, getHyperliquidPerpUniverseSnapshot, getHyperliquidWhaleAddresses, getHyperliquidWhaleRegistrySnapshot, getOrderArrivalSnapshot, getPrimaryBinanceBreadthUniverse, isTrackedHyperliquidPerp, isTrackedHyperliquidWhale, resolveHyperliquidPerpFromSignalSymbol, resolveStrategyConfig, validateEntryProtectionAtArrival };
215
+ export { BINANCE_BREADTH_UNIVERSE_KEYS, type BinanceBreadthUniverseDefinition, type BinanceBreadthUniverseKey, type BinanceBreadthUniverseSnapshot, type HyperliquidPerpUniverseSnapshot, type HyperliquidWhaleRegistrySnapshot, buildBinanceBreadthUniverseSnapshot, closeOppositePositionsBeforeOpen, createCloseAllOnGlobalProfitBeforeSignalsHook, createCloseOppositeBeforePlaceOrderHook, createMoveStopToBreakEvenAfterCoreDecisionHook, createMoveStopToBreakEvenOnBarHook, createStrategyRuntime, enrichSignalWithAi, enrichSignalWithBinanceMarketContext, enrichSignalWithCoinMarketCapContext, enrichSignalWithHyperliquidWhaleContext, enrichSignalWithMl, enrichSignalWithMlAi, executeEntryOrder, getBinanceBreadthUniverseSnapshot, getBinanceBreadthUniverses, getHyperliquidPerpSymbols, getHyperliquidPerpUniverseSnapshot, getHyperliquidWhaleAddresses, getHyperliquidWhaleRegistrySnapshot, getOrderArrivalSnapshot, getPrimaryBinanceBreadthUniverse, isTrackedHyperliquidPerp, isTrackedHyperliquidWhale, preloadBinanceMarketContextForWindow, resolveHyperliquidPerpFromSignalSymbol, resolveStrategyConfig, validateEntryProtectionAtArrival };