@tradejs/cli 2.0.15 → 2.0.17
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 +2982 -994
- package/dist/lib/aiPocketSearch.js +493 -24
- package/dist/lib/aiTrainResearch.js +19 -2
- package/dist/lib/hyperliquidWhaleBackfill.js +37 -1
- package/dist/lib/marketContextPrepare.js +112 -9
- 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 +136 -11
- package/dist/scripts/hyperliquidWhaleBackfill.js +27 -1
- package/dist/scripts/hyperliquidWhalesUpdate.js +1 -0
- package/dist/scripts/replay.js +122 -12
- package/dist/scripts/replayRunner.js +122 -12
- 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 +110 -9
- package/dist/scripts/runtimeScorecard.js +731 -0
- package/dist/scripts/signals.js +263 -145
- package/dist/scripts/signalsDaemon.js +263 -145
- package/dist/scripts/signalsSummary.js +9 -0
- package/dist/workers/testerWorker.js +2 -0
- package/package.json +11 -9
|
@@ -2078,6 +2078,115 @@ var normalizeFeaturePrimitive = (value) => {
|
|
|
2078
2078
|
return value;
|
|
2079
2079
|
};
|
|
2080
2080
|
var isOutcomePath = (segments) => segments.some((segment) => OUTCOME_SEGMENTS.has(segment.toLowerCase()));
|
|
2081
|
+
var DATA_QUALITY_LEAVES = /* @__PURE__ */ new Set([
|
|
2082
|
+
"age",
|
|
2083
|
+
"agems",
|
|
2084
|
+
"available",
|
|
2085
|
+
"asofts",
|
|
2086
|
+
"calcbars",
|
|
2087
|
+
"coverage",
|
|
2088
|
+
"latestindex",
|
|
2089
|
+
"points",
|
|
2090
|
+
"rowcount",
|
|
2091
|
+
"rows",
|
|
2092
|
+
"stale",
|
|
2093
|
+
"timestamp",
|
|
2094
|
+
"windowendts"
|
|
2095
|
+
]);
|
|
2096
|
+
var METADATA_LEAVES = /* @__PURE__ */ new Set([
|
|
2097
|
+
"connector",
|
|
2098
|
+
"exchange",
|
|
2099
|
+
"fingerprint",
|
|
2100
|
+
"interval",
|
|
2101
|
+
"provider",
|
|
2102
|
+
"source",
|
|
2103
|
+
"strategy",
|
|
2104
|
+
"symbol",
|
|
2105
|
+
"targetsymbol",
|
|
2106
|
+
"universe"
|
|
2107
|
+
]);
|
|
2108
|
+
var DERIVED_POLICY_FRAGMENTS = [
|
|
2109
|
+
"approval",
|
|
2110
|
+
"decisionhint",
|
|
2111
|
+
"gatefeature",
|
|
2112
|
+
"gatescore",
|
|
2113
|
+
"hardblock",
|
|
2114
|
+
"qualitycap",
|
|
2115
|
+
"recoverycandidate",
|
|
2116
|
+
"rejectreason",
|
|
2117
|
+
"riskflag"
|
|
2118
|
+
];
|
|
2119
|
+
var RAW_NONSTATIONARY_LEAVES = /* @__PURE__ */ new Set([
|
|
2120
|
+
"activeassets",
|
|
2121
|
+
"activemarkets",
|
|
2122
|
+
"close",
|
|
2123
|
+
"current",
|
|
2124
|
+
"currentprice",
|
|
2125
|
+
"high",
|
|
2126
|
+
"indexprice",
|
|
2127
|
+
"liquidations",
|
|
2128
|
+
"liquidationsusd",
|
|
2129
|
+
"low",
|
|
2130
|
+
"marketcap",
|
|
2131
|
+
"marketcapusd",
|
|
2132
|
+
"notional",
|
|
2133
|
+
"open",
|
|
2134
|
+
"openinterest",
|
|
2135
|
+
"openinterestusd",
|
|
2136
|
+
"price",
|
|
2137
|
+
"quotevolume",
|
|
2138
|
+
"turnover",
|
|
2139
|
+
"turnoverusd",
|
|
2140
|
+
"volume",
|
|
2141
|
+
"volumeusd",
|
|
2142
|
+
"vwap"
|
|
2143
|
+
]);
|
|
2144
|
+
var classifyAiPocketFeaturePath = (path2) => {
|
|
2145
|
+
const segments = (Array.isArray(path2) ? path2 : path2.split(".")).filter(
|
|
2146
|
+
Boolean
|
|
2147
|
+
);
|
|
2148
|
+
const normalized = segments.map((segment) => segment.toLowerCase());
|
|
2149
|
+
const leaf = normalized.at(-1) ?? "";
|
|
2150
|
+
const normalizedPath = normalized.join(".");
|
|
2151
|
+
const strategyGateFeaturesIndex = normalized.findIndex(
|
|
2152
|
+
(segment) => segment !== "gatefeatures" && segment.endsWith("gatefeatures")
|
|
2153
|
+
);
|
|
2154
|
+
const strategyGateFeaturePath = normalized.slice(
|
|
2155
|
+
strategyGateFeaturesIndex + 1
|
|
2156
|
+
);
|
|
2157
|
+
const isStrategySetupEvidence = normalized.includes("basecontext") && strategyGateFeaturesIndex >= 0 && (strategyGateFeaturePath.length === 0 || strategyGateFeaturePath.some(
|
|
2158
|
+
(segment) => segment === "geometry" || segment === "path"
|
|
2159
|
+
));
|
|
2160
|
+
if (DATA_QUALITY_LEAVES.has(leaf) || leaf.endsWith("timestamp") || leaf.endsWith("agems") || normalized.some(
|
|
2161
|
+
(segment) => ["availability", "dataquality", "freshness"].includes(segment)
|
|
2162
|
+
)) {
|
|
2163
|
+
return "data-quality";
|
|
2164
|
+
}
|
|
2165
|
+
if (METADATA_LEAVES.has(leaf) || leaf.endsWith("fingerprint") || normalized.some((segment) => segment === "metadata")) {
|
|
2166
|
+
return "metadata";
|
|
2167
|
+
}
|
|
2168
|
+
if (DERIVED_POLICY_FRAGMENTS.some(
|
|
2169
|
+
(fragment) => !(fragment === "gatefeature" && isStrategySetupEvidence) && normalizedPath.includes(fragment)
|
|
2170
|
+
)) {
|
|
2171
|
+
return "derived-policy";
|
|
2172
|
+
}
|
|
2173
|
+
const isDerivedFeature = normalized[0] === "derived";
|
|
2174
|
+
const isNormalizedLeaf = /(alpha|bps|change|delta|direction|distance|pct|percentile|ratio|regime|return|share|slope|trend|zscore)/.test(
|
|
2175
|
+
leaf
|
|
2176
|
+
);
|
|
2177
|
+
const isRawMovingAverage = /^(?:ema|ma|sma|wma)(?:fast|slow|\d+)$/.test(leaf);
|
|
2178
|
+
const isRawAbsolutePositioning = /^(?:liq(?:long|net|short|total)|oi|openinterest(?:long|short)?)$/.test(
|
|
2179
|
+
leaf
|
|
2180
|
+
);
|
|
2181
|
+
const isRawAbsoluteMeasure = /(?:liquidations?|marketcap|notional|openinterest|price|turnover|volume)$/.test(
|
|
2182
|
+
leaf
|
|
2183
|
+
);
|
|
2184
|
+
const isRawStructureLevel = leaf === "level" && normalized.includes("structure");
|
|
2185
|
+
if (!isDerivedFeature && !isNormalizedLeaf && (RAW_NONSTATIONARY_LEAVES.has(leaf) || isRawMovingAverage || isRawAbsolutePositioning || isRawAbsoluteMeasure || isRawStructureLevel)) {
|
|
2186
|
+
return "raw-nonstationary";
|
|
2187
|
+
}
|
|
2188
|
+
return "eligible";
|
|
2189
|
+
};
|
|
2081
2190
|
var isFeaturePathPrefix = (segments, prefix) => prefix.every((segment, index) => segments[index] === segment);
|
|
2082
2191
|
var isCompactFeaturePathSkipped = (segments) => {
|
|
2083
2192
|
if (!segments.length) {
|
|
@@ -2339,7 +2448,9 @@ var collectAiPocketFeatures = ({
|
|
|
2339
2448
|
gateContext,
|
|
2340
2449
|
includeSymbol = false,
|
|
2341
2450
|
includeGateContext = false,
|
|
2342
|
-
featureProfile = "all"
|
|
2451
|
+
featureProfile = "all",
|
|
2452
|
+
featurePolicy = "all",
|
|
2453
|
+
onFeatureExcluded
|
|
2343
2454
|
}) => {
|
|
2344
2455
|
const features = {};
|
|
2345
2456
|
const signal = payload.signal ?? {};
|
|
@@ -2359,8 +2470,35 @@ var collectAiPocketFeatures = ({
|
|
|
2359
2470
|
value: source,
|
|
2360
2471
|
segments: [],
|
|
2361
2472
|
maxDepth: 8,
|
|
2362
|
-
shouldSkipPath:
|
|
2473
|
+
shouldSkipPath: (segments) => {
|
|
2474
|
+
if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
|
|
2475
|
+
return true;
|
|
2476
|
+
}
|
|
2477
|
+
if (featurePolicy !== "causal-stationary") {
|
|
2478
|
+
return false;
|
|
2479
|
+
}
|
|
2480
|
+
const classification = classifyAiPocketFeaturePath(segments);
|
|
2481
|
+
if (classification === "eligible") {
|
|
2482
|
+
return false;
|
|
2483
|
+
}
|
|
2484
|
+
onFeatureExcluded?.({
|
|
2485
|
+
path: segments.join("."),
|
|
2486
|
+
classification
|
|
2487
|
+
});
|
|
2488
|
+
return true;
|
|
2489
|
+
}
|
|
2363
2490
|
});
|
|
2491
|
+
if (featurePolicy === "causal-stationary") {
|
|
2492
|
+
for (const [key, value] of Object.entries(features)) {
|
|
2493
|
+
if (value === null) {
|
|
2494
|
+
onFeatureExcluded?.({
|
|
2495
|
+
path: key,
|
|
2496
|
+
classification: "data-quality"
|
|
2497
|
+
});
|
|
2498
|
+
delete features[key];
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2364
2502
|
addSignalRiskDistanceFeatures({ features, signal });
|
|
2365
2503
|
addDirectionalDerivedFeatures(features);
|
|
2366
2504
|
return features;
|
|
@@ -2413,6 +2551,7 @@ var createSummaryAccumulator = () => ({
|
|
|
2413
2551
|
directionCounts: /* @__PURE__ */ new Map(),
|
|
2414
2552
|
symbolCounts: /* @__PURE__ */ new Map(),
|
|
2415
2553
|
monthProfits: /* @__PURE__ */ new Map(),
|
|
2554
|
+
eventStats: /* @__PURE__ */ new Map(),
|
|
2416
2555
|
equityPoints: []
|
|
2417
2556
|
});
|
|
2418
2557
|
var addSummaryRow = (accumulator, row) => {
|
|
@@ -2438,6 +2577,14 @@ var addSummaryRow = (accumulator, row) => {
|
|
|
2438
2577
|
symbolBucket.totalProfit += profit;
|
|
2439
2578
|
accumulator.symbolCounts.set(symbol, symbolBucket);
|
|
2440
2579
|
const timestamp = typeof row.timestamp === "number" && Number.isFinite(row.timestamp) ? row.timestamp : Number.POSITIVE_INFINITY;
|
|
2580
|
+
const eventKey = Number.isFinite(timestamp) ? String(timestamp) : `UNKNOWN:${accumulator.support}`;
|
|
2581
|
+
const event = accumulator.eventStats.get(eventKey) ?? {
|
|
2582
|
+
count: 0,
|
|
2583
|
+
totalProfit: 0
|
|
2584
|
+
};
|
|
2585
|
+
event.count += 1;
|
|
2586
|
+
event.totalProfit += profit;
|
|
2587
|
+
accumulator.eventStats.set(eventKey, event);
|
|
2441
2588
|
const month = Number.isFinite(timestamp) && timestamp !== Number.POSITIVE_INFINITY ? new Date(timestamp).toISOString().slice(0, 7) : "UNKNOWN";
|
|
2442
2589
|
accumulator.monthProfits.set(
|
|
2443
2590
|
month,
|
|
@@ -2451,6 +2598,15 @@ var emptyAiPocketSummary = ({
|
|
|
2451
2598
|
}) => ({
|
|
2452
2599
|
support: 0,
|
|
2453
2600
|
supportRatio,
|
|
2601
|
+
events: 0,
|
|
2602
|
+
eventBalancedProfit: 0,
|
|
2603
|
+
tradesPerEvent: null,
|
|
2604
|
+
p95Batch: 0,
|
|
2605
|
+
maxBatch: 0,
|
|
2606
|
+
topEventCountShare: null,
|
|
2607
|
+
topEventProfitShare: null,
|
|
2608
|
+
topSymbolCountShare: null,
|
|
2609
|
+
topSymbolProfitShare: null,
|
|
2454
2610
|
totalProfit: 0,
|
|
2455
2611
|
grossProfit: 0,
|
|
2456
2612
|
grossLoss: 0,
|
|
@@ -2522,9 +2678,42 @@ var finalizeAiPocketSummary = ({
|
|
|
2522
2678
|
const worstMonth = [...accumulator.monthProfits.entries()].sort(
|
|
2523
2679
|
(left, right) => left[1] - right[1]
|
|
2524
2680
|
)[0] ?? null;
|
|
2681
|
+
const eventStats = [...accumulator.eventStats.values()];
|
|
2682
|
+
const events = eventStats.length;
|
|
2683
|
+
const batchSizes = eventStats.map((event) => event.count).sort((left, right) => left - right);
|
|
2684
|
+
const p95Batch = batchSizes[Math.max(0, Math.ceil(batchSizes.length * 0.95) - 1)] ?? 0;
|
|
2685
|
+
const maxBatch = batchSizes.at(-1) ?? 0;
|
|
2686
|
+
const absoluteEventProfit = eventStats.reduce(
|
|
2687
|
+
(sum, event) => sum + Math.abs(event.totalProfit),
|
|
2688
|
+
0
|
|
2689
|
+
);
|
|
2690
|
+
const absoluteSymbolProfit = [...accumulator.symbolCounts.values()].reduce(
|
|
2691
|
+
(sum, symbol) => sum + Math.abs(symbol.totalProfit),
|
|
2692
|
+
0
|
|
2693
|
+
);
|
|
2525
2694
|
return {
|
|
2526
2695
|
support,
|
|
2527
2696
|
supportRatio,
|
|
2697
|
+
events,
|
|
2698
|
+
eventBalancedProfit: eventStats.reduce(
|
|
2699
|
+
(sum, event) => sum + event.totalProfit / event.count,
|
|
2700
|
+
0
|
|
2701
|
+
),
|
|
2702
|
+
tradesPerEvent: events > 0 ? support / events : null,
|
|
2703
|
+
p95Batch,
|
|
2704
|
+
maxBatch,
|
|
2705
|
+
topEventCountShare: support > 0 ? maxBatch / support : null,
|
|
2706
|
+
topEventProfitShare: absoluteEventProfit > 0 ? Math.max(...eventStats.map((event) => Math.abs(event.totalProfit))) / absoluteEventProfit : null,
|
|
2707
|
+
topSymbolCountShare: support > 0 ? Math.max(
|
|
2708
|
+
...[...accumulator.symbolCounts.values()].map(
|
|
2709
|
+
(symbol) => symbol.count
|
|
2710
|
+
)
|
|
2711
|
+
) / support : null,
|
|
2712
|
+
topSymbolProfitShare: absoluteSymbolProfit > 0 ? Math.max(
|
|
2713
|
+
...[...accumulator.symbolCounts.values()].map(
|
|
2714
|
+
(symbol) => Math.abs(symbol.totalProfit)
|
|
2715
|
+
)
|
|
2716
|
+
) / absoluteSymbolProfit : null,
|
|
2528
2717
|
totalProfit,
|
|
2529
2718
|
grossProfit,
|
|
2530
2719
|
grossLoss,
|
|
@@ -2829,27 +3018,82 @@ var buildAiPocketPredicateResult = (rows, options = {}) => {
|
|
|
2829
3018
|
var scorePositivePocket = (summary) => {
|
|
2830
3019
|
const profitFactor = summary.profitFactor ?? (summary.grossLoss === 0 ? 8 : 0);
|
|
2831
3020
|
const winRate = summary.winRate ?? 0;
|
|
2832
|
-
return summary.
|
|
3021
|
+
return summary.eventBalancedProfit - summary.maxDrawdown * 0.6 + Math.min(profitFactor, 8) * 12 + winRate * 30 + Math.log10(summary.events + 1) * 6;
|
|
2833
3022
|
};
|
|
2834
3023
|
var scoreNegativePocket = (summary) => -summary.totalProfit + summary.maxDrawdown * 0.4 + summary.grossLoss * 0.2 + summary.maxConsecutiveLosses * 3;
|
|
2835
3024
|
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;
|
|
2836
3025
|
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;
|
|
2837
|
-
var
|
|
3026
|
+
var mergeDistinctRows = (left, right) => {
|
|
3027
|
+
const seenRows = /* @__PURE__ */ new Set();
|
|
3028
|
+
const seenSignalIds = /* @__PURE__ */ new Set();
|
|
3029
|
+
return [...left, ...right].filter((row) => {
|
|
3030
|
+
if (seenRows.has(row)) {
|
|
3031
|
+
return false;
|
|
3032
|
+
}
|
|
3033
|
+
seenRows.add(row);
|
|
3034
|
+
const signalId = typeof row.signalId === "string" && row.signalId.trim() ? row.signalId : null;
|
|
3035
|
+
if (signalId == null) {
|
|
3036
|
+
return true;
|
|
3037
|
+
}
|
|
3038
|
+
if (seenSignalIds.has(signalId)) {
|
|
3039
|
+
return false;
|
|
3040
|
+
}
|
|
3041
|
+
seenSignalIds.add(signalId);
|
|
3042
|
+
return true;
|
|
3043
|
+
});
|
|
3044
|
+
};
|
|
3045
|
+
var resolveObjectiveRows = ({
|
|
3046
|
+
objective,
|
|
3047
|
+
selectedRows,
|
|
3048
|
+
baselineRows
|
|
3049
|
+
}) => objective === "add-to-gate" ? mergeDistinctRows(baselineRows, selectedRows) : selectedRows;
|
|
3050
|
+
var effectiveProfitFactor = (summary) => summary.profitFactor ?? (summary.grossLoss === 0 && summary.totalProfit >= 0 ? Number.POSITIVE_INFINITY : 0);
|
|
3051
|
+
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;
|
|
3052
|
+
var createPocketResult = (rows, predicates, mask, validationRows, testRows, objective, baselineRows, validationBaselineRows, testBaselineRows, objectiveBaseline, validationObjectiveBaseline, testObjectiveBaseline) => {
|
|
2838
3053
|
const publicPredicates = predicates.map(toPublicPredicate);
|
|
2839
3054
|
const summary = summarizeMask(rows, mask);
|
|
3055
|
+
const selectedRows = rows.filter((_, index) => mask[index] === 1);
|
|
3056
|
+
const objectiveRows = resolveObjectiveRows({
|
|
3057
|
+
objective,
|
|
3058
|
+
selectedRows,
|
|
3059
|
+
baselineRows
|
|
3060
|
+
});
|
|
3061
|
+
const objectiveSummary = objective === "add-to-gate" ? summarizeAiPocketRows(objectiveRows) : summary;
|
|
2840
3062
|
const validationMask = validationRows.length ? buildPredicateListMask(validationRows, publicPredicates).mask : null;
|
|
2841
3063
|
const validationSummary = validationMask == null ? void 0 : summarizeMask(validationRows, validationMask);
|
|
3064
|
+
const validationSelectedRows = validationMask == null ? [] : validationRows.filter((_, index) => validationMask[index] === 1);
|
|
3065
|
+
const validationObjectiveRows = resolveObjectiveRows({
|
|
3066
|
+
objective,
|
|
3067
|
+
selectedRows: validationSelectedRows,
|
|
3068
|
+
baselineRows: validationBaselineRows
|
|
3069
|
+
});
|
|
3070
|
+
const validationObjectiveSummary = validationRows.length ? objective === "add-to-gate" ? summarizeAiPocketRows(validationObjectiveRows) : validationSummary : void 0;
|
|
3071
|
+
const testMask = testRows.length ? buildPredicateListMask(testRows, publicPredicates).mask : null;
|
|
3072
|
+
const testSummary = testMask == null ? void 0 : summarizeMask(testRows, testMask);
|
|
3073
|
+
const testSelectedRows = testMask == null ? [] : testRows.filter((_, index) => testMask[index] === 1);
|
|
3074
|
+
const testObjectiveRows = resolveObjectiveRows({
|
|
3075
|
+
objective,
|
|
3076
|
+
selectedRows: testSelectedRows,
|
|
3077
|
+
baselineRows: testBaselineRows
|
|
3078
|
+
});
|
|
3079
|
+
const testObjectiveSummary = testRows.length ? objective === "add-to-gate" ? summarizeAiPocketRows(testObjectiveRows) : testSummary : void 0;
|
|
2842
3080
|
const condition = publicPredicates.map((predicate) => predicate.label).join(" AND ");
|
|
2843
|
-
const validationScore = validationSummary == null ? void 0 : validationSummary.support > 0 ? scorePositivePocket(
|
|
3081
|
+
const validationScore = validationSummary == null || validationObjectiveSummary == null ? void 0 : validationSummary.support > 0 ? scorePositivePocket(validationObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(validationObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
3082
|
+
const testScore = testSummary == null || testObjectiveSummary == null ? void 0 : testSummary.support > 0 ? scorePositivePocket(testObjectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(testObjectiveBaseline)) : Number.NEGATIVE_INFINITY;
|
|
2844
3083
|
return {
|
|
2845
3084
|
id: publicPredicates.map((predicate) => predicate.id).join("&&"),
|
|
2846
3085
|
depth: publicPredicates.length,
|
|
2847
3086
|
predicates: publicPredicates,
|
|
2848
3087
|
condition,
|
|
2849
3088
|
summary,
|
|
3089
|
+
...objective === "standalone" ? {} : { objectiveSummary },
|
|
2850
3090
|
...validationSummary ? { validationSummary } : {},
|
|
3091
|
+
...testSummary ? { testSummary } : {},
|
|
3092
|
+
...objective !== "standalone" && validationObjectiveSummary ? { validationObjectiveSummary } : {},
|
|
3093
|
+
...objective !== "standalone" && testObjectiveSummary ? { testObjectiveSummary } : {},
|
|
2851
3094
|
...validationScore != null ? { validationScore } : {},
|
|
2852
|
-
|
|
3095
|
+
...testScore != null ? { testScore } : {},
|
|
3096
|
+
score: scorePositivePocket(objectiveSummary) - (objective === "standalone" ? 0 : scorePositivePocket(objectiveBaseline))
|
|
2853
3097
|
};
|
|
2854
3098
|
};
|
|
2855
3099
|
var hashMask = (mask) => {
|
|
@@ -2880,6 +3124,83 @@ var estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
|
|
|
2880
3124
|
}
|
|
2881
3125
|
return Math.min(Math.trunc(total), maxCombinations);
|
|
2882
3126
|
};
|
|
3127
|
+
var classifyFeatureFamily = (featureKey) => {
|
|
3128
|
+
const key = featureKey.toLowerCase();
|
|
3129
|
+
if (/(setup|liquidity|doubletap|trendline|pivot|swing|zone)/.test(key)) {
|
|
3130
|
+
return "strategy-structure";
|
|
3131
|
+
}
|
|
3132
|
+
if (/(structure|breakout|rejection|range|level)/.test(key)) {
|
|
3133
|
+
return "market-structure";
|
|
3134
|
+
}
|
|
3135
|
+
if (/(participation|volume|turnover|obv|effort)/.test(key)) {
|
|
3136
|
+
return "participation";
|
|
3137
|
+
}
|
|
3138
|
+
if (/(relative|benchmark|cmc|breadth|targetvs|btc|eth)/.test(key)) {
|
|
3139
|
+
return "relative-market";
|
|
3140
|
+
}
|
|
3141
|
+
if (/(derivative|funding|openinterest|liquidation|longshort)/.test(key)) {
|
|
3142
|
+
return "derivatives";
|
|
3143
|
+
}
|
|
3144
|
+
if (/(risk|stop|takeprofit|execution|spread|slippage)/.test(key)) {
|
|
3145
|
+
return "execution-risk";
|
|
3146
|
+
}
|
|
3147
|
+
if (/(regime|momentum|trend|volatility|atr|macd|rsi|ma)/.test(key)) {
|
|
3148
|
+
return "regime-indicators";
|
|
3149
|
+
}
|
|
3150
|
+
return "other";
|
|
3151
|
+
};
|
|
3152
|
+
var diversifyPredicatePool = (predicates, maximum) => {
|
|
3153
|
+
const byFamily = /* @__PURE__ */ new Map();
|
|
3154
|
+
const featureCounts = /* @__PURE__ */ new Map();
|
|
3155
|
+
for (const predicate of predicates) {
|
|
3156
|
+
const family = classifyFeatureFamily(predicate.featureKey);
|
|
3157
|
+
const familyPredicates = byFamily.get(family) ?? [];
|
|
3158
|
+
familyPredicates.push(predicate);
|
|
3159
|
+
byFamily.set(family, familyPredicates);
|
|
3160
|
+
}
|
|
3161
|
+
const selected = [];
|
|
3162
|
+
const selectedIds = /* @__PURE__ */ new Set();
|
|
3163
|
+
while (selected.length < maximum) {
|
|
3164
|
+
let added = false;
|
|
3165
|
+
for (const familyPredicates of byFamily.values()) {
|
|
3166
|
+
while (familyPredicates.length) {
|
|
3167
|
+
const predicate = familyPredicates.shift();
|
|
3168
|
+
if (selectedIds.has(predicate.id) || (featureCounts.get(predicate.featureKey) ?? 0) >= 4) {
|
|
3169
|
+
continue;
|
|
3170
|
+
}
|
|
3171
|
+
selected.push(predicate);
|
|
3172
|
+
selectedIds.add(predicate.id);
|
|
3173
|
+
featureCounts.set(
|
|
3174
|
+
predicate.featureKey,
|
|
3175
|
+
(featureCounts.get(predicate.featureKey) ?? 0) + 1
|
|
3176
|
+
);
|
|
3177
|
+
added = true;
|
|
3178
|
+
break;
|
|
3179
|
+
}
|
|
3180
|
+
if (selected.length >= maximum) {
|
|
3181
|
+
break;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
if (!added) {
|
|
3185
|
+
break;
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
return selected;
|
|
3189
|
+
};
|
|
3190
|
+
var canCombinePredicate = (chosen, candidate) => {
|
|
3191
|
+
const sameFeature = chosen.filter(
|
|
3192
|
+
(predicate) => predicate.featureKey === candidate.featureKey
|
|
3193
|
+
);
|
|
3194
|
+
if (!sameFeature.length) {
|
|
3195
|
+
return true;
|
|
3196
|
+
}
|
|
3197
|
+
if (sameFeature.length !== 1 || sameFeature[0].kind !== "numeric" || candidate.kind !== "numeric" || sameFeature[0].op === candidate.op) {
|
|
3198
|
+
return false;
|
|
3199
|
+
}
|
|
3200
|
+
const lower = candidate.op === ">=" ? candidate.threshold : sameFeature[0].threshold;
|
|
3201
|
+
const upper = candidate.op === "<=" ? candidate.threshold : sameFeature[0].threshold;
|
|
3202
|
+
return lower <= upper;
|
|
3203
|
+
};
|
|
2883
3204
|
var searchAiPockets = (rows, options = {}) => {
|
|
2884
3205
|
const minSupport = Math.max(1, Math.trunc(options.minSupport ?? 20));
|
|
2885
3206
|
const minProfitFactor = Math.max(0, options.minProfitFactor ?? 1.2);
|
|
@@ -2896,10 +3217,36 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
2896
3217
|
);
|
|
2897
3218
|
const top = Math.max(1, Math.trunc(options.top ?? 50));
|
|
2898
3219
|
const validationRows = options.validationRows ?? [];
|
|
3220
|
+
const testRows = options.testRows ?? [];
|
|
2899
3221
|
const minValidationSupport = Math.max(
|
|
2900
3222
|
0,
|
|
2901
3223
|
Math.trunc(options.minValidationSupport ?? 0)
|
|
2902
3224
|
);
|
|
3225
|
+
const minEvents = Math.max(1, Math.trunc(options.minEvents ?? 1));
|
|
3226
|
+
const minValidationEvents = Math.max(
|
|
3227
|
+
0,
|
|
3228
|
+
Math.trunc(options.minValidationEvents ?? 0)
|
|
3229
|
+
);
|
|
3230
|
+
const maxBatch = Math.max(1, options.maxBatch ?? Number.POSITIVE_INFINITY);
|
|
3231
|
+
const maxEventCountShare = Math.max(
|
|
3232
|
+
0,
|
|
3233
|
+
Math.min(1, options.maxEventCountShare ?? 1)
|
|
3234
|
+
);
|
|
3235
|
+
const maxSymbolCountShare = Math.max(
|
|
3236
|
+
0,
|
|
3237
|
+
Math.min(1, options.maxSymbolCountShare ?? 1)
|
|
3238
|
+
);
|
|
3239
|
+
const objective = options.objective ?? "standalone";
|
|
3240
|
+
const baselineRows = options.baselineRows ?? (objective === "filter-gate" ? rows : []);
|
|
3241
|
+
const validationBaselineRows = options.validationBaselineRows ?? (objective === "filter-gate" ? validationRows : []);
|
|
3242
|
+
const testBaselineRows = options.testBaselineRows ?? (objective === "filter-gate" ? testRows : []);
|
|
3243
|
+
const objectiveBaseline = summarizeAiPocketRows(baselineRows);
|
|
3244
|
+
const validationObjectiveBaseline = summarizeAiPocketRows(
|
|
3245
|
+
validationBaselineRows
|
|
3246
|
+
);
|
|
3247
|
+
const testObjectiveBaseline = summarizeAiPocketRows(testBaselineRows);
|
|
3248
|
+
const allowRiskRegression = options.allowRiskRegression === true;
|
|
3249
|
+
const requireValidationEligibility = options.requireValidationEligibility === true;
|
|
2903
3250
|
const dedupeEquivalentSelections = options.dedupeEquivalentSelections !== false;
|
|
2904
3251
|
const progressInterval = Math.max(
|
|
2905
3252
|
1,
|
|
@@ -2942,11 +3289,13 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
2942
3289
|
const supportPool = [...scoredPredicates].sort((left, right) => right.support - left.support).slice(0, Math.ceil(maxAtomicPredicates * 0.2));
|
|
2943
3290
|
const predicatePoolById = /* @__PURE__ */ new Map();
|
|
2944
3291
|
[...predicatePool, ...negativePool, ...supportPool].forEach((predicate) => {
|
|
2945
|
-
|
|
2946
|
-
predicatePoolById.set(predicate.id, predicate);
|
|
2947
|
-
}
|
|
3292
|
+
predicatePoolById.set(predicate.id, predicate);
|
|
2948
3293
|
});
|
|
2949
|
-
const
|
|
3294
|
+
const diversifiedPredicates = diversifyPredicatePool(
|
|
3295
|
+
[...predicatePoolById.values()],
|
|
3296
|
+
maxAtomicPredicates
|
|
3297
|
+
);
|
|
3298
|
+
const selectedPredicatePool = diversifiedPredicates.map(
|
|
2950
3299
|
(predicate) => {
|
|
2951
3300
|
const { mask, support } = buildMask(rows, predicate);
|
|
2952
3301
|
return {
|
|
@@ -2990,14 +3339,30 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
2990
3339
|
rows,
|
|
2991
3340
|
pocketPredicates,
|
|
2992
3341
|
mask,
|
|
2993
|
-
validationRows
|
|
3342
|
+
validationRows,
|
|
3343
|
+
testRows,
|
|
3344
|
+
objective,
|
|
3345
|
+
baselineRows,
|
|
3346
|
+
validationBaselineRows,
|
|
3347
|
+
testBaselineRows,
|
|
3348
|
+
objectiveBaseline,
|
|
3349
|
+
validationObjectiveBaseline,
|
|
3350
|
+
testObjectiveBaseline
|
|
2994
3351
|
);
|
|
2995
3352
|
const { summary } = pocket;
|
|
2996
|
-
const
|
|
2997
|
-
const
|
|
3353
|
+
const scoredSummary = pocket.objectiveSummary ?? summary;
|
|
3354
|
+
const profitFactor = scoredSummary.profitFactor ?? (scoredSummary.grossLoss === 0 && scoredSummary.totalProfit > 0 ? Number.POSITIVE_INFINITY : 0);
|
|
3355
|
+
const winRate = scoredSummary.winRate ?? 0;
|
|
2998
3356
|
const validationSupport = pocket.validationSummary?.support ?? 0;
|
|
2999
|
-
const validationEligible = !validationRows.length || validationSupport >= minValidationSupport
|
|
3000
|
-
|
|
3357
|
+
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(
|
|
3358
|
+
pocket.validationObjectiveSummary ?? pocket.validationSummary
|
|
3359
|
+
) >= minProfitFactor && ((pocket.validationObjectiveSummary ?? pocket.validationSummary).winRate ?? 0) >= minWinRate);
|
|
3360
|
+
const concentrationEligible = summary.events >= minEvents && summary.maxBatch <= maxBatch && (summary.topEventCountShare ?? 0) <= maxEventCountShare && (summary.topSymbolCountShare ?? 0) <= maxSymbolCountShare;
|
|
3361
|
+
const riskEligible = objective === "standalone" || allowRiskRegression || (!objectiveBaseline.support || doesNotRegressRisk(scoredSummary, objectiveBaseline)) && (!validationRows.length || !validationObjectiveBaseline.support || doesNotRegressRisk(
|
|
3362
|
+
pocket.validationObjectiveSummary ?? pocket.validationSummary,
|
|
3363
|
+
validationObjectiveBaseline
|
|
3364
|
+
));
|
|
3365
|
+
if (summary.support >= minSupport && scoredSummary.totalProfit >= minTotalProfit && profitFactor >= minProfitFactor && winRate >= minWinRate && validationEligible && concentrationEligible && riskEligible) {
|
|
3001
3366
|
const selectionKey = `${summary.support}:${hashMask(mask)}`;
|
|
3002
3367
|
const mapKey = dedupeEquivalentSelections ? selectionKey : pocket.id;
|
|
3003
3368
|
const existing = dedupeEquivalentSelections ? positiveSelectionKeys.get(mapKey) : positivePockets.get(mapKey);
|
|
@@ -3034,8 +3399,7 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
3034
3399
|
const visit = ({
|
|
3035
3400
|
startIndex,
|
|
3036
3401
|
chosen,
|
|
3037
|
-
mask
|
|
3038
|
-
usedFeatureKeys
|
|
3402
|
+
mask
|
|
3039
3403
|
}) => {
|
|
3040
3404
|
if (truncated) {
|
|
3041
3405
|
return;
|
|
@@ -3046,7 +3410,7 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
3046
3410
|
return;
|
|
3047
3411
|
}
|
|
3048
3412
|
const predicate = selectedPredicatePool[index];
|
|
3049
|
-
if (
|
|
3413
|
+
if (!canCombinePredicate(chosen, predicate)) {
|
|
3050
3414
|
continue;
|
|
3051
3415
|
}
|
|
3052
3416
|
const intersection = mask == null ? { mask: predicate.mask, support: predicate.support } : intersectMasks(mask, predicate.mask);
|
|
@@ -3062,26 +3426,27 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
3062
3426
|
if (nextChosen.length >= maxDepth) {
|
|
3063
3427
|
continue;
|
|
3064
3428
|
}
|
|
3065
|
-
const nextUsedFeatureKeys = new Set(usedFeatureKeys);
|
|
3066
|
-
nextUsedFeatureKeys.add(predicate.featureKey);
|
|
3067
3429
|
visit({
|
|
3068
3430
|
startIndex: index + 1,
|
|
3069
3431
|
chosen: nextChosen,
|
|
3070
|
-
mask: nextMask
|
|
3071
|
-
usedFeatureKeys: nextUsedFeatureKeys
|
|
3432
|
+
mask: nextMask
|
|
3072
3433
|
});
|
|
3073
3434
|
}
|
|
3074
3435
|
};
|
|
3075
3436
|
visit({
|
|
3076
3437
|
startIndex: 0,
|
|
3077
3438
|
chosen: [],
|
|
3078
|
-
mask: null
|
|
3079
|
-
usedFeatureKeys: /* @__PURE__ */ new Set()
|
|
3439
|
+
mask: null
|
|
3080
3440
|
});
|
|
3081
3441
|
emitProgress(true);
|
|
3082
3442
|
return {
|
|
3443
|
+
objective,
|
|
3083
3444
|
baseline: summarizeAiPocketRows(rows),
|
|
3084
3445
|
...validationRows.length ? { validationBaseline: summarizeAiPocketRows(validationRows) } : {},
|
|
3446
|
+
...testRows.length ? { testBaseline: summarizeAiPocketRows(testRows) } : {},
|
|
3447
|
+
...objective === "standalone" ? {} : { objectiveBaseline },
|
|
3448
|
+
...objective !== "standalone" && validationRows.length ? { validationObjectiveBaseline } : {},
|
|
3449
|
+
...objective !== "standalone" && testRows.length ? { testObjectiveBaseline } : {},
|
|
3085
3450
|
predicates: predicates.map(toPublicPredicate),
|
|
3086
3451
|
positivePockets: [...positivePockets.values()].sort(comparePositivePockets).slice(0, top),
|
|
3087
3452
|
negativePockets: [...negativePockets.values()].sort(compareNegativePockets).slice(0, top),
|
|
@@ -3093,7 +3458,15 @@ var searchAiPockets = (rows, options = {}) => {
|
|
|
3093
3458
|
estimatedCombinations,
|
|
3094
3459
|
combinationsEvaluated,
|
|
3095
3460
|
validationRows: validationRows.length,
|
|
3461
|
+
testRows: testRows.length,
|
|
3096
3462
|
duplicatePocketsSkipped,
|
|
3463
|
+
featureFamiliesUsed: [
|
|
3464
|
+
...new Set(
|
|
3465
|
+
selectedPredicatePool.map(
|
|
3466
|
+
(predicate) => classifyFeatureFamily(predicate.featureKey)
|
|
3467
|
+
)
|
|
3468
|
+
)
|
|
3469
|
+
],
|
|
3097
3470
|
truncated
|
|
3098
3471
|
}
|
|
3099
3472
|
};
|
|
@@ -3111,6 +3484,13 @@ var markdownTable = (headers, rows) => {
|
|
|
3111
3484
|
};
|
|
3112
3485
|
var summaryMetricRows = (summary) => [
|
|
3113
3486
|
["rows", summary.support],
|
|
3487
|
+
["events", summary.events],
|
|
3488
|
+
["event_balanced_profit", formatMdNumber(summary.eventBalancedProfit)],
|
|
3489
|
+
["trades_per_event", formatMdNumber(summary.tradesPerEvent)],
|
|
3490
|
+
["p95_batch", summary.p95Batch],
|
|
3491
|
+
["max_batch", summary.maxBatch],
|
|
3492
|
+
["top_event_count_share", formatMdPercent(summary.topEventCountShare)],
|
|
3493
|
+
["top_symbol_count_share", formatMdPercent(summary.topSymbolCountShare)],
|
|
3114
3494
|
["win_rate", formatMdPercent(summary.winRate)],
|
|
3115
3495
|
["total_profit", formatMdNumber(summary.totalProfit)],
|
|
3116
3496
|
["gross_profit", formatMdNumber(summary.grossProfit)],
|
|
@@ -3139,15 +3519,22 @@ var summaryMetricRows = (summary) => [
|
|
|
3139
3519
|
var pocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
3140
3520
|
index + 1,
|
|
3141
3521
|
pocket.summary.support,
|
|
3522
|
+
pocket.summary.events,
|
|
3523
|
+
pocket.summary.maxBatch,
|
|
3142
3524
|
formatMdPercent(pocket.summary.supportRatio),
|
|
3143
3525
|
formatMdPercent(pocket.summary.winRate),
|
|
3144
3526
|
formatMdNumber(pocket.summary.profitFactor),
|
|
3145
3527
|
formatMdNumber(pocket.summary.totalProfit),
|
|
3528
|
+
pocket.objectiveSummary ? formatMdNumber(pocket.objectiveSummary.totalProfit) : "n/a",
|
|
3146
3529
|
formatMdNumber(pocket.summary.maxDrawdown),
|
|
3147
3530
|
pocket.validationSummary?.support ?? "n/a",
|
|
3148
3531
|
pocket.validationSummary ? formatMdPercent(pocket.validationSummary.winRate) : "n/a",
|
|
3149
3532
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.profitFactor) : "n/a",
|
|
3150
3533
|
pocket.validationSummary ? formatMdNumber(pocket.validationSummary.totalProfit) : "n/a",
|
|
3534
|
+
pocket.testSummary?.support ?? "n/a",
|
|
3535
|
+
pocket.testSummary ? formatMdNumber(pocket.testSummary.profitFactor) : "n/a",
|
|
3536
|
+
pocket.testSummary ? formatMdNumber(pocket.testSummary.totalProfit) : "n/a",
|
|
3537
|
+
pocket.testObjectiveSummary ? formatMdNumber(pocket.testObjectiveSummary.totalProfit) : "n/a",
|
|
3151
3538
|
formatMdNumber(pocket.summary.avgTradesPerDay),
|
|
3152
3539
|
pocket.summary.losingMonths,
|
|
3153
3540
|
formatMdNumber(pocket.score),
|
|
@@ -3161,6 +3548,13 @@ var buildAiPocketMarkdownReport = ({
|
|
|
3161
3548
|
errors
|
|
3162
3549
|
}) => {
|
|
3163
3550
|
const generatedIso = new Date(generatedAt).toISOString();
|
|
3551
|
+
const featurePolicyAuditRows = Object.entries(
|
|
3552
|
+
run.featurePolicyAudit ?? {}
|
|
3553
|
+
).map(([classification, audit]) => [
|
|
3554
|
+
classification,
|
|
3555
|
+
audit?.paths ?? 0,
|
|
3556
|
+
audit?.samples.join(", ") ?? ""
|
|
3557
|
+
]);
|
|
3164
3558
|
const lines = [
|
|
3165
3559
|
"# AI Pocket Search Report",
|
|
3166
3560
|
"",
|
|
@@ -3176,6 +3570,7 @@ var buildAiPocketMarkdownReport = ({
|
|
|
3176
3570
|
["selected_rows", run.selectedRows],
|
|
3177
3571
|
["evaluated_rows", run.evaluatedRows],
|
|
3178
3572
|
["scope", run.scope],
|
|
3573
|
+
["objective", run.objective ?? pocketSearch.objective],
|
|
3179
3574
|
["direction", run.direction ?? "all"],
|
|
3180
3575
|
["scope_rows", run.scopeRows],
|
|
3181
3576
|
["train_rows", run.trainRows],
|
|
@@ -3199,15 +3594,44 @@ var buildAiPocketMarkdownReport = ({
|
|
|
3199
3594
|
["min_quality", run.minQuality],
|
|
3200
3595
|
["max_depth", run.search.maxDepth],
|
|
3201
3596
|
["min_support", run.search.minSupport],
|
|
3597
|
+
["min_events", run.search.minEvents ?? 1],
|
|
3598
|
+
["min_validation_events", run.search.minValidationEvents ?? 0],
|
|
3599
|
+
["max_batch", run.search.maxBatch ?? "off"],
|
|
3600
|
+
[
|
|
3601
|
+
"max_event_count_share",
|
|
3602
|
+
run.search.maxEventCountShare == null ? "off" : formatMdPercent(run.search.maxEventCountShare)
|
|
3603
|
+
],
|
|
3604
|
+
[
|
|
3605
|
+
"max_symbol_count_share",
|
|
3606
|
+
run.search.maxSymbolCountShare == null ? "off" : formatMdPercent(run.search.maxSymbolCountShare)
|
|
3607
|
+
],
|
|
3608
|
+
[
|
|
3609
|
+
"allow_risk_regression",
|
|
3610
|
+
run.search.allowRiskRegression ? "yes" : "no"
|
|
3611
|
+
],
|
|
3612
|
+
[
|
|
3613
|
+
"require_validation_eligibility",
|
|
3614
|
+
run.search.requireValidationEligibility ? "yes" : "no"
|
|
3615
|
+
],
|
|
3202
3616
|
["max_atomic_predicates", run.search.maxAtomicPredicates],
|
|
3203
3617
|
["max_combinations", run.search.maxCombinations],
|
|
3204
3618
|
["include_symbol", run.includeSymbol ? "on" : "off"],
|
|
3205
3619
|
["include_gate_context", run.includeGateContext ? "on" : "off"],
|
|
3206
3620
|
["feature_profile", run.featureProfile ?? "all"],
|
|
3621
|
+
["feature_policy", run.featurePolicy ?? "all"],
|
|
3207
3622
|
["report_path", run.reportPath]
|
|
3208
3623
|
]
|
|
3209
3624
|
),
|
|
3210
3625
|
"",
|
|
3626
|
+
...featurePolicyAuditRows.length ? [
|
|
3627
|
+
"## Feature Policy Audit",
|
|
3628
|
+
"",
|
|
3629
|
+
markdownTable(
|
|
3630
|
+
["Classification", "Excluded paths", "Samples"],
|
|
3631
|
+
featurePolicyAuditRows
|
|
3632
|
+
),
|
|
3633
|
+
""
|
|
3634
|
+
] : [],
|
|
3211
3635
|
"## Dataset Files",
|
|
3212
3636
|
"",
|
|
3213
3637
|
...run.filePaths.map((filePath) => `- \`${filePath}\``),
|
|
@@ -3244,6 +3668,33 @@ var buildAiPocketMarkdownReport = ({
|
|
|
3244
3668
|
),
|
|
3245
3669
|
""
|
|
3246
3670
|
] : [],
|
|
3671
|
+
...pocketSearch.testBaseline ? [
|
|
3672
|
+
"## Untouched Test Baseline",
|
|
3673
|
+
"",
|
|
3674
|
+
markdownTable(
|
|
3675
|
+
["Metric", "Value"],
|
|
3676
|
+
summaryMetricRows(pocketSearch.testBaseline)
|
|
3677
|
+
),
|
|
3678
|
+
""
|
|
3679
|
+
] : [],
|
|
3680
|
+
...pocketSearch.objectiveBaseline ? [
|
|
3681
|
+
"## Current Gate Train Baseline",
|
|
3682
|
+
"",
|
|
3683
|
+
markdownTable(
|
|
3684
|
+
["Metric", "Value"],
|
|
3685
|
+
summaryMetricRows(pocketSearch.objectiveBaseline)
|
|
3686
|
+
),
|
|
3687
|
+
""
|
|
3688
|
+
] : [],
|
|
3689
|
+
...pocketSearch.testObjectiveBaseline ? [
|
|
3690
|
+
"## Current Gate Untouched Test Baseline",
|
|
3691
|
+
"",
|
|
3692
|
+
markdownTable(
|
|
3693
|
+
["Metric", "Value"],
|
|
3694
|
+
summaryMetricRows(pocketSearch.testObjectiveBaseline)
|
|
3695
|
+
),
|
|
3696
|
+
""
|
|
3697
|
+
] : [],
|
|
3247
3698
|
"## Search Stats",
|
|
3248
3699
|
"",
|
|
3249
3700
|
markdownTable(
|
|
@@ -3252,9 +3703,11 @@ var buildAiPocketMarkdownReport = ({
|
|
|
3252
3703
|
["feature_keys", pocketSearch.stats.featureKeys],
|
|
3253
3704
|
["predicates", pocketSearch.stats.predicates],
|
|
3254
3705
|
["atomic_used", pocketSearch.stats.atomicPredicatesUsed],
|
|
3706
|
+
["feature_families", pocketSearch.stats.featureFamiliesUsed.join(", ")],
|
|
3255
3707
|
["estimated_combinations", pocketSearch.stats.estimatedCombinations],
|
|
3256
3708
|
["combinations_evaluated", pocketSearch.stats.combinationsEvaluated],
|
|
3257
3709
|
["validation_rows", pocketSearch.stats.validationRows],
|
|
3710
|
+
["test_rows", pocketSearch.stats.testRows],
|
|
3258
3711
|
[
|
|
3259
3712
|
"duplicate_pockets_skipped",
|
|
3260
3713
|
pocketSearch.stats.duplicatePocketsSkipped
|
|
@@ -3269,15 +3722,22 @@ var buildAiPocketMarkdownReport = ({
|
|
|
3269
3722
|
[
|
|
3270
3723
|
"#",
|
|
3271
3724
|
"N",
|
|
3725
|
+
"Events",
|
|
3726
|
+
"Max batch",
|
|
3272
3727
|
"Support",
|
|
3273
3728
|
"WR",
|
|
3274
3729
|
"PF",
|
|
3275
3730
|
"PNL",
|
|
3731
|
+
"Objective PNL",
|
|
3276
3732
|
"Max DD",
|
|
3277
3733
|
"Val N",
|
|
3278
3734
|
"Val WR",
|
|
3279
3735
|
"Val PF",
|
|
3280
3736
|
"Val PNL",
|
|
3737
|
+
"Test N",
|
|
3738
|
+
"Test PF",
|
|
3739
|
+
"Test PNL",
|
|
3740
|
+
"Test objective PNL",
|
|
3281
3741
|
"Trades/Day",
|
|
3282
3742
|
"Losing Months",
|
|
3283
3743
|
"Score",
|
|
@@ -3292,15 +3752,22 @@ var buildAiPocketMarkdownReport = ({
|
|
|
3292
3752
|
[
|
|
3293
3753
|
"#",
|
|
3294
3754
|
"N",
|
|
3755
|
+
"Events",
|
|
3756
|
+
"Max batch",
|
|
3295
3757
|
"Support",
|
|
3296
3758
|
"WR",
|
|
3297
3759
|
"PF",
|
|
3298
3760
|
"PNL",
|
|
3761
|
+
"Objective PNL",
|
|
3299
3762
|
"Max DD",
|
|
3300
3763
|
"Val N",
|
|
3301
3764
|
"Val WR",
|
|
3302
3765
|
"Val PF",
|
|
3303
3766
|
"Val PNL",
|
|
3767
|
+
"Test N",
|
|
3768
|
+
"Test PF",
|
|
3769
|
+
"Test PNL",
|
|
3770
|
+
"Test objective PNL",
|
|
3304
3771
|
"Trades/Day",
|
|
3305
3772
|
"Losing Months",
|
|
3306
3773
|
"Score",
|
|
@@ -3478,6 +3945,46 @@ import_args.default.option(
|
|
|
3478
3945
|
"Minimum validation rows required for positive pockets (0 = auto)",
|
|
3479
3946
|
0
|
|
3480
3947
|
);
|
|
3948
|
+
import_args.default.option(
|
|
3949
|
+
["H", "minEvents"],
|
|
3950
|
+
"Minimum independent timestamp events required (0 = auto)",
|
|
3951
|
+
0
|
|
3952
|
+
);
|
|
3953
|
+
import_args.default.option(
|
|
3954
|
+
["J", "minValidationEvents"],
|
|
3955
|
+
"Minimum validation timestamp events required (0 = auto)",
|
|
3956
|
+
0
|
|
3957
|
+
);
|
|
3958
|
+
import_args.default.option(
|
|
3959
|
+
["X", "maxBatch"],
|
|
3960
|
+
"Maximum selected rows at one timestamp (0 disables)",
|
|
3961
|
+
5
|
|
3962
|
+
);
|
|
3963
|
+
import_args.default.option(
|
|
3964
|
+
["U", "maxEventCountShare"],
|
|
3965
|
+
"Maximum row share contributed by one timestamp event",
|
|
3966
|
+
"0.25"
|
|
3967
|
+
);
|
|
3968
|
+
import_args.default.option(
|
|
3969
|
+
["Z", "maxSymbolCountShare"],
|
|
3970
|
+
"Maximum row share contributed by one symbol",
|
|
3971
|
+
"0.5"
|
|
3972
|
+
);
|
|
3973
|
+
import_args.default.option(
|
|
3974
|
+
["A", "objective"],
|
|
3975
|
+
"Search objective: auto, standalone, add-to-gate, or filter-gate",
|
|
3976
|
+
"auto"
|
|
3977
|
+
);
|
|
3978
|
+
import_args.default.option(
|
|
3979
|
+
["G", "allowRiskRegression"],
|
|
3980
|
+
"Allow incremental pockets to worsen q4+ PF, PnL, drawdown, or loss streak",
|
|
3981
|
+
false
|
|
3982
|
+
);
|
|
3983
|
+
import_args.default.option(
|
|
3984
|
+
["L", "allowValidationRegression"],
|
|
3985
|
+
"Keep train-positive pockets that fail validation PnL/PF thresholds",
|
|
3986
|
+
false
|
|
3987
|
+
);
|
|
3481
3988
|
import_args.default.option(
|
|
3482
3989
|
["D", "dedupeEquivalentSelections"],
|
|
3483
3990
|
"Collapse pockets that select the same train rows",
|
|
@@ -3495,6 +4002,11 @@ import_args.default.option(
|
|
|
3495
4002
|
"Feature extraction profile: compact or all",
|
|
3496
4003
|
"all"
|
|
3497
4004
|
);
|
|
4005
|
+
import_args.default.option(
|
|
4006
|
+
["K", "featurePolicy"],
|
|
4007
|
+
"Feature policy: causal-stationary or all",
|
|
4008
|
+
"causal-stationary"
|
|
4009
|
+
);
|
|
3498
4010
|
import_args.default.option(
|
|
3499
4011
|
["r", "reportDir"],
|
|
3500
4012
|
"Directory for generated Markdown reports",
|
|
@@ -3599,10 +4111,41 @@ var normalizeRatio = (value, fallback) => {
|
|
|
3599
4111
|
}
|
|
3600
4112
|
return Math.max(0, Math.min(0.9, parsed));
|
|
3601
4113
|
};
|
|
4114
|
+
var normalizeUnitRatio = (value, fallback) => {
|
|
4115
|
+
const parsed = Number(value);
|
|
4116
|
+
return Number.isFinite(parsed) ? Math.max(0, Math.min(1, parsed)) : fallback;
|
|
4117
|
+
};
|
|
3602
4118
|
var normalizeFeatureProfile = (value) => {
|
|
3603
4119
|
const normalized = String(value || "all").trim().toLowerCase();
|
|
3604
4120
|
return normalized === "compact" ? "compact" : "all";
|
|
3605
4121
|
};
|
|
4122
|
+
var normalizeFeaturePolicy = (value) => {
|
|
4123
|
+
const normalized = String(value || "causal-stationary").trim().toLowerCase();
|
|
4124
|
+
if (!["causal-stationary", "all"].includes(normalized)) {
|
|
4125
|
+
throw new Error(
|
|
4126
|
+
`Unsupported --featurePolicy "${normalized}". Use causal-stationary or all.`
|
|
4127
|
+
);
|
|
4128
|
+
}
|
|
4129
|
+
return normalized;
|
|
4130
|
+
};
|
|
4131
|
+
var normalizeObjective = (value, scope) => {
|
|
4132
|
+
const normalized = String(value || "auto").trim().toLowerCase();
|
|
4133
|
+
if (normalized === "auto") {
|
|
4134
|
+
if (scope === "approved") {
|
|
4135
|
+
return "filter-gate";
|
|
4136
|
+
}
|
|
4137
|
+
if (scope === "rejected" || scope === "candidates") {
|
|
4138
|
+
return "add-to-gate";
|
|
4139
|
+
}
|
|
4140
|
+
return "standalone";
|
|
4141
|
+
}
|
|
4142
|
+
if (!["standalone", "add-to-gate", "filter-gate"].includes(normalized)) {
|
|
4143
|
+
throw new Error(
|
|
4144
|
+
`Unsupported --objective "${normalized}". Use auto, standalone, add-to-gate, or filter-gate.`
|
|
4145
|
+
);
|
|
4146
|
+
}
|
|
4147
|
+
return normalized;
|
|
4148
|
+
};
|
|
3606
4149
|
var normalizeQuality = (analysis) => {
|
|
3607
4150
|
const quality = Number(analysis?.quality);
|
|
3608
4151
|
return Number.isFinite(quality) ? Math.round(quality) : null;
|
|
@@ -3757,7 +4300,7 @@ var resolveScopeRows = (rows, scope) => {
|
|
|
3757
4300
|
return rows.filter((row) => !row.aiApproved);
|
|
3758
4301
|
}
|
|
3759
4302
|
if (scope === "candidates") {
|
|
3760
|
-
return rows.filter((row) => row.modelCandidate);
|
|
4303
|
+
return rows.filter((row) => row.modelCandidate && !row.aiApproved);
|
|
3761
4304
|
}
|
|
3762
4305
|
return rows;
|
|
3763
4306
|
};
|
|
@@ -3768,6 +4311,13 @@ var printSection = (title, table) => {
|
|
|
3768
4311
|
};
|
|
3769
4312
|
var buildSummaryRows = (summary) => [
|
|
3770
4313
|
["rows", import_chalk.default.cyan(String(summary.support))],
|
|
4314
|
+
["events", import_chalk.default.cyan(String(summary.events))],
|
|
4315
|
+
["event_balanced_profit", colorizeProfit(summary.eventBalancedProfit)],
|
|
4316
|
+
["trades_per_event", colorizeNumber(summary.tradesPerEvent)],
|
|
4317
|
+
["p95_batch", import_chalk.default.cyan(String(summary.p95Batch))],
|
|
4318
|
+
["max_batch", import_chalk.default.cyan(String(summary.maxBatch))],
|
|
4319
|
+
["top_event_count_share", colorizeRatio(summary.topEventCountShare)],
|
|
4320
|
+
["top_symbol_count_share", colorizeRatio(summary.topSymbolCountShare)],
|
|
3771
4321
|
["win_rate", colorizeRatio(summary.winRate)],
|
|
3772
4322
|
["total_profit", colorizeProfit(summary.totalProfit)],
|
|
3773
4323
|
["gross_profit", colorizeProfit(summary.grossProfit)],
|
|
@@ -3796,15 +4346,22 @@ var buildSummaryRows = (summary) => [
|
|
|
3796
4346
|
var buildPocketRows = (pockets) => pockets.map((pocket, index) => [
|
|
3797
4347
|
import_chalk.default.gray(String(index + 1)),
|
|
3798
4348
|
import_chalk.default.cyan(String(pocket.summary.support)),
|
|
4349
|
+
import_chalk.default.cyan(String(pocket.summary.events)),
|
|
4350
|
+
import_chalk.default.cyan(String(pocket.summary.maxBatch)),
|
|
3799
4351
|
colorizeRatio(pocket.summary.supportRatio),
|
|
3800
4352
|
colorizeRatio(pocket.summary.winRate),
|
|
3801
4353
|
colorizeNumber(pocket.summary.profitFactor),
|
|
3802
4354
|
colorizeProfit(pocket.summary.totalProfit),
|
|
4355
|
+
pocket.objectiveSummary ? colorizeProfit(pocket.objectiveSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
3803
4356
|
colorizeProfit(-pocket.summary.maxDrawdown),
|
|
3804
4357
|
pocket.validationSummary ? import_chalk.default.cyan(String(pocket.validationSummary.support)) : import_chalk.default.gray("n/a"),
|
|
3805
4358
|
pocket.validationSummary ? colorizeRatio(pocket.validationSummary.winRate) : import_chalk.default.gray("n/a"),
|
|
3806
4359
|
pocket.validationSummary ? colorizeNumber(pocket.validationSummary.profitFactor) : import_chalk.default.gray("n/a"),
|
|
3807
4360
|
pocket.validationSummary ? colorizeProfit(pocket.validationSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
4361
|
+
pocket.testSummary ? import_chalk.default.cyan(String(pocket.testSummary.support)) : import_chalk.default.gray("n/a"),
|
|
4362
|
+
pocket.testSummary ? colorizeNumber(pocket.testSummary.profitFactor) : import_chalk.default.gray("n/a"),
|
|
4363
|
+
pocket.testSummary ? colorizeProfit(pocket.testSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
4364
|
+
pocket.testObjectiveSummary ? colorizeProfit(pocket.testObjectiveSummary.totalProfit) : import_chalk.default.gray("n/a"),
|
|
3808
4365
|
colorizeNumber(pocket.summary.avgTradesPerDay),
|
|
3809
4366
|
import_chalk.default.yellow(String(pocket.summary.losingMonths)),
|
|
3810
4367
|
colorizeNumber(pocket.score),
|
|
@@ -3915,16 +4472,45 @@ var main = async () => {
|
|
|
3915
4472
|
flags.minValidationSupport,
|
|
3916
4473
|
0
|
|
3917
4474
|
);
|
|
4475
|
+
const explicitMinEvents = normalizeInt(flags.minEvents, 0);
|
|
4476
|
+
const explicitMinValidationEvents = normalizeInt(
|
|
4477
|
+
flags.minValidationEvents,
|
|
4478
|
+
0
|
|
4479
|
+
);
|
|
4480
|
+
const maxBatch = normalizeInt(flags.maxBatch, 5);
|
|
4481
|
+
const maxEventCountShare = normalizeUnitRatio(
|
|
4482
|
+
readAiPocketSearchCliOption({
|
|
4483
|
+
argv: process.argv,
|
|
4484
|
+
longName: "maxEventCountShare",
|
|
4485
|
+
shortName: "U"
|
|
4486
|
+
}) ?? flags.maxEventCountShare,
|
|
4487
|
+
0.25
|
|
4488
|
+
);
|
|
4489
|
+
const maxSymbolCountShare = normalizeUnitRatio(
|
|
4490
|
+
readAiPocketSearchCliOption({
|
|
4491
|
+
argv: process.argv,
|
|
4492
|
+
longName: "maxSymbolCountShare",
|
|
4493
|
+
shortName: "Z"
|
|
4494
|
+
}) ?? flags.maxSymbolCountShare,
|
|
4495
|
+
0.5
|
|
4496
|
+
);
|
|
4497
|
+
const objective = normalizeObjective(flags.objective, scope);
|
|
4498
|
+
const allowRiskRegression = Boolean(flags.allowRiskRegression);
|
|
4499
|
+
const requireValidationEligibility = !Boolean(
|
|
4500
|
+
flags.allowValidationRegression
|
|
4501
|
+
);
|
|
3918
4502
|
const dedupeEquivalentSelections = Boolean(flags.dedupeEquivalentSelections);
|
|
3919
4503
|
const top = normalizePositiveInt(flags.top, 30);
|
|
3920
4504
|
const includeSymbol = Boolean(flags.includeSymbol);
|
|
3921
4505
|
const includeGateContext = Boolean(flags.includeGateContext);
|
|
3922
4506
|
const featureProfile = normalizeFeatureProfile(flags.featureProfile);
|
|
4507
|
+
const featurePolicy = normalizeFeaturePolicy(flags.featurePolicy);
|
|
3923
4508
|
const jsonOutput = Boolean(flags.json);
|
|
3924
4509
|
const outputPath = String(flags.output || "").trim();
|
|
3925
4510
|
const reportDir = String(flags.reportDir || "data/ai/output").trim();
|
|
3926
4511
|
const explicitReportFile = String(flags.reportFile || "").trim();
|
|
3927
4512
|
const generatedAt = Date.now();
|
|
4513
|
+
const excludedFeaturePaths = /* @__PURE__ */ new Map();
|
|
3928
4514
|
await (0, import_ai2.ensureAiStrategyPluginsLoaded)();
|
|
3929
4515
|
const filePaths = await resolveMergedDatasetFiles({
|
|
3930
4516
|
outDir,
|
|
@@ -4029,7 +4615,13 @@ var main = async () => {
|
|
|
4029
4615
|
gateContext,
|
|
4030
4616
|
includeSymbol,
|
|
4031
4617
|
includeGateContext,
|
|
4032
|
-
featureProfile
|
|
4618
|
+
featureProfile,
|
|
4619
|
+
featurePolicy,
|
|
4620
|
+
onFeatureExcluded: ({ path: featurePath, classification }) => {
|
|
4621
|
+
const paths = excludedFeaturePaths.get(classification) ?? /* @__PURE__ */ new Set();
|
|
4622
|
+
paths.add(featurePath);
|
|
4623
|
+
excludedFeaturePaths.set(classification, paths);
|
|
4624
|
+
}
|
|
4033
4625
|
})
|
|
4034
4626
|
});
|
|
4035
4627
|
bar?.tick(1, {
|
|
@@ -4050,10 +4642,24 @@ var main = async () => {
|
|
|
4050
4642
|
}
|
|
4051
4643
|
}
|
|
4052
4644
|
});
|
|
4053
|
-
const
|
|
4054
|
-
const scopeRows =
|
|
4055
|
-
const
|
|
4645
|
+
const directionRows = direction ? rows.filter((row) => row.direction === direction) : rows;
|
|
4646
|
+
const scopeRows = resolveScopeRows(directionRows, scope);
|
|
4647
|
+
const split = splitAiPocketResearchRowsByTimestamp(
|
|
4648
|
+
directionRows,
|
|
4649
|
+
validationSplit,
|
|
4650
|
+
testSplit
|
|
4651
|
+
);
|
|
4652
|
+
const trainRows = resolveScopeRows(split.trainRows, scope);
|
|
4653
|
+
const validationRows = resolveScopeRows(split.validationRows, scope);
|
|
4654
|
+
const testRows = resolveScopeRows(split.testRows, scope);
|
|
4655
|
+
const baselineRows = split.trainRows.filter((row) => row.aiApproved);
|
|
4656
|
+
const validationBaselineRows = split.validationRows.filter(
|
|
4657
|
+
(row) => row.aiApproved
|
|
4658
|
+
);
|
|
4659
|
+
const testBaselineRows = split.testRows.filter((row) => row.aiApproved);
|
|
4056
4660
|
const minValidationSupport = explicitMinValidationSupport > 0 ? explicitMinValidationSupport : validationRows.length ? Math.max(3, Math.ceil(minSupport * validationSplit * 0.5)) : 0;
|
|
4661
|
+
const minEvents = explicitMinEvents > 0 ? explicitMinEvents : Math.max(5, Math.ceil(minSupport * 0.5));
|
|
4662
|
+
const minValidationEvents = explicitMinValidationEvents > 0 ? explicitMinValidationEvents : validationRows.length ? Math.max(2, Math.ceil(minEvents * validationSplit * 0.5)) : 0;
|
|
4057
4663
|
const currentGateSummary = summarizeAiTrainEvaluations(rows);
|
|
4058
4664
|
const currentGateQualityThresholds = summarizeAiTrainEvaluationsByQualityThreshold(rows, qualityThresholds);
|
|
4059
4665
|
let searchBar = null;
|
|
@@ -4068,7 +4674,19 @@ var main = async () => {
|
|
|
4068
4674
|
maxCombinations,
|
|
4069
4675
|
top,
|
|
4070
4676
|
validationRows,
|
|
4677
|
+
testRows,
|
|
4071
4678
|
minValidationSupport,
|
|
4679
|
+
minEvents,
|
|
4680
|
+
minValidationEvents,
|
|
4681
|
+
...maxBatch > 0 ? { maxBatch } : {},
|
|
4682
|
+
maxEventCountShare,
|
|
4683
|
+
maxSymbolCountShare,
|
|
4684
|
+
objective,
|
|
4685
|
+
baselineRows,
|
|
4686
|
+
validationBaselineRows,
|
|
4687
|
+
testBaselineRows,
|
|
4688
|
+
allowRiskRegression,
|
|
4689
|
+
requireValidationEligibility,
|
|
4072
4690
|
dedupeEquivalentSelections,
|
|
4073
4691
|
progressInterval: 250,
|
|
4074
4692
|
onProgress: (progress) => {
|
|
@@ -4133,6 +4751,17 @@ var main = async () => {
|
|
|
4133
4751
|
includeSymbol,
|
|
4134
4752
|
includeGateContext,
|
|
4135
4753
|
featureProfile,
|
|
4754
|
+
featurePolicy,
|
|
4755
|
+
featurePolicyAudit: Object.fromEntries(
|
|
4756
|
+
[...excludedFeaturePaths.entries()].map(([classification, paths]) => [
|
|
4757
|
+
classification,
|
|
4758
|
+
{
|
|
4759
|
+
paths: paths.size,
|
|
4760
|
+
samples: [...paths].sort().slice(0, 5)
|
|
4761
|
+
}
|
|
4762
|
+
])
|
|
4763
|
+
),
|
|
4764
|
+
objective,
|
|
4136
4765
|
validationSplit,
|
|
4137
4766
|
testSplit,
|
|
4138
4767
|
minValidationSupport,
|
|
@@ -4145,6 +4774,13 @@ var main = async () => {
|
|
|
4145
4774
|
minTotalProfit,
|
|
4146
4775
|
maxAtomicPredicates,
|
|
4147
4776
|
maxCombinations,
|
|
4777
|
+
minEvents,
|
|
4778
|
+
minValidationEvents,
|
|
4779
|
+
...maxBatch > 0 ? { maxBatch } : {},
|
|
4780
|
+
maxEventCountShare,
|
|
4781
|
+
maxSymbolCountShare,
|
|
4782
|
+
allowRiskRegression,
|
|
4783
|
+
requireValidationEligibility,
|
|
4148
4784
|
validationSplit,
|
|
4149
4785
|
testSplit,
|
|
4150
4786
|
minValidationSupport,
|
|
@@ -4188,6 +4824,7 @@ var main = async () => {
|
|
|
4188
4824
|
["selected", import_chalk.default.blue(String(selectedRows))],
|
|
4189
4825
|
["evaluated", import_chalk.default.blue(String(rows.length))],
|
|
4190
4826
|
["scope", import_chalk.default.yellow(scope)],
|
|
4827
|
+
["objective", import_chalk.default.yellow(objective)],
|
|
4191
4828
|
["direction", direction ? import_chalk.default.yellow(direction) : import_chalk.default.gray("all")],
|
|
4192
4829
|
["scope_rows", import_chalk.default.blue(String(scopeRows.length))],
|
|
4193
4830
|
["train_rows", import_chalk.default.blue(String(trainRows.length))],
|
|
@@ -4216,6 +4853,11 @@ var main = async () => {
|
|
|
4216
4853
|
["min_quality", import_chalk.default.magenta(String(minQuality))],
|
|
4217
4854
|
["max_depth", import_chalk.default.magenta(String(maxDepth))],
|
|
4218
4855
|
["min_support", import_chalk.default.magenta(String(minSupport))],
|
|
4856
|
+
["min_events", import_chalk.default.magenta(String(minEvents))],
|
|
4857
|
+
["min_validation_events", import_chalk.default.magenta(String(minValidationEvents))],
|
|
4858
|
+
["max_batch", import_chalk.default.magenta(maxBatch > 0 ? String(maxBatch) : "off")],
|
|
4859
|
+
["max_event_share", import_chalk.default.magenta(formatRatio(maxEventCountShare))],
|
|
4860
|
+
["max_symbol_share", import_chalk.default.magenta(formatRatio(maxSymbolCountShare))],
|
|
4219
4861
|
["max_atomic_predicates", import_chalk.default.magenta(String(maxAtomicPredicates))],
|
|
4220
4862
|
["max_combinations", import_chalk.default.magenta(String(maxCombinations))],
|
|
4221
4863
|
["validation_split", import_chalk.default.magenta(formatRatio(validationSplit))],
|
|
@@ -4234,6 +4876,15 @@ var main = async () => {
|
|
|
4234
4876
|
includeGateContext ? import_chalk.default.yellow("on") : import_chalk.default.gray("off")
|
|
4235
4877
|
],
|
|
4236
4878
|
["feature_profile", import_chalk.default.magenta(featureProfile)],
|
|
4879
|
+
["feature_policy", import_chalk.default.magenta(featurePolicy)],
|
|
4880
|
+
[
|
|
4881
|
+
"allow_risk_regression",
|
|
4882
|
+
allowRiskRegression ? import_chalk.default.yellow("on") : import_chalk.default.green("off")
|
|
4883
|
+
],
|
|
4884
|
+
[
|
|
4885
|
+
"validation_eligibility",
|
|
4886
|
+
requireValidationEligibility ? import_chalk.default.green("required") : import_chalk.default.yellow("off")
|
|
4887
|
+
],
|
|
4237
4888
|
["report", import_chalk.default.gray(reportPath)],
|
|
4238
4889
|
["output", outputPath ? import_chalk.default.gray(outputPath) : import_chalk.default.gray("off")]
|
|
4239
4890
|
]
|
|
@@ -4271,6 +4922,24 @@ var main = async () => {
|
|
|
4271
4922
|
)
|
|
4272
4923
|
);
|
|
4273
4924
|
}
|
|
4925
|
+
if (search.testBaseline) {
|
|
4926
|
+
printSection(
|
|
4927
|
+
"UNTOUCHED TEST BASELINE",
|
|
4928
|
+
createTable(
|
|
4929
|
+
[import_chalk.default.gray("METRIC"), import_chalk.default.gray("VALUE")],
|
|
4930
|
+
buildSummaryRows(search.testBaseline)
|
|
4931
|
+
)
|
|
4932
|
+
);
|
|
4933
|
+
}
|
|
4934
|
+
if (search.objectiveBaseline) {
|
|
4935
|
+
printSection(
|
|
4936
|
+
"CURRENT GATE TRAIN BASELINE",
|
|
4937
|
+
createTable(
|
|
4938
|
+
[import_chalk.default.gray("METRIC"), import_chalk.default.gray("VALUE")],
|
|
4939
|
+
buildSummaryRows(search.objectiveBaseline)
|
|
4940
|
+
)
|
|
4941
|
+
);
|
|
4942
|
+
}
|
|
4274
4943
|
printSection(
|
|
4275
4944
|
"SEARCH STATS",
|
|
4276
4945
|
createTable(
|
|
@@ -4279,6 +4948,10 @@ var main = async () => {
|
|
|
4279
4948
|
["feature_keys", import_chalk.default.cyan(String(search.stats.featureKeys))],
|
|
4280
4949
|
["predicates", import_chalk.default.cyan(String(search.stats.predicates))],
|
|
4281
4950
|
["atomic_used", import_chalk.default.cyan(String(search.stats.atomicPredicatesUsed))],
|
|
4951
|
+
[
|
|
4952
|
+
"feature_families",
|
|
4953
|
+
import_chalk.default.cyan(search.stats.featureFamiliesUsed.join(", "))
|
|
4954
|
+
],
|
|
4282
4955
|
[
|
|
4283
4956
|
"estimated_combinations",
|
|
4284
4957
|
import_chalk.default.cyan(String(search.stats.estimatedCombinations))
|
|
@@ -4288,6 +4961,7 @@ var main = async () => {
|
|
|
4288
4961
|
import_chalk.default.cyan(String(search.stats.combinationsEvaluated))
|
|
4289
4962
|
],
|
|
4290
4963
|
["validation_rows", import_chalk.default.cyan(String(search.stats.validationRows))],
|
|
4964
|
+
["test_rows", import_chalk.default.cyan(String(search.stats.testRows))],
|
|
4291
4965
|
[
|
|
4292
4966
|
"duplicate_pockets_skipped",
|
|
4293
4967
|
import_chalk.default.cyan(String(search.stats.duplicatePocketsSkipped))
|
|
@@ -4305,15 +4979,22 @@ var main = async () => {
|
|
|
4305
4979
|
[
|
|
4306
4980
|
import_chalk.default.gray("#"),
|
|
4307
4981
|
import_chalk.default.gray("N"),
|
|
4982
|
+
import_chalk.default.gray("EVENTS"),
|
|
4983
|
+
import_chalk.default.gray("MAX_B"),
|
|
4308
4984
|
import_chalk.default.gray("SUP"),
|
|
4309
4985
|
import_chalk.default.gray("WR"),
|
|
4310
4986
|
import_chalk.default.gray("PF"),
|
|
4311
4987
|
import_chalk.default.gray("PNL"),
|
|
4988
|
+
import_chalk.default.gray("OBJ_PNL"),
|
|
4312
4989
|
import_chalk.default.gray("MAX_DD"),
|
|
4313
4990
|
import_chalk.default.gray("VAL_N"),
|
|
4314
4991
|
import_chalk.default.gray("VAL_WR"),
|
|
4315
4992
|
import_chalk.default.gray("VAL_PF"),
|
|
4316
4993
|
import_chalk.default.gray("VAL_PNL"),
|
|
4994
|
+
import_chalk.default.gray("TEST_N"),
|
|
4995
|
+
import_chalk.default.gray("TEST_PF"),
|
|
4996
|
+
import_chalk.default.gray("TEST_PNL"),
|
|
4997
|
+
import_chalk.default.gray("TEST_OBJ"),
|
|
4317
4998
|
import_chalk.default.gray("TR/D"),
|
|
4318
4999
|
import_chalk.default.gray("LOSS_M"),
|
|
4319
5000
|
import_chalk.default.gray("SCORE"),
|
|
@@ -4328,15 +5009,22 @@ var main = async () => {
|
|
|
4328
5009
|
[
|
|
4329
5010
|
import_chalk.default.gray("#"),
|
|
4330
5011
|
import_chalk.default.gray("N"),
|
|
5012
|
+
import_chalk.default.gray("EVENTS"),
|
|
5013
|
+
import_chalk.default.gray("MAX_B"),
|
|
4331
5014
|
import_chalk.default.gray("SUP"),
|
|
4332
5015
|
import_chalk.default.gray("WR"),
|
|
4333
5016
|
import_chalk.default.gray("PF"),
|
|
4334
5017
|
import_chalk.default.gray("PNL"),
|
|
5018
|
+
import_chalk.default.gray("OBJ_PNL"),
|
|
4335
5019
|
import_chalk.default.gray("MAX_DD"),
|
|
4336
5020
|
import_chalk.default.gray("VAL_N"),
|
|
4337
5021
|
import_chalk.default.gray("VAL_WR"),
|
|
4338
5022
|
import_chalk.default.gray("VAL_PF"),
|
|
4339
5023
|
import_chalk.default.gray("VAL_PNL"),
|
|
5024
|
+
import_chalk.default.gray("TEST_N"),
|
|
5025
|
+
import_chalk.default.gray("TEST_PF"),
|
|
5026
|
+
import_chalk.default.gray("TEST_PNL"),
|
|
5027
|
+
import_chalk.default.gray("TEST_OBJ"),
|
|
4340
5028
|
import_chalk.default.gray("TR/D"),
|
|
4341
5029
|
import_chalk.default.gray("LOSS_M"),
|
|
4342
5030
|
import_chalk.default.gray("SCORE"),
|