@tradejs/cli 1.0.5 → 1.0.8
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 +4 -1
- package/dist/cli.js +13791 -7652
- package/dist/lib/aiTrainMetrics.js +173 -0
- package/dist/lib/candlesProviderMigration.js +266 -0
- package/dist/lib/cliArgs.js +40 -0
- package/dist/lib/derivativesContextBackfill.js +487 -0
- package/dist/lib/researchAgent.js +195 -0
- package/dist/lib/runtimeParity.js +234 -0
- package/dist/lib/telegramReports.js +91 -0
- package/dist/lib/timeWindow.js +101 -0
- package/dist/scripts/agentRun.js +895 -0
- package/dist/scripts/aiExport.js +192 -0
- package/dist/scripts/aiExportSelect.js +135 -0
- package/dist/scripts/aiTrain.js +2321 -0
- package/dist/scripts/backtest.js +998 -111
- package/dist/scripts/candlesMigrateProvider.js +5302 -0
- package/dist/scripts/continuity.js +1 -1
- package/dist/scripts/derivativesIngest.js +5 -0
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +21 -12
- package/dist/scripts/migration.js +1 -1
- package/dist/scripts/mlExport.js +112 -13
- package/dist/scripts/mlExportSelect.js +43 -9
- package/dist/scripts/mlTrainLatestSelect.js +4 -3
- package/dist/scripts/researchAuto.js +845 -0
- package/dist/scripts/resolveExportStrategy.js +133 -0
- package/dist/scripts/results.js +46 -22
- package/dist/scripts/runtimeParity.js +1651 -0
- package/dist/scripts/selectStrategy.js +4 -3
- package/dist/scripts/signals.js +799 -62
- package/dist/scripts/signalsSummary.js +655 -0
- package/dist/scripts/spawnSiblingScript.js +71 -0
- package/dist/scripts/user-add.js +0 -9
- package/dist/workers/testerWorker.js +13 -2
- package/package.json +18 -12
|
@@ -0,0 +1,234 @@
|
|
|
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/runtimeParity.ts
|
|
21
|
+
var runtimeParity_exports = {};
|
|
22
|
+
__export(runtimeParity_exports, {
|
|
23
|
+
compareTradeParityEntries: () => compareTradeParityEntries,
|
|
24
|
+
dedupeRuntimeParityEntries: () => dedupeRuntimeParityEntries,
|
|
25
|
+
extractBacktestEntryParityEntries: () => extractBacktestEntryParityEntries,
|
|
26
|
+
extractRuntimeParityEntries: () => extractRuntimeParityEntries,
|
|
27
|
+
findRuntimeDuplicateGroups: () => findRuntimeDuplicateGroups,
|
|
28
|
+
summarizeMatchedParity: () => summarizeMatchedParity
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(runtimeParity_exports);
|
|
31
|
+
var toFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
32
|
+
var toGroupKey = (entry) => `${entry.strategy}::${entry.symbol}::${entry.direction}`;
|
|
33
|
+
var toRuntimeDuplicateKey = (entry) => `${toGroupKey(entry)}::${entry.timestamp}`;
|
|
34
|
+
var sortTradeParityEntries = (left, right) => left.timestamp - right.timestamp || left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol) || left.direction.localeCompare(right.direction) || left.id.localeCompare(right.id);
|
|
35
|
+
var buildPriceDeltaPct = (leftPrice, rightPrice) => {
|
|
36
|
+
if (leftPrice == null || rightPrice == null || !Number.isFinite(leftPrice) || !Number.isFinite(rightPrice) || leftPrice === 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return Math.abs((rightPrice - leftPrice) / leftPrice * 100);
|
|
40
|
+
};
|
|
41
|
+
var extractBacktestEntryParityEntries = (orderLog) => {
|
|
42
|
+
if (!Array.isArray(orderLog)) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
return orderLog.filter(
|
|
46
|
+
(item) => (item.type === "OPEN_LONG" || item.type === "OPEN_SHORT") && item.signal && typeof item.signal.strategy === "string" && typeof item.signal.symbol === "string" && (item.signal.direction === "LONG" || item.signal.direction === "SHORT")
|
|
47
|
+
).map((item, index) => {
|
|
48
|
+
const signal = item.signal;
|
|
49
|
+
const timestamp = typeof signal.timestamp === "number" && Number.isFinite(signal.timestamp) ? signal.timestamp : item.timestamp;
|
|
50
|
+
return {
|
|
51
|
+
id: typeof signal.signalId === "string" && signal.signalId.trim() ? signal.signalId : `backtest-${index}-${timestamp}`,
|
|
52
|
+
source: "backtest",
|
|
53
|
+
strategy: signal.strategy,
|
|
54
|
+
symbol: signal.symbol,
|
|
55
|
+
direction: signal.direction,
|
|
56
|
+
timestamp,
|
|
57
|
+
price: toFiniteNumberOrNull(item.price),
|
|
58
|
+
signalId: typeof signal.signalId === "string" ? signal.signalId : void 0
|
|
59
|
+
};
|
|
60
|
+
}).sort((left, right) => left.timestamp - right.timestamp);
|
|
61
|
+
};
|
|
62
|
+
var extractRuntimeParityEntries = (trades) => trades.filter(
|
|
63
|
+
(trade) => typeof trade.strategy === "string" && typeof trade.symbol === "string" && (trade.direction === "LONG" || trade.direction === "SHORT") && typeof trade.entryTimestamp === "number" && Number.isFinite(trade.entryTimestamp)
|
|
64
|
+
).map((trade) => ({
|
|
65
|
+
id: trade.orderId,
|
|
66
|
+
source: "runtime",
|
|
67
|
+
strategy: trade.strategy,
|
|
68
|
+
symbol: trade.symbol,
|
|
69
|
+
direction: trade.direction,
|
|
70
|
+
timestamp: trade.entryTimestamp,
|
|
71
|
+
price: toFiniteNumberOrNull(trade.entryPrice),
|
|
72
|
+
orderId: trade.orderId,
|
|
73
|
+
signalId: typeof trade.signalId === "string" ? trade.signalId : void 0
|
|
74
|
+
})).sort((left, right) => left.timestamp - right.timestamp);
|
|
75
|
+
var findRuntimeDuplicateGroups = (entries) => {
|
|
76
|
+
const groups = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const entry of entries) {
|
|
78
|
+
if (entry.source !== "runtime") {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const key = toRuntimeDuplicateKey(entry);
|
|
82
|
+
const bucket = groups.get(key) ?? [];
|
|
83
|
+
bucket.push(entry);
|
|
84
|
+
groups.set(key, bucket);
|
|
85
|
+
}
|
|
86
|
+
return [...groups.entries()].filter(([, group]) => group.length > 1).map(([key, group]) => {
|
|
87
|
+
const sortedGroup = [...group].sort(sortTradeParityEntries);
|
|
88
|
+
const first = sortedGroup[0];
|
|
89
|
+
return {
|
|
90
|
+
key,
|
|
91
|
+
strategy: first.strategy,
|
|
92
|
+
symbol: first.symbol,
|
|
93
|
+
direction: first.direction,
|
|
94
|
+
timestamp: first.timestamp,
|
|
95
|
+
entries: sortedGroup
|
|
96
|
+
};
|
|
97
|
+
}).sort(
|
|
98
|
+
(left, right) => left.timestamp - right.timestamp || left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol) || left.direction.localeCompare(right.direction)
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
var dedupeRuntimeParityEntries = (entries) => {
|
|
102
|
+
const duplicateGroups = findRuntimeDuplicateGroups(entries);
|
|
103
|
+
const duplicateEntriesSet = /* @__PURE__ */ new Set();
|
|
104
|
+
for (const group of duplicateGroups) {
|
|
105
|
+
for (const duplicate of group.entries.slice(1)) {
|
|
106
|
+
duplicateEntriesSet.add(duplicate);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const dedupedEntries = entries.filter((entry) => !duplicateEntriesSet.has(entry)).sort(sortTradeParityEntries);
|
|
110
|
+
const duplicateEntries = duplicateGroups.flatMap((group) => group.entries.slice(1)).sort(sortTradeParityEntries);
|
|
111
|
+
return {
|
|
112
|
+
entries: dedupedEntries,
|
|
113
|
+
duplicateGroups,
|
|
114
|
+
duplicateEntries
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
var compareTradeParityEntries = ({
|
|
118
|
+
runtimeEntries,
|
|
119
|
+
backtestEntries,
|
|
120
|
+
toleranceMs
|
|
121
|
+
}) => {
|
|
122
|
+
const matched = [];
|
|
123
|
+
const runtimeOnly = [];
|
|
124
|
+
const backtestOnly = [];
|
|
125
|
+
const groupedRuntime = /* @__PURE__ */ new Map();
|
|
126
|
+
const groupedBacktest = /* @__PURE__ */ new Map();
|
|
127
|
+
for (const entry of runtimeEntries) {
|
|
128
|
+
const key = toGroupKey(entry);
|
|
129
|
+
const bucket = groupedRuntime.get(key) ?? [];
|
|
130
|
+
bucket.push(entry);
|
|
131
|
+
groupedRuntime.set(key, bucket);
|
|
132
|
+
}
|
|
133
|
+
for (const entry of backtestEntries) {
|
|
134
|
+
const key = toGroupKey(entry);
|
|
135
|
+
const bucket = groupedBacktest.get(key) ?? [];
|
|
136
|
+
bucket.push(entry);
|
|
137
|
+
groupedBacktest.set(key, bucket);
|
|
138
|
+
}
|
|
139
|
+
const groupKeys = /* @__PURE__ */ new Set([
|
|
140
|
+
...groupedRuntime.keys(),
|
|
141
|
+
...groupedBacktest.keys()
|
|
142
|
+
]);
|
|
143
|
+
for (const key of groupKeys) {
|
|
144
|
+
const runtimeGroup = [...groupedRuntime.get(key) ?? []].sort(
|
|
145
|
+
(left, right) => left.timestamp - right.timestamp
|
|
146
|
+
);
|
|
147
|
+
const backtestGroup = [...groupedBacktest.get(key) ?? []].sort(
|
|
148
|
+
(left, right) => left.timestamp - right.timestamp
|
|
149
|
+
);
|
|
150
|
+
const unmatchedBacktest = backtestGroup.map((entry) => ({
|
|
151
|
+
entry,
|
|
152
|
+
used: false
|
|
153
|
+
}));
|
|
154
|
+
for (const runtimeEntry of runtimeGroup) {
|
|
155
|
+
let bestIndex = -1;
|
|
156
|
+
let bestDiff = Number.POSITIVE_INFINITY;
|
|
157
|
+
for (let index = 0; index < unmatchedBacktest.length; index += 1) {
|
|
158
|
+
const candidate = unmatchedBacktest[index];
|
|
159
|
+
if (candidate.used) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const diff = Math.abs(
|
|
163
|
+
candidate.entry.timestamp - runtimeEntry.timestamp
|
|
164
|
+
);
|
|
165
|
+
if (diff > toleranceMs || diff >= bestDiff) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
bestIndex = index;
|
|
169
|
+
bestDiff = diff;
|
|
170
|
+
}
|
|
171
|
+
if (bestIndex < 0) {
|
|
172
|
+
runtimeOnly.push(runtimeEntry);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
unmatchedBacktest[bestIndex].used = true;
|
|
176
|
+
const backtestEntry = unmatchedBacktest[bestIndex].entry;
|
|
177
|
+
matched.push({
|
|
178
|
+
runtime: runtimeEntry,
|
|
179
|
+
backtest: backtestEntry,
|
|
180
|
+
timestampDiffMs: bestDiff,
|
|
181
|
+
priceDeltaPct: buildPriceDeltaPct(
|
|
182
|
+
runtimeEntry.price,
|
|
183
|
+
backtestEntry.price
|
|
184
|
+
)
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
for (const candidate of unmatchedBacktest) {
|
|
188
|
+
if (!candidate.used) {
|
|
189
|
+
backtestOnly.push(candidate.entry);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
matched.sort(
|
|
194
|
+
(left, right) => left.runtime.timestamp - right.runtime.timestamp
|
|
195
|
+
);
|
|
196
|
+
runtimeOnly.sort((left, right) => left.timestamp - right.timestamp);
|
|
197
|
+
backtestOnly.sort((left, right) => left.timestamp - right.timestamp);
|
|
198
|
+
return {
|
|
199
|
+
matched,
|
|
200
|
+
runtimeOnly,
|
|
201
|
+
backtestOnly
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
var summarizeMatchedParity = (matched) => {
|
|
205
|
+
if (!matched.length) {
|
|
206
|
+
return {
|
|
207
|
+
avgPriceDeltaPct: null,
|
|
208
|
+
maxPriceDeltaPct: null,
|
|
209
|
+
avgTimestampDiffMs: null,
|
|
210
|
+
maxTimestampDiffMs: null
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const priceDeltas = matched.map((item) => item.priceDeltaPct).filter(
|
|
214
|
+
(value) => value != null && Number.isFinite(value)
|
|
215
|
+
);
|
|
216
|
+
const timestampDiffs = matched.map((item) => item.timestampDiffMs).filter((value) => Number.isFinite(value));
|
|
217
|
+
const average = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
|
|
218
|
+
const maximum = (values) => values.length ? Math.max(...values) : null;
|
|
219
|
+
return {
|
|
220
|
+
avgPriceDeltaPct: average(priceDeltas),
|
|
221
|
+
maxPriceDeltaPct: maximum(priceDeltas),
|
|
222
|
+
avgTimestampDiffMs: average(timestampDiffs),
|
|
223
|
+
maxTimestampDiffMs: maximum(timestampDiffs)
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
227
|
+
0 && (module.exports = {
|
|
228
|
+
compareTradeParityEntries,
|
|
229
|
+
dedupeRuntimeParityEntries,
|
|
230
|
+
extractBacktestEntryParityEntries,
|
|
231
|
+
extractRuntimeParityEntries,
|
|
232
|
+
findRuntimeDuplicateGroups,
|
|
233
|
+
summarizeMatchedParity
|
|
234
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
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/telegramReports.ts
|
|
21
|
+
var telegramReports_exports = {};
|
|
22
|
+
__export(telegramReports_exports, {
|
|
23
|
+
TELEGRAM_REPORT_CHUNK_LIMIT: () => TELEGRAM_REPORT_CHUNK_LIMIT,
|
|
24
|
+
sendTelegramReport: () => sendTelegramReport,
|
|
25
|
+
splitTelegramReport: () => splitTelegramReport
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(telegramReports_exports);
|
|
28
|
+
var import_cli = require("@tradejs/node/cli");
|
|
29
|
+
var TELEGRAM_REPORT_CHUNK_LIMIT = 3900;
|
|
30
|
+
var buildPartHeader = (index, total) => `\u{1F4E9} <b>Part ${index}/${total}</b>`;
|
|
31
|
+
var splitLongLine = (line, limit) => {
|
|
32
|
+
const chunks = [];
|
|
33
|
+
for (let index = 0; index < line.length; index += limit) {
|
|
34
|
+
chunks.push(line.slice(index, index + limit));
|
|
35
|
+
}
|
|
36
|
+
return chunks;
|
|
37
|
+
};
|
|
38
|
+
var splitTelegramReport = (message, limit = TELEGRAM_REPORT_CHUNK_LIMIT) => {
|
|
39
|
+
const normalizedLimit = Math.max(100, Math.floor(limit));
|
|
40
|
+
if (message.length <= normalizedLimit) {
|
|
41
|
+
return [message];
|
|
42
|
+
}
|
|
43
|
+
const chunks = [];
|
|
44
|
+
let current = "";
|
|
45
|
+
const flush = () => {
|
|
46
|
+
if (!current) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
chunks.push(current);
|
|
50
|
+
current = "";
|
|
51
|
+
};
|
|
52
|
+
for (const line of message.split("\n")) {
|
|
53
|
+
const next = current ? `${current}
|
|
54
|
+
${line}` : line;
|
|
55
|
+
if (next.length <= normalizedLimit) {
|
|
56
|
+
current = next;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
flush();
|
|
60
|
+
if (line.length <= normalizedLimit) {
|
|
61
|
+
current = line;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
chunks.push(...splitLongLine(line, normalizedLimit));
|
|
65
|
+
}
|
|
66
|
+
flush();
|
|
67
|
+
return chunks;
|
|
68
|
+
};
|
|
69
|
+
var sendTelegramReport = async (message, options = {}) => {
|
|
70
|
+
const chunks = splitTelegramReport(message);
|
|
71
|
+
if (chunks.length === 1) {
|
|
72
|
+
await (0, import_cli.sendTextToTG)(chunks[0], options);
|
|
73
|
+
return chunks.length;
|
|
74
|
+
}
|
|
75
|
+
for (const [index, chunk] of chunks.entries()) {
|
|
76
|
+
const header = buildPartHeader(index + 1, chunks.length);
|
|
77
|
+
await (0, import_cli.sendTextToTG)(`${header}
|
|
78
|
+
|
|
79
|
+
${chunk}`, {
|
|
80
|
+
userName: options.userName,
|
|
81
|
+
markup: index === chunks.length - 1 ? options.markup : void 0
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return chunks.length;
|
|
85
|
+
};
|
|
86
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
87
|
+
0 && (module.exports = {
|
|
88
|
+
TELEGRAM_REPORT_CHUNK_LIMIT,
|
|
89
|
+
sendTelegramReport,
|
|
90
|
+
splitTelegramReport
|
|
91
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
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/timeWindow.ts
|
|
21
|
+
var timeWindow_exports = {};
|
|
22
|
+
__export(timeWindow_exports, {
|
|
23
|
+
resolveTimeWindow: () => resolveTimeWindow
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(timeWindow_exports);
|
|
26
|
+
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
27
|
+
var toEpochMs = (value) => {
|
|
28
|
+
if (value == null || value === "") {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const parsed = Number(value);
|
|
32
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return parsed < 1e12 ? Math.trunc(parsed * 1e3) : Math.trunc(parsed);
|
|
36
|
+
};
|
|
37
|
+
var toPositiveNumber = (value) => {
|
|
38
|
+
if (value == null || value === "") {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const parsed = Number(value);
|
|
42
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return parsed;
|
|
46
|
+
};
|
|
47
|
+
var resolveTimeWindow = ({
|
|
48
|
+
days,
|
|
49
|
+
startTime,
|
|
50
|
+
endTime,
|
|
51
|
+
nowMs = Date.now(),
|
|
52
|
+
defaultStartMs,
|
|
53
|
+
defaultEndMs
|
|
54
|
+
}) => {
|
|
55
|
+
const explicitStart = toEpochMs(startTime);
|
|
56
|
+
const explicitEnd = toEpochMs(endTime);
|
|
57
|
+
if (explicitStart != null || explicitEnd != null) {
|
|
58
|
+
const resolvedEnd2 = explicitEnd ?? defaultEndMs ?? nowMs;
|
|
59
|
+
const resolvedStart = explicitStart ?? defaultStartMs;
|
|
60
|
+
if (resolvedStart >= resolvedEnd2) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Invalid time window: startTime (${resolvedStart}) must be less than endTime (${resolvedEnd2})`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
start: resolvedStart,
|
|
67
|
+
end: resolvedEnd2,
|
|
68
|
+
source: "explicit"
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const resolvedDays = toPositiveNumber(days);
|
|
72
|
+
if (resolvedDays != null) {
|
|
73
|
+
const resolvedEnd2 = defaultEndMs ?? nowMs;
|
|
74
|
+
const resolvedStart = resolvedEnd2 - resolvedDays * ONE_DAY_MS;
|
|
75
|
+
if (resolvedStart >= resolvedEnd2) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Invalid time window: computed start (${resolvedStart}) must be less than end (${resolvedEnd2})`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
start: Math.trunc(resolvedStart),
|
|
82
|
+
end: Math.trunc(resolvedEnd2),
|
|
83
|
+
source: "days"
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const resolvedEnd = defaultEndMs ?? nowMs;
|
|
87
|
+
if (defaultStartMs >= resolvedEnd) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Invalid default time window: start (${defaultStartMs}) must be less than end (${resolvedEnd})`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
start: Math.trunc(defaultStartMs),
|
|
94
|
+
end: Math.trunc(resolvedEnd),
|
|
95
|
+
source: "default"
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
99
|
+
0 && (module.exports = {
|
|
100
|
+
resolveTimeWindow
|
|
101
|
+
});
|