@tradejs/cli 3.1.2 → 3.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -13668,8 +13668,7 @@ var init_runnerCore = __esm({
13668
13668
  };
13669
13669
  validateBacktestRuntimeDeployment = ({
13670
13670
  deployment,
13671
- deploymentId,
13672
- requestedInterval
13671
+ deploymentId
13673
13672
  }) => {
13674
13673
  if (deploymentId && !deployment) {
13675
13674
  throw new Error(`Runtime deployment not found: ${deploymentId}`);
@@ -13677,18 +13676,12 @@ var init_runnerCore = __esm({
13677
13676
  if (deployment && !deployment.enabled) {
13678
13677
  throw new Error(`Runtime deployment is disabled: ${deployment.id}`);
13679
13678
  }
13680
- if (deployment && String(deployment.interval) !== String(requestedInterval)) {
13681
- throw new Error(
13682
- `Deployment ${deployment.id} requires timeframe ${deployment.interval}; received ${requestedInterval}`
13683
- );
13684
- }
13685
13679
  return deployment;
13686
13680
  };
13687
13681
  prepareRunEnvironment2 = async () => {
13688
13682
  const deployment = validateBacktestRuntimeDeployment({
13689
13683
  deployment: flags5.deployment ? await (0, import_runtimeDeployments.getRuntimeDeployment)(userName, String(flags5.deployment)) : null,
13690
- deploymentId: typeof flags5.deployment === "string" ? flags5.deployment : void 0,
13691
- requestedInterval: interval
13684
+ deploymentId: typeof flags5.deployment === "string" ? flags5.deployment : void 0
13692
13685
  });
13693
13686
  const preparedRun = await prepareRunEnvironment({
13694
13687
  connector: deployment?.connectorName ?? flags5.connector,
@@ -13703,7 +13696,7 @@ var init_runnerCore = __esm({
13703
13696
  cacheOnly: flags5.cacheOnly,
13704
13697
  interval,
13705
13698
  projectRoot: projectRoot3,
13706
- universe: deployment?.universe ?? marketUniverse,
13699
+ universe: marketUniverse,
13707
13700
  accountId: deployment?.accountId ?? flags5.account,
13708
13701
  deploymentId: deployment?.id,
13709
13702
  assetClasses: deployment?.assetClasses,
@@ -14409,15 +14402,7 @@ var init_backtest = __esm({
14409
14402
  preparedRun.connectorName,
14410
14403
  interval
14411
14404
  ).map((test) => {
14412
- const deploymentStrategy = preparedRun.deployment?.strategies.find(
14413
- ({ strategyName }) => strategyName === config2.strategyName
14414
- );
14415
- if (deploymentStrategy?.enabled === false) {
14416
- throw new Error(
14417
- `Strategy ${config2.strategyName} is disabled in deployment ${preparedRun.deployment?.id}`
14418
- );
14419
- }
14420
- const policyProfileId = (typeof flags5.policyProfile === "string" && flags5.policyProfile.trim() ? flags5.policyProfile.trim() : deploymentStrategy?.policyProfileId) || void 0;
14405
+ const policyProfileId = (typeof flags5.policyProfile === "string" && flags5.policyProfile.trim() ? flags5.policyProfile.trim() : void 0) || void 0;
14421
14406
  return {
14422
14407
  ...test,
14423
14408
  instrument: preparedRun.instrumentsBySymbol.get(
@@ -14429,7 +14414,6 @@ var init_backtest = __esm({
14429
14414
  policyProfileId,
14430
14415
  strategyConfig: {
14431
14416
  ...test.strategyConfig,
14432
- ...deploymentStrategy?.config,
14433
14417
  ...policyProfileId ? { POLICY_PROFILE_ID: policyProfileId } : {}
14434
14418
  }
14435
14419
  };
@@ -28101,23 +28085,35 @@ var init_runtimeScorecard2 = __esm({
28101
28085
  // src/scripts/runtimeConfig.ts
28102
28086
  var runtimeConfig_exports = {};
28103
28087
  __export(runtimeConfig_exports, {
28104
- buildBootstrapRuntimeDeployment: () => buildBootstrapRuntimeDeployment,
28088
+ RUNTIME_CONFIG_ACTIONS: () => RUNTIME_CONFIG_ACTIONS,
28089
+ buildProvisionedRuntimeDeployment: () => buildProvisionedRuntimeDeployment,
28090
+ isEquivalentRuntimeStrategyRelease: () => isEquivalentRuntimeStrategyRelease,
28105
28091
  main: () => main37,
28092
+ pointRuntimeDeploymentAtRelease: () => pointRuntimeDeploymentAtRelease,
28106
28093
  runtimeConfig: () => runtimeConfig
28107
28094
  });
28108
- var import_config9, import_promises28, import_node_path23, import_runtimeDeployments2, import_runtimeStrategyConfigs2, import_runtimeStrategyReleases, import_runtimeStrategies, import_strategies11, argv, action, option, hasFlag, required2, projectRoot12, userName2, OPERATIONAL_CONFIG_KEYS, toReleaseConfig, writeMigrationBackup, publish, buildBootstrapRuntimeDeployment, bootstrap, migrate, publishDraft, updateControlState, rollback, verify, inspect, runtimeConfig, main37;
28095
+ var import_config9, import_promises28, import_node_path23, import_node_util2, import_runtimeDeployments2, import_runtimeStrategyReleases, import_runtimeStrategies, import_strategies11, argv, RUNTIME_CONFIG_ACTIONS, action, option, hasFlag, required2, projectRoot12, userName2, OPERATIONAL_CONFIG_KEYS, requireRuntimePackageIdentity, toReleaseConfig, publish, buildProvisionedRuntimeDeployment, isEquivalentRuntimeStrategyRelease, pointRuntimeDeploymentAtRelease, provision, rollout, updateControlState, rollback, verify, inspect, runtimeConfig, main37;
28109
28096
  var init_runtimeConfig = __esm({
28110
28097
  "src/scripts/runtimeConfig.ts"() {
28111
28098
  "use strict";
28112
28099
  import_config9 = require("dotenv/config");
28113
28100
  import_promises28 = require("fs/promises");
28114
28101
  import_node_path23 = __toESM(require("path"));
28102
+ import_node_util2 = require("util");
28115
28103
  import_runtimeDeployments2 = require("@tradejs/infra/runtimeDeployments");
28116
- import_runtimeStrategyConfigs2 = require("@tradejs/infra/runtimeStrategyConfigs");
28117
28104
  import_runtimeStrategyReleases = require("@tradejs/infra/runtimeStrategyReleases");
28118
28105
  import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
28119
28106
  import_strategies11 = require("@tradejs/node/strategies");
28120
28107
  argv = process.argv.slice(2);
28108
+ RUNTIME_CONFIG_ACTIONS = [
28109
+ "inspect",
28110
+ "verify",
28111
+ "provision",
28112
+ "rollout",
28113
+ "pause",
28114
+ "resume",
28115
+ "rollback"
28116
+ ];
28121
28117
  action = argv[0] ?? "inspect";
28122
28118
  option = (name) => {
28123
28119
  const index = argv.indexOf(`--${name}`);
@@ -28138,28 +28134,26 @@ var init_runtimeConfig = __esm({
28138
28134
  "ENABLE",
28139
28135
  "ENV",
28140
28136
  "MAKE_ORDERS",
28141
- "RECORD_RUNTIME_TRADES",
28142
- "configId"
28137
+ "RECORD_RUNTIME_TRADES"
28143
28138
  ];
28139
+ requireRuntimePackageIdentity = (strategyName, metadata) => {
28140
+ if (!metadata.strategyPackage || !metadata.strategyPackageVersion || !metadata.runtimePackageVersion) {
28141
+ throw new Error(
28142
+ `Runtime package manifest is incomplete for ${strategyName}`
28143
+ );
28144
+ }
28145
+ return {
28146
+ strategyPackage: metadata.strategyPackage,
28147
+ strategyPackageVersion: metadata.strategyPackageVersion,
28148
+ runtimePackageVersion: metadata.runtimePackageVersion
28149
+ };
28150
+ };
28144
28151
  toReleaseConfig = async (strategyName, sourceConfig) => {
28145
28152
  const defaults = await (0, import_strategies11.getStrategyDefaults)(strategyName, projectRoot12) ?? {};
28146
28153
  const config2 = { ...defaults, ...sourceConfig };
28147
28154
  for (const key of OPERATIONAL_CONFIG_KEYS) delete config2[key];
28148
28155
  return config2;
28149
28156
  };
28150
- writeMigrationBackup = async (payload) => {
28151
- const directory = import_node_path23.default.join(projectRoot12, "data", "runtime-config-backups");
28152
- await (0, import_promises28.mkdir)(directory, { recursive: true });
28153
- const backupPath = import_node_path23.default.join(
28154
- directory,
28155
- `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`
28156
- );
28157
- await (0, import_promises28.writeFile)(backupPath, `${JSON.stringify(payload, null, 2)}
28158
- `, {
28159
- flag: "wx"
28160
- });
28161
- return backupPath;
28162
- };
28163
28157
  publish = async ({
28164
28158
  strategyName,
28165
28159
  sourceConfig
@@ -28169,31 +28163,29 @@ var init_runtimeConfig = __esm({
28169
28163
  strategyName,
28170
28164
  projectRoot: projectRoot12
28171
28165
  });
28166
+ const packageIdentity = requireRuntimePackageIdentity(strategyName, metadata);
28172
28167
  return (0, import_runtimeStrategyReleases.publishRuntimeStrategyRelease)({
28173
28168
  userName: userName2,
28174
28169
  strategyName,
28175
28170
  config: config2,
28176
- ...metadata,
28171
+ ...packageIdentity,
28177
28172
  createdBy: `cli:${userName2}`
28178
28173
  });
28179
28174
  };
28180
- buildBootstrapRuntimeDeployment = ({
28175
+ buildProvisionedRuntimeDeployment = ({
28181
28176
  deploymentId,
28182
28177
  label,
28183
28178
  connectorName,
28184
28179
  provider,
28185
28180
  accountId,
28186
28181
  strategyName,
28187
- releaseVersion,
28188
- config: config2
28182
+ releaseVersion
28189
28183
  }) => ({
28190
28184
  id: deploymentId,
28191
28185
  label,
28192
28186
  connectorName,
28193
28187
  provider,
28194
28188
  accountId,
28195
- universe: config2.UNIVERSE,
28196
- interval: String(config2.INTERVAL),
28197
28189
  enabled: true,
28198
28190
  strategies: [
28199
28191
  {
@@ -28203,7 +28195,30 @@ var init_runtimeConfig = __esm({
28203
28195
  }
28204
28196
  ]
28205
28197
  });
28206
- bootstrap = async () => {
28198
+ isEquivalentRuntimeStrategyRelease = ({
28199
+ release,
28200
+ config: config2,
28201
+ strategyPackage,
28202
+ strategyPackageVersion,
28203
+ runtimePackageVersion
28204
+ }) => Boolean(
28205
+ release && (0, import_node_util2.isDeepStrictEqual)(release.config, config2) && release.strategyPackage === strategyPackage && release.strategyPackageVersion === strategyPackageVersion && release.runtimePackageVersion === runtimePackageVersion
28206
+ );
28207
+ pointRuntimeDeploymentAtRelease = ({
28208
+ deployment,
28209
+ strategyName,
28210
+ releaseVersion
28211
+ }) => ({
28212
+ ...deployment,
28213
+ strategies: deployment.strategies.map(
28214
+ (strategy) => strategy.strategyName === strategyName ? {
28215
+ strategyName,
28216
+ releaseVersion,
28217
+ controlState: "entries_paused"
28218
+ } : strategy
28219
+ )
28220
+ });
28221
+ provision = async () => {
28207
28222
  const strategyName = required2("strategy");
28208
28223
  const deploymentId = required2("deployment");
28209
28224
  const accountId = required2("account");
@@ -28221,15 +28236,14 @@ var init_runtimeConfig = __esm({
28221
28236
  );
28222
28237
  }
28223
28238
  const releaseConfig = await toReleaseConfig(strategyName, sourceConfig);
28224
- const previewDeployment = buildBootstrapRuntimeDeployment({
28239
+ const previewDeployment = buildProvisionedRuntimeDeployment({
28225
28240
  deploymentId,
28226
28241
  label,
28227
28242
  connectorName,
28228
28243
  provider,
28229
28244
  accountId,
28230
28245
  strategyName,
28231
- releaseVersion: 1,
28232
- config: releaseConfig
28246
+ releaseVersion: 1
28233
28247
  });
28234
28248
  if (!hasFlag("write")) {
28235
28249
  console.log(
@@ -28251,102 +28265,103 @@ var init_runtimeConfig = __esm({
28251
28265
  );
28252
28266
  return;
28253
28267
  }
28254
- const backupPath = await writeMigrationBackup({
28255
- userName: userName2,
28256
- capturedAt: Date.now(),
28257
- reason: "bootstrap",
28258
- sourceConfig
28259
- });
28260
28268
  const release = await publish({ strategyName, sourceConfig });
28261
28269
  const deployment = await (0, import_runtimeDeployments2.saveRuntimeDeployment)(
28262
28270
  userName2,
28263
- buildBootstrapRuntimeDeployment({
28271
+ buildProvisionedRuntimeDeployment({
28264
28272
  deploymentId,
28265
28273
  label,
28266
28274
  connectorName,
28267
28275
  provider,
28268
28276
  accountId,
28269
28277
  strategyName,
28270
- releaseVersion: release.releaseVersion,
28271
- config: release.config
28278
+ releaseVersion: release.releaseVersion
28272
28279
  })
28273
28280
  );
28274
28281
  console.log(
28275
- JSON.stringify(
28276
- { bootstrapped: true, backupPath, release, deployment },
28277
- null,
28278
- 2
28279
- )
28282
+ JSON.stringify({ provisioned: true, release, deployment }, null, 2)
28280
28283
  );
28281
28284
  };
28282
- migrate = async () => {
28285
+ rollout = async () => {
28283
28286
  const strategyName = required2("strategy");
28284
- const configId = option("config") ?? "config";
28285
28287
  const deploymentId = required2("deployment");
28286
- const [sourceConfig, deployment] = await Promise.all([
28287
- (0, import_runtimeStrategyConfigs2.getRuntimeStrategyConfig)(userName2, strategyName, configId),
28288
- (0, import_runtimeDeployments2.getRuntimeDeployment)(userName2, deploymentId)
28288
+ const configFile = import_node_path23.default.resolve(projectRoot12, required2("file"));
28289
+ const [deployment, sourceConfig] = await Promise.all([
28290
+ (0, import_runtimeDeployments2.getRuntimeDeployment)(userName2, deploymentId),
28291
+ (0, import_promises28.readFile)(configFile, "utf8").then(
28292
+ (value) => JSON.parse(value)
28293
+ )
28289
28294
  ]);
28290
- if (!sourceConfig) {
28291
- throw new Error(`Legacy config not found: ${strategyName}:${configId}`);
28292
- }
28293
28295
  if (!deployment) throw new Error(`Deployment not found: ${deploymentId}`);
28294
28296
  const reference = deployment.strategies.find(
28295
28297
  (strategy) => strategy.strategyName === strategyName
28296
28298
  );
28297
- if (!reference) {
28299
+ if (!reference)
28298
28300
  throw new Error(`${strategyName} is not bound to ${deploymentId}`);
28299
- }
28301
+ const [config2, metadata, currentRelease] = await Promise.all([
28302
+ toReleaseConfig(strategyName, sourceConfig),
28303
+ (0, import_runtimeStrategies.getRuntimeStrategyPackageMetadata)({ strategyName, projectRoot: projectRoot12 }),
28304
+ (0, import_runtimeStrategyReleases.getRuntimeStrategyRelease)(userName2, strategyName, reference.releaseVersion)
28305
+ ]);
28306
+ const packageIdentity = requireRuntimePackageIdentity(strategyName, metadata);
28307
+ const unchanged = isEquivalentRuntimeStrategyRelease({
28308
+ release: currentRelease,
28309
+ config: config2,
28310
+ ...packageIdentity
28311
+ });
28300
28312
  const preview = {
28301
- source: { configId, config: sourceConfig },
28302
- releaseConfig: await toReleaseConfig(strategyName, sourceConfig),
28303
- deployment: {
28304
- id: deployment.id,
28305
- accountId: deployment.accountId,
28306
- strategy: {
28307
- strategyName,
28308
- releaseVersion: "<allocated on write>",
28309
- controlState: "entries_paused"
28310
- }
28311
- }
28313
+ deploymentId,
28314
+ strategyName,
28315
+ currentReleaseVersion: reference.releaseVersion,
28316
+ nextControlState: "entries_paused",
28317
+ unchanged,
28318
+ config: config2,
28319
+ ...packageIdentity
28312
28320
  };
28313
28321
  if (!hasFlag("write")) {
28314
28322
  console.log(JSON.stringify({ dryRun: true, ...preview }, null, 2));
28315
28323
  return;
28316
28324
  }
28317
- const backupPath = await writeMigrationBackup({
28325
+ if (unchanged) {
28326
+ console.log(
28327
+ JSON.stringify(
28328
+ {
28329
+ rolledOut: false,
28330
+ reason: "release_config_and_packages_unchanged",
28331
+ release: currentRelease,
28332
+ deployment
28333
+ },
28334
+ null,
28335
+ 2
28336
+ )
28337
+ );
28338
+ return;
28339
+ }
28340
+ const release = await (0, import_runtimeStrategyReleases.publishRuntimeStrategyRelease)({
28318
28341
  userName: userName2,
28319
- capturedAt: Date.now(),
28342
+ strategyName,
28343
+ config: config2,
28344
+ ...packageIdentity,
28345
+ createdBy: `cli:${userName2}`
28346
+ });
28347
+ const updatedDeployment = pointRuntimeDeploymentAtRelease({
28320
28348
  deployment,
28321
- legacyConfig: sourceConfig
28349
+ strategyName,
28350
+ releaseVersion: release.releaseVersion
28322
28351
  });
28323
- const release = await publish({ strategyName, sourceConfig });
28324
- const updatedDeployment = {
28325
- ...deployment,
28326
- strategies: deployment.strategies.map(
28327
- (strategy) => strategy.strategyName === strategyName ? {
28328
- strategyName,
28329
- releaseVersion: release.releaseVersion,
28330
- controlState: "entries_paused"
28331
- } : strategy
28332
- )
28333
- };
28334
28352
  await (0, import_runtimeDeployments2.saveRuntimeDeployment)(userName2, updatedDeployment);
28335
28353
  console.log(
28336
28354
  JSON.stringify(
28337
- { migrated: true, backupPath, release, deployment: updatedDeployment },
28355
+ {
28356
+ rolledOut: true,
28357
+ release,
28358
+ deployment: updatedDeployment
28359
+ },
28338
28360
  null,
28339
28361
  2
28340
28362
  )
28341
28363
  );
28342
28364
  };
28343
- publishDraft = async () => {
28344
- const strategyName = required2("strategy");
28345
- const draft = await (0, import_runtimeStrategyReleases.getRuntimeStrategyDraft)(userName2, strategyName);
28346
- if (!draft) throw new Error(`Draft not found: ${strategyName}`);
28347
- const release = await publish({ strategyName, sourceConfig: draft.config });
28348
- console.log(JSON.stringify({ release }, null, 2));
28349
- };
28350
28365
  updateControlState = async (nextState) => {
28351
28366
  const strategyName = required2("strategy");
28352
28367
  const deploymentId = required2("deployment");
@@ -28355,10 +28370,9 @@ var init_runtimeConfig = __esm({
28355
28370
  const reference = deployment.strategies.find(
28356
28371
  (strategy) => strategy.strategyName === strategyName
28357
28372
  );
28358
- if (!reference?.releaseVersion) {
28359
- throw new Error(`${strategyName} is not a versioned deployment reference`);
28360
- }
28361
- const previousState = reference.controlState ?? "active";
28373
+ if (!reference)
28374
+ throw new Error(`${strategyName} is not bound to ${deploymentId}`);
28375
+ const previousState = reference.controlState;
28362
28376
  const updated = await (0, import_runtimeDeployments2.saveRuntimeDeployment)(userName2, {
28363
28377
  ...deployment,
28364
28378
  strategies: deployment.strategies.map(
@@ -28388,12 +28402,6 @@ var init_runtimeConfig = __esm({
28388
28402
  const release = (await (0, import_runtimeStrategyReleases.listRuntimeStrategyReleases)(userName2, strategyName)).find((candidate) => candidate.releaseVersion === releaseVersion);
28389
28403
  if (!release)
28390
28404
  throw new Error(`Release not found: ${strategyName} v${releaseVersion}`);
28391
- const backupPath = await writeMigrationBackup({
28392
- userName: userName2,
28393
- capturedAt: Date.now(),
28394
- deployment,
28395
- reason: "rollback"
28396
- });
28397
28405
  const updated = await (0, import_runtimeDeployments2.saveRuntimeDeployment)(userName2, {
28398
28406
  ...deployment,
28399
28407
  strategies: deployment.strategies.map(
@@ -28404,7 +28412,7 @@ var init_runtimeConfig = __esm({
28404
28412
  } : strategy
28405
28413
  )
28406
28414
  });
28407
- console.log(JSON.stringify({ backupPath, deployment: updated }, null, 2));
28415
+ console.log(JSON.stringify({ deployment: updated }, null, 2));
28408
28416
  };
28409
28417
  verify = async () => {
28410
28418
  const deployments = await (0, import_runtimeDeployments2.listRuntimeDeployments)(userName2);
@@ -28415,8 +28423,7 @@ var init_runtimeConfig = __esm({
28415
28423
  const strategies = await (0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({
28416
28424
  userName: userName2,
28417
28425
  projectRoot: projectRoot12,
28418
- deployment,
28419
- connectorName: deployment.connectorName
28426
+ deployment
28420
28427
  });
28421
28428
  results2.push({
28422
28429
  deploymentId: deployment.id,
@@ -28448,16 +28455,15 @@ var init_runtimeConfig = __esm({
28448
28455
  console.log(JSON.stringify({ userName: userName2, deployments, releases }, null, 2));
28449
28456
  };
28450
28457
  runtimeConfig = async () => {
28451
- if (action === "bootstrap") return bootstrap();
28452
- if (action === "migrate") return migrate();
28453
- if (action === "publish-draft") return publishDraft();
28458
+ if (action === "provision") return provision();
28459
+ if (action === "rollout") return rollout();
28454
28460
  if (action === "verify") return verify();
28455
28461
  if (action === "pause") return updateControlState("entries_paused");
28456
28462
  if (action === "resume") return updateControlState("active");
28457
28463
  if (action === "rollback") return rollback();
28458
28464
  if (action === "inspect") return inspect();
28459
28465
  throw new Error(
28460
- "Usage: tradejs runtime-config inspect|verify|bootstrap|migrate|publish-draft|pause|resume|rollback"
28466
+ `Usage: tradejs runtime-config ${RUNTIME_CONFIG_ACTIONS.join("|")}`
28461
28467
  );
28462
28468
  };
28463
28469
  main37 = runtimeConfig;
@@ -32057,18 +32063,15 @@ var init_tickerEvaluator = __esm({
32057
32063
  for (const runtimeStrategy of runtimeStrategies) {
32058
32064
  const {
32059
32065
  strategyName,
32060
- configId,
32061
32066
  releaseVersion,
32062
32067
  controlState,
32063
32068
  strategyPackageVersion,
32064
32069
  runtimePackageVersion,
32065
32070
  strategyCreator,
32066
32071
  sourceStrategyConfig,
32067
- strategyConfig,
32068
- strategyResults
32072
+ strategyConfig
32069
32073
  } = runtimeStrategy;
32070
- const runtimeIdentity = releaseVersion ? `v${releaseVersion}` : configId ?? "config";
32071
- const symbolResultConfig = strategyResults?.[symbol]?.config ?? null;
32074
+ const runtimeIdentity = `v${releaseVersion}`;
32072
32075
  const runtimeConfig2 = buildRuntimeModeStrategyConfig({
32073
32076
  strategyConfig,
32074
32077
  env: "CRON",
@@ -32081,7 +32084,7 @@ var init_tickerEvaluator = __esm({
32081
32084
  releaseVersion,
32082
32085
  strategyPackageVersion,
32083
32086
  runtimePackageVersion,
32084
- config: { configId, strategyConfig, symbolResultConfig },
32087
+ config: { strategyConfig },
32085
32088
  runContext: {
32086
32089
  connectorName: connectorName.toLowerCase(),
32087
32090
  interval: String(interval4),
@@ -32109,7 +32112,7 @@ var init_tickerEvaluator = __esm({
32109
32112
  evaluation = await lifecycle.evaluate({
32110
32113
  key: lifecycleKey,
32111
32114
  timestamp: lastCandle.timestamp,
32112
- config: { runtimeConfig: runtimeConfig2, sourceStrategyConfig, symbolResultConfig },
32115
+ config: { runtimeConfig: runtimeConfig2, sourceStrategyConfig },
32113
32116
  btcBinanceData,
32114
32117
  btcCoinbaseData,
32115
32118
  onRuntimeClose: (event) => runtimeCloseNotifications.push(event),
@@ -32120,13 +32123,12 @@ var init_tickerEvaluator = __esm({
32120
32123
  }) => strategyCreator({
32121
32124
  userName: userName3,
32122
32125
  connectorName,
32123
- runtimeConfigId: configId,
32126
+ runtimeConfigId: runtimeIdentity,
32124
32127
  runtimeReleaseVersion: releaseVersion,
32125
32128
  entriesPaused: controlState === "entries_paused",
32126
32129
  runtimeLineage,
32127
32130
  runtimeConfigSnapshot: {
32128
- userConfig: sourceStrategyConfig,
32129
- symbolResultConfig
32131
+ userConfig: sourceStrategyConfig
32130
32132
  },
32131
32133
  connector,
32132
32134
  symbol,
@@ -32176,12 +32178,12 @@ var init_tickerEvaluator = __esm({
32176
32178
  strategyName,
32177
32179
  symbol,
32178
32180
  timestamp: lastCandle.timestamp,
32179
- runtimeConfigId: configId,
32181
+ runtimeConfigId: runtimeIdentity,
32180
32182
  runtimeReleaseVersion: releaseVersion
32181
32183
  }),
32182
32184
  userName: userName3,
32183
32185
  strategy: strategyName,
32184
- runtimeConfigId: configId,
32186
+ runtimeConfigId: runtimeIdentity,
32185
32187
  runtimeReleaseVersion: releaseVersion,
32186
32188
  runtimeLineage,
32187
32189
  symbol,
@@ -32199,12 +32201,9 @@ var init_tickerEvaluator = __esm({
32199
32201
  continue;
32200
32202
  }
32201
32203
  if (stats) stats.signals += 1;
32202
- signal.runtimeConfigId = configId;
32204
+ signal.runtimeConfigId = runtimeIdentity;
32203
32205
  signal.runtimeReleaseVersion = releaseVersion;
32204
32206
  signal.runtimeLineage = runtimeLineage;
32205
- if (configId && configId !== "config" && !signal.signalId.endsWith(`:${configId}`)) {
32206
- signal.signalId = `${signal.signalId}:${configId}`;
32207
- }
32208
32207
  if (releaseVersion && !signal.signalId.endsWith(`:v${releaseVersion}`)) {
32209
32208
  signal.signalId = `${signal.signalId}:v${releaseVersion}`;
32210
32209
  }
@@ -32224,12 +32223,12 @@ var init_tickerEvaluator = __esm({
32224
32223
  strategyName,
32225
32224
  symbol,
32226
32225
  timestamp: lastCandle.timestamp,
32227
- runtimeConfigId: configId,
32226
+ runtimeConfigId: runtimeIdentity,
32228
32227
  runtimeReleaseVersion: releaseVersion
32229
32228
  }),
32230
32229
  userName: userName3,
32231
32230
  strategy: strategyName,
32232
- runtimeConfigId: configId,
32231
+ runtimeConfigId: runtimeIdentity,
32233
32232
  runtimeReleaseVersion: releaseVersion,
32234
32233
  runtimeLineage,
32235
32234
  symbol,
@@ -32338,15 +32337,12 @@ var init_runner = __esm({
32338
32337
  ].join("\n");
32339
32338
  const resolveSignalsConnectorName = async (value) => {
32340
32339
  const connectorName = await (0, import_connectors16.resolveConnectorName)(value, projectRoot15);
32341
- if (connectorName) {
32342
- return connectorName;
32340
+ if (!connectorName) {
32341
+ throw new Error(
32342
+ `Unknown runtime connector: ${String(value || "").trim() || String(value)}`
32343
+ );
32343
32344
  }
32344
- import_logger10.logger.warn(
32345
- 'Unknown connector "%s". Fallback to %s.',
32346
- String(value || "").trim() || String(value),
32347
- import_connectors16.DEFAULT_CONNECTOR_NAME
32348
- );
32349
- return import_connectors16.DEFAULT_CONNECTOR_NAME;
32345
+ return connectorName;
32350
32346
  };
32351
32347
  const createSignalsSession2 = async (lifecycle, scope = {}) => {
32352
32348
  const deployment = config2.deploymentId ? await (0, import_runtimeDeployments3.getRuntimeDeployment)(config2.userName, config2.deploymentId) : null;
@@ -32357,25 +32353,15 @@ var init_runner = __esm({
32357
32353
  throw new Error(`Runtime deployment is disabled: ${deployment.id}`);
32358
32354
  }
32359
32355
  const requestedRuntimeInterval = scope.interval ?? interval4;
32360
- const versionedDeployment = Boolean(
32361
- deployment?.strategies.some(
32362
- (strategy) => strategy.releaseVersion != null
32363
- )
32364
- );
32365
- const runtimeInterval = versionedDeployment ? requestedRuntimeInterval : deployment?.interval ?? requestedRuntimeInterval;
32356
+ const runtimeInterval = requestedRuntimeInterval;
32366
32357
  const runtimeIntervalMs = Number(runtimeInterval) * 6e4;
32367
32358
  if (!Number.isFinite(runtimeIntervalMs) || runtimeIntervalMs <= 0) {
32368
32359
  throw new Error(`Invalid runtime timeframe: ${runtimeInterval}`);
32369
32360
  }
32370
- if (deployment && !versionedDeployment && String(deployment.interval) !== String(requestedRuntimeInterval)) {
32371
- throw new Error(
32372
- `Deployment ${deployment.id} requires timeframe ${deployment.interval}; received ${requestedRuntimeInterval}`
32373
- );
32374
- }
32375
32361
  const connectorName = await resolveSignalsConnectorName(
32376
32362
  deployment?.connectorName ?? scope.connectorName ?? config2.connectorName
32377
32363
  );
32378
- const universe = versionedDeployment ? scope.universe ?? config2.universe : deployment?.universe ?? scope.universe ?? config2.universe;
32364
+ const universe = scope.universe ?? config2.universe;
32379
32365
  const requestedAccountId = deployment?.accountId ?? scope.accountId ?? config2.accountId;
32380
32366
  const connectorFactory = await (0, import_connectors16.getConnectorCreatorByName)(
32381
32367
  connectorName,
@@ -32587,7 +32573,6 @@ var init_runner = __esm({
32587
32573
  userName: config2.userName,
32588
32574
  projectRoot: projectRoot15,
32589
32575
  deployment,
32590
- connectorName,
32591
32576
  universe,
32592
32577
  accountId,
32593
32578
  interval: interval5
@@ -32595,8 +32580,8 @@ var init_runner = __esm({
32595
32580
  if (!runtimeStrategies.length) {
32596
32581
  lifecycle.clear();
32597
32582
  import_logger10.logger.warn(
32598
- "No strategy configs found by users:%s:strategies:*:config",
32599
- config2.userName
32583
+ "No strategy releases are bound to deployment %s",
32584
+ deployment?.id
32600
32585
  );
32601
32586
  return;
32602
32587
  }
@@ -32604,7 +32589,7 @@ var init_runner = __esm({
32604
32589
  new Set(
32605
32590
  tickers.flatMap(
32606
32591
  (symbol) => runtimeStrategies.map(
32607
- ({ strategyName, configId, releaseVersion }) => buildSignalsStrategyLifecycleKey({
32592
+ ({ strategyName, releaseVersion }) => buildSignalsStrategyLifecycleKey({
32608
32593
  connectorName,
32609
32594
  universe: sessionUniverse,
32610
32595
  accountId,
@@ -32612,7 +32597,7 @@ var init_runner = __esm({
32612
32597
  symbol,
32613
32598
  interval: interval5,
32614
32599
  strategyName,
32615
- configId: releaseVersion ? `v${releaseVersion}` : configId
32600
+ configId: `v${releaseVersion}`
32616
32601
  })
32617
32602
  )
32618
32603
  )
@@ -32801,11 +32786,10 @@ var init_runner = __esm({
32801
32786
  const configuredStrategies = await (0, import_runtimeStrategies2.loadResolvedRuntimeStrategies)({
32802
32787
  userName: config2.userName,
32803
32788
  projectRoot: projectRoot15,
32804
- deployment,
32805
- connectorName: config2.connectorName
32789
+ deployment
32806
32790
  });
32807
32791
  const connectorName = await resolveSignalsConnectorName(
32808
- deployment?.connectorName ?? config2.connectorName
32792
+ deployment.connectorName
32809
32793
  );
32810
32794
  const scopes = /* @__PURE__ */ new Map();
32811
32795
  for (const strategy of configuredStrategies) {
@@ -32824,13 +32808,18 @@ var init_runner = __esm({
32824
32808
  }
32825
32809
  return scopes;
32826
32810
  };
32827
- const hasExplicitSignalsScope = () => Boolean(config2.hasExplicitScope);
32828
32811
  const signalsConfiguredScopesOnce2 = async () => {
32829
- if (config2.updateOnly || config2.showTickersList || hasExplicitSignalsScope()) {
32812
+ if (config2.updateOnly || config2.showTickersList) {
32830
32813
  return signals2();
32831
32814
  }
32832
- const configuredDeployment = config2.deploymentId ? await (0, import_runtimeDeployments3.getRuntimeDeployment)(config2.userName, config2.deploymentId) : null;
32833
- if (config2.deploymentId && !configuredDeployment) {
32815
+ if (!config2.deploymentId) {
32816
+ throw new Error("Runtime deployment id is required");
32817
+ }
32818
+ const configuredDeployment = await (0, import_runtimeDeployments3.getRuntimeDeployment)(
32819
+ config2.userName,
32820
+ config2.deploymentId
32821
+ );
32822
+ if (!configuredDeployment) {
32834
32823
  throw new Error(`Runtime deployment not found: ${config2.deploymentId}`);
32835
32824
  }
32836
32825
  const scopes = await loadConfiguredSignalsScopes(configuredDeployment);
@@ -32855,8 +32844,14 @@ var init_runner = __esm({
32855
32844
  );
32856
32845
  }
32857
32846
  const abortController = new AbortController();
32858
- const daemonDeployment = config2.deploymentId ? await (0, import_runtimeDeployments3.getRuntimeDeployment)(config2.userName, config2.deploymentId) : null;
32859
- if (config2.deploymentId && !daemonDeployment) {
32847
+ if (!config2.deploymentId) {
32848
+ throw new Error("Runtime deployment id is required");
32849
+ }
32850
+ const daemonDeployment = await (0, import_runtimeDeployments3.getRuntimeDeployment)(
32851
+ config2.userName,
32852
+ config2.deploymentId
32853
+ );
32854
+ if (!daemonDeployment) {
32860
32855
  throw new Error(`Runtime deployment not found: ${config2.deploymentId}`);
32861
32856
  }
32862
32857
  const sessions = /* @__PURE__ */ new Map();
@@ -32869,10 +32864,7 @@ var init_runner = __esm({
32869
32864
  const stopOnSigterm = () => stop("SIGTERM");
32870
32865
  process.once("SIGINT", stopOnSigint);
32871
32866
  process.once("SIGTERM", stopOnSigterm);
32872
- import_logger10.logger.info(
32873
- "signals daemon started (config-driven scopes, fallback interval=%s)",
32874
- interval4
32875
- );
32867
+ import_logger10.logger.info("signals daemon started (deployment-driven scopes)");
32876
32868
  try {
32877
32869
  await runSignalsDaemon({
32878
32870
  intervalMs: 6e4,
@@ -32985,7 +32977,7 @@ __export(signals_exports, {
32985
32977
  signalsConfiguredScopesOnce: () => signalsConfiguredScopesOnce,
32986
32978
  signalsDaemon: () => signalsDaemon
32987
32979
  });
32988
- var import_config12, import_args31, flags29, hasExplicitScope, config, runner, createSignalsSession, signals, signalsConfiguredScopesOnce, signalsDaemon, main41;
32980
+ var import_config12, import_args31, flags29, config, runner, createSignalsSession, signals, signalsConfiguredScopesOnce, signalsDaemon, main41;
32989
32981
  var init_signals = __esm({
32990
32982
  "src/scripts/signals.ts"() {
32991
32983
  "use strict";
@@ -33029,11 +33021,6 @@ var init_signals = __esm({
33029
33021
  import_args31.default.option(["A", "account"], "Trading account id");
33030
33022
  import_args31.default.option(["D", "deployment"], "Runtime deployment id");
33031
33023
  flags29 = import_args31.default.parse(process.argv);
33032
- hasExplicitScope = process.argv.some(
33033
- (argument) => ["-f", "--timeframe", "-V", "--universe", "-A", "--account"].some(
33034
- (option2) => argument === option2 || argument.startsWith(`${option2}=`)
33035
- )
33036
- );
33037
33024
  config = {
33038
33025
  projectRoot: String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd(),
33039
33026
  userName: String(flags29.user || "root"),
@@ -33055,8 +33042,7 @@ var init_signals = __esm({
33055
33042
  showSkipStats: Boolean(flags29.showSkipStats),
33056
33043
  parallel: flags29.parallel,
33057
33044
  watch: Boolean(flags29.watch),
33058
- settleDelayMs: flags29.settleDelayMs,
33059
- hasExplicitScope
33045
+ settleDelayMs: flags29.settleDelayMs
33060
33046
  };
33061
33047
  runner = createSignalsRunner(config);
33062
33048
  createSignalsSession = runner.createSession;
@@ -37134,7 +37120,7 @@ var init_signalsSummary = __esm({
37134
37120
  for (const trade of trades) {
37135
37121
  const deployment = trade.deploymentId ? deploymentById.get(trade.deploymentId) : void 0;
37136
37122
  const connectorName = deployment?.connectorName ?? fallbackConnectorName;
37137
- const universe = trade.universe ?? deployment?.universe ?? "crypto";
37123
+ const universe = trade.universe ?? "crypto";
37138
37124
  const accountId = trade.accountId ?? deployment?.accountId;
37139
37125
  const deploymentId = trade.deploymentId;
37140
37126
  const scopeKey = JSON.stringify([