@tradejs/node 3.1.11 → 3.1.12-beta.218

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.
@@ -34,7 +34,7 @@ __export(runtimeDashboard_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(runtimeDashboard_exports);
36
36
  var import_time4 = require("@tradejs/core/time");
37
- var import_logger15 = require("@tradejs/infra/logger");
37
+ var import_logger14 = require("@tradejs/infra/logger");
38
38
  var import_tradingAccounts3 = require("@tradejs/infra/tradingAccounts");
39
39
  var import_redis4 = require("@tradejs/infra/redis");
40
40
 
@@ -1329,6 +1329,7 @@ var syncRuntimeTrades = async ({
1329
1329
  };
1330
1330
 
1331
1331
  // src/runtimeStrategies.ts
1332
+ var import_node_crypto4 = require("crypto");
1332
1333
  var import_promises = require("fs/promises");
1333
1334
  var import_node_path = __toESM(require("path"));
1334
1335
  var import_runtimeControls = require("@tradejs/infra/runtimeControls");
@@ -1337,10 +1338,10 @@ var import_tradingAccounts2 = require("@tradejs/infra/tradingAccounts");
1337
1338
  // src/strategyRuntime.ts
1338
1339
  var import_constants7 = require("@tradejs/core/constants");
1339
1340
  var import_strategies6 = require("@tradejs/core/strategies");
1340
- var import_logger14 = require("@tradejs/infra/logger");
1341
+ var import_logger13 = require("@tradejs/infra/logger");
1341
1342
 
1342
1343
  // src/strategyHelpers/runtime.ts
1343
- var import_logger12 = require("@tradejs/infra/logger");
1344
+ var import_logger11 = require("@tradejs/infra/logger");
1344
1345
  var import_constants5 = require("@tradejs/core/constants");
1345
1346
  var import_ml2 = require("@tradejs/infra/ml");
1346
1347
 
@@ -1922,7 +1923,6 @@ var buildAiMarketContext = (signal) => ({
1922
1923
 
1923
1924
  // src/strategy/manifests.ts
1924
1925
  var import_indicators = require("@tradejs/core/indicators");
1925
- var import_logger5 = require("@tradejs/infra/logger");
1926
1926
  var SHARED_STRATEGY_REGISTRY_KEY = "__tradejsNodeSharedStrategyRegistryV1__";
1927
1927
  var sharedRegistryScope = globalThis;
1928
1928
  var sharedStrategyRegistry = sharedRegistryScope[SHARED_STRATEGY_REGISTRY_KEY] ?? (sharedRegistryScope[SHARED_STRATEGY_REGISTRY_KEY] = {
@@ -1986,21 +1986,34 @@ var extractIndicatorPluginDefinition = (moduleExport) => {
1986
1986
  );
1987
1987
  return indicatorEntries ? { indicatorEntries } : null;
1988
1988
  };
1989
- var registerEntries2 = (entries, source, state) => {
1990
- for (const entry of entries) {
1991
- const strategyName = entry.manifest?.name;
1992
- if (!strategyName) {
1993
- import_logger5.logger.warn("Skip strategy entry without name from %s", source);
1994
- continue;
1989
+ var validateStrategyEntries = (moduleName, entries, state) => {
1990
+ const issues = [];
1991
+ const names = /* @__PURE__ */ new Set();
1992
+ entries.forEach((entry, index) => {
1993
+ const entryPath = `${moduleName}.strategyEntries[${index}]`;
1994
+ const strategyName = entry?.manifest?.name;
1995
+ if (typeof strategyName !== "string" || !strategyName.trim()) {
1996
+ issues.push(`${entryPath}: manifest.name is required`);
1997
+ } else if (names.has(strategyName) || state.strategyEntriesMap.has(strategyName)) {
1998
+ issues.push(`${entryPath}: duplicate strategy ${strategyName}`);
1999
+ } else {
2000
+ names.add(strategyName);
1995
2001
  }
1996
- if (state.strategyCreators.has(strategyName)) {
1997
- import_logger5.logger.warn(
1998
- 'Skip duplicate strategy "%s" from %s: already registered',
1999
- strategyName,
2000
- source
2001
- );
2002
- continue;
2002
+ if (!entry || typeof entry !== "object" || !entry.defaults || typeof entry.defaults !== "object" || Array.isArray(entry.defaults)) {
2003
+ issues.push(`${entryPath}: defaults must be an object`);
2004
+ }
2005
+ if (typeof entry?.parseConfig !== "function") {
2006
+ issues.push(`${entryPath}: parseConfig is required`);
2003
2007
  }
2008
+ if (typeof entry?.createCore !== "function") {
2009
+ issues.push(`${entryPath}: createCore is required`);
2010
+ }
2011
+ });
2012
+ return issues;
2013
+ };
2014
+ var registerEntries2 = (entries, source, state) => {
2015
+ for (const entry of entries) {
2016
+ const strategyName = entry.manifest.name;
2004
2017
  state.strategyManifestsMap.set(strategyName, entry.manifest);
2005
2018
  state.strategyEntriesMap.set(strategyName, entry);
2006
2019
  state.strategySourcesMap.set(strategyName, source);
@@ -2057,6 +2070,7 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
2057
2070
  if (!pluginModuleNames.length) {
2058
2071
  return;
2059
2072
  }
2073
+ const issues = [];
2060
2074
  for (const moduleName of pluginModuleNames) {
2061
2075
  try {
2062
2076
  const resolvedModuleName = resolvePluginModuleSpecifier(
@@ -2070,24 +2084,30 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
2070
2084
  if (strategySet.has(moduleName)) {
2071
2085
  const pluginDefinition = extractStrategyPluginDefinition(moduleExport);
2072
2086
  if (!pluginDefinition) {
2073
- import_logger5.logger.warn(
2074
- 'Skip strategy plugin "%s": export { strategyEntries } is missing',
2075
- moduleName
2087
+ issues.push(
2088
+ `${moduleName}: export { strategyEntries } is missing`
2076
2089
  );
2077
2090
  } else {
2078
- registerEntries2(
2079
- pluginDefinition.strategyEntries,
2091
+ const entryIssues = validateStrategyEntries(
2080
2092
  moduleName,
2093
+ pluginDefinition.strategyEntries,
2081
2094
  state
2082
2095
  );
2096
+ issues.push(...entryIssues);
2097
+ if (entryIssues.length === 0) {
2098
+ registerEntries2(
2099
+ pluginDefinition.strategyEntries,
2100
+ moduleName,
2101
+ state
2102
+ );
2103
+ }
2083
2104
  }
2084
2105
  }
2085
2106
  if (indicatorSet.has(moduleName)) {
2086
2107
  const indicatorPluginDefinition = extractIndicatorPluginDefinition(moduleExport);
2087
2108
  if (!indicatorPluginDefinition) {
2088
- import_logger5.logger.warn(
2089
- 'Skip indicator plugin "%s": export { indicatorEntries } is missing',
2090
- moduleName
2109
+ issues.push(
2110
+ `${moduleName}: export { indicatorEntries } is missing`
2091
2111
  );
2092
2112
  } else {
2093
2113
  (0, import_indicators.registerIndicatorEntries)(
@@ -2098,19 +2118,17 @@ var ensureStrategyPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
2098
2118
  }
2099
2119
  }
2100
2120
  if (!strategySet.has(moduleName) && !indicatorSet.has(moduleName)) {
2101
- import_logger5.logger.warn(
2102
- 'Skip plugin "%s": no strategy/indicator sections requested in config',
2103
- moduleName
2104
- );
2121
+ issues.push(`${moduleName}: plugin is not declared in config`);
2105
2122
  }
2106
2123
  } catch (error) {
2107
- import_logger5.logger.warn(
2108
- 'Failed to load plugin "%s": %s',
2109
- moduleName,
2110
- String(error)
2111
- );
2124
+ issues.push(`${moduleName}: failed to import: ${String(error)}`);
2112
2125
  }
2113
2126
  }
2127
+ if (issues.length > 0) {
2128
+ throw new Error(
2129
+ ["Invalid TradeJS plugin catalog:", ...issues].join("\n")
2130
+ );
2131
+ }
2114
2132
  })();
2115
2133
  }
2116
2134
  await state.pluginsLoadPromise;
@@ -2120,6 +2138,11 @@ var getStrategyCreator = async (name, cwd = getTradejsProjectCwd()) => {
2120
2138
  const { state } = getStrategyRegistryState(cwd);
2121
2139
  return state.strategyCreators.get(name);
2122
2140
  };
2141
+ var getStrategyEntry = async (name, cwd = getTradejsProjectCwd()) => {
2142
+ await ensureStrategyPluginsLoaded(cwd);
2143
+ const { state } = getStrategyRegistryState(cwd);
2144
+ return state.strategyEntriesMap.get(name);
2145
+ };
2123
2146
  var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd()) => {
2124
2147
  await ensureStrategyPluginsLoaded(cwd);
2125
2148
  const { state } = getStrategyRegistryState(cwd);
@@ -2772,7 +2795,7 @@ var import_node_crypto = require("crypto");
2772
2795
  var import_constants3 = require("@tradejs/core/constants");
2773
2796
  var import_time3 = require("@tradejs/core/time");
2774
2797
  var import_trade = require("@tradejs/core/trade");
2775
- var import_logger6 = require("@tradejs/infra/logger");
2798
+ var import_logger5 = require("@tradejs/infra/logger");
2776
2799
  var import_redis3 = require("@tradejs/infra/redis");
2777
2800
  var now = () => Date.now();
2778
2801
  var toRandomOrderSuffix = () => (0, import_node_crypto.randomUUID)().replace(/-/g, "").slice(0, 12).toLowerCase();
@@ -2831,7 +2854,7 @@ var recordRuntimeTradeOpen = async (params) => {
2831
2854
  )
2832
2855
  ]);
2833
2856
  } catch (error) {
2834
- import_logger6.logger.error(
2857
+ import_logger5.logger.error(
2835
2858
  "runtime trade open journal failed: %s %s",
2836
2859
  record.symbol,
2837
2860
  error?.message || String(error)
@@ -2898,7 +2921,7 @@ var recordRuntimeTradeIncrease = async (params) => {
2898
2921
  )
2899
2922
  ]);
2900
2923
  } catch (error) {
2901
- import_logger6.logger.error(
2924
+ import_logger5.logger.error(
2902
2925
  "runtime trade increase journal failed: %s %s",
2903
2926
  symbol,
2904
2927
  error?.message || String(error)
@@ -3005,7 +3028,7 @@ var markRuntimeTradeClosed = async (params) => {
3005
3028
  )
3006
3029
  ]);
3007
3030
  } catch (error) {
3008
- import_logger6.logger.error(
3031
+ import_logger5.logger.error(
3009
3032
  "runtime trade close journal failed: %s %s",
3010
3033
  symbol,
3011
3034
  error?.message || String(error)
@@ -3015,11 +3038,11 @@ var markRuntimeTradeClosed = async (params) => {
3015
3038
  };
3016
3039
 
3017
3040
  // src/strategyHelpers/marketContextStages.ts
3018
- var import_logger11 = require("@tradejs/infra/logger");
3041
+ var import_logger10 = require("@tradejs/infra/logger");
3019
3042
 
3020
3043
  // src/strategyHelpers/binanceMarketContext.ts
3021
3044
  var import_marketContext = require("@tradejs/infra/timescale/marketContext");
3022
- var import_logger7 = require("@tradejs/infra/logger");
3045
+ var import_logger6 = require("@tradejs/infra/logger");
3023
3046
  var import_strategies = require("@tradejs/core/strategies");
3024
3047
 
3025
3048
  // src/binanceBreadthUniverses.ts
@@ -3615,7 +3638,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
3615
3638
  throw error;
3616
3639
  }
3617
3640
  binanceMarketContextUnavailable = true;
3618
- import_logger7.logger.warn(
3641
+ import_logger6.logger.warn(
3619
3642
  "Binance market context disabled after Timescale read failure: %s",
3620
3643
  String(error)
3621
3644
  );
@@ -3625,7 +3648,7 @@ var enrichSignalWithBinanceMarketContext = async (params) => {
3625
3648
 
3626
3649
  // src/strategyHelpers/coinMarketCapContext.ts
3627
3650
  var import_strategies2 = require("@tradejs/core/strategies");
3628
- var import_logger8 = require("@tradejs/infra/logger");
3651
+ var import_logger7 = require("@tradejs/infra/logger");
3629
3652
  var import_marketContext2 = require("@tradejs/infra/timescale/marketContext");
3630
3653
  var DEFAULT_MAX_AGE_MS = 48 * 60 * 6e4;
3631
3654
  var SOURCE_GLOBAL_DAILY = "coinmarketcap_global";
@@ -4114,7 +4137,7 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
4114
4137
  throw error;
4115
4138
  }
4116
4139
  coinMarketCapContextUnavailable = true;
4117
- import_logger8.logger.warn(
4140
+ import_logger7.logger.warn(
4118
4141
  "CoinMarketCap context disabled after Timescale read failure: %s",
4119
4142
  String(error)
4120
4143
  );
@@ -4128,7 +4151,7 @@ var import_data2 = require("@tradejs/core/data");
4128
4151
  var import_strategies3 = require("@tradejs/core/strategies");
4129
4152
  var import_constants4 = require("@tradejs/core/constants");
4130
4153
  var import_derivatives = require("@tradejs/infra/timescale/derivatives");
4131
- var import_logger9 = require("@tradejs/infra/logger");
4154
+ var import_logger8 = require("@tradejs/infra/logger");
4132
4155
  var STORED_INTERVALS = ["15m", "1h"];
4133
4156
  var CONTEXT_INTERVALS = ["15m", "1h"];
4134
4157
  var DEFAULT_LOOKBACK_HOURS = 48;
@@ -4360,7 +4383,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
4360
4383
  throw error;
4361
4384
  }
4362
4385
  derivativesContextUnavailable = true;
4363
- import_logger9.logger.warn(
4386
+ import_logger8.logger.warn(
4364
4387
  "Derivatives context disabled after Timescale read failure: %s",
4365
4388
  String(error)
4366
4389
  );
@@ -4372,7 +4395,7 @@ var enrichSignalWithDerivativesContext = async (params) => {
4372
4395
  var import_data3 = require("@tradejs/core/data");
4373
4396
  var import_strategies4 = require("@tradejs/core/strategies");
4374
4397
  var import_hyperliquidWhales2 = require("@tradejs/infra/timescale/hyperliquidWhales");
4375
- var import_logger10 = require("@tradejs/infra/logger");
4398
+ var import_logger9 = require("@tradejs/infra/logger");
4376
4399
 
4377
4400
  // src/hyperliquidWhaleUniverse.ts
4378
4401
  var import_node_crypto3 = require("crypto");
@@ -4892,7 +4915,7 @@ var loadHyperliquidWhaleFlowContext = async (params) => {
4892
4915
  throw error;
4893
4916
  }
4894
4917
  hyperliquidWhaleContextUnavailable = true;
4895
- import_logger10.logger.warn(
4918
+ import_logger9.logger.warn(
4896
4919
  "Hyperliquid whale context disabled after Timescale read failure: %s",
4897
4920
  String(error)
4898
4921
  );
@@ -4975,7 +4998,7 @@ var runMarketContextStage = async ({
4975
4998
  elapsedMs: Date.now() - startedAt
4976
4999
  };
4977
5000
  if (status === "timed_out") {
4978
- import_logger11.logger.warn(
5001
+ import_logger10.logger.warn(
4979
5002
  "Market context stage timed out: %s after %sms",
4980
5003
  stage,
4981
5004
  result.elapsedMs
@@ -5165,7 +5188,7 @@ var enrichSignalWithAi = async ({
5165
5188
  signal.aiAnalysis = analysis;
5166
5189
  return resolveAiQuality(analysis, direction);
5167
5190
  } catch (err) {
5168
- import_logger12.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
5191
+ import_logger11.logger.error("AI analysis error: %s %s", symbol, formatAiError(err));
5169
5192
  }
5170
5193
  return void 0;
5171
5194
  };
@@ -5200,7 +5223,7 @@ var getOrderArrivalSnapshot = async ({
5200
5223
  spreadBps
5201
5224
  };
5202
5225
  } catch (error) {
5203
- import_logger12.logger.warn(
5226
+ import_logger11.logger.warn(
5204
5227
  "runtime order arrival snapshot failed: %s %s",
5205
5228
  symbol,
5206
5229
  error?.message || String(error)
@@ -5429,7 +5452,7 @@ var executeEntryOrder = async ({
5429
5452
  deploymentId: signal.deploymentId,
5430
5453
  policyProfileId: signal.policyProfileId,
5431
5454
  runtimeConfigId: signal.runtimeConfigId,
5432
- runtimeVersion: signal.runtimeVersion,
5455
+ strategyRevision: signal.strategyRevision,
5433
5456
  runtimeLineage: signal.runtimeLineage,
5434
5457
  ...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {}
5435
5458
  });
@@ -5981,7 +6004,7 @@ var canUseSharedReplayState = ({
5981
6004
  }) => (env === "BACKTEST" || env === "PARITY") && Boolean(sharedReplayKey);
5982
6005
 
5983
6006
  // src/strategy/runtimeExecution.ts
5984
- var import_logger13 = require("@tradejs/infra/logger");
6007
+ var import_logger12 = require("@tradejs/infra/logger");
5985
6008
  var import_types = require("@tradejs/types");
5986
6009
  var buildExitOrderSignal = ({
5987
6010
  strategyName,
@@ -6033,7 +6056,7 @@ var handleExitDecision = async ({
6033
6056
  deploymentId: connector.deploymentId
6034
6057
  });
6035
6058
  if (!activeTrade) {
6036
- import_logger13.logger.warn(
6059
+ import_logger12.logger.warn(
6037
6060
  "[%s] blocked closePosition for untracked runtime position: %s",
6038
6061
  strategyName ?? "unknown",
6039
6062
  symbol
@@ -6041,7 +6064,7 @@ var handleExitDecision = async ({
6041
6064
  return "CLOSE_BLOCKED_BY_UNTRACKED_POSITION";
6042
6065
  }
6043
6066
  if (!strategyName || activeTrade.strategy !== strategyName) {
6044
- import_logger13.logger.warn(
6067
+ import_logger12.logger.warn(
6045
6068
  "[%s] blocked closePosition for foreign runtime position: %s ownedBy=%s",
6046
6069
  strategyName ?? "unknown",
6047
6070
  symbol,
@@ -6093,7 +6116,7 @@ var handleExitDecision = async ({
6093
6116
  exitType: closedTrade?.exitType ?? "exit"
6094
6117
  });
6095
6118
  } catch (notificationError) {
6096
- import_logger13.logger.error(
6119
+ import_logger12.logger.error(
6097
6120
  "runtime close notification error: %s %s",
6098
6121
  symbol,
6099
6122
  notificationError
@@ -6107,7 +6130,7 @@ var handleExitDecision = async ({
6107
6130
  decision,
6108
6131
  market
6109
6132
  });
6110
- import_logger13.logger.error("close order error: %s %s", symbol, err);
6133
+ import_logger12.logger.error("close order error: %s %s", symbol, err);
6111
6134
  return "ORDER_ERROR";
6112
6135
  }
6113
6136
  return decision.code;
@@ -6134,7 +6157,7 @@ var handleProtectDecision = async ({
6134
6157
  decision,
6135
6158
  market
6136
6159
  });
6137
- import_logger13.logger.error("protect position error: %s %s", symbol, err);
6160
+ import_logger12.logger.error("protect position error: %s %s", symbol, err);
6138
6161
  return "ORDER_ERROR";
6139
6162
  }
6140
6163
  return decision.code;
@@ -6297,9 +6320,9 @@ var executeEntryDecision = async ({
6297
6320
  market
6298
6321
  });
6299
6322
  if (err?.message === import_types.BACKTEST_WARNING_CODES.TAKE_PROFIT_CROSSED_BEFORE_ENTRY) {
6300
- import_logger13.logger.warn("order warning: %s %s", symbol, err);
6323
+ import_logger12.logger.warn("order warning: %s %s", symbol, err);
6301
6324
  } else {
6302
- import_logger13.logger.error("order error: %s %s", symbol, err);
6325
+ import_logger12.logger.error("order error: %s %s", symbol, err);
6303
6326
  }
6304
6327
  return signal ?? "ORDER_ERROR";
6305
6328
  }
@@ -6340,7 +6363,7 @@ var createStrategyRuntime = ({
6340
6363
  deploymentId: requestedDeploymentId,
6341
6364
  policyProfileId,
6342
6365
  runtimeConfigId,
6343
- runtimeVersion,
6366
+ strategyRevision,
6344
6367
  entriesPaused = false,
6345
6368
  runtimeLineage,
6346
6369
  runtimeConfigSnapshot,
@@ -6453,7 +6476,7 @@ var createStrategyRuntime = ({
6453
6476
  try {
6454
6477
  await projectHook(errorParams);
6455
6478
  } catch (hookError) {
6456
- import_logger14.logger.error(
6479
+ import_logger13.logger.error(
6457
6480
  "project hook onRuntimeError failed: %s %s",
6458
6481
  strategyName,
6459
6482
  hookError
@@ -6467,7 +6490,7 @@ var createStrategyRuntime = ({
6467
6490
  try {
6468
6491
  await onRuntimeError(errorParams);
6469
6492
  } catch (hookError) {
6470
- import_logger14.logger.error(
6493
+ import_logger13.logger.error(
6471
6494
  "runtime hook onRuntimeError failed: %s %s",
6472
6495
  strategyName,
6473
6496
  hookError
@@ -6481,7 +6504,7 @@ var createStrategyRuntime = ({
6481
6504
  try {
6482
6505
  return await hook(params);
6483
6506
  } catch (error) {
6484
- import_logger14.logger.error(
6507
+ import_logger13.logger.error(
6485
6508
  'strategy hook "%s" failed for %s: %s',
6486
6509
  stage,
6487
6510
  strategyName,
@@ -7012,8 +7035,8 @@ var createStrategyRuntime = ({
7012
7035
  signal.signalId = `${signal.signalId}:${runtimeConfigId}`;
7013
7036
  }
7014
7037
  }
7015
- if (runtimeVersion) {
7016
- signal.runtimeVersion = runtimeVersion;
7038
+ if (strategyRevision) {
7039
+ signal.strategyRevision = strategyRevision;
7017
7040
  }
7018
7041
  if (decisionHookCtx.policyProfileId) {
7019
7042
  signal.policyProfileId = decisionHookCtx.policyProfileId;
@@ -7126,7 +7149,7 @@ var createStrategyRuntime = ({
7126
7149
  if (signal) {
7127
7150
  signal.orderStatus = "skipped";
7128
7151
  signal.orderSkipReason = skipReason;
7129
- signal.runtimeVersion = runtimeVersion;
7152
+ signal.strategyRevision = strategyRevision;
7130
7153
  }
7131
7154
  return signal ?? skipReason;
7132
7155
  }
@@ -7238,6 +7261,7 @@ var createStrategyRuntime = ({
7238
7261
  setStrategyRuntimeFactory(createStrategyRuntime);
7239
7262
 
7240
7263
  // src/runtimeStrategies.ts
7264
+ var RUNTIME_PACKAGE_MANIFEST_SCHEMA = "tradejs-runtime-package-manifest/v1";
7241
7265
  var INTERVALS = /* @__PURE__ */ new Set([
7242
7266
  "1",
7243
7267
  "3",
@@ -7264,7 +7288,7 @@ var DEPLOYMENT_KEYS = /* @__PURE__ */ new Set([
7264
7288
  "assetClasses",
7265
7289
  "tickers"
7266
7290
  ]);
7267
- var STRATEGY_KEYS = /* @__PURE__ */ new Set(["version", "enabled", "selection", "config"]);
7291
+ var STRATEGY_KEYS = /* @__PURE__ */ new Set(["generation", "enabled", "selection", "config"]);
7268
7292
  var SELECTION_KEYS = /* @__PURE__ */ new Set(["tickers"]);
7269
7293
  var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
7270
7294
  "ACCOUNT_ID",
@@ -7273,60 +7297,165 @@ var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set([
7273
7297
  "ENABLE"
7274
7298
  ]);
7275
7299
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
7276
- var readPackageManifest = async (projectRoot) => {
7277
- const candidates = [
7278
- process.env.TRADEJS_RUNTIME_PACKAGE_MANIFEST,
7279
- import_node_path.default.join(projectRoot, "runtime-package-manifest.json"),
7280
- "/app/runtime-package-manifest.json"
7281
- ].filter((candidate) => Boolean(candidate));
7282
- for (const candidate of candidates) {
7283
- try {
7284
- return JSON.parse(
7285
- await (0, import_promises.readFile)(candidate, "utf8")
7286
- );
7287
- } catch {
7288
- }
7300
+ var normalizeForCanonicalJson = (value) => {
7301
+ if (Array.isArray(value)) return value.map(normalizeForCanonicalJson);
7302
+ if (isRecord(value)) {
7303
+ return Object.fromEntries(
7304
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nestedValue]) => [
7305
+ key,
7306
+ normalizeForCanonicalJson(nestedValue)
7307
+ ])
7308
+ );
7289
7309
  }
7290
- return { packages: {} };
7310
+ return value;
7291
7311
  };
7292
- var resolveInstalledPackageVersion = async (projectRoot, packageName, manifest) => {
7293
- if (!packageName || packageName === "runtime") return null;
7294
- const manifestVersion = manifest.packages?.[packageName];
7295
- if (manifestVersion) return manifestVersion;
7312
+ var revision = (prefix, value) => `${prefix}:${(0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(normalizeForCanonicalJson(value))).digest("hex").slice(0, 16)}`;
7313
+ var computeStrategyRevision = ({
7314
+ strategyName,
7315
+ strategyPackage,
7316
+ strategyPackageVersion,
7317
+ strategyDependencyVersions,
7318
+ runtimePackageVersion,
7319
+ strategyConfig
7320
+ }) => revision("sr1", {
7321
+ schema: "tradejs-strategy-revision/v1",
7322
+ strategyName,
7323
+ strategyPackage,
7324
+ strategyPackageVersion,
7325
+ strategyDependencyVersions,
7326
+ runtimePackageVersion,
7327
+ strategyConfig
7328
+ });
7329
+ var computeDeploymentCompositionId = (value) => revision("dc1", {
7330
+ schema: "tradejs-deployment-composition/v1",
7331
+ ...value,
7332
+ assetClasses: value.assetClasses ? [...value.assetClasses].sort((left, right) => left.localeCompare(right)) : void 0,
7333
+ strategies: [...value.strategies].sort(
7334
+ (left, right) => left.strategyName.localeCompare(right.strategyName)
7335
+ ).map((strategy) => ({
7336
+ ...strategy,
7337
+ selection: strategy.selection ? {
7338
+ tickers: [...strategy.selection.tickers].sort(
7339
+ (left, right) => left.localeCompare(right)
7340
+ )
7341
+ } : void 0
7342
+ }))
7343
+ });
7344
+ var readRuntimePackageManifest = async (projectRoot) => {
7345
+ const manifestPath = process.env.TRADEJS_RUNTIME_PACKAGE_MANIFEST?.trim() || import_node_path.default.join(projectRoot, "runtime-package-manifest.json");
7346
+ let value;
7296
7347
  try {
7297
- const packageJsonPath = import_node_path.default.join(
7298
- projectRoot,
7299
- "node_modules",
7300
- ...packageName.split("/"),
7301
- "package.json"
7348
+ value = JSON.parse(await (0, import_promises.readFile)(manifestPath, "utf8"));
7349
+ } catch (error) {
7350
+ throw new Error(
7351
+ `Unable to read runtime package manifest ${manifestPath}: ${String(error)}`
7302
7352
  );
7353
+ }
7354
+ if (!isRecord(value) || Object.keys(value).some(
7355
+ (key) => !["schema", "projectSha", "packages"].includes(key)
7356
+ ) || value.schema !== RUNTIME_PACKAGE_MANIFEST_SCHEMA || typeof value.projectSha !== "string" || !/^[a-f0-9]{40}$/.test(value.projectSha) || !isRecord(value.packages) || Object.keys(value.packages).length === 0 || Object.entries(value.packages).some(
7357
+ ([packageName, version]) => !packageName.trim() || typeof version !== "string" || !version.trim()
7358
+ )) {
7359
+ throw new Error(`Invalid runtime package manifest: ${manifestPath}`);
7360
+ }
7361
+ return value;
7362
+ };
7363
+ var readInstalledPackageMetadata = async ({
7364
+ projectRoot,
7365
+ packageName,
7366
+ projectPackage
7367
+ }) => {
7368
+ const packageJsonPath = projectPackage ? import_node_path.default.join(projectRoot, "package.json") : import_node_path.default.join(
7369
+ projectRoot,
7370
+ "node_modules",
7371
+ ...packageName.split("/"),
7372
+ "package.json"
7373
+ );
7374
+ try {
7303
7375
  const packageJson = JSON.parse(await (0, import_promises.readFile)(packageJsonPath, "utf8"));
7304
- return packageJson.version ?? null;
7305
- } catch {
7306
- return null;
7376
+ if (packageJson.name !== void 0 && packageJson.name !== packageName || typeof packageJson.version !== "string" || !packageJson.version.trim()) {
7377
+ throw new Error("name or version is invalid");
7378
+ }
7379
+ const dependencyNames = [
7380
+ ...isRecord(packageJson.dependencies) ? Object.keys(packageJson.dependencies) : [],
7381
+ ...isRecord(packageJson.peerDependencies) ? Object.keys(packageJson.peerDependencies) : []
7382
+ ];
7383
+ return {
7384
+ version: packageJson.version,
7385
+ runtimeDependencies: [...new Set(dependencyNames)].filter((name) => name.startsWith("@tradejs/")).sort((left, right) => left.localeCompare(right))
7386
+ };
7387
+ } catch (error) {
7388
+ throw new Error(
7389
+ `Installed package manifest not found for ${packageName}: ${String(error)}`
7390
+ );
7391
+ }
7392
+ };
7393
+ var resolveVerifiedPackageVersion = async ({
7394
+ projectRoot,
7395
+ packageName,
7396
+ manifest,
7397
+ projectPackage = false
7398
+ }) => {
7399
+ const declaredVersion = manifest.packages[packageName];
7400
+ if (!declaredVersion) {
7401
+ throw new Error(`Runtime package manifest is missing ${packageName}`);
7307
7402
  }
7403
+ const installed = await readInstalledPackageMetadata({
7404
+ projectRoot,
7405
+ packageName,
7406
+ projectPackage
7407
+ });
7408
+ if (declaredVersion !== installed.version) {
7409
+ throw new Error(
7410
+ `Runtime package manifest mismatch for ${packageName}: declared=${declaredVersion} installed=${installed.version}`
7411
+ );
7412
+ }
7413
+ return installed.version;
7414
+ };
7415
+ var resolveVerifiedStrategyDependencyVersions = async ({
7416
+ projectRoot,
7417
+ strategyPackage,
7418
+ manifest
7419
+ }) => {
7420
+ const metadata = await readInstalledPackageMetadata({
7421
+ projectRoot,
7422
+ packageName: strategyPackage.name,
7423
+ projectPackage: strategyPackage.projectPackage
7424
+ });
7425
+ return Object.fromEntries(
7426
+ await Promise.all(
7427
+ metadata.runtimeDependencies.map(async (packageName) => [
7428
+ packageName,
7429
+ await resolveVerifiedPackageVersion({
7430
+ projectRoot,
7431
+ packageName,
7432
+ manifest
7433
+ })
7434
+ ])
7435
+ )
7436
+ );
7308
7437
  };
7309
- var resolveStrategyPackageName = async ({
7438
+ var resolveStrategyPackage = async ({
7310
7439
  pluginSource,
7311
7440
  projectRoot
7312
7441
  }) => {
7313
7442
  if (!pluginSource) return null;
7314
7443
  if (!pluginSource.startsWith(".") && !import_node_path.default.isAbsolute(pluginSource)) {
7315
- return pluginSource;
7444
+ return { name: pluginSource, projectPackage: false };
7316
7445
  }
7317
7446
  try {
7318
7447
  const packageJson = JSON.parse(
7319
7448
  await (0, import_promises.readFile)(import_node_path.default.join(projectRoot, "package.json"), "utf8")
7320
7449
  );
7321
- return typeof packageJson.name === "string" && packageJson.name.trim() ? packageJson.name : null;
7450
+ return typeof packageJson.name === "string" && packageJson.name.trim() ? { name: packageJson.name, projectPackage: true } : null;
7322
7451
  } catch {
7323
7452
  return null;
7324
7453
  }
7325
7454
  };
7326
- var verifyStringArray = (value) => value === void 0 || Array.isArray(value) && value.every((item) => typeof item === "string");
7327
- var verifyStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => SELECTION_KEYS.has(key)) && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every(
7328
- (ticker) => typeof ticker === "string" && ticker.trim().length > 0
7329
- );
7455
+ var verifyStringSet = (value) => value === void 0 || Array.isArray(value) && value.length > 0 && value.every(
7456
+ (item) => typeof item === "string" && item.length > 0 && item === item.trim()
7457
+ ) && new Set(value).size === value.length;
7458
+ var verifyStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => SELECTION_KEYS.has(key)) && value.tickers !== void 0 && verifyStringSet(value.tickers);
7330
7459
  var cloneSelection = (selection) => selection ? { tickers: [...selection.tickers] } : void 0;
7331
7460
  var resolveStrategySelection = ({
7332
7461
  deployment,
@@ -7335,13 +7464,13 @@ var resolveStrategySelection = ({
7335
7464
  strategy.selection ?? (deployment.tickers ? { tickers: deployment.tickers } : void 0)
7336
7465
  );
7337
7466
  var verifyDeploymentDeclaration = (deploymentId, value) => {
7338
- if (!deploymentId.trim() || !isRecord(value) || Object.keys(value).some((key) => !DEPLOYMENT_KEYS.has(key)) || typeof value.connectorName !== "string" || !value.connectorName.trim() || typeof value.accountId !== "string" || !value.accountId.trim() || value.label !== void 0 && typeof value.label !== "string" || value.provider !== void 0 && typeof value.provider !== "string" || value.enabled !== void 0 && typeof value.enabled !== "boolean" || !verifyStringArray(value.assetClasses) || !verifyStringArray(value.tickers) || !isRecord(value.strategies) || !Object.keys(value.strategies).length) {
7467
+ if (!deploymentId.trim() || !isRecord(value) || Object.keys(value).some((key) => !DEPLOYMENT_KEYS.has(key)) || typeof value.connectorName !== "string" || !value.connectorName.trim() || typeof value.accountId !== "string" || !value.accountId.trim() || value.label !== void 0 && typeof value.label !== "string" || value.provider !== void 0 && typeof value.provider !== "string" || value.enabled !== void 0 && typeof value.enabled !== "boolean" || !verifyStringSet(value.assetClasses) || !verifyStringSet(value.tickers) || !isRecord(value.strategies) || !Object.keys(value.strategies).length) {
7339
7468
  throw new Error(`Invalid runtime deployment declaration: ${deploymentId}`);
7340
7469
  }
7341
7470
  for (const [strategyName, strategyValue] of Object.entries(
7342
7471
  value.strategies
7343
7472
  )) {
7344
- if (!strategyName.trim() || !isRecord(strategyValue) || Object.keys(strategyValue).some((key) => !STRATEGY_KEYS.has(key)) || !Number.isSafeInteger(strategyValue.version) || Number(strategyValue.version) <= 0 || typeof strategyValue.enabled !== "boolean" || !verifyStrategySelection(strategyValue.selection) || !isRecord(strategyValue.config) || Object.keys(strategyValue.config).some(
7473
+ 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(
7345
7474
  (key) => FORBIDDEN_CONFIG_KEYS.has(key)
7346
7475
  ) || !INTERVALS.has(String(strategyValue.config.INTERVAL)) || !["crypto", "tradfi"].includes(String(strategyValue.config.UNIVERSE))) {
7347
7476
  throw new Error(
@@ -7360,55 +7489,180 @@ var verifyRuntimeDeclaration = (value) => {
7360
7489
  }
7361
7490
  return value;
7362
7491
  };
7363
- var toRuntimeDeployment = ({
7364
- id,
7492
+ var loadRuntimeDeclaration = async (projectRoot) => {
7493
+ const projectConfig = await loadTradejsConfig(projectRoot);
7494
+ if (!projectConfig.runtime) {
7495
+ throw new Error("Runtime declaration is required in tradejs.config.ts");
7496
+ }
7497
+ return verifyRuntimeDeclaration(projectConfig.runtime);
7498
+ };
7499
+ var resolveStrategyComposition = async ({
7500
+ strategyName,
7365
7501
  declaration,
7502
+ deployment,
7503
+ projectRoot,
7504
+ packageManifest
7505
+ }) => {
7506
+ const [strategyEntry, strategyCreator, pluginSource] = await Promise.all([
7507
+ getStrategyEntry(strategyName, projectRoot),
7508
+ getStrategyCreator(strategyName, projectRoot),
7509
+ getStrategyPluginSource(strategyName, projectRoot)
7510
+ ]);
7511
+ if (!strategyEntry || !strategyCreator) {
7512
+ throw new Error(`Unknown strategy: ${strategyName}`);
7513
+ }
7514
+ if (typeof strategyEntry.parseConfig !== "function") {
7515
+ throw new Error(`Strategy config parser is missing: ${strategyName}`);
7516
+ }
7517
+ const strategyPackage = await resolveStrategyPackage({
7518
+ pluginSource: pluginSource ?? null,
7519
+ projectRoot
7520
+ });
7521
+ if (!strategyPackage) {
7522
+ throw new Error(`Installed strategy package not found: ${strategyName}`);
7523
+ }
7524
+ const [
7525
+ strategyPackageVersion,
7526
+ strategyDependencyVersions,
7527
+ runtimePackageVersion
7528
+ ] = await Promise.all([
7529
+ resolveVerifiedPackageVersion({
7530
+ projectRoot,
7531
+ packageName: strategyPackage.name,
7532
+ projectPackage: strategyPackage.projectPackage,
7533
+ manifest: packageManifest
7534
+ }),
7535
+ resolveVerifiedStrategyDependencyVersions({
7536
+ projectRoot,
7537
+ strategyPackage,
7538
+ manifest: packageManifest
7539
+ }),
7540
+ resolveVerifiedPackageVersion({
7541
+ projectRoot,
7542
+ packageName: "@tradejs/node",
7543
+ manifest: packageManifest
7544
+ })
7545
+ ]);
7546
+ const parsedConfig = strategyEntry.parseConfig(declaration.config);
7547
+ if (!isRecord(parsedConfig)) {
7548
+ throw new Error(
7549
+ `Strategy config parser returned a non-object: ${strategyName}`
7550
+ );
7551
+ }
7552
+ const strategyConfig = parsedConfig;
7553
+ const selection = resolveStrategySelection({
7554
+ deployment,
7555
+ strategy: declaration
7556
+ });
7557
+ return {
7558
+ strategyName,
7559
+ strategyRevision: computeStrategyRevision({
7560
+ strategyName,
7561
+ strategyPackage: strategyPackage.name,
7562
+ strategyPackageVersion,
7563
+ strategyDependencyVersions,
7564
+ runtimePackageVersion,
7565
+ strategyConfig
7566
+ }),
7567
+ ...declaration.generation ? { generation: declaration.generation } : {},
7568
+ enabled: declaration.enabled,
7569
+ interval: String(strategyConfig.INTERVAL),
7570
+ universe: strategyConfig.UNIVERSE,
7571
+ strategyPackage: strategyPackage.name,
7572
+ strategyPackageVersion,
7573
+ strategyDependencyVersions,
7574
+ runtimePackageVersion,
7575
+ strategyCreator,
7576
+ sourceStrategyConfig: declaration.config,
7577
+ strategyConfig,
7578
+ ...selection ? { selection } : {}
7579
+ };
7580
+ };
7581
+ var resolveRuntimeComposition = async ({
7582
+ projectRoot
7583
+ }) => {
7584
+ const [runtime, packageManifest] = await Promise.all([
7585
+ loadRuntimeDeclaration(projectRoot),
7586
+ readRuntimePackageManifest(projectRoot)
7587
+ ]);
7588
+ const deployments = await Promise.all(
7589
+ Object.entries(runtime.deployments).map(
7590
+ async ([deploymentId, declaration]) => {
7591
+ const strategies2 = await Promise.all(
7592
+ Object.entries(declaration.strategies).map(
7593
+ ([strategyName, strategyDeclaration]) => resolveStrategyComposition({
7594
+ strategyName,
7595
+ declaration: strategyDeclaration,
7596
+ deployment: declaration,
7597
+ projectRoot,
7598
+ packageManifest
7599
+ })
7600
+ )
7601
+ );
7602
+ const provider = (declaration.provider || declaration.connectorName).trim().toLowerCase();
7603
+ return {
7604
+ deploymentId,
7605
+ deploymentCompositionId: computeDeploymentCompositionId({
7606
+ deploymentId,
7607
+ connectorName: declaration.connectorName.trim(),
7608
+ provider,
7609
+ accountId: declaration.accountId.trim(),
7610
+ enabled: declaration.enabled ?? true,
7611
+ ...declaration.assetClasses ? { assetClasses: declaration.assetClasses } : {},
7612
+ strategies: strategies2.map((strategy) => ({
7613
+ strategyName: strategy.strategyName,
7614
+ strategyRevision: strategy.strategyRevision,
7615
+ enabled: strategy.enabled,
7616
+ ...strategy.selection ? { selection: strategy.selection } : {}
7617
+ }))
7618
+ }),
7619
+ declaration,
7620
+ strategies: strategies2
7621
+ };
7622
+ }
7623
+ )
7624
+ );
7625
+ return {
7626
+ deployments: deployments.sort(
7627
+ (left, right) => left.deploymentId.localeCompare(right.deploymentId)
7628
+ )
7629
+ };
7630
+ };
7631
+ var toRuntimeDeployment = ({
7632
+ composition,
7366
7633
  controls
7367
7634
  }) => {
7635
+ const { declaration, deploymentId } = composition;
7368
7636
  const deploymentEnabled = declaration.enabled ?? true;
7369
7637
  return {
7370
- id,
7371
- label: declaration.label?.trim() || id,
7638
+ id: deploymentId,
7639
+ deploymentCompositionId: composition.deploymentCompositionId,
7640
+ label: declaration.label?.trim() || deploymentId,
7372
7641
  connectorName: declaration.connectorName.trim(),
7373
7642
  provider: (declaration.provider || declaration.connectorName).trim().toLowerCase(),
7374
7643
  accountId: declaration.accountId.trim(),
7375
7644
  enabled: deploymentEnabled,
7376
- strategies: Object.entries(declaration.strategies).map(
7377
- ([strategyName, strategy]) => {
7378
- const selection = resolveStrategySelection({
7379
- deployment: declaration,
7380
- strategy
7381
- });
7382
- return {
7383
- strategyName,
7384
- version: strategy.version,
7385
- enabled: strategy.enabled,
7386
- controlState: deploymentEnabled && strategy.enabled && !controls.deployments[id]?.[strategyName]?.entriesPaused ? "active" : "entries_paused",
7387
- ...selection ? { selection } : {}
7388
- };
7389
- }
7390
- ),
7645
+ strategies: composition.strategies.map((strategy) => ({
7646
+ strategyName: strategy.strategyName,
7647
+ strategyRevision: strategy.strategyRevision,
7648
+ enabled: strategy.enabled,
7649
+ controlState: deploymentEnabled && strategy.enabled && !controls.deployments[deploymentId]?.[strategy.strategyName]?.entriesPaused ? "active" : "entries_paused",
7650
+ ...strategy.selection ? { selection: strategy.selection } : {}
7651
+ })),
7391
7652
  ...declaration.assetClasses ? { assetClasses: declaration.assetClasses } : {},
7392
7653
  ...declaration.tickers ? { tickers: declaration.tickers } : {}
7393
7654
  };
7394
7655
  };
7395
- var loadRuntimeDeclaration = async (projectRoot) => {
7396
- const projectConfig = await loadTradejsConfig(projectRoot);
7397
- if (!projectConfig.runtime) {
7398
- throw new Error("Runtime declaration is required in tradejs.config.ts");
7399
- }
7400
- return verifyRuntimeDeclaration(projectConfig.runtime);
7401
- };
7402
7656
  var listRuntimeDeployments = async ({
7403
7657
  userName,
7404
7658
  projectRoot
7405
7659
  }) => {
7406
- const [runtime, controls] = await Promise.all([
7407
- loadRuntimeDeclaration(projectRoot),
7660
+ const [composition, controls] = await Promise.all([
7661
+ resolveRuntimeComposition({ projectRoot }),
7408
7662
  (0, import_runtimeControls.getRuntimeControls)(userName)
7409
7663
  ]);
7410
- return Object.entries(runtime.deployments).map(
7411
- ([id, declaration]) => toRuntimeDeployment({ id, declaration, controls })
7664
+ return composition.deployments.map(
7665
+ (deploymentComposition) => toRuntimeDeployment({ composition: deploymentComposition, controls })
7412
7666
  ).sort((left, right) => left.label.localeCompare(right.label));
7413
7667
  };
7414
7668
  var resolveAccountId = async ({
@@ -7435,87 +7689,37 @@ var loadResolvedRuntimeStrategies = async ({
7435
7689
  accountId,
7436
7690
  interval
7437
7691
  }) => {
7438
- const [runtime, controls, packageManifest] = await Promise.all([
7439
- loadRuntimeDeclaration(projectRoot),
7440
- (0, import_runtimeControls.getRuntimeControls)(userName),
7441
- readPackageManifest(projectRoot)
7692
+ const [composition, controls] = await Promise.all([
7693
+ resolveRuntimeComposition({ projectRoot }),
7694
+ (0, import_runtimeControls.getRuntimeControls)(userName)
7442
7695
  ]);
7443
- const declaration = runtime.deployments[deploymentId];
7444
- if (!declaration) {
7696
+ const deploymentComposition = composition.deployments.find(
7697
+ (candidate) => candidate.deploymentId === deploymentId
7698
+ );
7699
+ if (!deploymentComposition) {
7445
7700
  throw new Error(`Runtime deployment not found: ${deploymentId}`);
7446
7701
  }
7447
7702
  const deployment = toRuntimeDeployment({
7448
- id: deploymentId,
7449
- declaration,
7703
+ composition: deploymentComposition,
7450
7704
  controls
7451
7705
  });
7452
7706
  const strategies2 = await Promise.all(
7453
- Object.entries(declaration.strategies).map(
7454
- async ([strategyName, strategyDeclaration]) => {
7455
- const strategyCreator = await getStrategyCreator(
7456
- strategyName,
7457
- projectRoot
7458
- );
7459
- if (!strategyCreator) {
7460
- throw new Error(`Unknown strategy: ${strategyName}`);
7461
- }
7462
- const pluginSource = await getStrategyPluginSource(strategyName, projectRoot) ?? null;
7463
- const strategyPackage = await resolveStrategyPackageName({
7464
- pluginSource,
7465
- projectRoot
7466
- });
7467
- const [strategyPackageVersion, runtimePackageVersion] = await Promise.all([
7468
- resolveInstalledPackageVersion(
7469
- projectRoot,
7470
- strategyPackage,
7471
- packageManifest
7472
- ),
7473
- resolveInstalledPackageVersion(
7474
- projectRoot,
7475
- "@tradejs/node",
7476
- packageManifest
7477
- )
7478
- ]);
7479
- if (!strategyPackage || !strategyPackageVersion) {
7480
- throw new Error(
7481
- `Installed strategy package not found: ${strategyName}`
7482
- );
7483
- }
7484
- if (!runtimePackageVersion) {
7485
- throw new Error("Installed @tradejs/node package version not found");
7486
- }
7487
- const strategyView = deployment.strategies.find(
7488
- (candidate) => candidate.strategyName === strategyName
7489
- );
7490
- const selection = resolveStrategySelection({
7491
- deployment: declaration,
7492
- strategy: strategyDeclaration
7493
- });
7494
- const strategyConfig = strategyDeclaration.config;
7495
- const strategyUniverse = strategyConfig.UNIVERSE;
7496
- const resolvedAccountId = await resolveAccountId({
7497
- userName,
7498
- deployment,
7499
- universe: strategyUniverse
7500
- });
7501
- return {
7502
- strategyName,
7503
- version: strategyDeclaration.version,
7504
- enabled: strategyDeclaration.enabled,
7505
- controlState: strategyView?.controlState ?? "entries_paused",
7506
- interval: String(strategyConfig.INTERVAL),
7507
- universe: strategyUniverse,
7508
- accountId: resolvedAccountId,
7509
- strategyPackage,
7510
- strategyPackageVersion,
7511
- runtimePackageVersion,
7512
- strategyCreator,
7513
- sourceStrategyConfig: strategyConfig,
7514
- strategyConfig,
7515
- ...selection ? { selection } : {}
7516
- };
7517
- }
7518
- )
7707
+ deploymentComposition.strategies.map(async (strategy) => {
7708
+ const strategyView = deployment.strategies.find(
7709
+ (candidate) => candidate.strategyName === strategy.strategyName
7710
+ );
7711
+ const resolvedAccountId = await resolveAccountId({
7712
+ userName,
7713
+ deployment,
7714
+ universe: strategy.universe
7715
+ });
7716
+ return {
7717
+ ...strategy,
7718
+ deploymentCompositionId: deploymentComposition.deploymentCompositionId,
7719
+ accountId: resolvedAccountId,
7720
+ controlState: strategyView?.controlState ?? "entries_paused"
7721
+ };
7722
+ })
7519
7723
  );
7520
7724
  const filtered = strategies2.filter(
7521
7725
  (candidate) => (!universe || candidate.universe === universe) && (!interval || String(candidate.interval) === String(interval)) && (!accountId || candidate.accountId === accountId)
@@ -7615,7 +7819,7 @@ var loadExchangeRange = async ({
7615
7819
  } catch (error) {
7616
7820
  const message = error?.message || String(error);
7617
7821
  errors?.push(`${label}: ${message}`);
7618
- import_logger15.logger.warn("strategies runtime: %s failed: %s", label, message);
7822
+ import_logger14.logger.warn("strategies runtime: %s failed: %s", label, message);
7619
7823
  return [];
7620
7824
  }
7621
7825
  };
@@ -7655,7 +7859,7 @@ var loadClosedPnlRows = async ({
7655
7859
  } catch (error) {
7656
7860
  const message = error?.message || String(error);
7657
7861
  errors?.push(`getClosedPnl: ${message}`);
7658
- import_logger15.logger.warn("strategies runtime: getClosedPnl failed: %s", message);
7862
+ import_logger14.logger.warn("strategies runtime: getClosedPnl failed: %s", message);
7659
7863
  return [];
7660
7864
  }
7661
7865
  };
@@ -7688,7 +7892,7 @@ var loadExchangeEntryRows = async ({
7688
7892
  } catch (error) {
7689
7893
  const message = error?.message || String(error);
7690
7894
  errors?.push(`getEntryExecutions: ${message}`);
7691
- import_logger15.logger.warn("strategies runtime: getEntryExecutions failed: %s", message);
7895
+ import_logger14.logger.warn("strategies runtime: getEntryExecutions failed: %s", message);
7692
7896
  return [];
7693
7897
  }
7694
7898
  };
@@ -7704,7 +7908,7 @@ var loadOpenPositions = async (connector, errors) => {
7704
7908
  } catch (error) {
7705
7909
  const message = error?.message || String(error);
7706
7910
  errors?.push(`getOpenPositionPnl: ${message}`);
7707
- import_logger15.logger.warn("strategies runtime: getOpenPositionPnl failed: %s", message);
7911
+ import_logger14.logger.warn("strategies runtime: getOpenPositionPnl failed: %s", message);
7708
7912
  return { positions: [], reliable: false };
7709
7913
  }
7710
7914
  };
@@ -7822,7 +8026,7 @@ var loadRuntimeDashboard = async ({
7822
8026
  );
7823
8027
  const runtimeIdentityKey = (trade) => (0, import_runtimeTrades3.buildRuntimeStrategyIdentityKey)({
7824
8028
  strategyName: trade.strategy,
7825
- configId: trade.runtimeVersion ? `v${trade.runtimeVersion}` : void 0,
8029
+ configId: trade.strategyRevision,
7826
8030
  universe: trade.universe,
7827
8031
  accountId: trade.accountId,
7828
8032
  deploymentId: trade.deploymentId,
@@ -7835,7 +8039,7 @@ var loadRuntimeDashboard = async ({
7835
8039
  ) ?? []) {
7836
8040
  const strategyUniverse = resolvedStrategy.universe;
7837
8041
  const strategyInterval = resolvedStrategy.interval;
7838
- const strategyConfigId = `v${resolvedStrategy.version}`;
8042
+ const strategyConfigId = resolvedStrategy.strategyRevision;
7839
8043
  const strategyPolicyProfileId = typeof resolvedStrategy.strategyConfig.POLICY_PROFILE_ID === "string" ? resolvedStrategy.strategyConfig.POLICY_PROFILE_ID : void 0;
7840
8044
  const runtimeKey = (0, import_runtimeTrades3.buildRuntimeStrategyIdentityKey)({
7841
8045
  strategyName: resolvedStrategy.strategyName,
@@ -7848,7 +8052,7 @@ var loadRuntimeDashboard = async ({
7848
8052
  identityByKey.set(runtimeKey, {
7849
8053
  strategyName: resolvedStrategy.strategyName,
7850
8054
  configId: strategyConfigId,
7851
- version: resolvedStrategy.version,
8055
+ strategyRevision: resolvedStrategy.strategyRevision,
7852
8056
  controlState: resolvedStrategy.controlState,
7853
8057
  interval: strategyInterval,
7854
8058
  universe: strategyUniverse,
@@ -7868,8 +8072,8 @@ var loadRuntimeDashboard = async ({
7868
8072
  const key = runtimeIdentityKey(trade);
7869
8073
  const configuredIdentity = identityByKey.get(key);
7870
8074
  if (!configuredIdentity) continue;
7871
- const version = trade.runtimeVersion ?? (trade.runtimeLineage?.schemaVersion === 2 ? trade.runtimeLineage.version : void 0);
7872
- if (version !== configuredIdentity.version) continue;
8075
+ const strategyRevision = trade.strategyRevision ?? (trade.runtimeLineage?.schemaVersion === 3 ? trade.runtimeLineage.strategyRevision : void 0);
8076
+ if (strategyRevision !== configuredIdentity.strategyRevision) continue;
7873
8077
  identityByKey.set(key, {
7874
8078
  ...configuredIdentity,
7875
8079
  interval: String(
@@ -7896,7 +8100,7 @@ var loadRuntimeDashboard = async ({
7896
8100
  runtimeKey,
7897
8101
  strategyName,
7898
8102
  configId: identity.configId,
7899
- version: identity.version,
8103
+ strategyRevision: identity.strategyRevision,
7900
8104
  controlState: identity.controlState,
7901
8105
  interval: identity.interval,
7902
8106
  universe: identity.universe,