@tradejs/cli 1.0.9 → 1.0.11
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/README.md +13 -4
- package/dist/cli.js +29531 -13520
- package/dist/lib/aiPocketSearch.js +1316 -0
- package/dist/lib/aiTrainCharts.js +711 -0
- package/dist/lib/aiTrainDataset.js +40 -0
- package/dist/lib/aiTrainEvaluationDump.js +76 -0
- package/dist/lib/aiTrainMetrics.js +148 -8
- package/dist/lib/aiTrainOptions.js +130 -0
- package/dist/lib/aiTrainQuarantine.js +199 -0
- package/dist/lib/aiTrainResearch.js +467 -0
- package/dist/lib/binanceMarketContextBackfill.js +841 -0
- package/dist/lib/binanceMarketData.js +392 -0
- package/dist/lib/coinMarketCapContextBackfill.js +1126 -0
- package/dist/lib/continuity.js +60 -0
- package/dist/lib/derivativesContextBackfill.js +490 -77
- package/dist/lib/executionCalibration.js +705 -0
- package/dist/lib/marketContextPrepare.js +4441 -0
- package/dist/lib/paritySummary.js +101 -0
- package/dist/lib/runBot.js +1 -0
- package/dist/lib/runEnvironment.js +2259 -0
- package/dist/lib/runFormatting.js +1657 -0
- package/dist/lib/runtimeDebugEvidence.js +526 -0
- package/dist/lib/runtimeModeConfig.js +53 -0
- package/dist/lib/runtimeParity.js +88 -11
- package/dist/lib/runtimeParityDetails.js +751 -0
- package/dist/lib/runtimeRedis.js +157 -0
- package/dist/lib/runtimeSignalsLoader.js +40 -6
- package/dist/lib/runtimeSignalsStorage.js +45 -22
- package/dist/lib/runtimeStrategyBacktest.js +134 -0
- package/dist/lib/runtimeTradeSync.js +263 -0
- package/dist/lib/telegramReports.js +9 -0
- package/dist/lib/tickerUniverseCache.js +116 -0
- package/dist/lib/timeWindow.js +3 -3
- package/dist/scripts/agentRun.js +14 -8
- package/dist/scripts/aiExport.js +1721 -7
- package/dist/scripts/aiExportSelect.js +16 -4
- package/dist/scripts/aiPocketSearch.js +4190 -0
- package/dist/scripts/aiTrain.js +1866 -87
- package/dist/scripts/backtest.js +4534 -803
- package/dist/scripts/binanceMarketIngest.js +565 -0
- package/dist/scripts/bot.js +16 -2
- package/dist/scripts/candlesMigrateProvider.js +32 -22
- package/dist/scripts/cleanDir.js +15 -2
- package/dist/scripts/cleanRedis.js +15 -2
- package/dist/scripts/cleanTests.js +38 -2
- package/dist/scripts/cleanupMarketContext.js +69 -0
- package/dist/scripts/continuity.js +148 -67
- package/dist/scripts/derivativesIngest.js +14 -4
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +14 -4
- package/dist/scripts/doctor.js +14 -4
- package/dist/scripts/executionCalibration.js +792 -0
- package/dist/scripts/infraCommon.js +18 -5
- package/dist/scripts/infraDown.js +14 -4
- package/dist/scripts/infraInit.js +32 -9
- package/dist/scripts/infraUp.js +24 -6
- package/dist/scripts/marketWs.js +222 -0
- package/dist/scripts/migration.js +15 -2
- package/dist/scripts/mlExport.js +1698 -10
- package/dist/scripts/mlExportSelect.js +16 -4
- package/dist/scripts/mlInspect.js +13 -3
- package/dist/scripts/mlTrainLatestSelect.js +14 -4
- package/dist/scripts/replay.js +8867 -0
- package/dist/scripts/replayRunner.js +8870 -0
- package/dist/scripts/replayRuntimeEvidence.js +868 -0
- package/dist/scripts/researchAuto.js +286 -59
- package/dist/scripts/results.js +3 -3
- package/dist/scripts/runtimeEvidence.js +605 -0
- package/dist/scripts/runtimeParity.js +6400 -1043
- package/dist/scripts/serverHealth.js +588 -0
- package/dist/scripts/signals.js +5628 -511
- package/dist/scripts/signalsDaemon.js +6205 -0
- package/dist/scripts/signalsSummary.js +833 -248
- package/dist/scripts/test-ml.js +25 -3
- package/dist/scripts/test.js +26 -1
- package/dist/scripts/user-add.js +15 -2
- package/dist/workers/testerWorker.js +130 -21
- package/package.json +18 -12
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/aiTrainDataset.ts
|
|
21
|
+
var aiTrainDataset_exports = {};
|
|
22
|
+
__export(aiTrainDataset_exports, {
|
|
23
|
+
extractSignalFromAiDatasetRow: () => extractSignalFromAiDatasetRow
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(aiTrainDataset_exports);
|
|
26
|
+
var extractSignalFromAiDatasetRow = (row) => {
|
|
27
|
+
const { payload } = row;
|
|
28
|
+
return {
|
|
29
|
+
...payload.signal,
|
|
30
|
+
strategy: payload.signal.strategy,
|
|
31
|
+
figures: payload.figures ?? {},
|
|
32
|
+
indicators: payload.indicators ?? {},
|
|
33
|
+
additionalIndicators: payload.additionalIndicators ?? {},
|
|
34
|
+
prices: payload.signal.prices
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
38
|
+
0 && (module.exports = {
|
|
39
|
+
extractSignalFromAiDatasetRow
|
|
40
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/aiTrainEvaluationDump.ts
|
|
21
|
+
var aiTrainEvaluationDump_exports = {};
|
|
22
|
+
__export(aiTrainEvaluationDump_exports, {
|
|
23
|
+
buildAiTrainEvaluationFeatureSnapshot: () => buildAiTrainEvaluationFeatureSnapshot
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(aiTrainEvaluationDump_exports);
|
|
26
|
+
var BASE_CONTEXT_FEATURE_SECTIONS = [
|
|
27
|
+
"regime",
|
|
28
|
+
"structure",
|
|
29
|
+
"participation",
|
|
30
|
+
"relative",
|
|
31
|
+
"derivatives",
|
|
32
|
+
"mtf",
|
|
33
|
+
"gateFeatures"
|
|
34
|
+
];
|
|
35
|
+
var asRecord = (value) => typeof value === "object" && value != null && !Array.isArray(value) ? value : null;
|
|
36
|
+
var collectStrategyGateFeatures = (baseContext) => {
|
|
37
|
+
const entries = Object.entries(baseContext).filter(
|
|
38
|
+
([key, value]) => key !== "gateFeatures" && key.endsWith("GateFeatures") && asRecord(value) != null
|
|
39
|
+
);
|
|
40
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
41
|
+
};
|
|
42
|
+
var pickBaseContextFeatureSections = (baseContext) => Object.fromEntries(
|
|
43
|
+
BASE_CONTEXT_FEATURE_SECTIONS.map((section) => [
|
|
44
|
+
section,
|
|
45
|
+
baseContext[section] ?? null
|
|
46
|
+
])
|
|
47
|
+
);
|
|
48
|
+
var buildAiTrainEvaluationFeatureSnapshot = ({
|
|
49
|
+
additionalIndicators,
|
|
50
|
+
mode
|
|
51
|
+
}) => {
|
|
52
|
+
if (mode === "none") {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
const additional = asRecord(additionalIndicators);
|
|
56
|
+
const baseContext = asRecord(additional?.baseContext);
|
|
57
|
+
if (!baseContext) {
|
|
58
|
+
return {
|
|
59
|
+
baseContextAvailable: false
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const strategyGateFeatures = collectStrategyGateFeatures(baseContext);
|
|
63
|
+
const snapshot = {
|
|
64
|
+
baseContextAvailable: true,
|
|
65
|
+
gateFeatures: baseContext.gateFeatures ?? null,
|
|
66
|
+
...strategyGateFeatures ? { strategyGateFeatures } : {}
|
|
67
|
+
};
|
|
68
|
+
if (mode === "baseContext") {
|
|
69
|
+
snapshot.baseContext = pickBaseContextFeatureSections(baseContext);
|
|
70
|
+
}
|
|
71
|
+
return snapshot;
|
|
72
|
+
};
|
|
73
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
74
|
+
0 && (module.exports = {
|
|
75
|
+
buildAiTrainEvaluationFeatureSnapshot
|
|
76
|
+
});
|
|
@@ -21,7 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var aiTrainMetrics_exports = {};
|
|
22
22
|
__export(aiTrainMetrics_exports, {
|
|
23
23
|
summarizeAiTrainEvaluations: () => summarizeAiTrainEvaluations,
|
|
24
|
-
summarizeAiTrainEvaluationsByDirection: () => summarizeAiTrainEvaluationsByDirection
|
|
24
|
+
summarizeAiTrainEvaluationsByDirection: () => summarizeAiTrainEvaluationsByDirection,
|
|
25
|
+
summarizeAiTrainEvaluationsByMonth: () => summarizeAiTrainEvaluationsByMonth,
|
|
26
|
+
summarizeAiTrainEvaluationsByQualityThreshold: () => summarizeAiTrainEvaluationsByQualityThreshold
|
|
25
27
|
});
|
|
26
28
|
module.exports = __toCommonJS(aiTrainMetrics_exports);
|
|
27
29
|
var divideOrNull = (num, denom) => {
|
|
@@ -34,17 +36,119 @@ var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
|
34
36
|
var DAYS_PER_WEEK = 7;
|
|
35
37
|
var DAYS_PER_MONTH = 30.4375;
|
|
36
38
|
var getEvaluationPeriodDays = (evaluations) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
let minTimestamp = null;
|
|
40
|
+
let maxTimestamp = null;
|
|
41
|
+
for (const evaluation of evaluations) {
|
|
42
|
+
const timestamp = typeof evaluation.timestamp === "number" && Number.isFinite(evaluation.timestamp) ? evaluation.timestamp : null;
|
|
43
|
+
if (timestamp == null) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (minTimestamp == null || timestamp < minTimestamp) {
|
|
47
|
+
minTimestamp = timestamp;
|
|
48
|
+
}
|
|
49
|
+
if (maxTimestamp == null || timestamp > maxTimestamp) {
|
|
50
|
+
maxTimestamp = timestamp;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (minTimestamp == null || maxTimestamp == null) {
|
|
41
54
|
return null;
|
|
42
55
|
}
|
|
43
|
-
const minTimestamp = Math.min(...timestamps);
|
|
44
|
-
const maxTimestamp = Math.max(...timestamps);
|
|
45
56
|
return Math.max((maxTimestamp - minTimestamp) / DAY_MS, 1);
|
|
46
57
|
};
|
|
47
58
|
var qualitySortKey = (quality) => quality == null ? Number.POSITIVE_INFINITY : quality;
|
|
59
|
+
var emptyRiskSummary = () => ({
|
|
60
|
+
trades: 0,
|
|
61
|
+
totalProfit: 0,
|
|
62
|
+
grossProfit: 0,
|
|
63
|
+
grossLoss: 0,
|
|
64
|
+
profitFactor: null,
|
|
65
|
+
payoffRatio: null,
|
|
66
|
+
avgWin: null,
|
|
67
|
+
avgLoss: null,
|
|
68
|
+
largestWin: null,
|
|
69
|
+
largestLoss: null,
|
|
70
|
+
winRate: null,
|
|
71
|
+
maxDrawdown: 0,
|
|
72
|
+
maxDrawdownPctOfGrossProfit: null,
|
|
73
|
+
maxDrawdownPctOfTotalProfit: null,
|
|
74
|
+
recoveryFactor: null,
|
|
75
|
+
ulcerIndex: null,
|
|
76
|
+
maxConsecutiveWins: 0,
|
|
77
|
+
maxConsecutiveLosses: 0
|
|
78
|
+
});
|
|
79
|
+
var summarizeApprovedRisk = (evaluations) => {
|
|
80
|
+
const approvedEvaluations = evaluations.filter((evaluation) => evaluation.aiApproved).sort((left, right) => {
|
|
81
|
+
const leftTimestamp = typeof left.timestamp === "number" && Number.isFinite(left.timestamp) ? left.timestamp : Number.POSITIVE_INFINITY;
|
|
82
|
+
const rightTimestamp = typeof right.timestamp === "number" && Number.isFinite(right.timestamp) ? right.timestamp : Number.POSITIVE_INFINITY;
|
|
83
|
+
return leftTimestamp - rightTimestamp;
|
|
84
|
+
});
|
|
85
|
+
if (!approvedEvaluations.length) {
|
|
86
|
+
return emptyRiskSummary();
|
|
87
|
+
}
|
|
88
|
+
let grossProfit = 0;
|
|
89
|
+
let grossLoss = 0;
|
|
90
|
+
let wins = 0;
|
|
91
|
+
let losses = 0;
|
|
92
|
+
let largestWin = null;
|
|
93
|
+
let largestLoss = null;
|
|
94
|
+
let equity = 0;
|
|
95
|
+
let peakEquity = 0;
|
|
96
|
+
let maxDrawdown = 0;
|
|
97
|
+
let drawdownSquares = 0;
|
|
98
|
+
let currentWinStreak = 0;
|
|
99
|
+
let currentLossStreak = 0;
|
|
100
|
+
let maxConsecutiveWins = 0;
|
|
101
|
+
let maxConsecutiveLosses = 0;
|
|
102
|
+
for (const evaluation of approvedEvaluations) {
|
|
103
|
+
const profit = evaluation.profit;
|
|
104
|
+
if (profit > 0) {
|
|
105
|
+
grossProfit += profit;
|
|
106
|
+
wins += 1;
|
|
107
|
+
largestWin = largestWin == null ? profit : Math.max(largestWin, profit);
|
|
108
|
+
currentWinStreak += 1;
|
|
109
|
+
currentLossStreak = 0;
|
|
110
|
+
} else if (profit < 0) {
|
|
111
|
+
grossLoss += Math.abs(profit);
|
|
112
|
+
losses += 1;
|
|
113
|
+
largestLoss = largestLoss == null ? profit : Math.min(largestLoss, profit);
|
|
114
|
+
currentLossStreak += 1;
|
|
115
|
+
currentWinStreak = 0;
|
|
116
|
+
} else {
|
|
117
|
+
currentWinStreak = 0;
|
|
118
|
+
currentLossStreak = 0;
|
|
119
|
+
}
|
|
120
|
+
maxConsecutiveWins = Math.max(maxConsecutiveWins, currentWinStreak);
|
|
121
|
+
maxConsecutiveLosses = Math.max(maxConsecutiveLosses, currentLossStreak);
|
|
122
|
+
equity += profit;
|
|
123
|
+
peakEquity = Math.max(peakEquity, equity);
|
|
124
|
+
const drawdown = Math.max(0, peakEquity - equity);
|
|
125
|
+
maxDrawdown = Math.max(maxDrawdown, drawdown);
|
|
126
|
+
drawdownSquares += drawdown * drawdown;
|
|
127
|
+
}
|
|
128
|
+
const totalProfit = grossProfit - grossLoss;
|
|
129
|
+
const avgWin = divideOrNull(grossProfit, wins);
|
|
130
|
+
const avgLoss = divideOrNull(grossLoss, losses);
|
|
131
|
+
return {
|
|
132
|
+
trades: approvedEvaluations.length,
|
|
133
|
+
totalProfit,
|
|
134
|
+
grossProfit,
|
|
135
|
+
grossLoss,
|
|
136
|
+
profitFactor: grossLoss > 0 ? grossProfit / grossLoss : null,
|
|
137
|
+
payoffRatio: avgWin != null && avgLoss != null && avgLoss > 0 ? avgWin / avgLoss : null,
|
|
138
|
+
avgWin,
|
|
139
|
+
avgLoss,
|
|
140
|
+
largestWin,
|
|
141
|
+
largestLoss,
|
|
142
|
+
winRate: divideOrNull(wins, approvedEvaluations.length),
|
|
143
|
+
maxDrawdown,
|
|
144
|
+
maxDrawdownPctOfGrossProfit: grossProfit > 0 ? maxDrawdown / grossProfit : null,
|
|
145
|
+
maxDrawdownPctOfTotalProfit: totalProfit > 0 ? maxDrawdown / totalProfit : null,
|
|
146
|
+
recoveryFactor: maxDrawdown > 0 ? totalProfit / maxDrawdown : null,
|
|
147
|
+
ulcerIndex: Math.sqrt(drawdownSquares / approvedEvaluations.length),
|
|
148
|
+
maxConsecutiveWins,
|
|
149
|
+
maxConsecutiveLosses
|
|
150
|
+
};
|
|
151
|
+
};
|
|
48
152
|
var summarizeAiTrainEvaluations = (evaluations) => {
|
|
49
153
|
let approved = 0;
|
|
50
154
|
let rejected = 0;
|
|
@@ -137,6 +241,7 @@ var summarizeAiTrainEvaluations = (evaluations) => {
|
|
|
137
241
|
avgApprovedTradesPerDay,
|
|
138
242
|
avgApprovedTradesPerWeek,
|
|
139
243
|
expectancyDelta,
|
|
244
|
+
approvedRisk: summarizeApprovedRisk(evaluations),
|
|
140
245
|
qualityBuckets: [...bucketMap.values()].sort(
|
|
141
246
|
(a, b) => qualitySortKey(a.quality) - qualitySortKey(b.quality)
|
|
142
247
|
)
|
|
@@ -151,6 +256,16 @@ var getDirectionSortKey = (direction) => {
|
|
|
151
256
|
}
|
|
152
257
|
return 2;
|
|
153
258
|
};
|
|
259
|
+
var getMonthKey = (timestamp) => {
|
|
260
|
+
if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) {
|
|
261
|
+
return "UNKNOWN";
|
|
262
|
+
}
|
|
263
|
+
return new Date(timestamp).toISOString().slice(0, 7);
|
|
264
|
+
};
|
|
265
|
+
var isDirectionMatchAtThreshold = (evaluation, threshold) => {
|
|
266
|
+
const directionMatches = typeof evaluation.modelDirectionMatches === "boolean" ? evaluation.modelDirectionMatches : evaluation.aiApproved;
|
|
267
|
+
return directionMatches === true && evaluation.quality != null && evaluation.quality >= threshold;
|
|
268
|
+
};
|
|
154
269
|
var summarizeAiTrainEvaluationsByDirection = (evaluations) => {
|
|
155
270
|
const grouped = /* @__PURE__ */ new Map();
|
|
156
271
|
for (const evaluation of evaluations) {
|
|
@@ -166,8 +281,33 @@ var summarizeAiTrainEvaluationsByDirection = (evaluations) => {
|
|
|
166
281
|
summary: summarizeAiTrainEvaluations(directionEvaluations)
|
|
167
282
|
}));
|
|
168
283
|
};
|
|
284
|
+
var summarizeAiTrainEvaluationsByMonth = (evaluations) => {
|
|
285
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
286
|
+
for (const evaluation of evaluations) {
|
|
287
|
+
const month = getMonthKey(evaluation.timestamp);
|
|
288
|
+
const bucket = grouped.get(month) ?? [];
|
|
289
|
+
bucket.push(evaluation);
|
|
290
|
+
grouped.set(month, bucket);
|
|
291
|
+
}
|
|
292
|
+
return [...grouped.entries()].sort(([leftMonth], [rightMonth]) => leftMonth.localeCompare(rightMonth)).map(([month, monthEvaluations]) => ({
|
|
293
|
+
month,
|
|
294
|
+
summary: summarizeAiTrainEvaluations(monthEvaluations)
|
|
295
|
+
}));
|
|
296
|
+
};
|
|
297
|
+
var summarizeAiTrainEvaluationsByQualityThreshold = (evaluations, thresholds = [3, 4, 5]) => thresholds.map((threshold) => ({
|
|
298
|
+
threshold,
|
|
299
|
+
label: `q${threshold}+`,
|
|
300
|
+
summary: summarizeAiTrainEvaluations(
|
|
301
|
+
evaluations.map((evaluation) => ({
|
|
302
|
+
...evaluation,
|
|
303
|
+
aiApproved: isDirectionMatchAtThreshold(evaluation, threshold)
|
|
304
|
+
}))
|
|
305
|
+
)
|
|
306
|
+
}));
|
|
169
307
|
// Annotate the CommonJS export names for ESM import in node:
|
|
170
308
|
0 && (module.exports = {
|
|
171
309
|
summarizeAiTrainEvaluations,
|
|
172
|
-
summarizeAiTrainEvaluationsByDirection
|
|
310
|
+
summarizeAiTrainEvaluationsByDirection,
|
|
311
|
+
summarizeAiTrainEvaluationsByMonth,
|
|
312
|
+
summarizeAiTrainEvaluationsByQualityThreshold
|
|
173
313
|
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/aiTrainOptions.ts
|
|
21
|
+
var aiTrainOptions_exports = {};
|
|
22
|
+
__export(aiTrainOptions_exports, {
|
|
23
|
+
hasCliOption: () => hasCliOption,
|
|
24
|
+
parseDumpFeatureMode: () => parseDumpFeatureMode,
|
|
25
|
+
parseQualityThresholds: () => parseQualityThresholds,
|
|
26
|
+
parseTerminalWindowDays: () => parseTerminalWindowDays,
|
|
27
|
+
parseTimestampFilter: () => parseTimestampFilter,
|
|
28
|
+
parseTrailingPeriodMs: () => parseTrailingPeriodMs,
|
|
29
|
+
resolveAiTrainRecentLimit: () => resolveAiTrainRecentLimit
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(aiTrainOptions_exports);
|
|
32
|
+
var parseTimestampFilter = (value) => {
|
|
33
|
+
if (value == null || String(value).trim() === "") {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const text = String(value).trim();
|
|
37
|
+
const numeric = Number(text);
|
|
38
|
+
if (Number.isFinite(numeric)) {
|
|
39
|
+
return numeric;
|
|
40
|
+
}
|
|
41
|
+
const parsed = Date.parse(text);
|
|
42
|
+
if (Number.isFinite(parsed)) {
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Invalid timestamp filter "${text}". Use an ISO date or epoch milliseconds.`
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
var parseTrailingPeriodMs = (value) => {
|
|
50
|
+
if (value == null || String(value).trim() === "") {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const text = String(value).trim().toLowerCase();
|
|
54
|
+
const match = text.match(
|
|
55
|
+
/^(?:last)?(\d+)(d|day|days|w|week|weeks|m|month|months|y|year|years)$/
|
|
56
|
+
);
|
|
57
|
+
if (!match) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Invalid --period value "${String(value)}". Use values like last365d, 90d, 12w, or 1y.`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const amount = Number(match[1]);
|
|
63
|
+
const unit = match[2];
|
|
64
|
+
const dayMs = 24 * 60 * 60 * 1e3;
|
|
65
|
+
if (unit.startsWith("w")) {
|
|
66
|
+
return amount * 7 * dayMs;
|
|
67
|
+
}
|
|
68
|
+
if (unit.startsWith("m")) {
|
|
69
|
+
return amount * 30.4375 * dayMs;
|
|
70
|
+
}
|
|
71
|
+
if (unit.startsWith("y")) {
|
|
72
|
+
return amount * 365 * dayMs;
|
|
73
|
+
}
|
|
74
|
+
return amount * dayMs;
|
|
75
|
+
};
|
|
76
|
+
var parseQualityThresholds = (value) => {
|
|
77
|
+
const raw = String(value ?? "3,4,5").split(",").map((part) => Number(part.trim())).filter((part) => Number.isFinite(part)).map((part) => Math.trunc(part)).filter((part) => part > 0);
|
|
78
|
+
return [...new Set(raw)].sort((left, right) => left - right);
|
|
79
|
+
};
|
|
80
|
+
var parseTerminalWindowDays = (value) => {
|
|
81
|
+
const raw = String(value ?? "90,30,7").split(",").map((part) => Number(part.trim())).filter((part) => Number.isFinite(part)).map((part) => Math.trunc(part)).filter((part) => part > 0);
|
|
82
|
+
return [...new Set(raw)].sort((left, right) => right - left);
|
|
83
|
+
};
|
|
84
|
+
var parseDumpFeatureMode = (value) => {
|
|
85
|
+
const text = String(value ?? "none").trim().toLowerCase();
|
|
86
|
+
if (!text || text === "none" || text === "false" || text === "0") {
|
|
87
|
+
return "none";
|
|
88
|
+
}
|
|
89
|
+
if (text === "gatefeatures" || text === "gate-features") {
|
|
90
|
+
return "gateFeatures";
|
|
91
|
+
}
|
|
92
|
+
if (text === "basecontext" || text === "base-context") {
|
|
93
|
+
return "baseContext";
|
|
94
|
+
}
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Invalid --dumpFeatures value "${String(value)}". Use none, gateFeatures, or baseContext.`
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
var hasCliOption = ({
|
|
100
|
+
argv,
|
|
101
|
+
longName,
|
|
102
|
+
shortName
|
|
103
|
+
}) => argv.some(
|
|
104
|
+
(arg) => arg === `--${longName}` || arg.startsWith(`--${longName}=`) || arg === `-${shortName}` || arg.startsWith(`-${shortName}=`)
|
|
105
|
+
);
|
|
106
|
+
var resolveAiTrainRecentLimit = ({
|
|
107
|
+
argv,
|
|
108
|
+
recentValue,
|
|
109
|
+
hasDateFilter,
|
|
110
|
+
defaultRecent = 50
|
|
111
|
+
}) => {
|
|
112
|
+
const hasExplicitRecent = hasCliOption({
|
|
113
|
+
argv,
|
|
114
|
+
longName: "recent",
|
|
115
|
+
shortName: "n"
|
|
116
|
+
});
|
|
117
|
+
const selectedRecent = hasDateFilter && !hasExplicitRecent ? 0 : recentValue;
|
|
118
|
+
const parsed = Number(selectedRecent);
|
|
119
|
+
return Number.isFinite(parsed) ? Math.max(0, Math.trunc(parsed)) : defaultRecent;
|
|
120
|
+
};
|
|
121
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
122
|
+
0 && (module.exports = {
|
|
123
|
+
hasCliOption,
|
|
124
|
+
parseDumpFeatureMode,
|
|
125
|
+
parseQualityThresholds,
|
|
126
|
+
parseTerminalWindowDays,
|
|
127
|
+
parseTimestampFilter,
|
|
128
|
+
parseTrailingPeriodMs,
|
|
129
|
+
resolveAiTrainRecentLimit
|
|
130
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/aiTrainQuarantine.ts
|
|
21
|
+
var aiTrainQuarantine_exports = {};
|
|
22
|
+
__export(aiTrainQuarantine_exports, {
|
|
23
|
+
applyAiTrainSymbolQuarantine: () => applyAiTrainSymbolQuarantine,
|
|
24
|
+
summarizeAiTrainDuplicateSignals: () => summarizeAiTrainDuplicateSignals
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(aiTrainQuarantine_exports);
|
|
27
|
+
var import_crypto = require("crypto");
|
|
28
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
29
|
+
var normalizeKeyPart = (value, fallback) => {
|
|
30
|
+
if (typeof value !== "string") {
|
|
31
|
+
return fallback;
|
|
32
|
+
}
|
|
33
|
+
const trimmed = value.trim();
|
|
34
|
+
return trimmed || fallback;
|
|
35
|
+
};
|
|
36
|
+
var getProfitFactor = ({
|
|
37
|
+
grossProfit,
|
|
38
|
+
grossLoss
|
|
39
|
+
}) => {
|
|
40
|
+
if (grossLoss <= 0) {
|
|
41
|
+
return grossProfit > 0 ? null : 0;
|
|
42
|
+
}
|
|
43
|
+
return grossProfit / grossLoss;
|
|
44
|
+
};
|
|
45
|
+
var createEmptyState = () => ({
|
|
46
|
+
quarantineUntil: null,
|
|
47
|
+
approvedLosses: 0,
|
|
48
|
+
grossProfit: 0,
|
|
49
|
+
grossLoss: 0
|
|
50
|
+
});
|
|
51
|
+
var applyAiTrainSymbolQuarantine = (evaluations, options) => {
|
|
52
|
+
const summary = {
|
|
53
|
+
enabled: options.enabled,
|
|
54
|
+
minApprovedLosses: options.minApprovedLosses,
|
|
55
|
+
minProfitFactor: options.minProfitFactor,
|
|
56
|
+
cooldownDays: options.cooldownDays,
|
|
57
|
+
blocked: 0,
|
|
58
|
+
events: []
|
|
59
|
+
};
|
|
60
|
+
if (!options.enabled) {
|
|
61
|
+
return {
|
|
62
|
+
evaluations: evaluations.map((evaluation) => ({
|
|
63
|
+
...evaluation,
|
|
64
|
+
rawAiApproved: evaluation.aiApproved
|
|
65
|
+
})),
|
|
66
|
+
summary
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const cooldownMs = Math.max(0, options.cooldownDays) * DAY_MS;
|
|
70
|
+
const minApprovedLosses = Math.max(1, Math.trunc(options.minApprovedLosses));
|
|
71
|
+
const minProfitFactor = Math.max(0, options.minProfitFactor);
|
|
72
|
+
const states = /* @__PURE__ */ new Map();
|
|
73
|
+
const ordered = evaluations.map((evaluation, index) => ({ evaluation, index })).sort((left, right) => {
|
|
74
|
+
const leftTimestamp = typeof left.evaluation.timestamp === "number" && Number.isFinite(left.evaluation.timestamp) ? left.evaluation.timestamp : Number.POSITIVE_INFINITY;
|
|
75
|
+
const rightTimestamp = typeof right.evaluation.timestamp === "number" && Number.isFinite(right.evaluation.timestamp) ? right.evaluation.timestamp : Number.POSITIVE_INFINITY;
|
|
76
|
+
return leftTimestamp - rightTimestamp || left.index - right.index;
|
|
77
|
+
});
|
|
78
|
+
const result = evaluations.map((evaluation) => ({
|
|
79
|
+
...evaluation,
|
|
80
|
+
rawAiApproved: evaluation.aiApproved
|
|
81
|
+
}));
|
|
82
|
+
for (const { evaluation, index } of ordered) {
|
|
83
|
+
const timestamp = typeof evaluation.timestamp === "number" && Number.isFinite(evaluation.timestamp) ? evaluation.timestamp : null;
|
|
84
|
+
const strategy = normalizeKeyPart(evaluation.strategy, "unknown");
|
|
85
|
+
const symbol = normalizeKeyPart(evaluation.symbol, "unknown");
|
|
86
|
+
const key = `${strategy}:${symbol}`;
|
|
87
|
+
const state = states.get(key) ?? createEmptyState();
|
|
88
|
+
states.set(key, state);
|
|
89
|
+
if (timestamp != null && state.quarantineUntil != null && timestamp >= state.quarantineUntil) {
|
|
90
|
+
state.quarantineUntil = null;
|
|
91
|
+
state.approvedLosses = 0;
|
|
92
|
+
state.grossProfit = 0;
|
|
93
|
+
state.grossLoss = 0;
|
|
94
|
+
}
|
|
95
|
+
if (evaluation.aiApproved && timestamp != null && state.quarantineUntil != null && timestamp < state.quarantineUntil) {
|
|
96
|
+
result[index] = {
|
|
97
|
+
...result[index],
|
|
98
|
+
aiApproved: false
|
|
99
|
+
};
|
|
100
|
+
summary.blocked += 1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (!evaluation.aiApproved) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (evaluation.profit > 0) {
|
|
107
|
+
state.grossProfit += evaluation.profit;
|
|
108
|
+
} else if (evaluation.profit < 0) {
|
|
109
|
+
state.grossLoss += Math.abs(evaluation.profit);
|
|
110
|
+
state.approvedLosses += 1;
|
|
111
|
+
}
|
|
112
|
+
const profitFactor = getProfitFactor(state);
|
|
113
|
+
if (timestamp != null && cooldownMs > 0 && state.approvedLosses >= minApprovedLosses && profitFactor != null && profitFactor < minProfitFactor) {
|
|
114
|
+
state.quarantineUntil = timestamp + cooldownMs;
|
|
115
|
+
summary.events.push({
|
|
116
|
+
strategy,
|
|
117
|
+
symbol,
|
|
118
|
+
startedAt: timestamp,
|
|
119
|
+
until: state.quarantineUntil,
|
|
120
|
+
approvedLosses: state.approvedLosses,
|
|
121
|
+
profitFactor,
|
|
122
|
+
grossProfit: state.grossProfit,
|
|
123
|
+
grossLoss: state.grossLoss
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
evaluations: result,
|
|
129
|
+
summary
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
var stableStringify = (value) => {
|
|
133
|
+
if (value == null || typeof value !== "object") {
|
|
134
|
+
return JSON.stringify(value);
|
|
135
|
+
}
|
|
136
|
+
if (Array.isArray(value)) {
|
|
137
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
138
|
+
}
|
|
139
|
+
const record = value;
|
|
140
|
+
return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
|
|
141
|
+
};
|
|
142
|
+
var hashContext = (row) => {
|
|
143
|
+
const payload = row.payload;
|
|
144
|
+
const signal = payload?.signal;
|
|
145
|
+
const additional = payload?.additionalIndicators && typeof payload.additionalIndicators === "object" && !Array.isArray(payload.additionalIndicators) ? payload.additionalIndicators : {};
|
|
146
|
+
const context = {
|
|
147
|
+
prices: signal?.prices ?? null,
|
|
148
|
+
trendShiftContext: additional.trendShiftContext ?? null,
|
|
149
|
+
marketContext: additional.marketContext ?? null
|
|
150
|
+
};
|
|
151
|
+
return (0, import_crypto.createHash)("sha1").update(stableStringify(context)).digest("hex");
|
|
152
|
+
};
|
|
153
|
+
var summarizeAiTrainDuplicateSignals = (rows) => {
|
|
154
|
+
const groups = /* @__PURE__ */ new Map();
|
|
155
|
+
for (const row of rows) {
|
|
156
|
+
const strategy = normalizeKeyPart(row.strategyName, "unknown");
|
|
157
|
+
const symbol = normalizeKeyPart(row.symbol, "unknown");
|
|
158
|
+
const direction = normalizeKeyPart(row.direction, "UNKNOWN");
|
|
159
|
+
const timestamp = Number(row.timestamp);
|
|
160
|
+
const profit = Number(row.profit);
|
|
161
|
+
const key = [
|
|
162
|
+
strategy,
|
|
163
|
+
symbol,
|
|
164
|
+
direction,
|
|
165
|
+
Number.isFinite(timestamp) ? timestamp : "no_timestamp",
|
|
166
|
+
Number.isFinite(profit) ? profit : "no_profit",
|
|
167
|
+
hashContext(row)
|
|
168
|
+
].join("|");
|
|
169
|
+
const group = groups.get(key) ?? {
|
|
170
|
+
key,
|
|
171
|
+
strategy,
|
|
172
|
+
symbol,
|
|
173
|
+
direction,
|
|
174
|
+
timestamp: Number.isFinite(timestamp) ? timestamp : 0,
|
|
175
|
+
count: 0,
|
|
176
|
+
totalProfit: 0
|
|
177
|
+
};
|
|
178
|
+
group.count += 1;
|
|
179
|
+
group.totalProfit += Number.isFinite(profit) ? profit : 0;
|
|
180
|
+
groups.set(key, group);
|
|
181
|
+
}
|
|
182
|
+
const duplicateGroups = [...groups.values()].filter((group) => group.count > 1).sort(
|
|
183
|
+
(left, right) => left.totalProfit - right.totalProfit || right.count - left.count || left.key.localeCompare(right.key)
|
|
184
|
+
);
|
|
185
|
+
return {
|
|
186
|
+
groups: duplicateGroups.length,
|
|
187
|
+
rows: duplicateGroups.reduce((total, group) => total + group.count, 0),
|
|
188
|
+
maxGroupSize: duplicateGroups.reduce(
|
|
189
|
+
(max, group) => Math.max(max, group.count),
|
|
190
|
+
0
|
|
191
|
+
),
|
|
192
|
+
worstGroups: duplicateGroups.slice(0, 10)
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
196
|
+
0 && (module.exports = {
|
|
197
|
+
applyAiTrainSymbolQuarantine,
|
|
198
|
+
summarizeAiTrainDuplicateSignals
|
|
199
|
+
});
|