@tradejs/node 3.1.0 → 3.1.2

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.
@@ -0,0 +1,264 @@
1
+ import {
2
+ getStrategyCreator,
3
+ getStrategyPluginSource
4
+ } from "./chunk-XN7BC7XK.mjs";
5
+ import "./chunk-WS5DYEVZ.mjs";
6
+ import "./chunk-Y6FXYEAI.mjs";
7
+
8
+ // src/runtimeStrategies.ts
9
+ import { readFile } from "fs/promises";
10
+ import path from "path";
11
+ import { getData, redisKeys } from "@tradejs/infra/redis";
12
+ import { getRuntimeStrategyRelease } from "@tradejs/infra/runtimeStrategyReleases";
13
+ import { loadRuntimeStrategyConfigs } from "@tradejs/infra/runtimeStrategyConfigs";
14
+ import { resolveTradingAccount } from "@tradejs/infra/tradingAccounts";
15
+ var readPackageManifest = async (projectRoot) => {
16
+ const candidates = [
17
+ process.env.TRADEJS_RUNTIME_PACKAGE_MANIFEST,
18
+ path.join(projectRoot, "runtime-package-manifest.json"),
19
+ "/app/runtime-package-manifest.json"
20
+ ].filter((candidate) => Boolean(candidate));
21
+ for (const candidate of candidates) {
22
+ try {
23
+ return JSON.parse(
24
+ await readFile(candidate, "utf8")
25
+ );
26
+ } catch {
27
+ }
28
+ }
29
+ return { packages: {} };
30
+ };
31
+ var resolveInstalledPackageVersion = async (projectRoot, packageName, manifest) => {
32
+ if (!packageName || packageName === "runtime") return null;
33
+ const manifestVersion = manifest.packages?.[packageName];
34
+ if (manifestVersion) return manifestVersion;
35
+ try {
36
+ const packageJsonPath = path.join(
37
+ projectRoot,
38
+ "node_modules",
39
+ ...packageName.split("/"),
40
+ "package.json"
41
+ );
42
+ const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
43
+ return packageJson.version ?? null;
44
+ } catch {
45
+ return null;
46
+ }
47
+ };
48
+ var validateReleaseRuntimeCompatibility = async ({
49
+ release,
50
+ projectRoot,
51
+ packageManifest
52
+ }) => {
53
+ const installedStrategyVersion = await resolveInstalledPackageVersion(
54
+ projectRoot,
55
+ release.strategyPackage,
56
+ packageManifest
57
+ );
58
+ if (release.strategyPackageVersion && installedStrategyVersion && release.strategyPackageVersion !== installedStrategyVersion) {
59
+ throw new Error(
60
+ `${release.strategyName} v${release.releaseVersion} requires ${release.strategyPackage}@${release.strategyPackageVersion}, image has ${installedStrategyVersion}`
61
+ );
62
+ }
63
+ const installedRuntimeVersion = packageManifest.packages?.["@tradejs/node"];
64
+ if (release.runtimePackageVersion && installedRuntimeVersion && release.runtimePackageVersion !== installedRuntimeVersion) {
65
+ throw new Error(
66
+ `${release.strategyName} v${release.releaseVersion} requires @tradejs/node@${release.runtimePackageVersion}, image has ${installedRuntimeVersion}`
67
+ );
68
+ }
69
+ };
70
+ var resolveAccountId = async ({
71
+ userName,
72
+ deployment,
73
+ connectorName,
74
+ universe,
75
+ legacyAccountId
76
+ }) => {
77
+ const requestedAccountId = deployment?.accountId ?? legacyAccountId;
78
+ const account = await resolveTradingAccount({
79
+ userName,
80
+ accountId: requestedAccountId,
81
+ provider: deployment?.provider ?? connectorName,
82
+ universe
83
+ });
84
+ return account?.id ?? requestedAccountId;
85
+ };
86
+ var loadVersionedRuntimeStrategies = async ({
87
+ userName,
88
+ projectRoot,
89
+ deployment,
90
+ connectorName
91
+ }) => {
92
+ const packageManifest = await readPackageManifest(projectRoot);
93
+ return Promise.all(
94
+ deployment.strategies.map(async (reference) => {
95
+ if (!Number.isSafeInteger(reference.releaseVersion) || !reference.releaseVersion) {
96
+ throw new Error(
97
+ `Deployment ${deployment.id} strategy ${reference.strategyName} has no releaseVersion`
98
+ );
99
+ }
100
+ if (reference.config && Object.keys(reference.config).length) {
101
+ throw new Error(
102
+ `Deployment ${deployment.id} must not embed config for ${reference.strategyName}`
103
+ );
104
+ }
105
+ const release = await getRuntimeStrategyRelease(
106
+ userName,
107
+ reference.strategyName,
108
+ reference.releaseVersion
109
+ );
110
+ if (!release) {
111
+ throw new Error(
112
+ `Runtime release not found: ${reference.strategyName} v${reference.releaseVersion}`
113
+ );
114
+ }
115
+ await validateReleaseRuntimeCompatibility({
116
+ release,
117
+ projectRoot,
118
+ packageManifest
119
+ });
120
+ const strategyCreator = await getStrategyCreator(
121
+ reference.strategyName,
122
+ projectRoot
123
+ );
124
+ if (!strategyCreator) {
125
+ throw new Error(`Unknown strategy: ${reference.strategyName}`);
126
+ }
127
+ const interval = String(release.config.INTERVAL);
128
+ const universe = release.config.UNIVERSE;
129
+ const accountId = await resolveAccountId({
130
+ userName,
131
+ deployment,
132
+ connectorName,
133
+ universe
134
+ });
135
+ return {
136
+ strategyName: reference.strategyName,
137
+ releaseVersion: release.releaseVersion,
138
+ controlState: reference.controlState ?? "active",
139
+ interval,
140
+ universe,
141
+ accountId,
142
+ strategyPackage: release.strategyPackage,
143
+ strategyPackageVersion: release.strategyPackageVersion,
144
+ runtimePackageVersion: release.runtimePackageVersion,
145
+ strategyCreator,
146
+ sourceStrategyConfig: release.config,
147
+ strategyConfig: release.config,
148
+ // Symbol result configs are mutable legacy overlays and are not read by v2.
149
+ strategyResults: {}
150
+ };
151
+ })
152
+ );
153
+ };
154
+ var loadLegacyRuntimeStrategies = async ({
155
+ userName,
156
+ projectRoot,
157
+ deployment,
158
+ connectorName
159
+ }) => {
160
+ const deploymentStrategies = new Map(
161
+ (deployment?.strategies ?? []).map((strategy) => [
162
+ strategy.strategyName,
163
+ strategy
164
+ ])
165
+ );
166
+ const candidates = await Promise.all(
167
+ (await loadRuntimeStrategyConfigs(userName)).map(async (record) => {
168
+ const binding = deploymentStrategies.get(record.strategyName);
169
+ if (binding?.enabled === false || record.strategyConfig.ENABLE === false) {
170
+ return null;
171
+ }
172
+ const universe = record.strategyConfig.UNIVERSE === "tradfi" ? "tradfi" : "crypto";
173
+ const interval = String(
174
+ record.strategyConfig.INTERVAL ?? "15"
175
+ );
176
+ const accountId = await resolveAccountId({
177
+ userName,
178
+ deployment,
179
+ connectorName,
180
+ universe,
181
+ legacyAccountId: typeof record.strategyConfig.ACCOUNT_ID === "string" ? record.strategyConfig.ACCOUNT_ID : void 0
182
+ });
183
+ const [strategyCreator, strategyResults] = await Promise.all([
184
+ getStrategyCreator(record.strategyName, projectRoot),
185
+ getData(redisKeys.strategyResults(userName, record.strategyName), {})
186
+ ]);
187
+ if (!strategyCreator) return null;
188
+ return {
189
+ strategyName: record.strategyName,
190
+ configId: record.configId,
191
+ controlState: "active",
192
+ interval,
193
+ universe,
194
+ accountId,
195
+ strategyCreator,
196
+ sourceStrategyConfig: record.strategyConfig,
197
+ strategyConfig: record.strategyConfig,
198
+ strategyResults: strategyResults ?? {}
199
+ };
200
+ })
201
+ );
202
+ return candidates.filter(Boolean);
203
+ };
204
+ var loadResolvedRuntimeStrategies = async ({
205
+ userName,
206
+ projectRoot,
207
+ deployment,
208
+ connectorName = "bybit",
209
+ universe,
210
+ accountId,
211
+ interval
212
+ }) => {
213
+ const hasVersionedReferences = Boolean(
214
+ deployment?.strategies.some((strategy) => strategy.releaseVersion != null)
215
+ );
216
+ if (hasVersionedReferences && deployment?.strategies.some((strategy) => strategy.releaseVersion == null)) {
217
+ throw new Error(
218
+ `Deployment ${deployment.id} mixes legacy configs and versioned releases`
219
+ );
220
+ }
221
+ const strategies = hasVersionedReferences ? await loadVersionedRuntimeStrategies({
222
+ userName,
223
+ projectRoot,
224
+ deployment,
225
+ connectorName
226
+ }) : await loadLegacyRuntimeStrategies({
227
+ userName,
228
+ projectRoot,
229
+ deployment,
230
+ connectorName
231
+ });
232
+ const filtered = strategies.filter(
233
+ (candidate) => (!universe || candidate.universe === universe) && (!interval || String(candidate.interval) === String(interval)) && (!accountId || candidate.accountId === accountId)
234
+ );
235
+ const identities = /* @__PURE__ */ new Set();
236
+ for (const candidate of filtered) {
237
+ const identity = `${candidate.strategyName}:${candidate.accountId ?? "default"}`;
238
+ if (identities.has(identity)) {
239
+ throw new Error(`Runtime strategy conflict: ${identity}`);
240
+ }
241
+ identities.add(identity);
242
+ }
243
+ return filtered;
244
+ };
245
+ var getRuntimeStrategyPackageMetadata = async ({
246
+ strategyName,
247
+ projectRoot
248
+ }) => {
249
+ const packageManifest = await readPackageManifest(projectRoot);
250
+ const strategyPackage = await getStrategyPluginSource(strategyName, projectRoot) ?? null;
251
+ return {
252
+ strategyPackage,
253
+ strategyPackageVersion: await resolveInstalledPackageVersion(
254
+ projectRoot,
255
+ strategyPackage,
256
+ packageManifest
257
+ ),
258
+ runtimePackageVersion: packageManifest.packages?.["@tradejs/node"] ?? null
259
+ };
260
+ };
261
+ export {
262
+ getRuntimeStrategyPackageMetadata,
263
+ loadResolvedRuntimeStrategies
264
+ };
@@ -1,6 +1,6 @@
1
1
  export * from '@tradejs/core/strategies';
2
2
  export { AiChatMessage, DEFAULT_AI_MODEL, InvokeAiChatOptions, MAX_AI_SERIES_POINTS, askAI, buildAiHumanPrompt, buildAiPayload, buildAiPrompts, buildAiSystemPrompt, buildCompactAiIndicatorsSnapshot, getDeterministicAiGateContext, getOpenRouterModelKwargs, invokeAiChat, resetAiRuntimeCache, runAiPrompt, runAiPromptLocal, trimSeriesDeep } from './ai.mjs';
3
- export { ensureIndicatorPluginsLoaded, ensureStrategyPluginsLoaded, getAvailableStrategyNames, getRegisteredManifests, getRegisteredStrategies, getStrategyCreator, getStrategyDefaults, getStrategyManifest, isKnownStrategy, registerStrategyEntries, resetStrategyRegistryCache, strategies } from './registry.mjs';
3
+ export { e as ensureIndicatorPluginsLoaded, a as ensureStrategyPluginsLoaded, g as getAvailableStrategyNames, b as getRegisteredManifests, c as getRegisteredStrategies, d as getStrategyCreator, f as getStrategyDefaults, h as getStrategyManifest, i as getStrategyPluginSource, j as isKnownStrategy, r as registerStrategyEntries, k as resetStrategyRegistryCache, s as strategies } from './registry-DHTLjQcr.mjs';
4
4
  import { StrategyConfig, CreateStrategyCore, StrategyManifest, StrategyCreator, RuntimeStrategyConfigSnapshot, Signal, Direction, StrategyRuntimeMlOptions, StrategyRuntimeAiOptions, Connector, Tp, MarketFeatureInterval, StrategyEntrySignalContext } from '@tradejs/types';
5
5
  import { TradejsConfigOnBarHook, TradejsConfigBeforeSignalsHook } from '@tradejs/core/config';
6
6
 
@@ -1,6 +1,6 @@
1
1
  export * from '@tradejs/core/strategies';
2
2
  export { AiChatMessage, DEFAULT_AI_MODEL, InvokeAiChatOptions, MAX_AI_SERIES_POINTS, askAI, buildAiHumanPrompt, buildAiPayload, buildAiPrompts, buildAiSystemPrompt, buildCompactAiIndicatorsSnapshot, getDeterministicAiGateContext, getOpenRouterModelKwargs, invokeAiChat, resetAiRuntimeCache, runAiPrompt, runAiPromptLocal, trimSeriesDeep } from './ai.js';
3
- export { ensureIndicatorPluginsLoaded, ensureStrategyPluginsLoaded, getAvailableStrategyNames, getRegisteredManifests, getRegisteredStrategies, getStrategyCreator, getStrategyDefaults, getStrategyManifest, isKnownStrategy, registerStrategyEntries, resetStrategyRegistryCache, strategies } from './registry.js';
3
+ export { e as ensureIndicatorPluginsLoaded, a as ensureStrategyPluginsLoaded, g as getAvailableStrategyNames, b as getRegisteredManifests, c as getRegisteredStrategies, d as getStrategyCreator, f as getStrategyDefaults, h as getStrategyManifest, i as getStrategyPluginSource, j as isKnownStrategy, r as registerStrategyEntries, k as resetStrategyRegistryCache, s as strategies } from './registry-DHTLjQcr.js';
4
4
  import { StrategyConfig, CreateStrategyCore, StrategyManifest, StrategyCreator, RuntimeStrategyConfigSnapshot, Signal, Direction, StrategyRuntimeMlOptions, StrategyRuntimeAiOptions, Connector, Tp, MarketFeatureInterval, StrategyEntrySignalContext } from '@tradejs/types';
5
5
  import { TradejsConfigOnBarHook, TradejsConfigBeforeSignalsHook } from '@tradejs/core/config';
6
6
 
@@ -72,6 +72,7 @@ __export(strategies_exports, {
72
72
  getStrategyCreator: () => getStrategyCreator,
73
73
  getStrategyDefaults: () => getStrategyDefaults,
74
74
  getStrategyManifest: () => getStrategyManifest,
75
+ getStrategyPluginSource: () => getStrategyPluginSource,
75
76
  invokeAiChat: () => invokeAiChat,
76
77
  isKnownStrategy: () => isKnownStrategy,
77
78
  isTrackedHyperliquidPerp: () => isTrackedHyperliquidPerp,
@@ -965,6 +966,7 @@ var createStrategyRegistryState = () => ({
965
966
  strategyCreators: /* @__PURE__ */ new Map(),
966
967
  strategyManifestsMap: /* @__PURE__ */ new Map(),
967
968
  strategyEntriesMap: /* @__PURE__ */ new Map(),
969
+ strategySourcesMap: /* @__PURE__ */ new Map(),
968
970
  pluginsLoadPromise: null
969
971
  });
970
972
  var registryStateByProjectRoot = sharedStrategyRegistry.registryStateByProjectRoot;
@@ -1035,6 +1037,7 @@ var registerEntries = (entries, source, state) => {
1035
1037
  }
1036
1038
  state.strategyManifestsMap.set(strategyName, entry.manifest);
1037
1039
  state.strategyEntriesMap.set(strategyName, entry);
1040
+ state.strategySourcesMap.set(strategyName, source);
1038
1041
  materializeStrategyCreator(strategyName, state);
1039
1042
  }
1040
1043
  };
@@ -1157,6 +1160,11 @@ var getStrategyDefaults = async (name, cwd = getTradejsProjectCwd()) => {
1157
1160
  const { state } = getStrategyRegistryState(cwd);
1158
1161
  return state.strategyEntriesMap.get(name)?.defaults;
1159
1162
  };
1163
+ var getStrategyPluginSource = async (name, cwd = getTradejsProjectCwd()) => {
1164
+ await ensureStrategyPluginsLoaded(cwd);
1165
+ const { state } = getStrategyRegistryState(cwd);
1166
+ return state.strategySourcesMap.get(name);
1167
+ };
1160
1168
  var getAvailableStrategyNames = async (cwd = getTradejsProjectCwd()) => {
1161
1169
  await ensureStrategyPluginsLoaded(cwd);
1162
1170
  const { state } = getStrategyRegistryState(cwd);
@@ -4538,6 +4546,7 @@ var executeEntryOrder = async ({
4538
4546
  deploymentId: signal.deploymentId,
4539
4547
  policyProfileId: signal.policyProfileId,
4540
4548
  runtimeConfigId: signal.runtimeConfigId,
4549
+ runtimeReleaseVersion: signal.runtimeReleaseVersion,
4541
4550
  runtimeLineage: signal.runtimeLineage,
4542
4551
  ...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {}
4543
4552
  });
@@ -5462,6 +5471,9 @@ var createStrategyRuntime = ({
5462
5471
  deploymentId: requestedDeploymentId,
5463
5472
  policyProfileId,
5464
5473
  runtimeConfigId,
5474
+ runtimeReleaseVersion,
5475
+ entriesPaused = false,
5476
+ runtimeLineage,
5465
5477
  runtimeConfigSnapshot,
5466
5478
  data,
5467
5479
  btcData,
@@ -6120,6 +6132,7 @@ var createStrategyRuntime = ({
6120
6132
  });
6121
6133
  const signal = decision.signal;
6122
6134
  if (signal) {
6135
+ if (runtimeLineage) signal.runtimeLineage = runtimeLineage;
6123
6136
  if (universe) signal.universe = universe;
6124
6137
  if (assetClass) signal.assetClass = assetClass;
6125
6138
  if (accountId) signal.accountId = accountId;
@@ -6130,6 +6143,9 @@ var createStrategyRuntime = ({
6130
6143
  signal.signalId = `${signal.signalId}:${runtimeConfigId}`;
6131
6144
  }
6132
6145
  }
6146
+ if (runtimeReleaseVersion) {
6147
+ signal.runtimeReleaseVersion = runtimeReleaseVersion;
6148
+ }
6133
6149
  if (decisionHookCtx.policyProfileId) {
6134
6150
  signal.policyProfileId = decisionHookCtx.policyProfileId;
6135
6151
  }
@@ -6236,6 +6252,15 @@ var createStrategyRuntime = ({
6236
6252
  quality,
6237
6253
  minAiQuality
6238
6254
  });
6255
+ if (entriesPaused) {
6256
+ const skipReason = "RUNTIME_ENTRIES_PAUSED";
6257
+ if (signal) {
6258
+ signal.orderStatus = "skipped";
6259
+ signal.orderSkipReason = skipReason;
6260
+ signal.runtimeReleaseVersion = runtimeReleaseVersion;
6261
+ }
6262
+ return signal ?? skipReason;
6263
+ }
6239
6264
  if (!shouldMakeOrder) {
6240
6265
  if (signal) {
6241
6266
  signal.orderStatus = "skipped";
@@ -6752,6 +6777,7 @@ var createCloseAllOnGlobalProfitBeforeSignalsHook = ({
6752
6777
  getStrategyCreator,
6753
6778
  getStrategyDefaults,
6754
6779
  getStrategyManifest,
6780
+ getStrategyPluginSource,
6755
6781
  invokeAiChat,
6756
6782
  isKnownStrategy,
6757
6783
  isTrackedHyperliquidPerp,
@@ -29,7 +29,7 @@ import {
29
29
  resolveHyperliquidPerpFromSignalSymbol,
30
30
  resolveStrategyConfig,
31
31
  validateEntryProtectionAtArrival
32
- } from "./chunk-MKLTJQLY.mjs";
32
+ } from "./chunk-W26Y6IRP.mjs";
33
33
  import {
34
34
  DEFAULT_AI_MODEL,
35
35
  MAX_AI_SERIES_POINTS,
@@ -39,26 +39,29 @@ import {
39
39
  buildAiPrompts,
40
40
  buildAiSystemPrompt,
41
41
  buildCompactAiIndicatorsSnapshot,
42
+ getDeterministicAiGateContext,
43
+ getOpenRouterModelKwargs,
44
+ invokeAiChat,
45
+ resetAiRuntimeCache,
46
+ runAiPrompt,
47
+ runAiPromptLocal,
48
+ trimSeriesDeep
49
+ } from "./chunk-SEQJ6V6B.mjs";
50
+ import {
42
51
  ensureIndicatorPluginsLoaded,
43
52
  ensureStrategyPluginsLoaded,
44
53
  getAvailableStrategyNames,
45
- getDeterministicAiGateContext,
46
- getOpenRouterModelKwargs,
47
54
  getRegisteredManifests,
48
55
  getRegisteredStrategies,
49
56
  getStrategyCreator,
50
57
  getStrategyDefaults,
51
58
  getStrategyManifest,
52
- invokeAiChat,
59
+ getStrategyPluginSource,
53
60
  isKnownStrategy,
54
61
  registerStrategyEntries,
55
- resetAiRuntimeCache,
56
62
  resetStrategyRegistryCache,
57
- runAiPrompt,
58
- runAiPromptLocal,
59
- strategies,
60
- trimSeriesDeep
61
- } from "./chunk-KOQSLFT2.mjs";
63
+ strategies
64
+ } from "./chunk-XN7BC7XK.mjs";
62
65
  import "./chunk-WS5DYEVZ.mjs";
63
66
  import "./chunk-Y6FXYEAI.mjs";
64
67
  export {
@@ -103,6 +106,7 @@ export {
103
106
  getStrategyCreator,
104
107
  getStrategyDefaults,
105
108
  getStrategyManifest,
109
+ getStrategyPluginSource,
106
110
  invokeAiChat,
107
111
  isKnownStrategy,
108
112
  isTrackedHyperliquidPerp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/node",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Node-only runtime for the TradeJS TypeScript framework: strategies, backtests, Pine strategy loading, and plugin registries.",
5
5
  "keywords": [
6
6
  "tradejs",
@@ -9,7 +9,10 @@
9
9
  "node",
10
10
  "runtime",
11
11
  "strategy",
12
- "pine-script"
12
+ "pine-script",
13
+ "ai",
14
+ "claude",
15
+ "codex"
13
16
  ],
14
17
  "repository": {
15
18
  "type": "git",
@@ -68,6 +71,11 @@
68
71
  "import": "./dist/runtimeDashboard.mjs",
69
72
  "require": "./dist/runtimeDashboard.js"
70
73
  },
74
+ "./runtimeStrategies": {
75
+ "types": "./dist/runtimeStrategies.d.ts",
76
+ "import": "./dist/runtimeStrategies.mjs",
77
+ "require": "./dist/runtimeStrategies.js"
78
+ },
71
79
  "./strategies": {
72
80
  "types": "./dist/strategies.d.ts",
73
81
  "import": "./dist/strategies.mjs",
@@ -77,9 +85,9 @@
77
85
  "dependencies": {
78
86
  "@langchain/core": "^1.2.3",
79
87
  "@langchain/openai": "^1.5.5",
80
- "@tradejs/core": "^3.1.0",
81
- "@tradejs/infra": "^3.1.0",
82
- "@tradejs/types": "^3.1.0",
88
+ "@tradejs/core": "^3.1.2",
89
+ "@tradejs/infra": "^3.1.2",
90
+ "@tradejs/types": "^3.1.2",
83
91
  "chalk": "4.1.2",
84
92
  "ioredis": "5.11.1",
85
93
  "lodash": "^4.18.1",