@tradejs/node 3.1.28 → 3.1.29-beta.259
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.js +4 -1
- package/dist/ai.mjs +1 -1
- package/dist/backtest.js +941 -35
- package/dist/backtest.mjs +7 -3
- package/dist/chunk-3BBXGZ7M.mjs +271 -0
- package/dist/{chunk-K2YQ3MQC.mjs → chunk-BO42QWAB.mjs} +11 -2
- package/dist/{chunk-UITD6LG6.mjs → chunk-UL5Z46JL.mjs} +4 -1
- package/dist/{chunk-JDFPF2RG.mjs → chunk-WGL7XJ3W.mjs} +24 -2
- package/dist/chunk-ZZQLTUTP.mjs +614 -0
- package/dist/cli.js +9 -1
- package/dist/cli.mjs +6 -1
- package/dist/jev.d.mts +342 -0
- package/dist/jev.d.ts +342 -0
- package/dist/jev.js +931 -0
- package/dist/jev.mjs +23 -0
- package/dist/jevTraining-JYXUVAZG.mjs +13 -0
- package/dist/registry.js +933 -29
- package/dist/registry.mjs +4 -2
- package/dist/runtimeDashboard.js +952 -39
- package/dist/runtimeDashboard.mjs +5 -3
- package/dist/runtimeStrategies.js +952 -39
- package/dist/runtimeStrategies.mjs +5 -3
- package/dist/strategies.js +931 -27
- package/dist/strategies.mjs +4 -2
- package/package.json +10 -5
package/dist/backtest.mjs
CHANGED
|
@@ -5,14 +5,16 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
buildMlPayload,
|
|
7
7
|
enrichSignalWithMarketContextStages
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-WGL7XJ3W.mjs";
|
|
9
9
|
import {
|
|
10
10
|
buildAiPayload,
|
|
11
11
|
getStrategyCreator
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UL5Z46JL.mjs";
|
|
13
13
|
import {
|
|
14
14
|
getTradejsProjectCwd
|
|
15
15
|
} from "./chunk-LZDXRXIU.mjs";
|
|
16
|
+
import "./chunk-3BBXGZ7M.mjs";
|
|
17
|
+
import "./chunk-ZZQLTUTP.mjs";
|
|
16
18
|
import "./chunk-Y6FXYEAI.mjs";
|
|
17
19
|
|
|
18
20
|
// src/backtest.ts
|
|
@@ -1364,6 +1366,7 @@ var buildReplayEvaluation = ({
|
|
|
1364
1366
|
orderStatus: signal.orderStatus,
|
|
1365
1367
|
orderSkipReason: signal.orderSkipReason,
|
|
1366
1368
|
aiAnalysis: signal.aiAnalysis ?? null,
|
|
1369
|
+
assessment: signal.assessment,
|
|
1367
1370
|
ml: signal.ml
|
|
1368
1371
|
};
|
|
1369
1372
|
};
|
|
@@ -1502,7 +1505,7 @@ var createBacktestSession = async ({
|
|
|
1502
1505
|
})
|
|
1503
1506
|
);
|
|
1504
1507
|
}
|
|
1505
|
-
if (test.ai && signal && typeof signal !== "string" && signal.signalId) {
|
|
1508
|
+
if (test.ai && signal && typeof signal !== "string" && signal.signalId && !(signal.assessment && signal.orderStatus === "skipped")) {
|
|
1506
1509
|
pendingAiRowBySignalId.set(signal.signalId, {
|
|
1507
1510
|
signalId: signal.signalId,
|
|
1508
1511
|
strategyName: signal.strategy || test.strategyName,
|
|
@@ -1510,6 +1513,7 @@ var createBacktestSession = async ({
|
|
|
1510
1513
|
direction: signal.direction,
|
|
1511
1514
|
timestamp: signal.timestamp,
|
|
1512
1515
|
signal: cloneSignal(signal),
|
|
1516
|
+
assessment: signal.assessment,
|
|
1513
1517
|
testId: test.testId,
|
|
1514
1518
|
testSuiteId: test.testSuiteId,
|
|
1515
1519
|
testName: test.name,
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JEV_QUESTIONS,
|
|
3
|
+
buildJevInput,
|
|
4
|
+
questionsForJevInput,
|
|
5
|
+
stateForJevInput
|
|
6
|
+
} from "./chunk-ZZQLTUTP.mjs";
|
|
7
|
+
|
|
8
|
+
// src/jev.ts
|
|
9
|
+
import fs from "fs/promises";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import {
|
|
12
|
+
JEV_DIMENSIONS,
|
|
13
|
+
JEV_PROVIDERS,
|
|
14
|
+
parseJevConfig,
|
|
15
|
+
predictJevTree
|
|
16
|
+
} from "@tradejs/core/jev";
|
|
17
|
+
import {
|
|
18
|
+
jevHash,
|
|
19
|
+
jevFileHash,
|
|
20
|
+
readJevArtifact,
|
|
21
|
+
writeJevArtifact,
|
|
22
|
+
requestJev,
|
|
23
|
+
validateJevResponse
|
|
24
|
+
} from "@tradejs/infra/jev";
|
|
25
|
+
import { getUserSettings } from "@tradejs/infra/userSettings";
|
|
26
|
+
var resolveJevProvider = async (userName) => {
|
|
27
|
+
const settings = await getUserSettings(userName);
|
|
28
|
+
const provider = {
|
|
29
|
+
endpoint: settings.JEV_API_ENDPOINT || JEV_PROVIDERS[0].endpoint,
|
|
30
|
+
model: settings.JEV_MODEL || JEV_PROVIDERS[0].model
|
|
31
|
+
};
|
|
32
|
+
parseJevConfig({ source: "provider", mode: "observe", provider });
|
|
33
|
+
if (!settings.JEV_API_KEY)
|
|
34
|
+
throw new Error("Configure the Jev API key in Account settings");
|
|
35
|
+
return provider;
|
|
36
|
+
};
|
|
37
|
+
var emptyScores = () => Object.fromEntries(JEV_DIMENSIONS.map((key) => [key, null]));
|
|
38
|
+
var pending = /* @__PURE__ */ new Map();
|
|
39
|
+
var pendingResponses = /* @__PURE__ */ new Map();
|
|
40
|
+
var evaluateJevInput = async ({
|
|
41
|
+
input,
|
|
42
|
+
config,
|
|
43
|
+
userName,
|
|
44
|
+
projectRoot
|
|
45
|
+
}) => {
|
|
46
|
+
config = parseJevConfig(config);
|
|
47
|
+
const inputHash = jevHash(input);
|
|
48
|
+
const questions = questionsForJevInput(input);
|
|
49
|
+
const questionsHash = jevHash(questions);
|
|
50
|
+
const base = {
|
|
51
|
+
schema: "tradejs-signal-assessment/v5",
|
|
52
|
+
source: config.source,
|
|
53
|
+
mode: config.mode,
|
|
54
|
+
inputHash,
|
|
55
|
+
questionsHash,
|
|
56
|
+
geometryStatus: input.geometryStatus,
|
|
57
|
+
levelsValid: typeof input.features["signal.validLevels"] === "boolean" ? input.features["signal.validLevels"] : null
|
|
58
|
+
};
|
|
59
|
+
if (!input.questions.length)
|
|
60
|
+
return {
|
|
61
|
+
assessment: {
|
|
62
|
+
...base,
|
|
63
|
+
status: "unavailable",
|
|
64
|
+
model: "",
|
|
65
|
+
scores: emptyScores(),
|
|
66
|
+
confidence: emptyScores()
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
if (config.source === "local") {
|
|
70
|
+
const contents = await fs.readFile(
|
|
71
|
+
path.resolve(projectRoot, config.modelFile),
|
|
72
|
+
"utf8"
|
|
73
|
+
);
|
|
74
|
+
if (jevFileHash(contents) !== config.modelSha256)
|
|
75
|
+
throw new Error("Local Jev gate checksum mismatch");
|
|
76
|
+
const { validateJevGateModel: validateJevGateModel2 } = await import("./jevTraining-JYXUVAZG.mjs");
|
|
77
|
+
const model = validateJevGateModel2(JSON.parse(contents));
|
|
78
|
+
if (model.strategy !== input.strategy || model.questionsHash !== jevHash(JEV_QUESTIONS))
|
|
79
|
+
throw new Error("Local Jev gate strategy or question version mismatch");
|
|
80
|
+
const scores = Object.fromEntries(
|
|
81
|
+
JEV_DIMENSIONS.map((key) => [
|
|
82
|
+
key,
|
|
83
|
+
input.questions.includes(key) && model.trees[key] ? predictJevTree(model.trees[key], input.features) : null
|
|
84
|
+
])
|
|
85
|
+
);
|
|
86
|
+
return {
|
|
87
|
+
assessment: {
|
|
88
|
+
...base,
|
|
89
|
+
status: "available",
|
|
90
|
+
model: config.modelSha256,
|
|
91
|
+
scores,
|
|
92
|
+
confidence: emptyScores()
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const provider = config.provider ?? await resolveJevProvider(userName);
|
|
97
|
+
const id = jevHash({ inputHash, questionsHash, provider });
|
|
98
|
+
const dir = path.resolve(projectRoot, config.recordsDir ?? "data/ai/jev");
|
|
99
|
+
const file = path.join(dir, "records", `${id}.json`);
|
|
100
|
+
const getRecord = async () => {
|
|
101
|
+
const existing = await readJevArtifact(file);
|
|
102
|
+
if (existing) {
|
|
103
|
+
if (existing.schema !== "tradejs-jev-record/v4" || existing.id !== id || existing.inputHash !== inputHash || existing.questionsHash !== questionsHash || jevHash(existing.input) !== inputHash || jevHash(existing.provider) !== jevHash(provider))
|
|
104
|
+
throw new Error("Jev recording identity mismatch");
|
|
105
|
+
validateJevResponse(existing.response, input.questions);
|
|
106
|
+
for (const key of JEV_DIMENSIONS) {
|
|
107
|
+
const expected = input.questions.includes(key) ? existing.response.answers[key].score / 4 : null;
|
|
108
|
+
if (existing.scores[key] !== expected)
|
|
109
|
+
throw new Error("Jev recording scores do not match the response");
|
|
110
|
+
}
|
|
111
|
+
return existing;
|
|
112
|
+
}
|
|
113
|
+
if (config.source === "recorded")
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Missing Jev recording ${id} for ${input.strategy} ${input.symbol} at ${new Date(input.timestamp).toISOString()}. Recorded mode requires the same signal-time facts and provider; a shorter backtest can change warm-up indicators or prior trade state.`
|
|
116
|
+
);
|
|
117
|
+
const settings = await getUserSettings(userName);
|
|
118
|
+
if (!settings.JEV_API_KEY)
|
|
119
|
+
throw new Error("Configure the Jev API key in Account settings");
|
|
120
|
+
const apiKey = settings.JEV_API_KEY;
|
|
121
|
+
const configuredProvider = await resolveJevProvider(userName);
|
|
122
|
+
if (configuredProvider.endpoint !== provider.endpoint)
|
|
123
|
+
throw new Error(
|
|
124
|
+
"Jev account endpoint changed; update the frozen provider configuration"
|
|
125
|
+
);
|
|
126
|
+
const started = Date.now();
|
|
127
|
+
const state = stateForJevInput(input);
|
|
128
|
+
const responseId = jevHash({
|
|
129
|
+
state,
|
|
130
|
+
questionsHash,
|
|
131
|
+
provider,
|
|
132
|
+
user: jevHash(userName)
|
|
133
|
+
});
|
|
134
|
+
const responseFile = path.join(dir, "responses", `${responseId}.json`);
|
|
135
|
+
let responsePromise = pendingResponses.get(responseFile);
|
|
136
|
+
if (!responsePromise) {
|
|
137
|
+
responsePromise = (async () => {
|
|
138
|
+
const saved = await readJevArtifact(responseFile);
|
|
139
|
+
if (saved) return validateJevResponse(saved, input.questions);
|
|
140
|
+
const fresh = await requestJev(provider, apiKey, state, questions);
|
|
141
|
+
await writeJevArtifact(responseFile, fresh);
|
|
142
|
+
return fresh;
|
|
143
|
+
})();
|
|
144
|
+
pendingResponses.set(responseFile, responsePromise);
|
|
145
|
+
}
|
|
146
|
+
let response;
|
|
147
|
+
try {
|
|
148
|
+
response = await responsePromise;
|
|
149
|
+
} finally {
|
|
150
|
+
pendingResponses.delete(responseFile);
|
|
151
|
+
}
|
|
152
|
+
const scores = Object.fromEntries(
|
|
153
|
+
JEV_DIMENSIONS.map((key) => [
|
|
154
|
+
key,
|
|
155
|
+
input.questions.includes(key) ? response.answers[key].score / 4 : null
|
|
156
|
+
])
|
|
157
|
+
);
|
|
158
|
+
const value = {
|
|
159
|
+
schema: "tradejs-jev-record/v4",
|
|
160
|
+
id,
|
|
161
|
+
inputHash,
|
|
162
|
+
questionsHash,
|
|
163
|
+
provider,
|
|
164
|
+
input,
|
|
165
|
+
response,
|
|
166
|
+
scores,
|
|
167
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
168
|
+
elapsedMs: Date.now() - started
|
|
169
|
+
};
|
|
170
|
+
await writeJevArtifact(file, value);
|
|
171
|
+
return await readJevArtifact(file);
|
|
172
|
+
};
|
|
173
|
+
const pendingKey = `${file}:${jevHash(userName)}`;
|
|
174
|
+
let promise = pending.get(pendingKey);
|
|
175
|
+
if (!promise) {
|
|
176
|
+
promise = getRecord();
|
|
177
|
+
pending.set(pendingKey, promise);
|
|
178
|
+
}
|
|
179
|
+
let record;
|
|
180
|
+
try {
|
|
181
|
+
record = await promise;
|
|
182
|
+
} finally {
|
|
183
|
+
pending.delete(pendingKey);
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
record,
|
|
187
|
+
assessment: {
|
|
188
|
+
...base,
|
|
189
|
+
status: "available",
|
|
190
|
+
recordId: id,
|
|
191
|
+
model: record.response.model,
|
|
192
|
+
scores: record.scores,
|
|
193
|
+
confidence: Object.fromEntries(
|
|
194
|
+
JEV_DIMENSIONS.map((key) => [
|
|
195
|
+
key,
|
|
196
|
+
record.response.answers[key]?.confidence ?? null
|
|
197
|
+
])
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
var assessSignalWithJev = async ({
|
|
203
|
+
signal,
|
|
204
|
+
config,
|
|
205
|
+
userName,
|
|
206
|
+
projectRoot,
|
|
207
|
+
strict,
|
|
208
|
+
scope = "runtime"
|
|
209
|
+
}) => {
|
|
210
|
+
let assessment;
|
|
211
|
+
try {
|
|
212
|
+
const input = buildJevInput(signal);
|
|
213
|
+
({ assessment } = await evaluateJevInput({
|
|
214
|
+
input,
|
|
215
|
+
config,
|
|
216
|
+
userName,
|
|
217
|
+
projectRoot
|
|
218
|
+
}));
|
|
219
|
+
} catch (error) {
|
|
220
|
+
if (strict) throw error;
|
|
221
|
+
assessment = {
|
|
222
|
+
schema: "tradejs-signal-assessment/v5",
|
|
223
|
+
source: config.source,
|
|
224
|
+
mode: config.mode,
|
|
225
|
+
status: "unavailable",
|
|
226
|
+
inputHash: "",
|
|
227
|
+
questionsHash: "",
|
|
228
|
+
geometryStatus: "absent",
|
|
229
|
+
levelsValid: null,
|
|
230
|
+
model: config.provider?.model ?? config.modelSha256 ?? "",
|
|
231
|
+
scores: emptyScores(),
|
|
232
|
+
confidence: emptyScores()
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
signal.assessment = assessment;
|
|
236
|
+
signal.additionalIndicators = {
|
|
237
|
+
...signal.additionalIndicators,
|
|
238
|
+
jev: {
|
|
239
|
+
schema: "tradejs-jev-features/v2",
|
|
240
|
+
status: assessment.status,
|
|
241
|
+
scores: assessment.scores,
|
|
242
|
+
confidence: assessment.confidence
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
const identity = {
|
|
246
|
+
signalId: signal.signalId,
|
|
247
|
+
strategy: signal.strategy,
|
|
248
|
+
symbol: signal.symbol,
|
|
249
|
+
timestamp: signal.timestamp,
|
|
250
|
+
scope,
|
|
251
|
+
user: jevHash(userName),
|
|
252
|
+
config,
|
|
253
|
+
assessment
|
|
254
|
+
};
|
|
255
|
+
await writeJevArtifact(
|
|
256
|
+
path.resolve(
|
|
257
|
+
projectRoot,
|
|
258
|
+
config.recordsDir ?? "data/ai/jev",
|
|
259
|
+
"decisions",
|
|
260
|
+
`${jevHash(identity)}.json`
|
|
261
|
+
),
|
|
262
|
+
identity
|
|
263
|
+
);
|
|
264
|
+
return assessment;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export {
|
|
268
|
+
resolveJevProvider,
|
|
269
|
+
evaluateJevInput,
|
|
270
|
+
assessSignalWithJev
|
|
271
|
+
};
|
|
@@ -2,12 +2,13 @@ import {
|
|
|
2
2
|
getStrategyCreator,
|
|
3
3
|
getStrategyEntry,
|
|
4
4
|
getStrategyPluginSource
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UL5Z46JL.mjs";
|
|
6
6
|
import {
|
|
7
7
|
loadTradejsConfig
|
|
8
8
|
} from "./chunk-LZDXRXIU.mjs";
|
|
9
9
|
|
|
10
10
|
// src/runtimeStrategies.ts
|
|
11
|
+
import { parseJevConfig } from "@tradejs/core/jev";
|
|
11
12
|
import { createHash } from "crypto";
|
|
12
13
|
import { readFile } from "fs/promises";
|
|
13
14
|
import path from "path";
|
|
@@ -347,7 +348,15 @@ var resolveStrategyComposition = async ({
|
|
|
347
348
|
`Strategy config parser returned a non-object: ${strategyName}`
|
|
348
349
|
);
|
|
349
350
|
}
|
|
350
|
-
const
|
|
351
|
+
const jev = parseJevConfig(declaration.config.JEV);
|
|
352
|
+
if (jev && jev.source === "provider" && !jev.provider)
|
|
353
|
+
throw new Error(
|
|
354
|
+
"Runtime JEV requires a frozen provider endpoint and model"
|
|
355
|
+
);
|
|
356
|
+
const strategyConfig = {
|
|
357
|
+
...parsedConfig,
|
|
358
|
+
...jev ? { JEV: jev } : {}
|
|
359
|
+
};
|
|
351
360
|
const selection = resolveStrategySelection({
|
|
352
361
|
deployment,
|
|
353
362
|
strategy: declaration
|
|
@@ -1034,8 +1034,11 @@ var toRecord2 = (value) => {
|
|
|
1034
1034
|
return value;
|
|
1035
1035
|
};
|
|
1036
1036
|
var buildBaseAiPayload = (signal) => {
|
|
1037
|
+
const { jevEvidence: _jevEvidence, ...signalAdditionalIndicators } = toRecord2(
|
|
1038
|
+
signal.additionalIndicators
|
|
1039
|
+
);
|
|
1037
1040
|
const additionalIndicators = {
|
|
1038
|
-
...
|
|
1041
|
+
...signalAdditionalIndicators,
|
|
1039
1042
|
marketContext: buildAiMarketContext(signal)
|
|
1040
1043
|
};
|
|
1041
1044
|
return {
|
|
@@ -5,11 +5,14 @@ import {
|
|
|
5
5
|
resolveStrategyPolicyProfile,
|
|
6
6
|
runAiPromptLocal,
|
|
7
7
|
setStrategyRuntimeFactory
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-UL5Z46JL.mjs";
|
|
9
9
|
import {
|
|
10
10
|
getTradejsProjectCwd,
|
|
11
11
|
loadTradejsConfig
|
|
12
12
|
} from "./chunk-LZDXRXIU.mjs";
|
|
13
|
+
import {
|
|
14
|
+
assessSignalWithJev
|
|
15
|
+
} from "./chunk-3BBXGZ7M.mjs";
|
|
13
16
|
|
|
14
17
|
// src/binanceBreadthUniverses.ts
|
|
15
18
|
import { createHash } from "crypto";
|
|
@@ -3104,7 +3107,8 @@ var executeEntryOrder = async ({
|
|
|
3104
3107
|
runtimeConfigId: signal.runtimeConfigId,
|
|
3105
3108
|
strategyRevision: signal.strategyRevision,
|
|
3106
3109
|
runtimeLineage: signal.runtimeLineage,
|
|
3107
|
-
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {}
|
|
3110
|
+
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {},
|
|
3111
|
+
...signal.assessment ? { assessment: signal.assessment } : {}
|
|
3108
3112
|
});
|
|
3109
3113
|
}
|
|
3110
3114
|
if (orderPlaced && recordRuntimeTrade && isPositionIncrease) {
|
|
@@ -3176,6 +3180,7 @@ var resolveStrategyConfig = async ({
|
|
|
3176
3180
|
};
|
|
3177
3181
|
|
|
3178
3182
|
// src/strategyRuntime.ts
|
|
3183
|
+
import { parseJevConfig } from "@tradejs/core/jev";
|
|
3179
3184
|
import {
|
|
3180
3185
|
BACKTEST_EXECUTION_DELAY_MS,
|
|
3181
3186
|
BACKTEST_LOWER_TIMEFRAME_EXECUTION_ENABLED
|
|
@@ -3847,6 +3852,7 @@ var handleExitDecision = async ({
|
|
|
3847
3852
|
onRuntimeClose?.({
|
|
3848
3853
|
userName,
|
|
3849
3854
|
strategy: strategyName,
|
|
3855
|
+
deploymentId: connector.deploymentId,
|
|
3850
3856
|
openedByStrategy: trade.strategy,
|
|
3851
3857
|
symbol,
|
|
3852
3858
|
direction: trade.direction,
|
|
@@ -4139,6 +4145,11 @@ var createStrategyRuntime = ({
|
|
|
4139
4145
|
const projectConfig = await loadTradejsConfig(projectRoot);
|
|
4140
4146
|
const projectHooks = projectConfig.hooks;
|
|
4141
4147
|
const env = String(config.ENV ?? "BACKTEST");
|
|
4148
|
+
const jev = parseJevConfig(config.JEV);
|
|
4149
|
+
if (jev && env !== "BACKTEST" && jev.source === "provider" && !jev.provider)
|
|
4150
|
+
throw new Error(
|
|
4151
|
+
"Runtime JEV requires a frozen provider endpoint and model"
|
|
4152
|
+
);
|
|
4142
4153
|
const backtestPriceMode = config.BACKTEST_PRICE_MODE ?? "open";
|
|
4143
4154
|
const backtestEntryDelayBars = env === "BACKTEST" ? resolveBacktestEntryDelayBars(config.BACKTEST_ENTRY_DELAY_BARS) : 0;
|
|
4144
4155
|
const resolvedBacktestExecutionInterval = config.BACKTEST_EXECUTION_INTERVAL ?? backtestExecutionMarketData?.interval ?? resolveBacktestExecutionIntervalForPrimary(config.INTERVAL ?? "15");
|
|
@@ -4846,6 +4857,16 @@ var createStrategyRuntime = ({
|
|
|
4846
4857
|
env,
|
|
4847
4858
|
includeHyperliquidWhales: false
|
|
4848
4859
|
});
|
|
4860
|
+
if (jev) {
|
|
4861
|
+
await assessSignalWithJev({
|
|
4862
|
+
signal,
|
|
4863
|
+
config: jev,
|
|
4864
|
+
userName,
|
|
4865
|
+
projectRoot,
|
|
4866
|
+
strict: env === "BACKTEST",
|
|
4867
|
+
scope: runtimeLineage?.deploymentCompositionId ?? (env === "BACKTEST" ? "backtest" : "runtime")
|
|
4868
|
+
});
|
|
4869
|
+
}
|
|
4849
4870
|
quality = await enrichSignalWithAi({
|
|
4850
4871
|
signal,
|
|
4851
4872
|
userName,
|
|
@@ -4915,6 +4936,7 @@ var createStrategyRuntime = ({
|
|
|
4915
4936
|
if (!shouldMakeOrder) {
|
|
4916
4937
|
if (signal) {
|
|
4917
4938
|
const skipReason = getEntrySkipReason({
|
|
4939
|
+
signal,
|
|
4918
4940
|
makeOrdersEnabled,
|
|
4919
4941
|
env,
|
|
4920
4942
|
ml,
|