@tradejs/cli 3.0.1 → 3.1.1

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.
@@ -44,10 +44,10 @@ var import_chalk7 = __toESM(require("chalk"));
44
44
  var import_connectors6 = require("@tradejs/node/connectors");
45
45
  var import_cli2 = require("@tradejs/node/cli");
46
46
  var import_async3 = require("@tradejs/core/async");
47
- var import_strategies6 = require("@tradejs/core/strategies");
47
+ var import_strategies5 = require("@tradejs/core/strategies");
48
48
  var import_constants3 = require("@tradejs/core/constants");
49
- var import_time3 = require("@tradejs/core/time");
50
- var import_logger5 = require("@tradejs/infra/logger");
49
+ var import_time2 = require("@tradejs/core/time");
50
+ var import_logger4 = require("@tradejs/infra/logger");
51
51
  var import_runtimeDeployments = require("@tradejs/infra/runtimeDeployments");
52
52
 
53
53
  // src/lib/marketData/windows.ts
@@ -3735,125 +3735,15 @@ var updateBtcReferenceHistory = async ({
3735
3735
  };
3736
3736
 
3737
3737
  // src/lib/signals/runtimeStrategies.ts
3738
- var import_logger = require("@tradejs/infra/logger");
3739
- var import_redis2 = require("@tradejs/infra/redis");
3740
- var import_tradingAccounts = require("@tradejs/infra/tradingAccounts");
3741
- var import_strategies3 = require("@tradejs/node/strategies");
3742
-
3743
- // src/lib/runtimeRedis.ts
3744
- var import_redis = require("@tradejs/infra/redis");
3745
- var import_time = require("@tradejs/core/time");
3746
- var import_runtimeStrategyConfigs = require("@tradejs/infra/runtimeStrategyConfigs");
3747
- var isRuntimeStrategyEnabled = (strategyConfig) => {
3748
- const enabled = strategyConfig.ENABLE;
3749
- return enabled !== false;
3750
- };
3751
-
3752
- // src/lib/signals/runtimeStrategies.ts
3753
- var loadRuntimeStrategies = async ({
3754
- userName,
3755
- projectRoot,
3756
- deployment,
3757
- connectorName = "bybit",
3758
- universe,
3759
- accountId,
3760
- interval
3761
- }) => {
3762
- const deploymentStrategies = new Map(
3763
- (deployment?.strategies ?? []).map((strategy) => [
3764
- strategy.strategyName,
3765
- strategy
3766
- ])
3767
- );
3768
- const strategyConfigs = await Promise.all(
3769
- (await (0, import_runtimeStrategyConfigs.loadRuntimeStrategyConfigs)(userName)).map(
3770
- async ({
3771
- key,
3772
- strategyName,
3773
- configId,
3774
- strategyConfig
3775
- }) => {
3776
- const deploymentStrategy = deployment ? deploymentStrategies.get(strategyName) : void 0;
3777
- if (deploymentStrategy?.enabled === false) {
3778
- import_logger.logger.info(
3779
- "Skip deployment-disabled strategy config: %s",
3780
- strategyName
3781
- );
3782
- return null;
3783
- }
3784
- if (!isRuntimeStrategyEnabled(strategyConfig)) {
3785
- import_logger.logger.info(
3786
- "Skip inactive strategy config by ENABLE=false: %s",
3787
- strategyName
3788
- );
3789
- return null;
3790
- }
3791
- const configUniverse = deployment?.universe ?? (strategyConfig.UNIVERSE === "tradfi" ? "tradfi" : "crypto");
3792
- const configInterval = String(
3793
- deployment?.interval ?? strategyConfig.INTERVAL ?? "15"
3794
- );
3795
- const requestedAccountId = deployment?.accountId ?? (typeof strategyConfig.ACCOUNT_ID === "string" && strategyConfig.ACCOUNT_ID.trim() ? strategyConfig.ACCOUNT_ID.trim() : void 0);
3796
- const resolvedAccount = await (0, import_tradingAccounts.resolveTradingAccount)({
3797
- userName,
3798
- accountId: requestedAccountId,
3799
- provider: deployment?.provider ?? connectorName,
3800
- universe: configUniverse
3801
- });
3802
- const effectiveAccountId = resolvedAccount?.id ?? requestedAccountId;
3803
- const [strategyCreator, strategyResults] = await Promise.all([
3804
- (0, import_strategies3.getStrategyCreator)(strategyName, projectRoot),
3805
- (0, import_redis2.getData)(import_redis2.redisKeys.strategyResults(userName, strategyName), {})
3806
- ]);
3807
- if (!strategyCreator) {
3808
- import_logger.logger.warn("Skip unknown strategy config key: %s", key);
3809
- return null;
3810
- }
3811
- return {
3812
- strategyName,
3813
- configId,
3814
- interval: configInterval,
3815
- universe: configUniverse,
3816
- accountId: effectiveAccountId,
3817
- releaseCompositionId: deploymentStrategy?.releaseCompositionId,
3818
- strategyCreator,
3819
- sourceStrategyConfig: strategyConfig,
3820
- strategyConfig: {
3821
- ...strategyConfig,
3822
- ...deploymentStrategy?.config,
3823
- INTERVAL: configInterval,
3824
- UNIVERSE: configUniverse,
3825
- ...effectiveAccountId ? { ACCOUNT_ID: effectiveAccountId } : {},
3826
- ...deploymentStrategy?.policyProfileId ? { POLICY_PROFILE_ID: deploymentStrategy.policyProfileId } : {}
3827
- },
3828
- strategyResults: strategyResults ?? {}
3829
- };
3830
- }
3831
- )
3832
- );
3833
- const active = strategyConfigs.filter(Boolean);
3834
- const byStrategyAndAccount = /* @__PURE__ */ new Map();
3835
- for (const candidate of active) {
3836
- const conflictKey = `${candidate.strategyName}:${candidate.accountId ?? "default"}`;
3837
- const existing = byStrategyAndAccount.get(conflictKey);
3838
- if (existing) {
3839
- throw new Error(
3840
- `Runtime strategy conflict: ${candidate.strategyName} configs "${existing.configId}" and "${candidate.configId}" resolve to account "${candidate.accountId ?? "default"}". Disable one config or select another account.`
3841
- );
3842
- }
3843
- byStrategyAndAccount.set(conflictKey, candidate);
3844
- }
3845
- return active.filter(
3846
- (candidate) => (!universe || candidate.universe === universe) && (!interval || String(candidate.interval) === String(interval)) && (!accountId || candidate.accountId === accountId)
3847
- );
3848
- };
3738
+ var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
3849
3739
 
3850
3740
  // src/lib/signals/skipStats.ts
3851
3741
  var import_chalk6 = __toESM(require("chalk"));
3852
- var import_logger2 = require("@tradejs/infra/logger");
3742
+ var import_logger = require("@tradejs/infra/logger");
3853
3743
 
3854
3744
  // src/lib/runtimeSignalsStorage.ts
3855
3745
  var import_constants2 = require("@tradejs/core/constants");
3856
- var import_time2 = require("@tradejs/core/time");
3746
+ var import_time = require("@tradejs/core/time");
3857
3747
  var SECONDS_PER_DAY = 86400;
3858
3748
  var RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
3859
3749
  var DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants2.TTL_3D;
@@ -3879,7 +3769,8 @@ var toRuntimeSignalBucketRef = (signal) => ({
3879
3769
  symbol: signal.symbol,
3880
3770
  strategy: signal.strategy,
3881
3771
  timestamp: signal.timestamp,
3882
- ...signal.runtimeConfigId && signal.runtimeConfigId !== "config" ? { runtimeConfigId: signal.runtimeConfigId } : {}
3772
+ ...signal.runtimeConfigId && signal.runtimeConfigId !== "config" ? { runtimeConfigId: signal.runtimeConfigId } : {},
3773
+ ...signal.runtimeReleaseVersion ? { runtimeReleaseVersion: signal.runtimeReleaseVersion } : {}
3883
3774
  });
3884
3775
  var shouldStoreRuntimeSignalDiagnostics = (signal) => signal.orderStatus === "completed" || signal.orderStatus === "failed";
3885
3776
  var toStoredRuntimeSignal = (signal) => {
@@ -3978,30 +3869,30 @@ var recordStrategyReason = (strategyStats, strategyName, reason, fallbackSource
3978
3869
  );
3979
3870
  };
3980
3871
  var logStrategySkipStats = (runtimeStrategies, strategyStats) => {
3981
- import_logger2.logger.info(import_chalk6.default.yellow("skip stats:"));
3872
+ import_logger.logger.info(import_chalk6.default.yellow("skip stats:"));
3982
3873
  for (const { strategyName } of runtimeStrategies) {
3983
3874
  const stats = strategyStats.get(strategyName);
3984
3875
  if (!stats) {
3985
3876
  continue;
3986
3877
  }
3987
- import_logger2.logger.info(
3878
+ import_logger.logger.info(
3988
3879
  `${strategyName}: evaluated=${stats.evaluated}, signals=${stats.signals}`
3989
3880
  );
3990
3881
  const sortedReasons = [...stats.reasons.entries()].sort(
3991
3882
  (left, right) => right[1] - left[1] || left[0].localeCompare(right[0])
3992
3883
  );
3993
3884
  if (!sortedReasons.length) {
3994
- import_logger2.logger.info(" none");
3885
+ import_logger.logger.info(" none");
3995
3886
  continue;
3996
3887
  }
3997
3888
  for (const [reason, count] of sortedReasons) {
3998
- import_logger2.logger.info(` ${reason}: ${count}`);
3889
+ import_logger.logger.info(` ${reason}: ${count}`);
3999
3890
  }
4000
3891
  }
4001
3892
  };
4002
3893
 
4003
3894
  // src/lib/signals/evaluations.ts
4004
- var import_redis3 = require("@tradejs/infra/redis");
3895
+ var import_redis = require("@tradejs/infra/redis");
4005
3896
 
4006
3897
  // src/lib/runtimeLineage.ts
4007
3898
  var import_node_child_process = require("child_process");
@@ -4009,33 +3900,42 @@ var import_node_crypto2 = require("crypto");
4009
3900
  var import_promises2 = __toESM(require("fs/promises"));
4010
3901
  var import_node_path2 = __toESM(require("path"));
4011
3902
  var import_types = require("@tradejs/types");
4012
- var import_strategies4 = require("@tradejs/node/strategies");
3903
+ var import_strategies3 = require("@tradejs/node/strategies");
4013
3904
  var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
4014
3905
 
4015
3906
  // src/lib/strategyGateFingerprint.ts
4016
3907
  var import_node_crypto = require("crypto");
3908
+ var import_node_module = require("module");
4017
3909
  var import_promises = __toESM(require("fs/promises"));
4018
3910
  var import_node_path = __toESM(require("path"));
4019
- var gateFingerprintRelativePaths = (strategyName) => [
4020
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
4021
- `packages/strategies/src/${strategyName}/guardrails.ts`,
4022
- `packages/strategies/src/${strategyName}/pockets.ts`,
4023
- `packages/strategies/src/${strategyName}/config.ts`,
4024
- "packages/strategies/src/shared/localAiGate.ts",
4025
- "packages/node/src/ai.ts",
4026
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
3911
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
3912
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
3913
+ var gateFingerprintSpecifiers = (strategyName) => [
3914
+ getStrategyPackageName(strategyName),
3915
+ "@tradejs/strategy-kit/ai-gate",
3916
+ "@tradejs/node/ai",
3917
+ "@tradejs/core/strategies"
4027
3918
  ];
4028
3919
  var resolveStrategyGateFingerprint = async ({
4029
3920
  projectRoot,
4030
3921
  strategyName,
4031
3922
  gitSha
4032
3923
  }) => {
4033
- const candidates = await Promise.all(
4034
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
4035
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
4036
- return content == null ? null : { relativePath, content };
3924
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
3925
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
3926
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
3927
+ const candidates = requireFromProject ? await Promise.all(
3928
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
3929
+ let resolvedPath;
3930
+ try {
3931
+ resolvedPath = requireFromProject.resolve(specifier);
3932
+ } catch {
3933
+ return null;
3934
+ }
3935
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
3936
+ return content == null ? null : { specifier, content };
4037
3937
  })
4038
- );
3938
+ ) : [];
4039
3939
  const sourceEntries = candidates.filter(
4040
3940
  (entry) => entry != null
4041
3941
  );
@@ -4043,7 +3943,7 @@ var resolveStrategyGateFingerprint = async ({
4043
3943
  hash.update(strategyName);
4044
3944
  if (sourceEntries.length) {
4045
3945
  for (const entry of sourceEntries) {
4046
- hash.update(entry.relativePath);
3946
+ hash.update(entry.specifier);
4047
3947
  hash.update(entry.content);
4048
3948
  }
4049
3949
  } else {
@@ -4051,7 +3951,7 @@ var resolveStrategyGateFingerprint = async ({
4051
3951
  }
4052
3952
  return {
4053
3953
  gateFingerprint: hash.digest("hex").slice(0, 16),
4054
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
3954
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
4055
3955
  };
4056
3956
  };
4057
3957
 
@@ -4230,20 +4130,35 @@ var resolveRuntimeGateFingerprint = async ({
4230
4130
  gateFingerprintCache.set(cacheKey, result);
4231
4131
  return result;
4232
4132
  };
4233
- var buildRuntimeLineage = async ({
4133
+ async function buildRuntimeLineage({
4234
4134
  projectRoot,
4235
4135
  strategyName,
4236
4136
  compositionId,
4137
+ releaseVersion,
4138
+ strategyPackageVersion,
4139
+ runtimePackageVersion,
4237
4140
  config: config2,
4238
4141
  runContext,
4239
4142
  env = process.env
4240
- }) => {
4143
+ }) {
4144
+ if (releaseVersion != null) {
4145
+ if (!Number.isSafeInteger(releaseVersion) || releaseVersion <= 0) {
4146
+ throw new Error(`Invalid runtime releaseVersion: ${releaseVersion}`);
4147
+ }
4148
+ return {
4149
+ schemaVersion: 2,
4150
+ releaseVersion,
4151
+ strategyPackageVersion,
4152
+ runtimePackageVersion,
4153
+ maxLossValue: resolveRuntimeMaxLossValue(config2)
4154
+ };
4155
+ }
4241
4156
  const git = resolveGitLineage(projectRoot);
4242
- const hyperliquidPerpUniverseFingerprint = typeof import_strategies4.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies4.getHyperliquidPerpUniverseSnapshot)().fingerprint : await resolveSnapshotFingerprint(
4157
+ const hyperliquidPerpUniverseFingerprint = typeof import_strategies3.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies3.getHyperliquidPerpUniverseSnapshot)().fingerprint : await resolveSnapshotFingerprint(
4243
4158
  projectRoot,
4244
4159
  "packages/node/src/config/hyperliquidPerpUniverse.json"
4245
4160
  );
4246
- const hyperliquidWhaleRegistryFingerprint = typeof import_strategies4.getHyperliquidWhaleRegistrySnapshot === "function" ? (0, import_strategies4.getHyperliquidWhaleRegistrySnapshot)().fingerprint : await resolveSnapshotFingerprint(
4161
+ const hyperliquidWhaleRegistryFingerprint = typeof import_strategies3.getHyperliquidWhaleRegistrySnapshot === "function" ? (0, import_strategies3.getHyperliquidWhaleRegistrySnapshot)().fingerprint : await resolveSnapshotFingerprint(
4247
4162
  projectRoot,
4248
4163
  "packages/node/src/config/hyperliquidWhales.json"
4249
4164
  );
@@ -4272,8 +4187,8 @@ var buildRuntimeLineage = async ({
4272
4187
  contextFingerprint: fingerprintRuntimeValue(context),
4273
4188
  maxLossValue: resolveRuntimeMaxLossValue(config2)
4274
4189
  };
4275
- };
4276
- var runtimeLineageKey = (lineage) => [
4190
+ }
4191
+ var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.releaseVersion].join(":") : [
4277
4192
  lineage.schemaVersion,
4278
4193
  lineage.compositionId ?? "unbound-composition",
4279
4194
  lineage.gitSha ?? "unknown",
@@ -4291,11 +4206,13 @@ var buildRuntimeSignalEvaluationId = ({
4291
4206
  strategyName,
4292
4207
  symbol,
4293
4208
  timestamp,
4294
- runtimeConfigId
4295
- }) => runtimeConfigId && runtimeConfigId !== "config" ? [strategyName, runtimeConfigId, symbol, timestamp].join(":") : [strategyName, symbol, timestamp].join(":");
4209
+ runtimeConfigId,
4210
+ runtimeReleaseVersion
4211
+ }) => runtimeReleaseVersion ? [strategyName, `v${runtimeReleaseVersion}`, symbol, timestamp].join(":") : runtimeConfigId && runtimeConfigId !== "config" ? [strategyName, runtimeConfigId, symbol, timestamp].join(":") : [strategyName, symbol, timestamp].join(":");
4296
4212
  var buildLineageField = (scope) => [
4297
4213
  scope.strategy,
4298
4214
  scope.runtimeConfigId ?? "config",
4215
+ scope.runtimeReleaseVersion ? `v${scope.runtimeReleaseVersion}` : "legacy",
4299
4216
  scope.symbol,
4300
4217
  runtimeLineageKey(scope.lineage)
4301
4218
  ].join(":");
@@ -4303,7 +4220,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4303
4220
  if (evaluations.length === 0) return;
4304
4221
  const evaluationsByDay = /* @__PURE__ */ new Map();
4305
4222
  for (const evaluation of evaluations) {
4306
- const dayKey = (0, import_time2.getRuntimeStorageDayKey)(evaluation.timestamp);
4223
+ const dayKey = (0, import_time.getRuntimeStorageDayKey)(evaluation.timestamp);
4307
4224
  const dayEvaluations = evaluationsByDay.get(dayKey) ?? [];
4308
4225
  dayEvaluations.push(evaluation);
4309
4226
  evaluationsByDay.set(dayKey, dayEvaluations);
@@ -4315,7 +4232,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4315
4232
  runtimeLineageScopeCacheDayKey = dayKey;
4316
4233
  runtimeLineageScopeCacheLoaded = false;
4317
4234
  }
4318
- const lineageBucket = import_redis3.redisKeys.runtimeLineageScopeBucket(
4235
+ const lineageBucket = import_redis.redisKeys.runtimeLineageScopeBucket(
4319
4236
  dayEvaluations[0].userName,
4320
4237
  dayKey
4321
4238
  );
@@ -4323,7 +4240,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4323
4240
  (evaluation) => evaluation.runtimeLineage != null
4324
4241
  );
4325
4242
  if (lineageEvaluations.length > 0 && !runtimeLineageScopeCacheLoaded) {
4326
- const storedScopes = await (0, import_redis3.getHashJsonValues)(lineageBucket);
4243
+ const storedScopes = await (0, import_redis.getHashJsonValues)(lineageBucket);
4327
4244
  for (const scope of storedScopes) {
4328
4245
  const lineageField = buildLineageField(scope);
4329
4246
  runtimeLineageScopeCache.set(`${lineageBucket}:${lineageField}`, scope);
@@ -4335,6 +4252,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4335
4252
  const lineageField = buildLineageField({
4336
4253
  strategy: evaluation.strategy,
4337
4254
  runtimeConfigId: evaluation.runtimeConfigId,
4255
+ runtimeReleaseVersion: evaluation.runtimeReleaseVersion,
4338
4256
  symbol: evaluation.symbol,
4339
4257
  lineage: evaluation.runtimeLineage
4340
4258
  });
@@ -4344,6 +4262,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4344
4262
  strategy: evaluation.strategy,
4345
4263
  symbol: evaluation.symbol,
4346
4264
  runtimeConfigId: evaluation.runtimeConfigId,
4265
+ runtimeReleaseVersion: evaluation.runtimeReleaseVersion,
4347
4266
  lineage: evaluation.runtimeLineage,
4348
4267
  firstTimestamp: Math.min(
4349
4268
  existing?.firstTimestamp ?? evaluation.timestamp,
@@ -4358,7 +4277,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4358
4277
  lineageWrites.set(lineageField, scope);
4359
4278
  }
4360
4279
  if (lineageWrites.size > 0) {
4361
- await (0, import_redis3.setHashJsonFields)(
4280
+ await (0, import_redis.setHashJsonFields)(
4362
4281
  lineageBucket,
4363
4282
  [...lineageWrites].map(([field, data]) => ({ field, data })),
4364
4283
  {
@@ -4370,7 +4289,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4370
4289
  const statsIncrements = /* @__PURE__ */ new Map();
4371
4290
  for (const evaluation of dayEvaluations) {
4372
4291
  if (shouldStoreDetailedRuntimeSignalEvaluation(evaluation)) {
4373
- const bucket = import_redis3.redisKeys.runtimeSignalEvaluationBucket(
4292
+ const bucket = import_redis.redisKeys.runtimeSignalEvaluationBucket(
4374
4293
  evaluation.userName,
4375
4294
  dayKey,
4376
4295
  evaluation.strategy
@@ -4382,7 +4301,7 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4382
4301
  });
4383
4302
  detailedWrites.set(bucket, entries);
4384
4303
  }
4385
- const statsBucket = import_redis3.redisKeys.runtimeSignalEvaluationStatsBucket(
4304
+ const statsBucket = import_redis.redisKeys.runtimeSignalEvaluationStatsBucket(
4386
4305
  evaluation.userName,
4387
4306
  dayKey,
4388
4307
  evaluation.strategy
@@ -4397,12 +4316,12 @@ var flushRuntimeSignalEvaluations = async (evaluations) => {
4397
4316
  }
4398
4317
  await Promise.all([
4399
4318
  ...[...detailedWrites].map(
4400
- ([bucket, entries]) => (0, import_redis3.setHashJsonFields)(bucket, entries, {
4319
+ ([bucket, entries]) => (0, import_redis.setHashJsonFields)(bucket, entries, {
4401
4320
  expire: runtimeSignalRetentionTtl
4402
4321
  })
4403
4322
  ),
4404
4323
  ...[...statsIncrements].map(
4405
- ([bucket, increments]) => (0, import_redis3.incrHashFields)(bucket, increments, {
4324
+ ([bucket, increments]) => (0, import_redis.incrHashFields)(bucket, increments, {
4406
4325
  expire: runtimeSignalRetentionTtl
4407
4326
  })
4408
4327
  )
@@ -4418,9 +4337,9 @@ var createRuntimeSignalEvaluationBuffer = () => {
4418
4337
  const runtimeSignalRetentionTtl = getRuntimeSignalRetentionTtlSeconds();
4419
4338
  const signalRefsByBucket = /* @__PURE__ */ new Map();
4420
4339
  for (const { userName, signal } of pendingSignals) {
4421
- const bucket = import_redis3.redisKeys.runtimeSignalBucket(
4340
+ const bucket = import_redis.redisKeys.runtimeSignalBucket(
4422
4341
  userName,
4423
- (0, import_time2.getRuntimeStorageDayKey)(signal.timestamp),
4342
+ (0, import_time.getRuntimeStorageDayKey)(signal.timestamp),
4424
4343
  signal.strategy
4425
4344
  );
4426
4345
  const entries = signalRefsByBucket.get(bucket) ?? [];
@@ -4432,14 +4351,14 @@ var createRuntimeSignalEvaluationBuffer = () => {
4432
4351
  }
4433
4352
  await Promise.all([
4434
4353
  ...pendingSignals.map(
4435
- ({ signal }) => (0, import_redis3.setData)(
4436
- import_redis3.redisKeys.storeSignal(signal.symbol, signal.signalId),
4354
+ ({ signal }) => (0, import_redis.setData)(
4355
+ import_redis.redisKeys.storeSignal(signal.symbol, signal.signalId),
4437
4356
  toStoredRuntimeSignal(signal),
4438
4357
  { expire: runtimeSignalRetentionTtl }
4439
4358
  )
4440
4359
  ),
4441
4360
  ...[...signalRefsByBucket].map(
4442
- ([bucket, entries]) => (0, import_redis3.setHashJsonFields)(bucket, entries, {
4361
+ ([bucket, entries]) => (0, import_redis.setHashJsonFields)(bucket, entries, {
4443
4362
  expire: runtimeSignalRetentionTtl
4444
4363
  })
4445
4364
  )
@@ -4673,14 +4592,14 @@ var runSignalsDaemon = async ({
4673
4592
 
4674
4593
  // src/lib/signals/klineFeed.ts
4675
4594
  var import_connectors5 = require("@tradejs/connectors");
4676
- var import_logger3 = require("@tradejs/infra/logger");
4595
+ var import_logger2 = require("@tradejs/infra/logger");
4677
4596
  var import_candles = require("@tradejs/infra/timescale/candles");
4678
4597
 
4679
4598
  // src/lib/marketData/klineEvents.ts
4680
4599
  var import_ioredis = __toESM(require("ioredis"));
4681
- var import_redis4 = require("@tradejs/infra/redis");
4600
+ var import_redis2 = require("@tradejs/infra/redis");
4682
4601
  var MARKET_KLINE_CHANNEL = "tradejs:market:kline";
4683
- var publishMarketKlineEvent = (event) => (0, import_redis4.publishData)(MARKET_KLINE_CHANNEL, event);
4602
+ var publishMarketKlineEvent = (event) => (0, import_redis2.publishData)(MARKET_KLINE_CHANNEL, event);
4684
4603
 
4685
4604
  // src/lib/signals/klineFeed.ts
4686
4605
  var FLUSH_DELAY_MS = 100;
@@ -4734,7 +4653,7 @@ var createSignalsKlineFeed = async ({
4734
4653
  if (flushTimer || closed) return;
4735
4654
  flushTimer = setTimeout(() => {
4736
4655
  void flush().catch(
4737
- (error) => import_logger3.logger.error("websocket candle batch flush failed: %s", String(error))
4656
+ (error) => import_logger2.logger.error("websocket candle batch flush failed: %s", String(error))
4738
4657
  );
4739
4658
  }, FLUSH_DELAY_MS);
4740
4659
  };
@@ -4751,7 +4670,7 @@ var createSignalsKlineFeed = async ({
4751
4670
  confirm: event.confirm,
4752
4671
  receivedAt: event.receivedAt
4753
4672
  }).catch(
4754
- (error) => import_logger3.logger.warn("websocket candle publish failed: %s", String(error))
4673
+ (error) => import_logger2.logger.warn("websocket candle publish failed: %s", String(error))
4755
4674
  );
4756
4675
  if (!event.confirm) return;
4757
4676
  pending.set(`${event.symbol}:${event.candle.timestamp}`, {
@@ -4804,8 +4723,8 @@ var createSignalsKlineFeed = async ({
4804
4723
  };
4805
4724
 
4806
4725
  // src/lib/signals/tickerEvaluator.ts
4807
- var import_strategies5 = require("@tradejs/node/strategies");
4808
- var import_logger4 = require("@tradejs/infra/logger");
4726
+ var import_strategies4 = require("@tradejs/node/strategies");
4727
+ var import_logger3 = require("@tradejs/infra/logger");
4809
4728
 
4810
4729
  // src/lib/runtimeModeConfig.ts
4811
4730
  var buildRuntimeModeStrategyConfig = ({
@@ -4819,7 +4738,7 @@ var buildRuntimeModeStrategyConfig = ({
4819
4738
  ...strategyConfig,
4820
4739
  ENV: env,
4821
4740
  MAKE_ORDERS: makeOrders,
4822
- INTERVAL: interval,
4741
+ INTERVAL: strategyConfig.INTERVAL ?? interval,
4823
4742
  ...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
4824
4743
  ...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
4825
4744
  });
@@ -4883,12 +4802,16 @@ var createSignalsTickerEvaluator = ({
4883
4802
  const {
4884
4803
  strategyName,
4885
4804
  configId,
4805
+ releaseVersion,
4806
+ controlState,
4807
+ strategyPackageVersion,
4808
+ runtimePackageVersion,
4886
4809
  strategyCreator,
4887
- releaseCompositionId,
4888
4810
  sourceStrategyConfig,
4889
4811
  strategyConfig,
4890
4812
  strategyResults
4891
4813
  } = runtimeStrategy;
4814
+ const runtimeIdentity = releaseVersion ? `v${releaseVersion}` : configId ?? "config";
4892
4815
  const symbolResultConfig = strategyResults?.[symbol]?.config ?? null;
4893
4816
  const runtimeConfig = buildRuntimeModeStrategyConfig({
4894
4817
  strategyConfig,
@@ -4899,7 +4822,9 @@ var createSignalsTickerEvaluator = ({
4899
4822
  const runtimeLineage = await buildRuntimeLineage({
4900
4823
  projectRoot,
4901
4824
  strategyName,
4902
- compositionId: releaseCompositionId,
4825
+ releaseVersion,
4826
+ strategyPackageVersion,
4827
+ runtimePackageVersion,
4903
4828
  config: { configId, strategyConfig, symbolResultConfig },
4904
4829
  runContext: {
4905
4830
  connectorName: connectorName.toLowerCase(),
@@ -4915,7 +4840,7 @@ var createSignalsTickerEvaluator = ({
4915
4840
  symbol,
4916
4841
  interval,
4917
4842
  strategyName,
4918
- configId
4843
+ configId: runtimeIdentity
4919
4844
  });
4920
4845
  const stats = strategyStats.get(strategyName);
4921
4846
  const initialLengths = [
@@ -4940,6 +4865,9 @@ var createSignalsTickerEvaluator = ({
4940
4865
  userName,
4941
4866
  connectorName,
4942
4867
  runtimeConfigId: configId,
4868
+ runtimeReleaseVersion: releaseVersion,
4869
+ entriesPaused: controlState === "entries_paused",
4870
+ runtimeLineage,
4943
4871
  runtimeConfigSnapshot: {
4944
4872
  userConfig: sourceStrategyConfig,
4945
4873
  symbolResultConfig
@@ -4973,7 +4901,7 @@ var createSignalsTickerEvaluator = ({
4973
4901
  continue;
4974
4902
  }
4975
4903
  if (evaluation.action.startsWith("rebuilt_")) {
4976
- import_logger4.logger.info(
4904
+ import_logger3.logger.info(
4977
4905
  "Rebuilt signals strategy state (%s): %s %s",
4978
4906
  evaluation.action.slice("rebuilt_".length),
4979
4907
  strategyName,
@@ -4992,11 +4920,13 @@ var createSignalsTickerEvaluator = ({
4992
4920
  strategyName,
4993
4921
  symbol,
4994
4922
  timestamp: lastCandle.timestamp,
4995
- runtimeConfigId: configId
4923
+ runtimeConfigId: configId,
4924
+ runtimeReleaseVersion: releaseVersion
4996
4925
  }),
4997
4926
  userName,
4998
4927
  strategy: strategyName,
4999
4928
  runtimeConfigId: configId,
4929
+ runtimeReleaseVersion: releaseVersion,
5000
4930
  runtimeLineage,
5001
4931
  symbol,
5002
4932
  interval,
@@ -5014,11 +4944,15 @@ var createSignalsTickerEvaluator = ({
5014
4944
  }
5015
4945
  if (stats) stats.signals += 1;
5016
4946
  signal.runtimeConfigId = configId;
4947
+ signal.runtimeReleaseVersion = releaseVersion;
5017
4948
  signal.runtimeLineage = runtimeLineage;
5018
4949
  if (configId && configId !== "config" && !signal.signalId.endsWith(`:${configId}`)) {
5019
4950
  signal.signalId = `${signal.signalId}:${configId}`;
5020
4951
  }
5021
- await (0, import_strategies5.enrichSignalWithBinanceMarketContext)({ signal, env: "CRON" });
4952
+ if (releaseVersion && !signal.signalId.endsWith(`:v${releaseVersion}`)) {
4953
+ signal.signalId = `${signal.signalId}:v${releaseVersion}`;
4954
+ }
4955
+ await (0, import_strategies4.enrichSignalWithBinanceMarketContext)({ signal, env: "CRON" });
5022
4956
  if (signal.orderStatus === "skipped" && typeof signal.orderSkipReason === "string" && signal.orderSkipReason.trim()) {
5023
4957
  recordStrategyReason(
5024
4958
  strategyStats,
@@ -5034,11 +4968,13 @@ var createSignalsTickerEvaluator = ({
5034
4968
  strategyName,
5035
4969
  symbol,
5036
4970
  timestamp: lastCandle.timestamp,
5037
- runtimeConfigId: configId
4971
+ runtimeConfigId: configId,
4972
+ runtimeReleaseVersion: releaseVersion
5038
4973
  }),
5039
4974
  userName,
5040
4975
  strategy: strategyName,
5041
4976
  runtimeConfigId: configId,
4977
+ runtimeReleaseVersion: releaseVersion,
5042
4978
  runtimeLineage,
5043
4979
  symbol,
5044
4980
  interval,
@@ -5058,7 +4994,7 @@ var createSignalsTickerEvaluator = ({
5058
4994
  ...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {},
5059
4995
  ...signal.ml ? { ml: signal.ml } : {}
5060
4996
  });
5061
- import_logger4.logger.info("Signal found %s by strategy %s", symbol, strategyName);
4997
+ import_logger3.logger.info("Signal found %s by strategy %s", symbol, strategyName);
5062
4998
  }
5063
4999
  return strategySignals;
5064
5000
  };
@@ -5101,12 +5037,12 @@ var createSignalsRunner = (config2) => {
5101
5037
  const createDefaultSignalsLifecycle = (runtimeInterval = interval) => createSignalsStrategyLifecycle({
5102
5038
  intervalMs: Number(runtimeInterval) * 6e4,
5103
5039
  maxLiveBars: resolveSignalsDaemonMaxLiveBars(runtimeInterval),
5104
- releaseState: import_strategies6.releaseStrategyReplayCache
5040
+ releaseState: import_strategies5.releaseStrategyReplayCache
5105
5041
  });
5106
5042
  const timeOperation2 = (label, operation) => timeOperation(
5107
5043
  label,
5108
5044
  operation,
5109
- (message) => import_logger5.logger.info(import_chalk7.default.gray(message))
5045
+ (message) => import_logger4.logger.info(import_chalk7.default.gray(message))
5110
5046
  );
5111
5047
  const formatSlowSignalsWarning = (params) => [
5112
5048
  "<b>Slow yarn signals run</b>",
@@ -5120,7 +5056,7 @@ var createSignalsRunner = (config2) => {
5120
5056
  if (connectorName) {
5121
5057
  return connectorName;
5122
5058
  }
5123
- import_logger5.logger.warn(
5059
+ import_logger4.logger.warn(
5124
5060
  'Unknown connector "%s". Fallback to %s.',
5125
5061
  String(value || "").trim() || String(value),
5126
5062
  import_connectors6.DEFAULT_CONNECTOR_NAME
@@ -5136,12 +5072,17 @@ var createSignalsRunner = (config2) => {
5136
5072
  throw new Error(`Runtime deployment is disabled: ${deployment.id}`);
5137
5073
  }
5138
5074
  const requestedRuntimeInterval = scope.interval ?? interval;
5139
- const runtimeInterval = deployment?.interval ?? requestedRuntimeInterval;
5075
+ const versionedDeployment = Boolean(
5076
+ deployment?.strategies.some(
5077
+ (strategy) => strategy.releaseVersion != null
5078
+ )
5079
+ );
5080
+ const runtimeInterval = versionedDeployment ? requestedRuntimeInterval : deployment?.interval ?? requestedRuntimeInterval;
5140
5081
  const runtimeIntervalMs = Number(runtimeInterval) * 6e4;
5141
5082
  if (!Number.isFinite(runtimeIntervalMs) || runtimeIntervalMs <= 0) {
5142
5083
  throw new Error(`Invalid runtime timeframe: ${runtimeInterval}`);
5143
5084
  }
5144
- if (deployment && String(deployment.interval) !== String(requestedRuntimeInterval)) {
5085
+ if (deployment && !versionedDeployment && String(deployment.interval) !== String(requestedRuntimeInterval)) {
5145
5086
  throw new Error(
5146
5087
  `Deployment ${deployment.id} requires timeframe ${deployment.interval}; received ${requestedRuntimeInterval}`
5147
5088
  );
@@ -5149,7 +5090,7 @@ var createSignalsRunner = (config2) => {
5149
5090
  const connectorName = await resolveSignalsConnectorName(
5150
5091
  deployment?.connectorName ?? scope.connectorName ?? config2.connectorName
5151
5092
  );
5152
- const universe = deployment?.universe ?? scope.universe ?? config2.universe;
5093
+ const universe = versionedDeployment ? scope.universe ?? config2.universe : deployment?.universe ?? scope.universe ?? config2.universe;
5153
5094
  const requestedAccountId = deployment?.accountId ?? scope.accountId ?? config2.accountId;
5154
5095
  const connectorFactory = await (0, import_connectors6.getConnectorCreatorByName)(
5155
5096
  connectorName,
@@ -5170,7 +5111,7 @@ var createSignalsRunner = (config2) => {
5170
5111
  userName: config2.userName,
5171
5112
  projectRoot,
5172
5113
  shouldUseDedicatedReferences: universe === "crypto" && connectorName.toLowerCase() === import_connectors6.DEFAULT_CONNECTOR_NAME.toLowerCase(),
5173
- warn: (message) => import_logger5.logger.warn(message)
5114
+ warn: (message) => import_logger4.logger.warn(message)
5174
5115
  });
5175
5116
  return {
5176
5117
  connectorName,
@@ -5241,8 +5182,8 @@ var createSignalsRunner = (config2) => {
5241
5182
  }
5242
5183
  const projectConfig = await (0, import_cli2.loadTradejsConfig)(projectRoot);
5243
5184
  projectHooks = projectConfig.hooks;
5244
- const currentTimestamp = (0, import_time3.getTimestamp)();
5245
- const preloadStart = (0, import_time3.getTimestamp)(import_constants3.SIGNALS_CLI_PRELOAD_DAYS);
5185
+ const currentTimestamp = (0, import_time2.getTimestamp)();
5186
+ const preloadStart = (0, import_time2.getTimestamp)(import_constants3.SIGNALS_CLI_PRELOAD_DAYS);
5246
5187
  if (!config2.cacheOnly && session.klineFeed) {
5247
5188
  const expectedSymbols = universe === "crypto" ? [.../* @__PURE__ */ new Set([...tickers, "BTCUSDT", "ETHUSDT"])] : tickers;
5248
5189
  session.klineFeed.setSubscriptions(expectedSymbols);
@@ -5256,7 +5197,7 @@ var createSignalsRunner = (config2) => {
5256
5197
  })
5257
5198
  );
5258
5199
  await session.klineFeed.flush();
5259
- import_logger5.logger.info(
5200
+ import_logger4.logger.info(
5260
5201
  import_chalk7.default.gray(
5261
5202
  `websocket candles: ready=${expectedSymbols.length - missingSymbols.length}/${expectedSymbols.length} missing=${missingSymbols.length}`
5262
5203
  )
@@ -5268,7 +5209,7 @@ var createSignalsRunner = (config2) => {
5268
5209
  symbols: missingSymbols,
5269
5210
  preloadDays: import_constants3.SIGNALS_CLI_PRELOAD_DAYS,
5270
5211
  universe,
5271
- log: (message) => import_logger5.logger.info(import_chalk7.default.gray(message))
5212
+ log: (message) => import_logger4.logger.info(import_chalk7.default.gray(message))
5272
5213
  });
5273
5214
  await updateBtcReferenceHistory({
5274
5215
  marketConnector,
@@ -5276,7 +5217,7 @@ var createSignalsRunner = (config2) => {
5276
5217
  interval: interval2,
5277
5218
  preloadDays: import_constants3.SIGNALS_CLI_PRELOAD_DAYS,
5278
5219
  universe,
5279
- log: (message) => import_logger5.logger.info(import_chalk7.default.gray(message))
5220
+ log: (message) => import_logger4.logger.info(import_chalk7.default.gray(message))
5280
5221
  });
5281
5222
  } else if (!config2.cacheOnly) {
5282
5223
  await updateMarketHistoryWithBtcReferences({
@@ -5287,7 +5228,7 @@ var createSignalsRunner = (config2) => {
5287
5228
  symbols: tickers,
5288
5229
  preloadDays: import_constants3.SIGNALS_CLI_PRELOAD_DAYS,
5289
5230
  universe,
5290
- log: (message) => import_logger5.logger.info(import_chalk7.default.gray(message))
5231
+ log: (message) => import_logger4.logger.info(import_chalk7.default.gray(message))
5291
5232
  });
5292
5233
  }
5293
5234
  await prepareMarketContextForRun({
@@ -5301,7 +5242,7 @@ var createSignalsRunner = (config2) => {
5301
5242
  endMs: currentTimestamp,
5302
5243
  preloadStartMs: preloadStart,
5303
5244
  cacheOnly: config2.cacheOnly,
5304
- log: (message) => import_logger5.logger.info(import_chalk7.default.gray(message))
5245
+ log: (message) => import_logger4.logger.info(import_chalk7.default.gray(message))
5305
5246
  });
5306
5247
  if (config2.updateOnly) {
5307
5248
  return;
@@ -5357,7 +5298,7 @@ var createSignalsRunner = (config2) => {
5357
5298
  const primaryEthByTimestamp = new Map(
5358
5299
  primaryEthClosedData.map((candle) => [candle.timestamp, candle])
5359
5300
  );
5360
- const runtimeStrategies = await loadRuntimeStrategies({
5301
+ const runtimeStrategies = await (0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({
5361
5302
  userName: config2.userName,
5362
5303
  projectRoot,
5363
5304
  deployment,
@@ -5368,7 +5309,7 @@ var createSignalsRunner = (config2) => {
5368
5309
  });
5369
5310
  if (!runtimeStrategies.length) {
5370
5311
  lifecycle.clear();
5371
- import_logger5.logger.warn(
5312
+ import_logger4.logger.warn(
5372
5313
  "No strategy configs found by users:%s:strategies:*:config",
5373
5314
  config2.userName
5374
5315
  );
@@ -5378,7 +5319,7 @@ var createSignalsRunner = (config2) => {
5378
5319
  new Set(
5379
5320
  tickers.flatMap(
5380
5321
  (symbol) => runtimeStrategies.map(
5381
- ({ strategyName, configId }) => buildSignalsStrategyLifecycleKey({
5322
+ ({ strategyName, configId, releaseVersion }) => buildSignalsStrategyLifecycleKey({
5382
5323
  connectorName,
5383
5324
  universe: sessionUniverse,
5384
5325
  accountId,
@@ -5386,13 +5327,13 @@ var createSignalsRunner = (config2) => {
5386
5327
  symbol,
5387
5328
  interval: interval2,
5388
5329
  strategyName,
5389
- configId
5330
+ configId: releaseVersion ? `v${releaseVersion}` : configId
5390
5331
  })
5391
5332
  )
5392
5333
  )
5393
5334
  )
5394
5335
  );
5395
- import_logger5.logger.info(
5336
+ import_logger4.logger.info(
5396
5337
  import_chalk7.default.yellow(
5397
5338
  `loaded strategies (user=${config2.userName}): ${runtimeStrategies.map((s) => s.strategyName).join(", ")}`
5398
5339
  )
@@ -5415,7 +5356,7 @@ var createSignalsRunner = (config2) => {
5415
5356
  afterSignalsHookContext
5416
5357
  );
5417
5358
  if (beforeSignalsResult?.abort === true) {
5418
- import_logger5.logger.info(
5359
+ import_logger4.logger.info(
5419
5360
  "signals aborted before ticker evaluation: %s",
5420
5361
  beforeSignalsResult.reason ?? "PROJECT_BEFORE_SIGNALS_ABORTED"
5421
5362
  );
@@ -5429,9 +5370,9 @@ var createSignalsRunner = (config2) => {
5429
5370
  width: 30
5430
5371
  }
5431
5372
  );
5432
- import_logger5.logger.info(import_chalk7.default.yellow(`tickers: ${tickers.length}`));
5373
+ import_logger4.logger.info(import_chalk7.default.yellow(`tickers: ${tickers.length}`));
5433
5374
  const signalsParallel = resolvePositiveInteger(config2.parallel, 4);
5434
- import_logger5.logger.info(import_chalk7.default.yellow(`signal workers: ${signalsParallel}`));
5375
+ import_logger4.logger.info(import_chalk7.default.yellow(`signal workers: ${signalsParallel}`));
5435
5376
  const evaluateTicker = createSignalsTickerEvaluator({
5436
5377
  userName: config2.userName,
5437
5378
  makeOrders: config2.makeOrders,
@@ -5488,7 +5429,7 @@ var createSignalsRunner = (config2) => {
5488
5429
  config2.userName
5489
5430
  );
5490
5431
  }
5491
- import_logger5.logger.info(
5432
+ import_logger4.logger.info(
5492
5433
  JSON.stringify(
5493
5434
  signals3.map((s) => s.symbol),
5494
5435
  null,
@@ -5501,7 +5442,7 @@ var createSignalsRunner = (config2) => {
5501
5442
  } catch (error) {
5502
5443
  status = "failed";
5503
5444
  failureMessage = error?.message || String(error);
5504
- import_logger5.logger.error(
5445
+ import_logger4.logger.error(
5505
5446
  "signals failed: %s",
5506
5447
  error?.message || String(error)
5507
5448
  );
@@ -5510,7 +5451,7 @@ var createSignalsRunner = (config2) => {
5510
5451
  try {
5511
5452
  await runtimeSignalEvaluations.flush();
5512
5453
  } catch (error) {
5513
- import_logger5.logger.error(
5454
+ import_logger4.logger.error(
5514
5455
  "runtime signal evaluation flush failed: %s",
5515
5456
  error?.message || String(error)
5516
5457
  );
@@ -5538,7 +5479,7 @@ var createSignalsRunner = (config2) => {
5538
5479
  durationMs
5539
5480
  });
5540
5481
  } catch (error) {
5541
- import_logger5.logger.error(
5482
+ import_logger4.logger.error(
5542
5483
  "afterSignals hook failed: %s",
5543
5484
  error?.message || String(error)
5544
5485
  );
@@ -5555,24 +5496,24 @@ var createSignalsRunner = (config2) => {
5555
5496
  { userName: config2.userName }
5556
5497
  );
5557
5498
  } catch (error) {
5558
- import_logger5.logger.error(
5499
+ import_logger4.logger.error(
5559
5500
  "slow signals warning failed: %s",
5560
5501
  error?.message || String(error)
5561
5502
  );
5562
5503
  }
5563
5504
  }
5564
- import_logger5.logger.info(
5505
+ import_logger4.logger.info(
5565
5506
  import_chalk7.default.yellow(
5566
5507
  `signals ${status} in ${formatDuration2(durationMs)} (found=${signals3.length})`
5567
5508
  )
5568
5509
  );
5569
- import_logger5.logger.info("");
5570
- import_logger5.logger.info("");
5571
- import_logger5.logger.info("");
5510
+ import_logger4.logger.info("");
5511
+ import_logger4.logger.info("");
5512
+ import_logger4.logger.info("");
5572
5513
  }
5573
5514
  };
5574
5515
  const loadConfiguredSignalsScopes = async (deployment) => {
5575
- const configuredStrategies = await loadRuntimeStrategies({
5516
+ const configuredStrategies = await (0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({
5576
5517
  userName: config2.userName,
5577
5518
  projectRoot,
5578
5519
  deployment,
@@ -5600,10 +5541,14 @@ var createSignalsRunner = (config2) => {
5600
5541
  };
5601
5542
  const hasExplicitSignalsScope = () => Boolean(config2.hasExplicitScope);
5602
5543
  const signalsConfiguredScopesOnce2 = async () => {
5603
- if (config2.updateOnly || config2.showTickersList || config2.deploymentId || hasExplicitSignalsScope()) {
5544
+ if (config2.updateOnly || config2.showTickersList || hasExplicitSignalsScope()) {
5604
5545
  return signals2();
5605
5546
  }
5606
- const scopes = await loadConfiguredSignalsScopes();
5547
+ const configuredDeployment = config2.deploymentId ? await (0, import_runtimeDeployments.getRuntimeDeployment)(config2.userName, config2.deploymentId) : null;
5548
+ if (config2.deploymentId && !configuredDeployment) {
5549
+ throw new Error(`Runtime deployment not found: ${config2.deploymentId}`);
5550
+ }
5551
+ const scopes = await loadConfiguredSignalsScopes(configuredDeployment);
5607
5552
  if (!scopes.size) return signals2();
5608
5553
  for (const scope of scopes.values()) {
5609
5554
  const session = await createSignalsSession2(
@@ -5632,14 +5577,14 @@ var createSignalsRunner = (config2) => {
5632
5577
  const sessions = /* @__PURE__ */ new Map();
5633
5578
  const lastBoundaryByScope = /* @__PURE__ */ new Map();
5634
5579
  const stop = (signalName) => {
5635
- import_logger5.logger.info("signals daemon stopping by %s", signalName);
5580
+ import_logger4.logger.info("signals daemon stopping by %s", signalName);
5636
5581
  abortController.abort();
5637
5582
  };
5638
5583
  const stopOnSigint = () => stop("SIGINT");
5639
5584
  const stopOnSigterm = () => stop("SIGTERM");
5640
5585
  process.once("SIGINT", stopOnSigint);
5641
5586
  process.once("SIGTERM", stopOnSigterm);
5642
- import_logger5.logger.info(
5587
+ import_logger4.logger.info(
5643
5588
  "signals daemon started (config-driven scopes, fallback interval=%s)",
5644
5589
  interval
5645
5590
  );
@@ -5680,7 +5625,7 @@ var createSignalsRunner = (config2) => {
5680
5625
  interval: session.interval,
5681
5626
  universe: session.universe
5682
5627
  });
5683
- import_logger5.logger.info(
5628
+ import_logger4.logger.info(
5684
5629
  "Bybit websocket candle feed enabled (account=%s, universe=%s, interval=%s)",
5685
5630
  session.accountId ?? "default",
5686
5631
  session.universe,
@@ -5702,7 +5647,7 @@ var createSignalsRunner = (config2) => {
5702
5647
  (sum, session) => sum + session.lifecycle.size(),
5703
5648
  0
5704
5649
  );
5705
- import_logger5.logger.info(
5650
+ import_logger4.logger.info(
5706
5651
  "signals daemon resources: rss=%sMB heapUsed=%sMB heapTotal=%sMB stateKeys=%s scopes=%s",
5707
5652
  (memory.rss / 1024 / 1024).toFixed(1),
5708
5653
  (memory.heapUsed / 1024 / 1024).toFixed(1),
@@ -5712,7 +5657,7 @@ var createSignalsRunner = (config2) => {
5712
5657
  );
5713
5658
  },
5714
5659
  onCycleError: (error) => {
5715
- import_logger5.logger.error(
5660
+ import_logger4.logger.error(
5716
5661
  "signals daemon cycle failed: %s",
5717
5662
  error?.message || String(error)
5718
5663
  );
@@ -5783,16 +5728,9 @@ import_args.default.option(["A", "account"], "Trading account id");
5783
5728
  import_args.default.option(["D", "deployment"], "Runtime deployment id");
5784
5729
  var flags = import_args.default.parse(process.argv);
5785
5730
  var hasExplicitScope = process.argv.some(
5786
- (argument) => [
5787
- "-f",
5788
- "--timeframe",
5789
- "-V",
5790
- "--universe",
5791
- "-A",
5792
- "--account",
5793
- "-D",
5794
- "--deployment"
5795
- ].some((option) => argument === option || argument.startsWith(`${option}=`))
5731
+ (argument) => ["-f", "--timeframe", "-V", "--universe", "-A", "--account"].some(
5732
+ (option) => argument === option || argument.startsWith(`${option}=`)
5733
+ )
5796
5734
  );
5797
5735
  var config = {
5798
5736
  projectRoot: String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd(),