@tradejs/cli 2.0.19 → 2.0.20
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 +8787 -3214
- package/dist/lib/aiExport.js +14 -1
- package/dist/lib/aiPocketSearch.js +499 -67
- package/dist/lib/aiPocketSearchCli.js +113 -0
- package/dist/lib/aiTrainCharts.js +14 -1
- package/dist/lib/aiTrainMetrics.js +4 -1
- package/dist/lib/aiTrainResearch.js +88 -54
- package/dist/lib/coreResearch.js +2738 -0
- package/dist/lib/executionCalibration.js +6 -3
- package/dist/lib/runtimeLineage.js +81 -48
- package/dist/lib/runtimeScorecard.js +153 -10
- package/dist/lib/strategyGateFingerprint.js +80 -0
- package/dist/lib/strategyRelease.js +1365 -0
- package/dist/scripts/aiExport.js +16 -3
- package/dist/scripts/aiPocketSearch.js +1069 -163
- package/dist/scripts/aiTrain.js +91 -65
- package/dist/scripts/backtest.js +10 -1
- package/dist/scripts/coreResearch.js +2830 -0
- package/dist/scripts/executionCalibration.js +6 -3
- package/dist/scripts/replay.js +106 -73
- package/dist/scripts/replayRunner.js +106 -73
- package/dist/scripts/replayRuntimeEvidence.js +27 -14
- package/dist/scripts/runtimeEvidence.js +16 -8
- package/dist/scripts/runtimeScorecard.js +883 -29
- package/dist/scripts/signals.js +133 -89
- package/dist/scripts/signalsDaemon.js +133 -89
- package/dist/scripts/strategyRelease.js +1469 -0
- package/package.json +11 -9
|
@@ -22,15 +22,20 @@ var aiPocketSearch_exports = {};
|
|
|
22
22
|
__export(aiPocketSearch_exports, {
|
|
23
23
|
buildAiPocketMarkdownReport: () => buildAiPocketMarkdownReport,
|
|
24
24
|
buildAiPocketPredicates: () => buildAiPocketPredicates,
|
|
25
|
+
classifyAiPocketCoverageFeaturePath: () => classifyAiPocketCoverageFeaturePath,
|
|
25
26
|
classifyAiPocketFeaturePath: () => classifyAiPocketFeaturePath,
|
|
27
|
+
collectAiPocketFeatureSnapshot: () => collectAiPocketFeatureSnapshot,
|
|
26
28
|
collectAiPocketFeatures: () => collectAiPocketFeatures,
|
|
29
|
+
resolveAiPocketFeatureCoverage: () => resolveAiPocketFeatureCoverage,
|
|
27
30
|
searchAiPockets: () => searchAiPockets,
|
|
31
|
+
summarizeAiPocketFeatureCoverage: () => summarizeAiPocketFeatureCoverage,
|
|
28
32
|
summarizeAiPocketRows: () => summarizeAiPocketRows
|
|
29
33
|
});
|
|
30
34
|
module.exports = __toCommonJS(aiPocketSearch_exports);
|
|
31
35
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
32
36
|
var DAYS_PER_WEEK = 7;
|
|
33
37
|
var DAYS_PER_MONTH = 30.4375;
|
|
38
|
+
var PRODUCTION_CANDIDATE_MIN_EVENTS = 25;
|
|
34
39
|
var OUTCOME_SEGMENTS = /* @__PURE__ */ new Set([
|
|
35
40
|
"actual",
|
|
36
41
|
"aiapproved",
|
|
@@ -116,6 +121,146 @@ var METADATA_LEAVES = /* @__PURE__ */ new Set([
|
|
|
116
121
|
"targetsymbol",
|
|
117
122
|
"universe"
|
|
118
123
|
]);
|
|
124
|
+
var normalizeFeaturePath = (path) => (Array.isArray(path) ? path : path.split(".")).filter(Boolean).map((segment) => segment.toLowerCase());
|
|
125
|
+
var classifyAiPocketCoverageFeaturePath = (path) => {
|
|
126
|
+
const segments = normalizeFeaturePath(path);
|
|
127
|
+
const normalizedPath = segments.join(".");
|
|
128
|
+
if (segments.some(
|
|
129
|
+
(segment) => segment.includes("cmc") || segment.includes("coinmarketcap")
|
|
130
|
+
)) {
|
|
131
|
+
return "cmc";
|
|
132
|
+
}
|
|
133
|
+
if (segments.some(
|
|
134
|
+
(segment) => segment.includes("derivative") || segment.includes("coinalyze")
|
|
135
|
+
) || /(?:^|\.)(?:funding|openinterest|oi(?:change|acceleration|divergence)|priceoi|liq(?:long|short|total|imbalance|spike)|liquidation)/.test(
|
|
136
|
+
normalizedPath
|
|
137
|
+
)) {
|
|
138
|
+
return "coinalyze";
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
};
|
|
142
|
+
var hasUsableContextPrimitive = (value) => {
|
|
143
|
+
if (Array.isArray(value) || value == null) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (isFeaturePrimitive(value)) {
|
|
147
|
+
return typeof value !== "string" || value.toLowerCase() !== "unknown";
|
|
148
|
+
}
|
|
149
|
+
if (!isPlainRecord(value)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return Object.entries(value).some(([key, child]) => {
|
|
153
|
+
const normalizedKey = key.toLowerCase();
|
|
154
|
+
if (DATA_QUALITY_LEAVES.has(normalizedKey) || METADATA_LEAVES.has(normalizedKey) || normalizedKey === "riskflags" || normalizedKey.endsWith("timestamp") || normalizedKey.endsWith("agems")) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return hasUsableContextPrimitive(child);
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
var isUsableCmcContext = (value) => isPlainRecord(value) && value.available !== false && value.stale !== true && hasUsableContextPrimitive(value);
|
|
161
|
+
var hasUsableCmcContext = (baseContext) => {
|
|
162
|
+
const relative = isPlainRecord(baseContext?.relative) ? baseContext.relative : null;
|
|
163
|
+
return Boolean(
|
|
164
|
+
relative && Object.entries(relative).some(
|
|
165
|
+
([key, value]) => key.toLowerCase().startsWith("cmc") && isUsableCmcContext(value)
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
var isUsableDerivativesContext = (context) => {
|
|
170
|
+
if (!context) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
const summary = isPlainRecord(context.summary) ? context.summary : null;
|
|
174
|
+
const riskFlags = Array.isArray(summary?.riskFlags) ? summary.riskFlags.filter(
|
|
175
|
+
(flag) => typeof flag === "string"
|
|
176
|
+
) : [];
|
|
177
|
+
if (riskFlags.includes("missing_derivatives") || riskFlags.includes("stale_derivatives")) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
const intervals = isPlainRecord(context.intervals) ? context.intervals : null;
|
|
181
|
+
return Boolean(
|
|
182
|
+
intervals && Object.values(intervals).some(
|
|
183
|
+
(interval) => isPlainRecord(interval) && interval.stale !== true && hasUsableContextPrimitive(interval)
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
};
|
|
187
|
+
var hasUsableCoinalyzeContext = (baseContext) => {
|
|
188
|
+
const derivatives = isPlainRecord(baseContext?.derivatives) ? baseContext.derivatives : null;
|
|
189
|
+
if (!derivatives) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (isUsableDerivativesContext(derivatives)) {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
const targetContext = isPlainRecord(derivatives.targetContext) ? derivatives.targetContext : null;
|
|
196
|
+
if (isUsableDerivativesContext(targetContext)) {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
const referenceContexts = isPlainRecord(derivatives.referenceContexts) ? derivatives.referenceContexts : null;
|
|
200
|
+
return Boolean(
|
|
201
|
+
referenceContexts && Object.values(referenceContexts).some(
|
|
202
|
+
(context) => isUsableDerivativesContext(isPlainRecord(context) ? context : null)
|
|
203
|
+
)
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
var resolveAiPocketFeatureCoverage = (payload) => {
|
|
207
|
+
const additionalIndicators = isPlainRecord(payload.additionalIndicators) ? payload.additionalIndicators : null;
|
|
208
|
+
const baseContext = isPlainRecord(additionalIndicators?.baseContext) ? additionalIndicators.baseContext : null;
|
|
209
|
+
return {
|
|
210
|
+
cmc: hasUsableCmcContext(baseContext),
|
|
211
|
+
coinalyze: hasUsableCoinalyzeContext(baseContext)
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
var isAiPocketCoverageFeatureUsable = ({
|
|
215
|
+
payload,
|
|
216
|
+
segments,
|
|
217
|
+
family,
|
|
218
|
+
familyCoverage
|
|
219
|
+
}) => {
|
|
220
|
+
const additionalIndicators = isPlainRecord(payload.additionalIndicators) ? payload.additionalIndicators : null;
|
|
221
|
+
const baseContext = isPlainRecord(additionalIndicators?.baseContext) ? additionalIndicators.baseContext : null;
|
|
222
|
+
const baseContextIndex = segments.findIndex(
|
|
223
|
+
(segment) => segment.toLowerCase() === "basecontext"
|
|
224
|
+
);
|
|
225
|
+
if (family === "cmc") {
|
|
226
|
+
const relative = isPlainRecord(baseContext?.relative) ? baseContext.relative : null;
|
|
227
|
+
if (relative && baseContextIndex >= 0 && segments[baseContextIndex + 1]?.toLowerCase() === "relative") {
|
|
228
|
+
const contextKey = segments[baseContextIndex + 2];
|
|
229
|
+
if (contextKey?.toLowerCase().startsWith("cmc")) {
|
|
230
|
+
return isUsableCmcContext(relative[contextKey]);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return familyCoverage.cmc;
|
|
234
|
+
}
|
|
235
|
+
const derivatives = isPlainRecord(baseContext?.derivatives) ? baseContext.derivatives : null;
|
|
236
|
+
if (!derivatives || baseContextIndex < 0 || segments[baseContextIndex + 1]?.toLowerCase() !== "derivatives") {
|
|
237
|
+
return isUsableDerivativesContext(derivatives);
|
|
238
|
+
}
|
|
239
|
+
const branch = segments[baseContextIndex + 2]?.toLowerCase();
|
|
240
|
+
if (branch == null) {
|
|
241
|
+
return familyCoverage.coinalyze;
|
|
242
|
+
}
|
|
243
|
+
if (branch === "referencecontexts") {
|
|
244
|
+
const referenceContexts = isPlainRecord(derivatives.referenceContexts) ? derivatives.referenceContexts : null;
|
|
245
|
+
const symbol = segments[baseContextIndex + 3];
|
|
246
|
+
if (!symbol) {
|
|
247
|
+
return Boolean(
|
|
248
|
+
referenceContexts && Object.values(referenceContexts).some(
|
|
249
|
+
(context) => isUsableDerivativesContext(isPlainRecord(context) ? context : null)
|
|
250
|
+
)
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
return isUsableDerivativesContext(
|
|
254
|
+
symbol && referenceContexts && isPlainRecord(referenceContexts[symbol]) ? referenceContexts[symbol] : null
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
if (branch === "targetcontext" || branch === "targetderived") {
|
|
258
|
+
return isUsableDerivativesContext(
|
|
259
|
+
isPlainRecord(derivatives.targetContext) ? derivatives.targetContext : null
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return isUsableDerivativesContext(derivatives);
|
|
263
|
+
};
|
|
119
264
|
var DERIVED_POLICY_FRAGMENTS = [
|
|
120
265
|
"approval",
|
|
121
266
|
"decisionhint",
|
|
@@ -454,7 +599,7 @@ var addSignalRiskDistanceFeatures = ({
|
|
|
454
599
|
features["derived.takeProfitDistanceBps"] = Math.abs(takeProfitPrice - currentPrice) / Math.abs(currentPrice) * 1e4;
|
|
455
600
|
}
|
|
456
601
|
};
|
|
457
|
-
var
|
|
602
|
+
var collectAiPocketFeatureSnapshot = ({
|
|
458
603
|
payload,
|
|
459
604
|
gateContext,
|
|
460
605
|
includeSymbol = false,
|
|
@@ -464,6 +609,7 @@ var collectAiPocketFeatures = ({
|
|
|
464
609
|
onFeatureExcluded
|
|
465
610
|
}) => {
|
|
466
611
|
const features = {};
|
|
612
|
+
const featureCoverage = resolveAiPocketFeatureCoverage(payload);
|
|
467
613
|
const signal = payload.signal ?? {};
|
|
468
614
|
const source = {
|
|
469
615
|
signal: {
|
|
@@ -482,6 +628,19 @@ var collectAiPocketFeatures = ({
|
|
|
482
628
|
segments: [],
|
|
483
629
|
maxDepth: 8,
|
|
484
630
|
shouldSkipPath: (segments) => {
|
|
631
|
+
const coverageFamily = classifyAiPocketCoverageFeaturePath(segments);
|
|
632
|
+
if (featurePolicy === "causal-stationary" && coverageFamily != null && !isAiPocketCoverageFeatureUsable({
|
|
633
|
+
payload,
|
|
634
|
+
segments,
|
|
635
|
+
family: coverageFamily,
|
|
636
|
+
familyCoverage: featureCoverage
|
|
637
|
+
})) {
|
|
638
|
+
onFeatureExcluded?.({
|
|
639
|
+
path: segments.join("."),
|
|
640
|
+
classification: "data-quality"
|
|
641
|
+
});
|
|
642
|
+
return true;
|
|
643
|
+
}
|
|
485
644
|
if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
|
|
486
645
|
return true;
|
|
487
646
|
}
|
|
@@ -512,8 +671,9 @@ var collectAiPocketFeatures = ({
|
|
|
512
671
|
}
|
|
513
672
|
addSignalRiskDistanceFeatures({ features, signal });
|
|
514
673
|
addDirectionalDerivedFeatures(features);
|
|
515
|
-
return features;
|
|
674
|
+
return { features, featureCoverage };
|
|
516
675
|
};
|
|
676
|
+
var collectAiPocketFeatures = (options) => collectAiPocketFeatureSnapshot(options).features;
|
|
517
677
|
var formatNumber = (value) => {
|
|
518
678
|
if (Number.isInteger(value)) {
|
|
519
679
|
return String(value);
|
|
@@ -779,6 +939,37 @@ var summarizeRowIndexes = (rows, rowIndexes) => {
|
|
|
779
939
|
return finalizeAiPocketSummary({ rows, accumulator });
|
|
780
940
|
};
|
|
781
941
|
var summarizeAiPocketRows = (rows) => summarizeSelectedRows(rows, rows);
|
|
942
|
+
var summarizeAiPocketFeatureCoverage = (rows, family) => {
|
|
943
|
+
const coveredRows = rows.filter(
|
|
944
|
+
(row) => row.featureCoverage?.[family] === true
|
|
945
|
+
);
|
|
946
|
+
const allEvents = /* @__PURE__ */ new Set();
|
|
947
|
+
const coveredEvents = /* @__PURE__ */ new Set();
|
|
948
|
+
let minTimestamp = null;
|
|
949
|
+
let maxTimestamp = null;
|
|
950
|
+
for (const row of rows) {
|
|
951
|
+
if (isFiniteNumber(row.timestamp)) {
|
|
952
|
+
allEvents.add(row.timestamp);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
for (const row of coveredRows) {
|
|
956
|
+
if (!isFiniteNumber(row.timestamp)) {
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
coveredEvents.add(row.timestamp);
|
|
960
|
+
minTimestamp = minTimestamp == null ? row.timestamp : Math.min(minTimestamp, row.timestamp);
|
|
961
|
+
maxTimestamp = maxTimestamp == null ? row.timestamp : Math.max(maxTimestamp, row.timestamp);
|
|
962
|
+
}
|
|
963
|
+
return {
|
|
964
|
+
family,
|
|
965
|
+
rows: coveredRows.length,
|
|
966
|
+
rowRatio: rows.length > 0 ? coveredRows.length / rows.length : 0,
|
|
967
|
+
events: coveredEvents.size,
|
|
968
|
+
eventRatio: allEvents.size > 0 ? coveredEvents.size / allEvents.size : 0,
|
|
969
|
+
minTimestamp,
|
|
970
|
+
maxTimestamp
|
|
971
|
+
};
|
|
972
|
+
};
|
|
782
973
|
var matchesPredicate = (value, predicate) => {
|
|
783
974
|
if (predicate.kind === "numeric") {
|
|
784
975
|
if (!isFiniteNumber(value)) {
|
|
@@ -1092,6 +1283,19 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
|
|
|
1092
1283
|
const condition = publicPredicates.map((predicate) => predicate.label).join(" AND ");
|
|
1093
1284
|
const validationScore = validationSummary == null || validationObjectiveSummary == null ? void 0 : validationSummary.support > 0 ? scorePositivePocket(validationObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(validationObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
1094
1285
|
const testScore = testSummary == null || testObjectiveSummary == null ? void 0 : testSummary.support > 0 ? scorePositivePocket(testObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(testObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
1286
|
+
const readinessReasons = [];
|
|
1287
|
+
if (summary.events < PRODUCTION_CANDIDATE_MIN_EVENTS) {
|
|
1288
|
+
readinessReasons.push(
|
|
1289
|
+
`train events ${summary.events} < ${PRODUCTION_CANDIDATE_MIN_EVENTS}`
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
if (testSummary == null) {
|
|
1293
|
+
readinessReasons.push("untouched test missing");
|
|
1294
|
+
} else if (testSummary.events < PRODUCTION_CANDIDATE_MIN_EVENTS) {
|
|
1295
|
+
readinessReasons.push(
|
|
1296
|
+
`test events ${testSummary.events} < ${PRODUCTION_CANDIDATE_MIN_EVENTS}`
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1095
1299
|
return {
|
|
1096
1300
|
id: publicPredicates.map((predicate) => predicate.id).join("&&"),
|
|
1097
1301
|
depth: publicPredicates.length,
|
|
@@ -1105,6 +1309,8 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
|
|
|
1105
1309
|
...objective !== "standalone" && testObjectiveSummary ? { testObjectiveSummary } : {},
|
|
1106
1310
|
...validationScore != null ? { validationScore } : {},
|
|
1107
1311
|
...testScore != null ? { testScore } : {},
|
|
1312
|
+
readiness: readinessReasons.length === 0 ? "production-candidate" : "research-only",
|
|
1313
|
+
readinessReasons,
|
|
1108
1314
|
score: scorePositivePocket(objectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(objectiveBaseline))
|
|
1109
1315
|
};
|
|
1110
1316
|
};
|
|
@@ -1199,6 +1405,43 @@ var diversifyPredicatePool = (predicates, maximum) => {
|
|
|
1199
1405
|
}
|
|
1200
1406
|
return selected;
|
|
1201
1407
|
};
|
|
1408
|
+
var prioritizeRequiredFeatureFamilyPredicates = ({
|
|
1409
|
+
selected,
|
|
1410
|
+
predicates,
|
|
1411
|
+
requiredFeatureFamilies,
|
|
1412
|
+
maximum
|
|
1413
|
+
}) => {
|
|
1414
|
+
if (!requiredFeatureFamilies.length) {
|
|
1415
|
+
return selected;
|
|
1416
|
+
}
|
|
1417
|
+
const perFamilyLimit = Math.max(
|
|
1418
|
+
6,
|
|
1419
|
+
Math.floor(maximum * 0.2 / requiredFeatureFamilies.length)
|
|
1420
|
+
);
|
|
1421
|
+
const prioritized = /* @__PURE__ */ new Map();
|
|
1422
|
+
for (const family of requiredFeatureFamilies) {
|
|
1423
|
+
const familyPredicates = predicates.filter(
|
|
1424
|
+
(predicate) => classifyAiPocketCoverageFeaturePath(predicate.featureKey) === family
|
|
1425
|
+
);
|
|
1426
|
+
const positive = [...familyPredicates].sort(
|
|
1427
|
+
(left, right) => scorePositivePocket(right.atomSummary) - scorePositivePocket(left.atomSummary)
|
|
1428
|
+
).slice(0, Math.ceil(perFamilyLimit * 0.5));
|
|
1429
|
+
const negative = [...familyPredicates].sort(
|
|
1430
|
+
(left, right) => scoreNegativePocket(right.atomSummary) - scoreNegativePocket(left.atomSummary)
|
|
1431
|
+
).slice(0, Math.ceil(perFamilyLimit * 0.3));
|
|
1432
|
+
const broad = [...familyPredicates].sort((left, right) => right.support - left.support).slice(0, Math.ceil(perFamilyLimit * 0.2));
|
|
1433
|
+
for (const predicate of [...positive, ...negative, ...broad]) {
|
|
1434
|
+
if (prioritized.size >= perFamilyLimit * requiredFeatureFamilies.length) {
|
|
1435
|
+
break;
|
|
1436
|
+
}
|
|
1437
|
+
prioritized.set(predicate.id, predicate);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
for (const predicate of selected) {
|
|
1441
|
+
prioritized.set(predicate.id, predicate);
|
|
1442
|
+
}
|
|
1443
|
+
return [...prioritized.values()].slice(0, maximum);
|
|
1444
|
+
};
|
|
1202
1445
|
var canCombinePredicate = (chosen, candidate) => {
|
|
1203
1446
|
const sameFeature = chosen.filter(
|
|
1204
1447
|
(predicate) => predicate.featureKey === candidate.featureKey
|
|
@@ -1214,7 +1457,11 @@ var canCombinePredicate = (chosen, candidate) => {
|
|
|
1214
1457
|
return lower <= upper;
|
|
1215
1458
|
};
|
|
1216
1459
|
var searchAiPockets = (rows, options = {}) => {
|
|
1217
|
-
const
|
|
1460
|
+
const cadenceProfileOption = options.cadenceProfile;
|
|
1461
|
+
const minSupport = Math.max(
|
|
1462
|
+
1,
|
|
1463
|
+
Math.trunc(cadenceProfileOption?.minSupport ?? options.minSupport ?? 20)
|
|
1464
|
+
);
|
|
1218
1465
|
const minProfitFactor = Math.max(0, options.minProfitFactor ?? 1.2);
|
|
1219
1466
|
const minTotalProfit = options.minTotalProfit ?? 0;
|
|
1220
1467
|
const minWinRate = Math.max(0, options.minWinRate ?? 0);
|
|
@@ -1232,17 +1479,27 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1232
1479
|
const testRows = options.testRows ?? [];
|
|
1233
1480
|
const minValidationSupport = Math.max(
|
|
1234
1481
|
0,
|
|
1235
|
-
Math.trunc(
|
|
1482
|
+
Math.trunc(
|
|
1483
|
+
cadenceProfileOption?.minValidationSupport ?? options.minValidationSupport ?? 0
|
|
1484
|
+
)
|
|
1485
|
+
);
|
|
1486
|
+
const minEvents = Math.max(
|
|
1487
|
+
1,
|
|
1488
|
+
Math.trunc(cadenceProfileOption?.minEvents ?? options.minEvents ?? 1)
|
|
1236
1489
|
);
|
|
1237
|
-
const minEvents = Math.max(1, Math.trunc(options.minEvents ?? 1));
|
|
1238
1490
|
const minValidationEvents = Math.max(
|
|
1239
1491
|
0,
|
|
1240
|
-
Math.trunc(
|
|
1492
|
+
Math.trunc(
|
|
1493
|
+
cadenceProfileOption?.minValidationEvents ?? options.minValidationEvents ?? 0
|
|
1494
|
+
)
|
|
1241
1495
|
);
|
|
1242
1496
|
const maxBatch = Math.max(1, options.maxBatch ?? Number.POSITIVE_INFINITY);
|
|
1243
1497
|
const maxEventCountShare = Math.max(
|
|
1244
1498
|
0,
|
|
1245
|
-
Math.min(
|
|
1499
|
+
Math.min(
|
|
1500
|
+
1,
|
|
1501
|
+
cadenceProfileOption?.maxEventCountShare ?? options.maxEventCountShare ?? 1
|
|
1502
|
+
)
|
|
1246
1503
|
);
|
|
1247
1504
|
const maxSymbolCountShare = Math.max(
|
|
1248
1505
|
0,
|
|
@@ -1260,18 +1517,59 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1260
1517
|
const allowRiskRegression = options.allowRiskRegression === true;
|
|
1261
1518
|
const requireValidationEligibility = options.requireValidationEligibility === true;
|
|
1262
1519
|
const dedupeEquivalentSelections = options.dedupeEquivalentSelections !== false;
|
|
1520
|
+
const requiredFeatureFamilies = [
|
|
1521
|
+
...new Set(options.requiredFeatureFamilies ?? [])
|
|
1522
|
+
];
|
|
1523
|
+
const excludedFeatureFamilies = [
|
|
1524
|
+
...new Set(options.excludedFeatureFamilies ?? [])
|
|
1525
|
+
];
|
|
1263
1526
|
const progressInterval = Math.max(
|
|
1264
1527
|
1,
|
|
1265
1528
|
Math.trunc(options.progressInterval ?? 500)
|
|
1266
1529
|
);
|
|
1267
1530
|
const onProgress = options.onProgress;
|
|
1531
|
+
const summarizePartition = (partitionRows) => {
|
|
1532
|
+
const summary = summarizeAiPocketRows(partitionRows);
|
|
1533
|
+
const periodDays = getPeriodDays(partitionRows);
|
|
1534
|
+
return {
|
|
1535
|
+
rows: partitionRows.length,
|
|
1536
|
+
events: summary.events,
|
|
1537
|
+
periodDays,
|
|
1538
|
+
eventsPerDay: periodDays == null ? null : summary.events / periodDays
|
|
1539
|
+
};
|
|
1540
|
+
};
|
|
1541
|
+
const trainPartition = summarizePartition(rows);
|
|
1542
|
+
const validationPartition = summarizePartition(validationRows);
|
|
1543
|
+
const testPartition = summarizePartition(testRows);
|
|
1544
|
+
const cadenceProfile = cadenceProfileOption ?? {
|
|
1545
|
+
mode: "fixed",
|
|
1546
|
+
lowCadence: false,
|
|
1547
|
+
sparseSample: false,
|
|
1548
|
+
adaptiveThresholds: false,
|
|
1549
|
+
trainRows: trainPartition.rows,
|
|
1550
|
+
trainEvents: trainPartition.events,
|
|
1551
|
+
trainPeriodDays: trainPartition.periodDays,
|
|
1552
|
+
trainEventsPerDay: trainPartition.eventsPerDay,
|
|
1553
|
+
validationRows: validationPartition.rows,
|
|
1554
|
+
validationEvents: validationPartition.events,
|
|
1555
|
+
testRows: testPartition.rows,
|
|
1556
|
+
testEvents: testPartition.events,
|
|
1557
|
+
minSupport,
|
|
1558
|
+
minEvents,
|
|
1559
|
+
minValidationSupport,
|
|
1560
|
+
minValidationEvents,
|
|
1561
|
+
maxEventCountShare
|
|
1562
|
+
};
|
|
1268
1563
|
const predicateResult = buildAiPocketPredicateResult(rows, {
|
|
1269
1564
|
minSupport,
|
|
1270
1565
|
maxCategories: options.maxCategories,
|
|
1271
1566
|
progressInterval,
|
|
1272
1567
|
onProgress
|
|
1273
1568
|
});
|
|
1274
|
-
const
|
|
1569
|
+
const predicates = predicateResult.predicates.filter((predicate) => {
|
|
1570
|
+
const family = classifyAiPocketCoverageFeaturePath(predicate.featureKey);
|
|
1571
|
+
return family == null || !excludedFeatureFamilies.includes(family);
|
|
1572
|
+
});
|
|
1275
1573
|
let lastMaskProgress = 0;
|
|
1276
1574
|
const emitMaskProgress = (current, done = false) => {
|
|
1277
1575
|
if (!onProgress) {
|
|
@@ -1303,10 +1601,15 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1303
1601
|
[...predicatePool, ...negativePool, ...supportPool].forEach((predicate) => {
|
|
1304
1602
|
predicatePoolById.set(predicate.id, predicate);
|
|
1305
1603
|
});
|
|
1306
|
-
const diversifiedPredicates =
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1604
|
+
const diversifiedPredicates = prioritizeRequiredFeatureFamilyPredicates({
|
|
1605
|
+
selected: diversifyPredicatePool(
|
|
1606
|
+
[...predicatePoolById.values()],
|
|
1607
|
+
maxAtomicPredicates
|
|
1608
|
+
),
|
|
1609
|
+
predicates: scoredPredicates,
|
|
1610
|
+
requiredFeatureFamilies,
|
|
1611
|
+
maximum: maxAtomicPredicates
|
|
1612
|
+
});
|
|
1310
1613
|
const selectedPredicatePool = diversifiedPredicates.map(
|
|
1311
1614
|
(predicate) => {
|
|
1312
1615
|
const { mask, support } = buildMask(rows, predicate);
|
|
@@ -1347,6 +1650,13 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1347
1650
|
});
|
|
1348
1651
|
};
|
|
1349
1652
|
const addPocket = (pocketPredicates, mask) => {
|
|
1653
|
+
if (requiredFeatureFamilies.some(
|
|
1654
|
+
(family) => !pocketPredicates.some(
|
|
1655
|
+
(predicate) => classifyAiPocketCoverageFeaturePath(predicate.featureKey) === family
|
|
1656
|
+
)
|
|
1657
|
+
)) {
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1350
1660
|
const pocket = createPocketResult(
|
|
1351
1661
|
rows,
|
|
1352
1662
|
pocketPredicates,
|
|
@@ -1464,7 +1774,7 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1464
1774
|
negativePockets: [...negativePockets.values()].sort(compareNegativePockets).slice(0, top),
|
|
1465
1775
|
stats: {
|
|
1466
1776
|
rows: rows.length,
|
|
1467
|
-
featureKeys:
|
|
1777
|
+
featureKeys: new Set(predicates.map((predicate) => predicate.featureKey)).size,
|
|
1468
1778
|
predicates: predicates.length,
|
|
1469
1779
|
atomicPredicatesUsed: selectedPredicatePool.length,
|
|
1470
1780
|
estimatedCombinations,
|
|
@@ -1479,6 +1789,9 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1479
1789
|
)
|
|
1480
1790
|
)
|
|
1481
1791
|
],
|
|
1792
|
+
requiredFeatureFamilies,
|
|
1793
|
+
excludedFeatureFamilies,
|
|
1794
|
+
cadence: cadenceProfile,
|
|
1482
1795
|
truncated
|
|
1483
1796
|
}
|
|
1484
1797
|
};
|
|
@@ -1540,16 +1853,20 @@ var pocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
|
1540
1853
|
pocket.objectiveSummary ? formatMdNumber(pocket.objectiveSummary.totalProfit) : "n/a",
|
|
1541
1854
|
formatMdNumber(pocket.summary.maxDrawdown),
|
|
1542
1855
|
pocket.validationSummary?.support ?? "n/a",
|
|
1856
|
+
pocket.validationSummary?.events ?? "n/a",
|
|
1543
1857
|
pocket.validationSummary ? formatMdPercent(pocket.validationSummary.winRate) : "n/a",
|
|
1544
1858
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.profitFactor) : "n/a",
|
|
1545
1859
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.totalProfit) : "n/a",
|
|
1546
1860
|
pocket.testSummary?.support ?? "n/a",
|
|
1861
|
+
pocket.testSummary?.events ?? "n/a",
|
|
1547
1862
|
pocket.testSummary ? formatMdNumber(pocket.testSummary.profitFactor) : "n/a",
|
|
1548
1863
|
pocket.testSummary ? formatMdNumber(pocket.testSummary.totalProfit) : "n/a",
|
|
1549
1864
|
pocket.testObjectiveSummary ? formatMdNumber(pocket.testObjectiveSummary.totalProfit) : "n/a",
|
|
1550
1865
|
formatMdNumber(pocket.summary.avgTradesPerDay),
|
|
1551
1866
|
pocket.summary.losingMonths,
|
|
1552
1867
|
formatMdNumber(pocket.score),
|
|
1868
|
+
pocket.readiness,
|
|
1869
|
+
pocket.readinessReasons.join("; ") || "none",
|
|
1553
1870
|
pocket.condition
|
|
1554
1871
|
]);
|
|
1555
1872
|
var buildAiPocketMarkdownReport = ({
|
|
@@ -1557,6 +1874,7 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1557
1874
|
run,
|
|
1558
1875
|
currentGate,
|
|
1559
1876
|
pocketSearch,
|
|
1877
|
+
coverageSearches = [],
|
|
1560
1878
|
errors
|
|
1561
1879
|
}) => {
|
|
1562
1880
|
const generatedIso = new Date(generatedAt).toISOString();
|
|
@@ -1567,6 +1885,34 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1567
1885
|
audit?.paths ?? 0,
|
|
1568
1886
|
audit?.samples.join(", ") ?? ""
|
|
1569
1887
|
]);
|
|
1888
|
+
const pocketTableHeaders = [
|
|
1889
|
+
"#",
|
|
1890
|
+
"N",
|
|
1891
|
+
"Events",
|
|
1892
|
+
"Max batch",
|
|
1893
|
+
"Support",
|
|
1894
|
+
"WR",
|
|
1895
|
+
"PF",
|
|
1896
|
+
"PNL",
|
|
1897
|
+
"Objective PNL",
|
|
1898
|
+
"Max DD",
|
|
1899
|
+
"Val N",
|
|
1900
|
+
"Val Events",
|
|
1901
|
+
"Val WR",
|
|
1902
|
+
"Val PF",
|
|
1903
|
+
"Val PNL",
|
|
1904
|
+
"Test N",
|
|
1905
|
+
"Test Events",
|
|
1906
|
+
"Test PF",
|
|
1907
|
+
"Test PNL",
|
|
1908
|
+
"Test objective PNL",
|
|
1909
|
+
"Trades/Day",
|
|
1910
|
+
"Losing Months",
|
|
1911
|
+
"Score",
|
|
1912
|
+
"Readiness",
|
|
1913
|
+
"Readiness reasons",
|
|
1914
|
+
"Pocket"
|
|
1915
|
+
];
|
|
1570
1916
|
const lines = [
|
|
1571
1917
|
"# AI Pocket Search Report",
|
|
1572
1918
|
"",
|
|
@@ -1590,6 +1936,17 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1590
1936
|
["test_rows", run.testRows],
|
|
1591
1937
|
["validation_split", formatMdPercent(run.validationSplit)],
|
|
1592
1938
|
["test_split", formatMdPercent(run.testSplit)],
|
|
1939
|
+
["test_sealed", run.sealedTest?.sealed ? "yes" : "no"],
|
|
1940
|
+
["sealed_test_rows", run.sealedTest?.rows ?? run.testRows],
|
|
1941
|
+
["sealed_test_events", run.sealedTest?.events ?? "n/a"],
|
|
1942
|
+
[
|
|
1943
|
+
"sealed_test_start",
|
|
1944
|
+
run.sealedTest?.startTimestamp == null ? "n/a" : new Date(run.sealedTest.startTimestamp).toISOString()
|
|
1945
|
+
],
|
|
1946
|
+
[
|
|
1947
|
+
"sealed_test_end",
|
|
1948
|
+
run.sealedTest?.endTimestamp == null ? "n/a" : new Date(run.sealedTest.endTimestamp).toISOString()
|
|
1949
|
+
],
|
|
1593
1950
|
["min_validation_support", run.minValidationSupport],
|
|
1594
1951
|
["failed", run.failed],
|
|
1595
1952
|
["recent", run.recent === 0 ? "all" : run.recent],
|
|
@@ -1631,6 +1988,22 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1631
1988
|
["include_gate_context", run.includeGateContext ? "on" : "off"],
|
|
1632
1989
|
["feature_profile", run.featureProfile ?? "all"],
|
|
1633
1990
|
["feature_policy", run.featurePolicy ?? "all"],
|
|
1991
|
+
["coverage_mode", run.coverageMode ?? "full"],
|
|
1992
|
+
["cadence_mode", run.cadenceMode ?? "fixed"],
|
|
1993
|
+
["low_cadence", pocketSearch.stats.cadence.lowCadence ? "yes" : "no"],
|
|
1994
|
+
[
|
|
1995
|
+
"sparse_sample",
|
|
1996
|
+
pocketSearch.stats.cadence.sparseSample ? "yes" : "no"
|
|
1997
|
+
],
|
|
1998
|
+
[
|
|
1999
|
+
"adaptive_thresholds",
|
|
2000
|
+
pocketSearch.stats.cadence.adaptiveThresholds ? "on" : "off"
|
|
2001
|
+
],
|
|
2002
|
+
["train_events", pocketSearch.stats.cadence.trainEvents],
|
|
2003
|
+
[
|
|
2004
|
+
"train_events_per_day",
|
|
2005
|
+
formatMdNumber(pocketSearch.stats.cadence.trainEventsPerDay, 4)
|
|
2006
|
+
],
|
|
1634
2007
|
["report_path", run.reportPath]
|
|
1635
2008
|
]
|
|
1636
2009
|
),
|
|
@@ -1716,10 +2089,32 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1716
2089
|
["predicates", pocketSearch.stats.predicates],
|
|
1717
2090
|
["atomic_used", pocketSearch.stats.atomicPredicatesUsed],
|
|
1718
2091
|
["feature_families", pocketSearch.stats.featureFamiliesUsed.join(", ")],
|
|
2092
|
+
[
|
|
2093
|
+
"required_feature_families",
|
|
2094
|
+
pocketSearch.stats.requiredFeatureFamilies.join(", ") || "none"
|
|
2095
|
+
],
|
|
2096
|
+
[
|
|
2097
|
+
"excluded_feature_families",
|
|
2098
|
+
pocketSearch.stats.excludedFeatureFamilies.join(", ") || "none"
|
|
2099
|
+
],
|
|
1719
2100
|
["estimated_combinations", pocketSearch.stats.estimatedCombinations],
|
|
1720
2101
|
["combinations_evaluated", pocketSearch.stats.combinationsEvaluated],
|
|
1721
2102
|
["validation_rows", pocketSearch.stats.validationRows],
|
|
1722
2103
|
["test_rows", pocketSearch.stats.testRows],
|
|
2104
|
+
["effective_min_support", pocketSearch.stats.cadence.minSupport],
|
|
2105
|
+
["effective_min_events", pocketSearch.stats.cadence.minEvents],
|
|
2106
|
+
[
|
|
2107
|
+
"effective_min_validation_support",
|
|
2108
|
+
pocketSearch.stats.cadence.minValidationSupport
|
|
2109
|
+
],
|
|
2110
|
+
[
|
|
2111
|
+
"effective_min_validation_events",
|
|
2112
|
+
pocketSearch.stats.cadence.minValidationEvents
|
|
2113
|
+
],
|
|
2114
|
+
[
|
|
2115
|
+
"effective_max_event_count_share",
|
|
2116
|
+
formatMdPercent(pocketSearch.stats.cadence.maxEventCountShare)
|
|
2117
|
+
],
|
|
1723
2118
|
[
|
|
1724
2119
|
"duplicate_pockets_skipped",
|
|
1725
2120
|
pocketSearch.stats.duplicatePocketsSkipped
|
|
@@ -1730,65 +2125,98 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1730
2125
|
"",
|
|
1731
2126
|
"## Top Positive Pockets",
|
|
1732
2127
|
"",
|
|
1733
|
-
markdownTable(
|
|
1734
|
-
[
|
|
1735
|
-
"#",
|
|
1736
|
-
"N",
|
|
1737
|
-
"Events",
|
|
1738
|
-
"Max batch",
|
|
1739
|
-
"Support",
|
|
1740
|
-
"WR",
|
|
1741
|
-
"PF",
|
|
1742
|
-
"PNL",
|
|
1743
|
-
"Objective PNL",
|
|
1744
|
-
"Max DD",
|
|
1745
|
-
"Val N",
|
|
1746
|
-
"Val WR",
|
|
1747
|
-
"Val PF",
|
|
1748
|
-
"Val PNL",
|
|
1749
|
-
"Test N",
|
|
1750
|
-
"Test PF",
|
|
1751
|
-
"Test PNL",
|
|
1752
|
-
"Test objective PNL",
|
|
1753
|
-
"Trades/Day",
|
|
1754
|
-
"Losing Months",
|
|
1755
|
-
"Score",
|
|
1756
|
-
"Pocket"
|
|
1757
|
-
],
|
|
1758
|
-
pocketRows(pocketSearch.positivePockets)
|
|
1759
|
-
),
|
|
2128
|
+
markdownTable(pocketTableHeaders, pocketRows(pocketSearch.positivePockets)),
|
|
1760
2129
|
"",
|
|
1761
2130
|
"## Top Loss Pockets",
|
|
1762
2131
|
"",
|
|
1763
|
-
markdownTable(
|
|
1764
|
-
[
|
|
1765
|
-
"#",
|
|
1766
|
-
"N",
|
|
1767
|
-
"Events",
|
|
1768
|
-
"Max batch",
|
|
1769
|
-
"Support",
|
|
1770
|
-
"WR",
|
|
1771
|
-
"PF",
|
|
1772
|
-
"PNL",
|
|
1773
|
-
"Objective PNL",
|
|
1774
|
-
"Max DD",
|
|
1775
|
-
"Val N",
|
|
1776
|
-
"Val WR",
|
|
1777
|
-
"Val PF",
|
|
1778
|
-
"Val PNL",
|
|
1779
|
-
"Test N",
|
|
1780
|
-
"Test PF",
|
|
1781
|
-
"Test PNL",
|
|
1782
|
-
"Test objective PNL",
|
|
1783
|
-
"Trades/Day",
|
|
1784
|
-
"Losing Months",
|
|
1785
|
-
"Score",
|
|
1786
|
-
"Pocket"
|
|
1787
|
-
],
|
|
1788
|
-
pocketRows(pocketSearch.negativePockets)
|
|
1789
|
-
),
|
|
2132
|
+
markdownTable(pocketTableHeaders, pocketRows(pocketSearch.negativePockets)),
|
|
1790
2133
|
""
|
|
1791
2134
|
];
|
|
2135
|
+
for (const cohort of coverageSearches) {
|
|
2136
|
+
const title = cohort.family === "cmc" ? "CMC" : "Coinalyze";
|
|
2137
|
+
lines.push(
|
|
2138
|
+
`## Coverage Cohort: ${title}`,
|
|
2139
|
+
"",
|
|
2140
|
+
markdownTable(
|
|
2141
|
+
["Field", "Value"],
|
|
2142
|
+
[
|
|
2143
|
+
["coverage_rows", cohort.coverage.rows],
|
|
2144
|
+
["coverage_row_ratio", formatMdPercent(cohort.coverage.rowRatio)],
|
|
2145
|
+
["coverage_events", cohort.coverage.events],
|
|
2146
|
+
["coverage_event_ratio", formatMdPercent(cohort.coverage.eventRatio)],
|
|
2147
|
+
[
|
|
2148
|
+
"coverage_from",
|
|
2149
|
+
cohort.coverage.minTimestamp == null ? "n/a" : new Date(cohort.coverage.minTimestamp).toISOString()
|
|
2150
|
+
],
|
|
2151
|
+
[
|
|
2152
|
+
"coverage_to",
|
|
2153
|
+
cohort.coverage.maxTimestamp == null ? "n/a" : new Date(cohort.coverage.maxTimestamp).toISOString()
|
|
2154
|
+
],
|
|
2155
|
+
["scope_rows", cohort.scopeRows],
|
|
2156
|
+
["train_rows", cohort.trainRows],
|
|
2157
|
+
["validation_rows", cohort.validationRows],
|
|
2158
|
+
["test_rows", cohort.testRows],
|
|
2159
|
+
[
|
|
2160
|
+
"low_cadence",
|
|
2161
|
+
cohort.search.stats.cadence.lowCadence ? "yes" : "no"
|
|
2162
|
+
],
|
|
2163
|
+
[
|
|
2164
|
+
"sparse_sample",
|
|
2165
|
+
cohort.search.stats.cadence.sparseSample ? "yes" : "no"
|
|
2166
|
+
],
|
|
2167
|
+
[
|
|
2168
|
+
"adaptive_thresholds",
|
|
2169
|
+
cohort.search.stats.cadence.adaptiveThresholds ? "on" : "off"
|
|
2170
|
+
],
|
|
2171
|
+
["train_events", cohort.search.stats.cadence.trainEvents],
|
|
2172
|
+
[
|
|
2173
|
+
"train_events_per_day",
|
|
2174
|
+
formatMdNumber(cohort.search.stats.cadence.trainEventsPerDay, 4)
|
|
2175
|
+
],
|
|
2176
|
+
["effective_min_support", cohort.search.stats.cadence.minSupport],
|
|
2177
|
+
["effective_min_events", cohort.search.stats.cadence.minEvents],
|
|
2178
|
+
[
|
|
2179
|
+
"effective_min_validation_support",
|
|
2180
|
+
cohort.search.stats.cadence.minValidationSupport
|
|
2181
|
+
],
|
|
2182
|
+
[
|
|
2183
|
+
"effective_min_validation_events",
|
|
2184
|
+
cohort.search.stats.cadence.minValidationEvents
|
|
2185
|
+
],
|
|
2186
|
+
[
|
|
2187
|
+
"effective_max_event_count_share",
|
|
2188
|
+
formatMdPercent(cohort.search.stats.cadence.maxEventCountShare)
|
|
2189
|
+
],
|
|
2190
|
+
[
|
|
2191
|
+
"required_feature_families",
|
|
2192
|
+
cohort.search.stats.requiredFeatureFamilies.join(", ") || "none"
|
|
2193
|
+
]
|
|
2194
|
+
]
|
|
2195
|
+
),
|
|
2196
|
+
"",
|
|
2197
|
+
`### ${title} Train Baseline`,
|
|
2198
|
+
"",
|
|
2199
|
+
markdownTable(
|
|
2200
|
+
["Metric", "Value"],
|
|
2201
|
+
summaryMetricRows(cohort.search.baseline)
|
|
2202
|
+
),
|
|
2203
|
+
"",
|
|
2204
|
+
`### ${title} Top Positive Pockets`,
|
|
2205
|
+
"",
|
|
2206
|
+
markdownTable(
|
|
2207
|
+
pocketTableHeaders,
|
|
2208
|
+
pocketRows(cohort.search.positivePockets)
|
|
2209
|
+
),
|
|
2210
|
+
"",
|
|
2211
|
+
`### ${title} Top Loss Pockets`,
|
|
2212
|
+
"",
|
|
2213
|
+
markdownTable(
|
|
2214
|
+
pocketTableHeaders,
|
|
2215
|
+
pocketRows(cohort.search.negativePockets)
|
|
2216
|
+
),
|
|
2217
|
+
""
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
1792
2220
|
if (errors.length) {
|
|
1793
2221
|
lines.push("## Errors", "", ...errors.map((error) => `- ${error}`), "");
|
|
1794
2222
|
}
|
|
@@ -1799,8 +2227,12 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1799
2227
|
0 && (module.exports = {
|
|
1800
2228
|
buildAiPocketMarkdownReport,
|
|
1801
2229
|
buildAiPocketPredicates,
|
|
2230
|
+
classifyAiPocketCoverageFeaturePath,
|
|
1802
2231
|
classifyAiPocketFeaturePath,
|
|
2232
|
+
collectAiPocketFeatureSnapshot,
|
|
1803
2233
|
collectAiPocketFeatures,
|
|
2234
|
+
resolveAiPocketFeatureCoverage,
|
|
1804
2235
|
searchAiPockets,
|
|
2236
|
+
summarizeAiPocketFeatureCoverage,
|
|
1805
2237
|
summarizeAiPocketRows
|
|
1806
2238
|
});
|