@tradejs/infra 1.0.8 → 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-DSTV67R5.mjs → chunk-DXG2UDNA.mjs} +185 -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 +31 -3
- package/dist/redis.d.ts +31 -3
- package/dist/redis.js +194 -7
- package/dist/redis.mjs +17 -3
- 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 +30 -5
- package/dist/userSettings.mjs +2 -1
- package/package.json +13 -3
|
@@ -12,9 +12,12 @@ var logger = {
|
|
|
12
12
|
};
|
|
13
13
|
var redisConnectionWarningShown = false;
|
|
14
14
|
var redisUnavailable = false;
|
|
15
|
-
var isRedisConnectivityError = (error) =>
|
|
16
|
-
error.message
|
|
17
|
-
|
|
15
|
+
var isRedisConnectivityError = (error) => {
|
|
16
|
+
const errorText = [error.name, error.message, String(error)].join(" ");
|
|
17
|
+
return /ECONNREFUSED|ECONNRESET|ECONNABORTED|EPIPE|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|MaxRetriesPerRequestError|Connection is closed|Stream isn't writeable/i.test(
|
|
18
|
+
errorText
|
|
19
|
+
);
|
|
20
|
+
};
|
|
18
21
|
var toNonNegativeInt = (value, fallback) => {
|
|
19
22
|
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
20
23
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
@@ -70,6 +73,16 @@ var getRedis = () => {
|
|
|
70
73
|
}
|
|
71
74
|
return global.__redis__;
|
|
72
75
|
};
|
|
76
|
+
var closeRedisConnection = async () => {
|
|
77
|
+
const redis = global.__redis__;
|
|
78
|
+
if (!redis) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
global.__redis__ = void 0;
|
|
82
|
+
redisUnavailable = false;
|
|
83
|
+
redisConnectionWarningShown = false;
|
|
84
|
+
redis.disconnect();
|
|
85
|
+
};
|
|
73
86
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
74
87
|
var getRedisStatus = (redis) => String(redis.status ?? "ready");
|
|
75
88
|
var waitForRedisReady = async (redis) => {
|
|
@@ -110,6 +123,11 @@ var toResultString = (result) => {
|
|
|
110
123
|
if (Buffer.isBuffer(result)) return result.toString("utf8");
|
|
111
124
|
return String(result);
|
|
112
125
|
};
|
|
126
|
+
var publishData = async (channel, value) => {
|
|
127
|
+
const redis = await getReadyRedis();
|
|
128
|
+
if (!redis) return 0;
|
|
129
|
+
return redis.publish(channel, toJson(value));
|
|
130
|
+
};
|
|
113
131
|
var DEFAULT_OPTIONS = {
|
|
114
132
|
expire: TTL_1D
|
|
115
133
|
};
|
|
@@ -122,6 +140,31 @@ var parseJsonOrDeleteKey = async (redis, key, raw, fallback) => {
|
|
|
122
140
|
return fallback;
|
|
123
141
|
}
|
|
124
142
|
};
|
|
143
|
+
var parseHashMap = (value) => {
|
|
144
|
+
if (!value) {
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
const result = {};
|
|
149
|
+
for (let index = 0; index < value.length; index += 2) {
|
|
150
|
+
const field = value[index];
|
|
151
|
+
const fieldValue = value[index + 1];
|
|
152
|
+
if (field == null || fieldValue == null) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
result[String(field)] = toResultString(fieldValue) ?? "";
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
if (typeof value === "object") {
|
|
160
|
+
return Object.fromEntries(
|
|
161
|
+
Object.entries(value).map(
|
|
162
|
+
([field, fieldValue]) => [field, toResultString(fieldValue) ?? ""]
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
return {};
|
|
167
|
+
};
|
|
125
168
|
var getKeys = async (prefix) => {
|
|
126
169
|
if (redisUnavailable) return [];
|
|
127
170
|
const redis = await getReadyRedis();
|
|
@@ -258,6 +301,115 @@ var setData = async (key, data, options = {}) => {
|
|
|
258
301
|
}
|
|
259
302
|
}
|
|
260
303
|
};
|
|
304
|
+
var setHashJsonField = async (key, field, data, options = {}) => {
|
|
305
|
+
if (redisUnavailable) return;
|
|
306
|
+
const { expire } = { ...DEFAULT_OPTIONS, ...options };
|
|
307
|
+
const redis = await getReadyRedis();
|
|
308
|
+
if (!redis) return;
|
|
309
|
+
try {
|
|
310
|
+
await redis.call("HSET", key, field, toJson(data));
|
|
311
|
+
if (expire) {
|
|
312
|
+
await redis.expire(key, expire);
|
|
313
|
+
}
|
|
314
|
+
} catch (e) {
|
|
315
|
+
if (e instanceof Error && isRedisConnectivityError(e)) {
|
|
316
|
+
markRedisUnavailable(e);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
logger.log("error", "failed HSET %s[%s]: %s", key, field, String(e));
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
var getHashJsonField = async (key, field, fallback = null) => {
|
|
323
|
+
if (redisUnavailable) return fallback;
|
|
324
|
+
const redis = await getReadyRedis();
|
|
325
|
+
if (!redis) return fallback;
|
|
326
|
+
try {
|
|
327
|
+
const value = await redis.call("HGET", key, field);
|
|
328
|
+
if (typeof value !== "string" || !value) {
|
|
329
|
+
return fallback;
|
|
330
|
+
}
|
|
331
|
+
return JSON.parse(value);
|
|
332
|
+
} catch (e) {
|
|
333
|
+
if (e instanceof Error && isRedisConnectivityError(e)) {
|
|
334
|
+
markRedisUnavailable(e);
|
|
335
|
+
return fallback;
|
|
336
|
+
}
|
|
337
|
+
logger.log("error", "failed HGET %s[%s]: %s", key, field, String(e));
|
|
338
|
+
return fallback;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
var getHashJsonValues = async (key) => {
|
|
342
|
+
if (redisUnavailable) return [];
|
|
343
|
+
const redis = await getReadyRedis();
|
|
344
|
+
if (!redis) return [];
|
|
345
|
+
try {
|
|
346
|
+
const raw = await redis.call("HGETALL", key);
|
|
347
|
+
const values = Object.values(parseHashMap(raw));
|
|
348
|
+
const parsed = [];
|
|
349
|
+
for (const value of values) {
|
|
350
|
+
if (!value) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
parsed.push(JSON.parse(value));
|
|
355
|
+
} catch (e) {
|
|
356
|
+
logger.log(
|
|
357
|
+
"error",
|
|
358
|
+
"failed JSON.parse(HGETALL %s value): %s",
|
|
359
|
+
key,
|
|
360
|
+
String(e)
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return parsed;
|
|
365
|
+
} catch (e) {
|
|
366
|
+
if (e instanceof Error && isRedisConnectivityError(e)) {
|
|
367
|
+
markRedisUnavailable(e);
|
|
368
|
+
return [];
|
|
369
|
+
}
|
|
370
|
+
logger.log("error", "failed HGETALL %s: %s", key, String(e));
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
var incrHashFields = async (key, increments, options = {}) => {
|
|
375
|
+
if (redisUnavailable) return;
|
|
376
|
+
const { expire } = { ...DEFAULT_OPTIONS, ...options };
|
|
377
|
+
const redis = await getReadyRedis();
|
|
378
|
+
if (!redis) return;
|
|
379
|
+
try {
|
|
380
|
+
for (const [field, increment] of Object.entries(increments)) {
|
|
381
|
+
if (!Number.isFinite(increment) || increment === 0) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
await redis.call("HINCRBY", key, field, Math.trunc(increment));
|
|
385
|
+
}
|
|
386
|
+
if (expire) {
|
|
387
|
+
await redis.expire(key, expire);
|
|
388
|
+
}
|
|
389
|
+
} catch (e) {
|
|
390
|
+
if (e instanceof Error && isRedisConnectivityError(e)) {
|
|
391
|
+
markRedisUnavailable(e);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
logger.log("error", "failed HINCRBY %s: %s", key, String(e));
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
var getHashData = async (key) => {
|
|
398
|
+
if (redisUnavailable) return {};
|
|
399
|
+
const redis = await getReadyRedis();
|
|
400
|
+
if (!redis) return {};
|
|
401
|
+
try {
|
|
402
|
+
const raw = await redis.call("HGETALL", key);
|
|
403
|
+
return parseHashMap(raw);
|
|
404
|
+
} catch (e) {
|
|
405
|
+
if (e instanceof Error && isRedisConnectivityError(e)) {
|
|
406
|
+
markRedisUnavailable(e);
|
|
407
|
+
return {};
|
|
408
|
+
}
|
|
409
|
+
logger.log("error", "failed HGETALL %s: %s", key, String(e));
|
|
410
|
+
return {};
|
|
411
|
+
}
|
|
412
|
+
};
|
|
261
413
|
var createScreenshotSessionToken = async (userName) => {
|
|
262
414
|
const token = randomBytes(24).toString("hex");
|
|
263
415
|
await setData(
|
|
@@ -291,13 +443,21 @@ var consumeScreenshotSessionToken = async (token) => {
|
|
|
291
443
|
var redisKeys = {
|
|
292
444
|
users: () => "users:index:",
|
|
293
445
|
user: (userName) => `users:index:${userName}`,
|
|
446
|
+
tradingAccounts: (userName) => `users:${userName}:trading-accounts:`,
|
|
447
|
+
tradingAccount: (userName, accountId) => `users:${userName}:trading-accounts:${accountId}`,
|
|
448
|
+
runtimeDeployments: (userName) => `users:${userName}:runtime:deployments:`,
|
|
449
|
+
runtimeDeployment: (userName, deploymentId) => `users:${userName}:runtime:deployments:${deploymentId}`,
|
|
450
|
+
runtimeDeploymentHeartbeat: (userName, deploymentId) => `users:${userName}:runtime:deployments:${deploymentId}:heartbeat`,
|
|
294
451
|
bots: (userName) => `users:${userName}:bots`,
|
|
295
452
|
botsPrefix: () => "users:",
|
|
296
453
|
bot: (userName, botId) => `users:${userName}:bots:${botId}`,
|
|
297
454
|
backtestConfig: (userName, config) => `users:${userName}:backtests:configs:${config}`,
|
|
298
455
|
strategies: (userName) => `users:${userName}:strategies`,
|
|
299
|
-
strategyConfig: (userName, strategyName) => `users:${userName}:strategies:${strategyName}
|
|
456
|
+
strategyConfig: (userName, strategyName, configId = "config") => `users:${userName}:strategies:${strategyName}:${configId}`,
|
|
300
457
|
strategyResults: (userName, strategyName) => `users:${userName}:strategies:${strategyName}:results`,
|
|
458
|
+
strategyCharts: (userName, mode) => `users:${userName}:strategies:charts:${mode}`,
|
|
459
|
+
strategyChartCards: (userName, mode) => `users:${userName}:strategies:charts:${mode}:cards:`,
|
|
460
|
+
strategyChartCard: (userName, mode, cardId) => `users:${userName}:strategies:charts:${mode}:cards:${cardId}`,
|
|
301
461
|
tests: (userName, strategyName) => strategyName ? `users:${userName}:tests:${strategyName}` : `users:${userName}:tests:`,
|
|
302
462
|
testOrders: (userName, strategyName, testName) => `users:${userName}:tests:${strategyName}:${testName}:orders`,
|
|
303
463
|
testConfig: (userName, strategyName, testName) => `users:${userName}:tests:${strategyName}:${testName}:config`,
|
|
@@ -306,21 +466,34 @@ var redisKeys = {
|
|
|
306
466
|
cacheChunk: (userName, chunkId) => `users:${userName}:cache:tests:chunks:${chunkId}`,
|
|
307
467
|
cacheOrders: (userName, orderLogId) => `users:${userName}:cache:tests:orders:${orderLogId}`,
|
|
308
468
|
cachePositions: (userName, orderLogId) => `users:${userName}:cache:tests:positions:${orderLogId}`,
|
|
469
|
+
tickerUniverse: (userName, connectorName, universe, accountId) => universe || accountId ? `users:${userName}:cache:tickers:${connectorName}:${universe ?? "crypto"}:${accountId ?? "default"}` : `users:${userName}:cache:tickers:${connectorName}`,
|
|
309
470
|
signal: (symbol, signalId) => `signals:${symbol}:${signalId}`,
|
|
310
471
|
signalsBySymbol: (symbol) => `signals:${symbol}:`,
|
|
311
472
|
storeSignal: (symbol, signalId) => `store:signals:${symbol}:${signalId}`,
|
|
312
473
|
runtimeSignals: (userName) => `users:${userName}:runtime:signals:`,
|
|
313
474
|
runtimeSignal: (userName, signalId) => `users:${userName}:runtime:signals:${signalId}`,
|
|
475
|
+
runtimeSignalBuckets: (userName) => `users:${userName}:runtime:signals:days:`,
|
|
476
|
+
runtimeSignalBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signals:days:${dayKey}:${strategyName}`,
|
|
314
477
|
runtimeSignalEvaluations: (userName) => `users:${userName}:runtime:signal-evaluations:`,
|
|
315
478
|
runtimeSignalEvaluation: (userName, evaluationId) => `users:${userName}:runtime:signal-evaluations:${evaluationId}`,
|
|
479
|
+
runtimeSignalEvaluationBuckets: (userName) => `users:${userName}:runtime:signal-evaluations:days:`,
|
|
480
|
+
runtimeSignalEvaluationBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluations:days:${dayKey}:${strategyName}`,
|
|
481
|
+
runtimeSignalEvaluationStatsBuckets: (userName) => `users:${userName}:runtime:signal-evaluation-stats:days:`,
|
|
482
|
+
runtimeSignalEvaluationStatsBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluation-stats:days:${dayKey}:${strategyName}`,
|
|
316
483
|
runtimeTrades: (userName) => `users:${userName}:runtime:trade-records:`,
|
|
317
484
|
runtimeTrade: (userName, orderId) => `users:${userName}:runtime:trade-records:${orderId}`,
|
|
485
|
+
runtimeTradeBuckets: (userName) => `users:${userName}:runtime:trade-records:days:`,
|
|
486
|
+
runtimeTradeBucket: (userName, dayKey) => `users:${userName}:runtime:trade-records:days:${dayKey}`,
|
|
318
487
|
runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
|
|
319
|
-
runtimeActiveTrade: (userName, symbol) => `users:${userName}:runtime:active-trades:${symbol}`,
|
|
488
|
+
runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
|
|
320
489
|
aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
|
|
321
490
|
analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
|
|
322
491
|
screenshotSessionToken: (token) => `auth:screenshot:${token}`,
|
|
323
492
|
backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
|
|
493
|
+
backtestRuns: (userName) => `users:${userName}:backtests:runs:`,
|
|
494
|
+
backtestRun: (userName, runId) => `users:${userName}:backtests:runs:${runId}`,
|
|
495
|
+
backtestRunResults: (userName, runId) => `users:${userName}:backtests:runs:${runId}:results`,
|
|
496
|
+
backtestLatestRun: (userName, config) => `users:${userName}:backtests:latest:${config}`,
|
|
324
497
|
researchRuns: (userName) => `users:${userName}:research:runs:`,
|
|
325
498
|
researchRun: (userName, runId) => `users:${userName}:research:runs:${runId}`,
|
|
326
499
|
researchLatestRun: (userName, strategyName) => `users:${userName}:research:latest:${strategyName}`,
|
|
@@ -333,12 +506,19 @@ var redisKeys = {
|
|
|
333
506
|
};
|
|
334
507
|
|
|
335
508
|
export {
|
|
509
|
+
closeRedisConnection,
|
|
510
|
+
publishData,
|
|
336
511
|
getKeys,
|
|
337
512
|
getData,
|
|
338
513
|
delKey,
|
|
339
514
|
RedisWriteBlockedError,
|
|
340
515
|
delKeyWithOptions,
|
|
341
516
|
setData,
|
|
517
|
+
setHashJsonField,
|
|
518
|
+
getHashJsonField,
|
|
519
|
+
getHashJsonValues,
|
|
520
|
+
incrHashFields,
|
|
521
|
+
getHashData,
|
|
342
522
|
createScreenshotSessionToken,
|
|
343
523
|
consumeScreenshotSessionToken,
|
|
344
524
|
redisKeys
|
|
@@ -3,15 +3,26 @@ import { once } from "events";
|
|
|
3
3
|
import { createReadStream, createWriteStream } from "fs";
|
|
4
4
|
import fs from "fs/promises";
|
|
5
5
|
import path from "path";
|
|
6
|
+
import readline from "readline";
|
|
6
7
|
var DEFAULT_DIR = "data/ml/export";
|
|
7
8
|
var ML_DATASET_WRITE_BATCH_SIZE = 200;
|
|
8
9
|
var ML_CHUNK_FILE_RE = /^ml-dataset-(.+)-chunk-[^.]+\.jsonl$/;
|
|
10
|
+
var BACKTEST_RUN_CHUNK_ID_RE = /^(\d{12}-[a-f0-9]{8})-/;
|
|
9
11
|
var writerByPath = /* @__PURE__ */ new Map();
|
|
10
12
|
var toFileToken = (value) => value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "any";
|
|
11
13
|
var getMlChunkFilePath = (strategyName, chunkId, outDir = DEFAULT_DIR) => path.join(
|
|
12
14
|
outDir,
|
|
13
15
|
`ml-dataset-${toFileToken(strategyName)}-chunk-${toFileToken(chunkId)}.jsonl`
|
|
14
16
|
);
|
|
17
|
+
var getMlChunkFilePrefix = (strategyName, runId) => `ml-dataset-${toFileToken(strategyName)}-chunk-${runId ? `${toFileToken(runId)}-` : ""}`;
|
|
18
|
+
var getRunIdFromMlChunkFileName = (strategyName, fileName) => {
|
|
19
|
+
const prefix = getMlChunkFilePrefix(strategyName);
|
|
20
|
+
if (!fileName.startsWith(prefix) || !fileName.endsWith(".jsonl")) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
const chunkToken = fileName.slice(prefix.length, -".jsonl".length);
|
|
24
|
+
return chunkToken.match(BACKTEST_RUN_CHUNK_ID_RE)?.[1] ?? "";
|
|
25
|
+
};
|
|
15
26
|
var appendMlDatasetRow = async (params) => {
|
|
16
27
|
const { strategyName, chunkId, row, outDir = DEFAULT_DIR } = params;
|
|
17
28
|
const filePath = getMlChunkFilePath(strategyName, chunkId, outDir);
|
|
@@ -85,8 +96,8 @@ var closeAllMlDatasetWriters = async () => {
|
|
|
85
96
|
}
|
|
86
97
|
};
|
|
87
98
|
var listMlChunkFiles = async (params) => {
|
|
88
|
-
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
89
|
-
const prefix =
|
|
99
|
+
const { strategyName, outDir = DEFAULT_DIR, runId } = params;
|
|
100
|
+
const prefix = getMlChunkFilePrefix(strategyName, runId);
|
|
90
101
|
let entries = [];
|
|
91
102
|
try {
|
|
92
103
|
entries = await fs.readdir(outDir);
|
|
@@ -95,6 +106,20 @@ var listMlChunkFiles = async (params) => {
|
|
|
95
106
|
}
|
|
96
107
|
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).map((name) => path.join(outDir, name)).sort();
|
|
97
108
|
};
|
|
109
|
+
var listMlChunkRunIds = async (params) => {
|
|
110
|
+
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
111
|
+
let entries = [];
|
|
112
|
+
try {
|
|
113
|
+
entries = await fs.readdir(outDir);
|
|
114
|
+
} catch {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
return [
|
|
118
|
+
...new Set(
|
|
119
|
+
entries.map((name) => getRunIdFromMlChunkFileName(strategyName, name)).filter(Boolean)
|
|
120
|
+
)
|
|
121
|
+
].sort();
|
|
122
|
+
};
|
|
98
123
|
var listMlChunkStrategies = async (params) => {
|
|
99
124
|
const outDir = params?.outDir ?? DEFAULT_DIR;
|
|
100
125
|
let entries = [];
|
|
@@ -110,12 +135,37 @@ var listMlChunkStrategies = async (params) => {
|
|
|
110
135
|
].sort();
|
|
111
136
|
};
|
|
112
137
|
var mergeJsonlFiles = async (params) => {
|
|
113
|
-
const { filePaths, outPath } = params;
|
|
138
|
+
const { filePaths, outPath, shouldIncludeRow } = params;
|
|
114
139
|
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
115
140
|
const stream = createWriteStream(outPath, { encoding: "utf8" });
|
|
116
141
|
const done = Promise.all([once(stream, "finish"), once(stream, "close")]);
|
|
117
142
|
try {
|
|
118
143
|
for (const filePath of filePaths) {
|
|
144
|
+
if (shouldIncludeRow) {
|
|
145
|
+
const reader2 = readline.createInterface({
|
|
146
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
147
|
+
crlfDelay: Infinity
|
|
148
|
+
});
|
|
149
|
+
try {
|
|
150
|
+
for await (const line of reader2) {
|
|
151
|
+
const trimmed = line.trim();
|
|
152
|
+
if (!trimmed) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const row = JSON.parse(trimmed);
|
|
156
|
+
if (!shouldIncludeRow(row)) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (!stream.write(`${trimmed}
|
|
160
|
+
`)) {
|
|
161
|
+
await once(stream, "drain");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} finally {
|
|
165
|
+
reader2.close();
|
|
166
|
+
}
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
119
169
|
const reader = createReadStream(filePath, { encoding: "utf8" });
|
|
120
170
|
for await (const chunk of reader) {
|
|
121
171
|
if (!stream.write(chunk)) {
|
|
@@ -137,6 +187,7 @@ export {
|
|
|
137
187
|
closeMlDatasetWriter,
|
|
138
188
|
closeAllMlDatasetWriters,
|
|
139
189
|
listMlChunkFiles,
|
|
190
|
+
listMlChunkRunIds,
|
|
140
191
|
listMlChunkStrategies,
|
|
141
192
|
mergeJsonlFiles
|
|
142
193
|
};
|
package/dist/ml.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as appendMlDatasetRow, c as closeAllMlDatasetWriters, b as closeMlDatasetWriter, f as flushMlDatasetWriter, g as getMlChunkFilePath, l as listMlChunkFiles, d as listMlChunkStrategies, m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-
|
|
1
|
+
export { a as appendMlDatasetRow, c as closeAllMlDatasetWriters, b as closeMlDatasetWriter, f as flushMlDatasetWriter, g as getMlChunkFilePath, l as listMlChunkFiles, d as listMlChunkRunIds, e as listMlChunkStrategies, m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-Czx__g9M.mjs';
|
|
2
2
|
|
|
3
3
|
type MlPredictResponse = {
|
|
4
4
|
probability: number;
|
package/dist/ml.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as appendMlDatasetRow, c as closeAllMlDatasetWriters, b as closeMlDatasetWriter, f as flushMlDatasetWriter, g as getMlChunkFilePath, l as listMlChunkFiles, d as listMlChunkStrategies, m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-
|
|
1
|
+
export { a as appendMlDatasetRow, c as closeAllMlDatasetWriters, b as closeMlDatasetWriter, f as flushMlDatasetWriter, g as getMlChunkFilePath, l as listMlChunkFiles, d as listMlChunkRunIds, e as listMlChunkStrategies, m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-Czx__g9M.js';
|
|
2
2
|
|
|
3
3
|
type MlPredictResponse = {
|
|
4
4
|
probability: number;
|
package/dist/ml.js
CHANGED
|
@@ -45,6 +45,7 @@ __export(ml_exports, {
|
|
|
45
45
|
isDerivedDatasetFileName: () => isDerivedDatasetFileName,
|
|
46
46
|
isTimestampFeatureKey: () => isTimestampFeatureKey,
|
|
47
47
|
listMlChunkFiles: () => listMlChunkFiles,
|
|
48
|
+
listMlChunkRunIds: () => listMlChunkRunIds,
|
|
48
49
|
listMlChunkStrategies: () => listMlChunkStrategies,
|
|
49
50
|
mergeJsonlFiles: () => mergeJsonlFiles,
|
|
50
51
|
toFileToken: () => toFileToken,
|
|
@@ -58,15 +59,26 @@ var import_events = require("events");
|
|
|
58
59
|
var import_fs = require("fs");
|
|
59
60
|
var import_promises = __toESM(require("fs/promises"));
|
|
60
61
|
var import_path = __toESM(require("path"));
|
|
62
|
+
var import_node_readline = __toESM(require("readline"));
|
|
61
63
|
var DEFAULT_DIR = "data/ml/export";
|
|
62
64
|
var ML_DATASET_WRITE_BATCH_SIZE = 200;
|
|
63
65
|
var ML_CHUNK_FILE_RE = /^ml-dataset-(.+)-chunk-[^.]+\.jsonl$/;
|
|
66
|
+
var BACKTEST_RUN_CHUNK_ID_RE = /^(\d{12}-[a-f0-9]{8})-/;
|
|
64
67
|
var writerByPath = /* @__PURE__ */ new Map();
|
|
65
68
|
var toFileToken = (value) => value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "any";
|
|
66
69
|
var getMlChunkFilePath = (strategyName, chunkId, outDir = DEFAULT_DIR) => import_path.default.join(
|
|
67
70
|
outDir,
|
|
68
71
|
`ml-dataset-${toFileToken(strategyName)}-chunk-${toFileToken(chunkId)}.jsonl`
|
|
69
72
|
);
|
|
73
|
+
var getMlChunkFilePrefix = (strategyName, runId) => `ml-dataset-${toFileToken(strategyName)}-chunk-${runId ? `${toFileToken(runId)}-` : ""}`;
|
|
74
|
+
var getRunIdFromMlChunkFileName = (strategyName, fileName) => {
|
|
75
|
+
const prefix = getMlChunkFilePrefix(strategyName);
|
|
76
|
+
if (!fileName.startsWith(prefix) || !fileName.endsWith(".jsonl")) {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
const chunkToken = fileName.slice(prefix.length, -".jsonl".length);
|
|
80
|
+
return chunkToken.match(BACKTEST_RUN_CHUNK_ID_RE)?.[1] ?? "";
|
|
81
|
+
};
|
|
70
82
|
var appendMlDatasetRow = async (params) => {
|
|
71
83
|
const { strategyName, chunkId, row, outDir = DEFAULT_DIR } = params;
|
|
72
84
|
const filePath = getMlChunkFilePath(strategyName, chunkId, outDir);
|
|
@@ -140,8 +152,8 @@ var closeAllMlDatasetWriters = async () => {
|
|
|
140
152
|
}
|
|
141
153
|
};
|
|
142
154
|
var listMlChunkFiles = async (params) => {
|
|
143
|
-
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
144
|
-
const prefix =
|
|
155
|
+
const { strategyName, outDir = DEFAULT_DIR, runId } = params;
|
|
156
|
+
const prefix = getMlChunkFilePrefix(strategyName, runId);
|
|
145
157
|
let entries = [];
|
|
146
158
|
try {
|
|
147
159
|
entries = await import_promises.default.readdir(outDir);
|
|
@@ -150,6 +162,20 @@ var listMlChunkFiles = async (params) => {
|
|
|
150
162
|
}
|
|
151
163
|
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).map((name) => import_path.default.join(outDir, name)).sort();
|
|
152
164
|
};
|
|
165
|
+
var listMlChunkRunIds = async (params) => {
|
|
166
|
+
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
167
|
+
let entries = [];
|
|
168
|
+
try {
|
|
169
|
+
entries = await import_promises.default.readdir(outDir);
|
|
170
|
+
} catch {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
return [
|
|
174
|
+
...new Set(
|
|
175
|
+
entries.map((name) => getRunIdFromMlChunkFileName(strategyName, name)).filter(Boolean)
|
|
176
|
+
)
|
|
177
|
+
].sort();
|
|
178
|
+
};
|
|
153
179
|
var listMlChunkStrategies = async (params) => {
|
|
154
180
|
const outDir = params?.outDir ?? DEFAULT_DIR;
|
|
155
181
|
let entries = [];
|
|
@@ -165,12 +191,37 @@ var listMlChunkStrategies = async (params) => {
|
|
|
165
191
|
].sort();
|
|
166
192
|
};
|
|
167
193
|
var mergeJsonlFiles = async (params) => {
|
|
168
|
-
const { filePaths, outPath } = params;
|
|
194
|
+
const { filePaths, outPath, shouldIncludeRow } = params;
|
|
169
195
|
await import_promises.default.mkdir(import_path.default.dirname(outPath), { recursive: true });
|
|
170
196
|
const stream = (0, import_fs.createWriteStream)(outPath, { encoding: "utf8" });
|
|
171
197
|
const done = Promise.all([(0, import_events.once)(stream, "finish"), (0, import_events.once)(stream, "close")]);
|
|
172
198
|
try {
|
|
173
199
|
for (const filePath of filePaths) {
|
|
200
|
+
if (shouldIncludeRow) {
|
|
201
|
+
const reader2 = import_node_readline.default.createInterface({
|
|
202
|
+
input: (0, import_fs.createReadStream)(filePath, { encoding: "utf8" }),
|
|
203
|
+
crlfDelay: Infinity
|
|
204
|
+
});
|
|
205
|
+
try {
|
|
206
|
+
for await (const line of reader2) {
|
|
207
|
+
const trimmed = line.trim();
|
|
208
|
+
if (!trimmed) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const row = JSON.parse(trimmed);
|
|
212
|
+
if (!shouldIncludeRow(row)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (!stream.write(`${trimmed}
|
|
216
|
+
`)) {
|
|
217
|
+
await (0, import_events.once)(stream, "drain");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
} finally {
|
|
221
|
+
reader2.close();
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
174
225
|
const reader = (0, import_fs.createReadStream)(filePath, { encoding: "utf8" });
|
|
175
226
|
for await (const chunk of reader) {
|
|
176
227
|
if (!stream.write(chunk)) {
|
|
@@ -1740,6 +1791,7 @@ var findLookaheadViolations = (row) => {
|
|
|
1740
1791
|
isDerivedDatasetFileName,
|
|
1741
1792
|
isTimestampFeatureKey,
|
|
1742
1793
|
listMlChunkFiles,
|
|
1794
|
+
listMlChunkRunIds,
|
|
1743
1795
|
listMlChunkStrategies,
|
|
1744
1796
|
mergeJsonlFiles,
|
|
1745
1797
|
toFileToken,
|
package/dist/ml.mjs
CHANGED
|
@@ -5,10 +5,11 @@ import {
|
|
|
5
5
|
flushMlDatasetWriter,
|
|
6
6
|
getMlChunkFilePath,
|
|
7
7
|
listMlChunkFiles,
|
|
8
|
+
listMlChunkRunIds,
|
|
8
9
|
listMlChunkStrategies,
|
|
9
10
|
mergeJsonlFiles,
|
|
10
11
|
toFileToken
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RQP5VSTH.mjs";
|
|
12
13
|
import {
|
|
13
14
|
logger
|
|
14
15
|
} from "./chunk-LNFUOXDW.mjs";
|
|
@@ -1527,6 +1528,7 @@ export {
|
|
|
1527
1528
|
isDerivedDatasetFileName,
|
|
1528
1529
|
isTimestampFeatureKey,
|
|
1529
1530
|
listMlChunkFiles,
|
|
1531
|
+
listMlChunkRunIds,
|
|
1530
1532
|
listMlChunkStrategies,
|
|
1531
1533
|
mergeJsonlFiles,
|
|
1532
1534
|
toFileToken,
|
|
@@ -12,6 +12,11 @@ declare const closeAllMlDatasetWriters: () => Promise<void>;
|
|
|
12
12
|
declare const listMlChunkFiles: (params: {
|
|
13
13
|
strategyName: string;
|
|
14
14
|
outDir?: string;
|
|
15
|
+
runId?: string;
|
|
16
|
+
}) => Promise<string[]>;
|
|
17
|
+
declare const listMlChunkRunIds: (params: {
|
|
18
|
+
strategyName: string;
|
|
19
|
+
outDir?: string;
|
|
15
20
|
}) => Promise<string[]>;
|
|
16
21
|
declare const listMlChunkStrategies: (params?: {
|
|
17
22
|
outDir?: string;
|
|
@@ -19,6 +24,7 @@ declare const listMlChunkStrategies: (params?: {
|
|
|
19
24
|
declare const mergeJsonlFiles: (params: {
|
|
20
25
|
filePaths: string[];
|
|
21
26
|
outPath: string;
|
|
27
|
+
shouldIncludeRow?: (row: Record<string, unknown>) => boolean;
|
|
22
28
|
}) => Promise<void>;
|
|
23
29
|
|
|
24
|
-
export { appendMlDatasetRow as a, closeMlDatasetWriter as b, closeAllMlDatasetWriters as c,
|
|
30
|
+
export { appendMlDatasetRow as a, closeMlDatasetWriter as b, closeAllMlDatasetWriters as c, listMlChunkRunIds as d, listMlChunkStrategies as e, flushMlDatasetWriter as f, getMlChunkFilePath as g, listMlChunkFiles as l, mergeJsonlFiles as m, toFileToken as t };
|
|
@@ -12,6 +12,11 @@ declare const closeAllMlDatasetWriters: () => Promise<void>;
|
|
|
12
12
|
declare const listMlChunkFiles: (params: {
|
|
13
13
|
strategyName: string;
|
|
14
14
|
outDir?: string;
|
|
15
|
+
runId?: string;
|
|
16
|
+
}) => Promise<string[]>;
|
|
17
|
+
declare const listMlChunkRunIds: (params: {
|
|
18
|
+
strategyName: string;
|
|
19
|
+
outDir?: string;
|
|
15
20
|
}) => Promise<string[]>;
|
|
16
21
|
declare const listMlChunkStrategies: (params?: {
|
|
17
22
|
outDir?: string;
|
|
@@ -19,6 +24,7 @@ declare const listMlChunkStrategies: (params?: {
|
|
|
19
24
|
declare const mergeJsonlFiles: (params: {
|
|
20
25
|
filePaths: string[];
|
|
21
26
|
outPath: string;
|
|
27
|
+
shouldIncludeRow?: (row: Record<string, unknown>) => boolean;
|
|
22
28
|
}) => Promise<void>;
|
|
23
29
|
|
|
24
|
-
export { appendMlDatasetRow as a, closeMlDatasetWriter as b, closeAllMlDatasetWriters as c,
|
|
30
|
+
export { appendMlDatasetRow as a, closeMlDatasetWriter as b, closeAllMlDatasetWriters as c, listMlChunkRunIds as d, listMlChunkStrategies as e, flushMlDatasetWriter as f, getMlChunkFilePath as g, listMlChunkFiles as l, mergeJsonlFiles as m, toFileToken as t };
|
package/dist/redis.d.mts
CHANGED
|
@@ -3,9 +3,11 @@ import Redis from 'ioredis';
|
|
|
3
3
|
declare global {
|
|
4
4
|
var __redis__: Redis | undefined;
|
|
5
5
|
}
|
|
6
|
+
declare const closeRedisConnection: () => Promise<void>;
|
|
6
7
|
interface Options {
|
|
7
8
|
expire?: number;
|
|
8
9
|
}
|
|
10
|
+
declare const publishData: (channel: string, value: unknown) => Promise<number>;
|
|
9
11
|
interface DelKeyOptions {
|
|
10
12
|
raiseOnMisconf?: boolean;
|
|
11
13
|
}
|
|
@@ -17,18 +19,31 @@ declare class RedisWriteBlockedError extends Error {
|
|
|
17
19
|
}
|
|
18
20
|
declare const delKeyWithOptions: (key: string, options?: DelKeyOptions) => Promise<boolean>;
|
|
19
21
|
declare const setData: <T>(key: string, data: T, options?: Options) => Promise<void>;
|
|
22
|
+
declare const setHashJsonField: <T>(key: string, field: string, data: T, options?: Options) => Promise<void>;
|
|
23
|
+
declare const getHashJsonField: <T>(key: string, field: string, fallback?: T | null) => Promise<T | null>;
|
|
24
|
+
declare const getHashJsonValues: <T>(key: string) => Promise<T[]>;
|
|
25
|
+
declare const incrHashFields: (key: string, increments: Record<string, number>, options?: Options) => Promise<void>;
|
|
26
|
+
declare const getHashData: (key: string) => Promise<Record<string, string>>;
|
|
20
27
|
declare const createScreenshotSessionToken: (userName: string) => Promise<string | null>;
|
|
21
28
|
declare const consumeScreenshotSessionToken: (token: string) => Promise<string | null>;
|
|
22
29
|
declare const redisKeys: {
|
|
23
30
|
users: () => string;
|
|
24
31
|
user: (userName: string) => string;
|
|
32
|
+
tradingAccounts: (userName: string) => string;
|
|
33
|
+
tradingAccount: (userName: string, accountId: string) => string;
|
|
34
|
+
runtimeDeployments: (userName: string) => string;
|
|
35
|
+
runtimeDeployment: (userName: string, deploymentId: string) => string;
|
|
36
|
+
runtimeDeploymentHeartbeat: (userName: string, deploymentId: string) => string;
|
|
25
37
|
bots: (userName: string) => string;
|
|
26
38
|
botsPrefix: () => string;
|
|
27
39
|
bot: (userName: string, botId: string) => string;
|
|
28
40
|
backtestConfig: (userName: string, config: string) => string;
|
|
29
41
|
strategies: (userName: string) => string;
|
|
30
|
-
strategyConfig: (userName: string, strategyName: string) => string;
|
|
42
|
+
strategyConfig: (userName: string, strategyName: string, configId?: string) => string;
|
|
31
43
|
strategyResults: (userName: string, strategyName: string) => string;
|
|
44
|
+
strategyCharts: (userName: string, mode: string) => string;
|
|
45
|
+
strategyChartCards: (userName: string, mode: string) => string;
|
|
46
|
+
strategyChartCard: (userName: string, mode: string, cardId: string) => string;
|
|
32
47
|
tests: (userName: string, strategyName?: string) => string;
|
|
33
48
|
testOrders: (userName: string, strategyName: string, testName: string) => string;
|
|
34
49
|
testConfig: (userName: string, strategyName: string, testName: string) => string;
|
|
@@ -37,21 +52,34 @@ declare const redisKeys: {
|
|
|
37
52
|
cacheChunk: (userName: string, chunkId: string) => string;
|
|
38
53
|
cacheOrders: (userName: string, orderLogId: string) => string;
|
|
39
54
|
cachePositions: (userName: string, orderLogId: string) => string;
|
|
55
|
+
tickerUniverse: (userName: string, connectorName: string, universe?: string, accountId?: string) => string;
|
|
40
56
|
signal: (symbol: string, signalId: string) => string;
|
|
41
57
|
signalsBySymbol: (symbol: string) => string;
|
|
42
58
|
storeSignal: (symbol: string, signalId: string) => string;
|
|
43
59
|
runtimeSignals: (userName: string) => string;
|
|
44
60
|
runtimeSignal: (userName: string, signalId: string) => string;
|
|
61
|
+
runtimeSignalBuckets: (userName: string) => string;
|
|
62
|
+
runtimeSignalBucket: (userName: string, dayKey: string, strategyName: string) => string;
|
|
45
63
|
runtimeSignalEvaluations: (userName: string) => string;
|
|
46
64
|
runtimeSignalEvaluation: (userName: string, evaluationId: string) => string;
|
|
65
|
+
runtimeSignalEvaluationBuckets: (userName: string) => string;
|
|
66
|
+
runtimeSignalEvaluationBucket: (userName: string, dayKey: string, strategyName: string) => string;
|
|
67
|
+
runtimeSignalEvaluationStatsBuckets: (userName: string) => string;
|
|
68
|
+
runtimeSignalEvaluationStatsBucket: (userName: string, dayKey: string, strategyName: string) => string;
|
|
47
69
|
runtimeTrades: (userName: string) => string;
|
|
48
70
|
runtimeTrade: (userName: string, orderId: string) => string;
|
|
71
|
+
runtimeTradeBuckets: (userName: string) => string;
|
|
72
|
+
runtimeTradeBucket: (userName: string, dayKey: string) => string;
|
|
49
73
|
runtimeActiveTrades: (userName: string) => string;
|
|
50
|
-
runtimeActiveTrade: (userName: string, symbol: string) => string;
|
|
74
|
+
runtimeActiveTrade: (userName: string, symbol: string, scopeId?: string) => string;
|
|
51
75
|
aiChatHistory: (userName: string, symbolKey: string) => string;
|
|
52
76
|
analysis: (symbol: string, signalId: string) => string;
|
|
53
77
|
screenshotSessionToken: (token: string) => string;
|
|
54
78
|
backtestResults: (userName: string, config: string, timestamp: string) => string;
|
|
79
|
+
backtestRuns: (userName: string) => string;
|
|
80
|
+
backtestRun: (userName: string, runId: string) => string;
|
|
81
|
+
backtestRunResults: (userName: string, runId: string) => string;
|
|
82
|
+
backtestLatestRun: (userName: string, config: string) => string;
|
|
55
83
|
researchRuns: (userName: string) => string;
|
|
56
84
|
researchRun: (userName: string, runId: string) => string;
|
|
57
85
|
researchLatestRun: (userName: string, strategyName: string) => string;
|
|
@@ -63,4 +91,4 @@ declare const redisKeys: {
|
|
|
63
91
|
mlResult: (strategyName: string, signalId: string) => string;
|
|
64
92
|
};
|
|
65
93
|
|
|
66
|
-
export { RedisWriteBlockedError, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getKeys, redisKeys, setData };
|
|
94
|
+
export { RedisWriteBlockedError, closeRedisConnection, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getHashData, getHashJsonField, getHashJsonValues, getKeys, incrHashFields, publishData, redisKeys, setData, setHashJsonField };
|