@tradejs/node 1.0.0

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/cli.mjs ADDED
@@ -0,0 +1,548 @@
1
+ import {
2
+ AI_CONCURRENCY_LIMIT,
3
+ KLINE_CONCURRENCY_LIMIT,
4
+ SCREENSHOT_CONCURRENCY_LIMIT,
5
+ TG_CONCURRENCY_LIMIT
6
+ } from "./chunk-4ZPGZWO7.mjs";
7
+ import {
8
+ require_lodash
9
+ } from "./chunk-GKDBAF3A.mjs";
10
+ import {
11
+ askAI
12
+ } from "./chunk-ZIMX3JX2.mjs";
13
+ import "./chunk-MHCXPD2B.mjs";
14
+ import "./chunk-DE7ADBIR.mjs";
15
+ import {
16
+ __toESM
17
+ } from "./chunk-6DZX6EAA.mjs";
18
+
19
+ // src/cli.ts
20
+ var import_lodash = __toESM(require_lodash());
21
+ import fs2 from "fs/promises";
22
+ import ProgressBar from "progress";
23
+ import chalk from "chalk";
24
+ import { runWithConcurrency } from "@tradejs/core/async";
25
+ import { getFormatted } from "@tradejs/core/backtest";
26
+ import { PRELOAD_DAYS } from "@tradejs/core/constants";
27
+ import { getTopTickers } from "@tradejs/core/tickers";
28
+ import { getTimestamp } from "@tradejs/core/time";
29
+ import { getFiles } from "@tradejs/infra/files";
30
+ import {
31
+ RedisWriteBlockedError,
32
+ delKeyWithOptions,
33
+ getKeys,
34
+ getData as getData2,
35
+ redisKeys as redisKeys2
36
+ } from "@tradejs/infra/redis";
37
+ import { logger as logger2 } from "@tradejs/infra/logger";
38
+
39
+ // src/screenshot.ts
40
+ import fs from "fs/promises";
41
+ import path from "path";
42
+ import puppeteer from "puppeteer";
43
+ import { delay } from "@tradejs/core/async";
44
+ import { getData, redisKeys } from "@tradejs/infra/redis";
45
+ var { APP_URL } = process.env;
46
+ var getProjectRoot = () => {
47
+ const fromEnv = String(process.env.PROJECT_CWD || "").trim();
48
+ return fromEnv ? path.resolve(fromEnv) : process.cwd();
49
+ };
50
+ var getScreenshotsDir = () => path.join(getProjectRoot(), "data", "screenshots");
51
+ var getImageUrl = ({ symbol, signalId, interval }) => `${APP_URL}/api/files/screenshot/${symbol}_${signalId}_${interval}`;
52
+ var getScreenshotPath = ({ symbol, signalId, interval }) => {
53
+ return path.join(
54
+ getScreenshotsDir(),
55
+ `${symbol}_${signalId}_${interval}.png`
56
+ );
57
+ };
58
+ var screenDashboard = async (signal) => {
59
+ const { symbol, signalId, interval } = signal;
60
+ const rootUser = await getData(redisKeys.user("root"), null);
61
+ const token2 = rootUser && typeof rootUser === "object" ? rootUser.token : null;
62
+ const tokenParam = typeof token2 === "string" && token2.length > 0 ? `&token=${encodeURIComponent(token2)}` : "";
63
+ const browser = await puppeteer.launch({
64
+ headless: true,
65
+ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
66
+ args: [
67
+ "--no-sandbox",
68
+ "--disable-setuid-sandbox",
69
+ "--disable-dev-shm-usage",
70
+ "--disable-gpu",
71
+ "--font-render-hinting=medium"
72
+ ]
73
+ });
74
+ try {
75
+ const page = await browser.newPage();
76
+ try {
77
+ await page.setViewport({
78
+ width: 1400,
79
+ height: 960,
80
+ deviceScaleFactor: 2
81
+ });
82
+ await page.goto(
83
+ `${APP_URL}/routes/dashboard/bybit/${symbol}/${interval}/?signalId=${signalId}&autoZoom=true${tokenParam}`
84
+ );
85
+ await delay(1e4);
86
+ await fs.mkdir(getScreenshotsDir(), { recursive: true });
87
+ await page.screenshot({
88
+ path: getScreenshotPath(signal)
89
+ });
90
+ } finally {
91
+ await page.close();
92
+ }
93
+ } finally {
94
+ await browser.close();
95
+ }
96
+ };
97
+
98
+ // src/signals.ts
99
+ import { formatNumber } from "@tradejs/core/math";
100
+ import { logger } from "@tradejs/infra/logger";
101
+ var escapeHtml = (s) => {
102
+ if (!s) return "";
103
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
104
+ };
105
+ var { APP_URL: APP_URL2, TG_BOT_TOKEN: token, TG_CHAT_ID: chatId } = process.env;
106
+ var normalizeQuality = (value) => typeof value === "number" ? Math.max(1, Math.min(5, Math.round(value))) : null;
107
+ var getLastNumber = (value) => {
108
+ if (Array.isArray(value)) {
109
+ const last = value[value.length - 1];
110
+ return typeof last === "number" ? last : void 0;
111
+ }
112
+ return typeof value === "number" ? value : void 0;
113
+ };
114
+ var getAiQualityLine = (analysis) => {
115
+ const quality = normalizeQuality(analysis?.quality);
116
+ if (!quality) return null;
117
+ const approvedCurrentDirection = analysis?.direction != null && analysis.direction !== null;
118
+ if (quality >= 4 && approvedCurrentDirection) {
119
+ return `\u{1F7E2} AI Quality: ${quality}/5`;
120
+ }
121
+ if (quality === 3 && approvedCurrentDirection) {
122
+ return `\u{1F7E1} AI Quality: ${quality}/5`;
123
+ }
124
+ return `\u{1F534} AI Quality: ${quality}/5`;
125
+ };
126
+ var formatMessage = (signal, analysis) => {
127
+ const {
128
+ symbol,
129
+ direction,
130
+ strategy,
131
+ orderStatus,
132
+ orderSkipReason,
133
+ isConfigFromBacktest,
134
+ ml,
135
+ prices: { currentPrice, takeProfitPrice, stopLossPrice, riskRatio },
136
+ indicators,
137
+ additionalIndicators
138
+ } = signal;
139
+ try {
140
+ const lines = [];
141
+ const distance = additionalIndicators?.distance;
142
+ const touches = additionalIndicators?.touches;
143
+ const correlation = getLastNumber(indicators.correlation);
144
+ const atrPct = getLastNumber(indicators.atrPct);
145
+ const spread = getLastNumber(indicators.spread);
146
+ const formatPrices = () => {
147
+ const tpPercent = Math.abs(
148
+ (takeProfitPrice - currentPrice) / currentPrice * 100
149
+ ).toFixed(2) + "%";
150
+ const slPercent = Math.abs((stopLossPrice - currentPrice) / currentPrice * 100).toFixed(
151
+ 2
152
+ ) + "%";
153
+ const prices = [
154
+ `Price: <b>${formatNumber(currentPrice)}</b>`,
155
+ `TP: <b>${formatNumber(takeProfitPrice)}</b> (${tpPercent})`,
156
+ `SL: <b>${formatNumber(stopLossPrice)}</b> (${slPercent})`,
157
+ `R:R = <b>${riskRatio.toFixed(2)}</b>`
158
+ ].filter(Boolean).join("\n");
159
+ return prices;
160
+ };
161
+ const checkAnalys = () => {
162
+ const emojiDir = direction === "LONG" ? "\u{1F7E9} LONG" : direction === "SHORT" ? "\u{1F7E5} SHORT" : "\u2B1C\uFE0F NO TRADE";
163
+ lines.push(`<b>${emojiDir} ${symbol}</b>`);
164
+ lines.push(`Strategy: ${strategy}`);
165
+ lines.push("");
166
+ if (orderStatus) {
167
+ let orderStatusText = "\u26AA\uFE0F Order skipped";
168
+ if (orderStatus === "completed") {
169
+ orderStatusText = "\u{1F7E2} Order completed";
170
+ } else if (orderStatus === "failed") {
171
+ orderStatusText = "\u{1F534} Order failed";
172
+ } else if (orderStatus === "canceled") {
173
+ orderStatusText = "\u26AA\uFE0F Order skipped";
174
+ }
175
+ lines.push(orderStatusText);
176
+ if ((orderStatus === "skipped" || orderStatus === "canceled") && orderSkipReason) {
177
+ lines.push(`Skip reason: <b>${escapeHtml(orderSkipReason)}</b>`);
178
+ }
179
+ }
180
+ if (isConfigFromBacktest) {
181
+ lines.push("\u{1F7E2} Using config from backtest");
182
+ } else {
183
+ lines.push("\u{1F7E1} Using base config");
184
+ }
185
+ if (ml) {
186
+ lines.push(
187
+ `${ml.passed ? "\u{1F7E2} ML: PASS" : "\u{1F534} ML: FAIL"} (${ml.probability.toFixed(3)} / ${ml.threshold.toFixed(2)})`
188
+ );
189
+ }
190
+ const aiQualityLine = getAiQualityLine(analysis);
191
+ if (aiQualityLine) {
192
+ lines.push(aiQualityLine);
193
+ }
194
+ lines.push("");
195
+ if (touches) {
196
+ lines.push(`Points: ${touches}`);
197
+ }
198
+ if (atrPct != null && Number.isFinite(atrPct)) {
199
+ lines.push(`ATR: ${atrPct.toFixed(2)}`);
200
+ }
201
+ if (distance) {
202
+ lines.push(`Distance: ${distance}`);
203
+ }
204
+ if (correlation) {
205
+ lines.push(`BTC correlation: ${correlation}`);
206
+ }
207
+ if (spread != null && Number.isFinite(spread)) {
208
+ lines.push(`BTC spread (CB-BN)/BN: ${spread.toFixed(6)}`);
209
+ }
210
+ const prices = formatPrices();
211
+ if (prices) {
212
+ lines.push("");
213
+ lines.push(prices);
214
+ }
215
+ };
216
+ checkAnalys();
217
+ return lines.join("\n").trim();
218
+ } catch (err) {
219
+ return `<b>\u26A0\uFE0F \u041E\u0448\u0438\u0431\u043A\u0430 \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0434\u043B\u044F ${symbol}</b>
220
+ \u0414\u0435\u0442\u0430\u043B\u0438: ${err.message || String(err)}`;
221
+ }
222
+ };
223
+ var sendSignal = async (signal, imgInterval, analysis) => {
224
+ const { symbol, signalId, interval } = signal;
225
+ const message = formatMessage(signal, analysis);
226
+ const markup = {
227
+ inline_keyboard: [
228
+ [
229
+ {
230
+ text: "Dashboard",
231
+ url: `${APP_URL2}/routes/dashboard/bybit/${symbol}/${interval}/?signalId=${signalId}`
232
+ }
233
+ ]
234
+ ]
235
+ };
236
+ if (!APP_URL2?.startsWith("https")) {
237
+ await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
238
+ method: "POST",
239
+ headers: { "Content-Type": "application/json" },
240
+ body: JSON.stringify({
241
+ chat_id: chatId,
242
+ text: message,
243
+ parse_mode: "HTML"
244
+ })
245
+ });
246
+ return;
247
+ }
248
+ const imageUrl = getImageUrl({ ...signal, interval: imgInterval });
249
+ const res = await fetch(`https://api.telegram.org/bot${token}/sendPhoto`, {
250
+ method: "POST",
251
+ headers: { "Content-Type": "application/json" },
252
+ body: JSON.stringify({
253
+ chat_id: chatId,
254
+ photo: imageUrl,
255
+ caption: message,
256
+ reply_markup: markup,
257
+ parse_mode: "HTML"
258
+ })
259
+ });
260
+ const data = await res.json();
261
+ if (!data?.ok) {
262
+ await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
263
+ method: "POST",
264
+ headers: { "Content-Type": "application/json" },
265
+ body: JSON.stringify({
266
+ chat_id: chatId,
267
+ text: JSON.stringify(data),
268
+ parse_mode: "HTML"
269
+ })
270
+ });
271
+ }
272
+ logger.info("tg sendPhoto: %s", data?.ok ? "sent" : JSON.stringify(data));
273
+ };
274
+ var formatAnalysisMessage = (signal, analysis) => {
275
+ const lines = [];
276
+ const blocks = [];
277
+ const quality = normalizeQuality(analysis.quality);
278
+ lines.push(`<b>AI analysis ${signal.symbol}</b>`);
279
+ lines.push(`Signal direction: <b>${signal.direction}</b>`);
280
+ lines.push(`AI direction: <b>${analysis.direction ?? "NO TRADE"}</b>`);
281
+ if (quality) {
282
+ lines.push(`Quality: <b>${quality}/5</b>`);
283
+ }
284
+ if (typeof analysis.needRetest === "boolean") {
285
+ lines.push(`Need retest: <b>${analysis.needRetest ? "YES" : "NO"}</b>`);
286
+ }
287
+ if (typeof analysis.retestPrice === "number") {
288
+ lines.push(`Retest price: <b>${formatNumber(analysis.retestPrice)}</b>`);
289
+ }
290
+ if (typeof analysis.takeProfitPrice === "number") {
291
+ lines.push(`AI TP: <b>${formatNumber(analysis.takeProfitPrice)}</b>`);
292
+ }
293
+ if (typeof analysis.stopLossPrice === "number") {
294
+ lines.push(`AI SL: <b>${formatNumber(analysis.stopLossPrice)}</b>`);
295
+ }
296
+ const pushBlock = (title, value) => {
297
+ if (!value) return;
298
+ const clean = value.trim();
299
+ if (!clean) return;
300
+ blocks.push(`<b>${title}:</b>
301
+ ${escapeHtml(clean)}`);
302
+ };
303
+ pushBlock("Setup", analysis.setup);
304
+ pushBlock("Confirmations", analysis.confirmations);
305
+ pushBlock("BTC", analysis.btcContext);
306
+ pushBlock("Retest", analysis.retestPlan);
307
+ pushBlock("Risk/Levels", analysis.riskLevels);
308
+ pushBlock("Why Quality", analysis.qualityReason);
309
+ pushBlock("Trigger/Invalidation", analysis.triggerInvalidation);
310
+ if (blocks.length > 0) {
311
+ lines.push("");
312
+ lines.push(blocks.join("\n\n"));
313
+ }
314
+ return lines.join("\n");
315
+ };
316
+ var sendSignalAnalysis = async (signal, analysis) => {
317
+ const message = formatAnalysisMessage(signal, analysis);
318
+ const res = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
319
+ method: "POST",
320
+ headers: { "Content-Type": "application/json" },
321
+ body: JSON.stringify({
322
+ chat_id: chatId,
323
+ text: message,
324
+ parse_mode: "HTML"
325
+ })
326
+ });
327
+ const data = await res.json();
328
+ logger.info(
329
+ "tg sendMessage (analysis): %s",
330
+ data?.ok ? "sent" : JSON.stringify(data)
331
+ );
332
+ };
333
+
334
+ // src/cli.ts
335
+ var cleanFiles = async (dir) => {
336
+ let completed = 0;
337
+ const files = await getFiles(dir);
338
+ const bar = new ProgressBar(":current/:total [:bar][:percent] :eta(s)", {
339
+ total: files.length,
340
+ width: 30
341
+ });
342
+ logger2.info(chalk.yellow("clean:", dir));
343
+ for await (const file of files) {
344
+ completed++;
345
+ const fullPath = `${dir}/${file}`;
346
+ const stat = await fs2.lstat(fullPath);
347
+ if (stat.isDirectory()) {
348
+ await fs2.rm(fullPath, { recursive: true, force: true });
349
+ } else {
350
+ await fs2.unlink(fullPath);
351
+ }
352
+ if (completed % 100 === 0 || completed === files.length) {
353
+ bar.tick(completed === files.length ? completed % 100 : 100);
354
+ }
355
+ }
356
+ logger2.info("");
357
+ };
358
+ var cleanRedis = async (area) => {
359
+ let completed = 0;
360
+ const keys = await getKeys(area);
361
+ const bar = new ProgressBar(":current/:total [:bar][:percent] :eta(s)", {
362
+ total: keys.length,
363
+ width: 30
364
+ });
365
+ logger2.info(chalk.yellow("clean:", area));
366
+ try {
367
+ for await (const key of keys) {
368
+ completed++;
369
+ await delKeyWithOptions(key, { raiseOnMisconf: true });
370
+ if (completed % 100 === 0 || completed === keys.length) {
371
+ bar.tick(completed === keys.length ? completed % 100 : 100);
372
+ }
373
+ }
374
+ } catch (e) {
375
+ if (e instanceof RedisWriteBlockedError || String(e).includes("MISCONF")) {
376
+ logger2.error(
377
+ "Redis write is blocked by MISCONF (RDB save failure). Cleanup stopped early."
378
+ );
379
+ logger2.error(
380
+ "Check Redis logs and fix persistence/memory pressure before retry."
381
+ );
382
+ logger2.info("");
383
+ return;
384
+ }
385
+ throw e;
386
+ }
387
+ logger2.info("");
388
+ };
389
+ var update = async (connector, interval, tickers) => {
390
+ const PRELOAD_START = getTimestamp(PRELOAD_DAYS);
391
+ const PRELOAD_END = getTimestamp();
392
+ const bar = new ProgressBar(
393
+ ":current/:total [:bar][:percent] :eta(s) :symbol",
394
+ {
395
+ total: tickers.length,
396
+ width: 30
397
+ }
398
+ );
399
+ logger2.info(chalk.yellow("update:", tickers.length));
400
+ const queue = tickers.slice();
401
+ if (!queue.includes("BTCUSDT")) {
402
+ queue.unshift("BTCUSDT");
403
+ }
404
+ await runWithConcurrency(queue, KLINE_CONCURRENCY_LIMIT, async (symbol) => {
405
+ try {
406
+ await connector.kline({
407
+ symbol,
408
+ start: PRELOAD_START,
409
+ end: PRELOAD_END,
410
+ interval,
411
+ silent: true
412
+ });
413
+ } catch {
414
+ logger2.error("Failed loading: %s", symbol);
415
+ } finally {
416
+ bar.tick(1, { symbol: chalk.gray(symbol) });
417
+ }
418
+ });
419
+ logger2.info("");
420
+ };
421
+ var parseSymbolsFromCLI = (symbol = "") => symbol.split(",").map((s) => {
422
+ const ticker = s.toUpperCase();
423
+ return ticker.endsWith("USDT") ? ticker : `${ticker}USDT`;
424
+ });
425
+ var getCLILevelColor = (level) => {
426
+ switch (level) {
427
+ case "success":
428
+ return chalk.green;
429
+ case "warning":
430
+ return chalk.yellow;
431
+ case "error":
432
+ return chalk.red;
433
+ }
434
+ };
435
+ var drawStatInCLI = (stat, keys) => {
436
+ return keys.map((key) => {
437
+ const { formatted, level } = getFormatted(stat, key);
438
+ const color = getCLILevelColor(level);
439
+ return color(formatted);
440
+ });
441
+ };
442
+ var scanner = async (connector, limit) => {
443
+ const data = await connector.getTickers();
444
+ const tickers = getTopTickers(data, limit);
445
+ return tickers.map(({ value }) => value);
446
+ };
447
+ var getTickers = async (connector, include = "", exclude = "", limit, chunk) => {
448
+ let tickers;
449
+ const excludeTickers = parseSymbolsFromCLI(exclude);
450
+ if (include) {
451
+ tickers = parseSymbolsFromCLI(include);
452
+ } else {
453
+ tickers = await scanner(connector, limit);
454
+ }
455
+ if (chunk) {
456
+ const [currentChunk, chunksCount] = chunk.split("/").map((c) => parseInt(c));
457
+ logger2.info("chunk: %d / %d", currentChunk, chunksCount);
458
+ const chunkSize = Math.ceil(tickers.length / chunksCount);
459
+ const chunks = import_lodash.default.chunk(tickers, chunkSize);
460
+ tickers = chunks[currentChunk - 1];
461
+ }
462
+ return tickers.filter((t) => !excludeTickers.includes(t));
463
+ };
464
+ var makeScreenshots = async (signals, interval) => {
465
+ const bar = new ProgressBar(
466
+ ":current/:total [:bar][:percent] :eta(s) :symbol",
467
+ {
468
+ total: signals.length,
469
+ width: 30
470
+ }
471
+ );
472
+ logger2.info(chalk.yellow("screenshots:", `${interval}m`, signals.length));
473
+ await runWithConcurrency(
474
+ signals,
475
+ SCREENSHOT_CONCURRENCY_LIMIT,
476
+ async (signal) => {
477
+ try {
478
+ await screenDashboard({ ...signal, interval });
479
+ } catch (error) {
480
+ logger2.error(
481
+ "Failed screenshot: %s (%s)",
482
+ signal.symbol,
483
+ error?.message || String(error)
484
+ );
485
+ } finally {
486
+ bar.tick(1, { symbol: chalk.gray(signal.symbol) });
487
+ }
488
+ }
489
+ );
490
+ logger2.info("");
491
+ };
492
+ var sendToAI = async (signals) => {
493
+ const bar = new ProgressBar(
494
+ ":current/:total [:bar][:percent] :eta(s) :symbol",
495
+ {
496
+ total: signals.length,
497
+ width: 30
498
+ }
499
+ );
500
+ logger2.info(chalk.yellow("AI:", signals.length));
501
+ await runWithConcurrency(signals, AI_CONCURRENCY_LIMIT, async (signal) => {
502
+ try {
503
+ await askAI(signal);
504
+ } catch {
505
+ logger2.error("Failed ask: %s", signal.symbol);
506
+ } finally {
507
+ bar.tick(1, { symbol: chalk.gray(signal.symbol) });
508
+ }
509
+ });
510
+ logger2.info("");
511
+ };
512
+ var sendToTG = async (signals, imgInterval) => {
513
+ const bar = new ProgressBar(
514
+ ":current/:total [:bar][:percent] :eta(s) :symbol",
515
+ {
516
+ total: signals.length,
517
+ width: 30
518
+ }
519
+ );
520
+ logger2.info(chalk.yellow("messages:", signals.length));
521
+ await runWithConcurrency(signals, TG_CONCURRENCY_LIMIT, async (signal) => {
522
+ try {
523
+ const analysis = await getData2(
524
+ redisKeys2.analysis(signal.symbol, signal.signalId),
525
+ null
526
+ );
527
+ await sendSignal(signal, imgInterval, analysis);
528
+ if (analysis && typeof analysis === "object" && Object.keys(analysis).length > 0) {
529
+ await sendSignalAnalysis(signal, analysis);
530
+ }
531
+ } catch {
532
+ logger2.error("Failed sent: %s", signal.symbol);
533
+ } finally {
534
+ bar.tick(1, { symbol: chalk.gray(signal.symbol) });
535
+ }
536
+ });
537
+ logger2.info("");
538
+ };
539
+ export {
540
+ cleanFiles,
541
+ cleanRedis,
542
+ drawStatInCLI,
543
+ getTickers,
544
+ makeScreenshots,
545
+ sendToAI,
546
+ sendToTG,
547
+ update
548
+ };
@@ -0,0 +1,20 @@
1
+ import { ConnectorCreator, ConnectorRegistryEntry } from '@tradejs/types';
2
+
3
+ declare const BUILTIN_CONNECTOR_NAMES: {
4
+ readonly ByBit: "ByBit";
5
+ readonly Binance: "Binance";
6
+ readonly Coinbase: "Coinbase";
7
+ readonly Test: "Test";
8
+ };
9
+ declare const ensureConnectorPluginsLoaded: () => Promise<void>;
10
+ declare const getConnectorCreatorByName: (connectorName: unknown) => Promise<ConnectorCreator | undefined>;
11
+ declare const getConnectorNameByProvider: (provider: unknown) => Promise<string | undefined>;
12
+ declare const getConnectorCreatorByProvider: (provider: unknown) => Promise<ConnectorCreator | undefined>;
13
+ declare const resolveConnectorName: (providerOrName: unknown) => Promise<string | undefined>;
14
+ declare const getAvailableConnectorNames: () => Promise<string[]>;
15
+ declare const getAvailableConnectorProviders: () => Promise<string[]>;
16
+ declare const registerConnectorEntries: (entries: readonly ConnectorRegistryEntry[]) => void;
17
+ declare const resetConnectorRegistryCache: () => void;
18
+ declare const DEFAULT_CONNECTOR_NAME: "ByBit";
19
+
20
+ export { BUILTIN_CONNECTOR_NAMES, DEFAULT_CONNECTOR_NAME, ensureConnectorPluginsLoaded, getAvailableConnectorNames, getAvailableConnectorProviders, getConnectorCreatorByName, getConnectorCreatorByProvider, getConnectorNameByProvider, registerConnectorEntries, resetConnectorRegistryCache, resolveConnectorName };
@@ -0,0 +1,20 @@
1
+ import { ConnectorCreator, ConnectorRegistryEntry } from '@tradejs/types';
2
+
3
+ declare const BUILTIN_CONNECTOR_NAMES: {
4
+ readonly ByBit: "ByBit";
5
+ readonly Binance: "Binance";
6
+ readonly Coinbase: "Coinbase";
7
+ readonly Test: "Test";
8
+ };
9
+ declare const ensureConnectorPluginsLoaded: () => Promise<void>;
10
+ declare const getConnectorCreatorByName: (connectorName: unknown) => Promise<ConnectorCreator | undefined>;
11
+ declare const getConnectorNameByProvider: (provider: unknown) => Promise<string | undefined>;
12
+ declare const getConnectorCreatorByProvider: (provider: unknown) => Promise<ConnectorCreator | undefined>;
13
+ declare const resolveConnectorName: (providerOrName: unknown) => Promise<string | undefined>;
14
+ declare const getAvailableConnectorNames: () => Promise<string[]>;
15
+ declare const getAvailableConnectorProviders: () => Promise<string[]>;
16
+ declare const registerConnectorEntries: (entries: readonly ConnectorRegistryEntry[]) => void;
17
+ declare const resetConnectorRegistryCache: () => void;
18
+ declare const DEFAULT_CONNECTOR_NAME: "ByBit";
19
+
20
+ export { BUILTIN_CONNECTOR_NAMES, DEFAULT_CONNECTOR_NAME, ensureConnectorPluginsLoaded, getAvailableConnectorNames, getAvailableConnectorProviders, getConnectorCreatorByName, getConnectorCreatorByProvider, getConnectorNameByProvider, registerConnectorEntries, resetConnectorRegistryCache, resolveConnectorName };