@tradejs/connectors 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.
- package/README.md +2 -0
- package/dist/index.d.mts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +114 -381
- package/dist/index.mjs +96 -368
- package/package.json +7 -5
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,41 @@
|
|
|
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
|
|
28
|
+
var getApiRegion = () => {
|
|
29
|
+
const apiRegion = process.env.TRADEJS_BYBIT_API_REGION?.trim();
|
|
30
|
+
return apiRegion ? apiRegion : void 0;
|
|
31
|
+
};
|
|
32
|
+
var getApiRegionOptions = () => {
|
|
33
|
+
const apiRegion = getApiRegion();
|
|
34
|
+
return apiRegion ? { apiRegion } : {};
|
|
35
|
+
};
|
|
36
|
+
var getClient = async (config, access = "private", runtime) => {
|
|
37
|
+
const logger = getConnectorLogger(runtime);
|
|
38
|
+
const resolveTradingAccount = getConnectorAccountResolver(runtime);
|
|
18
39
|
const account = access === "public" && !config.accountId ? null : await resolveTradingAccount({
|
|
19
40
|
userName: config.userName,
|
|
20
41
|
accountId: config.accountId,
|
|
@@ -24,6 +45,7 @@ var getClient = async (config, access = "private") => {
|
|
|
24
45
|
const useTestnet = account?.environment === "testnet";
|
|
25
46
|
if (access === "public") {
|
|
26
47
|
return new RestClientV5({
|
|
48
|
+
...getApiRegionOptions(),
|
|
27
49
|
parseAPIRateLimits: true,
|
|
28
50
|
testnet: useTestnet
|
|
29
51
|
});
|
|
@@ -42,6 +64,7 @@ var getClient = async (config, access = "private") => {
|
|
|
42
64
|
return null;
|
|
43
65
|
}
|
|
44
66
|
const client = new RestClientV5({
|
|
67
|
+
...getApiRegionOptions(),
|
|
45
68
|
key: account.apiKey,
|
|
46
69
|
secret: account.apiSecret,
|
|
47
70
|
parseAPIRateLimits: true,
|
|
@@ -54,310 +77,6 @@ var getClient = async (config, access = "private") => {
|
|
|
54
77
|
return client;
|
|
55
78
|
};
|
|
56
79
|
|
|
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
80
|
// src/ByBit/utils.ts
|
|
362
81
|
import { formatUnix } from "@tradejs/core/time";
|
|
363
82
|
var BYBIT_CATEGORY = "linear";
|
|
@@ -555,7 +274,8 @@ var loadFundingFeeRows = async ({
|
|
|
555
274
|
client,
|
|
556
275
|
startTime,
|
|
557
276
|
endTime,
|
|
558
|
-
symbol
|
|
277
|
+
symbol,
|
|
278
|
+
logger
|
|
559
279
|
}) => {
|
|
560
280
|
if (typeof client.getTransactionLog !== "function") {
|
|
561
281
|
return [];
|
|
@@ -574,7 +294,7 @@ var loadFundingFeeRows = async ({
|
|
|
574
294
|
...cursor ? { cursor } : {}
|
|
575
295
|
});
|
|
576
296
|
if (response?.retCode !== 0) {
|
|
577
|
-
|
|
297
|
+
logger.log(
|
|
578
298
|
"debug",
|
|
579
299
|
"funding transaction log retCode: %s, %s",
|
|
580
300
|
response?.retCode,
|
|
@@ -606,7 +326,7 @@ var loadFundingFeeRows = async ({
|
|
|
606
326
|
}
|
|
607
327
|
return rows;
|
|
608
328
|
} catch (error) {
|
|
609
|
-
|
|
329
|
+
logger.log("debug", "funding transaction log failed: %s", error);
|
|
610
330
|
return [];
|
|
611
331
|
}
|
|
612
332
|
};
|
|
@@ -653,7 +373,8 @@ var resolveKlineRetryDelayMs = (res, attempt) => {
|
|
|
653
373
|
);
|
|
654
374
|
return backoffMs + jitterMs;
|
|
655
375
|
};
|
|
656
|
-
var ByBitConnectorCreator = async (config) => {
|
|
376
|
+
var ByBitConnectorCreator = async (config, runtime) => {
|
|
377
|
+
const logger = getConnectorLogger(runtime);
|
|
657
378
|
let state = {};
|
|
658
379
|
const universe = resolveConnectorUniverse(
|
|
659
380
|
BYBIT_CAPABILITIES,
|
|
@@ -664,11 +385,11 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
664
385
|
const positionSnapshotCache = /* @__PURE__ */ new Map();
|
|
665
386
|
const inflightPositionSnapshots = /* @__PURE__ */ new Map();
|
|
666
387
|
const getPublicClient = async () => {
|
|
667
|
-
publicClientPromise ??= getClient(config, "public");
|
|
388
|
+
publicClientPromise ??= getClient(config, "public", runtime);
|
|
668
389
|
return publicClientPromise;
|
|
669
390
|
};
|
|
670
391
|
const getPrivateClient = async () => {
|
|
671
|
-
privateClientPromise ??= getClient(config, "private");
|
|
392
|
+
privateClientPromise ??= getClient(config, "private", runtime);
|
|
672
393
|
return privateClientPromise;
|
|
673
394
|
};
|
|
674
395
|
const instrumentCache = /* @__PURE__ */ new Map();
|
|
@@ -796,7 +517,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
796
517
|
silent
|
|
797
518
|
}) => {
|
|
798
519
|
const normalizedStart = round(
|
|
799
|
-
start ||
|
|
520
|
+
start || getTimestamp(PRELOAD_FALLBACK_DAYS),
|
|
800
521
|
0
|
|
801
522
|
);
|
|
802
523
|
const normalizedEnd = round(end || Date.now());
|
|
@@ -818,7 +539,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
818
539
|
if (isKlineRateLimited(kline)) {
|
|
819
540
|
if (attempt < KLINE_RATE_LIMIT_MAX_ATTEMPTS) {
|
|
820
541
|
const waitMs = resolveKlineRetryDelayMs(kline, attempt);
|
|
821
|
-
|
|
542
|
+
logger.log(
|
|
822
543
|
"warn",
|
|
823
544
|
"kline rate limited for %s %s: attempt=%s/%s waitMs=%s",
|
|
824
545
|
symbol,
|
|
@@ -827,13 +548,13 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
827
548
|
KLINE_RATE_LIMIT_MAX_ATTEMPTS,
|
|
828
549
|
waitMs
|
|
829
550
|
);
|
|
830
|
-
await
|
|
551
|
+
await delay(waitMs);
|
|
831
552
|
continue;
|
|
832
553
|
}
|
|
833
554
|
}
|
|
834
555
|
if (!kline?.result?.list) {
|
|
835
556
|
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
|
-
|
|
557
|
+
logger.log(
|
|
837
558
|
"error",
|
|
838
559
|
"empty kline.list for %s %s%s",
|
|
839
560
|
symbol,
|
|
@@ -843,7 +564,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
843
564
|
return [];
|
|
844
565
|
}
|
|
845
566
|
if (!silent && (process.stdout.isTTY || process.env.TRADEJS_LOG_KLINE_REQUESTS === "1")) {
|
|
846
|
-
|
|
567
|
+
logger.log(
|
|
847
568
|
"info",
|
|
848
569
|
"%s %s %s %s",
|
|
849
570
|
chalk.yellow(formatUnix2(normalizedEnd)),
|
|
@@ -856,7 +577,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
856
577
|
}
|
|
857
578
|
return [];
|
|
858
579
|
} catch (error) {
|
|
859
|
-
|
|
580
|
+
logger.log(
|
|
860
581
|
"error",
|
|
861
582
|
"request kline: %s %s %s",
|
|
862
583
|
normalizedStart,
|
|
@@ -884,7 +605,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
884
605
|
`bybit getPositionInfo ${symbol}`
|
|
885
606
|
);
|
|
886
607
|
if (positionRes.retCode !== 0) {
|
|
887
|
-
|
|
608
|
+
logger.log(
|
|
888
609
|
getLogLevel(positionRes),
|
|
889
610
|
"position retCode: %s, %s",
|
|
890
611
|
symbol,
|
|
@@ -897,7 +618,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
897
618
|
return null;
|
|
898
619
|
}
|
|
899
620
|
const position = positions[0];
|
|
900
|
-
|
|
621
|
+
logger.log(
|
|
901
622
|
"debug",
|
|
902
623
|
"position: %s %s qty=%s price=%s",
|
|
903
624
|
position.symbol,
|
|
@@ -909,7 +630,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
909
630
|
...position
|
|
910
631
|
};
|
|
911
632
|
} catch (error) {
|
|
912
|
-
|
|
633
|
+
logger.log("error", "getPositionSnapshot failed: %s %s", symbol, error);
|
|
913
634
|
return null;
|
|
914
635
|
}
|
|
915
636
|
};
|
|
@@ -948,7 +669,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
948
669
|
const meta = await getSymbolMeta(marketDataClient, symbol);
|
|
949
670
|
const positionQty = qty ?? (await getPositionSnapshot(symbol))?.qty ?? 0;
|
|
950
671
|
if (!Number.isFinite(positionQty) || positionQty <= 0) {
|
|
951
|
-
|
|
672
|
+
logger.log(
|
|
952
673
|
"warn",
|
|
953
674
|
"setTakeProfits: missing position qty: %s",
|
|
954
675
|
toJson({ symbol, qty, positionQty, takeProfits }, true)
|
|
@@ -963,7 +684,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
963
684
|
meta
|
|
964
685
|
);
|
|
965
686
|
if (!tpSizeNum || tpSizeNum < meta.minOrderQty) {
|
|
966
|
-
|
|
687
|
+
logger.log(
|
|
967
688
|
"warn",
|
|
968
689
|
"tp skipped: size too small %s",
|
|
969
690
|
toJson(
|
|
@@ -990,7 +711,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
990
711
|
positionIdx: 0
|
|
991
712
|
});
|
|
992
713
|
if (isTradingStopNotModified(tpRes)) {
|
|
993
|
-
|
|
714
|
+
logger.log(
|
|
994
715
|
"debug",
|
|
995
716
|
"tp unchanged: %s %s price=%s rate=%s",
|
|
996
717
|
symbol,
|
|
@@ -999,7 +720,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
999
720
|
tp.rate
|
|
1000
721
|
);
|
|
1001
722
|
} else if (tpRes.retCode === 0) {
|
|
1002
|
-
|
|
723
|
+
logger.log(
|
|
1003
724
|
"info",
|
|
1004
725
|
"tp updated: %s %s price=%s rate=%s",
|
|
1005
726
|
symbol,
|
|
@@ -1008,7 +729,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1008
729
|
tp.rate
|
|
1009
730
|
);
|
|
1010
731
|
} else {
|
|
1011
|
-
|
|
732
|
+
logger.log(
|
|
1012
733
|
"error",
|
|
1013
734
|
"tp failed: %s %s price=%s rate=%s %s",
|
|
1014
735
|
symbol,
|
|
@@ -1053,7 +774,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1053
774
|
positionIdx: 0
|
|
1054
775
|
});
|
|
1055
776
|
if (isTradingStopNotModified(slRes)) {
|
|
1056
|
-
|
|
777
|
+
logger.log(
|
|
1057
778
|
"debug",
|
|
1058
779
|
"sl unchanged: %s %s stopLoss=%s",
|
|
1059
780
|
symbol,
|
|
@@ -1061,7 +782,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1061
782
|
slNormalized.priceStr
|
|
1062
783
|
);
|
|
1063
784
|
} else if (slRes.retCode === 0) {
|
|
1064
|
-
|
|
785
|
+
logger.log(
|
|
1065
786
|
"info",
|
|
1066
787
|
"sl updated: %s %s stopLoss=%s",
|
|
1067
788
|
symbol,
|
|
@@ -1069,7 +790,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1069
790
|
slNormalized.priceStr
|
|
1070
791
|
);
|
|
1071
792
|
} else {
|
|
1072
|
-
|
|
793
|
+
logger.log(
|
|
1073
794
|
"error",
|
|
1074
795
|
"sl failed: %s %s stopLoss=%s %s",
|
|
1075
796
|
symbol,
|
|
@@ -1090,7 +811,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1090
811
|
setState: async (newState) => {
|
|
1091
812
|
state = { ...state, ...newState };
|
|
1092
813
|
},
|
|
1093
|
-
kline:
|
|
814
|
+
kline: decorateConnectorKline(runtime, {
|
|
1094
815
|
provider: "bybit",
|
|
1095
816
|
request,
|
|
1096
817
|
intervalToMinutes: intervalToMinutes3,
|
|
@@ -1107,7 +828,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1107
828
|
settleCoin: "USDT"
|
|
1108
829
|
});
|
|
1109
830
|
if (positionRes.retCode !== 0) {
|
|
1110
|
-
|
|
831
|
+
logger.log(
|
|
1111
832
|
getLogLevel(positionRes),
|
|
1112
833
|
"positions retCode: %s, %s",
|
|
1113
834
|
positionRes.retCode
|
|
@@ -1130,7 +851,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1130
851
|
settleCoin: "USDT"
|
|
1131
852
|
});
|
|
1132
853
|
if (positionRes.retCode !== 0) {
|
|
1133
|
-
|
|
854
|
+
logger.log(
|
|
1134
855
|
getLogLevel(positionRes),
|
|
1135
856
|
"positions pnl retCode: %s, %s",
|
|
1136
857
|
positionRes.retCode
|
|
@@ -1190,7 +911,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1190
911
|
...cursor ? { cursor } : {}
|
|
1191
912
|
});
|
|
1192
913
|
if (response.retCode !== 0) {
|
|
1193
|
-
|
|
914
|
+
logger.log(
|
|
1194
915
|
"error",
|
|
1195
916
|
"closedPnl retCode: %s, %s",
|
|
1196
917
|
response.retCode,
|
|
@@ -1212,7 +933,8 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1212
933
|
client,
|
|
1213
934
|
startTime,
|
|
1214
935
|
endTime,
|
|
1215
|
-
symbol
|
|
936
|
+
symbol,
|
|
937
|
+
logger
|
|
1216
938
|
});
|
|
1217
939
|
return closedPnlRows.map((item) => {
|
|
1218
940
|
const qty = Number(item.qty ?? item.closedSize ?? Number.NaN);
|
|
@@ -1287,7 +1009,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1287
1009
|
...cursor ? { cursor } : {}
|
|
1288
1010
|
});
|
|
1289
1011
|
if (response.retCode !== 0) {
|
|
1290
|
-
|
|
1012
|
+
logger.log(
|
|
1291
1013
|
"error",
|
|
1292
1014
|
"entryExecutions retCode: %s, %s",
|
|
1293
1015
|
response.retCode,
|
|
@@ -1309,7 +1031,8 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1309
1031
|
client,
|
|
1310
1032
|
startTime,
|
|
1311
1033
|
endTime,
|
|
1312
|
-
symbol
|
|
1034
|
+
symbol,
|
|
1035
|
+
logger
|
|
1313
1036
|
});
|
|
1314
1037
|
return executionRows.map((item) => {
|
|
1315
1038
|
const qty = Number(item.execQty ?? item.orderQty ?? Number.NaN);
|
|
@@ -1371,7 +1094,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1371
1094
|
if (signal) {
|
|
1372
1095
|
signal.orderFailureReason = failureReason;
|
|
1373
1096
|
}
|
|
1374
|
-
|
|
1097
|
+
logger.log(
|
|
1375
1098
|
"warn",
|
|
1376
1099
|
"placeOrder: rejected position increase: %s",
|
|
1377
1100
|
toJson(
|
|
@@ -1396,7 +1119,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1396
1119
|
signal.orderValue = normalizedQty.qtyNum * price;
|
|
1397
1120
|
signal.orderFailureReason = "QTY_BELOW_MIN_ORDER";
|
|
1398
1121
|
}
|
|
1399
|
-
|
|
1122
|
+
logger.log(
|
|
1400
1123
|
"warn",
|
|
1401
1124
|
"placeOrder: rejected qty below minOrderQty: %s",
|
|
1402
1125
|
toJson(
|
|
@@ -1418,7 +1141,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1418
1141
|
signal.orderValue = orderQty * price;
|
|
1419
1142
|
}
|
|
1420
1143
|
const entryNormalized = isLimit ? normalizePrice(price, "ENTRY", meta) : void 0;
|
|
1421
|
-
|
|
1144
|
+
logger.log(
|
|
1422
1145
|
"info",
|
|
1423
1146
|
"placeOrder: %s",
|
|
1424
1147
|
toJson(
|
|
@@ -1451,7 +1174,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1451
1174
|
orderFilter: "Order",
|
|
1452
1175
|
orderLinkId: typeof orderId === "string" && orderId.trim() ? orderId : void 0
|
|
1453
1176
|
});
|
|
1454
|
-
|
|
1177
|
+
logger.log(
|
|
1455
1178
|
getLogLevel(orderRes),
|
|
1456
1179
|
"placeOrder:response: %s",
|
|
1457
1180
|
toJson(orderRes, true)
|
|
@@ -1484,7 +1207,7 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1484
1207
|
qty: "0",
|
|
1485
1208
|
reduceOnly: true
|
|
1486
1209
|
});
|
|
1487
|
-
|
|
1210
|
+
logger.log(
|
|
1488
1211
|
getLogLevel(closeRes),
|
|
1489
1212
|
"closePosition: %s, %s, %s",
|
|
1490
1213
|
symbol,
|
|
@@ -1595,7 +1318,6 @@ var ByBitConnectorCreator = async (config) => {
|
|
|
1595
1318
|
};
|
|
1596
1319
|
|
|
1597
1320
|
// src/Binance/index.ts
|
|
1598
|
-
import { fetchWithRetry } from "@tradejs/infra/http";
|
|
1599
1321
|
import {
|
|
1600
1322
|
resolveConnectorUniverse as resolveConnectorUniverse2
|
|
1601
1323
|
} from "@tradejs/types";
|
|
@@ -1605,6 +1327,7 @@ var DEFAULT_BINANCE_PUBLIC_API_URL = "https://data-api.binance.vision";
|
|
|
1605
1327
|
var getBinancePublicApiUrl = () => process.env.BINANCE_BASE_URL?.trim() || DEFAULT_BINANCE_PUBLIC_API_URL;
|
|
1606
1328
|
|
|
1607
1329
|
// src/Binance/index.ts
|
|
1330
|
+
import { fetchWithRetry } from "@tradejs/core/http";
|
|
1608
1331
|
var INTERVAL_MAP = {
|
|
1609
1332
|
"1": "1m",
|
|
1610
1333
|
"3": "3m",
|
|
@@ -1651,7 +1374,7 @@ var capabilities = {
|
|
|
1651
1374
|
supportedUniverses: ["crypto"],
|
|
1652
1375
|
defaultUniverse: "crypto"
|
|
1653
1376
|
};
|
|
1654
|
-
var BinanceConnectorCreator = async (config) => {
|
|
1377
|
+
var BinanceConnectorCreator = async (config, runtime) => {
|
|
1655
1378
|
let state = {};
|
|
1656
1379
|
const universe = resolveConnectorUniverse2(capabilities, config.universe);
|
|
1657
1380
|
const requestKline = async ({
|
|
@@ -1779,7 +1502,7 @@ var BinanceConnectorCreator = async (config) => {
|
|
|
1779
1502
|
setState: async (newState) => {
|
|
1780
1503
|
state = { ...state, ...newState };
|
|
1781
1504
|
},
|
|
1782
|
-
kline:
|
|
1505
|
+
kline: decorateConnectorKline(runtime, {
|
|
1783
1506
|
provider: "binance",
|
|
1784
1507
|
request: requestKline,
|
|
1785
1508
|
intervalToMinutes
|
|
@@ -1874,10 +1597,10 @@ var BinanceConnectorCreator = async (config) => {
|
|
|
1874
1597
|
};
|
|
1875
1598
|
|
|
1876
1599
|
// src/Coinbase/index.ts
|
|
1877
|
-
import { fetchWithRetry as fetchWithRetry2 } from "@tradejs/infra/http";
|
|
1878
1600
|
import {
|
|
1879
1601
|
resolveConnectorUniverse as resolveConnectorUniverse3
|
|
1880
1602
|
} from "@tradejs/types";
|
|
1603
|
+
import { fetchWithRetry as fetchWithRetry2 } from "@tradejs/core/http";
|
|
1881
1604
|
var INTERVAL_MS2 = {
|
|
1882
1605
|
"1": 6e4,
|
|
1883
1606
|
"3": 18e4,
|
|
@@ -1944,7 +1667,7 @@ var capabilities2 = {
|
|
|
1944
1667
|
supportedUniverses: ["crypto"],
|
|
1945
1668
|
defaultUniverse: "crypto"
|
|
1946
1669
|
};
|
|
1947
|
-
var CoinbaseConnectorCreator = async (config) => {
|
|
1670
|
+
var CoinbaseConnectorCreator = async (config, runtime) => {
|
|
1948
1671
|
let state = {};
|
|
1949
1672
|
const universe = resolveConnectorUniverse3(capabilities2, config.universe);
|
|
1950
1673
|
const requestKline = async ({
|
|
@@ -2072,7 +1795,7 @@ var CoinbaseConnectorCreator = async (config) => {
|
|
|
2072
1795
|
setState: async (newState) => {
|
|
2073
1796
|
state = { ...state, ...newState };
|
|
2074
1797
|
},
|
|
2075
|
-
kline:
|
|
1798
|
+
kline: decorateConnectorKline(runtime, {
|
|
2076
1799
|
provider: "coinbase",
|
|
2077
1800
|
request: requestKline,
|
|
2078
1801
|
intervalToMinutes: intervalToMinutes2
|
|
@@ -2092,7 +1815,7 @@ var CoinbaseConnectorCreator = async (config) => {
|
|
|
2092
1815
|
};
|
|
2093
1816
|
|
|
2094
1817
|
// src/marketData/spotKlineProviders.ts
|
|
2095
|
-
import { fetchWithRetry as fetchWithRetry3 } from "@tradejs/
|
|
1818
|
+
import { fetchWithRetry as fetchWithRetry3 } from "@tradejs/core/http";
|
|
2096
1819
|
var toIntervalToken = (interval) => interval === "1h" ? "1h" : "15m";
|
|
2097
1820
|
var mapBinanceKline = (payload) => payload.map((item) => {
|
|
2098
1821
|
if (!Array.isArray(item)) return null;
|
|
@@ -2197,8 +1920,6 @@ var spotKlineProviders = {
|
|
|
2197
1920
|
// src/ByBit/klineStream.ts
|
|
2198
1921
|
import { WebsocketClient } from "bybit-api";
|
|
2199
1922
|
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
1923
|
var CATEGORY = "linear";
|
|
2203
1924
|
var SUBSCRIPTION_BATCH_SIZE = 100;
|
|
2204
1925
|
var KLINE_TOPIC_PATTERN = /^kline\.([^.]+)\.(.+)$/;
|
|
@@ -2255,22 +1976,23 @@ var parseBybitKlineEvent = (value, receivedAt = Date.now()) => {
|
|
|
2255
1976
|
};
|
|
2256
1977
|
var createBybitKlineStreamWithClient = ({
|
|
2257
1978
|
client,
|
|
2258
|
-
onEvent
|
|
1979
|
+
onEvent,
|
|
1980
|
+
logger = getConnectorLogger()
|
|
2259
1981
|
}) => {
|
|
2260
1982
|
let topics = /* @__PURE__ */ new Set();
|
|
2261
1983
|
let closed = false;
|
|
2262
1984
|
client.on("update", (value) => {
|
|
2263
1985
|
for (const event of parseBybitKlineEvent(value)) {
|
|
2264
1986
|
void Promise.resolve(onEvent(event)).catch((error) => {
|
|
2265
|
-
|
|
1987
|
+
logger.error("Bybit kline stream handler failed: %s", String(error));
|
|
2266
1988
|
});
|
|
2267
1989
|
}
|
|
2268
1990
|
});
|
|
2269
1991
|
client.on("reconnected", ({ wsKey }) => {
|
|
2270
|
-
|
|
1992
|
+
logger.info("Bybit kline stream reconnected: %s", wsKey);
|
|
2271
1993
|
});
|
|
2272
1994
|
client.on("exception", (error) => {
|
|
2273
|
-
|
|
1995
|
+
logger.error("Bybit kline stream exception: %s", String(error));
|
|
2274
1996
|
});
|
|
2275
1997
|
return {
|
|
2276
1998
|
setSubscriptions: (symbols, interval) => {
|
|
@@ -2284,16 +2006,16 @@ var createBybitKlineStreamWithClient = ({
|
|
|
2284
2006
|
const removed = [...topics].filter((topic) => !nextTopics.has(topic));
|
|
2285
2007
|
for (const batch of chunk(removed, SUBSCRIPTION_BATCH_SIZE)) {
|
|
2286
2008
|
void Promise.all(client.unsubscribeV5(batch, CATEGORY)).catch(
|
|
2287
|
-
(error) =>
|
|
2009
|
+
(error) => logger.error("Bybit kline unsubscribe failed: %s", String(error))
|
|
2288
2010
|
);
|
|
2289
2011
|
}
|
|
2290
2012
|
for (const batch of chunk(added, SUBSCRIPTION_BATCH_SIZE)) {
|
|
2291
2013
|
void Promise.all(client.subscribeV5(batch, CATEGORY)).catch(
|
|
2292
|
-
(error) =>
|
|
2014
|
+
(error) => logger.error("Bybit kline subscribe failed: %s", String(error))
|
|
2293
2015
|
);
|
|
2294
2016
|
}
|
|
2295
2017
|
topics = nextTopics;
|
|
2296
|
-
|
|
2018
|
+
logger.info(
|
|
2297
2019
|
"Bybit kline stream subscriptions: topics=%s added=%s removed=%s",
|
|
2298
2020
|
topics.size,
|
|
2299
2021
|
added.length,
|
|
@@ -2314,9 +2036,11 @@ var createBybitKlineStreamWithClient = ({
|
|
|
2314
2036
|
};
|
|
2315
2037
|
var createBybitKlineStream = async ({
|
|
2316
2038
|
config,
|
|
2317
|
-
onEvent
|
|
2039
|
+
onEvent,
|
|
2040
|
+
runtime
|
|
2318
2041
|
}) => {
|
|
2319
|
-
const
|
|
2042
|
+
const resolveTradingAccount = getConnectorAccountResolver(runtime);
|
|
2043
|
+
const account = config.accountId ? await resolveTradingAccount({
|
|
2320
2044
|
userName: config.userName,
|
|
2321
2045
|
accountId: config.accountId,
|
|
2322
2046
|
provider: "bybit",
|
|
@@ -2329,7 +2053,11 @@ var createBybitKlineStream = async ({
|
|
|
2329
2053
|
Number(process.env.BYBIT_WS_RECONNECT_TIMEOUT_MS ?? 1e3)
|
|
2330
2054
|
)
|
|
2331
2055
|
});
|
|
2332
|
-
return createBybitKlineStreamWithClient({
|
|
2056
|
+
return createBybitKlineStreamWithClient({
|
|
2057
|
+
client,
|
|
2058
|
+
onEvent,
|
|
2059
|
+
logger: getConnectorLogger(runtime)
|
|
2060
|
+
});
|
|
2333
2061
|
};
|
|
2334
2062
|
|
|
2335
2063
|
// src/marketData/providers/binanceCoinbaseSpread.ts
|
|
@@ -2392,7 +2120,7 @@ var binanceCoinbaseSpreadProvider = {
|
|
|
2392
2120
|
};
|
|
2393
2121
|
|
|
2394
2122
|
// src/marketData/providers/coinalyze.ts
|
|
2395
|
-
import { delay as
|
|
2123
|
+
import { delay as delay2 } from "@tradejs/core/async";
|
|
2396
2124
|
import {
|
|
2397
2125
|
coinalyzePointsToRows,
|
|
2398
2126
|
mergeCoinalyzeMetrics
|
|
@@ -2465,7 +2193,7 @@ var fetchCoinalyzeSeries = async (params) => {
|
|
|
2465
2193
|
lastRequestTs + coinalyzeMinRequestDelayMs - now
|
|
2466
2194
|
);
|
|
2467
2195
|
if (waitMs > 0) {
|
|
2468
|
-
await
|
|
2196
|
+
await delay2(waitMs);
|
|
2469
2197
|
}
|
|
2470
2198
|
lastRequestTs = Date.now();
|
|
2471
2199
|
const response = await fetch(url.toString(), { headers });
|
|
@@ -2479,7 +2207,7 @@ var fetchCoinalyzeSeries = async (params) => {
|
|
|
2479
2207
|
const transient = response.status === 429 || response.status >= 500;
|
|
2480
2208
|
if (attempt < coinalyzeMaxRetries && transient) {
|
|
2481
2209
|
const backoffMs = Math.min(1e4, 750 * 2 ** attempt);
|
|
2482
|
-
await
|
|
2210
|
+
await delay2(retryAfterMs ?? backoffMs);
|
|
2483
2211
|
continue;
|
|
2484
2212
|
}
|
|
2485
2213
|
throw new Error(`Coinalyze ${endpoint} ${response.status}: ${text}`);
|