@tradejs/infra 1.0.9 → 1.0.10
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/ai.d.mts +39 -3
- package/dist/ai.d.ts +39 -3
- package/dist/ai.js +404 -28
- package/dist/ai.mjs +372 -24
- package/dist/backtestArtifacts.d.mts +57 -0
- package/dist/backtestArtifacts.d.ts +57 -0
- package/dist/backtestArtifacts.js +255 -0
- package/dist/backtestArtifacts.mjs +211 -0
- package/dist/{chunk-MLVWC2I2.mjs → chunk-DXG2UDNA.mjs} +60 -5
- package/dist/{chunk-KVEZORMS.mjs → chunk-RQP5VSTH.mjs} +54 -3
- package/dist/ml.d.mts +1 -1
- package/dist/ml.d.ts +1 -1
- package/dist/ml.js +55 -3
- package/dist/ml.mjs +3 -1
- package/dist/{mlDatasetFile-sRGWgR_o.d.mts → mlDatasetFile-Czx__g9M.d.mts} +7 -1
- package/dist/{mlDatasetFile-sRGWgR_o.d.ts → mlDatasetFile-Czx__g9M.d.ts} +7 -1
- package/dist/redis.d.mts +21 -3
- package/dist/redis.d.ts +21 -3
- package/dist/redis.js +63 -5
- package/dist/redis.mjs +7 -1
- package/dist/timescale.d.mts +220 -5
- package/dist/timescale.d.ts +220 -5
- package/dist/timescale.js +1983 -93
- package/dist/timescale.mjs +1955 -93
- package/dist/tradingAccounts.d.mts +20 -0
- package/dist/tradingAccounts.d.ts +20 -0
- package/dist/tradingAccounts.js +556 -0
- package/dist/tradingAccounts.mjs +190 -0
- package/dist/userSettings.d.mts +2 -0
- package/dist/userSettings.d.ts +2 -0
- package/dist/userSettings.js +24 -5
- package/dist/userSettings.mjs +2 -1
- package/package.json +13 -3
package/dist/ai.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mergeJsonlFiles,
|
|
3
3
|
toFileToken
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RQP5VSTH.mjs";
|
|
5
5
|
|
|
6
6
|
// src/aiDatasetFile.ts
|
|
7
7
|
import { once } from "events";
|
|
@@ -10,16 +10,81 @@ import fs from "fs/promises";
|
|
|
10
10
|
import path from "path";
|
|
11
11
|
import { createReadStream } from "fs";
|
|
12
12
|
import readline from "readline";
|
|
13
|
+
|
|
14
|
+
// ../../node_modules/date-fns/toDate.mjs
|
|
15
|
+
function toDate(argument) {
|
|
16
|
+
const argStr = Object.prototype.toString.call(argument);
|
|
17
|
+
if (argument instanceof Date || typeof argument === "object" && argStr === "[object Date]") {
|
|
18
|
+
return new argument.constructor(+argument);
|
|
19
|
+
} else if (typeof argument === "number" || argStr === "[object Number]" || typeof argument === "string" || argStr === "[object String]") {
|
|
20
|
+
return new Date(argument);
|
|
21
|
+
} else {
|
|
22
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ../../node_modules/date-fns/constructFrom.mjs
|
|
27
|
+
function constructFrom(date, value) {
|
|
28
|
+
if (date instanceof Date) {
|
|
29
|
+
return new date.constructor(value);
|
|
30
|
+
} else {
|
|
31
|
+
return new Date(value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ../../node_modules/date-fns/addMonths.mjs
|
|
36
|
+
function addMonths(date, amount) {
|
|
37
|
+
const _date = toDate(date);
|
|
38
|
+
if (isNaN(amount)) return constructFrom(date, NaN);
|
|
39
|
+
if (!amount) {
|
|
40
|
+
return _date;
|
|
41
|
+
}
|
|
42
|
+
const dayOfMonth = _date.getDate();
|
|
43
|
+
const endOfDesiredMonth = constructFrom(date, _date.getTime());
|
|
44
|
+
endOfDesiredMonth.setMonth(_date.getMonth() + amount + 1, 0);
|
|
45
|
+
const daysInMonth = endOfDesiredMonth.getDate();
|
|
46
|
+
if (dayOfMonth >= daysInMonth) {
|
|
47
|
+
return endOfDesiredMonth;
|
|
48
|
+
} else {
|
|
49
|
+
_date.setFullYear(
|
|
50
|
+
endOfDesiredMonth.getFullYear(),
|
|
51
|
+
endOfDesiredMonth.getMonth(),
|
|
52
|
+
dayOfMonth
|
|
53
|
+
);
|
|
54
|
+
return _date;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ../../node_modules/date-fns/startOfMonth.mjs
|
|
59
|
+
function startOfMonth(date) {
|
|
60
|
+
const _date = toDate(date);
|
|
61
|
+
_date.setDate(1);
|
|
62
|
+
_date.setHours(0, 0, 0, 0);
|
|
63
|
+
return _date;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/aiDatasetFile.ts
|
|
13
67
|
var DEFAULT_DIR = "data/ai/export";
|
|
14
68
|
var AI_DATASET_WRITE_BATCH_SIZE = 100;
|
|
15
69
|
var AI_MERGE_SORT_RUN_MAX_ROWS = 2e3;
|
|
16
70
|
var AI_MERGE_SORT_RUN_MAX_BYTES = 16 * 1024 * 1024;
|
|
71
|
+
var AI_MERGE_SORT_MAX_OPEN_RUNS = 16;
|
|
17
72
|
var AI_CHUNK_FILE_RE = /^ai-dataset-(.+)-chunk-[^.]+\.jsonl$/;
|
|
73
|
+
var BACKTEST_RUN_CHUNK_ID_RE = /^(\d{12}-[a-f0-9]{8})-/;
|
|
18
74
|
var writerByPath = /* @__PURE__ */ new Map();
|
|
19
75
|
var getAiChunkFilePath = (strategyName, chunkId, outDir = DEFAULT_DIR) => path.join(
|
|
20
76
|
outDir,
|
|
21
77
|
`ai-dataset-${toFileToken(strategyName)}-chunk-${toFileToken(chunkId)}.jsonl`
|
|
22
78
|
);
|
|
79
|
+
var getAiChunkFilePrefix = (strategyName, runId) => `ai-dataset-${toFileToken(strategyName)}-chunk-${runId ? `${toFileToken(runId)}-` : ""}`;
|
|
80
|
+
var getRunIdFromAiChunkFileName = (strategyName, fileName) => {
|
|
81
|
+
const prefix = getAiChunkFilePrefix(strategyName);
|
|
82
|
+
if (!fileName.startsWith(prefix) || !fileName.endsWith(".jsonl")) {
|
|
83
|
+
return "";
|
|
84
|
+
}
|
|
85
|
+
const chunkToken = fileName.slice(prefix.length, -".jsonl".length);
|
|
86
|
+
return chunkToken.match(BACKTEST_RUN_CHUNK_ID_RE)?.[1] ?? "";
|
|
87
|
+
};
|
|
23
88
|
var appendAiDatasetRow = async (params) => {
|
|
24
89
|
const { strategyName, chunkId, row, outDir = DEFAULT_DIR } = params;
|
|
25
90
|
const filePath = getAiChunkFilePath(strategyName, chunkId, outDir);
|
|
@@ -95,8 +160,8 @@ var closeAllAiDatasetWriters = async () => {
|
|
|
95
160
|
}
|
|
96
161
|
};
|
|
97
162
|
var listAiChunkFiles = async (params) => {
|
|
98
|
-
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
99
|
-
const prefix =
|
|
163
|
+
const { strategyName, outDir = DEFAULT_DIR, runId } = params;
|
|
164
|
+
const prefix = getAiChunkFilePrefix(strategyName, runId);
|
|
100
165
|
let entries = [];
|
|
101
166
|
try {
|
|
102
167
|
entries = await fs.readdir(outDir);
|
|
@@ -105,6 +170,20 @@ var listAiChunkFiles = async (params) => {
|
|
|
105
170
|
}
|
|
106
171
|
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).map((name) => path.join(outDir, name)).sort();
|
|
107
172
|
};
|
|
173
|
+
var listAiChunkRunIds = async (params) => {
|
|
174
|
+
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
175
|
+
let entries = [];
|
|
176
|
+
try {
|
|
177
|
+
entries = await fs.readdir(outDir);
|
|
178
|
+
} catch {
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
return [
|
|
182
|
+
...new Set(
|
|
183
|
+
entries.map((name) => getRunIdFromAiChunkFileName(strategyName, name)).filter(Boolean)
|
|
184
|
+
)
|
|
185
|
+
].sort();
|
|
186
|
+
};
|
|
108
187
|
var listAiChunkStrategies = async (params) => {
|
|
109
188
|
const outDir = params?.outDir ?? DEFAULT_DIR;
|
|
110
189
|
let entries = [];
|
|
@@ -203,7 +282,7 @@ var readNextNonEmptyLine = async (iterator) => {
|
|
|
203
282
|
}
|
|
204
283
|
}
|
|
205
284
|
};
|
|
206
|
-
var
|
|
285
|
+
var mergeSortedRunBatch = async (params) => {
|
|
207
286
|
const { runPaths, outPath } = params;
|
|
208
287
|
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
209
288
|
const output = createWriteStream(outPath, { encoding: "utf8" });
|
|
@@ -264,12 +343,58 @@ var mergeSortedRuns = async (params) => {
|
|
|
264
343
|
await outputDone;
|
|
265
344
|
}
|
|
266
345
|
};
|
|
346
|
+
var mergeSortedRuns = async (params) => {
|
|
347
|
+
const {
|
|
348
|
+
runPaths,
|
|
349
|
+
outPath,
|
|
350
|
+
tempDir,
|
|
351
|
+
maxOpenRuns = AI_MERGE_SORT_MAX_OPEN_RUNS
|
|
352
|
+
} = params;
|
|
353
|
+
const resolvedMaxOpenRuns = Math.max(2, Math.trunc(maxOpenRuns));
|
|
354
|
+
let currentRunPaths = [...runPaths];
|
|
355
|
+
let passIndex = 0;
|
|
356
|
+
while (currentRunPaths.length > resolvedMaxOpenRuns) {
|
|
357
|
+
const nextRunPaths = [];
|
|
358
|
+
for (let groupStart = 0, groupIndex = 0; groupStart < currentRunPaths.length; groupStart += resolvedMaxOpenRuns, groupIndex += 1) {
|
|
359
|
+
const groupRunPaths = currentRunPaths.slice(
|
|
360
|
+
groupStart,
|
|
361
|
+
groupStart + resolvedMaxOpenRuns
|
|
362
|
+
);
|
|
363
|
+
if (groupRunPaths.length === 1) {
|
|
364
|
+
nextRunPaths.push(groupRunPaths[0]);
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
const passPath = path.join(
|
|
368
|
+
tempDir,
|
|
369
|
+
`merge-pass-${String(passIndex).padStart(3, "0")}-${String(
|
|
370
|
+
groupIndex
|
|
371
|
+
).padStart(6, "0")}.jsonl`
|
|
372
|
+
);
|
|
373
|
+
await mergeSortedRunBatch({
|
|
374
|
+
runPaths: groupRunPaths,
|
|
375
|
+
outPath: passPath
|
|
376
|
+
});
|
|
377
|
+
nextRunPaths.push(passPath);
|
|
378
|
+
await Promise.all(
|
|
379
|
+
groupRunPaths.map((runPath) => fs.rm(runPath, { force: true }))
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
currentRunPaths = nextRunPaths;
|
|
383
|
+
passIndex += 1;
|
|
384
|
+
}
|
|
385
|
+
await mergeSortedRunBatch({
|
|
386
|
+
runPaths: currentRunPaths,
|
|
387
|
+
outPath
|
|
388
|
+
});
|
|
389
|
+
};
|
|
267
390
|
var mergeAiJsonlFiles = async (params) => {
|
|
268
391
|
const {
|
|
269
392
|
filePaths,
|
|
270
393
|
outPath,
|
|
271
394
|
maxRowsInMemory = AI_MERGE_SORT_RUN_MAX_ROWS,
|
|
272
|
-
maxBytesInMemory = AI_MERGE_SORT_RUN_MAX_BYTES
|
|
395
|
+
maxBytesInMemory = AI_MERGE_SORT_RUN_MAX_BYTES,
|
|
396
|
+
maxOpenRuns = AI_MERGE_SORT_MAX_OPEN_RUNS,
|
|
397
|
+
shouldIncludeRow
|
|
273
398
|
} = params;
|
|
274
399
|
const tempDir = path.join(
|
|
275
400
|
path.dirname(outPath),
|
|
@@ -308,9 +433,13 @@ var mergeAiJsonlFiles = async (params) => {
|
|
|
308
433
|
if (!trimmed) {
|
|
309
434
|
continue;
|
|
310
435
|
}
|
|
436
|
+
const row = parseAiDatasetLine(trimmed, filePath);
|
|
437
|
+
if (shouldIncludeRow && !shouldIncludeRow(row)) {
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
311
440
|
batch.push({
|
|
312
441
|
line: trimmed,
|
|
313
|
-
sortKey: getAiDatasetSortKey(
|
|
442
|
+
sortKey: getAiDatasetSortKey(row),
|
|
314
443
|
sourceIndex
|
|
315
444
|
});
|
|
316
445
|
sourceIndex += 1;
|
|
@@ -331,56 +460,275 @@ var mergeAiJsonlFiles = async (params) => {
|
|
|
331
460
|
}
|
|
332
461
|
await mergeSortedRuns({
|
|
333
462
|
runPaths,
|
|
334
|
-
outPath
|
|
463
|
+
outPath,
|
|
464
|
+
tempDir,
|
|
465
|
+
maxOpenRuns
|
|
335
466
|
});
|
|
336
467
|
} finally {
|
|
337
468
|
await fs.rm(tempDir, { recursive: true, force: true });
|
|
338
469
|
}
|
|
339
470
|
};
|
|
471
|
+
var getAiDatasetPartPath = (filePath, partIndex) => {
|
|
472
|
+
const parsed = path.parse(filePath);
|
|
473
|
+
return path.join(parsed.dir, `${parsed.name}-part${partIndex}${parsed.ext}`);
|
|
474
|
+
};
|
|
475
|
+
var getPartWindowEndExclusive = (timestamp, monthsPerPart) => {
|
|
476
|
+
const partStart = startOfMonth(new Date(timestamp));
|
|
477
|
+
return addMonths(partStart, Math.max(1, monthsPerPart)).getTime();
|
|
478
|
+
};
|
|
479
|
+
var splitAiMergedDatasetFile = async (params) => {
|
|
480
|
+
const { filePath, monthsPerPart = 2 } = params;
|
|
481
|
+
const resolvedMonthsPerPart = Math.max(1, Math.trunc(monthsPerPart));
|
|
482
|
+
const reader = readline.createInterface({
|
|
483
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
484
|
+
crlfDelay: Infinity
|
|
485
|
+
});
|
|
486
|
+
const partPaths = [];
|
|
487
|
+
let currentPartIndex = 0;
|
|
488
|
+
let currentPartPath = "";
|
|
489
|
+
let currentPartEndExclusive = Number.NaN;
|
|
490
|
+
let currentWriter = null;
|
|
491
|
+
let currentWriterDone = null;
|
|
492
|
+
let rowCount = 0;
|
|
493
|
+
const openPart = async (timestamp) => {
|
|
494
|
+
currentPartIndex += 1;
|
|
495
|
+
currentPartPath = getAiDatasetPartPath(filePath, currentPartIndex);
|
|
496
|
+
currentPartEndExclusive = getPartWindowEndExclusive(
|
|
497
|
+
timestamp,
|
|
498
|
+
resolvedMonthsPerPart
|
|
499
|
+
);
|
|
500
|
+
currentWriter = createWriteStream(currentPartPath, { encoding: "utf8" });
|
|
501
|
+
currentWriterDone = Promise.all([
|
|
502
|
+
once(currentWriter, "finish"),
|
|
503
|
+
once(currentWriter, "close")
|
|
504
|
+
]);
|
|
505
|
+
partPaths.push(currentPartPath);
|
|
506
|
+
};
|
|
507
|
+
const closeCurrentWriter = async () => {
|
|
508
|
+
if (!currentWriter || !currentWriterDone) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
currentWriter.end();
|
|
512
|
+
await currentWriterDone;
|
|
513
|
+
currentWriter = null;
|
|
514
|
+
currentWriterDone = null;
|
|
515
|
+
};
|
|
516
|
+
const getCurrentWriter = () => {
|
|
517
|
+
if (!currentWriter) {
|
|
518
|
+
throw new Error(
|
|
519
|
+
`AI dataset part writer was not initialized for ${filePath}`
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
return currentWriter;
|
|
523
|
+
};
|
|
524
|
+
try {
|
|
525
|
+
for await (const line of reader) {
|
|
526
|
+
const trimmed = line.trim();
|
|
527
|
+
if (!trimmed) {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
const row = parseAiDatasetLine(trimmed, filePath);
|
|
531
|
+
const timestamp = Number(row.timestamp);
|
|
532
|
+
const safeTimestamp = Number.isFinite(timestamp) ? timestamp : Date.now();
|
|
533
|
+
if (!currentWriter || !Number.isFinite(currentPartEndExclusive) || safeTimestamp >= currentPartEndExclusive) {
|
|
534
|
+
await closeCurrentWriter();
|
|
535
|
+
await openPart(safeTimestamp);
|
|
536
|
+
}
|
|
537
|
+
const writer = getCurrentWriter();
|
|
538
|
+
if (!writer.write(`${trimmed}
|
|
539
|
+
`)) {
|
|
540
|
+
await once(writer, "drain");
|
|
541
|
+
}
|
|
542
|
+
rowCount += 1;
|
|
543
|
+
}
|
|
544
|
+
} finally {
|
|
545
|
+
reader.close();
|
|
546
|
+
await closeCurrentWriter();
|
|
547
|
+
}
|
|
548
|
+
if (partPaths.length <= 1) {
|
|
549
|
+
for (const partPath of partPaths) {
|
|
550
|
+
await fs.rm(partPath, { force: true });
|
|
551
|
+
}
|
|
552
|
+
return {
|
|
553
|
+
partPaths: [filePath],
|
|
554
|
+
partCount: partPaths.length || (rowCount > 0 ? 1 : 0),
|
|
555
|
+
rowCount,
|
|
556
|
+
splitApplied: false
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
await fs.rm(filePath, { force: true });
|
|
560
|
+
return {
|
|
561
|
+
partPaths,
|
|
562
|
+
partCount: partPaths.length,
|
|
563
|
+
rowCount,
|
|
564
|
+
splitApplied: true
|
|
565
|
+
};
|
|
566
|
+
};
|
|
340
567
|
var readAiDatasetRows = async (params) => {
|
|
341
|
-
const {
|
|
568
|
+
const { limitFromEnd = 0, skipFromEnd = 0 } = params;
|
|
569
|
+
const resolvedFilePaths = resolveAiDatasetFilePaths(params);
|
|
570
|
+
if (!resolvedFilePaths.length) {
|
|
571
|
+
return {
|
|
572
|
+
rows: [],
|
|
573
|
+
totalRows: 0
|
|
574
|
+
};
|
|
575
|
+
}
|
|
342
576
|
const rows = [];
|
|
343
577
|
const recentLines = [];
|
|
344
578
|
let totalRows = 0;
|
|
345
579
|
const recentWindowLimit = limitFromEnd > 0 ? limitFromEnd + Math.max(0, skipFromEnd) : 0;
|
|
580
|
+
for (const currentFilePath of resolvedFilePaths) {
|
|
581
|
+
const reader = readline.createInterface({
|
|
582
|
+
input: createReadStream(currentFilePath, { encoding: "utf8" }),
|
|
583
|
+
crlfDelay: Infinity
|
|
584
|
+
});
|
|
585
|
+
for await (const line of reader) {
|
|
586
|
+
const trimmed = line.trim();
|
|
587
|
+
if (!trimmed) {
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
totalRows += 1;
|
|
591
|
+
if (limitFromEnd > 0) {
|
|
592
|
+
if (recentLines.length === recentWindowLimit) {
|
|
593
|
+
recentLines.shift();
|
|
594
|
+
}
|
|
595
|
+
recentLines.push(trimmed);
|
|
596
|
+
} else {
|
|
597
|
+
const row = JSON.parse(trimmed);
|
|
598
|
+
rows.push(row);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
reader.close();
|
|
602
|
+
}
|
|
603
|
+
const effectiveSkip = Math.max(0, skipFromEnd);
|
|
604
|
+
const selectedRecentLines = effectiveSkip > 0 ? recentLines.slice(0, Math.max(0, recentLines.length - effectiveSkip)) : recentLines;
|
|
605
|
+
const selectedRows = limitFromEnd > 0 ? selectedRecentLines.map((line) => JSON.parse(line)) : effectiveSkip > 0 ? rows.slice(0, Math.max(0, rows.length - effectiveSkip)) : rows;
|
|
606
|
+
return {
|
|
607
|
+
rows: selectedRows,
|
|
608
|
+
totalRows
|
|
609
|
+
};
|
|
610
|
+
};
|
|
611
|
+
var resolveAiDatasetFilePaths = (params) => (Array.isArray(params.filePaths) && params.filePaths.length ? params.filePaths : params.filePath ? [params.filePath] : []).map((item) => path.resolve(item));
|
|
612
|
+
var countNonEmptyAiDatasetRows = async (filePath) => {
|
|
613
|
+
let totalRows = 0;
|
|
346
614
|
const reader = readline.createInterface({
|
|
347
615
|
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
348
616
|
crlfDelay: Infinity
|
|
349
617
|
});
|
|
350
618
|
for await (const line of reader) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
619
|
+
if (line.trim()) {
|
|
620
|
+
totalRows += 1;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
reader.close();
|
|
624
|
+
return totalRows;
|
|
625
|
+
};
|
|
626
|
+
var countAiDatasetRows = async (params) => {
|
|
627
|
+
const { limitFromEnd = 0, skipFromEnd = 0 } = params;
|
|
628
|
+
const resolvedFilePaths = resolveAiDatasetFilePaths(params);
|
|
629
|
+
let totalRows = 0;
|
|
630
|
+
for (const filePath of resolvedFilePaths) {
|
|
631
|
+
totalRows += await countNonEmptyAiDatasetRows(filePath);
|
|
632
|
+
}
|
|
633
|
+
const effectiveSkip = Math.max(0, skipFromEnd);
|
|
634
|
+
const selectedRows = limitFromEnd > 0 ? Math.min(limitFromEnd, Math.max(0, totalRows - effectiveSkip)) : Math.max(0, totalRows - effectiveSkip);
|
|
635
|
+
return {
|
|
636
|
+
totalRows,
|
|
637
|
+
selectedRows
|
|
638
|
+
};
|
|
639
|
+
};
|
|
640
|
+
var streamAiDatasetRows = async (params) => {
|
|
641
|
+
const { limitFromEnd = 0, skipFromEnd = 0, onRow } = params;
|
|
642
|
+
const resolvedFilePaths = resolveAiDatasetFilePaths(params);
|
|
643
|
+
if (!resolvedFilePaths.length) {
|
|
644
|
+
return {
|
|
645
|
+
totalRows: 0,
|
|
646
|
+
selectedRows: 0
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
const effectiveSkip = Math.max(0, skipFromEnd);
|
|
650
|
+
let totalRows = 0;
|
|
651
|
+
let selectedRows = 0;
|
|
652
|
+
if (limitFromEnd > 0) {
|
|
653
|
+
const recentLines = [];
|
|
654
|
+
const recentWindowLimit = limitFromEnd + effectiveSkip;
|
|
655
|
+
for (const currentFilePath of resolvedFilePaths) {
|
|
656
|
+
const reader = readline.createInterface({
|
|
657
|
+
input: createReadStream(currentFilePath, { encoding: "utf8" }),
|
|
658
|
+
crlfDelay: Infinity
|
|
659
|
+
});
|
|
660
|
+
for await (const line of reader) {
|
|
661
|
+
const trimmed = line.trim();
|
|
662
|
+
if (!trimmed) {
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
totalRows += 1;
|
|
666
|
+
if (recentLines.length === recentWindowLimit) {
|
|
667
|
+
recentLines.shift();
|
|
668
|
+
}
|
|
669
|
+
recentLines.push(trimmed);
|
|
670
|
+
}
|
|
671
|
+
reader.close();
|
|
672
|
+
}
|
|
673
|
+
const selectedRecentLines = effectiveSkip > 0 ? recentLines.slice(0, Math.max(0, recentLines.length - effectiveSkip)) : recentLines;
|
|
674
|
+
for (const line of selectedRecentLines) {
|
|
675
|
+
await onRow(JSON.parse(line), selectedRows);
|
|
676
|
+
selectedRows += 1;
|
|
354
677
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
678
|
+
return {
|
|
679
|
+
totalRows,
|
|
680
|
+
selectedRows
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
const trailingSkipBuffer = [];
|
|
684
|
+
for (const currentFilePath of resolvedFilePaths) {
|
|
685
|
+
const reader = readline.createInterface({
|
|
686
|
+
input: createReadStream(currentFilePath, { encoding: "utf8" }),
|
|
687
|
+
crlfDelay: Infinity
|
|
688
|
+
});
|
|
689
|
+
for await (const line of reader) {
|
|
690
|
+
const trimmed = line.trim();
|
|
691
|
+
if (!trimmed) {
|
|
692
|
+
continue;
|
|
359
693
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
694
|
+
totalRows += 1;
|
|
695
|
+
if (effectiveSkip > 0) {
|
|
696
|
+
trailingSkipBuffer.push(trimmed);
|
|
697
|
+
if (trailingSkipBuffer.length <= effectiveSkip) {
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
const selectedLine = trailingSkipBuffer.shift();
|
|
701
|
+
if (!selectedLine) {
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
await onRow(JSON.parse(selectedLine), selectedRows);
|
|
705
|
+
selectedRows += 1;
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
await onRow(JSON.parse(trimmed), selectedRows);
|
|
709
|
+
selectedRows += 1;
|
|
364
710
|
}
|
|
711
|
+
reader.close();
|
|
365
712
|
}
|
|
366
|
-
const effectiveSkip = Math.max(0, skipFromEnd);
|
|
367
|
-
const selectedRecentLines = effectiveSkip > 0 ? recentLines.slice(0, Math.max(0, recentLines.length - effectiveSkip)) : recentLines;
|
|
368
|
-
const selectedRows = limitFromEnd > 0 ? selectedRecentLines.map((line) => JSON.parse(line)) : effectiveSkip > 0 ? rows.slice(0, Math.max(0, rows.length - effectiveSkip)) : rows;
|
|
369
713
|
return {
|
|
370
|
-
|
|
371
|
-
|
|
714
|
+
totalRows,
|
|
715
|
+
selectedRows
|
|
372
716
|
};
|
|
373
717
|
};
|
|
374
718
|
export {
|
|
375
719
|
appendAiDatasetRow,
|
|
376
720
|
closeAiDatasetWriter,
|
|
377
721
|
closeAllAiDatasetWriters,
|
|
722
|
+
countAiDatasetRows,
|
|
378
723
|
flushAiDatasetWriter,
|
|
379
724
|
getAiChunkFilePath,
|
|
380
725
|
listAiChunkFiles,
|
|
726
|
+
listAiChunkRunIds,
|
|
381
727
|
listAiChunkStrategies,
|
|
382
728
|
mergeAiJsonlFiles,
|
|
383
729
|
mergeJsonlFiles,
|
|
384
730
|
readAiDatasetRows,
|
|
731
|
+
splitAiMergedDatasetFile,
|
|
732
|
+
streamAiDatasetRows,
|
|
385
733
|
toFileToken
|
|
386
734
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { OrderLogData, PositionLogData } from '@tradejs/types';
|
|
2
|
+
|
|
3
|
+
interface BacktestArtifactRef {
|
|
4
|
+
kind: 'file';
|
|
5
|
+
version: 1;
|
|
6
|
+
path: string;
|
|
7
|
+
}
|
|
8
|
+
declare const writeCachedBacktestArtifacts: ({ orderLog, orderLogId, positionLog, projectRoot, userName, }: {
|
|
9
|
+
orderLog: OrderLogData;
|
|
10
|
+
orderLogId: string;
|
|
11
|
+
positionLog: PositionLogData;
|
|
12
|
+
projectRoot?: string;
|
|
13
|
+
userName: string;
|
|
14
|
+
}) => Promise<{
|
|
15
|
+
orderLog: BacktestArtifactRef;
|
|
16
|
+
positionLog: BacktestArtifactRef;
|
|
17
|
+
}>;
|
|
18
|
+
declare const readCachedBacktestArtifacts: ({ orderLogId, projectRoot, userName, }: {
|
|
19
|
+
orderLogId: string;
|
|
20
|
+
projectRoot?: string;
|
|
21
|
+
userName: string;
|
|
22
|
+
}) => Promise<{
|
|
23
|
+
orderLog: OrderLogData | null;
|
|
24
|
+
positionLog: PositionLogData | null;
|
|
25
|
+
}>;
|
|
26
|
+
declare const deleteCachedBacktestArtifacts: ({ orderLogId, projectRoot, userName, }: {
|
|
27
|
+
orderLogId: string;
|
|
28
|
+
projectRoot?: string;
|
|
29
|
+
userName: string;
|
|
30
|
+
}) => Promise<boolean>;
|
|
31
|
+
declare const writePersistedBacktestOrderLog: ({ orderLog, projectRoot, strategyName, testName, userName, }: {
|
|
32
|
+
orderLog: OrderLogData;
|
|
33
|
+
projectRoot?: string;
|
|
34
|
+
strategyName: string;
|
|
35
|
+
testName: string;
|
|
36
|
+
userName: string;
|
|
37
|
+
}) => Promise<BacktestArtifactRef>;
|
|
38
|
+
declare const readPersistedBacktestOrderLog: ({ projectRoot, ref, strategyName, testName, userName, }: {
|
|
39
|
+
projectRoot?: string;
|
|
40
|
+
ref?: BacktestArtifactRef | null;
|
|
41
|
+
strategyName: string;
|
|
42
|
+
testName: string;
|
|
43
|
+
userName: string;
|
|
44
|
+
}) => Promise<OrderLogData | null>;
|
|
45
|
+
declare const deletePersistedBacktestOrderLog: ({ projectRoot, ref, strategyName, testName, userName, }: {
|
|
46
|
+
projectRoot?: string;
|
|
47
|
+
ref?: BacktestArtifactRef | null;
|
|
48
|
+
strategyName: string;
|
|
49
|
+
testName: string;
|
|
50
|
+
userName: string;
|
|
51
|
+
}) => Promise<boolean>;
|
|
52
|
+
declare const parseBacktestArtifactRef: (value: unknown) => BacktestArtifactRef | null;
|
|
53
|
+
declare const getBacktestArtifactsRootDir: (projectRoot?: string) => string;
|
|
54
|
+
declare const getBacktestCacheArtifactsDirForUser: (userName: string, projectRoot?: string) => string;
|
|
55
|
+
declare const getPersistedBacktestArtifactsDirForUser: (userName: string, projectRoot?: string) => string;
|
|
56
|
+
|
|
57
|
+
export { type BacktestArtifactRef, deleteCachedBacktestArtifacts, deletePersistedBacktestOrderLog, getBacktestArtifactsRootDir, getBacktestCacheArtifactsDirForUser, getPersistedBacktestArtifactsDirForUser, parseBacktestArtifactRef, readCachedBacktestArtifacts, readPersistedBacktestOrderLog, writeCachedBacktestArtifacts, writePersistedBacktestOrderLog };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { OrderLogData, PositionLogData } from '@tradejs/types';
|
|
2
|
+
|
|
3
|
+
interface BacktestArtifactRef {
|
|
4
|
+
kind: 'file';
|
|
5
|
+
version: 1;
|
|
6
|
+
path: string;
|
|
7
|
+
}
|
|
8
|
+
declare const writeCachedBacktestArtifacts: ({ orderLog, orderLogId, positionLog, projectRoot, userName, }: {
|
|
9
|
+
orderLog: OrderLogData;
|
|
10
|
+
orderLogId: string;
|
|
11
|
+
positionLog: PositionLogData;
|
|
12
|
+
projectRoot?: string;
|
|
13
|
+
userName: string;
|
|
14
|
+
}) => Promise<{
|
|
15
|
+
orderLog: BacktestArtifactRef;
|
|
16
|
+
positionLog: BacktestArtifactRef;
|
|
17
|
+
}>;
|
|
18
|
+
declare const readCachedBacktestArtifacts: ({ orderLogId, projectRoot, userName, }: {
|
|
19
|
+
orderLogId: string;
|
|
20
|
+
projectRoot?: string;
|
|
21
|
+
userName: string;
|
|
22
|
+
}) => Promise<{
|
|
23
|
+
orderLog: OrderLogData | null;
|
|
24
|
+
positionLog: PositionLogData | null;
|
|
25
|
+
}>;
|
|
26
|
+
declare const deleteCachedBacktestArtifacts: ({ orderLogId, projectRoot, userName, }: {
|
|
27
|
+
orderLogId: string;
|
|
28
|
+
projectRoot?: string;
|
|
29
|
+
userName: string;
|
|
30
|
+
}) => Promise<boolean>;
|
|
31
|
+
declare const writePersistedBacktestOrderLog: ({ orderLog, projectRoot, strategyName, testName, userName, }: {
|
|
32
|
+
orderLog: OrderLogData;
|
|
33
|
+
projectRoot?: string;
|
|
34
|
+
strategyName: string;
|
|
35
|
+
testName: string;
|
|
36
|
+
userName: string;
|
|
37
|
+
}) => Promise<BacktestArtifactRef>;
|
|
38
|
+
declare const readPersistedBacktestOrderLog: ({ projectRoot, ref, strategyName, testName, userName, }: {
|
|
39
|
+
projectRoot?: string;
|
|
40
|
+
ref?: BacktestArtifactRef | null;
|
|
41
|
+
strategyName: string;
|
|
42
|
+
testName: string;
|
|
43
|
+
userName: string;
|
|
44
|
+
}) => Promise<OrderLogData | null>;
|
|
45
|
+
declare const deletePersistedBacktestOrderLog: ({ projectRoot, ref, strategyName, testName, userName, }: {
|
|
46
|
+
projectRoot?: string;
|
|
47
|
+
ref?: BacktestArtifactRef | null;
|
|
48
|
+
strategyName: string;
|
|
49
|
+
testName: string;
|
|
50
|
+
userName: string;
|
|
51
|
+
}) => Promise<boolean>;
|
|
52
|
+
declare const parseBacktestArtifactRef: (value: unknown) => BacktestArtifactRef | null;
|
|
53
|
+
declare const getBacktestArtifactsRootDir: (projectRoot?: string) => string;
|
|
54
|
+
declare const getBacktestCacheArtifactsDirForUser: (userName: string, projectRoot?: string) => string;
|
|
55
|
+
declare const getPersistedBacktestArtifactsDirForUser: (userName: string, projectRoot?: string) => string;
|
|
56
|
+
|
|
57
|
+
export { type BacktestArtifactRef, deleteCachedBacktestArtifacts, deletePersistedBacktestOrderLog, getBacktestArtifactsRootDir, getBacktestCacheArtifactsDirForUser, getPersistedBacktestArtifactsDirForUser, parseBacktestArtifactRef, readCachedBacktestArtifacts, readPersistedBacktestOrderLog, writeCachedBacktestArtifacts, writePersistedBacktestOrderLog };
|