@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
|
@@ -414,6 +414,7 @@ var resolveAiTrainRecentLimit = ({
|
|
|
414
414
|
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
415
415
|
var DAYS_PER_WEEK2 = 7;
|
|
416
416
|
var DAYS_PER_MONTH2 = 30.4375;
|
|
417
|
+
var PRODUCTION_CANDIDATE_MIN_EVENTS = 25;
|
|
417
418
|
var OUTCOME_SEGMENTS = /* @__PURE__ */ new Set([
|
|
418
419
|
"actual",
|
|
419
420
|
"aiapproved",
|
|
@@ -499,6 +500,146 @@ var METADATA_LEAVES = /* @__PURE__ */ new Set([
|
|
|
499
500
|
"targetsymbol",
|
|
500
501
|
"universe"
|
|
501
502
|
]);
|
|
503
|
+
var normalizeFeaturePath = (path2) => (Array.isArray(path2) ? path2 : path2.split(".")).filter(Boolean).map((segment) => segment.toLowerCase());
|
|
504
|
+
var classifyAiPocketCoverageFeaturePath = (path2) => {
|
|
505
|
+
const segments = normalizeFeaturePath(path2);
|
|
506
|
+
const normalizedPath = segments.join(".");
|
|
507
|
+
if (segments.some(
|
|
508
|
+
(segment) => segment.includes("cmc") || segment.includes("coinmarketcap")
|
|
509
|
+
)) {
|
|
510
|
+
return "cmc";
|
|
511
|
+
}
|
|
512
|
+
if (segments.some(
|
|
513
|
+
(segment) => segment.includes("derivative") || segment.includes("coinalyze")
|
|
514
|
+
) || /(?:^|\.)(?:funding|openinterest|oi(?:change|acceleration|divergence)|priceoi|liq(?:long|short|total|imbalance|spike)|liquidation)/.test(
|
|
515
|
+
normalizedPath
|
|
516
|
+
)) {
|
|
517
|
+
return "coinalyze";
|
|
518
|
+
}
|
|
519
|
+
return null;
|
|
520
|
+
};
|
|
521
|
+
var hasUsableContextPrimitive = (value) => {
|
|
522
|
+
if (Array.isArray(value) || value == null) {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
if (isFeaturePrimitive(value)) {
|
|
526
|
+
return typeof value !== "string" || value.toLowerCase() !== "unknown";
|
|
527
|
+
}
|
|
528
|
+
if (!isPlainRecord(value)) {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
return Object.entries(value).some(([key, child]) => {
|
|
532
|
+
const normalizedKey = key.toLowerCase();
|
|
533
|
+
if (DATA_QUALITY_LEAVES.has(normalizedKey) || METADATA_LEAVES.has(normalizedKey) || normalizedKey === "riskflags" || normalizedKey.endsWith("timestamp") || normalizedKey.endsWith("agems")) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
return hasUsableContextPrimitive(child);
|
|
537
|
+
});
|
|
538
|
+
};
|
|
539
|
+
var isUsableCmcContext = (value) => isPlainRecord(value) && value.available !== false && value.stale !== true && hasUsableContextPrimitive(value);
|
|
540
|
+
var hasUsableCmcContext = (baseContext) => {
|
|
541
|
+
const relative = isPlainRecord(baseContext?.relative) ? baseContext.relative : null;
|
|
542
|
+
return Boolean(
|
|
543
|
+
relative && Object.entries(relative).some(
|
|
544
|
+
([key, value]) => key.toLowerCase().startsWith("cmc") && isUsableCmcContext(value)
|
|
545
|
+
)
|
|
546
|
+
);
|
|
547
|
+
};
|
|
548
|
+
var isUsableDerivativesContext = (context) => {
|
|
549
|
+
if (!context) {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
const summary = isPlainRecord(context.summary) ? context.summary : null;
|
|
553
|
+
const riskFlags = Array.isArray(summary?.riskFlags) ? summary.riskFlags.filter(
|
|
554
|
+
(flag) => typeof flag === "string"
|
|
555
|
+
) : [];
|
|
556
|
+
if (riskFlags.includes("missing_derivatives") || riskFlags.includes("stale_derivatives")) {
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
const intervals = isPlainRecord(context.intervals) ? context.intervals : null;
|
|
560
|
+
return Boolean(
|
|
561
|
+
intervals && Object.values(intervals).some(
|
|
562
|
+
(interval) => isPlainRecord(interval) && interval.stale !== true && hasUsableContextPrimitive(interval)
|
|
563
|
+
)
|
|
564
|
+
);
|
|
565
|
+
};
|
|
566
|
+
var hasUsableCoinalyzeContext = (baseContext) => {
|
|
567
|
+
const derivatives = isPlainRecord(baseContext?.derivatives) ? baseContext.derivatives : null;
|
|
568
|
+
if (!derivatives) {
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
if (isUsableDerivativesContext(derivatives)) {
|
|
572
|
+
return true;
|
|
573
|
+
}
|
|
574
|
+
const targetContext = isPlainRecord(derivatives.targetContext) ? derivatives.targetContext : null;
|
|
575
|
+
if (isUsableDerivativesContext(targetContext)) {
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
const referenceContexts = isPlainRecord(derivatives.referenceContexts) ? derivatives.referenceContexts : null;
|
|
579
|
+
return Boolean(
|
|
580
|
+
referenceContexts && Object.values(referenceContexts).some(
|
|
581
|
+
(context) => isUsableDerivativesContext(isPlainRecord(context) ? context : null)
|
|
582
|
+
)
|
|
583
|
+
);
|
|
584
|
+
};
|
|
585
|
+
var resolveAiPocketFeatureCoverage = (payload) => {
|
|
586
|
+
const additionalIndicators = isPlainRecord(payload.additionalIndicators) ? payload.additionalIndicators : null;
|
|
587
|
+
const baseContext = isPlainRecord(additionalIndicators?.baseContext) ? additionalIndicators.baseContext : null;
|
|
588
|
+
return {
|
|
589
|
+
cmc: hasUsableCmcContext(baseContext),
|
|
590
|
+
coinalyze: hasUsableCoinalyzeContext(baseContext)
|
|
591
|
+
};
|
|
592
|
+
};
|
|
593
|
+
var isAiPocketCoverageFeatureUsable = ({
|
|
594
|
+
payload,
|
|
595
|
+
segments,
|
|
596
|
+
family,
|
|
597
|
+
familyCoverage
|
|
598
|
+
}) => {
|
|
599
|
+
const additionalIndicators = isPlainRecord(payload.additionalIndicators) ? payload.additionalIndicators : null;
|
|
600
|
+
const baseContext = isPlainRecord(additionalIndicators?.baseContext) ? additionalIndicators.baseContext : null;
|
|
601
|
+
const baseContextIndex = segments.findIndex(
|
|
602
|
+
(segment) => segment.toLowerCase() === "basecontext"
|
|
603
|
+
);
|
|
604
|
+
if (family === "cmc") {
|
|
605
|
+
const relative = isPlainRecord(baseContext?.relative) ? baseContext.relative : null;
|
|
606
|
+
if (relative && baseContextIndex >= 0 && segments[baseContextIndex + 1]?.toLowerCase() === "relative") {
|
|
607
|
+
const contextKey = segments[baseContextIndex + 2];
|
|
608
|
+
if (contextKey?.toLowerCase().startsWith("cmc")) {
|
|
609
|
+
return isUsableCmcContext(relative[contextKey]);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return familyCoverage.cmc;
|
|
613
|
+
}
|
|
614
|
+
const derivatives = isPlainRecord(baseContext?.derivatives) ? baseContext.derivatives : null;
|
|
615
|
+
if (!derivatives || baseContextIndex < 0 || segments[baseContextIndex + 1]?.toLowerCase() !== "derivatives") {
|
|
616
|
+
return isUsableDerivativesContext(derivatives);
|
|
617
|
+
}
|
|
618
|
+
const branch = segments[baseContextIndex + 2]?.toLowerCase();
|
|
619
|
+
if (branch == null) {
|
|
620
|
+
return familyCoverage.coinalyze;
|
|
621
|
+
}
|
|
622
|
+
if (branch === "referencecontexts") {
|
|
623
|
+
const referenceContexts = isPlainRecord(derivatives.referenceContexts) ? derivatives.referenceContexts : null;
|
|
624
|
+
const symbol = segments[baseContextIndex + 3];
|
|
625
|
+
if (!symbol) {
|
|
626
|
+
return Boolean(
|
|
627
|
+
referenceContexts && Object.values(referenceContexts).some(
|
|
628
|
+
(context) => isUsableDerivativesContext(isPlainRecord(context) ? context : null)
|
|
629
|
+
)
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
return isUsableDerivativesContext(
|
|
633
|
+
symbol && referenceContexts && isPlainRecord(referenceContexts[symbol]) ? referenceContexts[symbol] : null
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
if (branch === "targetcontext" || branch === "targetderived") {
|
|
637
|
+
return isUsableDerivativesContext(
|
|
638
|
+
isPlainRecord(derivatives.targetContext) ? derivatives.targetContext : null
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
return isUsableDerivativesContext(derivatives);
|
|
642
|
+
};
|
|
502
643
|
var DERIVED_POLICY_FRAGMENTS = [
|
|
503
644
|
"approval",
|
|
504
645
|
"decisionhint",
|
|
@@ -837,7 +978,7 @@ var addSignalRiskDistanceFeatures = ({
|
|
|
837
978
|
features["derived.takeProfitDistanceBps"] = Math.abs(takeProfitPrice - currentPrice) / Math.abs(currentPrice) * 1e4;
|
|
838
979
|
}
|
|
839
980
|
};
|
|
840
|
-
var
|
|
981
|
+
var collectAiPocketFeatureSnapshot = ({
|
|
841
982
|
payload,
|
|
842
983
|
gateContext,
|
|
843
984
|
includeSymbol = false,
|
|
@@ -847,6 +988,7 @@ var collectAiPocketFeatures = ({
|
|
|
847
988
|
onFeatureExcluded
|
|
848
989
|
}) => {
|
|
849
990
|
const features = {};
|
|
991
|
+
const featureCoverage = resolveAiPocketFeatureCoverage(payload);
|
|
850
992
|
const signal = payload.signal ?? {};
|
|
851
993
|
const source = {
|
|
852
994
|
signal: {
|
|
@@ -865,6 +1007,19 @@ var collectAiPocketFeatures = ({
|
|
|
865
1007
|
segments: [],
|
|
866
1008
|
maxDepth: 8,
|
|
867
1009
|
shouldSkipPath: (segments) => {
|
|
1010
|
+
const coverageFamily = classifyAiPocketCoverageFeaturePath(segments);
|
|
1011
|
+
if (featurePolicy === "causal-stationary" && coverageFamily != null && !isAiPocketCoverageFeatureUsable({
|
|
1012
|
+
payload,
|
|
1013
|
+
segments,
|
|
1014
|
+
family: coverageFamily,
|
|
1015
|
+
familyCoverage: featureCoverage
|
|
1016
|
+
})) {
|
|
1017
|
+
onFeatureExcluded?.({
|
|
1018
|
+
path: segments.join("."),
|
|
1019
|
+
classification: "data-quality"
|
|
1020
|
+
});
|
|
1021
|
+
return true;
|
|
1022
|
+
}
|
|
868
1023
|
if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
|
|
869
1024
|
return true;
|
|
870
1025
|
}
|
|
@@ -895,7 +1050,7 @@ var collectAiPocketFeatures = ({
|
|
|
895
1050
|
}
|
|
896
1051
|
addSignalRiskDistanceFeatures({ features, signal });
|
|
897
1052
|
addDirectionalDerivedFeatures(features);
|
|
898
|
-
return features;
|
|
1053
|
+
return { features, featureCoverage };
|
|
899
1054
|
};
|
|
900
1055
|
var formatNumber = (value) => {
|
|
901
1056
|
if (Number.isInteger(value)) {
|
|
@@ -1162,6 +1317,37 @@ var summarizeRowIndexes = (rows, rowIndexes) => {
|
|
|
1162
1317
|
return finalizeAiPocketSummary({ rows, accumulator });
|
|
1163
1318
|
};
|
|
1164
1319
|
var summarizeAiPocketRows = (rows) => summarizeSelectedRows(rows, rows);
|
|
1320
|
+
var summarizeAiPocketFeatureCoverage = (rows, family) => {
|
|
1321
|
+
const coveredRows = rows.filter(
|
|
1322
|
+
(row) => row.featureCoverage?.[family] === true
|
|
1323
|
+
);
|
|
1324
|
+
const allEvents = /* @__PURE__ */ new Set();
|
|
1325
|
+
const coveredEvents = /* @__PURE__ */ new Set();
|
|
1326
|
+
let minTimestamp = null;
|
|
1327
|
+
let maxTimestamp = null;
|
|
1328
|
+
for (const row of rows) {
|
|
1329
|
+
if (isFiniteNumber(row.timestamp)) {
|
|
1330
|
+
allEvents.add(row.timestamp);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
for (const row of coveredRows) {
|
|
1334
|
+
if (!isFiniteNumber(row.timestamp)) {
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1337
|
+
coveredEvents.add(row.timestamp);
|
|
1338
|
+
minTimestamp = minTimestamp == null ? row.timestamp : Math.min(minTimestamp, row.timestamp);
|
|
1339
|
+
maxTimestamp = maxTimestamp == null ? row.timestamp : Math.max(maxTimestamp, row.timestamp);
|
|
1340
|
+
}
|
|
1341
|
+
return {
|
|
1342
|
+
family,
|
|
1343
|
+
rows: coveredRows.length,
|
|
1344
|
+
rowRatio: rows.length > 0 ? coveredRows.length / rows.length : 0,
|
|
1345
|
+
events: coveredEvents.size,
|
|
1346
|
+
eventRatio: allEvents.size > 0 ? coveredEvents.size / allEvents.size : 0,
|
|
1347
|
+
minTimestamp,
|
|
1348
|
+
maxTimestamp
|
|
1349
|
+
};
|
|
1350
|
+
};
|
|
1165
1351
|
var matchesPredicate = (value, predicate) => {
|
|
1166
1352
|
if (predicate.kind === "numeric") {
|
|
1167
1353
|
if (!isFiniteNumber(value)) {
|
|
@@ -1474,6 +1660,19 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
|
|
|
1474
1660
|
const condition = publicPredicates.map((predicate) => predicate.label).join(" AND ");
|
|
1475
1661
|
const validationScore = validationSummary == null || validationObjectiveSummary == null ? void 0 : validationSummary.support > 0 ? scorePositivePocket(validationObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(validationObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
1476
1662
|
const testScore = testSummary == null || testObjectiveSummary == null ? void 0 : testSummary.support > 0 ? scorePositivePocket(testObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(testObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
1663
|
+
const readinessReasons = [];
|
|
1664
|
+
if (summary.events < PRODUCTION_CANDIDATE_MIN_EVENTS) {
|
|
1665
|
+
readinessReasons.push(
|
|
1666
|
+
`train events ${summary.events} < ${PRODUCTION_CANDIDATE_MIN_EVENTS}`
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
if (testSummary == null) {
|
|
1670
|
+
readinessReasons.push("untouched test missing");
|
|
1671
|
+
} else if (testSummary.events < PRODUCTION_CANDIDATE_MIN_EVENTS) {
|
|
1672
|
+
readinessReasons.push(
|
|
1673
|
+
`test events ${testSummary.events} < ${PRODUCTION_CANDIDATE_MIN_EVENTS}`
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1477
1676
|
return {
|
|
1478
1677
|
id: publicPredicates.map((predicate) => predicate.id).join("&&"),
|
|
1479
1678
|
depth: publicPredicates.length,
|
|
@@ -1487,6 +1686,8 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
|
|
|
1487
1686
|
...objective !== "standalone" && testObjectiveSummary ? { testObjectiveSummary } : {},
|
|
1488
1687
|
...validationScore != null ? { validationScore } : {},
|
|
1489
1688
|
...testScore != null ? { testScore } : {},
|
|
1689
|
+
readiness: readinessReasons.length === 0 ? "production-candidate" : "research-only",
|
|
1690
|
+
readinessReasons,
|
|
1490
1691
|
score: scorePositivePocket(objectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(objectiveBaseline))
|
|
1491
1692
|
};
|
|
1492
1693
|
};
|
|
@@ -1581,6 +1782,43 @@ var diversifyPredicatePool = (predicates, maximum) => {
|
|
|
1581
1782
|
}
|
|
1582
1783
|
return selected;
|
|
1583
1784
|
};
|
|
1785
|
+
var prioritizeRequiredFeatureFamilyPredicates = ({
|
|
1786
|
+
selected,
|
|
1787
|
+
predicates,
|
|
1788
|
+
requiredFeatureFamilies,
|
|
1789
|
+
maximum
|
|
1790
|
+
}) => {
|
|
1791
|
+
if (!requiredFeatureFamilies.length) {
|
|
1792
|
+
return selected;
|
|
1793
|
+
}
|
|
1794
|
+
const perFamilyLimit = Math.max(
|
|
1795
|
+
6,
|
|
1796
|
+
Math.floor(maximum * 0.2 / requiredFeatureFamilies.length)
|
|
1797
|
+
);
|
|
1798
|
+
const prioritized = /* @__PURE__ */ new Map();
|
|
1799
|
+
for (const family of requiredFeatureFamilies) {
|
|
1800
|
+
const familyPredicates = predicates.filter(
|
|
1801
|
+
(predicate) => classifyAiPocketCoverageFeaturePath(predicate.featureKey) === family
|
|
1802
|
+
);
|
|
1803
|
+
const positive = [...familyPredicates].sort(
|
|
1804
|
+
(left, right) => scorePositivePocket(right.atomSummary) - scorePositivePocket(left.atomSummary)
|
|
1805
|
+
).slice(0, Math.ceil(perFamilyLimit * 0.5));
|
|
1806
|
+
const negative = [...familyPredicates].sort(
|
|
1807
|
+
(left, right) => scoreNegativePocket(right.atomSummary) - scoreNegativePocket(left.atomSummary)
|
|
1808
|
+
).slice(0, Math.ceil(perFamilyLimit * 0.3));
|
|
1809
|
+
const broad = [...familyPredicates].sort((left, right) => right.support - left.support).slice(0, Math.ceil(perFamilyLimit * 0.2));
|
|
1810
|
+
for (const predicate of [...positive, ...negative, ...broad]) {
|
|
1811
|
+
if (prioritized.size >= perFamilyLimit * requiredFeatureFamilies.length) {
|
|
1812
|
+
break;
|
|
1813
|
+
}
|
|
1814
|
+
prioritized.set(predicate.id, predicate);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
for (const predicate of selected) {
|
|
1818
|
+
prioritized.set(predicate.id, predicate);
|
|
1819
|
+
}
|
|
1820
|
+
return [...prioritized.values()].slice(0, maximum);
|
|
1821
|
+
};
|
|
1584
1822
|
var canCombinePredicate = (chosen, candidate) => {
|
|
1585
1823
|
const sameFeature = chosen.filter(
|
|
1586
1824
|
(predicate) => predicate.featureKey === candidate.featureKey
|
|
@@ -1596,7 +1834,11 @@ var canCombinePredicate = (chosen, candidate) => {
|
|
|
1596
1834
|
return lower <= upper;
|
|
1597
1835
|
};
|
|
1598
1836
|
var searchAiPockets = (rows, options = {}) => {
|
|
1599
|
-
const
|
|
1837
|
+
const cadenceProfileOption = options.cadenceProfile;
|
|
1838
|
+
const minSupport = Math.max(
|
|
1839
|
+
1,
|
|
1840
|
+
Math.trunc(cadenceProfileOption?.minSupport ?? options.minSupport ?? 20)
|
|
1841
|
+
);
|
|
1600
1842
|
const minProfitFactor = Math.max(0, options.minProfitFactor ?? 1.2);
|
|
1601
1843
|
const minTotalProfit = options.minTotalProfit ?? 0;
|
|
1602
1844
|
const minWinRate = Math.max(0, options.minWinRate ?? 0);
|
|
@@ -1614,17 +1856,27 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1614
1856
|
const testRows = options.testRows ?? [];
|
|
1615
1857
|
const minValidationSupport = Math.max(
|
|
1616
1858
|
0,
|
|
1617
|
-
Math.trunc(
|
|
1859
|
+
Math.trunc(
|
|
1860
|
+
cadenceProfileOption?.minValidationSupport ?? options.minValidationSupport ?? 0
|
|
1861
|
+
)
|
|
1862
|
+
);
|
|
1863
|
+
const minEvents = Math.max(
|
|
1864
|
+
1,
|
|
1865
|
+
Math.trunc(cadenceProfileOption?.minEvents ?? options.minEvents ?? 1)
|
|
1618
1866
|
);
|
|
1619
|
-
const minEvents = Math.max(1, Math.trunc(options.minEvents ?? 1));
|
|
1620
1867
|
const minValidationEvents = Math.max(
|
|
1621
1868
|
0,
|
|
1622
|
-
Math.trunc(
|
|
1869
|
+
Math.trunc(
|
|
1870
|
+
cadenceProfileOption?.minValidationEvents ?? options.minValidationEvents ?? 0
|
|
1871
|
+
)
|
|
1623
1872
|
);
|
|
1624
1873
|
const maxBatch = Math.max(1, options.maxBatch ?? Number.POSITIVE_INFINITY);
|
|
1625
1874
|
const maxEventCountShare = Math.max(
|
|
1626
1875
|
0,
|
|
1627
|
-
Math.min(
|
|
1876
|
+
Math.min(
|
|
1877
|
+
1,
|
|
1878
|
+
cadenceProfileOption?.maxEventCountShare ?? options.maxEventCountShare ?? 1
|
|
1879
|
+
)
|
|
1628
1880
|
);
|
|
1629
1881
|
const maxSymbolCountShare = Math.max(
|
|
1630
1882
|
0,
|
|
@@ -1642,18 +1894,59 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1642
1894
|
const allowRiskRegression = options.allowRiskRegression === true;
|
|
1643
1895
|
const requireValidationEligibility = options.requireValidationEligibility === true;
|
|
1644
1896
|
const dedupeEquivalentSelections = options.dedupeEquivalentSelections !== false;
|
|
1897
|
+
const requiredFeatureFamilies = [
|
|
1898
|
+
...new Set(options.requiredFeatureFamilies ?? [])
|
|
1899
|
+
];
|
|
1900
|
+
const excludedFeatureFamilies = [
|
|
1901
|
+
...new Set(options.excludedFeatureFamilies ?? [])
|
|
1902
|
+
];
|
|
1645
1903
|
const progressInterval = Math.max(
|
|
1646
1904
|
1,
|
|
1647
1905
|
Math.trunc(options.progressInterval ?? 500)
|
|
1648
1906
|
);
|
|
1649
1907
|
const onProgress = options.onProgress;
|
|
1908
|
+
const summarizePartition = (partitionRows) => {
|
|
1909
|
+
const summary = summarizeAiPocketRows(partitionRows);
|
|
1910
|
+
const periodDays = getPeriodDays(partitionRows);
|
|
1911
|
+
return {
|
|
1912
|
+
rows: partitionRows.length,
|
|
1913
|
+
events: summary.events,
|
|
1914
|
+
periodDays,
|
|
1915
|
+
eventsPerDay: periodDays == null ? null : summary.events / periodDays
|
|
1916
|
+
};
|
|
1917
|
+
};
|
|
1918
|
+
const trainPartition = summarizePartition(rows);
|
|
1919
|
+
const validationPartition = summarizePartition(validationRows);
|
|
1920
|
+
const testPartition = summarizePartition(testRows);
|
|
1921
|
+
const cadenceProfile = cadenceProfileOption ?? {
|
|
1922
|
+
mode: "fixed",
|
|
1923
|
+
lowCadence: false,
|
|
1924
|
+
sparseSample: false,
|
|
1925
|
+
adaptiveThresholds: false,
|
|
1926
|
+
trainRows: trainPartition.rows,
|
|
1927
|
+
trainEvents: trainPartition.events,
|
|
1928
|
+
trainPeriodDays: trainPartition.periodDays,
|
|
1929
|
+
trainEventsPerDay: trainPartition.eventsPerDay,
|
|
1930
|
+
validationRows: validationPartition.rows,
|
|
1931
|
+
validationEvents: validationPartition.events,
|
|
1932
|
+
testRows: testPartition.rows,
|
|
1933
|
+
testEvents: testPartition.events,
|
|
1934
|
+
minSupport,
|
|
1935
|
+
minEvents,
|
|
1936
|
+
minValidationSupport,
|
|
1937
|
+
minValidationEvents,
|
|
1938
|
+
maxEventCountShare
|
|
1939
|
+
};
|
|
1650
1940
|
const predicateResult = buildAiPocketPredicateResult(rows, {
|
|
1651
1941
|
minSupport,
|
|
1652
1942
|
maxCategories: options.maxCategories,
|
|
1653
1943
|
progressInterval,
|
|
1654
1944
|
onProgress
|
|
1655
1945
|
});
|
|
1656
|
-
const
|
|
1946
|
+
const predicates = predicateResult.predicates.filter((predicate) => {
|
|
1947
|
+
const family = classifyAiPocketCoverageFeaturePath(predicate.featureKey);
|
|
1948
|
+
return family == null || !excludedFeatureFamilies.includes(family);
|
|
1949
|
+
});
|
|
1657
1950
|
let lastMaskProgress = 0;
|
|
1658
1951
|
const emitMaskProgress = (current, done = false) => {
|
|
1659
1952
|
if (!onProgress) {
|
|
@@ -1685,10 +1978,15 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1685
1978
|
[...predicatePool, ...negativePool, ...supportPool].forEach((predicate) => {
|
|
1686
1979
|
predicatePoolById.set(predicate.id, predicate);
|
|
1687
1980
|
});
|
|
1688
|
-
const diversifiedPredicates =
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1981
|
+
const diversifiedPredicates = prioritizeRequiredFeatureFamilyPredicates({
|
|
1982
|
+
selected: diversifyPredicatePool(
|
|
1983
|
+
[...predicatePoolById.values()],
|
|
1984
|
+
maxAtomicPredicates
|
|
1985
|
+
),
|
|
1986
|
+
predicates: scoredPredicates,
|
|
1987
|
+
requiredFeatureFamilies,
|
|
1988
|
+
maximum: maxAtomicPredicates
|
|
1989
|
+
});
|
|
1692
1990
|
const selectedPredicatePool = diversifiedPredicates.map(
|
|
1693
1991
|
(predicate) => {
|
|
1694
1992
|
const { mask, support } = buildMask(rows, predicate);
|
|
@@ -1729,6 +2027,13 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1729
2027
|
});
|
|
1730
2028
|
};
|
|
1731
2029
|
const addPocket = (pocketPredicates, mask) => {
|
|
2030
|
+
if (requiredFeatureFamilies.some(
|
|
2031
|
+
(family) => !pocketPredicates.some(
|
|
2032
|
+
(predicate) => classifyAiPocketCoverageFeaturePath(predicate.featureKey) === family
|
|
2033
|
+
)
|
|
2034
|
+
)) {
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
1732
2037
|
const pocket = createPocketResult(
|
|
1733
2038
|
rows,
|
|
1734
2039
|
pocketPredicates,
|
|
@@ -1846,7 +2151,7 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1846
2151
|
negativePockets: [...negativePockets.values()].sort(compareNegativePockets).slice(0, top),
|
|
1847
2152
|
stats: {
|
|
1848
2153
|
rows: rows.length,
|
|
1849
|
-
featureKeys:
|
|
2154
|
+
featureKeys: new Set(predicates.map((predicate) => predicate.featureKey)).size,
|
|
1850
2155
|
predicates: predicates.length,
|
|
1851
2156
|
atomicPredicatesUsed: selectedPredicatePool.length,
|
|
1852
2157
|
estimatedCombinations,
|
|
@@ -1861,6 +2166,9 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1861
2166
|
)
|
|
1862
2167
|
)
|
|
1863
2168
|
],
|
|
2169
|
+
requiredFeatureFamilies,
|
|
2170
|
+
excludedFeatureFamilies,
|
|
2171
|
+
cadence: cadenceProfile,
|
|
1864
2172
|
truncated
|
|
1865
2173
|
}
|
|
1866
2174
|
};
|
|
@@ -1922,16 +2230,20 @@ var pocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
|
1922
2230
|
pocket.objectiveSummary ? formatMdNumber(pocket.objectiveSummary.totalProfit) : "n/a",
|
|
1923
2231
|
formatMdNumber(pocket.summary.maxDrawdown),
|
|
1924
2232
|
pocket.validationSummary?.support ?? "n/a",
|
|
2233
|
+
pocket.validationSummary?.events ?? "n/a",
|
|
1925
2234
|
pocket.validationSummary ? formatMdPercent(pocket.validationSummary.winRate) : "n/a",
|
|
1926
2235
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.profitFactor) : "n/a",
|
|
1927
2236
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.totalProfit) : "n/a",
|
|
1928
2237
|
pocket.testSummary?.support ?? "n/a",
|
|
2238
|
+
pocket.testSummary?.events ?? "n/a",
|
|
1929
2239
|
pocket.testSummary ? formatMdNumber(pocket.testSummary.profitFactor) : "n/a",
|
|
1930
2240
|
pocket.testSummary ? formatMdNumber(pocket.testSummary.totalProfit) : "n/a",
|
|
1931
2241
|
pocket.testObjectiveSummary ? formatMdNumber(pocket.testObjectiveSummary.totalProfit) : "n/a",
|
|
1932
2242
|
formatMdNumber(pocket.summary.avgTradesPerDay),
|
|
1933
2243
|
pocket.summary.losingMonths,
|
|
1934
2244
|
formatMdNumber(pocket.score),
|
|
2245
|
+
pocket.readiness,
|
|
2246
|
+
pocket.readinessReasons.join("; ") || "none",
|
|
1935
2247
|
pocket.condition
|
|
1936
2248
|
]);
|
|
1937
2249
|
var buildAiPocketMarkdownReport = ({
|
|
@@ -1939,6 +2251,7 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1939
2251
|
run,
|
|
1940
2252
|
currentGate,
|
|
1941
2253
|
pocketSearch,
|
|
2254
|
+
coverageSearches = [],
|
|
1942
2255
|
errors
|
|
1943
2256
|
}) => {
|
|
1944
2257
|
const generatedIso = new Date(generatedAt).toISOString();
|
|
@@ -1949,6 +2262,34 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1949
2262
|
audit?.paths ?? 0,
|
|
1950
2263
|
audit?.samples.join(", ") ?? ""
|
|
1951
2264
|
]);
|
|
2265
|
+
const pocketTableHeaders = [
|
|
2266
|
+
"#",
|
|
2267
|
+
"N",
|
|
2268
|
+
"Events",
|
|
2269
|
+
"Max batch",
|
|
2270
|
+
"Support",
|
|
2271
|
+
"WR",
|
|
2272
|
+
"PF",
|
|
2273
|
+
"PNL",
|
|
2274
|
+
"Objective PNL",
|
|
2275
|
+
"Max DD",
|
|
2276
|
+
"Val N",
|
|
2277
|
+
"Val Events",
|
|
2278
|
+
"Val WR",
|
|
2279
|
+
"Val PF",
|
|
2280
|
+
"Val PNL",
|
|
2281
|
+
"Test N",
|
|
2282
|
+
"Test Events",
|
|
2283
|
+
"Test PF",
|
|
2284
|
+
"Test PNL",
|
|
2285
|
+
"Test objective PNL",
|
|
2286
|
+
"Trades/Day",
|
|
2287
|
+
"Losing Months",
|
|
2288
|
+
"Score",
|
|
2289
|
+
"Readiness",
|
|
2290
|
+
"Readiness reasons",
|
|
2291
|
+
"Pocket"
|
|
2292
|
+
];
|
|
1952
2293
|
const lines = [
|
|
1953
2294
|
"# AI Pocket Search Report",
|
|
1954
2295
|
"",
|
|
@@ -1972,6 +2313,17 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1972
2313
|
["test_rows", run.testRows],
|
|
1973
2314
|
["validation_split", formatMdPercent(run.validationSplit)],
|
|
1974
2315
|
["test_split", formatMdPercent(run.testSplit)],
|
|
2316
|
+
["test_sealed", run.sealedTest?.sealed ? "yes" : "no"],
|
|
2317
|
+
["sealed_test_rows", run.sealedTest?.rows ?? run.testRows],
|
|
2318
|
+
["sealed_test_events", run.sealedTest?.events ?? "n/a"],
|
|
2319
|
+
[
|
|
2320
|
+
"sealed_test_start",
|
|
2321
|
+
run.sealedTest?.startTimestamp == null ? "n/a" : new Date(run.sealedTest.startTimestamp).toISOString()
|
|
2322
|
+
],
|
|
2323
|
+
[
|
|
2324
|
+
"sealed_test_end",
|
|
2325
|
+
run.sealedTest?.endTimestamp == null ? "n/a" : new Date(run.sealedTest.endTimestamp).toISOString()
|
|
2326
|
+
],
|
|
1975
2327
|
["min_validation_support", run.minValidationSupport],
|
|
1976
2328
|
["failed", run.failed],
|
|
1977
2329
|
["recent", run.recent === 0 ? "all" : run.recent],
|
|
@@ -2013,6 +2365,22 @@ var buildAiPocketMarkdownReport = ({
|
|
|
2013
2365
|
["include_gate_context", run.includeGateContext ? "on" : "off"],
|
|
2014
2366
|
["feature_profile", run.featureProfile ?? "all"],
|
|
2015
2367
|
["feature_policy", run.featurePolicy ?? "all"],
|
|
2368
|
+
["coverage_mode", run.coverageMode ?? "full"],
|
|
2369
|
+
["cadence_mode", run.cadenceMode ?? "fixed"],
|
|
2370
|
+
["low_cadence", pocketSearch.stats.cadence.lowCadence ? "yes" : "no"],
|
|
2371
|
+
[
|
|
2372
|
+
"sparse_sample",
|
|
2373
|
+
pocketSearch.stats.cadence.sparseSample ? "yes" : "no"
|
|
2374
|
+
],
|
|
2375
|
+
[
|
|
2376
|
+
"adaptive_thresholds",
|
|
2377
|
+
pocketSearch.stats.cadence.adaptiveThresholds ? "on" : "off"
|
|
2378
|
+
],
|
|
2379
|
+
["train_events", pocketSearch.stats.cadence.trainEvents],
|
|
2380
|
+
[
|
|
2381
|
+
"train_events_per_day",
|
|
2382
|
+
formatMdNumber(pocketSearch.stats.cadence.trainEventsPerDay, 4)
|
|
2383
|
+
],
|
|
2016
2384
|
["report_path", run.reportPath]
|
|
2017
2385
|
]
|
|
2018
2386
|
),
|
|
@@ -2098,10 +2466,32 @@ var buildAiPocketMarkdownReport = ({
|
|
|
2098
2466
|
["predicates", pocketSearch.stats.predicates],
|
|
2099
2467
|
["atomic_used", pocketSearch.stats.atomicPredicatesUsed],
|
|
2100
2468
|
["feature_families", pocketSearch.stats.featureFamiliesUsed.join(", ")],
|
|
2469
|
+
[
|
|
2470
|
+
"required_feature_families",
|
|
2471
|
+
pocketSearch.stats.requiredFeatureFamilies.join(", ") || "none"
|
|
2472
|
+
],
|
|
2473
|
+
[
|
|
2474
|
+
"excluded_feature_families",
|
|
2475
|
+
pocketSearch.stats.excludedFeatureFamilies.join(", ") || "none"
|
|
2476
|
+
],
|
|
2101
2477
|
["estimated_combinations", pocketSearch.stats.estimatedCombinations],
|
|
2102
2478
|
["combinations_evaluated", pocketSearch.stats.combinationsEvaluated],
|
|
2103
2479
|
["validation_rows", pocketSearch.stats.validationRows],
|
|
2104
2480
|
["test_rows", pocketSearch.stats.testRows],
|
|
2481
|
+
["effective_min_support", pocketSearch.stats.cadence.minSupport],
|
|
2482
|
+
["effective_min_events", pocketSearch.stats.cadence.minEvents],
|
|
2483
|
+
[
|
|
2484
|
+
"effective_min_validation_support",
|
|
2485
|
+
pocketSearch.stats.cadence.minValidationSupport
|
|
2486
|
+
],
|
|
2487
|
+
[
|
|
2488
|
+
"effective_min_validation_events",
|
|
2489
|
+
pocketSearch.stats.cadence.minValidationEvents
|
|
2490
|
+
],
|
|
2491
|
+
[
|
|
2492
|
+
"effective_max_event_count_share",
|
|
2493
|
+
formatMdPercent(pocketSearch.stats.cadence.maxEventCountShare)
|
|
2494
|
+
],
|
|
2105
2495
|
[
|
|
2106
2496
|
"duplicate_pockets_skipped",
|
|
2107
2497
|
pocketSearch.stats.duplicatePocketsSkipped
|
|
@@ -2112,65 +2502,98 @@ var buildAiPocketMarkdownReport = ({
|
|
|
2112
2502
|
"",
|
|
2113
2503
|
"## Top Positive Pockets",
|
|
2114
2504
|
"",
|
|
2115
|
-
markdownTable(
|
|
2116
|
-
[
|
|
2117
|
-
"#",
|
|
2118
|
-
"N",
|
|
2119
|
-
"Events",
|
|
2120
|
-
"Max batch",
|
|
2121
|
-
"Support",
|
|
2122
|
-
"WR",
|
|
2123
|
-
"PF",
|
|
2124
|
-
"PNL",
|
|
2125
|
-
"Objective PNL",
|
|
2126
|
-
"Max DD",
|
|
2127
|
-
"Val N",
|
|
2128
|
-
"Val WR",
|
|
2129
|
-
"Val PF",
|
|
2130
|
-
"Val PNL",
|
|
2131
|
-
"Test N",
|
|
2132
|
-
"Test PF",
|
|
2133
|
-
"Test PNL",
|
|
2134
|
-
"Test objective PNL",
|
|
2135
|
-
"Trades/Day",
|
|
2136
|
-
"Losing Months",
|
|
2137
|
-
"Score",
|
|
2138
|
-
"Pocket"
|
|
2139
|
-
],
|
|
2140
|
-
pocketRows(pocketSearch.positivePockets)
|
|
2141
|
-
),
|
|
2505
|
+
markdownTable(pocketTableHeaders, pocketRows(pocketSearch.positivePockets)),
|
|
2142
2506
|
"",
|
|
2143
2507
|
"## Top Loss Pockets",
|
|
2144
2508
|
"",
|
|
2145
|
-
markdownTable(
|
|
2146
|
-
[
|
|
2147
|
-
"#",
|
|
2148
|
-
"N",
|
|
2149
|
-
"Events",
|
|
2150
|
-
"Max batch",
|
|
2151
|
-
"Support",
|
|
2152
|
-
"WR",
|
|
2153
|
-
"PF",
|
|
2154
|
-
"PNL",
|
|
2155
|
-
"Objective PNL",
|
|
2156
|
-
"Max DD",
|
|
2157
|
-
"Val N",
|
|
2158
|
-
"Val WR",
|
|
2159
|
-
"Val PF",
|
|
2160
|
-
"Val PNL",
|
|
2161
|
-
"Test N",
|
|
2162
|
-
"Test PF",
|
|
2163
|
-
"Test PNL",
|
|
2164
|
-
"Test objective PNL",
|
|
2165
|
-
"Trades/Day",
|
|
2166
|
-
"Losing Months",
|
|
2167
|
-
"Score",
|
|
2168
|
-
"Pocket"
|
|
2169
|
-
],
|
|
2170
|
-
pocketRows(pocketSearch.negativePockets)
|
|
2171
|
-
),
|
|
2509
|
+
markdownTable(pocketTableHeaders, pocketRows(pocketSearch.negativePockets)),
|
|
2172
2510
|
""
|
|
2173
2511
|
];
|
|
2512
|
+
for (const cohort of coverageSearches) {
|
|
2513
|
+
const title = cohort.family === "cmc" ? "CMC" : "Coinalyze";
|
|
2514
|
+
lines.push(
|
|
2515
|
+
`## Coverage Cohort: ${title}`,
|
|
2516
|
+
"",
|
|
2517
|
+
markdownTable(
|
|
2518
|
+
["Field", "Value"],
|
|
2519
|
+
[
|
|
2520
|
+
["coverage_rows", cohort.coverage.rows],
|
|
2521
|
+
["coverage_row_ratio", formatMdPercent(cohort.coverage.rowRatio)],
|
|
2522
|
+
["coverage_events", cohort.coverage.events],
|
|
2523
|
+
["coverage_event_ratio", formatMdPercent(cohort.coverage.eventRatio)],
|
|
2524
|
+
[
|
|
2525
|
+
"coverage_from",
|
|
2526
|
+
cohort.coverage.minTimestamp == null ? "n/a" : new Date(cohort.coverage.minTimestamp).toISOString()
|
|
2527
|
+
],
|
|
2528
|
+
[
|
|
2529
|
+
"coverage_to",
|
|
2530
|
+
cohort.coverage.maxTimestamp == null ? "n/a" : new Date(cohort.coverage.maxTimestamp).toISOString()
|
|
2531
|
+
],
|
|
2532
|
+
["scope_rows", cohort.scopeRows],
|
|
2533
|
+
["train_rows", cohort.trainRows],
|
|
2534
|
+
["validation_rows", cohort.validationRows],
|
|
2535
|
+
["test_rows", cohort.testRows],
|
|
2536
|
+
[
|
|
2537
|
+
"low_cadence",
|
|
2538
|
+
cohort.search.stats.cadence.lowCadence ? "yes" : "no"
|
|
2539
|
+
],
|
|
2540
|
+
[
|
|
2541
|
+
"sparse_sample",
|
|
2542
|
+
cohort.search.stats.cadence.sparseSample ? "yes" : "no"
|
|
2543
|
+
],
|
|
2544
|
+
[
|
|
2545
|
+
"adaptive_thresholds",
|
|
2546
|
+
cohort.search.stats.cadence.adaptiveThresholds ? "on" : "off"
|
|
2547
|
+
],
|
|
2548
|
+
["train_events", cohort.search.stats.cadence.trainEvents],
|
|
2549
|
+
[
|
|
2550
|
+
"train_events_per_day",
|
|
2551
|
+
formatMdNumber(cohort.search.stats.cadence.trainEventsPerDay, 4)
|
|
2552
|
+
],
|
|
2553
|
+
["effective_min_support", cohort.search.stats.cadence.minSupport],
|
|
2554
|
+
["effective_min_events", cohort.search.stats.cadence.minEvents],
|
|
2555
|
+
[
|
|
2556
|
+
"effective_min_validation_support",
|
|
2557
|
+
cohort.search.stats.cadence.minValidationSupport
|
|
2558
|
+
],
|
|
2559
|
+
[
|
|
2560
|
+
"effective_min_validation_events",
|
|
2561
|
+
cohort.search.stats.cadence.minValidationEvents
|
|
2562
|
+
],
|
|
2563
|
+
[
|
|
2564
|
+
"effective_max_event_count_share",
|
|
2565
|
+
formatMdPercent(cohort.search.stats.cadence.maxEventCountShare)
|
|
2566
|
+
],
|
|
2567
|
+
[
|
|
2568
|
+
"required_feature_families",
|
|
2569
|
+
cohort.search.stats.requiredFeatureFamilies.join(", ") || "none"
|
|
2570
|
+
]
|
|
2571
|
+
]
|
|
2572
|
+
),
|
|
2573
|
+
"",
|
|
2574
|
+
`### ${title} Train Baseline`,
|
|
2575
|
+
"",
|
|
2576
|
+
markdownTable(
|
|
2577
|
+
["Metric", "Value"],
|
|
2578
|
+
summaryMetricRows(cohort.search.baseline)
|
|
2579
|
+
),
|
|
2580
|
+
"",
|
|
2581
|
+
`### ${title} Top Positive Pockets`,
|
|
2582
|
+
"",
|
|
2583
|
+
markdownTable(
|
|
2584
|
+
pocketTableHeaders,
|
|
2585
|
+
pocketRows(cohort.search.positivePockets)
|
|
2586
|
+
),
|
|
2587
|
+
"",
|
|
2588
|
+
`### ${title} Top Loss Pockets`,
|
|
2589
|
+
"",
|
|
2590
|
+
markdownTable(
|
|
2591
|
+
pocketTableHeaders,
|
|
2592
|
+
pocketRows(cohort.search.negativePockets)
|
|
2593
|
+
),
|
|
2594
|
+
""
|
|
2595
|
+
);
|
|
2596
|
+
}
|
|
2174
2597
|
if (errors.length) {
|
|
2175
2598
|
lines.push("## Errors", "", ...errors.map((error) => `- ${error}`), "");
|
|
2176
2599
|
}
|
|
@@ -2179,6 +2602,90 @@ var buildAiPocketMarkdownReport = ({
|
|
|
2179
2602
|
};
|
|
2180
2603
|
|
|
2181
2604
|
// src/lib/aiPocketSearchCli.ts
|
|
2605
|
+
var DAY_MS3 = 24 * 60 * 60 * 1e3;
|
|
2606
|
+
var DEFAULT_MIN_SUPPORT = 20;
|
|
2607
|
+
var LOW_CADENCE_EVENT_LIMIT = 200;
|
|
2608
|
+
var LOW_CADENCE_MAX_EVENT_SHARE = 1 / 3;
|
|
2609
|
+
var countIndependentEvents = (rows) => {
|
|
2610
|
+
const timestampEvents = /* @__PURE__ */ new Set();
|
|
2611
|
+
let rowsWithoutTimestamp = 0;
|
|
2612
|
+
for (const row of rows) {
|
|
2613
|
+
if (typeof row.timestamp === "number" && Number.isFinite(row.timestamp)) {
|
|
2614
|
+
timestampEvents.add(row.timestamp);
|
|
2615
|
+
} else {
|
|
2616
|
+
rowsWithoutTimestamp += 1;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
return timestampEvents.size + rowsWithoutTimestamp;
|
|
2620
|
+
};
|
|
2621
|
+
var getPeriodDays2 = (rows) => {
|
|
2622
|
+
let minTimestamp = null;
|
|
2623
|
+
let maxTimestamp = null;
|
|
2624
|
+
for (const row of rows) {
|
|
2625
|
+
const timestamp = row.timestamp;
|
|
2626
|
+
if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) {
|
|
2627
|
+
continue;
|
|
2628
|
+
}
|
|
2629
|
+
minTimestamp = minTimestamp == null ? timestamp : Math.min(minTimestamp, timestamp);
|
|
2630
|
+
maxTimestamp = maxTimestamp == null ? timestamp : Math.max(maxTimestamp, timestamp);
|
|
2631
|
+
}
|
|
2632
|
+
if (minTimestamp == null || maxTimestamp == null) {
|
|
2633
|
+
return null;
|
|
2634
|
+
}
|
|
2635
|
+
return Math.max((maxTimestamp - minTimestamp) / DAY_MS3, 1);
|
|
2636
|
+
};
|
|
2637
|
+
var clampInt = (value, minimum, maximum) => Math.max(minimum, Math.min(maximum, Math.ceil(value)));
|
|
2638
|
+
var resolveAiPocketCadenceProfile = ({
|
|
2639
|
+
trainRows,
|
|
2640
|
+
validationRows = [],
|
|
2641
|
+
testRows = [],
|
|
2642
|
+
mode = "auto",
|
|
2643
|
+
validationSplit = 0.25,
|
|
2644
|
+
minSupport,
|
|
2645
|
+
minEvents,
|
|
2646
|
+
minValidationSupport,
|
|
2647
|
+
minValidationEvents,
|
|
2648
|
+
maxEventCountShare = 0.25,
|
|
2649
|
+
explicitMaxEventCountShare = false
|
|
2650
|
+
}) => {
|
|
2651
|
+
const trainEvents = countIndependentEvents(trainRows);
|
|
2652
|
+
const validationEvents = countIndependentEvents(validationRows);
|
|
2653
|
+
const testEvents = countIndependentEvents(testRows);
|
|
2654
|
+
const trainPeriodDays = getPeriodDays2(trainRows);
|
|
2655
|
+
const trainEventsPerDay = trainPeriodDays == null ? null : trainEvents / trainPeriodDays;
|
|
2656
|
+
const sparseSample = trainEvents < LOW_CADENCE_EVENT_LIMIT;
|
|
2657
|
+
const lowCadence = trainEventsPerDay != null && trainEventsPerDay < 0.25;
|
|
2658
|
+
const adaptiveSample = mode === "auto" && sparseSample;
|
|
2659
|
+
const adaptiveThresholds = adaptiveSample && (minSupport == null || minEvents == null || validationRows.length > 0 && (minValidationSupport == null || minValidationEvents == null) || !explicitMaxEventCountShare);
|
|
2660
|
+
const resolvedMinSupport = minSupport ?? (adaptiveSample ? clampInt(trainEvents * 0.1, 3, DEFAULT_MIN_SUPPORT) : DEFAULT_MIN_SUPPORT);
|
|
2661
|
+
const resolvedMinEvents = minEvents ?? (minSupport != null || !adaptiveSample ? Math.max(5, Math.ceil(resolvedMinSupport * 0.5)) : clampInt(resolvedMinSupport * 0.5, 3, 10));
|
|
2662
|
+
const hasValidation = validationRows.length > 0;
|
|
2663
|
+
const resolvedMinValidationSupport = minValidationSupport ?? (hasValidation ? Math.max(3, Math.ceil(resolvedMinSupport * validationSplit * 0.5)) : 0);
|
|
2664
|
+
const resolvedMinValidationEvents = minValidationEvents ?? (hasValidation ? Math.max(
|
|
2665
|
+
adaptiveSample ? 3 : 2,
|
|
2666
|
+
Math.ceil(resolvedMinEvents * validationSplit * 0.5)
|
|
2667
|
+
) : 0);
|
|
2668
|
+
const resolvedMaxEventCountShare = adaptiveSample && !explicitMaxEventCountShare ? Math.max(maxEventCountShare, LOW_CADENCE_MAX_EVENT_SHARE) : maxEventCountShare;
|
|
2669
|
+
return {
|
|
2670
|
+
mode,
|
|
2671
|
+
lowCadence,
|
|
2672
|
+
sparseSample,
|
|
2673
|
+
adaptiveThresholds,
|
|
2674
|
+
trainRows: trainRows.length,
|
|
2675
|
+
trainEvents,
|
|
2676
|
+
trainPeriodDays,
|
|
2677
|
+
trainEventsPerDay,
|
|
2678
|
+
validationRows: validationRows.length,
|
|
2679
|
+
validationEvents,
|
|
2680
|
+
testRows: testRows.length,
|
|
2681
|
+
testEvents,
|
|
2682
|
+
minSupport: resolvedMinSupport,
|
|
2683
|
+
minEvents: resolvedMinEvents,
|
|
2684
|
+
minValidationSupport: resolvedMinValidationSupport,
|
|
2685
|
+
minValidationEvents: resolvedMinValidationEvents,
|
|
2686
|
+
maxEventCountShare: resolvedMaxEventCountShare
|
|
2687
|
+
};
|
|
2688
|
+
};
|
|
2182
2689
|
var AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS = {
|
|
2183
2690
|
minProfitFactor: "1.2",
|
|
2184
2691
|
minWinRate: "0",
|
|
@@ -2225,6 +2732,29 @@ var splitAiPocketResearchRowsByTimestamp = (rows, validationSplit, testSplit = 0
|
|
|
2225
2732
|
testRows: rows.filter((row) => isIn(testTimestamps, row.timestamp))
|
|
2226
2733
|
};
|
|
2227
2734
|
};
|
|
2735
|
+
var splitAiPocketCoverageRowsByTimestamp = (rows, family, validationSplit, testSplit = 0) => splitAiPocketResearchRowsByTimestamp(
|
|
2736
|
+
rows.filter((row) => row.featureCoverage?.[family] === true),
|
|
2737
|
+
validationSplit,
|
|
2738
|
+
testSplit
|
|
2739
|
+
);
|
|
2740
|
+
var sealAiPocketTestPartition = (split, sealed) => {
|
|
2741
|
+
const finiteTimestamps = split.testRows.map((row) => row.timestamp).filter((timestamp) => Number.isFinite(timestamp));
|
|
2742
|
+
return {
|
|
2743
|
+
discoveryRows: [
|
|
2744
|
+
...split.trainRows,
|
|
2745
|
+
...split.validationRows,
|
|
2746
|
+
...sealed ? [] : split.testRows
|
|
2747
|
+
],
|
|
2748
|
+
searchTestRows: sealed ? [] : split.testRows,
|
|
2749
|
+
evidence: {
|
|
2750
|
+
sealed,
|
|
2751
|
+
rows: split.testRows.length,
|
|
2752
|
+
events: countIndependentEvents(split.testRows),
|
|
2753
|
+
startTimestamp: finiteTimestamps.length ? Math.min(...finiteTimestamps) : null,
|
|
2754
|
+
endTimestamp: finiteTimestamps.length ? Math.max(...finiteTimestamps) : null
|
|
2755
|
+
}
|
|
2756
|
+
};
|
|
2757
|
+
};
|
|
2228
2758
|
var readAiPocketSearchCliOption = ({
|
|
2229
2759
|
argv,
|
|
2230
2760
|
longName,
|
|
@@ -2298,7 +2828,11 @@ import_args.default.option(
|
|
|
2298
2828
|
""
|
|
2299
2829
|
);
|
|
2300
2830
|
import_args.default.option(["d", "maxDepth"], "Maximum predicate-combination depth", 2);
|
|
2301
|
-
import_args.default.option(
|
|
2831
|
+
import_args.default.option(
|
|
2832
|
+
["m", "minSupport"],
|
|
2833
|
+
"Minimum rows override; cadence auto derives it when omitted",
|
|
2834
|
+
20
|
|
2835
|
+
);
|
|
2302
2836
|
import_args.default.option(
|
|
2303
2837
|
["F", "minProfitFactor"],
|
|
2304
2838
|
"Minimum profit factor required for positive pockets",
|
|
@@ -2334,6 +2868,11 @@ import_args.default.option(
|
|
|
2334
2868
|
"Trailing timestamp-grouped scope share withheld as untouched test",
|
|
2335
2869
|
AI_POCKET_SEARCH_CLI_DECIMAL_DEFAULTS.testSplit
|
|
2336
2870
|
);
|
|
2871
|
+
import_args.default.option(
|
|
2872
|
+
["w", "sealTest"],
|
|
2873
|
+
"Reserve test bounds without exposing its rows or economics to discovery",
|
|
2874
|
+
false
|
|
2875
|
+
);
|
|
2337
2876
|
import_args.default.option(
|
|
2338
2877
|
["N", "minValidationSupport"],
|
|
2339
2878
|
"Minimum validation rows required for positive pockets (0 = auto)",
|
|
@@ -2401,6 +2940,16 @@ import_args.default.option(
|
|
|
2401
2940
|
"Feature policy: causal-stationary or all",
|
|
2402
2941
|
"causal-stationary"
|
|
2403
2942
|
);
|
|
2943
|
+
import_args.default.option(
|
|
2944
|
+
["Q", "coverageMode"],
|
|
2945
|
+
"Coverage-aware search mode: auto or full",
|
|
2946
|
+
"auto"
|
|
2947
|
+
);
|
|
2948
|
+
import_args.default.option(
|
|
2949
|
+
["c", "cadenceMode"],
|
|
2950
|
+
"Cadence thresholds: auto adapts discovery support, fixed keeps legacy defaults",
|
|
2951
|
+
"auto"
|
|
2952
|
+
);
|
|
2404
2953
|
import_args.default.option(
|
|
2405
2954
|
["r", "reportDir"],
|
|
2406
2955
|
"Directory for generated Markdown reports",
|
|
@@ -2522,6 +3071,24 @@ var normalizeFeaturePolicy = (value) => {
|
|
|
2522
3071
|
}
|
|
2523
3072
|
return normalized;
|
|
2524
3073
|
};
|
|
3074
|
+
var normalizeCoverageMode = (value) => {
|
|
3075
|
+
const normalized = String(value || "auto").trim().toLowerCase();
|
|
3076
|
+
if (!["auto", "full"].includes(normalized)) {
|
|
3077
|
+
throw new Error(
|
|
3078
|
+
`Unsupported --coverageMode "${normalized}". Use auto or full.`
|
|
3079
|
+
);
|
|
3080
|
+
}
|
|
3081
|
+
return normalized;
|
|
3082
|
+
};
|
|
3083
|
+
var normalizeCadenceMode = (value) => {
|
|
3084
|
+
const normalized = String(value || "auto").trim().toLowerCase();
|
|
3085
|
+
if (!["auto", "fixed"].includes(normalized)) {
|
|
3086
|
+
throw new Error(
|
|
3087
|
+
`Unsupported --cadenceMode "${normalized}". Use auto or fixed.`
|
|
3088
|
+
);
|
|
3089
|
+
}
|
|
3090
|
+
return normalized;
|
|
3091
|
+
};
|
|
2525
3092
|
var normalizeObjective = (value, scope) => {
|
|
2526
3093
|
const normalized = String(value || "auto").trim().toLowerCase();
|
|
2527
3094
|
if (normalized === "auto") {
|
|
@@ -2749,16 +3316,20 @@ var buildPocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
|
2749
3316
|
pocket.objectiveSummary ? colorizeProfit(pocket.objectiveSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
2750
3317
|
colorizeProfit(-pocket.summary.maxDrawdown),
|
|
2751
3318
|
pocket.validationSummary ? import_chalk.default.cyan(String(pocket.validationSummary.support)) : import_chalk.default.gray("n/a"),
|
|
3319
|
+
pocket.validationSummary ? import_chalk.default.cyan(String(pocket.validationSummary.events)) : import_chalk.default.gray("n/a"),
|
|
2752
3320
|
pocket.validationSummary ? colorizeRatio(pocket.validationSummary.winRate) : import_chalk.default.gray("n/a"),
|
|
2753
3321
|
pocket.validationSummary ? colorizeNumber(pocket.validationSummary.profitFactor) : import_chalk.default.gray("n/a"),
|
|
2754
3322
|
pocket.validationSummary ? colorizeProfit(pocket.validationSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
2755
3323
|
pocket.testSummary ? import_chalk.default.cyan(String(pocket.testSummary.support)) : import_chalk.default.gray("n/a"),
|
|
3324
|
+
pocket.testSummary ? import_chalk.default.cyan(String(pocket.testSummary.events)) : import_chalk.default.gray("n/a"),
|
|
2756
3325
|
pocket.testSummary ? colorizeNumber(pocket.testSummary.profitFactor) : import_chalk.default.gray("n/a"),
|
|
2757
3326
|
pocket.testSummary ? colorizeProfit(pocket.testSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
2758
3327
|
pocket.testObjectiveSummary ? colorizeProfit(pocket.testObjectiveSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
2759
3328
|
colorizeNumber(pocket.summary.avgTradesPerDay),
|
|
2760
3329
|
import_chalk.default.yellow(String(pocket.summary.losingMonths)),
|
|
2761
3330
|
colorizeNumber(pocket.score),
|
|
3331
|
+
pocket.readiness === "production-candidate" ? import_chalk.default.green(pocket.readiness) : import_chalk.default.yellow(pocket.readiness),
|
|
3332
|
+
pocket.readinessReasons.length ? import_chalk.default.yellow(pocket.readinessReasons.join("; ")) : import_chalk.default.gray("none"),
|
|
2762
3333
|
pocket.condition
|
|
2763
3334
|
]);
|
|
2764
3335
|
var buildQualityRows = (qualityThresholds) => qualityThresholds.map(({ label, summary }) => [
|
|
@@ -2818,7 +3389,7 @@ var main = async () => {
|
|
|
2818
3389
|
);
|
|
2819
3390
|
}
|
|
2820
3391
|
const maxDepth = normalizePositiveInt(flags.maxDepth, 2);
|
|
2821
|
-
const
|
|
3392
|
+
const explicitMinSupport = hasCliOption2("minSupport", "m") ? normalizePositiveInt(flags.minSupport, 20) : void 0;
|
|
2822
3393
|
const minProfitFactor = normalizeNonNegativeNumber(
|
|
2823
3394
|
readAiPocketSearchCliOption({
|
|
2824
3395
|
argv: process.argv,
|
|
@@ -2862,6 +3433,10 @@ var main = async () => {
|
|
|
2862
3433
|
}) ?? flags.testSplit,
|
|
2863
3434
|
0
|
|
2864
3435
|
) : 0;
|
|
3436
|
+
const sealTest = Boolean(flags.sealTest);
|
|
3437
|
+
if (sealTest && testSplit <= 0) {
|
|
3438
|
+
throw new Error("--sealTest requires a positive --testSplit");
|
|
3439
|
+
}
|
|
2865
3440
|
const explicitMinValidationSupport = normalizeInt(
|
|
2866
3441
|
flags.minValidationSupport,
|
|
2867
3442
|
0
|
|
@@ -2899,6 +3474,8 @@ var main = async () => {
|
|
|
2899
3474
|
const includeGateContext = Boolean(flags.includeGateContext);
|
|
2900
3475
|
const featureProfile = normalizeFeatureProfile(flags.featureProfile);
|
|
2901
3476
|
const featurePolicy = normalizeFeaturePolicy(flags.featurePolicy);
|
|
3477
|
+
const coverageMode = normalizeCoverageMode(flags.coverageMode);
|
|
3478
|
+
const cadenceMode = normalizeCadenceMode(flags.cadenceMode);
|
|
2902
3479
|
const jsonOutput = Boolean(flags.json);
|
|
2903
3480
|
const outputPath = String(flags.output || "").trim();
|
|
2904
3481
|
const reportDir = String(flags.reportDir || "data/ai/output").trim();
|
|
@@ -2992,6 +3569,19 @@ var main = async () => {
|
|
|
2992
3569
|
const modelDirection = typeof analysis.direction === "string" && analysis.direction.trim() ? analysis.direction : null;
|
|
2993
3570
|
const modelDirectionMatches = modelDirection === row.direction;
|
|
2994
3571
|
const profit = Number(row.profit);
|
|
3572
|
+
const featureSnapshot = collectAiPocketFeatureSnapshot({
|
|
3573
|
+
payload,
|
|
3574
|
+
gateContext,
|
|
3575
|
+
includeSymbol,
|
|
3576
|
+
includeGateContext,
|
|
3577
|
+
featureProfile,
|
|
3578
|
+
featurePolicy,
|
|
3579
|
+
onFeatureExcluded: ({ path: featurePath, classification }) => {
|
|
3580
|
+
const paths = excludedFeaturePaths.get(classification) ?? /* @__PURE__ */ new Set();
|
|
3581
|
+
paths.add(featurePath);
|
|
3582
|
+
excludedFeaturePaths.set(classification, paths);
|
|
3583
|
+
}
|
|
3584
|
+
});
|
|
2995
3585
|
rows.push({
|
|
2996
3586
|
signalId: row.signalId,
|
|
2997
3587
|
strategy: row.strategyName,
|
|
@@ -3004,19 +3594,8 @@ var main = async () => {
|
|
|
3004
3594
|
quality,
|
|
3005
3595
|
modelDirectionMatches,
|
|
3006
3596
|
modelCandidate: getDeterministicModelCandidate(signal),
|
|
3007
|
-
features:
|
|
3008
|
-
|
|
3009
|
-
gateContext,
|
|
3010
|
-
includeSymbol,
|
|
3011
|
-
includeGateContext,
|
|
3012
|
-
featureProfile,
|
|
3013
|
-
featurePolicy,
|
|
3014
|
-
onFeatureExcluded: ({ path: featurePath, classification }) => {
|
|
3015
|
-
const paths = excludedFeaturePaths.get(classification) ?? /* @__PURE__ */ new Set();
|
|
3016
|
-
paths.add(featurePath);
|
|
3017
|
-
excludedFeaturePaths.set(classification, paths);
|
|
3018
|
-
}
|
|
3019
|
-
})
|
|
3597
|
+
features: featureSnapshot.features,
|
|
3598
|
+
featureCoverage: featureSnapshot.featureCoverage
|
|
3020
3599
|
});
|
|
3021
3600
|
bar?.tick(1, {
|
|
3022
3601
|
symbol: import_chalk.default.gray(row.symbol),
|
|
@@ -3038,86 +3617,188 @@ var main = async () => {
|
|
|
3038
3617
|
});
|
|
3039
3618
|
const directionRows = direction ? rows.filter((row) => row.direction === direction) : rows;
|
|
3040
3619
|
const scopeRows = resolveScopeRows(directionRows, scope);
|
|
3041
|
-
const
|
|
3620
|
+
const fullSplit = splitAiPocketResearchRowsByTimestamp(
|
|
3042
3621
|
directionRows,
|
|
3043
3622
|
validationSplit,
|
|
3044
3623
|
testSplit
|
|
3045
3624
|
);
|
|
3046
|
-
const
|
|
3047
|
-
const
|
|
3048
|
-
const
|
|
3049
|
-
const
|
|
3050
|
-
const
|
|
3625
|
+
const sealedFullSplit = sealAiPocketTestPartition(fullSplit, sealTest);
|
|
3626
|
+
const discoveryRows = sealedFullSplit.discoveryRows;
|
|
3627
|
+
const trainRows = resolveScopeRows(fullSplit.trainRows, scope);
|
|
3628
|
+
const validationRows = resolveScopeRows(fullSplit.validationRows, scope);
|
|
3629
|
+
const testRows = resolveScopeRows(sealedFullSplit.searchTestRows, scope);
|
|
3630
|
+
const baselineRows = fullSplit.trainRows.filter((row) => row.aiApproved);
|
|
3631
|
+
const validationBaselineRows = fullSplit.validationRows.filter(
|
|
3051
3632
|
(row) => row.aiApproved
|
|
3052
3633
|
);
|
|
3053
|
-
const testBaselineRows =
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
const
|
|
3057
|
-
const
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
const
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3634
|
+
const testBaselineRows = sealedFullSplit.searchTestRows.filter(
|
|
3635
|
+
(row) => row.aiApproved
|
|
3636
|
+
);
|
|
3637
|
+
const currentGateSummary = summarizeAiTrainEvaluations(discoveryRows);
|
|
3638
|
+
const currentGateQualityThresholds = summarizeAiTrainEvaluationsByQualityThreshold(
|
|
3639
|
+
discoveryRows,
|
|
3640
|
+
qualityThresholds
|
|
3641
|
+
);
|
|
3642
|
+
const runSearch = ({
|
|
3643
|
+
label,
|
|
3644
|
+
train,
|
|
3645
|
+
validation,
|
|
3646
|
+
test,
|
|
3647
|
+
trainBaseline,
|
|
3648
|
+
validationBaseline,
|
|
3649
|
+
testBaseline,
|
|
3650
|
+
requiredFeatureFamilies = [],
|
|
3651
|
+
excludedFeatureFamilies = []
|
|
3652
|
+
}) => {
|
|
3653
|
+
const cadenceProfile = resolveAiPocketCadenceProfile({
|
|
3654
|
+
trainRows: train,
|
|
3655
|
+
validationRows: validation,
|
|
3656
|
+
testRows: test,
|
|
3657
|
+
mode: cadenceMode,
|
|
3658
|
+
validationSplit,
|
|
3659
|
+
...explicitMinSupport != null ? { minSupport: explicitMinSupport } : {},
|
|
3660
|
+
...explicitMinEvents > 0 ? { minEvents: explicitMinEvents } : {},
|
|
3661
|
+
...explicitMinValidationSupport > 0 ? { minValidationSupport: explicitMinValidationSupport } : {},
|
|
3662
|
+
...explicitMinValidationEvents > 0 ? { minValidationEvents: explicitMinValidationEvents } : {},
|
|
3663
|
+
maxEventCountShare,
|
|
3664
|
+
explicitMaxEventCountShare: hasCliOption2("maxEventCountShare", "U")
|
|
3665
|
+
});
|
|
3666
|
+
let searchBar = null;
|
|
3667
|
+
let searchBarPhase = null;
|
|
3668
|
+
return searchAiPockets(train, {
|
|
3669
|
+
minSupport: cadenceProfile.minSupport,
|
|
3670
|
+
minProfitFactor,
|
|
3671
|
+
minTotalProfit,
|
|
3672
|
+
minWinRate,
|
|
3673
|
+
maxDepth,
|
|
3674
|
+
maxAtomicPredicates,
|
|
3675
|
+
maxCombinations,
|
|
3676
|
+
top,
|
|
3677
|
+
validationRows: validation,
|
|
3678
|
+
testRows: test,
|
|
3679
|
+
minValidationSupport: cadenceProfile.minValidationSupport,
|
|
3680
|
+
minEvents: cadenceProfile.minEvents,
|
|
3681
|
+
minValidationEvents: cadenceProfile.minValidationEvents,
|
|
3682
|
+
...maxBatch > 0 ? { maxBatch } : {},
|
|
3683
|
+
maxEventCountShare: cadenceProfile.maxEventCountShare,
|
|
3684
|
+
maxSymbolCountShare,
|
|
3685
|
+
objective,
|
|
3686
|
+
baselineRows: trainBaseline,
|
|
3687
|
+
validationBaselineRows: validationBaseline,
|
|
3688
|
+
testBaselineRows: testBaseline,
|
|
3689
|
+
allowRiskRegression,
|
|
3690
|
+
requireValidationEligibility,
|
|
3691
|
+
dedupeEquivalentSelections,
|
|
3692
|
+
requiredFeatureFamilies,
|
|
3693
|
+
excludedFeatureFamilies,
|
|
3694
|
+
cadenceProfile,
|
|
3695
|
+
progressInterval: 250,
|
|
3696
|
+
onProgress: (progress) => {
|
|
3697
|
+
if (searchBar && searchBarPhase !== progress.phase) {
|
|
3698
|
+
tickProgressBarTo(searchBar, searchBar.total, {
|
|
3699
|
+
status: import_chalk.default.gray("done")
|
|
3700
|
+
});
|
|
3701
|
+
searchBar = null;
|
|
3702
|
+
}
|
|
3703
|
+
if (!searchBar) {
|
|
3704
|
+
searchBarPhase = progress.phase;
|
|
3705
|
+
const phaseLabel = searchPhaseLabels[progress.phase].padEnd(8, " ");
|
|
3706
|
+
console.error(
|
|
3707
|
+
import_chalk.default.gray(
|
|
3708
|
+
`stage: ${label}/${searchPhaseLabels[progress.phase]} (${progress.total})`
|
|
3709
|
+
)
|
|
3710
|
+
);
|
|
3711
|
+
searchBar = new import_progress.default(
|
|
3712
|
+
`${phaseLabel} :current/:total [:bar] :percent :status`,
|
|
3713
|
+
{
|
|
3714
|
+
total: Math.max(progress.total, 1),
|
|
3715
|
+
width: 20,
|
|
3716
|
+
stream: process.stderr
|
|
3717
|
+
}
|
|
3718
|
+
);
|
|
3719
|
+
}
|
|
3720
|
+
tickProgressBarTo(searchBar, progress.current, {
|
|
3721
|
+
status: progress.truncated ? import_chalk.default.yellow("truncated") : "running"
|
|
3090
3722
|
});
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
import_chalk.default.gray(
|
|
3098
|
-
`stage: ${searchPhaseLabels[progress.phase]} (${progress.total})`
|
|
3099
|
-
)
|
|
3100
|
-
);
|
|
3101
|
-
searchBar = new import_progress.default(
|
|
3102
|
-
`${label} :current/:total [:bar] :percent :status`,
|
|
3103
|
-
{
|
|
3104
|
-
total: Math.max(progress.total, 1),
|
|
3105
|
-
width: 20,
|
|
3106
|
-
stream: process.stderr
|
|
3107
|
-
}
|
|
3108
|
-
);
|
|
3723
|
+
if (progress.done) {
|
|
3724
|
+
tickProgressBarTo(searchBar, searchBar.total, {
|
|
3725
|
+
status: progress.truncated ? import_chalk.default.yellow("truncated") : "done"
|
|
3726
|
+
});
|
|
3727
|
+
searchBar = null;
|
|
3728
|
+
}
|
|
3109
3729
|
}
|
|
3110
|
-
|
|
3111
|
-
|
|
3730
|
+
});
|
|
3731
|
+
};
|
|
3732
|
+
const search = runSearch({
|
|
3733
|
+
label: "full",
|
|
3734
|
+
train: trainRows,
|
|
3735
|
+
validation: validationRows,
|
|
3736
|
+
test: testRows,
|
|
3737
|
+
trainBaseline: baselineRows,
|
|
3738
|
+
validationBaseline: validationBaselineRows,
|
|
3739
|
+
testBaseline: testBaselineRows,
|
|
3740
|
+
...coverageMode === "auto" ? {
|
|
3741
|
+
excludedFeatureFamilies: [
|
|
3742
|
+
"cmc",
|
|
3743
|
+
"coinalyze"
|
|
3744
|
+
]
|
|
3745
|
+
} : {}
|
|
3746
|
+
});
|
|
3747
|
+
const coverageSearches = [];
|
|
3748
|
+
if (coverageMode === "auto") {
|
|
3749
|
+
for (const family of ["cmc", "coinalyze"]) {
|
|
3750
|
+
const cohortSplit = splitAiPocketCoverageRowsByTimestamp(
|
|
3751
|
+
directionRows,
|
|
3752
|
+
family,
|
|
3753
|
+
validationSplit,
|
|
3754
|
+
testSplit
|
|
3755
|
+
);
|
|
3756
|
+
const sealedCohortSplit = sealAiPocketTestPartition(
|
|
3757
|
+
cohortSplit,
|
|
3758
|
+
sealTest
|
|
3759
|
+
);
|
|
3760
|
+
const cohortTrainRows = resolveScopeRows(cohortSplit.trainRows, scope);
|
|
3761
|
+
const cohortValidationRows = resolveScopeRows(
|
|
3762
|
+
cohortSplit.validationRows,
|
|
3763
|
+
scope
|
|
3764
|
+
);
|
|
3765
|
+
const cohortTestRows = resolveScopeRows(
|
|
3766
|
+
sealedCohortSplit.searchTestRows,
|
|
3767
|
+
scope
|
|
3768
|
+
);
|
|
3769
|
+
const cohortSearch = runSearch({
|
|
3770
|
+
label: family,
|
|
3771
|
+
train: cohortTrainRows,
|
|
3772
|
+
validation: cohortValidationRows,
|
|
3773
|
+
test: cohortTestRows,
|
|
3774
|
+
trainBaseline: cohortSplit.trainRows.filter((row) => row.aiApproved),
|
|
3775
|
+
validationBaseline: cohortSplit.validationRows.filter(
|
|
3776
|
+
(row) => row.aiApproved
|
|
3777
|
+
),
|
|
3778
|
+
testBaseline: sealedCohortSplit.searchTestRows.filter(
|
|
3779
|
+
(row) => row.aiApproved
|
|
3780
|
+
),
|
|
3781
|
+
requiredFeatureFamilies: [family]
|
|
3782
|
+
});
|
|
3783
|
+
coverageSearches.push({
|
|
3784
|
+
family,
|
|
3785
|
+
coverage: summarizeAiPocketFeatureCoverage(
|
|
3786
|
+
sealedCohortSplit.discoveryRows,
|
|
3787
|
+
family
|
|
3788
|
+
),
|
|
3789
|
+
scopeRows: resolveScopeRows(
|
|
3790
|
+
sealedCohortSplit.discoveryRows.filter(
|
|
3791
|
+
(row) => row.featureCoverage?.[family] === true
|
|
3792
|
+
),
|
|
3793
|
+
scope
|
|
3794
|
+
).length,
|
|
3795
|
+
trainRows: cohortTrainRows.length,
|
|
3796
|
+
validationRows: cohortValidationRows.length,
|
|
3797
|
+
testRows: cohortTestRows.length,
|
|
3798
|
+
search: cohortSearch
|
|
3112
3799
|
});
|
|
3113
|
-
if (progress.done) {
|
|
3114
|
-
tickProgressBarTo(searchBar, searchBar.total, {
|
|
3115
|
-
status: progress.truncated ? import_chalk.default.yellow("truncated") : "done"
|
|
3116
|
-
});
|
|
3117
|
-
searchBar = null;
|
|
3118
|
-
}
|
|
3119
3800
|
}
|
|
3120
|
-
}
|
|
3801
|
+
}
|
|
3121
3802
|
const result = {
|
|
3122
3803
|
generatedAt,
|
|
3123
3804
|
run: {
|
|
@@ -3146,6 +3827,25 @@ var main = async () => {
|
|
|
3146
3827
|
includeGateContext,
|
|
3147
3828
|
featureProfile,
|
|
3148
3829
|
featurePolicy,
|
|
3830
|
+
coverageMode,
|
|
3831
|
+
cadenceMode,
|
|
3832
|
+
coverageSearches: coverageSearches.map(
|
|
3833
|
+
({
|
|
3834
|
+
family,
|
|
3835
|
+
coverage,
|
|
3836
|
+
scopeRows: scopeRows2,
|
|
3837
|
+
trainRows: trainRows2,
|
|
3838
|
+
validationRows: validationRows2,
|
|
3839
|
+
testRows: testRows2
|
|
3840
|
+
}) => ({
|
|
3841
|
+
family,
|
|
3842
|
+
coverage,
|
|
3843
|
+
scopeRows: scopeRows2,
|
|
3844
|
+
trainRows: trainRows2,
|
|
3845
|
+
validationRows: validationRows2,
|
|
3846
|
+
testRows: testRows2
|
|
3847
|
+
})
|
|
3848
|
+
),
|
|
3149
3849
|
featurePolicyAudit: Object.fromEntries(
|
|
3150
3850
|
[...excludedFeaturePaths.entries()].map(([classification, paths]) => [
|
|
3151
3851
|
classification,
|
|
@@ -3158,26 +3858,27 @@ var main = async () => {
|
|
|
3158
3858
|
objective,
|
|
3159
3859
|
validationSplit,
|
|
3160
3860
|
testSplit,
|
|
3161
|
-
|
|
3861
|
+
sealedTest: sealedFullSplit.evidence,
|
|
3862
|
+
minValidationSupport: search.stats.cadence.minValidationSupport,
|
|
3162
3863
|
reportPath,
|
|
3163
3864
|
search: {
|
|
3164
3865
|
maxDepth,
|
|
3165
|
-
minSupport,
|
|
3866
|
+
minSupport: search.stats.cadence.minSupport,
|
|
3166
3867
|
minProfitFactor,
|
|
3167
3868
|
minWinRate,
|
|
3168
3869
|
minTotalProfit,
|
|
3169
3870
|
maxAtomicPredicates,
|
|
3170
3871
|
maxCombinations,
|
|
3171
|
-
minEvents,
|
|
3172
|
-
minValidationEvents,
|
|
3872
|
+
minEvents: search.stats.cadence.minEvents,
|
|
3873
|
+
minValidationEvents: search.stats.cadence.minValidationEvents,
|
|
3173
3874
|
...maxBatch > 0 ? { maxBatch } : {},
|
|
3174
|
-
maxEventCountShare,
|
|
3875
|
+
maxEventCountShare: search.stats.cadence.maxEventCountShare,
|
|
3175
3876
|
maxSymbolCountShare,
|
|
3176
3877
|
allowRiskRegression,
|
|
3177
3878
|
requireValidationEligibility,
|
|
3879
|
+
cadence: search.stats.cadence,
|
|
3178
3880
|
validationSplit,
|
|
3179
3881
|
testSplit,
|
|
3180
|
-
minValidationSupport,
|
|
3181
3882
|
dedupeEquivalentSelections,
|
|
3182
3883
|
top
|
|
3183
3884
|
}
|
|
@@ -3187,6 +3888,7 @@ var main = async () => {
|
|
|
3187
3888
|
qualityThresholds: currentGateQualityThresholds
|
|
3188
3889
|
},
|
|
3189
3890
|
pocketSearch: search,
|
|
3891
|
+
coverageSearches,
|
|
3190
3892
|
errors
|
|
3191
3893
|
};
|
|
3192
3894
|
const markdownReport = buildAiPocketMarkdownReport(result);
|
|
@@ -3246,17 +3948,53 @@ var main = async () => {
|
|
|
3246
3948
|
],
|
|
3247
3949
|
["min_quality", import_chalk.default.magenta(String(minQuality))],
|
|
3248
3950
|
["max_depth", import_chalk.default.magenta(String(maxDepth))],
|
|
3249
|
-
["
|
|
3250
|
-
[
|
|
3251
|
-
|
|
3951
|
+
["cadence_mode", import_chalk.default.magenta(cadenceMode)],
|
|
3952
|
+
[
|
|
3953
|
+
"low_cadence",
|
|
3954
|
+
search.stats.cadence.lowCadence ? import_chalk.default.yellow("yes") : import_chalk.default.green("no")
|
|
3955
|
+
],
|
|
3956
|
+
[
|
|
3957
|
+
"sparse_sample",
|
|
3958
|
+
search.stats.cadence.sparseSample ? import_chalk.default.yellow("yes") : import_chalk.default.green("no")
|
|
3959
|
+
],
|
|
3960
|
+
[
|
|
3961
|
+
"adaptive_thresholds",
|
|
3962
|
+
search.stats.cadence.adaptiveThresholds ? import_chalk.default.yellow("on") : import_chalk.default.gray("off")
|
|
3963
|
+
],
|
|
3964
|
+
[
|
|
3965
|
+
"train_events",
|
|
3966
|
+
import_chalk.default.magenta(String(search.stats.cadence.trainEvents))
|
|
3967
|
+
],
|
|
3968
|
+
[
|
|
3969
|
+
"train_events_per_day",
|
|
3970
|
+
import_chalk.default.magenta(formatNumber2(search.stats.cadence.trainEventsPerDay))
|
|
3971
|
+
],
|
|
3972
|
+
["min_support", import_chalk.default.magenta(String(search.stats.cadence.minSupport))],
|
|
3973
|
+
["min_events", import_chalk.default.magenta(String(search.stats.cadence.minEvents))],
|
|
3974
|
+
[
|
|
3975
|
+
"min_validation_events",
|
|
3976
|
+
import_chalk.default.magenta(String(search.stats.cadence.minValidationEvents))
|
|
3977
|
+
],
|
|
3252
3978
|
["max_batch", import_chalk.default.magenta(maxBatch > 0 ? String(maxBatch) : "off")],
|
|
3253
|
-
[
|
|
3979
|
+
[
|
|
3980
|
+
"max_event_share",
|
|
3981
|
+
import_chalk.default.magenta(formatRatio(search.stats.cadence.maxEventCountShare))
|
|
3982
|
+
],
|
|
3254
3983
|
["max_symbol_share", import_chalk.default.magenta(formatRatio(maxSymbolCountShare))],
|
|
3255
3984
|
["max_atomic_predicates", import_chalk.default.magenta(String(maxAtomicPredicates))],
|
|
3256
3985
|
["max_combinations", import_chalk.default.magenta(String(maxCombinations))],
|
|
3257
3986
|
["validation_split", import_chalk.default.magenta(formatRatio(validationSplit))],
|
|
3258
3987
|
["test_split", import_chalk.default.magenta(formatRatio(testSplit))],
|
|
3259
|
-
[
|
|
3988
|
+
[
|
|
3989
|
+
"test_evidence",
|
|
3990
|
+
sealedFullSplit.evidence.sealed ? import_chalk.default.green(
|
|
3991
|
+
`sealed (${sealedFullSplit.evidence.rows} rows / ${sealedFullSplit.evidence.events} events)`
|
|
3992
|
+
) : import_chalk.default.yellow("open")
|
|
3993
|
+
],
|
|
3994
|
+
[
|
|
3995
|
+
"min_validation_support",
|
|
3996
|
+
import_chalk.default.magenta(String(search.stats.cadence.minValidationSupport))
|
|
3997
|
+
],
|
|
3260
3998
|
[
|
|
3261
3999
|
"dedupe_equivalent",
|
|
3262
4000
|
dedupeEquivalentSelections ? import_chalk.default.green("on") : import_chalk.default.gray("off")
|
|
@@ -3271,6 +4009,7 @@ var main = async () => {
|
|
|
3271
4009
|
],
|
|
3272
4010
|
["feature_profile", import_chalk.default.magenta(featureProfile)],
|
|
3273
4011
|
["feature_policy", import_chalk.default.magenta(featurePolicy)],
|
|
4012
|
+
["coverage_mode", import_chalk.default.magenta(coverageMode)],
|
|
3274
4013
|
[
|
|
3275
4014
|
"allow_risk_regression",
|
|
3276
4015
|
allowRiskRegression ? import_chalk.default.yellow("on") : import_chalk.default.green("off")
|
|
@@ -3346,6 +4085,14 @@ var main = async () => {
|
|
|
3346
4085
|
"feature_families",
|
|
3347
4086
|
import_chalk.default.cyan(search.stats.featureFamiliesUsed.join(", "))
|
|
3348
4087
|
],
|
|
4088
|
+
[
|
|
4089
|
+
"required_feature_families",
|
|
4090
|
+
import_chalk.default.cyan(search.stats.requiredFeatureFamilies.join(", ") || "none")
|
|
4091
|
+
],
|
|
4092
|
+
[
|
|
4093
|
+
"excluded_feature_families",
|
|
4094
|
+
import_chalk.default.cyan(search.stats.excludedFeatureFamilies.join(", ") || "none")
|
|
4095
|
+
],
|
|
3349
4096
|
[
|
|
3350
4097
|
"estimated_combinations",
|
|
3351
4098
|
import_chalk.default.cyan(String(search.stats.estimatedCombinations))
|
|
@@ -3356,6 +4103,27 @@ var main = async () => {
|
|
|
3356
4103
|
],
|
|
3357
4104
|
["validation_rows", import_chalk.default.cyan(String(search.stats.validationRows))],
|
|
3358
4105
|
["test_rows", import_chalk.default.cyan(String(search.stats.testRows))],
|
|
4106
|
+
["train_events", import_chalk.default.cyan(String(search.stats.cadence.trainEvents))],
|
|
4107
|
+
[
|
|
4108
|
+
"train_events_per_day",
|
|
4109
|
+
import_chalk.default.cyan(formatNumber2(search.stats.cadence.trainEventsPerDay))
|
|
4110
|
+
],
|
|
4111
|
+
[
|
|
4112
|
+
"effective_min_support",
|
|
4113
|
+
import_chalk.default.cyan(String(search.stats.cadence.minSupport))
|
|
4114
|
+
],
|
|
4115
|
+
[
|
|
4116
|
+
"effective_min_events",
|
|
4117
|
+
import_chalk.default.cyan(String(search.stats.cadence.minEvents))
|
|
4118
|
+
],
|
|
4119
|
+
[
|
|
4120
|
+
"effective_min_validation_support",
|
|
4121
|
+
import_chalk.default.cyan(String(search.stats.cadence.minValidationSupport))
|
|
4122
|
+
],
|
|
4123
|
+
[
|
|
4124
|
+
"effective_min_validation_events",
|
|
4125
|
+
import_chalk.default.cyan(String(search.stats.cadence.minValidationEvents))
|
|
4126
|
+
],
|
|
3359
4127
|
[
|
|
3360
4128
|
"duplicate_pockets_skipped",
|
|
3361
4129
|
import_chalk.default.cyan(String(search.stats.duplicatePocketsSkipped))
|
|
@@ -3382,16 +4150,20 @@ var main = async () => {
|
|
|
3382
4150
|
import_chalk.default.gray("OBJ_PNL"),
|
|
3383
4151
|
import_chalk.default.gray("MAX_DD"),
|
|
3384
4152
|
import_chalk.default.gray("VAL_N"),
|
|
4153
|
+
import_chalk.default.gray("VAL_EVENTS"),
|
|
3385
4154
|
import_chalk.default.gray("VAL_WR"),
|
|
3386
4155
|
import_chalk.default.gray("VAL_PF"),
|
|
3387
4156
|
import_chalk.default.gray("VAL_PNL"),
|
|
3388
4157
|
import_chalk.default.gray("TEST_N"),
|
|
4158
|
+
import_chalk.default.gray("TEST_EVENTS"),
|
|
3389
4159
|
import_chalk.default.gray("TEST_PF"),
|
|
3390
4160
|
import_chalk.default.gray("TEST_PNL"),
|
|
3391
4161
|
import_chalk.default.gray("TEST_OBJ"),
|
|
3392
4162
|
import_chalk.default.gray("TR/D"),
|
|
3393
4163
|
import_chalk.default.gray("LOSS_M"),
|
|
3394
4164
|
import_chalk.default.gray("SCORE"),
|
|
4165
|
+
import_chalk.default.gray("READINESS"),
|
|
4166
|
+
import_chalk.default.gray("REASONS"),
|
|
3395
4167
|
import_chalk.default.gray("POCKET")
|
|
3396
4168
|
],
|
|
3397
4169
|
buildPocketRows(search.positivePockets)
|
|
@@ -3412,21 +4184,155 @@ var main = async () => {
|
|
|
3412
4184
|
import_chalk.default.gray("OBJ_PNL"),
|
|
3413
4185
|
import_chalk.default.gray("MAX_DD"),
|
|
3414
4186
|
import_chalk.default.gray("VAL_N"),
|
|
4187
|
+
import_chalk.default.gray("VAL_EVENTS"),
|
|
3415
4188
|
import_chalk.default.gray("VAL_WR"),
|
|
3416
4189
|
import_chalk.default.gray("VAL_PF"),
|
|
3417
4190
|
import_chalk.default.gray("VAL_PNL"),
|
|
3418
4191
|
import_chalk.default.gray("TEST_N"),
|
|
4192
|
+
import_chalk.default.gray("TEST_EVENTS"),
|
|
3419
4193
|
import_chalk.default.gray("TEST_PF"),
|
|
3420
4194
|
import_chalk.default.gray("TEST_PNL"),
|
|
3421
4195
|
import_chalk.default.gray("TEST_OBJ"),
|
|
3422
4196
|
import_chalk.default.gray("TR/D"),
|
|
3423
4197
|
import_chalk.default.gray("LOSS_M"),
|
|
3424
4198
|
import_chalk.default.gray("SCORE"),
|
|
4199
|
+
import_chalk.default.gray("READINESS"),
|
|
4200
|
+
import_chalk.default.gray("REASONS"),
|
|
3425
4201
|
import_chalk.default.gray("POCKET")
|
|
3426
4202
|
],
|
|
3427
4203
|
buildPocketRows(search.negativePockets)
|
|
3428
4204
|
)
|
|
3429
4205
|
);
|
|
4206
|
+
for (const cohort of coverageSearches) {
|
|
4207
|
+
const title = cohort.family === "cmc" ? "CMC" : "COINALYZE";
|
|
4208
|
+
printSection(
|
|
4209
|
+
`${title} COVERAGE COHORT`,
|
|
4210
|
+
createTable(
|
|
4211
|
+
[import_chalk.default.gray("FIELD"), import_chalk.default.gray("VALUE")],
|
|
4212
|
+
[
|
|
4213
|
+
["coverage_rows", import_chalk.default.cyan(String(cohort.coverage.rows))],
|
|
4214
|
+
["coverage_ratio", import_chalk.default.cyan(formatRatio(cohort.coverage.rowRatio))],
|
|
4215
|
+
["coverage_events", import_chalk.default.cyan(String(cohort.coverage.events))],
|
|
4216
|
+
["event_ratio", import_chalk.default.cyan(formatRatio(cohort.coverage.eventRatio))],
|
|
4217
|
+
[
|
|
4218
|
+
"coverage_from",
|
|
4219
|
+
cohort.coverage.minTimestamp == null ? import_chalk.default.gray("n/a") : import_chalk.default.gray(
|
|
4220
|
+
new Date(cohort.coverage.minTimestamp).toISOString()
|
|
4221
|
+
)
|
|
4222
|
+
],
|
|
4223
|
+
[
|
|
4224
|
+
"coverage_to",
|
|
4225
|
+
cohort.coverage.maxTimestamp == null ? import_chalk.default.gray("n/a") : import_chalk.default.gray(
|
|
4226
|
+
new Date(cohort.coverage.maxTimestamp).toISOString()
|
|
4227
|
+
)
|
|
4228
|
+
],
|
|
4229
|
+
["scope_rows", import_chalk.default.cyan(String(cohort.scopeRows))],
|
|
4230
|
+
["train_rows", import_chalk.default.cyan(String(cohort.trainRows))],
|
|
4231
|
+
["validation_rows", import_chalk.default.cyan(String(cohort.validationRows))],
|
|
4232
|
+
["test_rows", import_chalk.default.cyan(String(cohort.testRows))],
|
|
4233
|
+
[
|
|
4234
|
+
"low_cadence",
|
|
4235
|
+
cohort.search.stats.cadence.lowCadence ? import_chalk.default.yellow("yes") : import_chalk.default.green("no")
|
|
4236
|
+
],
|
|
4237
|
+
[
|
|
4238
|
+
"sparse_sample",
|
|
4239
|
+
cohort.search.stats.cadence.sparseSample ? import_chalk.default.yellow("yes") : import_chalk.default.green("no")
|
|
4240
|
+
],
|
|
4241
|
+
[
|
|
4242
|
+
"adaptive_thresholds",
|
|
4243
|
+
cohort.search.stats.cadence.adaptiveThresholds ? import_chalk.default.yellow("on") : import_chalk.default.gray("off")
|
|
4244
|
+
],
|
|
4245
|
+
[
|
|
4246
|
+
"train_events",
|
|
4247
|
+
import_chalk.default.cyan(String(cohort.search.stats.cadence.trainEvents))
|
|
4248
|
+
],
|
|
4249
|
+
[
|
|
4250
|
+
"effective_min_support",
|
|
4251
|
+
import_chalk.default.cyan(String(cohort.search.stats.cadence.minSupport))
|
|
4252
|
+
],
|
|
4253
|
+
[
|
|
4254
|
+
"effective_min_events",
|
|
4255
|
+
import_chalk.default.cyan(String(cohort.search.stats.cadence.minEvents))
|
|
4256
|
+
]
|
|
4257
|
+
]
|
|
4258
|
+
)
|
|
4259
|
+
);
|
|
4260
|
+
printSection(
|
|
4261
|
+
`${title} TRAIN BASELINE`,
|
|
4262
|
+
createTable(
|
|
4263
|
+
[import_chalk.default.gray("METRIC"), import_chalk.default.gray("VALUE")],
|
|
4264
|
+
buildSummaryRows(cohort.search.baseline)
|
|
4265
|
+
)
|
|
4266
|
+
);
|
|
4267
|
+
printSection(
|
|
4268
|
+
`${title} TOP POSITIVE POCKETS`,
|
|
4269
|
+
createTable(
|
|
4270
|
+
[
|
|
4271
|
+
import_chalk.default.gray("#"),
|
|
4272
|
+
import_chalk.default.gray("N"),
|
|
4273
|
+
import_chalk.default.gray("EVENTS"),
|
|
4274
|
+
import_chalk.default.gray("MAX_B"),
|
|
4275
|
+
import_chalk.default.gray("SUP"),
|
|
4276
|
+
import_chalk.default.gray("WR"),
|
|
4277
|
+
import_chalk.default.gray("PF"),
|
|
4278
|
+
import_chalk.default.gray("PNL"),
|
|
4279
|
+
import_chalk.default.gray("OBJ_PNL"),
|
|
4280
|
+
import_chalk.default.gray("MAX_DD"),
|
|
4281
|
+
import_chalk.default.gray("VAL_N"),
|
|
4282
|
+
import_chalk.default.gray("VAL_EVENTS"),
|
|
4283
|
+
import_chalk.default.gray("VAL_WR"),
|
|
4284
|
+
import_chalk.default.gray("VAL_PF"),
|
|
4285
|
+
import_chalk.default.gray("VAL_PNL"),
|
|
4286
|
+
import_chalk.default.gray("TEST_N"),
|
|
4287
|
+
import_chalk.default.gray("TEST_EVENTS"),
|
|
4288
|
+
import_chalk.default.gray("TEST_PF"),
|
|
4289
|
+
import_chalk.default.gray("TEST_PNL"),
|
|
4290
|
+
import_chalk.default.gray("TEST_OBJ"),
|
|
4291
|
+
import_chalk.default.gray("TR/D"),
|
|
4292
|
+
import_chalk.default.gray("LOSS_M"),
|
|
4293
|
+
import_chalk.default.gray("SCORE"),
|
|
4294
|
+
import_chalk.default.gray("READINESS"),
|
|
4295
|
+
import_chalk.default.gray("REASONS"),
|
|
4296
|
+
import_chalk.default.gray("POCKET")
|
|
4297
|
+
],
|
|
4298
|
+
buildPocketRows(cohort.search.positivePockets)
|
|
4299
|
+
)
|
|
4300
|
+
);
|
|
4301
|
+
printSection(
|
|
4302
|
+
`${title} TOP LOSS POCKETS`,
|
|
4303
|
+
createTable(
|
|
4304
|
+
[
|
|
4305
|
+
import_chalk.default.gray("#"),
|
|
4306
|
+
import_chalk.default.gray("N"),
|
|
4307
|
+
import_chalk.default.gray("EVENTS"),
|
|
4308
|
+
import_chalk.default.gray("MAX_B"),
|
|
4309
|
+
import_chalk.default.gray("SUP"),
|
|
4310
|
+
import_chalk.default.gray("WR"),
|
|
4311
|
+
import_chalk.default.gray("PF"),
|
|
4312
|
+
import_chalk.default.gray("PNL"),
|
|
4313
|
+
import_chalk.default.gray("OBJ_PNL"),
|
|
4314
|
+
import_chalk.default.gray("MAX_DD"),
|
|
4315
|
+
import_chalk.default.gray("VAL_N"),
|
|
4316
|
+
import_chalk.default.gray("VAL_EVENTS"),
|
|
4317
|
+
import_chalk.default.gray("VAL_WR"),
|
|
4318
|
+
import_chalk.default.gray("VAL_PF"),
|
|
4319
|
+
import_chalk.default.gray("VAL_PNL"),
|
|
4320
|
+
import_chalk.default.gray("TEST_N"),
|
|
4321
|
+
import_chalk.default.gray("TEST_EVENTS"),
|
|
4322
|
+
import_chalk.default.gray("TEST_PF"),
|
|
4323
|
+
import_chalk.default.gray("TEST_PNL"),
|
|
4324
|
+
import_chalk.default.gray("TEST_OBJ"),
|
|
4325
|
+
import_chalk.default.gray("TR/D"),
|
|
4326
|
+
import_chalk.default.gray("LOSS_M"),
|
|
4327
|
+
import_chalk.default.gray("SCORE"),
|
|
4328
|
+
import_chalk.default.gray("READINESS"),
|
|
4329
|
+
import_chalk.default.gray("REASONS"),
|
|
4330
|
+
import_chalk.default.gray("POCKET")
|
|
4331
|
+
],
|
|
4332
|
+
buildPocketRows(cohort.search.negativePockets)
|
|
4333
|
+
)
|
|
4334
|
+
);
|
|
4335
|
+
}
|
|
3430
4336
|
if (errors.length) {
|
|
3431
4337
|
console.log(import_chalk.default.yellow("Errors:"));
|
|
3432
4338
|
errors.forEach((error) => console.log(import_chalk.default.yellow(`- ${error}`)));
|