@tradejs/node 3.1.29-beta.260 → 3.1.29-beta.262
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/backtest.js +189 -75
- package/dist/backtest.mjs +3 -3
- package/dist/{chunk-ZZQLTUTP.mjs → chunk-GHSLOJLE.mjs} +195 -69
- package/dist/{chunk-WGL7XJ3W.mjs → chunk-SKY2HNZU.mjs} +1 -1
- package/dist/{chunk-3BBXGZ7M.mjs → chunk-YR55Q355.mjs} +11 -11
- package/dist/jev.d.mts +64 -69
- package/dist/jev.d.ts +64 -69
- package/dist/jev.js +193 -75
- package/dist/jev.mjs +6 -2
- package/dist/{jevTraining-JYXUVAZG.mjs → jevTraining-J4Y4VCM4.mjs} +1 -1
- package/dist/registry.js +189 -75
- package/dist/registry.mjs +3 -3
- package/dist/runtimeDashboard.js +189 -75
- package/dist/runtimeDashboard.mjs +3 -3
- package/dist/runtimeStrategies.js +189 -75
- package/dist/runtimeStrategies.mjs +3 -3
- package/dist/strategies.js +189 -75
- package/dist/strategies.mjs +3 -3
- package/package.json +7 -6
package/dist/strategies.js
CHANGED
|
@@ -37,7 +37,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
37
37
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
38
|
|
|
39
39
|
// src/jevInput.ts
|
|
40
|
-
var import_data, import_jev, object, at, finite, fact, buildJevInput,
|
|
40
|
+
var import_data, import_jev, object, at, finite, fact, buildJevInput, JEV_COMPONENT_QUESTIONS, JEV_SIGNAL_STRENGTH_QUESTION, JEV_QUESTIONS, questionsForJevInput, groupJevFields, stateForJevInput;
|
|
41
41
|
var init_jevInput = __esm({
|
|
42
42
|
"src/jevInput.ts"() {
|
|
43
43
|
"use strict";
|
|
@@ -121,6 +121,35 @@ var init_jevInput = __esm({
|
|
|
121
121
|
const stop = finite(signal.prices.stopLossPrice);
|
|
122
122
|
const target = finite(signal.prices.takeProfitPrice);
|
|
123
123
|
const atr = baseProblem ? null : finite(at(base, "raw", "volatility", "atr"));
|
|
124
|
+
if (!baseProblem) {
|
|
125
|
+
const open = finite(at(base, "candle", "open"));
|
|
126
|
+
const close = finite(at(base, "candle", "close"));
|
|
127
|
+
const high = finite(at(base, "candle", "high"));
|
|
128
|
+
const low = finite(at(base, "candle", "low"));
|
|
129
|
+
const sign = signal.direction === "LONG" ? 1 : -1;
|
|
130
|
+
const candleFact = {
|
|
131
|
+
knownAt: baseKnownAt,
|
|
132
|
+
scope: "target",
|
|
133
|
+
source: "baseContext.candle"
|
|
134
|
+
};
|
|
135
|
+
if (open != null && close != null && atr != null && atr > 0)
|
|
136
|
+
put("entry.directionalBodyAtr", sign * (close - open) / atr, {
|
|
137
|
+
...candleFact,
|
|
138
|
+
unit: "ATR"
|
|
139
|
+
});
|
|
140
|
+
if (high != null && low != null && close != null && high > low && close >= low && close <= high) {
|
|
141
|
+
put(
|
|
142
|
+
"entry.directionalCloseLocation",
|
|
143
|
+
signal.direction === "LONG" ? (close - low) / (high - low) : (high - close) / (high - low),
|
|
144
|
+
{ ...candleFact, unit: "ratio" }
|
|
145
|
+
);
|
|
146
|
+
if (atr != null && atr > 0)
|
|
147
|
+
put("entry.rangeAtr", (high - low) / atr, {
|
|
148
|
+
...candleFact,
|
|
149
|
+
unit: "ATR"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
124
153
|
if (price == null || stop == null || target == null)
|
|
125
154
|
throw new Error("Invalid Jev signal prices");
|
|
126
155
|
put(
|
|
@@ -207,33 +236,30 @@ var init_jevInput = __esm({
|
|
|
207
236
|
);
|
|
208
237
|
const questions = import_jev.JEV_DIMENSIONS.filter((dimension) => {
|
|
209
238
|
switch (dimension) {
|
|
239
|
+
case "signalStrength":
|
|
240
|
+
return has("signal.validLevels");
|
|
210
241
|
case "trend":
|
|
211
242
|
return has("market.trendBias");
|
|
212
243
|
case "swing":
|
|
213
|
-
return has("
|
|
244
|
+
return has("setup.retracementRatio");
|
|
214
245
|
case "participation":
|
|
215
|
-
return has("market.volumeRel20")
|
|
246
|
+
return has("market.volumeRel20");
|
|
216
247
|
case "setupParticipation":
|
|
217
248
|
return setupKeys.some(
|
|
218
249
|
(key) => /volume|delta|flow|liquidity|turnover/i.test(key)
|
|
219
250
|
);
|
|
220
251
|
case "extension":
|
|
221
|
-
return has("
|
|
252
|
+
return has("setup.breakoutDistanceAtr");
|
|
222
253
|
case "confirmation":
|
|
223
|
-
return
|
|
224
|
-
(key) => /stage|confirm|retest|accept/i.test(key)
|
|
225
|
-
);
|
|
254
|
+
return has("entry.directionalBodyAtr") && has("entry.directionalCloseLocation");
|
|
226
255
|
case "setupStrength":
|
|
227
|
-
return setupKeys.some(
|
|
228
|
-
(key) => key !== "setup.version" && !/volume|delta|flow|liquidity|turnover|stage|confirm|retest|accept|breakoutDistance/i.test(
|
|
229
|
-
key
|
|
230
|
-
)
|
|
231
|
-
);
|
|
256
|
+
return setupKeys.some((key) => /efficiencyRatio$/i.test(key));
|
|
232
257
|
case "geometry":
|
|
233
258
|
return geometryStatus !== "invalid" && Object.keys(features).some((key) => key.startsWith("geometry."));
|
|
234
259
|
}
|
|
235
260
|
});
|
|
236
261
|
return {
|
|
262
|
+
questionSet: import_jev.JEV_QUESTION_SET,
|
|
237
263
|
schema: "tradejs-jev-input/v4",
|
|
238
264
|
strategy: signal.strategy,
|
|
239
265
|
symbol: signal.symbol,
|
|
@@ -247,68 +273,155 @@ var init_jevInput = __esm({
|
|
|
247
273
|
geometryStatus
|
|
248
274
|
};
|
|
249
275
|
};
|
|
250
|
-
|
|
251
|
-
`${subject} is clearly contradicted by the supplied facts.`,
|
|
252
|
-
`${subject} has a material conflict.`,
|
|
253
|
-
`${subject} is uncertain from the supplied facts.`,
|
|
254
|
-
`${subject} has adequate support.`,
|
|
255
|
-
`${subject} has strong support without a material conflict.`
|
|
256
|
-
];
|
|
257
|
-
JEV_QUESTIONS = {
|
|
276
|
+
JEV_COMPONENT_QUESTIONS = {
|
|
258
277
|
trend: {
|
|
259
278
|
type: "score",
|
|
260
|
-
instructions: "
|
|
261
|
-
criteria:
|
|
279
|
+
instructions: "Rate agreement of market.trendBias and market.swingBias with signal.direction: bull supports LONG, bear supports SHORT; neutral/unknown is inconclusive. No profit prediction.",
|
|
280
|
+
criteria: [
|
|
281
|
+
"Both oppose.",
|
|
282
|
+
"One opposes; other inconclusive.",
|
|
283
|
+
"Biases conflict, or both inconclusive.",
|
|
284
|
+
"One supports; other inconclusive.",
|
|
285
|
+
"Both support."
|
|
286
|
+
]
|
|
262
287
|
},
|
|
263
288
|
swing: {
|
|
264
289
|
type: "score",
|
|
265
|
-
instructions: "
|
|
266
|
-
criteria:
|
|
290
|
+
instructions: "Rate shallow correction using only setup.retracementRatio (correction / preceding impulse). Missing is inconclusive, not favorable.",
|
|
291
|
+
criteria: [
|
|
292
|
+
"Exceeds impulse (>1).",
|
|
293
|
+
"Deep (>0.65 to 1).",
|
|
294
|
+
"Moderate (>0.4 to 0.65), or missing.",
|
|
295
|
+
"Contained (>0.2 to 0.4).",
|
|
296
|
+
"Shallow (0 to 0.2)."
|
|
297
|
+
]
|
|
267
298
|
},
|
|
268
299
|
participation: {
|
|
269
300
|
type: "score",
|
|
270
|
-
instructions: "
|
|
271
|
-
criteria:
|
|
301
|
+
instructions: "Rate activity using only market.volumeRel20 (candle volume / trailing 20-candle mean). Not directional flow; ignore setup volume.",
|
|
302
|
+
criteria: [
|
|
303
|
+
"Very low (<0.5).",
|
|
304
|
+
"Below ordinary (0.5 to <0.8).",
|
|
305
|
+
"Ordinary (0.8 to <1.2), or missing.",
|
|
306
|
+
"Elevated (1.2 to <2).",
|
|
307
|
+
"Strong expansion (>=2)."
|
|
308
|
+
]
|
|
272
309
|
},
|
|
273
310
|
setupParticipation: {
|
|
274
311
|
type: "score",
|
|
275
|
-
instructions: "
|
|
276
|
-
criteria:
|
|
312
|
+
instructions: "Rate consolidation volume contraction using a supplied setup consolidation / preceding impulse volume ratio, e.g. setup.flagToPoleVolumeRatio. Smaller means stronger contraction. Ignore current volume and directional flow; unrelated setup semantics are inconclusive.",
|
|
313
|
+
criteria: [
|
|
314
|
+
"Exceeds impulse (>1.2).",
|
|
315
|
+
"No contraction (>0.9 to 1.2).",
|
|
316
|
+
"Mild (>0.7 to 0.9), or inconclusive.",
|
|
317
|
+
"Clear (>0.4 to 0.7).",
|
|
318
|
+
"Strong (0 to 0.4)."
|
|
319
|
+
]
|
|
277
320
|
},
|
|
278
321
|
extension: {
|
|
279
322
|
type: "score",
|
|
280
|
-
instructions: "
|
|
281
|
-
criteria:
|
|
323
|
+
instructions: "Rate absence of entry extension using only setup.breakoutDistanceAtr (distance past setup boundary in ATR). Stop/target distances are not extension.",
|
|
324
|
+
criteria: [
|
|
325
|
+
"Extreme (>2 ATR).",
|
|
326
|
+
"Large (>1 to 2 ATR).",
|
|
327
|
+
"Moderate (>0.5 to 1 ATR), or missing.",
|
|
328
|
+
"Small (>0.2 to 0.5 ATR).",
|
|
329
|
+
"Near boundary (0 to 0.2 ATR)."
|
|
330
|
+
]
|
|
282
331
|
},
|
|
283
332
|
confirmation: {
|
|
284
333
|
type: "score",
|
|
285
|
-
instructions: "
|
|
286
|
-
criteria:
|
|
334
|
+
instructions: "Rate closed entry candle conviction using entry.directionalBodyAtr (signed toward signal.direction) and entry.directionalCloseLocation (1=favorable extreme). Stage names alone prove neither conviction nor breakout retention.",
|
|
335
|
+
criteria: [
|
|
336
|
+
"Opposing body AND unfavorable-quarter close.",
|
|
337
|
+
"Opposing body OR unfavorable-half close.",
|
|
338
|
+
"Small body (<0.2 ATR), mixed or missing evidence.",
|
|
339
|
+
"Supporting body (>=0.2 ATR) AND favorable-half close.",
|
|
340
|
+
"Strong supporting body (>=0.5 ATR) AND favorable-quarter close."
|
|
341
|
+
]
|
|
287
342
|
},
|
|
288
343
|
setupStrength: {
|
|
289
344
|
type: "score",
|
|
290
|
-
instructions: "
|
|
291
|
-
criteria:
|
|
345
|
+
instructions: "Rate impulse persistence using only supplied setup efficiency (absolute net move / sum of absolute bar moves), e.g. setup.poleEfficiencyRatio. Exclude size, volume, correction and geometry.",
|
|
346
|
+
criteria: [
|
|
347
|
+
"Highly choppy (<0.2).",
|
|
348
|
+
"Weak (0.2 to <0.4).",
|
|
349
|
+
"Mixed (0.4 to <0.6), or missing.",
|
|
350
|
+
"Clear (0.6 to <0.8).",
|
|
351
|
+
"Highly persistent (0.8 to 1)."
|
|
352
|
+
]
|
|
292
353
|
},
|
|
293
354
|
geometry: {
|
|
294
355
|
type: "score",
|
|
295
|
-
instructions: "
|
|
296
|
-
criteria:
|
|
356
|
+
instructions: "Rate fitted consolidation boundaries jointly: geometry.upperR2 and lowerR2 (1=best fit), slopeDivergenceRatio (0=parallel). Use the weaker fit; exclude depth, width, volume and profit. Missing equivalent geometry is inconclusive.",
|
|
357
|
+
criteria: [
|
|
358
|
+
"Fit <0.5 OR divergence >0.5.",
|
|
359
|
+
"Fit <0.7 OR divergence >0.3.",
|
|
360
|
+
"Fit <0.85 OR divergence >0.15, or missing.",
|
|
361
|
+
"Both fits >=0.85 AND divergence <=0.15.",
|
|
362
|
+
"Both fits >=0.95 AND divergence <=0.05."
|
|
363
|
+
]
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
JEV_SIGNAL_STRENGTH_QUESTION = {
|
|
367
|
+
type: "score",
|
|
368
|
+
instructions: "Rate overall support for entry now from signal-time facts: direction, market, setup, candle, placement, relevant geometry and stop/target plan. No other Jev answers, future prices or outcomes. Essential missing facts and conflicts weaken support; optional missing geometry alone does not disqualify. Invalid signal.validLevels cannot rate strong. Not win probability or execution permission. Criteria 1\u201310 map to API indices 0\u20139.",
|
|
369
|
+
criteria: [
|
|
370
|
+
"1: Invalid levels or decisive contrary evidence.",
|
|
371
|
+
"2: Severe directional/setup conflicts; poor support.",
|
|
372
|
+
"3: Substantial weaknesses outweigh support.",
|
|
373
|
+
"4: Some support; material weakness makes entry unattractive.",
|
|
374
|
+
"5: Balanced conflicts or essential evidence missing.",
|
|
375
|
+
"6: Modest coherent support; reasonable but limited evidence.",
|
|
376
|
+
"7: Convincing support from several facts; remaining weakness.",
|
|
377
|
+
"8: Strong coherent support, suitable placement/plan; no material conflict.",
|
|
378
|
+
"9: Very strong independent support; well-defined entry/stop/target plan.",
|
|
379
|
+
"10: Exceptional coherent support and plan; no visible material weakness, profit uncertain."
|
|
380
|
+
]
|
|
381
|
+
};
|
|
382
|
+
JEV_QUESTIONS = {
|
|
383
|
+
...JEV_COMPONENT_QUESTIONS,
|
|
384
|
+
signalStrength: JEV_SIGNAL_STRENGTH_QUESTION
|
|
385
|
+
};
|
|
386
|
+
questionsForJevInput = (input) => {
|
|
387
|
+
if (input.questionSet !== import_jev.JEV_QUESTION_SET)
|
|
388
|
+
throw new Error(
|
|
389
|
+
"Unsupported Jev recording question set; rerun the backtest with --jev"
|
|
390
|
+
);
|
|
391
|
+
return Object.fromEntries(
|
|
392
|
+
input.questions.map((key) => {
|
|
393
|
+
const question = JEV_QUESTIONS[key];
|
|
394
|
+
if (!question) throw new Error("Unknown Jev question");
|
|
395
|
+
return [key, question];
|
|
396
|
+
})
|
|
397
|
+
);
|
|
398
|
+
};
|
|
399
|
+
groupJevFields = (entries) => {
|
|
400
|
+
const groups = /* @__PURE__ */ new Map();
|
|
401
|
+
const flat = [];
|
|
402
|
+
for (const [key, value] of entries) {
|
|
403
|
+
const separator = key.indexOf(".");
|
|
404
|
+
if (separator < 0) {
|
|
405
|
+
flat.push([key, value]);
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
const namespace = key.slice(0, separator);
|
|
409
|
+
const group = groups.get(namespace) ?? [];
|
|
410
|
+
group.push([key.slice(separator + 1), value]);
|
|
411
|
+
groups.set(namespace, group);
|
|
297
412
|
}
|
|
413
|
+
return Object.fromEntries([
|
|
414
|
+
...flat,
|
|
415
|
+
...Array.from(groups, ([key, fields]) => [key, Object.fromEntries(fields)])
|
|
416
|
+
]);
|
|
298
417
|
};
|
|
299
|
-
questionsForJevInput = (input) => Object.fromEntries(input.questions.map((key) => [key, JEV_QUESTIONS[key]]));
|
|
300
418
|
stateForJevInput = (input) => ({
|
|
301
|
-
schema: input.schema,
|
|
302
419
|
strategy: input.strategy,
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
missing: input.missing,
|
|
420
|
+
facts: groupJevFields(Object.entries(input.features)),
|
|
421
|
+
missing: groupJevFields(Object.entries(input.missing)),
|
|
306
422
|
geometryStatus: input.geometryStatus,
|
|
307
|
-
units:
|
|
423
|
+
units: groupJevFields(
|
|
308
424
|
Object.entries(input.provenance).filter(([, detail]) => detail.unit != null).map(([key, detail]) => [key, detail.unit])
|
|
309
|
-
),
|
|
310
|
-
sources: Object.fromEntries(
|
|
311
|
-
Object.entries(input.provenance).filter(([, detail]) => detail.source != null).map(([key, detail]) => [key, detail.source])
|
|
312
425
|
)
|
|
313
426
|
});
|
|
314
427
|
}
|
|
@@ -342,7 +455,7 @@ var init_jevTraining = __esm({
|
|
|
342
455
|
);
|
|
343
456
|
for (const row of rows) {
|
|
344
457
|
const record = row?.record;
|
|
345
|
-
if (row?.schema !== "tradejs-jev-study/v4" || !row.signalId || record?.schema !== "tradejs-jev-record/v4" || record.input?.schema !== "tradejs-jev-input/v4" || !Number.isFinite(record.input.timestamp) || record.inputHash !== (0, import_jev3.jevHash)(record.input) || record.questionsHash !== (0, import_jev3.jevHash)(questionsForJevInput(record.input)) || record.id !== (0, import_jev3.jevHash)({
|
|
458
|
+
if (row?.schema !== "tradejs-jev-study/v4" || !row.signalId || record?.schema !== "tradejs-jev-record/v4" || record.input?.schema !== "tradejs-jev-input/v4" || record.input.questionSet !== import_jev2.JEV_QUESTION_SET || !Number.isFinite(record.input.timestamp) || record.inputHash !== (0, import_jev3.jevHash)(record.input) || record.questionsHash !== (0, import_jev3.jevHash)(questionsForJevInput(record.input)) || record.id !== (0, import_jev3.jevHash)({
|
|
346
459
|
inputHash: record.inputHash,
|
|
347
460
|
questionsHash: record.questionsHash,
|
|
348
461
|
provider: record.provider
|
|
@@ -350,7 +463,7 @@ var init_jevTraining = __esm({
|
|
|
350
463
|
throw new Error("Invalid Jev study provenance");
|
|
351
464
|
(0, import_jev3.validateJevResponse)(record.response, record.input.questions);
|
|
352
465
|
for (const dimension of import_jev2.JEV_DIMENSIONS) {
|
|
353
|
-
const expected = record.input.questions.includes(dimension) ? record.response.answers[dimension].score /
|
|
466
|
+
const expected = record.input.questions.includes(dimension) ? record.response.answers[dimension].score / (0, import_jev3.jevScoreMaximum)(dimension) : null;
|
|
354
467
|
if (record.scores[dimension] !== expected)
|
|
355
468
|
throw new Error("Jev study scores do not match the teacher response");
|
|
356
469
|
}
|
|
@@ -433,10 +546,12 @@ var init_jevTraining = __esm({
|
|
|
433
546
|
};
|
|
434
547
|
validateJevGateModel = (value) => {
|
|
435
548
|
const model = value;
|
|
436
|
-
if (model?.schema !== "tradejs-jev-gate/v2" || model.inputSchema !== "tradejs-jev-input/v4" || typeof model.strategy !== "string" || !model.strategy || !model.teacherModel || !model.trees || model.
|
|
549
|
+
if (model?.schema !== "tradejs-jev-gate/v2" || model.inputSchema !== "tradejs-jev-input/v4" || typeof model.strategy !== "string" || !model.strategy || !model.teacherModel || !model.trees || model.questionSet !== import_jev2.JEV_QUESTION_SET || import_jev2.JEV_DIMENSIONS.some((dimension) => !(dimension in model.trees)) || Object.keys(model.trees).some(
|
|
550
|
+
(dimension) => !import_jev2.JEV_DIMENSIONS.includes(dimension)
|
|
551
|
+
) || model.questionsHash !== (0, import_jev3.jevHash)(JEV_QUESTIONS) || !model.training || !/^[a-f0-9]{64}$/.test(model.training.datasetHash))
|
|
437
552
|
throw new Error("Invalid local Jev gate");
|
|
438
553
|
const { trainEnd, validationEnd, testEnd } = model.training;
|
|
439
|
-
if (![trainEnd, validationEnd, testEnd].every(Number.isFinite) || !(trainEnd
|
|
554
|
+
if (![trainEnd, validationEnd, testEnd].every(Number.isFinite) || model.training.split !== "outer-60-40" || !(trainEnd === validationEnd && trainEnd < testEnd))
|
|
440
555
|
throw new Error("Invalid local Jev gate partitions");
|
|
441
556
|
const check = (tree, depth) => {
|
|
442
557
|
if (!tree || depth > 8) throw new Error("Invalid local Jev tree");
|
|
@@ -572,13 +687,10 @@ var init_jevTraining = __esm({
|
|
|
572
687
|
];
|
|
573
688
|
if (rows.length < 30 || timestamps.length < 10)
|
|
574
689
|
throw new Error("Need at least 30 distinct samples across 10 signal times");
|
|
575
|
-
const trainEnd = timestamps[Math.floor(timestamps.length * 0.
|
|
576
|
-
const validationEnd =
|
|
690
|
+
const trainEnd = timestamps[timestamps.length - Math.max(1, Math.floor(timestamps.length * 0.4)) - 1];
|
|
691
|
+
const validationEnd = trainEnd;
|
|
577
692
|
const train = rows.filter((row) => row.record.input.timestamp <= trainEnd);
|
|
578
|
-
const
|
|
579
|
-
(row) => row.record.input.timestamp > trainEnd && row.record.input.timestamp <= validationEnd
|
|
580
|
-
);
|
|
581
|
-
const test = rows.filter((row) => row.record.input.timestamp > validationEnd);
|
|
693
|
+
const test = rows.filter((row) => row.record.input.timestamp > trainEnd);
|
|
582
694
|
const fit = (samples) => Object.fromEntries(
|
|
583
695
|
import_jev2.JEV_DIMENSIONS.map((key) => {
|
|
584
696
|
const eligible = samples.filter(
|
|
@@ -595,10 +707,12 @@ var init_jevTraining = __esm({
|
|
|
595
707
|
schema: "tradejs-jev-gate/v2",
|
|
596
708
|
inputSchema: "tradejs-jev-input/v4",
|
|
597
709
|
strategy: first.input.strategy,
|
|
710
|
+
questionSet: import_jev2.JEV_QUESTION_SET,
|
|
598
711
|
questionsHash: (0, import_jev3.jevHash)(JEV_QUESTIONS),
|
|
599
712
|
teacherModel: first.response.model,
|
|
600
713
|
trees: fit(train),
|
|
601
714
|
training: {
|
|
715
|
+
split: "outer-60-40",
|
|
602
716
|
datasetHash: (0, import_jev3.jevHash)(
|
|
603
717
|
rows.map((row) => ({
|
|
604
718
|
id: row.record.id,
|
|
@@ -613,18 +727,20 @@ var init_jevTraining = __esm({
|
|
|
613
727
|
}
|
|
614
728
|
};
|
|
615
729
|
validateJevGateModel(model);
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
730
|
+
const developmentTimes = timestamps.filter(
|
|
731
|
+
(timestamp) => timestamp <= trainEnd
|
|
732
|
+
);
|
|
733
|
+
const walkForward = [0.25, 0.5, 0.75].map((fraction) => {
|
|
734
|
+
const trainThrough = developmentTimes[Math.max(0, Math.floor(developmentTimes.length * fraction) - 1)];
|
|
735
|
+
const testThrough = developmentTimes[Math.min(
|
|
736
|
+
developmentTimes.length - 1,
|
|
737
|
+
Math.floor(developmentTimes.length * (fraction + 0.25)) - 1
|
|
622
738
|
)];
|
|
623
|
-
const fitting =
|
|
739
|
+
const fitting = train.filter(
|
|
624
740
|
(row) => row.record.input.timestamp <= trainThrough
|
|
625
741
|
);
|
|
626
|
-
const evaluation =
|
|
627
|
-
(row) => row.record.input.timestamp >
|
|
742
|
+
const evaluation = train.filter(
|
|
743
|
+
(row) => row.record.input.timestamp > trainThrough && row.record.input.timestamp <= testThrough
|
|
628
744
|
);
|
|
629
745
|
const fold = {
|
|
630
746
|
...model,
|
|
@@ -632,13 +748,13 @@ var init_jevTraining = __esm({
|
|
|
632
748
|
training: {
|
|
633
749
|
...model.training,
|
|
634
750
|
trainEnd: trainThrough,
|
|
635
|
-
validationEnd:
|
|
751
|
+
validationEnd: trainThrough,
|
|
636
752
|
testEnd: testThrough
|
|
637
753
|
}
|
|
638
754
|
};
|
|
639
755
|
return {
|
|
640
756
|
trainThrough,
|
|
641
|
-
validationThrough,
|
|
757
|
+
validationThrough: trainThrough,
|
|
642
758
|
testThrough,
|
|
643
759
|
trainRows: fitting.length,
|
|
644
760
|
test: compareJevGate(fold, evaluation)
|
|
@@ -648,7 +764,8 @@ var init_jevTraining = __esm({
|
|
|
648
764
|
model,
|
|
649
765
|
report: {
|
|
650
766
|
train: compareJevGate(model, train),
|
|
651
|
-
|
|
767
|
+
partitionScheme: "outer-60-40",
|
|
768
|
+
stabilityRole: "independently fitted folds inside development only",
|
|
652
769
|
test: compareJevGate(model, test),
|
|
653
770
|
walkForward,
|
|
654
771
|
promotion: "research-only; validate a sequential backtest and prospective signals before runtime admission"
|
|
@@ -2576,6 +2693,7 @@ var evaluateJevInput = async ({
|
|
|
2576
2693
|
const questions = questionsForJevInput(input);
|
|
2577
2694
|
const questionsHash = (0, import_jev5.jevHash)(questions);
|
|
2578
2695
|
const base = {
|
|
2696
|
+
questionSet: import_jev4.JEV_QUESTION_SET,
|
|
2579
2697
|
schema: "tradejs-signal-assessment/v5",
|
|
2580
2698
|
source: config.source,
|
|
2581
2699
|
mode: config.mode,
|
|
@@ -2632,7 +2750,7 @@ var evaluateJevInput = async ({
|
|
|
2632
2750
|
throw new Error("Jev recording identity mismatch");
|
|
2633
2751
|
(0, import_jev5.validateJevResponse)(existing.response, input.questions);
|
|
2634
2752
|
for (const key of import_jev4.JEV_DIMENSIONS) {
|
|
2635
|
-
const expected = input.questions.includes(key) ? existing.response.answers[key].score /
|
|
2753
|
+
const expected = input.questions.includes(key) ? existing.response.answers[key].score / (0, import_jev5.jevScoreMaximum)(key) : null;
|
|
2636
2754
|
if (existing.scores[key] !== expected)
|
|
2637
2755
|
throw new Error("Jev recording scores do not match the response");
|
|
2638
2756
|
}
|
|
@@ -2680,7 +2798,7 @@ var evaluateJevInput = async ({
|
|
|
2680
2798
|
const scores = Object.fromEntries(
|
|
2681
2799
|
import_jev4.JEV_DIMENSIONS.map((key) => [
|
|
2682
2800
|
key,
|
|
2683
|
-
input.questions.includes(key) ? response.answers[key].score /
|
|
2801
|
+
input.questions.includes(key) ? response.answers[key].score / (0, import_jev5.jevScoreMaximum)(key) : null
|
|
2684
2802
|
])
|
|
2685
2803
|
);
|
|
2686
2804
|
const value = {
|
|
@@ -2747,6 +2865,7 @@ var assessSignalWithJev = async ({
|
|
|
2747
2865
|
} catch (error) {
|
|
2748
2866
|
if (strict) throw error;
|
|
2749
2867
|
assessment = {
|
|
2868
|
+
questionSet: import_jev4.JEV_QUESTION_SET,
|
|
2750
2869
|
schema: "tradejs-signal-assessment/v5",
|
|
2751
2870
|
source: config.source,
|
|
2752
2871
|
mode: config.mode,
|
|
@@ -2763,12 +2882,7 @@ var assessSignalWithJev = async ({
|
|
|
2763
2882
|
signal.assessment = assessment;
|
|
2764
2883
|
signal.additionalIndicators = {
|
|
2765
2884
|
...signal.additionalIndicators,
|
|
2766
|
-
jev:
|
|
2767
|
-
schema: "tradejs-jev-features/v2",
|
|
2768
|
-
status: assessment.status,
|
|
2769
|
-
scores: assessment.scores,
|
|
2770
|
-
confidence: assessment.confidence
|
|
2771
|
-
}
|
|
2885
|
+
jev: (0, import_jev4.jevAssessmentFeatures)(assessment)
|
|
2772
2886
|
};
|
|
2773
2887
|
const identity = {
|
|
2774
2888
|
signalId: signal.signalId,
|
package/dist/strategies.mjs
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
resolveHyperliquidPerpFromSignalSymbol,
|
|
24
24
|
resolveStrategyConfig,
|
|
25
25
|
validateEntryProtectionAtArrival
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-SKY2HNZU.mjs";
|
|
27
27
|
import {
|
|
28
28
|
DEFAULT_AI_MODEL,
|
|
29
29
|
MAX_AI_SERIES_POINTS,
|
|
@@ -55,8 +55,8 @@ import {
|
|
|
55
55
|
trimSeriesDeep
|
|
56
56
|
} from "./chunk-UL5Z46JL.mjs";
|
|
57
57
|
import "./chunk-LZDXRXIU.mjs";
|
|
58
|
-
import "./chunk-
|
|
59
|
-
import "./chunk-
|
|
58
|
+
import "./chunk-YR55Q355.mjs";
|
|
59
|
+
import "./chunk-GHSLOJLE.mjs";
|
|
60
60
|
import "./chunk-Y6FXYEAI.mjs";
|
|
61
61
|
|
|
62
62
|
// src/strategies.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/node",
|
|
3
|
-
"version": "3.1.29-beta.
|
|
3
|
+
"version": "3.1.29-beta.262",
|
|
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",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"coinbase",
|
|
17
17
|
"ai",
|
|
18
18
|
"claude",
|
|
19
|
-
"codex"
|
|
19
|
+
"codex",
|
|
20
|
+
"jev"
|
|
20
21
|
],
|
|
21
22
|
"repository": {
|
|
22
23
|
"type": "git",
|
|
@@ -94,9 +95,9 @@
|
|
|
94
95
|
"dependencies": {
|
|
95
96
|
"@langchain/core": "^1.2.3",
|
|
96
97
|
"@langchain/openai": "^1.5.5",
|
|
97
|
-
"@tradejs/core": "^3.1.29-beta.
|
|
98
|
-
"@tradejs/infra": "^3.1.29-beta.
|
|
99
|
-
"@tradejs/types": "^3.1.29-beta.
|
|
98
|
+
"@tradejs/core": "^3.1.29-beta.262",
|
|
99
|
+
"@tradejs/infra": "^3.1.29-beta.262",
|
|
100
|
+
"@tradejs/types": "^3.1.29-beta.262",
|
|
100
101
|
"@types/node": "^24",
|
|
101
102
|
"chalk": "4.1.2",
|
|
102
103
|
"ioredis": "5.11.1",
|
|
@@ -109,7 +110,7 @@
|
|
|
109
110
|
"typescript": "^5.9"
|
|
110
111
|
},
|
|
111
112
|
"devDependencies": {
|
|
112
|
-
"@tradejs/indicators": "^3.1.29-beta.
|
|
113
|
+
"@tradejs/indicators": "^3.1.29-beta.262",
|
|
113
114
|
"@tradejs/strategy-adaptive-momentum-ribbon": "3.0.2",
|
|
114
115
|
"@tradejs/strategy-hyperliquid-consensus": "3.0.2",
|
|
115
116
|
"@tradejs/strategy-kit": "3.0.6",
|