@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.
@@ -5013,8 +5013,7 @@ var persistTestSummariesIndex = async () => {
5013
5013
  };
5014
5014
  var validateBacktestRuntimeDeployment = ({
5015
5015
  deployment,
5016
- deploymentId,
5017
- requestedInterval
5016
+ deploymentId
5018
5017
  }) => {
5019
5018
  if (deploymentId && !deployment) {
5020
5019
  throw new Error(`Runtime deployment not found: ${deploymentId}`);
@@ -5022,18 +5021,12 @@ var validateBacktestRuntimeDeployment = ({
5022
5021
  if (deployment && !deployment.enabled) {
5023
5022
  throw new Error(`Runtime deployment is disabled: ${deployment.id}`);
5024
5023
  }
5025
- if (deployment && String(deployment.interval) !== String(requestedInterval)) {
5026
- throw new Error(
5027
- `Deployment ${deployment.id} requires timeframe ${deployment.interval}; received ${requestedInterval}`
5028
- );
5029
- }
5030
5024
  return deployment;
5031
5025
  };
5032
5026
  var prepareRunEnvironment2 = async () => {
5033
5027
  const deployment = validateBacktestRuntimeDeployment({
5034
5028
  deployment: flags.deployment ? await (0, import_runtimeDeployments.getRuntimeDeployment)(userName, String(flags.deployment)) : null,
5035
- deploymentId: typeof flags.deployment === "string" ? flags.deployment : void 0,
5036
- requestedInterval: interval
5029
+ deploymentId: typeof flags.deployment === "string" ? flags.deployment : void 0
5037
5030
  });
5038
5031
  const preparedRun = await prepareRunEnvironment({
5039
5032
  connector: deployment?.connectorName ?? flags.connector,
@@ -5048,7 +5041,7 @@ var prepareRunEnvironment2 = async () => {
5048
5041
  cacheOnly: flags.cacheOnly,
5049
5042
  interval,
5050
5043
  projectRoot,
5051
- universe: deployment?.universe ?? marketUniverse,
5044
+ universe: marketUniverse,
5052
5045
  accountId: deployment?.accountId ?? flags.account,
5053
5046
  deploymentId: deployment?.id,
5054
5047
  assetClasses: deployment?.assetClasses,
@@ -5708,15 +5701,7 @@ var backtest = async () => {
5708
5701
  preparedRun.connectorName,
5709
5702
  interval
5710
5703
  ).map((test) => {
5711
- const deploymentStrategy = preparedRun.deployment?.strategies.find(
5712
- ({ strategyName }) => strategyName === config.strategyName
5713
- );
5714
- if (deploymentStrategy?.enabled === false) {
5715
- throw new Error(
5716
- `Strategy ${config.strategyName} is disabled in deployment ${preparedRun.deployment?.id}`
5717
- );
5718
- }
5719
- const policyProfileId = (typeof flags.policyProfile === "string" && flags.policyProfile.trim() ? flags.policyProfile.trim() : deploymentStrategy?.policyProfileId) || void 0;
5704
+ const policyProfileId = (typeof flags.policyProfile === "string" && flags.policyProfile.trim() ? flags.policyProfile.trim() : void 0) || void 0;
5720
5705
  return {
5721
5706
  ...test,
5722
5707
  instrument: preparedRun.instrumentsBySymbol.get(
@@ -5728,7 +5713,6 @@ var backtest = async () => {
5728
5713
  policyProfileId,
5729
5714
  strategyConfig: {
5730
5715
  ...test.strategyConfig,
5731
- ...deploymentStrategy?.config,
5732
5716
  ...policyProfileId ? { POLICY_PROFILE_ID: policyProfileId } : {}
5733
5717
  }
5734
5718
  };
@@ -30,20 +30,32 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/scripts/runtimeConfig.ts
31
31
  var runtimeConfig_exports = {};
32
32
  __export(runtimeConfig_exports, {
33
- buildBootstrapRuntimeDeployment: () => buildBootstrapRuntimeDeployment,
33
+ RUNTIME_CONFIG_ACTIONS: () => RUNTIME_CONFIG_ACTIONS,
34
+ buildProvisionedRuntimeDeployment: () => buildProvisionedRuntimeDeployment,
35
+ isEquivalentRuntimeStrategyRelease: () => isEquivalentRuntimeStrategyRelease,
34
36
  main: () => main,
37
+ pointRuntimeDeploymentAtRelease: () => pointRuntimeDeploymentAtRelease,
35
38
  runtimeConfig: () => runtimeConfig
36
39
  });
37
40
  module.exports = __toCommonJS(runtimeConfig_exports);
38
41
  var import_config = require("dotenv/config");
39
42
  var import_promises = require("fs/promises");
40
43
  var import_node_path = __toESM(require("path"));
44
+ var import_node_util = require("util");
41
45
  var import_runtimeDeployments = require("@tradejs/infra/runtimeDeployments");
42
- var import_runtimeStrategyConfigs = require("@tradejs/infra/runtimeStrategyConfigs");
43
46
  var import_runtimeStrategyReleases = require("@tradejs/infra/runtimeStrategyReleases");
44
47
  var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
45
48
  var import_strategies = require("@tradejs/node/strategies");
46
49
  var argv = process.argv.slice(2);
50
+ var RUNTIME_CONFIG_ACTIONS = [
51
+ "inspect",
52
+ "verify",
53
+ "provision",
54
+ "rollout",
55
+ "pause",
56
+ "resume",
57
+ "rollback"
58
+ ];
47
59
  var action = argv[0] ?? "inspect";
48
60
  var option = (name) => {
49
61
  const index = argv.indexOf(`--${name}`);
@@ -64,28 +76,26 @@ var OPERATIONAL_CONFIG_KEYS = [
64
76
  "ENABLE",
65
77
  "ENV",
66
78
  "MAKE_ORDERS",
67
- "RECORD_RUNTIME_TRADES",
68
- "configId"
79
+ "RECORD_RUNTIME_TRADES"
69
80
  ];
81
+ var requireRuntimePackageIdentity = (strategyName, metadata) => {
82
+ if (!metadata.strategyPackage || !metadata.strategyPackageVersion || !metadata.runtimePackageVersion) {
83
+ throw new Error(
84
+ `Runtime package manifest is incomplete for ${strategyName}`
85
+ );
86
+ }
87
+ return {
88
+ strategyPackage: metadata.strategyPackage,
89
+ strategyPackageVersion: metadata.strategyPackageVersion,
90
+ runtimePackageVersion: metadata.runtimePackageVersion
91
+ };
92
+ };
70
93
  var toReleaseConfig = async (strategyName, sourceConfig) => {
71
94
  const defaults = await (0, import_strategies.getStrategyDefaults)(strategyName, projectRoot) ?? {};
72
95
  const config = { ...defaults, ...sourceConfig };
73
96
  for (const key of OPERATIONAL_CONFIG_KEYS) delete config[key];
74
97
  return config;
75
98
  };
76
- var writeMigrationBackup = async (payload) => {
77
- const directory = import_node_path.default.join(projectRoot, "data", "runtime-config-backups");
78
- await (0, import_promises.mkdir)(directory, { recursive: true });
79
- const backupPath = import_node_path.default.join(
80
- directory,
81
- `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`
82
- );
83
- await (0, import_promises.writeFile)(backupPath, `${JSON.stringify(payload, null, 2)}
84
- `, {
85
- flag: "wx"
86
- });
87
- return backupPath;
88
- };
89
99
  var publish = async ({
90
100
  strategyName,
91
101
  sourceConfig
@@ -95,31 +105,29 @@ var publish = async ({
95
105
  strategyName,
96
106
  projectRoot
97
107
  });
108
+ const packageIdentity = requireRuntimePackageIdentity(strategyName, metadata);
98
109
  return (0, import_runtimeStrategyReleases.publishRuntimeStrategyRelease)({
99
110
  userName,
100
111
  strategyName,
101
112
  config,
102
- ...metadata,
113
+ ...packageIdentity,
103
114
  createdBy: `cli:${userName}`
104
115
  });
105
116
  };
106
- var buildBootstrapRuntimeDeployment = ({
117
+ var buildProvisionedRuntimeDeployment = ({
107
118
  deploymentId,
108
119
  label,
109
120
  connectorName,
110
121
  provider,
111
122
  accountId,
112
123
  strategyName,
113
- releaseVersion,
114
- config
124
+ releaseVersion
115
125
  }) => ({
116
126
  id: deploymentId,
117
127
  label,
118
128
  connectorName,
119
129
  provider,
120
130
  accountId,
121
- universe: config.UNIVERSE,
122
- interval: String(config.INTERVAL),
123
131
  enabled: true,
124
132
  strategies: [
125
133
  {
@@ -129,7 +137,30 @@ var buildBootstrapRuntimeDeployment = ({
129
137
  }
130
138
  ]
131
139
  });
132
- var bootstrap = async () => {
140
+ var isEquivalentRuntimeStrategyRelease = ({
141
+ release,
142
+ config,
143
+ strategyPackage,
144
+ strategyPackageVersion,
145
+ runtimePackageVersion
146
+ }) => Boolean(
147
+ release && (0, import_node_util.isDeepStrictEqual)(release.config, config) && release.strategyPackage === strategyPackage && release.strategyPackageVersion === strategyPackageVersion && release.runtimePackageVersion === runtimePackageVersion
148
+ );
149
+ var pointRuntimeDeploymentAtRelease = ({
150
+ deployment,
151
+ strategyName,
152
+ releaseVersion
153
+ }) => ({
154
+ ...deployment,
155
+ strategies: deployment.strategies.map(
156
+ (strategy) => strategy.strategyName === strategyName ? {
157
+ strategyName,
158
+ releaseVersion,
159
+ controlState: "entries_paused"
160
+ } : strategy
161
+ )
162
+ });
163
+ var provision = async () => {
133
164
  const strategyName = required("strategy");
134
165
  const deploymentId = required("deployment");
135
166
  const accountId = required("account");
@@ -147,15 +178,14 @@ var bootstrap = async () => {
147
178
  );
148
179
  }
149
180
  const releaseConfig = await toReleaseConfig(strategyName, sourceConfig);
150
- const previewDeployment = buildBootstrapRuntimeDeployment({
181
+ const previewDeployment = buildProvisionedRuntimeDeployment({
151
182
  deploymentId,
152
183
  label,
153
184
  connectorName,
154
185
  provider,
155
186
  accountId,
156
187
  strategyName,
157
- releaseVersion: 1,
158
- config: releaseConfig
188
+ releaseVersion: 1
159
189
  });
160
190
  if (!hasFlag("write")) {
161
191
  console.log(
@@ -177,102 +207,103 @@ var bootstrap = async () => {
177
207
  );
178
208
  return;
179
209
  }
180
- const backupPath = await writeMigrationBackup({
181
- userName,
182
- capturedAt: Date.now(),
183
- reason: "bootstrap",
184
- sourceConfig
185
- });
186
210
  const release = await publish({ strategyName, sourceConfig });
187
211
  const deployment = await (0, import_runtimeDeployments.saveRuntimeDeployment)(
188
212
  userName,
189
- buildBootstrapRuntimeDeployment({
213
+ buildProvisionedRuntimeDeployment({
190
214
  deploymentId,
191
215
  label,
192
216
  connectorName,
193
217
  provider,
194
218
  accountId,
195
219
  strategyName,
196
- releaseVersion: release.releaseVersion,
197
- config: release.config
220
+ releaseVersion: release.releaseVersion
198
221
  })
199
222
  );
200
223
  console.log(
201
- JSON.stringify(
202
- { bootstrapped: true, backupPath, release, deployment },
203
- null,
204
- 2
205
- )
224
+ JSON.stringify({ provisioned: true, release, deployment }, null, 2)
206
225
  );
207
226
  };
208
- var migrate = async () => {
227
+ var rollout = async () => {
209
228
  const strategyName = required("strategy");
210
- const configId = option("config") ?? "config";
211
229
  const deploymentId = required("deployment");
212
- const [sourceConfig, deployment] = await Promise.all([
213
- (0, import_runtimeStrategyConfigs.getRuntimeStrategyConfig)(userName, strategyName, configId),
214
- (0, import_runtimeDeployments.getRuntimeDeployment)(userName, deploymentId)
230
+ const configFile = import_node_path.default.resolve(projectRoot, required("file"));
231
+ const [deployment, sourceConfig] = await Promise.all([
232
+ (0, import_runtimeDeployments.getRuntimeDeployment)(userName, deploymentId),
233
+ (0, import_promises.readFile)(configFile, "utf8").then(
234
+ (value) => JSON.parse(value)
235
+ )
215
236
  ]);
216
- if (!sourceConfig) {
217
- throw new Error(`Legacy config not found: ${strategyName}:${configId}`);
218
- }
219
237
  if (!deployment) throw new Error(`Deployment not found: ${deploymentId}`);
220
238
  const reference = deployment.strategies.find(
221
239
  (strategy) => strategy.strategyName === strategyName
222
240
  );
223
- if (!reference) {
241
+ if (!reference)
224
242
  throw new Error(`${strategyName} is not bound to ${deploymentId}`);
225
- }
243
+ const [config, metadata, currentRelease] = await Promise.all([
244
+ toReleaseConfig(strategyName, sourceConfig),
245
+ (0, import_runtimeStrategies.getRuntimeStrategyPackageMetadata)({ strategyName, projectRoot }),
246
+ (0, import_runtimeStrategyReleases.getRuntimeStrategyRelease)(userName, strategyName, reference.releaseVersion)
247
+ ]);
248
+ const packageIdentity = requireRuntimePackageIdentity(strategyName, metadata);
249
+ const unchanged = isEquivalentRuntimeStrategyRelease({
250
+ release: currentRelease,
251
+ config,
252
+ ...packageIdentity
253
+ });
226
254
  const preview = {
227
- source: { configId, config: sourceConfig },
228
- releaseConfig: await toReleaseConfig(strategyName, sourceConfig),
229
- deployment: {
230
- id: deployment.id,
231
- accountId: deployment.accountId,
232
- strategy: {
233
- strategyName,
234
- releaseVersion: "<allocated on write>",
235
- controlState: "entries_paused"
236
- }
237
- }
255
+ deploymentId,
256
+ strategyName,
257
+ currentReleaseVersion: reference.releaseVersion,
258
+ nextControlState: "entries_paused",
259
+ unchanged,
260
+ config,
261
+ ...packageIdentity
238
262
  };
239
263
  if (!hasFlag("write")) {
240
264
  console.log(JSON.stringify({ dryRun: true, ...preview }, null, 2));
241
265
  return;
242
266
  }
243
- const backupPath = await writeMigrationBackup({
267
+ if (unchanged) {
268
+ console.log(
269
+ JSON.stringify(
270
+ {
271
+ rolledOut: false,
272
+ reason: "release_config_and_packages_unchanged",
273
+ release: currentRelease,
274
+ deployment
275
+ },
276
+ null,
277
+ 2
278
+ )
279
+ );
280
+ return;
281
+ }
282
+ const release = await (0, import_runtimeStrategyReleases.publishRuntimeStrategyRelease)({
244
283
  userName,
245
- capturedAt: Date.now(),
284
+ strategyName,
285
+ config,
286
+ ...packageIdentity,
287
+ createdBy: `cli:${userName}`
288
+ });
289
+ const updatedDeployment = pointRuntimeDeploymentAtRelease({
246
290
  deployment,
247
- legacyConfig: sourceConfig
291
+ strategyName,
292
+ releaseVersion: release.releaseVersion
248
293
  });
249
- const release = await publish({ strategyName, sourceConfig });
250
- const updatedDeployment = {
251
- ...deployment,
252
- strategies: deployment.strategies.map(
253
- (strategy) => strategy.strategyName === strategyName ? {
254
- strategyName,
255
- releaseVersion: release.releaseVersion,
256
- controlState: "entries_paused"
257
- } : strategy
258
- )
259
- };
260
294
  await (0, import_runtimeDeployments.saveRuntimeDeployment)(userName, updatedDeployment);
261
295
  console.log(
262
296
  JSON.stringify(
263
- { migrated: true, backupPath, release, deployment: updatedDeployment },
297
+ {
298
+ rolledOut: true,
299
+ release,
300
+ deployment: updatedDeployment
301
+ },
264
302
  null,
265
303
  2
266
304
  )
267
305
  );
268
306
  };
269
- var publishDraft = async () => {
270
- const strategyName = required("strategy");
271
- const draft = await (0, import_runtimeStrategyReleases.getRuntimeStrategyDraft)(userName, strategyName);
272
- if (!draft) throw new Error(`Draft not found: ${strategyName}`);
273
- const release = await publish({ strategyName, sourceConfig: draft.config });
274
- console.log(JSON.stringify({ release }, null, 2));
275
- };
276
307
  var updateControlState = async (nextState) => {
277
308
  const strategyName = required("strategy");
278
309
  const deploymentId = required("deployment");
@@ -281,10 +312,9 @@ var updateControlState = async (nextState) => {
281
312
  const reference = deployment.strategies.find(
282
313
  (strategy) => strategy.strategyName === strategyName
283
314
  );
284
- if (!reference?.releaseVersion) {
285
- throw new Error(`${strategyName} is not a versioned deployment reference`);
286
- }
287
- const previousState = reference.controlState ?? "active";
315
+ if (!reference)
316
+ throw new Error(`${strategyName} is not bound to ${deploymentId}`);
317
+ const previousState = reference.controlState;
288
318
  const updated = await (0, import_runtimeDeployments.saveRuntimeDeployment)(userName, {
289
319
  ...deployment,
290
320
  strategies: deployment.strategies.map(
@@ -314,12 +344,6 @@ var rollback = async () => {
314
344
  const release = (await (0, import_runtimeStrategyReleases.listRuntimeStrategyReleases)(userName, strategyName)).find((candidate) => candidate.releaseVersion === releaseVersion);
315
345
  if (!release)
316
346
  throw new Error(`Release not found: ${strategyName} v${releaseVersion}`);
317
- const backupPath = await writeMigrationBackup({
318
- userName,
319
- capturedAt: Date.now(),
320
- deployment,
321
- reason: "rollback"
322
- });
323
347
  const updated = await (0, import_runtimeDeployments.saveRuntimeDeployment)(userName, {
324
348
  ...deployment,
325
349
  strategies: deployment.strategies.map(
@@ -330,7 +354,7 @@ var rollback = async () => {
330
354
  } : strategy
331
355
  )
332
356
  });
333
- console.log(JSON.stringify({ backupPath, deployment: updated }, null, 2));
357
+ console.log(JSON.stringify({ deployment: updated }, null, 2));
334
358
  };
335
359
  var verify = async () => {
336
360
  const deployments = await (0, import_runtimeDeployments.listRuntimeDeployments)(userName);
@@ -341,8 +365,7 @@ var verify = async () => {
341
365
  const strategies = await (0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({
342
366
  userName,
343
367
  projectRoot,
344
- deployment,
345
- connectorName: deployment.connectorName
368
+ deployment
346
369
  });
347
370
  results.push({
348
371
  deploymentId: deployment.id,
@@ -374,22 +397,24 @@ var inspect = async () => {
374
397
  console.log(JSON.stringify({ userName, deployments, releases }, null, 2));
375
398
  };
376
399
  var runtimeConfig = async () => {
377
- if (action === "bootstrap") return bootstrap();
378
- if (action === "migrate") return migrate();
379
- if (action === "publish-draft") return publishDraft();
400
+ if (action === "provision") return provision();
401
+ if (action === "rollout") return rollout();
380
402
  if (action === "verify") return verify();
381
403
  if (action === "pause") return updateControlState("entries_paused");
382
404
  if (action === "resume") return updateControlState("active");
383
405
  if (action === "rollback") return rollback();
384
406
  if (action === "inspect") return inspect();
385
407
  throw new Error(
386
- "Usage: tradejs runtime-config inspect|verify|bootstrap|migrate|publish-draft|pause|resume|rollback"
408
+ `Usage: tradejs runtime-config ${RUNTIME_CONFIG_ACTIONS.join("|")}`
387
409
  );
388
410
  };
389
411
  var main = runtimeConfig;
390
412
  // Annotate the CommonJS export names for ESM import in node:
391
413
  0 && (module.exports = {
392
- buildBootstrapRuntimeDeployment,
414
+ RUNTIME_CONFIG_ACTIONS,
415
+ buildProvisionedRuntimeDeployment,
416
+ isEquivalentRuntimeStrategyRelease,
393
417
  main,
418
+ pointRuntimeDeploymentAtRelease,
394
419
  runtimeConfig
395
420
  });