@tradejs/cli 3.1.29-beta.283 → 3.1.29-beta.284
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/cli.js +4877 -1182
- package/dist/lib/aiPocketSearch.js +3 -0
- package/dist/lib/aiTrainResearch.js +7 -0
- package/dist/lib/coreResearch.js +111 -36
- package/dist/lib/strategyResearch.js +6483 -0
- package/dist/scripts/aiPocketSearch.js +3 -0
- package/dist/scripts/coreResearch.js +113 -38
- package/dist/scripts/mcpWorker.js +16 -2
- package/dist/scripts/strategyResearch.js +6904 -0
- package/package.json +8 -7
|
@@ -39,6 +39,7 @@ var DAYS_PER_WEEK = 7;
|
|
|
39
39
|
var DAYS_PER_MONTH = 30.4375;
|
|
40
40
|
var PRODUCTION_CANDIDATE_MIN_EVENTS = 25;
|
|
41
41
|
var OUTCOME_SEGMENTS = /* @__PURE__ */ new Set([
|
|
42
|
+
"researchentrydecision",
|
|
42
43
|
"actual",
|
|
43
44
|
"aiapproved",
|
|
44
45
|
"approvalallowednow",
|
|
@@ -323,6 +324,8 @@ var classifyAiPocketFeaturePath = (path) => {
|
|
|
323
324
|
if (METADATA_LEAVES.has(leaf) || leaf.endsWith("fingerprint") || normalized.some((segment) => segment === "metadata")) {
|
|
324
325
|
return "metadata";
|
|
325
326
|
}
|
|
327
|
+
if (normalized.some((segment) => OUTCOME_SEGMENTS.has(segment)))
|
|
328
|
+
return "derived-policy";
|
|
326
329
|
if (DERIVED_POLICY_FRAGMENTS.some(
|
|
327
330
|
(fragment) => !(fragment === "gatefeature" && isStrategySetupEvidence) && normalizedPath.includes(fragment)
|
|
328
331
|
)) {
|
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var aiTrainResearch_exports = {};
|
|
32
32
|
__export(aiTrainResearch_exports, {
|
|
33
33
|
buildAiTrainLineage: () => buildAiTrainLineage,
|
|
34
|
+
fingerprintResearchContextEnvironment: () => fingerprintResearchContextEnvironment,
|
|
34
35
|
fingerprintResearchValue: () => fingerprintResearchValue,
|
|
35
36
|
summarizeAiTrainCoverage: () => summarizeAiTrainCoverage,
|
|
36
37
|
summarizeAiTrainRejectReasons: () => summarizeAiTrainRejectReasons,
|
|
@@ -548,6 +549,11 @@ var getGitLineage = (projectRoot) => {
|
|
|
548
549
|
return { gitSha: null, gitDirty: null };
|
|
549
550
|
}
|
|
550
551
|
};
|
|
552
|
+
var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintResearchValue(
|
|
553
|
+
Object.fromEntries(
|
|
554
|
+
RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
|
|
555
|
+
)
|
|
556
|
+
);
|
|
551
557
|
var buildAiTrainLineage = async ({
|
|
552
558
|
projectRoot,
|
|
553
559
|
strategyName,
|
|
@@ -588,6 +594,7 @@ var buildAiTrainLineage = async ({
|
|
|
588
594
|
// Annotate the CommonJS export names for ESM import in node:
|
|
589
595
|
0 && (module.exports = {
|
|
590
596
|
buildAiTrainLineage,
|
|
597
|
+
fingerprintResearchContextEnvironment,
|
|
591
598
|
fingerprintResearchValue,
|
|
592
599
|
summarizeAiTrainCoverage,
|
|
593
600
|
summarizeAiTrainRejectReasons,
|
package/dist/lib/coreResearch.js
CHANGED
|
@@ -45,7 +45,7 @@ __export(coreResearch_exports, {
|
|
|
45
45
|
module.exports = __toCommonJS(coreResearch_exports);
|
|
46
46
|
|
|
47
47
|
// src/lib/coreResearch/orchestrator.ts
|
|
48
|
-
var
|
|
48
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
49
49
|
var import_node_path6 = __toESM(require("path"));
|
|
50
50
|
var import_node_child_process = require("child_process");
|
|
51
51
|
var import_node_crypto5 = require("crypto");
|
|
@@ -1019,6 +1019,8 @@ var calendarClusterBootstrap = (params) => {
|
|
|
1019
1019
|
const alpha = 1 - params.confidenceLevel;
|
|
1020
1020
|
const positive = samples.filter((value) => value > 0).length;
|
|
1021
1021
|
const probabilityPositive = positive / samples.length;
|
|
1022
|
+
const observed = deltas.reduce((sum, value) => sum + value, 0) / deltas.length;
|
|
1023
|
+
const oneSidedPValue = (1 + samples.filter((value) => value - observed >= observed - 1e-12).length) / (samples.length + 1);
|
|
1022
1024
|
return {
|
|
1023
1025
|
method: "calendar-cluster-bootstrap",
|
|
1024
1026
|
clusterDays: params.clusterDays,
|
|
@@ -1030,7 +1032,7 @@ var calendarClusterBootstrap = (params) => {
|
|
|
1030
1032
|
percentile(samples, 1 - alpha / 2)
|
|
1031
1033
|
],
|
|
1032
1034
|
probabilityPositive,
|
|
1033
|
-
oneSidedPValue
|
|
1035
|
+
oneSidedPValue,
|
|
1034
1036
|
holmAdjustedPValue: null
|
|
1035
1037
|
};
|
|
1036
1038
|
};
|
|
@@ -1097,7 +1099,7 @@ var erf = (value) => {
|
|
|
1097
1099
|
return sign * y;
|
|
1098
1100
|
};
|
|
1099
1101
|
var normalCdf = (value) => 0.5 * (1 + erf(value / Math.SQRT2));
|
|
1100
|
-
var deflatedSharpeDiagnostic = (returns, trials) => {
|
|
1102
|
+
var deflatedSharpeDiagnostic = (returns, trials, trialSharpes) => {
|
|
1101
1103
|
const periods = returns.length;
|
|
1102
1104
|
if (periods < 3) {
|
|
1103
1105
|
return {
|
|
@@ -1122,9 +1124,18 @@ var deflatedSharpeDiagnostic = (returns, trials) => {
|
|
|
1122
1124
|
const observedSharpe = mean / standardDeviation;
|
|
1123
1125
|
const skew = centered.reduce((sum, value) => sum + (value / standardDeviation) ** 3, 0) / periods;
|
|
1124
1126
|
const kurtosis = centered.reduce((sum, value) => sum + (value / standardDeviation) ** 4, 0) / periods;
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1127
|
-
|
|
1127
|
+
const available = trialSharpes?.filter(Number.isFinite) ?? [];
|
|
1128
|
+
if (trials > 1 && available.length < 2)
|
|
1129
|
+
return {
|
|
1130
|
+
periods,
|
|
1131
|
+
observedSharpe,
|
|
1132
|
+
expectedMaximumSharpe: null,
|
|
1133
|
+
probabilityAboveSelectionBias: null
|
|
1134
|
+
};
|
|
1135
|
+
const trialMean = available.length ? available.reduce((sum, value) => sum + value, 0) / available.length : 0;
|
|
1136
|
+
const trialVariance = available.length > 1 ? available.reduce((sum, value) => sum + (value - trialMean) ** 2, 0) / (available.length - 1) : 0;
|
|
1137
|
+
const gamma = 0.5772156649015329;
|
|
1138
|
+
const expectedMaximumSharpe = trials <= 1 ? 0 : Math.sqrt(trialVariance) * ((1 - gamma) * inverseNormalCdf(1 - 1 / trials) + gamma * inverseNormalCdf(1 - 1 / (trials * Math.E)));
|
|
1128
1139
|
const standardError = Math.sqrt(
|
|
1129
1140
|
Math.max(
|
|
1130
1141
|
1e-12,
|
|
@@ -1142,6 +1153,27 @@ var deflatedSharpeDiagnostic = (returns, trials) => {
|
|
|
1142
1153
|
};
|
|
1143
1154
|
var combinations = (items, choose) => {
|
|
1144
1155
|
const output = [];
|
|
1156
|
+
if (items.length > 10) {
|
|
1157
|
+
const random = createSeededRandom(`cscv-balanced-${items.length}`);
|
|
1158
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1159
|
+
for (let attempt = 0; output.length < 512 && attempt < 1e5; attempt++) {
|
|
1160
|
+
const shuffled = [...items];
|
|
1161
|
+
for (let index = shuffled.length - 1; index > 0; index--) {
|
|
1162
|
+
const swap = Math.floor(random() * (index + 1));
|
|
1163
|
+
[shuffled[index], shuffled[swap]] = [shuffled[swap], shuffled[index]];
|
|
1164
|
+
}
|
|
1165
|
+
const selected = shuffled.slice(0, choose).sort((a, b) => a - b);
|
|
1166
|
+
const complement = items.filter((item) => !selected.includes(item));
|
|
1167
|
+
for (const half of [selected, complement]) {
|
|
1168
|
+
const key = half.join(",");
|
|
1169
|
+
if (!seen.has(key)) {
|
|
1170
|
+
seen.add(key);
|
|
1171
|
+
output.push(half);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return output;
|
|
1176
|
+
}
|
|
1145
1177
|
const visit = (start, selected) => {
|
|
1146
1178
|
if (output.length >= 512) return;
|
|
1147
1179
|
if (selected.length === choose) {
|
|
@@ -1180,14 +1212,23 @@ var probabilityOfBacktestOverfitting = (performanceByVariant) => {
|
|
|
1180
1212
|
const inScores = performanceByVariant.map(
|
|
1181
1213
|
(performance) => inSample.reduce((sum, index) => sum + performance[index], 0)
|
|
1182
1214
|
);
|
|
1183
|
-
const
|
|
1215
|
+
const maximum = Math.max(...inScores);
|
|
1216
|
+
const selected = inScores.flatMap(
|
|
1217
|
+
(score, index) => score === maximum ? [index] : []
|
|
1218
|
+
);
|
|
1184
1219
|
const outScores = performanceByVariant.map(
|
|
1185
1220
|
(performance) => outSample.reduce((sum, index) => sum + performance[index], 0)
|
|
1186
1221
|
);
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1222
|
+
for (const winner of selected) {
|
|
1223
|
+
const less = outScores.filter(
|
|
1224
|
+
(score) => score < outScores[winner]
|
|
1225
|
+
).length;
|
|
1226
|
+
const equal = outScores.filter(
|
|
1227
|
+
(score) => score === outScores[winner]
|
|
1228
|
+
).length;
|
|
1229
|
+
const omega = (less + (equal + 1) / 2) / (outScores.length + 1);
|
|
1230
|
+
if (omega < 0.5) belowMedian += 1 / selected.length;
|
|
1231
|
+
}
|
|
1191
1232
|
}
|
|
1192
1233
|
return {
|
|
1193
1234
|
method: "CSCV",
|
|
@@ -2117,34 +2158,55 @@ var applyCoreResearchRobustnessGuardrails = (params) => {
|
|
|
2117
2158
|
};
|
|
2118
2159
|
|
|
2119
2160
|
// src/lib/coreResearch/trace.ts
|
|
2120
|
-
var
|
|
2161
|
+
var import_node_fs4 = require("fs");
|
|
2162
|
+
var import_node_readline2 = __toESM(require("readline"));
|
|
2121
2163
|
var import_node_path4 = __toESM(require("path"));
|
|
2122
2164
|
var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
2123
2165
|
const events = /* @__PURE__ */ Object.create(null);
|
|
2124
2166
|
const skipCounts = /* @__PURE__ */ Object.create(null);
|
|
2125
2167
|
const exitCodes = /* @__PURE__ */ Object.create(null);
|
|
2168
|
+
const policyRejections = {};
|
|
2169
|
+
const policyExamples = [];
|
|
2126
2170
|
for (const inputPath of filePaths) {
|
|
2127
2171
|
const filePath = import_node_path4.default.resolve(inputPath);
|
|
2128
|
-
const
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2172
|
+
const input = (0, import_node_fs4.createReadStream)(filePath);
|
|
2173
|
+
const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
|
|
2174
|
+
let index = -1;
|
|
2175
|
+
try {
|
|
2176
|
+
for await (const line of lines) {
|
|
2177
|
+
index++;
|
|
2178
|
+
if (!line.trim()) continue;
|
|
2179
|
+
let event;
|
|
2180
|
+
try {
|
|
2181
|
+
event = JSON.parse(line);
|
|
2182
|
+
} catch (error) {
|
|
2183
|
+
throw new Error(
|
|
2184
|
+
`${filePath}:${index + 1} contains invalid trace JSON: ${String(error)}`
|
|
2185
|
+
);
|
|
2186
|
+
}
|
|
2187
|
+
events[event.event] = (events[event.event] ?? 0) + 1;
|
|
2188
|
+
if (event.event === "skip_summary") {
|
|
2189
|
+
for (const [reason, count] of Object.entries(event.skipCounts)) {
|
|
2190
|
+
skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
if (event.event === "position_exited" && event.exitCode) {
|
|
2194
|
+
exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
|
|
2195
|
+
}
|
|
2196
|
+
if ("researchEntryDecision" in event && event.researchEntryDecision && !event.researchEntryDecision.allowed) {
|
|
2197
|
+
const reason = event.researchEntryDecision.reason;
|
|
2198
|
+
policyRejections[reason] = (policyRejections[reason] ?? 0) + 1;
|
|
2199
|
+
if (policyExamples.length < 20)
|
|
2200
|
+
policyExamples.push({
|
|
2201
|
+
timestamp: event.timestamp,
|
|
2202
|
+
symbol: event.symbol,
|
|
2203
|
+
decision: event.researchEntryDecision
|
|
2204
|
+
});
|
|
2143
2205
|
}
|
|
2144
2206
|
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2207
|
+
} finally {
|
|
2208
|
+
lines.close();
|
|
2209
|
+
input.destroy();
|
|
2148
2210
|
}
|
|
2149
2211
|
}
|
|
2150
2212
|
return {
|
|
@@ -2158,7 +2220,13 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
|
2158
2220
|
Object.entries(exitCodes).sort(
|
|
2159
2221
|
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
2160
2222
|
)
|
|
2161
|
-
)
|
|
2223
|
+
),
|
|
2224
|
+
...policyExamples.length ? {
|
|
2225
|
+
researchPolicy: {
|
|
2226
|
+
rejections: policyRejections,
|
|
2227
|
+
examples: policyExamples
|
|
2228
|
+
}
|
|
2229
|
+
} : {}
|
|
2162
2230
|
};
|
|
2163
2231
|
};
|
|
2164
2232
|
|
|
@@ -2417,7 +2485,14 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
|
|
|
2417
2485
|
analysis.variant.id,
|
|
2418
2486
|
deflatedSharpeDiagnostic(
|
|
2419
2487
|
analysis.monthly.map((window) => window.cohorts.ALL.pnl),
|
|
2420
|
-
Math.max(comparisons.length, familyHypotheses)
|
|
2488
|
+
Math.max(comparisons.length, familyHypotheses),
|
|
2489
|
+
analyses.flatMap((entry) => {
|
|
2490
|
+
const diagnostic = deflatedSharpeDiagnostic(
|
|
2491
|
+
entry.monthly.map((window) => window.cohorts.ALL.pnl),
|
|
2492
|
+
1
|
|
2493
|
+
);
|
|
2494
|
+
return diagnostic.observedSharpe == null ? [] : [diagnostic.observedSharpe];
|
|
2495
|
+
})
|
|
2421
2496
|
)
|
|
2422
2497
|
])
|
|
2423
2498
|
),
|
|
@@ -2442,7 +2517,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
|
|
|
2442
2517
|
const tradesByVariant = new Map(
|
|
2443
2518
|
windowed.map((entry) => [entry.variant.id, entry.trades])
|
|
2444
2519
|
);
|
|
2445
|
-
await
|
|
2520
|
+
await import_promises3.default.writeFile(
|
|
2446
2521
|
paths.reportPath,
|
|
2447
2522
|
buildCoreResearchHtml({ spec, result, tradesByVariant }),
|
|
2448
2523
|
"utf8"
|
|
@@ -2462,7 +2537,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
|
|
|
2462
2537
|
if (error.code !== "ENOENT") throw error;
|
|
2463
2538
|
}
|
|
2464
2539
|
try {
|
|
2465
|
-
for (const name of await
|
|
2540
|
+
for (const name of await import_promises3.default.readdir(paths.runLogDir)) {
|
|
2466
2541
|
if (!name.endsWith(".log")) continue;
|
|
2467
2542
|
artifactHashes[`runs/${name}`] = await sha256File(
|
|
2468
2543
|
import_node_path6.default.join(paths.runLogDir, name)
|
|
@@ -2662,7 +2737,7 @@ var createCoreResearchSpecTemplate = (params) => {
|
|
|
2662
2737
|
};
|
|
2663
2738
|
var runCommand = async (params) => {
|
|
2664
2739
|
if (!params.command.length) throw new Error("Cannot run an empty command");
|
|
2665
|
-
await
|
|
2740
|
+
await import_promises3.default.mkdir(import_node_path6.default.dirname(params.logPath), { recursive: true });
|
|
2666
2741
|
const chunks = [];
|
|
2667
2742
|
const child = (0, import_node_child_process.spawn)(params.command[0], params.command.slice(1), {
|
|
2668
2743
|
cwd: params.cwd,
|
|
@@ -2682,7 +2757,7 @@ var runCommand = async (params) => {
|
|
|
2682
2757
|
child.once("close", (code) => resolve(code ?? 1));
|
|
2683
2758
|
});
|
|
2684
2759
|
const output = chunks.join("");
|
|
2685
|
-
await
|
|
2760
|
+
await import_promises3.default.writeFile(params.logPath, output, "utf8");
|
|
2686
2761
|
if (exitCode !== 0) {
|
|
2687
2762
|
throw new Error(
|
|
2688
2763
|
`Command failed with exit ${exitCode}: ${params.command.join(" ")}`
|