@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.
@@ -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 = `ml-dataset-${toFileToken(strategyName)}-chunk-`;
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-sRGWgR_o.mjs';
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-sRGWgR_o.js';
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 = `ml-dataset-${toFileToken(strategyName)}-chunk-`;
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-KVEZORMS.mjs";
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, listMlChunkStrategies as d, flushMlDatasetWriter as f, getMlChunkFilePath as g, listMlChunkFiles as l, mergeJsonlFiles as m, toFileToken as t };
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, listMlChunkStrategies as d, flushMlDatasetWriter as f, getMlChunkFilePath as g, listMlChunkFiles as l, mergeJsonlFiles as m, toFileToken as t };
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
  }
@@ -18,6 +20,7 @@ declare class RedisWriteBlockedError extends Error {
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>;
20
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>;
21
24
  declare const getHashJsonValues: <T>(key: string) => Promise<T[]>;
22
25
  declare const incrHashFields: (key: string, increments: Record<string, number>, options?: Options) => Promise<void>;
23
26
  declare const getHashData: (key: string) => Promise<Record<string, string>>;
@@ -26,13 +29,21 @@ declare const consumeScreenshotSessionToken: (token: string) => Promise<string |
26
29
  declare const redisKeys: {
27
30
  users: () => string;
28
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;
29
37
  bots: (userName: string) => string;
30
38
  botsPrefix: () => string;
31
39
  bot: (userName: string, botId: string) => string;
32
40
  backtestConfig: (userName: string, config: string) => string;
33
41
  strategies: (userName: string) => string;
34
- strategyConfig: (userName: string, strategyName: string) => string;
42
+ strategyConfig: (userName: string, strategyName: string, configId?: string) => string;
35
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;
36
47
  tests: (userName: string, strategyName?: string) => string;
37
48
  testOrders: (userName: string, strategyName: string, testName: string) => string;
38
49
  testConfig: (userName: string, strategyName: string, testName: string) => string;
@@ -41,6 +52,7 @@ declare const redisKeys: {
41
52
  cacheChunk: (userName: string, chunkId: string) => string;
42
53
  cacheOrders: (userName: string, orderLogId: string) => string;
43
54
  cachePositions: (userName: string, orderLogId: string) => string;
55
+ tickerUniverse: (userName: string, connectorName: string, universe?: string, accountId?: string) => string;
44
56
  signal: (symbol: string, signalId: string) => string;
45
57
  signalsBySymbol: (symbol: string) => string;
46
58
  storeSignal: (symbol: string, signalId: string) => string;
@@ -56,12 +68,18 @@ declare const redisKeys: {
56
68
  runtimeSignalEvaluationStatsBucket: (userName: string, dayKey: string, strategyName: string) => string;
57
69
  runtimeTrades: (userName: string) => string;
58
70
  runtimeTrade: (userName: string, orderId: string) => string;
71
+ runtimeTradeBuckets: (userName: string) => string;
72
+ runtimeTradeBucket: (userName: string, dayKey: string) => string;
59
73
  runtimeActiveTrades: (userName: string) => string;
60
- runtimeActiveTrade: (userName: string, symbol: string) => string;
74
+ runtimeActiveTrade: (userName: string, symbol: string, scopeId?: string) => string;
61
75
  aiChatHistory: (userName: string, symbolKey: string) => string;
62
76
  analysis: (symbol: string, signalId: string) => string;
63
77
  screenshotSessionToken: (token: string) => string;
64
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;
65
83
  researchRuns: (userName: string) => string;
66
84
  researchRun: (userName: string, runId: string) => string;
67
85
  researchLatestRun: (userName: string, strategyName: string) => string;
@@ -73,4 +91,4 @@ declare const redisKeys: {
73
91
  mlResult: (strategyName: string, signalId: string) => string;
74
92
  };
75
93
 
76
- export { RedisWriteBlockedError, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getHashData, getHashJsonValues, getKeys, incrHashFields, redisKeys, setData, setHashJsonField };
94
+ export { RedisWriteBlockedError, closeRedisConnection, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getHashData, getHashJsonField, getHashJsonValues, getKeys, incrHashFields, publishData, redisKeys, setData, setHashJsonField };
package/dist/redis.d.ts 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
  }
@@ -18,6 +20,7 @@ declare class RedisWriteBlockedError extends Error {
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>;
20
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>;
21
24
  declare const getHashJsonValues: <T>(key: string) => Promise<T[]>;
22
25
  declare const incrHashFields: (key: string, increments: Record<string, number>, options?: Options) => Promise<void>;
23
26
  declare const getHashData: (key: string) => Promise<Record<string, string>>;
@@ -26,13 +29,21 @@ declare const consumeScreenshotSessionToken: (token: string) => Promise<string |
26
29
  declare const redisKeys: {
27
30
  users: () => string;
28
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;
29
37
  bots: (userName: string) => string;
30
38
  botsPrefix: () => string;
31
39
  bot: (userName: string, botId: string) => string;
32
40
  backtestConfig: (userName: string, config: string) => string;
33
41
  strategies: (userName: string) => string;
34
- strategyConfig: (userName: string, strategyName: string) => string;
42
+ strategyConfig: (userName: string, strategyName: string, configId?: string) => string;
35
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;
36
47
  tests: (userName: string, strategyName?: string) => string;
37
48
  testOrders: (userName: string, strategyName: string, testName: string) => string;
38
49
  testConfig: (userName: string, strategyName: string, testName: string) => string;
@@ -41,6 +52,7 @@ declare const redisKeys: {
41
52
  cacheChunk: (userName: string, chunkId: string) => string;
42
53
  cacheOrders: (userName: string, orderLogId: string) => string;
43
54
  cachePositions: (userName: string, orderLogId: string) => string;
55
+ tickerUniverse: (userName: string, connectorName: string, universe?: string, accountId?: string) => string;
44
56
  signal: (symbol: string, signalId: string) => string;
45
57
  signalsBySymbol: (symbol: string) => string;
46
58
  storeSignal: (symbol: string, signalId: string) => string;
@@ -56,12 +68,18 @@ declare const redisKeys: {
56
68
  runtimeSignalEvaluationStatsBucket: (userName: string, dayKey: string, strategyName: string) => string;
57
69
  runtimeTrades: (userName: string) => string;
58
70
  runtimeTrade: (userName: string, orderId: string) => string;
71
+ runtimeTradeBuckets: (userName: string) => string;
72
+ runtimeTradeBucket: (userName: string, dayKey: string) => string;
59
73
  runtimeActiveTrades: (userName: string) => string;
60
- runtimeActiveTrade: (userName: string, symbol: string) => string;
74
+ runtimeActiveTrade: (userName: string, symbol: string, scopeId?: string) => string;
61
75
  aiChatHistory: (userName: string, symbolKey: string) => string;
62
76
  analysis: (symbol: string, signalId: string) => string;
63
77
  screenshotSessionToken: (token: string) => string;
64
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;
65
83
  researchRuns: (userName: string) => string;
66
84
  researchRun: (userName: string, runId: string) => string;
67
85
  researchLatestRun: (userName: string, strategyName: string) => string;
@@ -73,4 +91,4 @@ declare const redisKeys: {
73
91
  mlResult: (strategyName: string, signalId: string) => string;
74
92
  };
75
93
 
76
- export { RedisWriteBlockedError, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getHashData, getHashJsonValues, getKeys, incrHashFields, redisKeys, setData, setHashJsonField };
94
+ export { RedisWriteBlockedError, closeRedisConnection, consumeScreenshotSessionToken, createScreenshotSessionToken, delKey, delKeyWithOptions, getData, getHashData, getHashJsonField, getHashJsonValues, getKeys, incrHashFields, publishData, redisKeys, setData, setHashJsonField };
package/dist/redis.js CHANGED
@@ -31,15 +31,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var redis_exports = {};
32
32
  __export(redis_exports, {
33
33
  RedisWriteBlockedError: () => RedisWriteBlockedError,
34
+ closeRedisConnection: () => closeRedisConnection,
34
35
  consumeScreenshotSessionToken: () => consumeScreenshotSessionToken,
35
36
  createScreenshotSessionToken: () => createScreenshotSessionToken,
36
37
  delKey: () => delKey,
37
38
  delKeyWithOptions: () => delKeyWithOptions,
38
39
  getData: () => getData,
39
40
  getHashData: () => getHashData,
41
+ getHashJsonField: () => getHashJsonField,
40
42
  getHashJsonValues: () => getHashJsonValues,
41
43
  getKeys: () => getKeys,
42
44
  incrHashFields: () => incrHashFields,
45
+ publishData: () => publishData,
43
46
  redisKeys: () => redisKeys,
44
47
  setData: () => setData,
45
48
  setHashJsonField: () => setHashJsonField
@@ -58,9 +61,12 @@ var logger = {
58
61
  };
59
62
  var redisConnectionWarningShown = false;
60
63
  var redisUnavailable = false;
61
- var isRedisConnectivityError = (error) => /ECONNREFUSED|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|MaxRetriesPerRequestError|Connection is closed|Stream isn't writeable/i.test(
62
- error.message
63
- );
64
+ var isRedisConnectivityError = (error) => {
65
+ const errorText = [error.name, error.message, String(error)].join(" ");
66
+ return /ECONNREFUSED|ECONNRESET|ECONNABORTED|EPIPE|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|MaxRetriesPerRequestError|Connection is closed|Stream isn't writeable/i.test(
67
+ errorText
68
+ );
69
+ };
64
70
  var toNonNegativeInt = (value, fallback) => {
65
71
  const parsed = Number.parseInt(String(value ?? ""), 10);
66
72
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
@@ -116,6 +122,16 @@ var getRedis = () => {
116
122
  }
117
123
  return global.__redis__;
118
124
  };
125
+ var closeRedisConnection = async () => {
126
+ const redis = global.__redis__;
127
+ if (!redis) {
128
+ return;
129
+ }
130
+ global.__redis__ = void 0;
131
+ redisUnavailable = false;
132
+ redisConnectionWarningShown = false;
133
+ redis.disconnect();
134
+ };
119
135
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
120
136
  var getRedisStatus = (redis) => String(redis.status ?? "ready");
121
137
  var waitForRedisReady = async (redis) => {
@@ -156,6 +172,11 @@ var toResultString = (result) => {
156
172
  if (Buffer.isBuffer(result)) return result.toString("utf8");
157
173
  return String(result);
158
174
  };
175
+ var publishData = async (channel, value) => {
176
+ const redis = await getReadyRedis();
177
+ if (!redis) return 0;
178
+ return redis.publish(channel, toJson(value));
179
+ };
159
180
  var DEFAULT_OPTIONS = {
160
181
  expire: TTL_1D
161
182
  };
@@ -347,6 +368,25 @@ var setHashJsonField = async (key, field, data, options = {}) => {
347
368
  logger.log("error", "failed HSET %s[%s]: %s", key, field, String(e));
348
369
  }
349
370
  };
371
+ var getHashJsonField = async (key, field, fallback = null) => {
372
+ if (redisUnavailable) return fallback;
373
+ const redis = await getReadyRedis();
374
+ if (!redis) return fallback;
375
+ try {
376
+ const value = await redis.call("HGET", key, field);
377
+ if (typeof value !== "string" || !value) {
378
+ return fallback;
379
+ }
380
+ return JSON.parse(value);
381
+ } catch (e) {
382
+ if (e instanceof Error && isRedisConnectivityError(e)) {
383
+ markRedisUnavailable(e);
384
+ return fallback;
385
+ }
386
+ logger.log("error", "failed HGET %s[%s]: %s", key, field, String(e));
387
+ return fallback;
388
+ }
389
+ };
350
390
  var getHashJsonValues = async (key) => {
351
391
  if (redisUnavailable) return [];
352
392
  const redis = await getReadyRedis();
@@ -452,13 +492,21 @@ var consumeScreenshotSessionToken = async (token) => {
452
492
  var redisKeys = {
453
493
  users: () => "users:index:",
454
494
  user: (userName) => `users:index:${userName}`,
495
+ tradingAccounts: (userName) => `users:${userName}:trading-accounts:`,
496
+ tradingAccount: (userName, accountId) => `users:${userName}:trading-accounts:${accountId}`,
497
+ runtimeDeployments: (userName) => `users:${userName}:runtime:deployments:`,
498
+ runtimeDeployment: (userName, deploymentId) => `users:${userName}:runtime:deployments:${deploymentId}`,
499
+ runtimeDeploymentHeartbeat: (userName, deploymentId) => `users:${userName}:runtime:deployments:${deploymentId}:heartbeat`,
455
500
  bots: (userName) => `users:${userName}:bots`,
456
501
  botsPrefix: () => "users:",
457
502
  bot: (userName, botId) => `users:${userName}:bots:${botId}`,
458
503
  backtestConfig: (userName, config) => `users:${userName}:backtests:configs:${config}`,
459
504
  strategies: (userName) => `users:${userName}:strategies`,
460
- strategyConfig: (userName, strategyName) => `users:${userName}:strategies:${strategyName}:config`,
505
+ strategyConfig: (userName, strategyName, configId = "config") => `users:${userName}:strategies:${strategyName}:${configId}`,
461
506
  strategyResults: (userName, strategyName) => `users:${userName}:strategies:${strategyName}:results`,
507
+ strategyCharts: (userName, mode) => `users:${userName}:strategies:charts:${mode}`,
508
+ strategyChartCards: (userName, mode) => `users:${userName}:strategies:charts:${mode}:cards:`,
509
+ strategyChartCard: (userName, mode, cardId) => `users:${userName}:strategies:charts:${mode}:cards:${cardId}`,
462
510
  tests: (userName, strategyName) => strategyName ? `users:${userName}:tests:${strategyName}` : `users:${userName}:tests:`,
463
511
  testOrders: (userName, strategyName, testName) => `users:${userName}:tests:${strategyName}:${testName}:orders`,
464
512
  testConfig: (userName, strategyName, testName) => `users:${userName}:tests:${strategyName}:${testName}:config`,
@@ -467,6 +515,7 @@ var redisKeys = {
467
515
  cacheChunk: (userName, chunkId) => `users:${userName}:cache:tests:chunks:${chunkId}`,
468
516
  cacheOrders: (userName, orderLogId) => `users:${userName}:cache:tests:orders:${orderLogId}`,
469
517
  cachePositions: (userName, orderLogId) => `users:${userName}:cache:tests:positions:${orderLogId}`,
518
+ tickerUniverse: (userName, connectorName, universe, accountId) => universe || accountId ? `users:${userName}:cache:tickers:${connectorName}:${universe ?? "crypto"}:${accountId ?? "default"}` : `users:${userName}:cache:tickers:${connectorName}`,
470
519
  signal: (symbol, signalId) => `signals:${symbol}:${signalId}`,
471
520
  signalsBySymbol: (symbol) => `signals:${symbol}:`,
472
521
  storeSignal: (symbol, signalId) => `store:signals:${symbol}:${signalId}`,
@@ -482,12 +531,18 @@ var redisKeys = {
482
531
  runtimeSignalEvaluationStatsBucket: (userName, dayKey, strategyName) => `users:${userName}:runtime:signal-evaluation-stats:days:${dayKey}:${strategyName}`,
483
532
  runtimeTrades: (userName) => `users:${userName}:runtime:trade-records:`,
484
533
  runtimeTrade: (userName, orderId) => `users:${userName}:runtime:trade-records:${orderId}`,
534
+ runtimeTradeBuckets: (userName) => `users:${userName}:runtime:trade-records:days:`,
535
+ runtimeTradeBucket: (userName, dayKey) => `users:${userName}:runtime:trade-records:days:${dayKey}`,
485
536
  runtimeActiveTrades: (userName) => `users:${userName}:runtime:active-trades:`,
486
- runtimeActiveTrade: (userName, symbol) => `users:${userName}:runtime:active-trades:${symbol}`,
537
+ runtimeActiveTrade: (userName, symbol, scopeId) => scopeId ? `users:${userName}:runtime:active-trades:${scopeId}:${symbol}` : `users:${userName}:runtime:active-trades:${symbol}`,
487
538
  aiChatHistory: (userName, symbolKey) => `users:${userName}:ai:chats:${symbolKey}`,
488
539
  analysis: (symbol, signalId) => `analysis:${symbol}:${signalId}`,
489
540
  screenshotSessionToken: (token) => `auth:screenshot:${token}`,
490
541
  backtestResults: (userName, config, timestamp) => `users:${userName}:backtests:results:${config}:${timestamp}`,
542
+ backtestRuns: (userName) => `users:${userName}:backtests:runs:`,
543
+ backtestRun: (userName, runId) => `users:${userName}:backtests:runs:${runId}`,
544
+ backtestRunResults: (userName, runId) => `users:${userName}:backtests:runs:${runId}:results`,
545
+ backtestLatestRun: (userName, config) => `users:${userName}:backtests:latest:${config}`,
491
546
  researchRuns: (userName) => `users:${userName}:research:runs:`,
492
547
  researchRun: (userName, runId) => `users:${userName}:research:runs:${runId}`,
493
548
  researchLatestRun: (userName, strategyName) => `users:${userName}:research:latest:${strategyName}`,
@@ -501,15 +556,18 @@ var redisKeys = {
501
556
  // Annotate the CommonJS export names for ESM import in node:
502
557
  0 && (module.exports = {
503
558
  RedisWriteBlockedError,
559
+ closeRedisConnection,
504
560
  consumeScreenshotSessionToken,
505
561
  createScreenshotSessionToken,
506
562
  delKey,
507
563
  delKeyWithOptions,
508
564
  getData,
509
565
  getHashData,
566
+ getHashJsonField,
510
567
  getHashJsonValues,
511
568
  getKeys,
512
569
  incrHashFields,
570
+ publishData,
513
571
  redisKeys,
514
572
  setData,
515
573
  setHashJsonField
package/dist/redis.mjs CHANGED
@@ -1,29 +1,35 @@
1
1
  import {
2
2
  RedisWriteBlockedError,
3
+ closeRedisConnection,
3
4
  consumeScreenshotSessionToken,
4
5
  createScreenshotSessionToken,
5
6
  delKey,
6
7
  delKeyWithOptions,
7
8
  getData,
8
9
  getHashData,
10
+ getHashJsonField,
9
11
  getHashJsonValues,
10
12
  getKeys,
11
13
  incrHashFields,
14
+ publishData,
12
15
  redisKeys,
13
16
  setData,
14
17
  setHashJsonField
15
- } from "./chunk-MLVWC2I2.mjs";
18
+ } from "./chunk-DXG2UDNA.mjs";
16
19
  export {
17
20
  RedisWriteBlockedError,
21
+ closeRedisConnection,
18
22
  consumeScreenshotSessionToken,
19
23
  createScreenshotSessionToken,
20
24
  delKey,
21
25
  delKeyWithOptions,
22
26
  getData,
23
27
  getHashData,
28
+ getHashJsonField,
24
29
  getHashJsonValues,
25
30
  getKeys,
26
31
  incrHashFields,
32
+ publishData,
27
33
  redisKeys,
28
34
  setData,
29
35
  setHashJsonField