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