@tradejs/cli 2.0.14 → 2.0.16
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 +2916 -978
- package/dist/lib/aiPocketSearch.js +493 -24
- package/dist/lib/aiTrainResearch.js +19 -2
- package/dist/lib/marketContextPrepare.js +85 -8
- package/dist/lib/researchAgent.js +3 -30
- package/dist/lib/runtimeDebugEvidence.js +76 -1
- package/dist/lib/runtimeEvidenceArtifacts.js +255 -0
- package/dist/lib/runtimeEvidenceSync.js +308 -0
- package/dist/lib/runtimeRedis.js +25 -0
- package/dist/lib/runtimeScorecard.js +442 -0
- package/dist/lib/runtimeTradeSync.js +9 -0
- package/dist/scripts/agentRun.js +16 -31
- package/dist/scripts/aiPocketSearch.js +717 -29
- package/dist/scripts/aiTrain.js +32 -2
- package/dist/scripts/backtest.js +83 -8
- package/dist/scripts/replay.js +92 -8
- package/dist/scripts/replayRunner.js +92 -8
- package/dist/scripts/replayRuntimeEvidence.js +68 -161
- package/dist/scripts/runtimeEvidence.js +316 -161
- package/dist/scripts/runtimeEvidenceSync.js +335 -0
- package/dist/scripts/runtimeParity.js +83 -8
- package/dist/scripts/runtimeScorecard.js +731 -0
- package/dist/scripts/signals.js +234 -142
- package/dist/scripts/signalsDaemon.js +234 -142
- package/dist/scripts/signalsSummary.js +9 -0
- package/dist/workers/testerWorker.js +2 -0
- package/package.json +11 -9
|
@@ -22,6 +22,7 @@ var aiPocketSearch_exports = {};
|
|
|
22
22
|
__export(aiPocketSearch_exports, {
|
|
23
23
|
buildAiPocketMarkdownReport: () => buildAiPocketMarkdownReport,
|
|
24
24
|
buildAiPocketPredicates: () => buildAiPocketPredicates,
|
|
25
|
+
classifyAiPocketFeaturePath: () => classifyAiPocketFeaturePath,
|
|
25
26
|
collectAiPocketFeatures: () => collectAiPocketFeatures,
|
|
26
27
|
searchAiPockets: () => searchAiPockets,
|
|
27
28
|
summarizeAiPocketRows: () => summarizeAiPocketRows
|
|
@@ -88,6 +89,115 @@ var normalizeFeaturePrimitive = (value) => {
|
|
|
88
89
|
return value;
|
|
89
90
|
};
|
|
90
91
|
var isOutcomePath = (segments) => segments.some((segment) => OUTCOME_SEGMENTS.has(segment.toLowerCase()));
|
|
92
|
+
var DATA_QUALITY_LEAVES = /* @__PURE__ */ new Set([
|
|
93
|
+
"age",
|
|
94
|
+
"agems",
|
|
95
|
+
"available",
|
|
96
|
+
"asofts",
|
|
97
|
+
"calcbars",
|
|
98
|
+
"coverage",
|
|
99
|
+
"latestindex",
|
|
100
|
+
"points",
|
|
101
|
+
"rowcount",
|
|
102
|
+
"rows",
|
|
103
|
+
"stale",
|
|
104
|
+
"timestamp",
|
|
105
|
+
"windowendts"
|
|
106
|
+
]);
|
|
107
|
+
var METADATA_LEAVES = /* @__PURE__ */ new Set([
|
|
108
|
+
"connector",
|
|
109
|
+
"exchange",
|
|
110
|
+
"fingerprint",
|
|
111
|
+
"interval",
|
|
112
|
+
"provider",
|
|
113
|
+
"source",
|
|
114
|
+
"strategy",
|
|
115
|
+
"symbol",
|
|
116
|
+
"targetsymbol",
|
|
117
|
+
"universe"
|
|
118
|
+
]);
|
|
119
|
+
var DERIVED_POLICY_FRAGMENTS = [
|
|
120
|
+
"approval",
|
|
121
|
+
"decisionhint",
|
|
122
|
+
"gatefeature",
|
|
123
|
+
"gatescore",
|
|
124
|
+
"hardblock",
|
|
125
|
+
"qualitycap",
|
|
126
|
+
"recoverycandidate",
|
|
127
|
+
"rejectreason",
|
|
128
|
+
"riskflag"
|
|
129
|
+
];
|
|
130
|
+
var RAW_NONSTATIONARY_LEAVES = /* @__PURE__ */ new Set([
|
|
131
|
+
"activeassets",
|
|
132
|
+
"activemarkets",
|
|
133
|
+
"close",
|
|
134
|
+
"current",
|
|
135
|
+
"currentprice",
|
|
136
|
+
"high",
|
|
137
|
+
"indexprice",
|
|
138
|
+
"liquidations",
|
|
139
|
+
"liquidationsusd",
|
|
140
|
+
"low",
|
|
141
|
+
"marketcap",
|
|
142
|
+
"marketcapusd",
|
|
143
|
+
"notional",
|
|
144
|
+
"open",
|
|
145
|
+
"openinterest",
|
|
146
|
+
"openinterestusd",
|
|
147
|
+
"price",
|
|
148
|
+
"quotevolume",
|
|
149
|
+
"turnover",
|
|
150
|
+
"turnoverusd",
|
|
151
|
+
"volume",
|
|
152
|
+
"volumeusd",
|
|
153
|
+
"vwap"
|
|
154
|
+
]);
|
|
155
|
+
var classifyAiPocketFeaturePath = (path) => {
|
|
156
|
+
const segments = (Array.isArray(path) ? path : path.split(".")).filter(
|
|
157
|
+
Boolean
|
|
158
|
+
);
|
|
159
|
+
const normalized = segments.map((segment) => segment.toLowerCase());
|
|
160
|
+
const leaf = normalized.at(-1) ?? "";
|
|
161
|
+
const normalizedPath = normalized.join(".");
|
|
162
|
+
const strategyGateFeaturesIndex = normalized.findIndex(
|
|
163
|
+
(segment) => segment !== "gatefeatures" && segment.endsWith("gatefeatures")
|
|
164
|
+
);
|
|
165
|
+
const strategyGateFeaturePath = normalized.slice(
|
|
166
|
+
strategyGateFeaturesIndex + 1
|
|
167
|
+
);
|
|
168
|
+
const isStrategySetupEvidence = normalized.includes("basecontext") && strategyGateFeaturesIndex >= 0 && (strategyGateFeaturePath.length === 0 || strategyGateFeaturePath.some(
|
|
169
|
+
(segment) => segment === "geometry" || segment === "path"
|
|
170
|
+
));
|
|
171
|
+
if (DATA_QUALITY_LEAVES.has(leaf) || leaf.endsWith("timestamp") || leaf.endsWith("agems") || normalized.some(
|
|
172
|
+
(segment) => ["availability", "dataquality", "freshness"].includes(segment)
|
|
173
|
+
)) {
|
|
174
|
+
return "data-quality";
|
|
175
|
+
}
|
|
176
|
+
if (METADATA_LEAVES.has(leaf) || leaf.endsWith("fingerprint") || normalized.some((segment) => segment === "metadata")) {
|
|
177
|
+
return "metadata";
|
|
178
|
+
}
|
|
179
|
+
if (DERIVED_POLICY_FRAGMENTS.some(
|
|
180
|
+
(fragment) => !(fragment === "gatefeature" && isStrategySetupEvidence) && normalizedPath.includes(fragment)
|
|
181
|
+
)) {
|
|
182
|
+
return "derived-policy";
|
|
183
|
+
}
|
|
184
|
+
const isDerivedFeature = normalized[0] === "derived";
|
|
185
|
+
const isNormalizedLeaf = /(alpha|bps|change|delta|direction|distance|pct|percentile|ratio|regime|return|share|slope|trend|zscore)/.test(
|
|
186
|
+
leaf
|
|
187
|
+
);
|
|
188
|
+
const isRawMovingAverage = /^(?:ema|ma|sma|wma)(?:fast|slow|\d+)$/.test(leaf);
|
|
189
|
+
const isRawAbsolutePositioning = /^(?:liq(?:long|net|short|total)|oi|openinterest(?:long|short)?)$/.test(
|
|
190
|
+
leaf
|
|
191
|
+
);
|
|
192
|
+
const isRawAbsoluteMeasure = /(?:liquidations?|marketcap|notional|openinterest|price|turnover|volume)$/.test(
|
|
193
|
+
leaf
|
|
194
|
+
);
|
|
195
|
+
const isRawStructureLevel = leaf === "level" && normalized.includes("structure");
|
|
196
|
+
if (!isDerivedFeature && !isNormalizedLeaf && (RAW_NONSTATIONARY_LEAVES.has(leaf) || isRawMovingAverage || isRawAbsolutePositioning || isRawAbsoluteMeasure || isRawStructureLevel)) {
|
|
197
|
+
return "raw-nonstationary";
|
|
198
|
+
}
|
|
199
|
+
return "eligible";
|
|
200
|
+
};
|
|
91
201
|
var isFeaturePathPrefix = (segments, prefix) => prefix.every((segment, index) => segments[index] === segment);
|
|
92
202
|
var isCompactFeaturePathSkipped = (segments) => {
|
|
93
203
|
if (!segments.length) {
|
|
@@ -349,7 +459,9 @@ var collectAiPocketFeatures = ({
|
|
|
349
459
|
gateContext,
|
|
350
460
|
includeSymbol = false,
|
|
351
461
|
includeGateContext = false,
|
|
352
|
-
featureProfile = "all"
|
|
462
|
+
featureProfile = "all",
|
|
463
|
+
featurePolicy = "all",
|
|
464
|
+
onFeatureExcluded
|
|
353
465
|
}) => {
|
|
354
466
|
const features = {};
|
|
355
467
|
const signal = payload.signal ?? {};
|
|
@@ -369,8 +481,35 @@ var collectAiPocketFeatures = ({
|
|
|
369
481
|
value: source,
|
|
370
482
|
segments: [],
|
|
371
483
|
maxDepth: 8,
|
|
372
|
-
shouldSkipPath:
|
|
484
|
+
shouldSkipPath: (segments) => {
|
|
485
|
+
if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
if (featurePolicy !== "causal-stationary") {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const classification = classifyAiPocketFeaturePath(segments);
|
|
492
|
+
if (classification === "eligible") {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
onFeatureExcluded?.({
|
|
496
|
+
path: segments.join("."),
|
|
497
|
+
classification
|
|
498
|
+
});
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
373
501
|
});
|
|
502
|
+
if (featurePolicy === "causal-stationary") {
|
|
503
|
+
for (const [key, value] of Object.entries(features)) {
|
|
504
|
+
if (value === null) {
|
|
505
|
+
onFeatureExcluded?.({
|
|
506
|
+
path: key,
|
|
507
|
+
classification: "data-quality"
|
|
508
|
+
});
|
|
509
|
+
delete features[key];
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
374
513
|
addSignalRiskDistanceFeatures({ features, signal });
|
|
375
514
|
addDirectionalDerivedFeatures(features);
|
|
376
515
|
return features;
|
|
@@ -423,6 +562,7 @@ var createSummaryAccumulator = () => ({
|
|
|
423
562
|
directionCounts: /* @__PURE__ */ new Map(),
|
|
424
563
|
symbolCounts: /* @__PURE__ */ new Map(),
|
|
425
564
|
monthProfits: /* @__PURE__ */ new Map(),
|
|
565
|
+
eventStats: /* @__PURE__ */ new Map(),
|
|
426
566
|
equityPoints: []
|
|
427
567
|
});
|
|
428
568
|
var addSummaryRow = (accumulator, row) => {
|
|
@@ -448,6 +588,14 @@ var addSummaryRow = (accumulator, row) => {
|
|
|
448
588
|
symbolBucket.totalProfit += profit;
|
|
449
589
|
accumulator.symbolCounts.set(symbol, symbolBucket);
|
|
450
590
|
const timestamp = typeof row.timestamp === "number" && Number.isFinite(row.timestamp) ? row.timestamp : Number.POSITIVE_INFINITY;
|
|
591
|
+
const eventKey = Number.isFinite(timestamp) ? String(timestamp) : `UNKNOWN:${accumulator.support}`;
|
|
592
|
+
const event = accumulator.eventStats.get(eventKey) ?? {
|
|
593
|
+
count: 0,
|
|
594
|
+
totalProfit: 0
|
|
595
|
+
};
|
|
596
|
+
event.count += 1;
|
|
597
|
+
event.totalProfit += profit;
|
|
598
|
+
accumulator.eventStats.set(eventKey, event);
|
|
451
599
|
const month = Number.isFinite(timestamp) && timestamp !== Number.POSITIVE_INFINITY ? new Date(timestamp).toISOString().slice(0, 7) : "UNKNOWN";
|
|
452
600
|
accumulator.monthProfits.set(
|
|
453
601
|
month,
|
|
@@ -461,6 +609,15 @@ var emptyAiPocketSummary = ({
|
|
|
461
609
|
}) => ({
|
|
462
610
|
support: 0,
|
|
463
611
|
supportRatio,
|
|
612
|
+
events: 0,
|
|
613
|
+
eventBalancedProfit: 0,
|
|
614
|
+
tradesPerEvent: null,
|
|
615
|
+
p95Batch: 0,
|
|
616
|
+
maxBatch: 0,
|
|
617
|
+
topEventCountShare: null,
|
|
618
|
+
topEventProfitShare: null,
|
|
619
|
+
topSymbolCountShare: null,
|
|
620
|
+
topSymbolProfitShare: null,
|
|
464
621
|
totalProfit: 0,
|
|
465
622
|
grossProfit: 0,
|
|
466
623
|
grossLoss: 0,
|
|
@@ -532,9 +689,42 @@ var finalizeAiPocketSummary = ({
|
|
|
532
689
|
const worstMonth = [...accumulator.monthProfits.entries()].sort(
|
|
533
690
|
(left, right) => left[1] - right[1]
|
|
534
691
|
)[0] ?? null;
|
|
692
|
+
const eventStats = [...accumulator.eventStats.values()];
|
|
693
|
+
const events = eventStats.length;
|
|
694
|
+
const batchSizes = eventStats.map((event) => event.count).sort((left, right) => left - right);
|
|
695
|
+
const p95Batch = batchSizes[Math.max(0, Math.ceil(batchSizes.length * 0.95) - 1)] ?? 0;
|
|
696
|
+
const maxBatch = batchSizes.at(-1) ?? 0;
|
|
697
|
+
const absoluteEventProfit = eventStats.reduce(
|
|
698
|
+
(sum, event) => sum + Math.abs(event.totalProfit),
|
|
699
|
+
0
|
|
700
|
+
);
|
|
701
|
+
const absoluteSymbolProfit = [...accumulator.symbolCounts.values()].reduce(
|
|
702
|
+
(sum, symbol) => sum + Math.abs(symbol.totalProfit),
|
|
703
|
+
0
|
|
704
|
+
);
|
|
535
705
|
return {
|
|
536
706
|
support,
|
|
537
707
|
supportRatio,
|
|
708
|
+
events,
|
|
709
|
+
eventBalancedProfit: eventStats.reduce(
|
|
710
|
+
(sum, event) => sum + event.totalProfit / event.count,
|
|
711
|
+
0
|
|
712
|
+
),
|
|
713
|
+
tradesPerEvent: events > 0 ? support / events : null,
|
|
714
|
+
p95Batch,
|
|
715
|
+
maxBatch,
|
|
716
|
+
topEventCountShare: support > 0 ? maxBatch / support : null,
|
|
717
|
+
topEventProfitShare: absoluteEventProfit > 0 ? Math.max(...eventStats.map((event) => Math.abs(event.totalProfit))) / absoluteEventProfit : null,
|
|
718
|
+
topSymbolCountShare: support > 0 ? Math.max(
|
|
719
|
+
...[...accumulator.symbolCounts.values()].map(
|
|
720
|
+
(symbol) => symbol.count
|
|
721
|
+
)
|
|
722
|
+
) / support : null,
|
|
723
|
+
topSymbolProfitShare: absoluteSymbolProfit > 0 ? Math.max(
|
|
724
|
+
...[...accumulator.symbolCounts.values()].map(
|
|
725
|
+
(symbol) => Math.abs(symbol.totalProfit)
|
|
726
|
+
)
|
|
727
|
+
) / absoluteSymbolProfit : null,
|
|
538
728
|
totalProfit,
|
|
539
729
|
grossProfit,
|
|
540
730
|
grossLoss,
|
|
@@ -840,27 +1030,82 @@ var buildAiPocketPredicates = (rows, options = {}) => buildAiPocketPredicateResu
|
|
|
840
1030
|
var scorePositivePocket = (summary) => {
|
|
841
1031
|
const profitFactor = summary.profitFactor ?? (summary.grossLoss === 0 ? 8 : 0);
|
|
842
1032
|
const winRate = summary.winRate ?? 0;
|
|
843
|
-
return summary.
|
|
1033
|
+
return summary.eventBalancedProfit - summary.maxDrawdown * 0.6 + Math.min(profitFactor, 8) * 12 + winRate * 30 + Math.log10(summary.events + 1) * 6;
|
|
844
1034
|
};
|
|
845
1035
|
var scoreNegativePocket = (summary) => -summary.totalProfit + summary.maxDrawdown * 0.4 + summary.grossLoss * 0.2 + summary.maxConsecutiveLosses * 3;
|
|
846
1036
|
var comparePositivePockets = (left, right) => (right.validationScore ?? right.score) - (left.validationScore ?? left.score) || right.score - left.score || (right.validationSummary?.totalProfit ?? right.summary.totalProfit) - (left.validationSummary?.totalProfit ?? left.summary.totalProfit) || right.summary.totalProfit - left.summary.totalProfit || (right.summary.profitFactor ?? 999) - (left.summary.profitFactor ?? 999) || right.summary.support - left.summary.support;
|
|
847
1037
|
var compareNegativePockets = (left, right) => (right.validationScore ?? right.score) - (left.validationScore ?? left.score) || right.score - left.score || (left.validationSummary?.totalProfit ?? left.summary.totalProfit) - (right.validationSummary?.totalProfit ?? right.summary.totalProfit) || left.summary.totalProfit - right.summary.totalProfit || right.summary.grossLoss - left.summary.grossLoss || right.summary.support - left.summary.support;
|
|
848
|
-
var
|
|
1038
|
+
var mergeDistinctRows = (left, right) => {
|
|
1039
|
+
const seenRows = /* @__PURE__ */ new Set();
|
|
1040
|
+
const seenSignalIds = /* @__PURE__ */ new Set();
|
|
1041
|
+
return [...left, ...right].filter((row) => {
|
|
1042
|
+
if (seenRows.has(row)) {
|
|
1043
|
+
return false;
|
|
1044
|
+
}
|
|
1045
|
+
seenRows.add(row);
|
|
1046
|
+
const signalId = typeof row.signalId === "string" && row.signalId.trim() ? row.signalId : null;
|
|
1047
|
+
if (signalId == null) {
|
|
1048
|
+
return true;
|
|
1049
|
+
}
|
|
1050
|
+
if (seenSignalIds.has(signalId)) {
|
|
1051
|
+
return false;
|
|
1052
|
+
}
|
|
1053
|
+
seenSignalIds.add(signalId);
|
|
1054
|
+
return true;
|
|
1055
|
+
});
|
|
1056
|
+
};
|
|
1057
|
+
var resolveObjectiveRows = ({
|
|
1058
|
+
objective,
|
|
1059
|
+
selectedRows,
|
|
1060
|
+
baselineRows
|
|
1061
|
+
}) => objective === "add-to-gate" ? mergeDistinctRows(baselineRows, selectedRows) : selectedRows;
|
|
1062
|
+
var effectiveProfitFactor = (summary) => summary.profitFactor ?? (summary.grossLoss === 0 && summary.totalProfit >= 0 ? Number.POSITIVE_INFINITY : 0);
|
|
1063
|
+
var doesNotRegressRisk = (candidate, baseline) => candidate.totalProfit >= baseline.totalProfit - 1e-9 && effectiveProfitFactor(candidate) >= effectiveProfitFactor(baseline) && candidate.maxDrawdown <= baseline.maxDrawdown + 1e-9 && candidate.maxConsecutiveLosses <= baseline.maxConsecutiveLosses && candidate.losingMonths <= baseline.losingMonths;
|
|
1064
|
+
var createPocketResult = (rows, predicates, mask, validationRows, testRows, objective, baselineRows, validationBaselineRows, testBaselineRows, objectiveBaseline, validationObjectiveBaseline, testObjectiveBaseline) => {
|
|
849
1065
|
const publicPredicates = predicates.map(toPublicPredicate);
|
|
850
1066
|
const summary = summarizeMask(rows, mask);
|
|
1067
|
+
const selectedRows = rows.filter((_, index) => mask[index] === 1);
|
|
1068
|
+
const objectiveRows = resolveObjectiveRows({
|
|
1069
|
+
objective,
|
|
1070
|
+
selectedRows,
|
|
1071
|
+
baselineRows
|
|
1072
|
+
});
|
|
1073
|
+
const objectiveSummary = objective === "add-to-gate" ? summarizeAiPocketRows(objectiveRows) : summary;
|
|
851
1074
|
const validationMask = validationRows.length ? buildPredicateListMask(validationRows, publicPredicates).mask : null;
|
|
852
1075
|
const validationSummary = validationMask == null ? void 0 : summarizeMask(validationRows, validationMask);
|
|
1076
|
+
const validationSelectedRows = validationMask == null ? [] : validationRows.filter((_, index) => validationMask[index] === 1);
|
|
1077
|
+
const validationObjectiveRows = resolveObjectiveRows({
|
|
1078
|
+
objective,
|
|
1079
|
+
selectedRows: validationSelectedRows,
|
|
1080
|
+
baselineRows: validationBaselineRows
|
|
1081
|
+
});
|
|
1082
|
+
const validationObjectiveSummary = validationRows.length ? objective === "add-to-gate" ? summarizeAiPocketRows(validationObjectiveRows) : validationSummary : void 0;
|
|
1083
|
+
const testMask = testRows.length ? buildPredicateListMask(testRows, publicPredicates).mask : null;
|
|
1084
|
+
const testSummary = testMask == null ? void 0 : summarizeMask(testRows, testMask);
|
|
1085
|
+
const testSelectedRows = testMask == null ? [] : testRows.filter((_, index) => testMask[index] === 1);
|
|
1086
|
+
const testObjectiveRows = resolveObjectiveRows({
|
|
1087
|
+
objective,
|
|
1088
|
+
selectedRows: testSelectedRows,
|
|
1089
|
+
baselineRows: testBaselineRows
|
|
1090
|
+
});
|
|
1091
|
+
const testObjectiveSummary = testRows.length ? objective === "add-to-gate" ? summarizeAiPocketRows(testObjectiveRows) : testSummary : void 0;
|
|
853
1092
|
const condition = publicPredicates.map((predicate) => predicate.label).join(" AND ");
|
|
854
|
-
const validationScore = validationSummary == null ? void 0 : validationSummary.support > 0 ? scorePositivePocket(
|
|
1093
|
+
const validationScore = validationSummary == null || validationObjectiveSummary == null ? void 0 : validationSummary.support > 0 ? scorePositivePocket(validationObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(validationObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
1094
|
+
const testScore = testSummary == null || testObjectiveSummary == null ? void 0 : testSummary.support > 0 ? scorePositivePocket(testObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(testObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
855
1095
|
return {
|
|
856
1096
|
id: publicPredicates.map((predicate) => predicate.id).join("&&"),
|
|
857
1097
|
depth: publicPredicates.length,
|
|
858
1098
|
predicates: publicPredicates,
|
|
859
1099
|
condition,
|
|
860
1100
|
summary,
|
|
1101
|
+
...objective === "standalone" ? {} : { objectiveSummary },
|
|
861
1102
|
...validationSummary ? { validationSummary } : {},
|
|
1103
|
+
...testSummary ? { testSummary } : {},
|
|
1104
|
+
...objective !== "standalone" && validationObjectiveSummary ? { validationObjectiveSummary } : {},
|
|
1105
|
+
...objective !== "standalone" && testObjectiveSummary ? { testObjectiveSummary } : {},
|
|
862
1106
|
...validationScore != null ? { validationScore } : {},
|
|
863
|
-
|
|
1107
|
+
...testScore != null ? { testScore } : {},
|
|
1108
|
+
score: scorePositivePocket(objectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(objectiveBaseline))
|
|
864
1109
|
};
|
|
865
1110
|
};
|
|
866
1111
|
var hashMask = (mask) => {
|
|
@@ -891,6 +1136,83 @@ var estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
|
|
|
891
1136
|
}
|
|
892
1137
|
return Math.min(Math.trunc(total), maxCombinations);
|
|
893
1138
|
};
|
|
1139
|
+
var classifyFeatureFamily = (featureKey) => {
|
|
1140
|
+
const key = featureKey.toLowerCase();
|
|
1141
|
+
if (/(setup|liquidity|doubletap|trendline|pivot|swing|zone)/.test(key)) {
|
|
1142
|
+
return "strategy-structure";
|
|
1143
|
+
}
|
|
1144
|
+
if (/(structure|breakout|rejection|range|level)/.test(key)) {
|
|
1145
|
+
return "market-structure";
|
|
1146
|
+
}
|
|
1147
|
+
if (/(participation|volume|turnover|obv|effort)/.test(key)) {
|
|
1148
|
+
return "participation";
|
|
1149
|
+
}
|
|
1150
|
+
if (/(relative|benchmark|cmc|breadth|targetvs|btc|eth)/.test(key)) {
|
|
1151
|
+
return "relative-market";
|
|
1152
|
+
}
|
|
1153
|
+
if (/(derivative|funding|openinterest|liquidation|longshort)/.test(key)) {
|
|
1154
|
+
return "derivatives";
|
|
1155
|
+
}
|
|
1156
|
+
if (/(risk|stop|takeprofit|execution|spread|slippage)/.test(key)) {
|
|
1157
|
+
return "execution-risk";
|
|
1158
|
+
}
|
|
1159
|
+
if (/(regime|momentum|trend|volatility|atr|macd|rsi|ma)/.test(key)) {
|
|
1160
|
+
return "regime-indicators";
|
|
1161
|
+
}
|
|
1162
|
+
return "other";
|
|
1163
|
+
};
|
|
1164
|
+
var diversifyPredicatePool = (predicates, maximum) => {
|
|
1165
|
+
const byFamily = /* @__PURE__ */ new Map();
|
|
1166
|
+
const featureCounts = /* @__PURE__ */ new Map();
|
|
1167
|
+
for (const predicate of predicates) {
|
|
1168
|
+
const family = classifyFeatureFamily(predicate.featureKey);
|
|
1169
|
+
const familyPredicates = byFamily.get(family) ?? [];
|
|
1170
|
+
familyPredicates.push(predicate);
|
|
1171
|
+
byFamily.set(family, familyPredicates);
|
|
1172
|
+
}
|
|
1173
|
+
const selected = [];
|
|
1174
|
+
const selectedIds = /* @__PURE__ */ new Set();
|
|
1175
|
+
while (selected.length < maximum) {
|
|
1176
|
+
let added = false;
|
|
1177
|
+
for (const familyPredicates of byFamily.values()) {
|
|
1178
|
+
while (familyPredicates.length) {
|
|
1179
|
+
const predicate = familyPredicates.shift();
|
|
1180
|
+
if (selectedIds.has(predicate.id) || (featureCounts.get(predicate.featureKey) ?? 0) >= 4) {
|
|
1181
|
+
continue;
|
|
1182
|
+
}
|
|
1183
|
+
selected.push(predicate);
|
|
1184
|
+
selectedIds.add(predicate.id);
|
|
1185
|
+
featureCounts.set(
|
|
1186
|
+
predicate.featureKey,
|
|
1187
|
+
(featureCounts.get(predicate.featureKey) ?? 0) + 1
|
|
1188
|
+
);
|
|
1189
|
+
added = true;
|
|
1190
|
+
break;
|
|
1191
|
+
}
|
|
1192
|
+
if (selected.length >= maximum) {
|
|
1193
|
+
break;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
if (!added) {
|
|
1197
|
+
break;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return selected;
|
|
1201
|
+
};
|
|
1202
|
+
var canCombinePredicate = (chosen, candidate) => {
|
|
1203
|
+
const sameFeature = chosen.filter(
|
|
1204
|
+
(predicate) => predicate.featureKey === candidate.featureKey
|
|
1205
|
+
);
|
|
1206
|
+
if (!sameFeature.length) {
|
|
1207
|
+
return true;
|
|
1208
|
+
}
|
|
1209
|
+
if (sameFeature.length !== 1 || sameFeature[0].kind !== "numeric" || candidate.kind !== "numeric" || sameFeature[0].op === candidate.op) {
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
const lower = candidate.op === ">=" ? candidate.threshold : sameFeature[0].threshold;
|
|
1213
|
+
const upper = candidate.op === "<=" ? candidate.threshold : sameFeature[0].threshold;
|
|
1214
|
+
return lower <= upper;
|
|
1215
|
+
};
|
|
894
1216
|
var searchAiPockets = (rows, options = {}) => {
|
|
895
1217
|
const minSupport = Math.max(1, Math.trunc(options.minSupport ?? 20));
|
|
896
1218
|
const minProfitFactor = Math.max(0, options.minProfitFactor ?? 1.2);
|
|
@@ -907,10 +1229,36 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
907
1229
|
);
|
|
908
1230
|
const top = Math.max(1, Math.trunc(options.top ?? 50));
|
|
909
1231
|
const validationRows = options.validationRows ?? [];
|
|
1232
|
+
const testRows = options.testRows ?? [];
|
|
910
1233
|
const minValidationSupport = Math.max(
|
|
911
1234
|
0,
|
|
912
1235
|
Math.trunc(options.minValidationSupport ?? 0)
|
|
913
1236
|
);
|
|
1237
|
+
const minEvents = Math.max(1, Math.trunc(options.minEvents ?? 1));
|
|
1238
|
+
const minValidationEvents = Math.max(
|
|
1239
|
+
0,
|
|
1240
|
+
Math.trunc(options.minValidationEvents ?? 0)
|
|
1241
|
+
);
|
|
1242
|
+
const maxBatch = Math.max(1, options.maxBatch ?? Number.POSITIVE_INFINITY);
|
|
1243
|
+
const maxEventCountShare = Math.max(
|
|
1244
|
+
0,
|
|
1245
|
+
Math.min(1, options.maxEventCountShare ?? 1)
|
|
1246
|
+
);
|
|
1247
|
+
const maxSymbolCountShare = Math.max(
|
|
1248
|
+
0,
|
|
1249
|
+
Math.min(1, options.maxSymbolCountShare ?? 1)
|
|
1250
|
+
);
|
|
1251
|
+
const objective = options.objective ?? "standalone";
|
|
1252
|
+
const baselineRows = options.baselineRows ?? (objective === "filter-gate" ? rows : []);
|
|
1253
|
+
const validationBaselineRows = options.validationBaselineRows ?? (objective === "filter-gate" ? validationRows : []);
|
|
1254
|
+
const testBaselineRows = options.testBaselineRows ?? (objective === "filter-gate" ? testRows : []);
|
|
1255
|
+
const objectiveBaseline = summarizeAiPocketRows(baselineRows);
|
|
1256
|
+
const validationObjectiveBaseline = summarizeAiPocketRows(
|
|
1257
|
+
validationBaselineRows
|
|
1258
|
+
);
|
|
1259
|
+
const testObjectiveBaseline = summarizeAiPocketRows(testBaselineRows);
|
|
1260
|
+
const allowRiskRegression = options.allowRiskRegression === true;
|
|
1261
|
+
const requireValidationEligibility = options.requireValidationEligibility === true;
|
|
914
1262
|
const dedupeEquivalentSelections = options.dedupeEquivalentSelections !== false;
|
|
915
1263
|
const progressInterval = Math.max(
|
|
916
1264
|
1,
|
|
@@ -953,11 +1301,13 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
953
1301
|
const supportPool = [...scoredPredicates].sort((left, right) => right.support - left.support).slice(0, Math.ceil(maxAtomicPredicates * 0.2));
|
|
954
1302
|
const predicatePoolById = /* @__PURE__ */ new Map();
|
|
955
1303
|
[...predicatePool, ...negativePool, ...supportPool].forEach((predicate) => {
|
|
956
|
-
|
|
957
|
-
predicatePoolById.set(predicate.id, predicate);
|
|
958
|
-
}
|
|
1304
|
+
predicatePoolById.set(predicate.id, predicate);
|
|
959
1305
|
});
|
|
960
|
-
const
|
|
1306
|
+
const diversifiedPredicates = diversifyPredicatePool(
|
|
1307
|
+
[...predicatePoolById.values()],
|
|
1308
|
+
maxAtomicPredicates
|
|
1309
|
+
);
|
|
1310
|
+
const selectedPredicatePool = diversifiedPredicates.map(
|
|
961
1311
|
(predicate) => {
|
|
962
1312
|
const { mask, support } = buildMask(rows, predicate);
|
|
963
1313
|
return {
|
|
@@ -1001,14 +1351,30 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1001
1351
|
rows,
|
|
1002
1352
|
pocketPredicates,
|
|
1003
1353
|
mask,
|
|
1004
|
-
validationRows
|
|
1354
|
+
validationRows,
|
|
1355
|
+
testRows,
|
|
1356
|
+
objective,
|
|
1357
|
+
baselineRows,
|
|
1358
|
+
validationBaselineRows,
|
|
1359
|
+
testBaselineRows,
|
|
1360
|
+
objectiveBaseline,
|
|
1361
|
+
validationObjectiveBaseline,
|
|
1362
|
+
testObjectiveBaseline
|
|
1005
1363
|
);
|
|
1006
1364
|
const { summary } = pocket;
|
|
1007
|
-
const
|
|
1008
|
-
const
|
|
1365
|
+
const scoredSummary = pocket.objectiveSummary ?? summary;
|
|
1366
|
+
const profitFactor = scoredSummary.profitFactor ?? (scoredSummary.grossLoss === 0 && scoredSummary.totalProfit > 0 ? Number.POSITIVE_INFINITY : 0);
|
|
1367
|
+
const winRate = scoredSummary.winRate ?? 0;
|
|
1009
1368
|
const validationSupport = pocket.validationSummary?.support ?? 0;
|
|
1010
|
-
const validationEligible = !validationRows.length || validationSupport >= minValidationSupport
|
|
1011
|
-
|
|
1369
|
+
const validationEligible = !validationRows.length || validationSupport >= minValidationSupport && (pocket.validationSummary?.events ?? 0) >= minValidationEvents && (pocket.validationSummary?.maxBatch ?? 0) <= maxBatch && (pocket.validationSummary?.topEventCountShare ?? 0) <= maxEventCountShare && (pocket.validationSummary?.topSymbolCountShare ?? 0) <= maxSymbolCountShare && (!requireValidationEligibility || (pocket.validationObjectiveSummary ?? pocket.validationSummary).totalProfit >= minTotalProfit && effectiveProfitFactor(
|
|
1370
|
+
pocket.validationObjectiveSummary ?? pocket.validationSummary
|
|
1371
|
+
) >= minProfitFactor && ((pocket.validationObjectiveSummary ?? pocket.validationSummary).winRate ?? 0) >= minWinRate);
|
|
1372
|
+
const concentrationEligible = summary.events >= minEvents && summary.maxBatch <= maxBatch && (summary.topEventCountShare ?? 0) <= maxEventCountShare && (summary.topSymbolCountShare ?? 0) <= maxSymbolCountShare;
|
|
1373
|
+
const riskEligible = objective === "standalone" || allowRiskRegression || (!objectiveBaseline.support || doesNotRegressRisk(scoredSummary, objectiveBaseline)) && (!validationRows.length || !validationObjectiveBaseline.support || doesNotRegressRisk(
|
|
1374
|
+
pocket.validationObjectiveSummary ?? pocket.validationSummary,
|
|
1375
|
+
validationObjectiveBaseline
|
|
1376
|
+
));
|
|
1377
|
+
if (summary.support >= minSupport && scoredSummary.totalProfit >= minTotalProfit && profitFactor >= minProfitFactor && winRate >= minWinRate && validationEligible && concentrationEligible && riskEligible) {
|
|
1012
1378
|
const selectionKey = `${summary.support}:${hashMask(mask)}`;
|
|
1013
1379
|
const mapKey = dedupeEquivalentSelections ? selectionKey : pocket.id;
|
|
1014
1380
|
const existing = dedupeEquivalentSelections ? positiveSelectionKeys.get(mapKey) : positivePockets.get(mapKey);
|
|
@@ -1045,8 +1411,7 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1045
1411
|
const visit = ({
|
|
1046
1412
|
startIndex,
|
|
1047
1413
|
chosen,
|
|
1048
|
-
mask
|
|
1049
|
-
usedFeatureKeys
|
|
1414
|
+
mask
|
|
1050
1415
|
}) => {
|
|
1051
1416
|
if (truncated) {
|
|
1052
1417
|
return;
|
|
@@ -1057,7 +1422,7 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1057
1422
|
return;
|
|
1058
1423
|
}
|
|
1059
1424
|
const predicate = selectedPredicatePool[index];
|
|
1060
|
-
if (
|
|
1425
|
+
if (!canCombinePredicate(chosen, predicate)) {
|
|
1061
1426
|
continue;
|
|
1062
1427
|
}
|
|
1063
1428
|
const intersection = mask == null ? { mask: predicate.mask, support: predicate.support } : intersectMasks(mask, predicate.mask);
|
|
@@ -1073,26 +1438,27 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1073
1438
|
if (nextChosen.length >= maxDepth) {
|
|
1074
1439
|
continue;
|
|
1075
1440
|
}
|
|
1076
|
-
const nextUsedFeatureKeys = new Set(usedFeatureKeys);
|
|
1077
|
-
nextUsedFeatureKeys.add(predicate.featureKey);
|
|
1078
1441
|
visit({
|
|
1079
1442
|
startIndex: index + 1,
|
|
1080
1443
|
chosen: nextChosen,
|
|
1081
|
-
mask: nextMask
|
|
1082
|
-
usedFeatureKeys: nextUsedFeatureKeys
|
|
1444
|
+
mask: nextMask
|
|
1083
1445
|
});
|
|
1084
1446
|
}
|
|
1085
1447
|
};
|
|
1086
1448
|
visit({
|
|
1087
1449
|
startIndex: 0,
|
|
1088
1450
|
chosen: [],
|
|
1089
|
-
mask: null
|
|
1090
|
-
usedFeatureKeys: /* @__PURE__ */ new Set()
|
|
1451
|
+
mask: null
|
|
1091
1452
|
});
|
|
1092
1453
|
emitProgress(true);
|
|
1093
1454
|
return {
|
|
1455
|
+
objective,
|
|
1094
1456
|
baseline: summarizeAiPocketRows(rows),
|
|
1095
1457
|
...validationRows.length ? { validationBaseline: summarizeAiPocketRows(validationRows) } : {},
|
|
1458
|
+
...testRows.length ? { testBaseline: summarizeAiPocketRows(testRows) } : {},
|
|
1459
|
+
...objective === "standalone" ? {} : { objectiveBaseline },
|
|
1460
|
+
...objective !== "standalone" && validationRows.length ? { validationObjectiveBaseline } : {},
|
|
1461
|
+
...objective !== "standalone" && testRows.length ? { testObjectiveBaseline } : {},
|
|
1096
1462
|
predicates: predicates.map(toPublicPredicate),
|
|
1097
1463
|
positivePockets: [...positivePockets.values()].sort(comparePositivePockets).slice(0, top),
|
|
1098
1464
|
negativePockets: [...negativePockets.values()].sort(compareNegativePockets).slice(0, top),
|
|
@@ -1104,7 +1470,15 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
1104
1470
|
estimatedCombinations,
|
|
1105
1471
|
combinationsEvaluated,
|
|
1106
1472
|
validationRows: validationRows.length,
|
|
1473
|
+
testRows: testRows.length,
|
|
1107
1474
|
duplicatePocketsSkipped,
|
|
1475
|
+
featureFamiliesUsed: [
|
|
1476
|
+
...new Set(
|
|
1477
|
+
selectedPredicatePool.map(
|
|
1478
|
+
(predicate) => classifyFeatureFamily(predicate.featureKey)
|
|
1479
|
+
)
|
|
1480
|
+
)
|
|
1481
|
+
],
|
|
1108
1482
|
truncated
|
|
1109
1483
|
}
|
|
1110
1484
|
};
|
|
@@ -1122,6 +1496,13 @@ var markdownTable = (headers, rows) => {
|
|
|
1122
1496
|
};
|
|
1123
1497
|
var summaryMetricRows = (summary) => [
|
|
1124
1498
|
["rows", summary.support],
|
|
1499
|
+
["events", summary.events],
|
|
1500
|
+
["event_balanced_profit", formatMdNumber(summary.eventBalancedProfit)],
|
|
1501
|
+
["trades_per_event", formatMdNumber(summary.tradesPerEvent)],
|
|
1502
|
+
["p95_batch", summary.p95Batch],
|
|
1503
|
+
["max_batch", summary.maxBatch],
|
|
1504
|
+
["top_event_count_share", formatMdPercent(summary.topEventCountShare)],
|
|
1505
|
+
["top_symbol_count_share", formatMdPercent(summary.topSymbolCountShare)],
|
|
1125
1506
|
["win_rate", formatMdPercent(summary.winRate)],
|
|
1126
1507
|
["total_profit", formatMdNumber(summary.totalProfit)],
|
|
1127
1508
|
["gross_profit", formatMdNumber(summary.grossProfit)],
|
|
@@ -1150,15 +1531,22 @@ var summaryMetricRows = (summary) => [
|
|
|
1150
1531
|
var pocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
1151
1532
|
index + 1,
|
|
1152
1533
|
pocket.summary.support,
|
|
1534
|
+
pocket.summary.events,
|
|
1535
|
+
pocket.summary.maxBatch,
|
|
1153
1536
|
formatMdPercent(pocket.summary.supportRatio),
|
|
1154
1537
|
formatMdPercent(pocket.summary.winRate),
|
|
1155
1538
|
formatMdNumber(pocket.summary.profitFactor),
|
|
1156
1539
|
formatMdNumber(pocket.summary.totalProfit),
|
|
1540
|
+
pocket.objectiveSummary ? formatMdNumber(pocket.objectiveSummary.totalProfit) : "n/a",
|
|
1157
1541
|
formatMdNumber(pocket.summary.maxDrawdown),
|
|
1158
1542
|
pocket.validationSummary?.support ?? "n/a",
|
|
1159
1543
|
pocket.validationSummary ? formatMdPercent(pocket.validationSummary.winRate) : "n/a",
|
|
1160
1544
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.profitFactor) : "n/a",
|
|
1161
1545
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.totalProfit) : "n/a",
|
|
1546
|
+
pocket.testSummary?.support ?? "n/a",
|
|
1547
|
+
pocket.testSummary ? formatMdNumber(pocket.testSummary.profitFactor) : "n/a",
|
|
1548
|
+
pocket.testSummary ? formatMdNumber(pocket.testSummary.totalProfit) : "n/a",
|
|
1549
|
+
pocket.testObjectiveSummary ? formatMdNumber(pocket.testObjectiveSummary.totalProfit) : "n/a",
|
|
1162
1550
|
formatMdNumber(pocket.summary.avgTradesPerDay),
|
|
1163
1551
|
pocket.summary.losingMonths,
|
|
1164
1552
|
formatMdNumber(pocket.score),
|
|
@@ -1172,6 +1560,13 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1172
1560
|
errors
|
|
1173
1561
|
}) => {
|
|
1174
1562
|
const generatedIso = new Date(generatedAt).toISOString();
|
|
1563
|
+
const featurePolicyAuditRows = Object.entries(
|
|
1564
|
+
run.featurePolicyAudit ?? {}
|
|
1565
|
+
).map(([classification, audit]) => [
|
|
1566
|
+
classification,
|
|
1567
|
+
audit?.paths ?? 0,
|
|
1568
|
+
audit?.samples.join(", ") ?? ""
|
|
1569
|
+
]);
|
|
1175
1570
|
const lines = [
|
|
1176
1571
|
"# AI Pocket Search Report",
|
|
1177
1572
|
"",
|
|
@@ -1187,6 +1582,7 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1187
1582
|
["selected_rows", run.selectedRows],
|
|
1188
1583
|
["evaluated_rows", run.evaluatedRows],
|
|
1189
1584
|
["scope", run.scope],
|
|
1585
|
+
["objective", run.objective ?? pocketSearch.objective],
|
|
1190
1586
|
["direction", run.direction ?? "all"],
|
|
1191
1587
|
["scope_rows", run.scopeRows],
|
|
1192
1588
|
["train_rows", run.trainRows],
|
|
@@ -1210,15 +1606,44 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1210
1606
|
["min_quality", run.minQuality],
|
|
1211
1607
|
["max_depth", run.search.maxDepth],
|
|
1212
1608
|
["min_support", run.search.minSupport],
|
|
1609
|
+
["min_events", run.search.minEvents ?? 1],
|
|
1610
|
+
["min_validation_events", run.search.minValidationEvents ?? 0],
|
|
1611
|
+
["max_batch", run.search.maxBatch ?? "off"],
|
|
1612
|
+
[
|
|
1613
|
+
"max_event_count_share",
|
|
1614
|
+
run.search.maxEventCountShare == null ? "off" : formatMdPercent(run.search.maxEventCountShare)
|
|
1615
|
+
],
|
|
1616
|
+
[
|
|
1617
|
+
"max_symbol_count_share",
|
|
1618
|
+
run.search.maxSymbolCountShare == null ? "off" : formatMdPercent(run.search.maxSymbolCountShare)
|
|
1619
|
+
],
|
|
1620
|
+
[
|
|
1621
|
+
"allow_risk_regression",
|
|
1622
|
+
run.search.allowRiskRegression ? "yes" : "no"
|
|
1623
|
+
],
|
|
1624
|
+
[
|
|
1625
|
+
"require_validation_eligibility",
|
|
1626
|
+
run.search.requireValidationEligibility ? "yes" : "no"
|
|
1627
|
+
],
|
|
1213
1628
|
["max_atomic_predicates", run.search.maxAtomicPredicates],
|
|
1214
1629
|
["max_combinations", run.search.maxCombinations],
|
|
1215
1630
|
["include_symbol", run.includeSymbol ? "on" : "off"],
|
|
1216
1631
|
["include_gate_context", run.includeGateContext ? "on" : "off"],
|
|
1217
1632
|
["feature_profile", run.featureProfile ?? "all"],
|
|
1633
|
+
["feature_policy", run.featurePolicy ?? "all"],
|
|
1218
1634
|
["report_path", run.reportPath]
|
|
1219
1635
|
]
|
|
1220
1636
|
),
|
|
1221
1637
|
"",
|
|
1638
|
+
...featurePolicyAuditRows.length ? [
|
|
1639
|
+
"## Feature Policy Audit",
|
|
1640
|
+
"",
|
|
1641
|
+
markdownTable(
|
|
1642
|
+
["Classification", "Excluded paths", "Samples"],
|
|
1643
|
+
featurePolicyAuditRows
|
|
1644
|
+
),
|
|
1645
|
+
""
|
|
1646
|
+
] : [],
|
|
1222
1647
|
"## Dataset Files",
|
|
1223
1648
|
"",
|
|
1224
1649
|
...run.filePaths.map((filePath) => `- \`${filePath}\``),
|
|
@@ -1255,6 +1680,33 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1255
1680
|
),
|
|
1256
1681
|
""
|
|
1257
1682
|
] : [],
|
|
1683
|
+
...pocketSearch.testBaseline ? [
|
|
1684
|
+
"## Untouched Test Baseline",
|
|
1685
|
+
"",
|
|
1686
|
+
markdownTable(
|
|
1687
|
+
["Metric", "Value"],
|
|
1688
|
+
summaryMetricRows(pocketSearch.testBaseline)
|
|
1689
|
+
),
|
|
1690
|
+
""
|
|
1691
|
+
] : [],
|
|
1692
|
+
...pocketSearch.objectiveBaseline ? [
|
|
1693
|
+
"## Current Gate Train Baseline",
|
|
1694
|
+
"",
|
|
1695
|
+
markdownTable(
|
|
1696
|
+
["Metric", "Value"],
|
|
1697
|
+
summaryMetricRows(pocketSearch.objectiveBaseline)
|
|
1698
|
+
),
|
|
1699
|
+
""
|
|
1700
|
+
] : [],
|
|
1701
|
+
...pocketSearch.testObjectiveBaseline ? [
|
|
1702
|
+
"## Current Gate Untouched Test Baseline",
|
|
1703
|
+
"",
|
|
1704
|
+
markdownTable(
|
|
1705
|
+
["Metric", "Value"],
|
|
1706
|
+
summaryMetricRows(pocketSearch.testObjectiveBaseline)
|
|
1707
|
+
),
|
|
1708
|
+
""
|
|
1709
|
+
] : [],
|
|
1258
1710
|
"## Search Stats",
|
|
1259
1711
|
"",
|
|
1260
1712
|
markdownTable(
|
|
@@ -1263,9 +1715,11 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1263
1715
|
["feature_keys", pocketSearch.stats.featureKeys],
|
|
1264
1716
|
["predicates", pocketSearch.stats.predicates],
|
|
1265
1717
|
["atomic_used", pocketSearch.stats.atomicPredicatesUsed],
|
|
1718
|
+
["feature_families", pocketSearch.stats.featureFamiliesUsed.join(", ")],
|
|
1266
1719
|
["estimated_combinations", pocketSearch.stats.estimatedCombinations],
|
|
1267
1720
|
["combinations_evaluated", pocketSearch.stats.combinationsEvaluated],
|
|
1268
1721
|
["validation_rows", pocketSearch.stats.validationRows],
|
|
1722
|
+
["test_rows", pocketSearch.stats.testRows],
|
|
1269
1723
|
[
|
|
1270
1724
|
"duplicate_pockets_skipped",
|
|
1271
1725
|
pocketSearch.stats.duplicatePocketsSkipped
|
|
@@ -1280,15 +1734,22 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1280
1734
|
[
|
|
1281
1735
|
"#",
|
|
1282
1736
|
"N",
|
|
1737
|
+
"Events",
|
|
1738
|
+
"Max batch",
|
|
1283
1739
|
"Support",
|
|
1284
1740
|
"WR",
|
|
1285
1741
|
"PF",
|
|
1286
1742
|
"PNL",
|
|
1743
|
+
"Objective PNL",
|
|
1287
1744
|
"Max DD",
|
|
1288
1745
|
"Val N",
|
|
1289
1746
|
"Val WR",
|
|
1290
1747
|
"Val PF",
|
|
1291
1748
|
"Val PNL",
|
|
1749
|
+
"Test N",
|
|
1750
|
+
"Test PF",
|
|
1751
|
+
"Test PNL",
|
|
1752
|
+
"Test objective PNL",
|
|
1292
1753
|
"Trades/Day",
|
|
1293
1754
|
"Losing Months",
|
|
1294
1755
|
"Score",
|
|
@@ -1303,15 +1764,22 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1303
1764
|
[
|
|
1304
1765
|
"#",
|
|
1305
1766
|
"N",
|
|
1767
|
+
"Events",
|
|
1768
|
+
"Max batch",
|
|
1306
1769
|
"Support",
|
|
1307
1770
|
"WR",
|
|
1308
1771
|
"PF",
|
|
1309
1772
|
"PNL",
|
|
1773
|
+
"Objective PNL",
|
|
1310
1774
|
"Max DD",
|
|
1311
1775
|
"Val N",
|
|
1312
1776
|
"Val WR",
|
|
1313
1777
|
"Val PF",
|
|
1314
1778
|
"Val PNL",
|
|
1779
|
+
"Test N",
|
|
1780
|
+
"Test PF",
|
|
1781
|
+
"Test PNL",
|
|
1782
|
+
"Test objective PNL",
|
|
1315
1783
|
"Trades/Day",
|
|
1316
1784
|
"Losing Months",
|
|
1317
1785
|
"Score",
|
|
@@ -1331,6 +1799,7 @@ var buildAiPocketMarkdownReport = ({
|
|
|
1331
1799
|
0 && (module.exports = {
|
|
1332
1800
|
buildAiPocketMarkdownReport,
|
|
1333
1801
|
buildAiPocketPredicates,
|
|
1802
|
+
classifyAiPocketFeaturePath,
|
|
1334
1803
|
collectAiPocketFeatures,
|
|
1335
1804
|
searchAiPockets,
|
|
1336
1805
|
summarizeAiPocketRows
|