@tradejs/node 3.0.1 → 3.1.1

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.
Files changed (43) hide show
  1. package/README.md +4 -0
  2. package/dist/ai.d.mts +26 -4
  3. package/dist/ai.d.ts +26 -4
  4. package/dist/ai.js +162 -165
  5. package/dist/ai.mjs +4 -1
  6. package/dist/backtest.js +515 -188
  7. package/dist/backtest.mjs +6 -4
  8. package/dist/chunk-3TWULKHV.mjs +595 -0
  9. package/dist/chunk-FB5NUEOQ.mjs +295 -0
  10. package/dist/chunk-LAJ7NA3Q.mjs +377 -0
  11. package/dist/{chunk-VRXU4E4O.mjs → chunk-SEQJ6V6B.mjs} +165 -446
  12. package/dist/{chunk-OGAWBO3Z.mjs → chunk-W26Y6IRP.mjs} +22 -3
  13. package/dist/chunk-XN7BC7XK.mjs +295 -0
  14. package/dist/cli.js +152 -161
  15. package/dist/cli.mjs +4 -2
  16. package/dist/connectors.d.mts +5 -2
  17. package/dist/connectors.d.ts +5 -2
  18. package/dist/connectors.js +329 -8
  19. package/dist/connectors.mjs +5 -1
  20. package/dist/registry-DHTLjQcr.d.mts +17 -0
  21. package/dist/registry-DHTLjQcr.d.ts +17 -0
  22. package/dist/registry.d.mts +2 -15
  23. package/dist/registry.d.ts +2 -15
  24. package/dist/registry.js +176 -161
  25. package/dist/registry.mjs +5 -2
  26. package/dist/runtimeDashboard.d.mts +12 -0
  27. package/dist/runtimeDashboard.d.ts +12 -0
  28. package/dist/runtimeDashboard.js +8502 -0
  29. package/dist/runtimeDashboard.mjs +1000 -0
  30. package/dist/runtimeStrategies.d.mts +38 -0
  31. package/dist/runtimeStrategies.d.ts +38 -0
  32. package/dist/runtimeStrategies.js +798 -0
  33. package/dist/runtimeStrategies.mjs +264 -0
  34. package/dist/runtimeTrades.d.mts +31 -0
  35. package/dist/runtimeTrades.d.ts +31 -0
  36. package/dist/runtimeTrades.js +321 -0
  37. package/dist/runtimeTrades.mjs +11 -0
  38. package/dist/strategies.d.mts +2 -2
  39. package/dist/strategies.d.ts +2 -2
  40. package/dist/strategies.js +194 -165
  41. package/dist/strategies.mjs +24 -379
  42. package/package.json +27 -6
  43. package/dist/chunk-V3YMKE4I.mjs +0 -271
package/dist/backtest.mjs CHANGED
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  BUILTIN_CONNECTOR_NAMES,
3
3
  getConnectorCreatorByName
4
- } from "./chunk-V3YMKE4I.mjs";
4
+ } from "./chunk-3TWULKHV.mjs";
5
5
  import {
6
6
  buildMlPayload,
7
7
  enrichSignalWithMarketContextStages
8
- } from "./chunk-OGAWBO3Z.mjs";
8
+ } from "./chunk-W26Y6IRP.mjs";
9
+ import {
10
+ buildAiPayload
11
+ } from "./chunk-SEQJ6V6B.mjs";
9
12
  import {
10
- buildAiPayload,
11
13
  getStrategyCreator
12
- } from "./chunk-VRXU4E4O.mjs";
14
+ } from "./chunk-XN7BC7XK.mjs";
13
15
  import {
14
16
  getTradejsProjectCwd
15
17
  } from "./chunk-WS5DYEVZ.mjs";
@@ -0,0 +1,595 @@
1
+ import {
2
+ getTradejsProjectCwd,
3
+ importTradejsModule,
4
+ loadTradejsConfig,
5
+ resolvePluginModuleSpecifier
6
+ } from "./chunk-WS5DYEVZ.mjs";
7
+
8
+ // src/connectorRuntime.ts
9
+ import { logger as logger2 } from "@tradejs/infra/logger";
10
+ import { resolveTradingAccount } from "@tradejs/infra/tradingAccounts";
11
+
12
+ // src/timescaleCachedKline.ts
13
+ import { PRELOAD_FALLBACK_DAYS } from "@tradejs/core/constants";
14
+ import { mergeData } from "@tradejs/core/data";
15
+ import { getItemTimestamp, getTimestamp } from "@tradejs/core/time";
16
+ import { delay } from "@tradejs/core/async";
17
+ import { logger } from "@tradejs/infra/logger";
18
+ import {
19
+ getCandlesRange,
20
+ getDataEdges,
21
+ toRows,
22
+ upsertCandles
23
+ } from "@tradejs/infra/timescale/candles";
24
+ var DEFAULT_LIMIT = 1e3;
25
+ var DEFAULT_CACHE_FALLBACK_WINDOW = 1e3;
26
+ var DEFAULT_TIMESCALE_RETRIES = 2;
27
+ var DEFAULT_TIMESCALE_RETRY_DELAY_MS = 1e3;
28
+ var resolveNonNegativeInt = (value, fallback) => {
29
+ const parsed = Number(value);
30
+ if (!Number.isFinite(parsed) || parsed < 0) {
31
+ return fallback;
32
+ }
33
+ return Math.floor(parsed);
34
+ };
35
+ var getTimescaleRetryCount = () => resolveNonNegativeInt(
36
+ process.env.TIMESCALE_KLINE_RETRIES,
37
+ DEFAULT_TIMESCALE_RETRIES
38
+ );
39
+ var getTimescaleRetryDelayMs = () => resolveNonNegativeInt(
40
+ process.env.TIMESCALE_KLINE_RETRY_DELAY_MS,
41
+ DEFAULT_TIMESCALE_RETRY_DELAY_MS
42
+ );
43
+ var intervalMsOf = (interval) => interval * 6e4;
44
+ var clampToClosedCandle = (value, intervalMs) => Math.floor(value / intervalMs) * intervalMs;
45
+ var normalizeRangeToClosed = (intervalMs, start, end) => {
46
+ const lastClosed = Math.floor(Date.now() / intervalMs) * intervalMs;
47
+ const normStart = start !== void 0 ? clampToClosedCandle(start, intervalMs) : 0;
48
+ const cappedEnd = Math.min(end ?? Date.now(), lastClosed);
49
+ const normEnd = clampToClosedCandle(cappedEnd, intervalMs);
50
+ return { normStart, normEnd };
51
+ };
52
+ var rowsToKline = (rows) => rows.map(({ ts, ...data }) => ({
53
+ timestamp: new Date(ts).getTime(),
54
+ ...data
55
+ }));
56
+ var createTimescaleCachedKline = ({
57
+ provider,
58
+ request,
59
+ intervalToMinutes,
60
+ limit = DEFAULT_LIMIT,
61
+ cacheFallbackWindow = DEFAULT_CACHE_FALLBACK_WINDOW
62
+ }) => {
63
+ let isTimescaleFallbackMode = false;
64
+ const runTimescaleOperation = async (operation) => {
65
+ const retries = getTimescaleRetryCount();
66
+ const retryDelayMs = getTimescaleRetryDelayMs();
67
+ for (let attempt = 0; ; attempt += 1) {
68
+ try {
69
+ return await operation();
70
+ } catch (error) {
71
+ if (attempt >= retries) {
72
+ throw error;
73
+ }
74
+ const waitMs = retryDelayMs * 2 ** attempt;
75
+ if (waitMs > 0) {
76
+ await delay(waitMs);
77
+ }
78
+ }
79
+ }
80
+ };
81
+ const loadData = async (direction, pointer, limitBoundary, requestParams, intervalMs, options = {}) => {
82
+ if (pointer === void 0) return { data: [], loaded: false };
83
+ let accumulated = [];
84
+ let fulfilled = false;
85
+ let loaded = false;
86
+ const shouldAccumulate = options.accumulate ?? true;
87
+ while (!fulfilled) {
88
+ const currentPointer = pointer;
89
+ const params = {
90
+ symbol: requestParams.symbol,
91
+ interval: requestParams.interval,
92
+ silent: requestParams.silent,
93
+ end: requestParams.end
94
+ };
95
+ if (direction === "older") {
96
+ params.end = pointer;
97
+ if (limitBoundary !== void 0) params.start = limitBoundary;
98
+ } else {
99
+ params.start = pointer;
100
+ if (limitBoundary !== void 0) params.end = limitBoundary;
101
+ }
102
+ const partData = await request(params);
103
+ if (!partData.length) {
104
+ fulfilled = true;
105
+ break;
106
+ }
107
+ loaded = true;
108
+ if (options.onPartData) {
109
+ await options.onPartData(partData);
110
+ }
111
+ if (shouldAccumulate) {
112
+ accumulated = direction === "older" ? mergeData(partData, accumulated) : mergeData(accumulated, partData);
113
+ }
114
+ const boundaryReached = limitBoundary !== void 0 && (direction === "older" && currentPointer <= limitBoundary || direction === "newer" && currentPointer >= limitBoundary);
115
+ if (partData.length < limit || boundaryReached) {
116
+ fulfilled = true;
117
+ break;
118
+ }
119
+ const nextPointer = direction === "older" ? getItemTimestamp(partData[0]) - intervalMs : getItemTimestamp(partData[partData.length - 1]) + intervalMs;
120
+ if (!Number.isFinite(nextPointer) || nextPointer === currentPointer) {
121
+ fulfilled = true;
122
+ break;
123
+ }
124
+ pointer = nextPointer;
125
+ }
126
+ return { data: accumulated, loaded };
127
+ };
128
+ const refreshTail = async ({
129
+ symbol,
130
+ interval,
131
+ silent,
132
+ tailCount = 2
133
+ }) => {
134
+ const intMinutes = intervalToMinutes(interval);
135
+ if (!intMinutes) {
136
+ logger.log("error", "refreshTail: invalid interval %s", interval);
137
+ return;
138
+ }
139
+ const intervalMs = intervalMsOf(intMinutes);
140
+ const lastClosed = Math.floor(Date.now() / intervalMs) * intervalMs;
141
+ const tailEnd = lastClosed + intervalMs;
142
+ const tailStart = tailEnd - tailCount * intervalMs;
143
+ const part = await request({
144
+ symbol,
145
+ interval,
146
+ start: tailStart,
147
+ end: tailEnd,
148
+ silent
149
+ });
150
+ if (part.length) {
151
+ await runTimescaleOperation(
152
+ () => upsertCandles(toRows(provider, symbol, intMinutes, part))
153
+ );
154
+ }
155
+ };
156
+ return async ({
157
+ symbol,
158
+ interval,
159
+ start: defaultStart,
160
+ end: defaultEnd,
161
+ silent = false,
162
+ cacheOnly = false,
163
+ warmOnly = false
164
+ }) => {
165
+ const intMinutes = intervalToMinutes(interval);
166
+ if (!intMinutes) {
167
+ logger.log("error", "kline: invalid interval %s", interval);
168
+ return [];
169
+ }
170
+ if (defaultStart !== void 0 && defaultEnd !== void 0 && defaultEnd <= defaultStart) {
171
+ return [];
172
+ }
173
+ const intervalMs = intervalMsOf(intMinutes);
174
+ try {
175
+ const edges = await runTimescaleOperation(
176
+ () => getDataEdges(provider, symbol, intMinutes)
177
+ );
178
+ let dataStart = edges.min;
179
+ let dataEnd = edges.max;
180
+ const { normStart, normEnd } = normalizeRangeToClosed(
181
+ intervalMs,
182
+ defaultStart,
183
+ defaultEnd
184
+ );
185
+ if (cacheOnly) {
186
+ const base = edges.max ?? Date.now();
187
+ const s = Math.max(
188
+ defaultStart ?? base - cacheFallbackWindow * intervalMs,
189
+ 0
190
+ );
191
+ const e = defaultEnd ?? base;
192
+ const dbData2 = await runTimescaleOperation(
193
+ () => getCandlesRange(provider, symbol, intMinutes, s, e)
194
+ );
195
+ return rowsToKline(dbData2);
196
+ }
197
+ const needOlderData = defaultStart !== void 0 && (dataStart === void 0 || normStart < dataStart);
198
+ const persistPartData = warmOnly ? (partData) => runTimescaleOperation(
199
+ () => upsertCandles(toRows(provider, symbol, intMinutes, partData))
200
+ ) : void 0;
201
+ if (needOlderData) {
202
+ const pointerForOlder = dataStart ?? normEnd ?? Date.now();
203
+ const olderResult = await loadData(
204
+ "older",
205
+ pointerForOlder,
206
+ normStart,
207
+ {
208
+ symbol,
209
+ interval,
210
+ silent,
211
+ start: normStart,
212
+ end: pointerForOlder
213
+ },
214
+ intervalMs,
215
+ {
216
+ accumulate: !warmOnly,
217
+ onPartData: persistPartData
218
+ }
219
+ );
220
+ if (warmOnly && olderResult.loaded) {
221
+ dataStart = normStart;
222
+ if (dataEnd === void 0) {
223
+ dataEnd = normEnd;
224
+ }
225
+ } else if (olderResult.data.length) {
226
+ await runTimescaleOperation(
227
+ () => upsertCandles(
228
+ toRows(provider, symbol, intMinutes, olderResult.data)
229
+ )
230
+ );
231
+ dataStart = normStart;
232
+ if (dataEnd === void 0) {
233
+ dataEnd = normEnd;
234
+ }
235
+ }
236
+ }
237
+ const needNewerData = defaultEnd !== void 0 && (dataEnd === void 0 || normEnd > dataEnd);
238
+ if (needNewerData) {
239
+ const fallbackStart = getTimestamp(PRELOAD_FALLBACK_DAYS);
240
+ const pointerForNewer = dataEnd ?? (defaultStart !== void 0 ? normStart : fallbackStart) ?? 0;
241
+ const newerResult = await loadData(
242
+ "newer",
243
+ pointerForNewer,
244
+ normEnd,
245
+ {
246
+ symbol,
247
+ interval,
248
+ silent,
249
+ start: pointerForNewer,
250
+ end: normEnd
251
+ },
252
+ intervalMs,
253
+ {
254
+ accumulate: !warmOnly,
255
+ onPartData: persistPartData
256
+ }
257
+ );
258
+ if (warmOnly && newerResult.loaded) {
259
+ dataEnd = normEnd;
260
+ } else if (newerResult.data.length) {
261
+ await runTimescaleOperation(
262
+ () => upsertCandles(
263
+ toRows(provider, symbol, intMinutes, newerResult.data)
264
+ )
265
+ );
266
+ dataEnd = normEnd;
267
+ }
268
+ }
269
+ const isRightEdgeQuery = defaultEnd === void 0 || defaultEnd && defaultEnd >= Date.now() - intervalMs;
270
+ if (!cacheOnly && isRightEdgeQuery) {
271
+ await refreshTail({ symbol, interval, silent });
272
+ }
273
+ if (warmOnly) {
274
+ if (isTimescaleFallbackMode) {
275
+ isTimescaleFallbackMode = false;
276
+ logger.log("info", "TimescaleDB connection restored for kline cache");
277
+ }
278
+ return [];
279
+ }
280
+ const rangeStart = defaultStart ?? dataStart ?? 0;
281
+ const rangeEnd = defaultEnd ?? dataEnd ?? Date.now();
282
+ const { normStart: finalStart, normEnd: finalEnd } = normalizeRangeToClosed(intervalMs, rangeStart, rangeEnd);
283
+ const dbData = await runTimescaleOperation(
284
+ () => getCandlesRange(provider, symbol, intMinutes, finalStart, finalEnd)
285
+ );
286
+ if (isTimescaleFallbackMode) {
287
+ isTimescaleFallbackMode = false;
288
+ logger.log("info", "TimescaleDB connection restored for kline cache");
289
+ }
290
+ return rowsToKline(dbData);
291
+ } catch (error) {
292
+ if (!isTimescaleFallbackMode) {
293
+ isTimescaleFallbackMode = true;
294
+ logger.log(
295
+ "warn",
296
+ "TimescaleDB unavailable for %s %s: %s. Falling back to exchange API.",
297
+ symbol,
298
+ interval,
299
+ String(error)
300
+ );
301
+ }
302
+ if (cacheOnly || warmOnly) {
303
+ return [];
304
+ }
305
+ return request({
306
+ symbol,
307
+ interval,
308
+ start: defaultStart,
309
+ end: defaultEnd,
310
+ silent
311
+ });
312
+ }
313
+ };
314
+ };
315
+
316
+ // src/connectorRuntime.ts
317
+ var connectorRuntime = {
318
+ logger: logger2,
319
+ resolveTradingAccount,
320
+ createCachedKline: createTimescaleCachedKline
321
+ };
322
+ var bindConnectorRuntime = (creator, runtime = connectorRuntime) => {
323
+ const boundCreator = (config) => creator(config, runtime);
324
+ return boundCreator;
325
+ };
326
+
327
+ // src/connectorsRegistry.ts
328
+ import { logger as logger3 } from "@tradejs/infra/logger";
329
+ var createConnectorRegistryState = () => ({
330
+ connectorCreators: /* @__PURE__ */ new Map(),
331
+ providerToConnectorName: /* @__PURE__ */ new Map(),
332
+ pluginsLoadPromise: null
333
+ });
334
+ var registryStateByProjectRoot = /* @__PURE__ */ new Map();
335
+ var getConnectorRegistryState = (cwd = getTradejsProjectCwd()) => {
336
+ const projectRoot = getTradejsProjectCwd(cwd);
337
+ let state = registryStateByProjectRoot.get(projectRoot);
338
+ if (!state) {
339
+ state = createConnectorRegistryState();
340
+ registryStateByProjectRoot.set(projectRoot, state);
341
+ }
342
+ return {
343
+ projectRoot,
344
+ state
345
+ };
346
+ };
347
+ var BUILTIN_CONNECTOR_NAMES = {
348
+ ByBit: "ByBit",
349
+ Binance: "Binance",
350
+ Coinbase: "Coinbase",
351
+ Test: "Test"
352
+ };
353
+ var normalizeProvider = (value) => String(value ?? "").trim().toLowerCase();
354
+ var toUniqueModules = (modules = []) => [
355
+ ...new Set(modules.map((moduleName) => moduleName.trim()).filter(Boolean))
356
+ ];
357
+ var findConnectorNameInsensitive = (name, connectorCreators) => {
358
+ const normalized = name.trim().toLowerCase();
359
+ if (!normalized) {
360
+ return null;
361
+ }
362
+ for (const existingName of connectorCreators.keys()) {
363
+ if (existingName.toLowerCase() === normalized) {
364
+ return existingName;
365
+ }
366
+ }
367
+ return null;
368
+ };
369
+ var normalizeProviders = (providers, connectorName) => {
370
+ const list = Array.isArray(providers) ? providers.map((item) => normalizeProvider(item)).filter(Boolean) : [];
371
+ const deduped = [...new Set(list)];
372
+ if (deduped.length) {
373
+ return deduped;
374
+ }
375
+ return [normalizeProvider(connectorName)];
376
+ };
377
+ var registerProvider = (provider, connectorName, source, providerToConnectorName) => {
378
+ const existing = providerToConnectorName.get(provider);
379
+ if (existing && existing !== connectorName) {
380
+ logger3.warn(
381
+ 'Skip duplicate connector provider "%s" from %s: already mapped to %s',
382
+ provider,
383
+ source,
384
+ existing
385
+ );
386
+ return;
387
+ }
388
+ providerToConnectorName.set(provider, connectorName);
389
+ };
390
+ var registerEntry = (entry, source, state) => {
391
+ const connectorName = String(entry?.name ?? "").trim();
392
+ if (!connectorName) {
393
+ logger3.warn("Skip connector entry without name from %s", source);
394
+ return;
395
+ }
396
+ if (typeof entry.creator !== "function") {
397
+ logger3.warn(
398
+ 'Skip connector entry "%s" from %s: creator must be a function',
399
+ connectorName,
400
+ source
401
+ );
402
+ return;
403
+ }
404
+ const existingByName = findConnectorNameInsensitive(
405
+ connectorName,
406
+ state.connectorCreators
407
+ );
408
+ if (existingByName) {
409
+ logger3.warn(
410
+ 'Skip duplicate connector "%s" from %s: already registered as %s',
411
+ connectorName,
412
+ source,
413
+ existingByName
414
+ );
415
+ return;
416
+ }
417
+ state.connectorCreators.set(
418
+ connectorName,
419
+ bindConnectorRuntime(entry.creator)
420
+ );
421
+ const providers = normalizeProviders(entry.providers, connectorName);
422
+ for (const provider of providers) {
423
+ registerProvider(
424
+ provider,
425
+ connectorName,
426
+ source,
427
+ state.providerToConnectorName
428
+ );
429
+ }
430
+ };
431
+ var registerEntries = (entries, source, state) => {
432
+ for (const entry of entries) {
433
+ registerEntry(entry, source, state);
434
+ }
435
+ };
436
+ var extractConnectorPluginDefinition = (moduleExport) => {
437
+ if (!moduleExport || typeof moduleExport !== "object") {
438
+ return null;
439
+ }
440
+ const candidate = moduleExport;
441
+ if (Array.isArray(candidate.connectorEntries)) {
442
+ return {
443
+ connectorEntries: candidate.connectorEntries
444
+ };
445
+ }
446
+ const defaultExport = candidate.default;
447
+ if (defaultExport && Array.isArray(defaultExport.connectorEntries)) {
448
+ return {
449
+ connectorEntries: defaultExport.connectorEntries
450
+ };
451
+ }
452
+ return null;
453
+ };
454
+ var importConnectorPluginModule = async (moduleName, cwd = getTradejsProjectCwd()) => {
455
+ if (typeof importTradejsModule === "function") {
456
+ return importTradejsModule(moduleName, cwd);
457
+ }
458
+ return import(
459
+ /* webpackIgnore: true */
460
+ moduleName
461
+ );
462
+ };
463
+ var ensureConnectorPluginsLoaded = async (cwd = getTradejsProjectCwd()) => {
464
+ const { projectRoot, state } = getConnectorRegistryState(cwd);
465
+ if (!state.pluginsLoadPromise) {
466
+ state.pluginsLoadPromise = (async () => {
467
+ const config = await loadTradejsConfig(projectRoot);
468
+ const connectorModules = toUniqueModules(config.connectors);
469
+ if (!connectorModules.length) {
470
+ return;
471
+ }
472
+ for (const moduleName of connectorModules) {
473
+ try {
474
+ const resolvedModuleName = resolvePluginModuleSpecifier(
475
+ moduleName,
476
+ projectRoot
477
+ );
478
+ const moduleExport = await importConnectorPluginModule(
479
+ resolvedModuleName,
480
+ projectRoot
481
+ );
482
+ const pluginDefinition = extractConnectorPluginDefinition(moduleExport);
483
+ if (!pluginDefinition) {
484
+ logger3.warn(
485
+ 'Skip connector plugin "%s": export { connectorEntries } is missing',
486
+ moduleName
487
+ );
488
+ continue;
489
+ }
490
+ registerEntries(pluginDefinition.connectorEntries, moduleName, state);
491
+ } catch (error) {
492
+ logger3.warn(
493
+ 'Failed to load connector plugin "%s": %s',
494
+ moduleName,
495
+ String(error)
496
+ );
497
+ }
498
+ }
499
+ })();
500
+ }
501
+ await state.pluginsLoadPromise;
502
+ };
503
+ var getConnectorCreatorByName = async (connectorName, cwd = getTradejsProjectCwd()) => {
504
+ await ensureConnectorPluginsLoaded(cwd);
505
+ const { state } = getConnectorRegistryState(cwd);
506
+ const raw = String(connectorName ?? "").trim();
507
+ if (!raw) {
508
+ return void 0;
509
+ }
510
+ const direct = state.connectorCreators.get(raw);
511
+ if (direct) {
512
+ return direct;
513
+ }
514
+ const existing = findConnectorNameInsensitive(raw, state.connectorCreators);
515
+ if (!existing) {
516
+ return void 0;
517
+ }
518
+ return state.connectorCreators.get(existing);
519
+ };
520
+ var getConnectorNameByProvider = async (provider, cwd = getTradejsProjectCwd()) => {
521
+ await ensureConnectorPluginsLoaded(cwd);
522
+ const { state } = getConnectorRegistryState(cwd);
523
+ const normalized = normalizeProvider(provider);
524
+ if (!normalized) {
525
+ return void 0;
526
+ }
527
+ return state.providerToConnectorName.get(normalized);
528
+ };
529
+ var getConnectorCreatorByProvider = async (provider, cwd = getTradejsProjectCwd()) => {
530
+ await ensureConnectorPluginsLoaded(cwd);
531
+ const { state } = getConnectorRegistryState(cwd);
532
+ const normalized = normalizeProvider(provider);
533
+ if (!normalized) {
534
+ return void 0;
535
+ }
536
+ const connectorName = state.providerToConnectorName.get(normalized);
537
+ if (!connectorName) {
538
+ return void 0;
539
+ }
540
+ return state.connectorCreators.get(connectorName);
541
+ };
542
+ var resolveConnectorName = async (providerOrName, cwd = getTradejsProjectCwd()) => {
543
+ await ensureConnectorPluginsLoaded(cwd);
544
+ const { state } = getConnectorRegistryState(cwd);
545
+ const raw = String(providerOrName ?? "").trim();
546
+ if (!raw) {
547
+ return void 0;
548
+ }
549
+ const byProvider = state.providerToConnectorName.get(normalizeProvider(raw));
550
+ if (byProvider) {
551
+ return byProvider;
552
+ }
553
+ return state.connectorCreators.get(raw) && raw ? raw : findConnectorNameInsensitive(raw, state.connectorCreators) ?? void 0;
554
+ };
555
+ var getAvailableConnectorNames = async (cwd = getTradejsProjectCwd()) => {
556
+ await ensureConnectorPluginsLoaded(cwd);
557
+ const { state } = getConnectorRegistryState(cwd);
558
+ return [...state.connectorCreators.keys()].sort((a, b) => a.localeCompare(b));
559
+ };
560
+ var getAvailableConnectorProviders = async (cwd = getTradejsProjectCwd()) => {
561
+ await ensureConnectorPluginsLoaded(cwd);
562
+ const { state } = getConnectorRegistryState(cwd);
563
+ return [...state.providerToConnectorName.keys()].sort(
564
+ (a, b) => a.localeCompare(b)
565
+ );
566
+ };
567
+ var registerConnectorEntries = (entries, cwd = getTradejsProjectCwd()) => {
568
+ const { state } = getConnectorRegistryState(cwd);
569
+ registerEntries(entries, "runtime", state);
570
+ };
571
+ var resetConnectorRegistryCache = (cwd) => {
572
+ const normalizedCwd = String(cwd ?? "").trim();
573
+ if (!normalizedCwd) {
574
+ registryStateByProjectRoot.clear();
575
+ return;
576
+ }
577
+ registryStateByProjectRoot.delete(getTradejsProjectCwd(normalizedCwd));
578
+ };
579
+ var DEFAULT_CONNECTOR_NAME = BUILTIN_CONNECTOR_NAMES.ByBit;
580
+
581
+ export {
582
+ connectorRuntime,
583
+ bindConnectorRuntime,
584
+ BUILTIN_CONNECTOR_NAMES,
585
+ ensureConnectorPluginsLoaded,
586
+ getConnectorCreatorByName,
587
+ getConnectorNameByProvider,
588
+ getConnectorCreatorByProvider,
589
+ resolveConnectorName,
590
+ getAvailableConnectorNames,
591
+ getAvailableConnectorProviders,
592
+ registerConnectorEntries,
593
+ resetConnectorRegistryCache,
594
+ DEFAULT_CONNECTOR_NAME
595
+ };