@tradejs/connectors 3.0.0 → 3.1.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/index.d.mts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +104 -381
- package/dist/index.mjs +86 -368
- package/package.json +3 -4
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
// src/ByBit/index.ts
|
|
2
2
|
import _ from "lodash";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
-
import { delay
|
|
5
|
-
import { PRELOAD_FALLBACK_DAYS
|
|
4
|
+
import { delay } from "@tradejs/core/async";
|
|
5
|
+
import { PRELOAD_FALLBACK_DAYS } from "@tradejs/core/constants";
|
|
6
6
|
import { toJson } from "@tradejs/core/data";
|
|
7
7
|
import { round } from "@tradejs/core/math";
|
|
8
8
|
import { normalizeTickerData } from "@tradejs/core/tickers";
|
|
9
|
-
import { formatUnix as formatUnix2, getTimestamp
|
|
10
|
-
import { logger as logger3 } from "@tradejs/infra/logger";
|
|
9
|
+
import { formatUnix as formatUnix2, getTimestamp } from "@tradejs/core/time";
|
|
11
10
|
|
|
12
11
|
// src/ByBit/client.ts
|
|
13
12
|
import { RestClientV5 } from "bybit-api";
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
|
|
14
|
+
// src/shared/runtime.ts
|
|
15
|
+
var noop = () => void 0;
|
|
16
|
+
var silentConnectorLogger = {
|
|
17
|
+
log: noop,
|
|
18
|
+
info: noop,
|
|
19
|
+
warn: noop,
|
|
20
|
+
error: noop
|
|
21
|
+
};
|
|
22
|
+
var getConnectorLogger = (runtime) => runtime?.logger ?? silentConnectorLogger;
|
|
23
|
+
var getConnectorAccountResolver = (runtime) => runtime?.resolveTradingAccount ?? (async () => null);
|
|
24
|
+
var decorateConnectorKline = (runtime, options) => runtime?.createCachedKline(options) ?? options.request;
|
|
25
|
+
|
|
26
|
+
// src/ByBit/client.ts
|
|
16
27
|
var PRIVATE_RECV_WINDOW_MS = 1e4;
|
|
17
|
-
var getClient = async (config, access = "private") => {
|
|
28
|
+
var getClient = async (config, access = "private", runtime) => {
|
|
29
|
+
const logger = getConnectorLogger(runtime);
|
|
30
|
+
const resolveTradingAccount = getConnectorAccountResolver(runtime);
|
|
18
31
|
const account = access === "public" && !config.accountId ? null : await resolveTradingAccount({
|
|
19
32
|
userName: config.userName,
|
|
20
33
|
accountId: config.accountId,
|
|
@@ -54,310 +67,6 @@ var getClient = async (config, access = "private") => {
|
|
|
54
67
|
return client;
|
|
55
68
|
};
|
|
56
69
|
|
|
57
|
-
// src/shared/timescaleKlineCache.ts
|
|
58
|
-
import { PRELOAD_FALLBACK_DAYS } from "@tradejs/core/constants";
|
|
59
|
-
import { mergeData } from "@tradejs/core/data";
|
|
60
|
-
import { getItemTimestamp, getTimestamp } from "@tradejs/core/time";
|
|
61
|
-
import { delay } from "@tradejs/core/async";
|
|
62
|
-
import { logger as logger2 } from "@tradejs/infra/logger";
|
|
63
|
-
import {
|
|
64
|
-
getCandlesRange,
|
|
65
|
-
getDataEdges,
|
|
66
|
-
toRows,
|
|
67
|
-
upsertCandles
|
|
68
|
-
} from "@tradejs/infra/timescale/candles";
|
|
69
|
-
var DEFAULT_LIMIT = 1e3;
|
|
70
|
-
var DEFAULT_CACHE_FALLBACK_WINDOW = 1e3;
|
|
71
|
-
var DEFAULT_TIMESCALE_RETRIES = 2;
|
|
72
|
-
var DEFAULT_TIMESCALE_RETRY_DELAY_MS = 1e3;
|
|
73
|
-
var resolveNonNegativeInt = (value, fallback) => {
|
|
74
|
-
const parsed = Number(value);
|
|
75
|
-
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
76
|
-
return fallback;
|
|
77
|
-
}
|
|
78
|
-
return Math.floor(parsed);
|
|
79
|
-
};
|
|
80
|
-
var getTimescaleRetryCount = () => resolveNonNegativeInt(
|
|
81
|
-
process.env.TIMESCALE_KLINE_RETRIES,
|
|
82
|
-
DEFAULT_TIMESCALE_RETRIES
|
|
83
|
-
);
|
|
84
|
-
var getTimescaleRetryDelayMs = () => resolveNonNegativeInt(
|
|
85
|
-
process.env.TIMESCALE_KLINE_RETRY_DELAY_MS,
|
|
86
|
-
DEFAULT_TIMESCALE_RETRY_DELAY_MS
|
|
87
|
-
);
|
|
88
|
-
var intervalMsOf = (interval) => interval * 6e4;
|
|
89
|
-
var clampToClosedCandle = (value, intervalMs) => Math.floor(value / intervalMs) * intervalMs;
|
|
90
|
-
var normalizeRangeToClosed = (intervalMs, start, end) => {
|
|
91
|
-
const lastClosed = Math.floor(Date.now() / intervalMs) * intervalMs;
|
|
92
|
-
const normStart = start !== void 0 ? clampToClosedCandle(start, intervalMs) : 0;
|
|
93
|
-
const cappedEnd = Math.min(end ?? Date.now(), lastClosed);
|
|
94
|
-
const normEnd = clampToClosedCandle(cappedEnd, intervalMs);
|
|
95
|
-
return { normStart, normEnd };
|
|
96
|
-
};
|
|
97
|
-
var rowsToKline = (rows) => rows.map(({ ts, ...data }) => ({
|
|
98
|
-
timestamp: new Date(ts).getTime(),
|
|
99
|
-
...data
|
|
100
|
-
}));
|
|
101
|
-
var createTimescaleCachedKline = ({
|
|
102
|
-
provider,
|
|
103
|
-
request,
|
|
104
|
-
intervalToMinutes: intervalToMinutes3,
|
|
105
|
-
limit = DEFAULT_LIMIT,
|
|
106
|
-
cacheFallbackWindow = DEFAULT_CACHE_FALLBACK_WINDOW
|
|
107
|
-
}) => {
|
|
108
|
-
let isTimescaleFallbackMode = false;
|
|
109
|
-
const runTimescaleOperation = async (operation) => {
|
|
110
|
-
const retries = getTimescaleRetryCount();
|
|
111
|
-
const retryDelayMs = getTimescaleRetryDelayMs();
|
|
112
|
-
for (let attempt = 0; ; attempt += 1) {
|
|
113
|
-
try {
|
|
114
|
-
return await operation();
|
|
115
|
-
} catch (error) {
|
|
116
|
-
if (attempt >= retries) {
|
|
117
|
-
throw error;
|
|
118
|
-
}
|
|
119
|
-
const waitMs = retryDelayMs * 2 ** attempt;
|
|
120
|
-
if (waitMs > 0) {
|
|
121
|
-
await delay(waitMs);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
const loadData = async (direction, pointer, limitBoundary, requestParams, intervalMs, options = {}) => {
|
|
127
|
-
if (pointer === void 0) return { data: [], loaded: false };
|
|
128
|
-
let accumulated = [];
|
|
129
|
-
let fulfilled = false;
|
|
130
|
-
let loaded = false;
|
|
131
|
-
const shouldAccumulate = options.accumulate ?? true;
|
|
132
|
-
while (!fulfilled) {
|
|
133
|
-
const currentPointer = pointer;
|
|
134
|
-
const params = {
|
|
135
|
-
symbol: requestParams.symbol,
|
|
136
|
-
interval: requestParams.interval,
|
|
137
|
-
silent: requestParams.silent,
|
|
138
|
-
end: requestParams.end
|
|
139
|
-
};
|
|
140
|
-
if (direction === "older") {
|
|
141
|
-
params.end = pointer;
|
|
142
|
-
if (limitBoundary !== void 0) params.start = limitBoundary;
|
|
143
|
-
} else {
|
|
144
|
-
params.start = pointer;
|
|
145
|
-
if (limitBoundary !== void 0) params.end = limitBoundary;
|
|
146
|
-
}
|
|
147
|
-
const partData = await request(params);
|
|
148
|
-
if (!partData.length) {
|
|
149
|
-
fulfilled = true;
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
loaded = true;
|
|
153
|
-
if (options.onPartData) {
|
|
154
|
-
await options.onPartData(partData);
|
|
155
|
-
}
|
|
156
|
-
if (shouldAccumulate) {
|
|
157
|
-
accumulated = direction === "older" ? mergeData(partData, accumulated) : mergeData(accumulated, partData);
|
|
158
|
-
}
|
|
159
|
-
const boundaryReached = limitBoundary !== void 0 && (direction === "older" && currentPointer <= limitBoundary || direction === "newer" && currentPointer >= limitBoundary);
|
|
160
|
-
if (partData.length < limit || boundaryReached) {
|
|
161
|
-
fulfilled = true;
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
const nextPointer = direction === "older" ? getItemTimestamp(partData[0]) - intervalMs : getItemTimestamp(partData[partData.length - 1]) + intervalMs;
|
|
165
|
-
if (!Number.isFinite(nextPointer) || nextPointer === currentPointer) {
|
|
166
|
-
fulfilled = true;
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
pointer = nextPointer;
|
|
170
|
-
}
|
|
171
|
-
return { data: accumulated, loaded };
|
|
172
|
-
};
|
|
173
|
-
const refreshTail = async ({
|
|
174
|
-
symbol,
|
|
175
|
-
interval,
|
|
176
|
-
silent,
|
|
177
|
-
tailCount = 2
|
|
178
|
-
}) => {
|
|
179
|
-
const intMinutes = intervalToMinutes3(interval);
|
|
180
|
-
if (!intMinutes) {
|
|
181
|
-
logger2.log("error", "refreshTail: invalid interval %s", interval);
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
const intervalMs = intervalMsOf(intMinutes);
|
|
185
|
-
const lastClosed = Math.floor(Date.now() / intervalMs) * intervalMs;
|
|
186
|
-
const tailEnd = lastClosed + intervalMs;
|
|
187
|
-
const tailStart = tailEnd - tailCount * intervalMs;
|
|
188
|
-
const part = await request({
|
|
189
|
-
symbol,
|
|
190
|
-
interval,
|
|
191
|
-
start: tailStart,
|
|
192
|
-
end: tailEnd,
|
|
193
|
-
silent
|
|
194
|
-
});
|
|
195
|
-
if (part.length) {
|
|
196
|
-
await runTimescaleOperation(
|
|
197
|
-
() => upsertCandles(toRows(provider, symbol, intMinutes, part))
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
return async ({
|
|
202
|
-
symbol,
|
|
203
|
-
interval,
|
|
204
|
-
start: defaultStart,
|
|
205
|
-
end: defaultEnd,
|
|
206
|
-
silent = false,
|
|
207
|
-
cacheOnly = false,
|
|
208
|
-
warmOnly = false
|
|
209
|
-
}) => {
|
|
210
|
-
const intMinutes = intervalToMinutes3(interval);
|
|
211
|
-
if (!intMinutes) {
|
|
212
|
-
logger2.log("error", "kline: invalid interval %s", interval);
|
|
213
|
-
return [];
|
|
214
|
-
}
|
|
215
|
-
if (defaultStart !== void 0 && defaultEnd !== void 0 && defaultEnd <= defaultStart) {
|
|
216
|
-
return [];
|
|
217
|
-
}
|
|
218
|
-
const intervalMs = intervalMsOf(intMinutes);
|
|
219
|
-
try {
|
|
220
|
-
const edges = await runTimescaleOperation(
|
|
221
|
-
() => getDataEdges(provider, symbol, intMinutes)
|
|
222
|
-
);
|
|
223
|
-
let dataStart = edges.min;
|
|
224
|
-
let dataEnd = edges.max;
|
|
225
|
-
const { normStart, normEnd } = normalizeRangeToClosed(
|
|
226
|
-
intervalMs,
|
|
227
|
-
defaultStart,
|
|
228
|
-
defaultEnd
|
|
229
|
-
);
|
|
230
|
-
if (cacheOnly) {
|
|
231
|
-
const base = edges.max ?? Date.now();
|
|
232
|
-
const s = Math.max(
|
|
233
|
-
defaultStart ?? base - cacheFallbackWindow * intervalMs,
|
|
234
|
-
0
|
|
235
|
-
);
|
|
236
|
-
const e = defaultEnd ?? base;
|
|
237
|
-
const dbData2 = await runTimescaleOperation(
|
|
238
|
-
() => getCandlesRange(provider, symbol, intMinutes, s, e)
|
|
239
|
-
);
|
|
240
|
-
return rowsToKline(dbData2);
|
|
241
|
-
}
|
|
242
|
-
const needOlderData = defaultStart !== void 0 && (dataStart === void 0 || normStart < dataStart);
|
|
243
|
-
const persistPartData = warmOnly ? (partData) => runTimescaleOperation(
|
|
244
|
-
() => upsertCandles(toRows(provider, symbol, intMinutes, partData))
|
|
245
|
-
) : void 0;
|
|
246
|
-
if (needOlderData) {
|
|
247
|
-
const pointerForOlder = dataStart ?? normEnd ?? Date.now();
|
|
248
|
-
const olderResult = await loadData(
|
|
249
|
-
"older",
|
|
250
|
-
pointerForOlder,
|
|
251
|
-
normStart,
|
|
252
|
-
{
|
|
253
|
-
symbol,
|
|
254
|
-
interval,
|
|
255
|
-
silent,
|
|
256
|
-
start: normStart,
|
|
257
|
-
end: pointerForOlder
|
|
258
|
-
},
|
|
259
|
-
intervalMs,
|
|
260
|
-
{
|
|
261
|
-
accumulate: !warmOnly,
|
|
262
|
-
onPartData: persistPartData
|
|
263
|
-
}
|
|
264
|
-
);
|
|
265
|
-
if (warmOnly && olderResult.loaded) {
|
|
266
|
-
dataStart = normStart;
|
|
267
|
-
if (dataEnd === void 0) {
|
|
268
|
-
dataEnd = normEnd;
|
|
269
|
-
}
|
|
270
|
-
} else if (olderResult.data.length) {
|
|
271
|
-
await runTimescaleOperation(
|
|
272
|
-
() => upsertCandles(
|
|
273
|
-
toRows(provider, symbol, intMinutes, olderResult.data)
|
|
274
|
-
)
|
|
275
|
-
);
|
|
276
|
-
dataStart = normStart;
|
|
277
|
-
if (dataEnd === void 0) {
|
|
278
|
-
dataEnd = normEnd;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
const needNewerData = defaultEnd !== void 0 && (dataEnd === void 0 || normEnd > dataEnd);
|
|
283
|
-
if (needNewerData) {
|
|
284
|
-
const fallbackStart = getTimestamp(PRELOAD_FALLBACK_DAYS);
|
|
285
|
-
const pointerForNewer = dataEnd ?? (defaultStart !== void 0 ? normStart : fallbackStart) ?? 0;
|
|
286
|
-
const newerResult = await loadData(
|
|
287
|
-
"newer",
|
|
288
|
-
pointerForNewer,
|
|
289
|
-
normEnd,
|
|
290
|
-
{
|
|
291
|
-
symbol,
|
|
292
|
-
interval,
|
|
293
|
-
silent,
|
|
294
|
-
start: pointerForNewer,
|
|
295
|
-
end: normEnd
|
|
296
|
-
},
|
|
297
|
-
intervalMs,
|
|
298
|
-
{
|
|
299
|
-
accumulate: !warmOnly,
|
|
300
|
-
onPartData: persistPartData
|
|
301
|
-
}
|
|
302
|
-
);
|
|
303
|
-
if (warmOnly && newerResult.loaded) {
|
|
304
|
-
dataEnd = normEnd;
|
|
305
|
-
} else if (newerResult.data.length) {
|
|
306
|
-
await runTimescaleOperation(
|
|
307
|
-
() => upsertCandles(
|
|
308
|
-
toRows(provider, symbol, intMinutes, newerResult.data)
|
|
309
|
-
)
|
|
310
|
-
);
|
|
311
|
-
dataEnd = normEnd;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
const isRightEdgeQuery = defaultEnd === void 0 || defaultEnd && defaultEnd >= Date.now() - intervalMs;
|
|
315
|
-
if (!cacheOnly && isRightEdgeQuery) {
|
|
316
|
-
await refreshTail({ symbol, interval, silent });
|
|
317
|
-
}
|
|
318
|
-
if (warmOnly) {
|
|
319
|
-
if (isTimescaleFallbackMode) {
|
|
320
|
-
isTimescaleFallbackMode = false;
|
|
321
|
-
logger2.log("info", "TimescaleDB connection restored for kline cache");
|
|
322
|
-
}
|
|
323
|
-
return [];
|
|
324
|
-
}
|
|
325
|
-
const rangeStart = defaultStart ?? dataStart ?? 0;
|
|
326
|
-
const rangeEnd = defaultEnd ?? dataEnd ?? Date.now();
|
|
327
|
-
const { normStart: finalStart, normEnd: finalEnd } = normalizeRangeToClosed(intervalMs, rangeStart, rangeEnd);
|
|
328
|
-
const dbData = await runTimescaleOperation(
|
|
329
|
-
() => getCandlesRange(provider, symbol, intMinutes, finalStart, finalEnd)
|
|
330
|
-
);
|
|
331
|
-
if (isTimescaleFallbackMode) {
|
|
332
|
-
isTimescaleFallbackMode = false;
|
|
333
|
-
logger2.log("info", "TimescaleDB connection restored for kline cache");
|
|
334
|
-
}
|
|
335
|
-
return rowsToKline(dbData);
|
|
336
|
-
} catch (error) {
|
|
337
|
-
if (!isTimescaleFallbackMode) {
|
|
338
|
-
isTimescaleFallbackMode = true;
|
|
339
|
-
logger2.log(
|
|
340
|
-
"warn",
|
|
341
|
-
"TimescaleDB unavailable for %s %s: %s. Falling back to exchange API.",
|
|
342
|
-
symbol,
|
|
343
|
-
interval,
|
|
344
|
-
String(error)
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
if (cacheOnly || warmOnly) {
|
|
348
|
-
return [];
|
|
349
|
-
}
|
|
350
|
-
return request({
|
|
351
|
-
symbol,
|
|
352
|
-
interval,
|
|
353
|
-
start: defaultStart,
|
|
354
|
-
end: defaultEnd,
|
|
355
|
-
silent
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
};
|
|
360
|
-
|
|
361
70
|
// src/ByBit/utils.ts
|
|
362
71
|
import { formatUnix } from "@tradejs/core/time";
|
|
363
72
|
var BYBIT_CATEGORY = "linear";
|
|
@@ -555,7 +264,8 @@ var loadFundingFeeRows = async ({
|
|
|
555
264
|
client,
|
|
556
265
|
startTime,
|
|
557
266
|
endTime,
|
|
558
|
-
symbol
|
|
267
|
+
symbol,
|
|
268
|
+
logger
|
|
559
269
|
}) => {
|
|
560
270
|
if (typeof client.getTransactionLog !== "function") {
|
|
561
271
|
return [];
|
|
@@ -574,7 +284,7 @@ var loadFundingFeeRows = async ({
|
|
|
574
284
|
...cursor ? { cursor } : {}
|
|
575
285
|
});
|
|
576
286
|
if (response?.retCode !== 0) {
|
|
577
|
-
|
|
287
|
+
logger.log(
|
|
578
288
|
"debug",
|
|
579
289
|
"funding transaction log retCode: %s, %s",
|
|
580
290
|
response?.retCode,
|
|
@@ -606,7 +316,7 @@ var loadFundingFeeRows = async ({
|
|
|
606
316
|
}
|
|
607
317
|
return rows;
|
|
608
318
|
} catch (error) {
|
|
609
|
-
|
|
319
|
+
logger.log("debug", "funding transaction log failed: %s", error);
|
|
610
320
|
return [];
|
|
611
321
|
}
|
|
612
322
|
};
|
|
@@ -653,7 +363,8 @@ var resolveKlineRetryDelayMs = (res, attempt) => {
|
|
|
653
363
|
);
|
|
654
364
|
return backoffMs + jitterMs;
|
|
655
365
|
};
|
|
656
|
-
var ByBitConnectorCreator = async (config) => {
|
|
366
|
+
var ByBitConnectorCreator = async (config, runtime) => {
|
|
367
|
+
const logger = getConnectorLogger(runtime);
|
|
657
368
|
let state = {};
|
|
658
369
|
const universe = resolveConnectorUniverse(
|
|
659
370
|
BYBIT_CAPABILITIES,
|
|
@@ -664,11 +375,11 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
664
375
|
const positionSnapshotCache = /* @__PURE__ */ new Map();
|
|
665
376
|
const inflightPositionSnapshots = /* @__PURE__ */ new Map();
|
|
666
377
|
const getPublicClient = async () => {
|
|
667
|
-
publicClientPromise ??= getClient(config, "public");
|
|
378
|
+
publicClientPromise ??= getClient(config, "public", runtime);
|
|
668
379
|
return publicClientPromise;
|
|
669
380
|
};
|
|
670
381
|
const getPrivateClient = async () => {
|
|
671
|
-
privateClientPromise ??= getClient(config, "private");
|
|
382
|
+
privateClientPromise ??= getClient(config, "private", runtime);
|
|
672
383
|
return privateClientPromise;
|
|
673
384
|
};
|
|
674
385
|
const instrumentCache = /* @__PURE__ */ new Map();
|
|
@@ -796,7 +507,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
796
507
|
silent
|
|
797
508
|
}) => {
|
|
798
509
|
const normalizedStart = round(
|
|
799
|
-
start ||
|
|
510
|
+
start || getTimestamp(PRELOAD_FALLBACK_DAYS),
|
|
800
511
|
0
|
|
801
512
|
);
|
|
802
513
|
const normalizedEnd = round(end || Date.now());
|
|
@@ -818,7 +529,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
818
529
|
if (isKlineRateLimited(kline)) {
|
|
819
530
|
if (attempt < KLINE_RATE_LIMIT_MAX_ATTEMPTS) {
|
|
820
531
|
const waitMs = resolveKlineRetryDelayMs(kline, attempt);
|
|
821
|
-
|
|
532
|
+
logger.log(
|
|
822
533
|
"warn",
|
|
823
534
|
"kline rate limited for %s %s: attempt=%s/%s waitMs=%s",
|
|
824
535
|
symbol,
|
|
@@ -827,13 +538,13 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
827
538
|
KLINE_RATE_LIMIT_MAX_ATTEMPTS,
|
|
828
539
|
waitMs
|
|
829
540
|
);
|
|
830
|
-
await
|
|
541
|
+
await delay(waitMs);
|
|
831
542
|
continue;
|
|
832
543
|
}
|
|
833
544
|
}
|
|
834
545
|
if (!kline?.result?.list) {
|
|
835
546
|
const responseError = typeof kline?.retMsg === "string" && kline.retMsg !== "OK" ? `${kline.retMsg}${typeof kline?.retCode === "number" ? ` (retCode: ${kline.retCode})` : ""}` : typeof kline?.retCode === "number" && kline.retCode !== 0 ? `retCode: ${kline.retCode}` : "";
|
|
836
|
-
|
|
547
|
+
logger.log(
|
|
837
548
|
"error",
|
|
838
549
|
"empty kline.list for %s %s%s",
|
|
839
550
|
symbol,
|
|
@@ -843,7 +554,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
843
554
|
return [];
|
|
844
555
|
}
|
|
845
556
|
if (!silent && (process.stdout.isTTY || process.env.TRADEJS_LOG_KLINE_REQUESTS === "1")) {
|
|
846
|
-
|
|
557
|
+
logger.log(
|
|
847
558
|
"info",
|
|
848
559
|
"%s %s %s %s",
|
|
849
560
|
chalk.yellow(formatUnix2(normalizedEnd)),
|
|
@@ -856,7 +567,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
856
567
|
}
|
|
857
568
|
return [];
|
|
858
569
|
} catch (error) {
|
|
859
|
-
|
|
570
|
+
logger.log(
|
|
860
571
|
"error",
|
|
861
572
|
"request kline: %s %s %s",
|
|
862
573
|
normalizedStart,
|
|
@@ -884,7 +595,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
884
595
|
`bybit getPositionInfo ${symbol}`
|
|
885
596
|
);
|
|
886
597
|
if (positionRes.retCode !== 0) {
|
|
887
|
-
|
|
598
|
+
logger.log(
|
|
888
599
|
getLogLevel(positionRes),
|
|
889
600
|
"position retCode: %s, %s",
|
|
890
601
|
symbol,
|
|
@@ -897,7 +608,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
897
608
|
return null;
|
|
898
609
|
}
|
|
899
610
|
const position = positions[0];
|
|
900
|
-
|
|
611
|
+
logger.log(
|
|
901
612
|
"debug",
|
|
902
613
|
"position: %s %s qty=%s price=%s",
|
|
903
614
|
position.symbol,
|
|
@@ -909,7 +620,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
909
620
|
...position
|
|
910
621
|
};
|
|
911
622
|
} catch (error) {
|
|
912
|
-
|
|
623
|
+
logger.log("error", "getPositionSnapshot failed: %s %s", symbol, error);
|
|
913
624
|
return null;
|
|
914
625
|
}
|
|
915
626
|
};
|
|
@@ -948,7 +659,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
948
659
|
const meta = await getSymbolMeta(marketDataClient, symbol);
|
|
949
660
|
const positionQty = qty ?? (await getPositionSnapshot(symbol))?.qty ?? 0;
|
|
950
661
|
if (!Number.isFinite(positionQty) || positionQty <= 0) {
|
|
951
|
-
|
|
662
|
+
logger.log(
|
|
952
663
|
"warn",
|
|
953
664
|
"setTakeProfits: missing position qty: %s",
|
|
954
665
|
toJson({ symbol, qty, positionQty, takeProfits }, true)
|
|
@@ -963,7 +674,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
963
674
|
meta
|
|
964
675
|
);
|
|
965
676
|
if (!tpSizeNum || tpSizeNum < meta.minOrderQty) {
|
|
966
|
-
|
|
677
|
+
logger.log(
|
|
967
678
|
"warn",
|
|
968
679
|
"tp skipped: size too small %s",
|
|
969
680
|
toJson(
|
|
@@ -990,7 +701,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
990
701
|
positionIdx: 0
|
|
991
702
|
});
|
|
992
703
|
if (isTradingStopNotModified(tpRes)) {
|
|
993
|
-
|
|
704
|
+
logger.log(
|
|
994
705
|
"debug",
|
|
995
706
|
"tp unchanged: %s %s price=%s rate=%s",
|
|
996
707
|
symbol,
|
|
@@ -999,7 +710,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
999
710
|
tp.rate
|
|
1000
711
|
);
|
|
1001
712
|
} else if (tpRes.retCode === 0) {
|
|
1002
|
-
|
|
713
|
+
logger.log(
|
|
1003
714
|
"info",
|
|
1004
715
|
"tp updated: %s %s price=%s rate=%s",
|
|
1005
716
|
symbol,
|
|
@@ -1008,7 +719,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1008
719
|
tp.rate
|
|
1009
720
|
);
|
|
1010
721
|
} else {
|
|
1011
|
-
|
|
722
|
+
logger.log(
|
|
1012
723
|
"error",
|
|
1013
724
|
"tp failed: %s %s price=%s rate=%s %s",
|
|
1014
725
|
symbol,
|
|
@@ -1053,7 +764,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1053
764
|
positionIdx: 0
|
|
1054
765
|
});
|
|
1055
766
|
if (isTradingStopNotModified(slRes)) {
|
|
1056
|
-
|
|
767
|
+
logger.log(
|
|
1057
768
|
"debug",
|
|
1058
769
|
"sl unchanged: %s %s stopLoss=%s",
|
|
1059
770
|
symbol,
|
|
@@ -1061,7 +772,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1061
772
|
slNormalized.priceStr
|
|
1062
773
|
);
|
|
1063
774
|
} else if (slRes.retCode === 0) {
|
|
1064
|
-
|
|
775
|
+
logger.log(
|
|
1065
776
|
"info",
|
|
1066
777
|
"sl updated: %s %s stopLoss=%s",
|
|
1067
778
|
symbol,
|
|
@@ -1069,7 +780,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1069
780
|
slNormalized.priceStr
|
|
1070
781
|
);
|
|
1071
782
|
} else {
|
|
1072
|
-
|
|
783
|
+
logger.log(
|
|
1073
784
|
"error",
|
|
1074
785
|
"sl failed: %s %s stopLoss=%s %s",
|
|
1075
786
|
symbol,
|
|
@@ -1090,7 +801,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1090
801
|
setState: async (newState) => {
|
|
1091
802
|
state = { ...state, ...newState };
|
|
1092
803
|
},
|
|
1093
|
-
kline:
|
|
804
|
+
kline: decorateConnectorKline(runtime, {
|
|
1094
805
|
provider: "bybit",
|
|
1095
806
|
request,
|
|
1096
807
|
intervalToMinutes: intervalToMinutes3,
|
|
@@ -1107,7 +818,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1107
818
|
settleCoin: "USDT"
|
|
1108
819
|
});
|
|
1109
820
|
if (positionRes.retCode !== 0) {
|
|
1110
|
-
|
|
821
|
+
logger.log(
|
|
1111
822
|
getLogLevel(positionRes),
|
|
1112
823
|
"positions retCode: %s, %s",
|
|
1113
824
|
positionRes.retCode
|
|
@@ -1130,7 +841,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1130
841
|
settleCoin: "USDT"
|
|
1131
842
|
});
|
|
1132
843
|
if (positionRes.retCode !== 0) {
|
|
1133
|
-
|
|
844
|
+
logger.log(
|
|
1134
845
|
getLogLevel(positionRes),
|
|
1135
846
|
"positions pnl retCode: %s, %s",
|
|
1136
847
|
positionRes.retCode
|
|
@@ -1190,7 +901,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1190
901
|
...cursor ? { cursor } : {}
|
|
1191
902
|
});
|
|
1192
903
|
if (response.retCode !== 0) {
|
|
1193
|
-
|
|
904
|
+
logger.log(
|
|
1194
905
|
"error",
|
|
1195
906
|
"closedPnl retCode: %s, %s",
|
|
1196
907
|
response.retCode,
|
|
@@ -1212,7 +923,8 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1212
923
|
client,
|
|
1213
924
|
startTime,
|
|
1214
925
|
endTime,
|
|
1215
|
-
symbol
|
|
926
|
+
symbol,
|
|
927
|
+
logger
|
|
1216
928
|
});
|
|
1217
929
|
return closedPnlRows.map((item) => {
|
|
1218
930
|
const qty = Number(item.qty ?? item.closedSize ?? Number.NaN);
|
|
@@ -1287,7 +999,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1287
999
|
...cursor ? { cursor } : {}
|
|
1288
1000
|
});
|
|
1289
1001
|
if (response.retCode !== 0) {
|
|
1290
|
-
|
|
1002
|
+
logger.log(
|
|
1291
1003
|
"error",
|
|
1292
1004
|
"entryExecutions retCode: %s, %s",
|
|
1293
1005
|
response.retCode,
|
|
@@ -1309,7 +1021,8 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1309
1021
|
client,
|
|
1310
1022
|
startTime,
|
|
1311
1023
|
endTime,
|
|
1312
|
-
symbol
|
|
1024
|
+
symbol,
|
|
1025
|
+
logger
|
|
1313
1026
|
});
|
|
1314
1027
|
return executionRows.map((item) => {
|
|
1315
1028
|
const qty = Number(item.execQty ?? item.orderQty ?? Number.NaN);
|
|
@@ -1371,7 +1084,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1371
1084
|
if (signal) {
|
|
1372
1085
|
signal.orderFailureReason = failureReason;
|
|
1373
1086
|
}
|
|
1374
|
-
|
|
1087
|
+
logger.log(
|
|
1375
1088
|
"warn",
|
|
1376
1089
|
"placeOrder: rejected position increase: %s",
|
|
1377
1090
|
toJson(
|
|
@@ -1396,7 +1109,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1396
1109
|
signal.orderValue = normalizedQty.qtyNum * price;
|
|
1397
1110
|
signal.orderFailureReason = "QTY_BELOW_MIN_ORDER";
|
|
1398
1111
|
}
|
|
1399
|
-
|
|
1112
|
+
logger.log(
|
|
1400
1113
|
"warn",
|
|
1401
1114
|
"placeOrder: rejected qty below minOrderQty: %s",
|
|
1402
1115
|
toJson(
|
|
@@ -1418,7 +1131,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1418
1131
|
signal.orderValue = orderQty * price;
|
|
1419
1132
|
}
|
|
1420
1133
|
const entryNormalized = isLimit ? normalizePrice(price, "ENTRY", meta) : void 0;
|
|
1421
|
-
|
|
1134
|
+
logger.log(
|
|
1422
1135
|
"info",
|
|
1423
1136
|
"placeOrder: %s",
|
|
1424
1137
|
toJson(
|
|
@@ -1451,7 +1164,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1451
1164
|
orderFilter: "Order",
|
|
1452
1165
|
orderLinkId: typeof orderId === "string" && orderId.trim() ? orderId : void 0
|
|
1453
1166
|
});
|
|
1454
|
-
|
|
1167
|
+
logger.log(
|
|
1455
1168
|
getLogLevel(orderRes),
|
|
1456
1169
|
"placeOrder:response: %s",
|
|
1457
1170
|
toJson(orderRes, true)
|
|
@@ -1484,7 +1197,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1484
1197
|
qty: "0",
|
|
1485
1198
|
reduceOnly: true
|
|
1486
1199
|
});
|
|
1487
|
-
|
|
1200
|
+
logger.log(
|
|
1488
1201
|
getLogLevel(closeRes),
|
|
1489
1202
|
"closePosition: %s, %s, %s",
|
|
1490
1203
|
symbol,
|
|
@@ -1595,7 +1308,6 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1595
1308
|
};
|
|
1596
1309
|
|
|
1597
1310
|
// src/Binance/index.ts
|
|
1598
|
-
import { fetchWithRetry } from "@tradejs/infra/http";
|
|
1599
1311
|
import {
|
|
1600
1312
|
resolveConnectorUniverse as resolveConnectorUniverse2
|
|
1601
1313
|
} from "@tradejs/types";
|
|
@@ -1605,6 +1317,7 @@ var DEFAULT_BINANCE_PUBLIC_API_URL = "https://data-api.binance.vision";
|
|
|
1605
1317
|
var getBinancePublicApiUrl = () => process.env.BINANCE_BASE_URL?.trim() || DEFAULT_BINANCE_PUBLIC_API_URL;
|
|
1606
1318
|
|
|
1607
1319
|
// src/Binance/index.ts
|
|
1320
|
+
import { fetchWithRetry } from "@tradejs/core/http";
|
|
1608
1321
|
var INTERVAL_MAP = {
|
|
1609
1322
|
"1": "1m",
|
|
1610
1323
|
"3": "3m",
|
|
@@ -1651,7 +1364,7 @@ var capabilities = {
|
|
|
1651
1364
|
supportedUniverses: ["crypto"],
|
|
1652
1365
|
defaultUniverse: "crypto"
|
|
1653
1366
|
};
|
|
1654
|
-
var BinanceConnectorCreator = async (config) => {
|
|
1367
|
+
var BinanceConnectorCreator = async (config, runtime) => {
|
|
1655
1368
|
let state = {};
|
|
1656
1369
|
const universe = resolveConnectorUniverse2(capabilities, config.universe);
|
|
1657
1370
|
const requestKline = async ({
|
|
@@ -1779,7 +1492,7 @@ var BinanceConnectorCreator = async (config) => {
|
|
|
1779
1492
|
setState: async (newState) => {
|
|
1780
1493
|
state = { ...state, ...newState };
|
|
1781
1494
|
},
|
|
1782
|
-
kline:
|
|
1495
|
+
kline: decorateConnectorKline(runtime, {
|
|
1783
1496
|
provider: "binance",
|
|
1784
1497
|
request: requestKline,
|
|
1785
1498
|
intervalToMinutes
|
|
@@ -1874,10 +1587,10 @@ var BinanceConnectorCreator = async (config) => {
|
|
|
1874
1587
|
};
|
|
1875
1588
|
|
|
1876
1589
|
// src/Coinbase/index.ts
|
|
1877
|
-
import { fetchWithRetry as fetchWithRetry2 } from "@tradejs/infra/http";
|
|
1878
1590
|
import {
|
|
1879
1591
|
resolveConnectorUniverse as resolveConnectorUniverse3
|
|
1880
1592
|
} from "@tradejs/types";
|
|
1593
|
+
import { fetchWithRetry as fetchWithRetry2 } from "@tradejs/core/http";
|
|
1881
1594
|
var INTERVAL_MS2 = {
|
|
1882
1595
|
"1": 6e4,
|
|
1883
1596
|
"3": 18e4,
|
|
@@ -1944,7 +1657,7 @@ var capabilities2 = {
|
|
|
1944
1657
|
supportedUniverses: ["crypto"],
|
|
1945
1658
|
defaultUniverse: "crypto"
|
|
1946
1659
|
};
|
|
1947
|
-
var CoinbaseConnectorCreator = async (config) => {
|
|
1660
|
+
var CoinbaseConnectorCreator = async (config, runtime) => {
|
|
1948
1661
|
let state = {};
|
|
1949
1662
|
const universe = resolveConnectorUniverse3(capabilities2, config.universe);
|
|
1950
1663
|
const requestKline = async ({
|
|
@@ -2072,7 +1785,7 @@ var CoinbaseConnectorCreator = async (config) => {
|
|
|
2072
1785
|
setState: async (newState) => {
|
|
2073
1786
|
state = { ...state, ...newState };
|
|
2074
1787
|
},
|
|
2075
|
-
kline:
|
|
1788
|
+
kline: decorateConnectorKline(runtime, {
|
|
2076
1789
|
provider: "coinbase",
|
|
2077
1790
|
request: requestKline,
|
|
2078
1791
|
intervalToMinutes: intervalToMinutes2
|
|
@@ -2092,7 +1805,7 @@ var CoinbaseConnectorCreator = async (config) => {
|
|
|
2092
1805
|
};
|
|
2093
1806
|
|
|
2094
1807
|
// src/marketData/spotKlineProviders.ts
|
|
2095
|
-
import { fetchWithRetry as fetchWithRetry3 } from "@tradejs/
|
|
1808
|
+
import { fetchWithRetry as fetchWithRetry3 } from "@tradejs/core/http";
|
|
2096
1809
|
var toIntervalToken = (interval) => interval === "1h" ? "1h" : "15m";
|
|
2097
1810
|
var mapBinanceKline = (payload) => payload.map((item) => {
|
|
2098
1811
|
if (!Array.isArray(item)) return null;
|
|
@@ -2197,8 +1910,6 @@ var spotKlineProviders = {
|
|
|
2197
1910
|
// src/ByBit/klineStream.ts
|
|
2198
1911
|
import { WebsocketClient } from "bybit-api";
|
|
2199
1912
|
import { formatUnix as formatUnix3 } from "@tradejs/core/time";
|
|
2200
|
-
import { logger as logger4 } from "@tradejs/infra/logger";
|
|
2201
|
-
import { resolveTradingAccount as resolveTradingAccount2 } from "@tradejs/infra/tradingAccounts";
|
|
2202
1913
|
var CATEGORY = "linear";
|
|
2203
1914
|
var SUBSCRIPTION_BATCH_SIZE = 100;
|
|
2204
1915
|
var KLINE_TOPIC_PATTERN = /^kline\.([^.]+)\.(.+)$/;
|
|
@@ -2255,22 +1966,23 @@ var parseBybitKlineEvent = (value, receivedAt = Date.now()) => {
|
|
|
2255
1966
|
};
|
|
2256
1967
|
var createBybitKlineStreamWithClient = ({
|
|
2257
1968
|
client,
|
|
2258
|
-
onEvent
|
|
1969
|
+
onEvent,
|
|
1970
|
+
logger = getConnectorLogger()
|
|
2259
1971
|
}) => {
|
|
2260
1972
|
let topics = /* @__PURE__ */ new Set();
|
|
2261
1973
|
let closed = false;
|
|
2262
1974
|
client.on("update", (value) => {
|
|
2263
1975
|
for (const event of parseBybitKlineEvent(value)) {
|
|
2264
1976
|
void Promise.resolve(onEvent(event)).catch((error) => {
|
|
2265
|
-
|
|
1977
|
+
logger.error("Bybit kline stream handler failed: %s", String(error));
|
|
2266
1978
|
});
|
|
2267
1979
|
}
|
|
2268
1980
|
});
|
|
2269
1981
|
client.on("reconnected", ({ wsKey }) => {
|
|
2270
|
-
|
|
1982
|
+
logger.info("Bybit kline stream reconnected: %s", wsKey);
|
|
2271
1983
|
});
|
|
2272
1984
|
client.on("exception", (error) => {
|
|
2273
|
-
|
|
1985
|
+
logger.error("Bybit kline stream exception: %s", String(error));
|
|
2274
1986
|
});
|
|
2275
1987
|
return {
|
|
2276
1988
|
setSubscriptions: (symbols, interval) => {
|
|
@@ -2284,16 +1996,16 @@ var createBybitKlineStreamWithClient = ({
|
|
|
2284
1996
|
const removed = [...topics].filter((topic) => !nextTopics.has(topic));
|
|
2285
1997
|
for (const batch of chunk(removed, SUBSCRIPTION_BATCH_SIZE)) {
|
|
2286
1998
|
void Promise.all(client.unsubscribeV5(batch, CATEGORY)).catch(
|
|
2287
|
-
(error) =>
|
|
1999
|
+
(error) => logger.error("Bybit kline unsubscribe failed: %s", String(error))
|
|
2288
2000
|
);
|
|
2289
2001
|
}
|
|
2290
2002
|
for (const batch of chunk(added, SUBSCRIPTION_BATCH_SIZE)) {
|
|
2291
2003
|
void Promise.all(client.subscribeV5(batch, CATEGORY)).catch(
|
|
2292
|
-
(error) =>
|
|
2004
|
+
(error) => logger.error("Bybit kline subscribe failed: %s", String(error))
|
|
2293
2005
|
);
|
|
2294
2006
|
}
|
|
2295
2007
|
topics = nextTopics;
|
|
2296
|
-
|
|
2008
|
+
logger.info(
|
|
2297
2009
|
"Bybit kline stream subscriptions: topics=%s added=%s removed=%s",
|
|
2298
2010
|
topics.size,
|
|
2299
2011
|
added.length,
|
|
@@ -2314,9 +2026,11 @@ var createBybitKlineStreamWithClient = ({
|
|
|
2314
2026
|
};
|
|
2315
2027
|
var createBybitKlineStream = async ({
|
|
2316
2028
|
config,
|
|
2317
|
-
onEvent
|
|
2029
|
+
onEvent,
|
|
2030
|
+
runtime
|
|
2318
2031
|
}) => {
|
|
2319
|
-
const
|
|
2032
|
+
const resolveTradingAccount = getConnectorAccountResolver(runtime);
|
|
2033
|
+
const account = config.accountId ? await resolveTradingAccount({
|
|
2320
2034
|
userName: config.userName,
|
|
2321
2035
|
accountId: config.accountId,
|
|
2322
2036
|
provider: "bybit",
|
|
@@ -2329,7 +2043,11 @@ var createBybitKlineStream = async ({
|
|
|
2329
2043
|
Number(process.env.BYBIT_WS_RECONNECT_TIMEOUT_MS ?? 1e3)
|
|
2330
2044
|
)
|
|
2331
2045
|
});
|
|
2332
|
-
return createBybitKlineStreamWithClient({
|
|
2046
|
+
return createBybitKlineStreamWithClient({
|
|
2047
|
+
client,
|
|
2048
|
+
onEvent,
|
|
2049
|
+
logger: getConnectorLogger(runtime)
|
|
2050
|
+
});
|
|
2333
2051
|
};
|
|
2334
2052
|
|
|
2335
2053
|
// src/marketData/providers/binanceCoinbaseSpread.ts
|
|
@@ -2392,7 +2110,7 @@ var binanceCoinbaseSpreadProvider = {
|
|
|
2392
2110
|
};
|
|
2393
2111
|
|
|
2394
2112
|
// src/marketData/providers/coinalyze.ts
|
|
2395
|
-
import { delay as
|
|
2113
|
+
import { delay as delay2 } from "@tradejs/core/async";
|
|
2396
2114
|
import {
|
|
2397
2115
|
coinalyzePointsToRows,
|
|
2398
2116
|
mergeCoinalyzeMetrics
|
|
@@ -2465,7 +2183,7 @@ var fetchCoinalyzeSeries = async (params) => {
|
|
|
2465
2183
|
lastRequestTs + coinalyzeMinRequestDelayMs - now
|
|
2466
2184
|
);
|
|
2467
2185
|
if (waitMs > 0) {
|
|
2468
|
-
await
|
|
2186
|
+
await delay2(waitMs);
|
|
2469
2187
|
}
|
|
2470
2188
|
lastRequestTs = Date.now();
|
|
2471
2189
|
const response = await fetch(url.toString(), { headers });
|
|
@@ -2479,7 +2197,7 @@ var fetchCoinalyzeSeries = async (params) => {
|
|
|
2479
2197
|
const transient = response.status === 429 || response.status >= 500;
|
|
2480
2198
|
if (attempt < coinalyzeMaxRetries && transient) {
|
|
2481
2199
|
const backoffMs = Math.min(1e4, 750 * 2 ** attempt);
|
|
2482
|
-
await
|
|
2200
|
+
await delay2(retryAfterMs ?? backoffMs);
|
|
2483
2201
|
continue;
|
|
2484
2202
|
}
|
|
2485
2203
|
throw new Error(`Coinalyze ${endpoint} ${response.status}: ${text}`);
|