@luxalgo/vela 0.5.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/LICENSE +201 -0
- package/NOTICE +28 -0
- package/README.md +135 -0
- package/dist/DataProvider-DKNDHpNv.d.cts +134 -0
- package/dist/DataProvider-Dzd-Erlk.d.ts +134 -0
- package/dist/chunk-7UFX5ZIG.js +5976 -0
- package/dist/chunk-GYD2THPV.js +252 -0
- package/dist/chunk-KCCZNKH7.js +19137 -0
- package/dist/chunk-KM6LHB3Y.js +76 -0
- package/dist/chunk-OVQKKXLZ.js +3978 -0
- package/dist/chunk-Q3XQHLIH.js +7 -0
- package/dist/chunk-RHIDOUFL.js +698 -0
- package/dist/contributions-hX3EUyjG.d.ts +1528 -0
- package/dist/contributions-o1GRKPI_.d.cts +1528 -0
- package/dist/history-Dzxz-MQj.d.ts +298 -0
- package/dist/history-LJkz4-sS.d.cts +298 -0
- package/dist/icons-BZYbJXSV.d.cts +10 -0
- package/dist/icons-BZYbJXSV.d.ts +10 -0
- package/dist/index.cjs +25294 -0
- package/dist/index.d.cts +1189 -0
- package/dist/index.d.ts +1189 -0
- package/dist/index.js +5 -0
- package/dist/keymap-CGOz5F5f.d.cts +64 -0
- package/dist/keymap-CGOz5F5f.d.ts +64 -0
- package/dist/options-Q-576hIi.d.cts +1545 -0
- package/dist/options-Q-576hIi.d.ts +1545 -0
- package/dist/plugin-D94muTV-.d.cts +405 -0
- package/dist/plugin-aGUD1epn.d.ts +405 -0
- package/dist/plugin.cjs +5967 -0
- package/dist/plugin.d.cts +7 -0
- package/dist/plugin.d.ts +7 -0
- package/dist/plugin.js +3 -0
- package/dist/providers/binance.cjs +390 -0
- package/dist/providers/binance.d.cts +62 -0
- package/dist/providers/binance.d.ts +62 -0
- package/dist/providers/binance.js +388 -0
- package/dist/providers/coinbase.cjs +462 -0
- package/dist/providers/coinbase.d.cts +59 -0
- package/dist/providers/coinbase.d.ts +59 -0
- package/dist/providers/coinbase.js +460 -0
- package/dist/providers/hyperliquid.cjs +361 -0
- package/dist/providers/hyperliquid.d.cts +54 -0
- package/dist/providers/hyperliquid.d.ts +54 -0
- package/dist/providers/hyperliquid.js +359 -0
- package/dist/side-panel-CT9ZwIGz.d.cts +63 -0
- package/dist/side-panel-CT9ZwIGz.d.ts +63 -0
- package/dist/ui.cjs +1030 -0
- package/dist/ui.d.cts +188 -0
- package/dist/ui.d.ts +188 -0
- package/dist/ui.js +3 -0
- package/dist/vela.global.js +26509 -0
- package/dist/vela.global.min.js +230 -0
- package/dist/widget.cjs +31178 -0
- package/dist/widget.d.cts +799 -0
- package/dist/widget.d.ts +799 -0
- package/dist/widget.js +1060 -0
- package/dist/workspace.cjs +31692 -0
- package/dist/workspace.d.cts +579 -0
- package/dist/workspace.d.ts +579 -0
- package/dist/workspace.js +1694 -0
- package/package.json +95 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/data/providers/hyperliquid/HyperliquidProvider.ts
|
|
4
|
+
var INFO_URL = "https://api.hyperliquid.xyz/info";
|
|
5
|
+
var WS_URL = "wss://api.hyperliquid.xyz/ws";
|
|
6
|
+
var STREAM_STALL_MS = 15e3;
|
|
7
|
+
var STREAM_RECONNECT_MS = 2e3;
|
|
8
|
+
var TF_TO_INTERVAL = {
|
|
9
|
+
"1": "1m",
|
|
10
|
+
"3": "3m",
|
|
11
|
+
"5": "5m",
|
|
12
|
+
"15": "15m",
|
|
13
|
+
"30": "30m",
|
|
14
|
+
"60": "1h",
|
|
15
|
+
"120": "2h",
|
|
16
|
+
"240": "4h",
|
|
17
|
+
"480": "8h",
|
|
18
|
+
"720": "12h",
|
|
19
|
+
D: "1d",
|
|
20
|
+
W: "1w",
|
|
21
|
+
M: "1M"
|
|
22
|
+
};
|
|
23
|
+
var TF_NORMALIZE = {
|
|
24
|
+
"1m": "1",
|
|
25
|
+
"3m": "3",
|
|
26
|
+
"5m": "5",
|
|
27
|
+
"15m": "15",
|
|
28
|
+
"30m": "30",
|
|
29
|
+
"45m": "45",
|
|
30
|
+
"1h": "60",
|
|
31
|
+
"2h": "120",
|
|
32
|
+
"3h": "180",
|
|
33
|
+
"4h": "240",
|
|
34
|
+
"6h": "360",
|
|
35
|
+
"8h": "480",
|
|
36
|
+
"12h": "720",
|
|
37
|
+
"1d": "D",
|
|
38
|
+
"1w": "W",
|
|
39
|
+
"1mo": "M",
|
|
40
|
+
"1D": "D",
|
|
41
|
+
"1W": "W",
|
|
42
|
+
"4H": "240",
|
|
43
|
+
D: "D",
|
|
44
|
+
W: "W",
|
|
45
|
+
M: "M"
|
|
46
|
+
};
|
|
47
|
+
var NATIVE_MINUTES = [1, 3, 5, 15, 30, 60, 120, 240, 480, 720];
|
|
48
|
+
var MIN_TO_INTERVAL = {
|
|
49
|
+
1: "1m",
|
|
50
|
+
3: "3m",
|
|
51
|
+
5: "5m",
|
|
52
|
+
15: "15m",
|
|
53
|
+
30: "30m",
|
|
54
|
+
60: "1h",
|
|
55
|
+
120: "2h",
|
|
56
|
+
240: "4h",
|
|
57
|
+
480: "8h",
|
|
58
|
+
720: "12h"
|
|
59
|
+
};
|
|
60
|
+
var SUPPORTED_TIMEFRAMES = ["1", "3", "5", "15", "30", "45", "60", "120", "180", "240", "360", "480", "720", "D", "W", "M"];
|
|
61
|
+
var TF_MS = {
|
|
62
|
+
D: 864e5,
|
|
63
|
+
W: 6048e5,
|
|
64
|
+
M: 2592e6
|
|
65
|
+
// month ≈ 30d (windowing only; not bar alignment)
|
|
66
|
+
};
|
|
67
|
+
function tfMs(tf) {
|
|
68
|
+
if (TF_MS[tf]) return TF_MS[tf];
|
|
69
|
+
const min = parseInt(tf, 10);
|
|
70
|
+
return Number.isFinite(min) && min > 0 ? min * 6e4 : 36e5;
|
|
71
|
+
}
|
|
72
|
+
function normalizeTf(tf) {
|
|
73
|
+
return TF_NORMALIZE[tf] ?? TF_NORMALIZE[tf.toLowerCase()] ?? tf;
|
|
74
|
+
}
|
|
75
|
+
function parseCoin(ticker) {
|
|
76
|
+
const t = ticker.trim();
|
|
77
|
+
return t.includes("/") ? t : t.toUpperCase();
|
|
78
|
+
}
|
|
79
|
+
function candleToOHLCV(k) {
|
|
80
|
+
return { time: Number(k.t), open: Number(k.o), high: Number(k.h), low: Number(k.l), close: Number(k.c), volume: Number(k.v) };
|
|
81
|
+
}
|
|
82
|
+
function dedupeSorted(bars) {
|
|
83
|
+
const byTime = /* @__PURE__ */ new Map();
|
|
84
|
+
for (const b of bars) byTime.set(b.time, b);
|
|
85
|
+
return [...byTime.values()].sort((a, b) => a.time - b.time);
|
|
86
|
+
}
|
|
87
|
+
function aggregate(sub, bucketMs) {
|
|
88
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
89
|
+
for (const b of sub) {
|
|
90
|
+
const key = Math.floor(b.time / bucketMs) * bucketMs;
|
|
91
|
+
const cur = buckets.get(key);
|
|
92
|
+
if (!cur) {
|
|
93
|
+
buckets.set(key, { time: key, open: b.open, high: b.high, low: b.low, close: b.close, volume: b.volume ?? 0 });
|
|
94
|
+
} else {
|
|
95
|
+
cur.high = Math.max(cur.high, b.high);
|
|
96
|
+
cur.low = Math.min(cur.low, b.low);
|
|
97
|
+
cur.close = b.close;
|
|
98
|
+
cur.volume = (cur.volume ?? 0) + (b.volume ?? 0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return [...buckets.values()].sort((a, b) => a.time - b.time);
|
|
102
|
+
}
|
|
103
|
+
function selectSubTf(targetMin) {
|
|
104
|
+
return NATIVE_MINUTES.filter((m) => m < targetMin && targetMin % m === 0).sort((a, b) => b - a)[0] ?? null;
|
|
105
|
+
}
|
|
106
|
+
var HyperliquidProvider = class {
|
|
107
|
+
constructor() {
|
|
108
|
+
/** Cached perp `meta` (universe is large; fetch once). */
|
|
109
|
+
this.metaPromise = null;
|
|
110
|
+
/** Cached `spotMeta`. */
|
|
111
|
+
this.spotMetaPromise = null;
|
|
112
|
+
/** Cached symbol enumeration. */
|
|
113
|
+
this.symbolsPromise = null;
|
|
114
|
+
}
|
|
115
|
+
info() {
|
|
116
|
+
return {
|
|
117
|
+
name: "hyperliquid",
|
|
118
|
+
displayName: "Hyperliquid",
|
|
119
|
+
requiresApiKey: false,
|
|
120
|
+
supportedTimeframes: SUPPORTED_TIMEFRAMES,
|
|
121
|
+
capabilities: { enumerate: true, stream: true, symbolInfo: true }
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async getBars(ticker, timeframe, range) {
|
|
125
|
+
try {
|
|
126
|
+
const coin = parseCoin(ticker);
|
|
127
|
+
const tf = normalizeTf(timeframe);
|
|
128
|
+
const nativeInterval = TF_TO_INTERVAL[tf];
|
|
129
|
+
if (nativeInterval) {
|
|
130
|
+
return dedupeSorted((await this.fetchCandles(coin, nativeInterval, tfMs(tf), range)).map(candleToOHLCV));
|
|
131
|
+
}
|
|
132
|
+
const targetMin = /^\d+$/.test(tf) ? parseInt(tf, 10) : null;
|
|
133
|
+
const subMin = targetMin != null ? selectSubTf(targetMin) : null;
|
|
134
|
+
if (targetMin == null || subMin == null) {
|
|
135
|
+
console.warn(`[vela] Hyperliquid: timeframe "${timeframe}" is not supported and cannot be aggregated.`);
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const ratio = targetMin / subMin;
|
|
139
|
+
const subRange = { ...range, limit: range.limit != null ? range.limit * ratio + ratio : void 0 };
|
|
140
|
+
const sub = (await this.fetchCandles(coin, MIN_TO_INTERVAL[subMin], subMin * 6e4, subRange)).map(candleToOHLCV);
|
|
141
|
+
const agg = aggregate(sub, targetMin * 6e4);
|
|
142
|
+
return range.limit != null && agg.length > range.limit ? agg.slice(-range.limit) : agg;
|
|
143
|
+
} catch (e) {
|
|
144
|
+
console.warn(`[vela] Hyperliquid: failed to fetch ${ticker} ${timeframe} \u2014 ${e instanceof Error ? e.message : String(e)}`);
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async getSymbolInfo(ticker) {
|
|
149
|
+
const coin = parseCoin(ticker);
|
|
150
|
+
const meta = await this.fetchMeta().catch(() => null);
|
|
151
|
+
const perp = meta?.universe?.find((u) => u.name === coin);
|
|
152
|
+
if (perp) {
|
|
153
|
+
const mintick = decimalsToTick(Math.max(0, 6 - (perp.szDecimals ?? 2)));
|
|
154
|
+
return symbolInfo(ticker, coin, "USD", "futures", `${coin} / USD Perpetual`, mintick);
|
|
155
|
+
}
|
|
156
|
+
if (coin.includes("/")) {
|
|
157
|
+
const spot = await this.fetchSpotMeta().catch(() => null);
|
|
158
|
+
const entry = spot?.universe?.find((u) => u.name === coin);
|
|
159
|
+
const baseTok = entry && spot?.tokens ? spot.tokens[entry.tokens?.[0] ?? -1] : void 0;
|
|
160
|
+
const [base = coin, quote = "USDC"] = coin.split("/");
|
|
161
|
+
const mintick = decimalsToTick(Math.max(0, 8 - (baseTok?.szDecimals ?? 2)));
|
|
162
|
+
return symbolInfo(ticker, base, quote, "crypto", `${base} / ${quote}`, mintick);
|
|
163
|
+
}
|
|
164
|
+
return void 0;
|
|
165
|
+
}
|
|
166
|
+
listSymbols() {
|
|
167
|
+
if (!this.symbolsPromise) {
|
|
168
|
+
this.symbolsPromise = Promise.all([
|
|
169
|
+
this.listPerps().catch(() => []),
|
|
170
|
+
this.listSpot().catch(() => [])
|
|
171
|
+
]).then(([perps, spot]) => [...perps, ...spot]);
|
|
172
|
+
}
|
|
173
|
+
return this.symbolsPromise;
|
|
174
|
+
}
|
|
175
|
+
subscribe(ticker, timeframe, onBar) {
|
|
176
|
+
const coin = parseCoin(ticker);
|
|
177
|
+
const interval = TF_TO_INTERVAL[normalizeTf(timeframe)];
|
|
178
|
+
if (interval && typeof WebSocket !== "undefined") return this.streamCandles(ticker, timeframe, coin, interval, onBar);
|
|
179
|
+
return this.pollBars(ticker, timeframe, onBar);
|
|
180
|
+
}
|
|
181
|
+
// ── internals ────────────────────────────────────────────────────────
|
|
182
|
+
async listPerps() {
|
|
183
|
+
const meta = await this.fetchMeta();
|
|
184
|
+
return (meta.universe ?? []).filter((u) => !u.isDelisted).map((u) => ({ ticker: u.name, description: `${u.name} / USD Perpetual`, type: "futures" }));
|
|
185
|
+
}
|
|
186
|
+
async listSpot() {
|
|
187
|
+
const meta = await this.fetchSpotMeta();
|
|
188
|
+
const tokens = meta.tokens ?? [];
|
|
189
|
+
const nameOf = (i) => i != null ? tokens[i]?.name ?? null : null;
|
|
190
|
+
return (meta.universe ?? []).map((u) => {
|
|
191
|
+
const base = nameOf(u.tokens?.[0]);
|
|
192
|
+
const quote = nameOf(u.tokens?.[1]);
|
|
193
|
+
const description = base && quote ? `${base} / ${quote}` : u.name;
|
|
194
|
+
return { ticker: u.name, description, type: "crypto" };
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Fetch candles for a time window. Hyperliquid's `candleSnapshot` has no count
|
|
199
|
+
* parameter — it returns candles in `[startTime, endTime]` (capped to the most
|
|
200
|
+
* recent ~5000). We translate a bar `limit` into a start offset; a `from` range
|
|
201
|
+
* (the cache's tail refresh) is used directly. The newest candle is the forming one.
|
|
202
|
+
*/
|
|
203
|
+
async fetchCandles(coin, interval, intervalMs, range) {
|
|
204
|
+
const end = range.to ?? Date.now();
|
|
205
|
+
const start = range.from != null ? range.from : end - ((range.limit ?? 500) + 2) * intervalMs;
|
|
206
|
+
const candles = await this.candleSnapshot(coin, interval, start, end);
|
|
207
|
+
if (range.from == null && range.limit != null && candles.length > range.limit) return candles.slice(-range.limit);
|
|
208
|
+
return candles;
|
|
209
|
+
}
|
|
210
|
+
async candleSnapshot(coin, interval, startTime, endTime) {
|
|
211
|
+
const data = await this.post({ type: "candleSnapshot", req: { coin, interval, startTime: Math.floor(startTime), endTime: Math.floor(endTime) } });
|
|
212
|
+
return Array.isArray(data) ? data : [];
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Open a WebSocket candle stream; reconnects on unexpected close until unsubscribed.
|
|
216
|
+
* A stall watchdog falls the subscription back to polling if the socket opens but
|
|
217
|
+
* never delivers a candle (a blocked/silent stream) — so live updates never go
|
|
218
|
+
* silently dead. Mirrors the Binance provider's streaming resilience.
|
|
219
|
+
*/
|
|
220
|
+
streamCandles(ticker, timeframe, coin, interval, onBar) {
|
|
221
|
+
let closed = false;
|
|
222
|
+
let ws = null;
|
|
223
|
+
let ping = null;
|
|
224
|
+
let reconnect = null;
|
|
225
|
+
let stall = null;
|
|
226
|
+
let polling = null;
|
|
227
|
+
const clearStall = () => {
|
|
228
|
+
if (stall) {
|
|
229
|
+
clearTimeout(stall);
|
|
230
|
+
stall = null;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const clearPing = () => {
|
|
234
|
+
if (ping) {
|
|
235
|
+
clearInterval(ping);
|
|
236
|
+
ping = null;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const fallToPolling = () => {
|
|
240
|
+
if (closed || polling) return;
|
|
241
|
+
clearStall();
|
|
242
|
+
clearPing();
|
|
243
|
+
if (reconnect) {
|
|
244
|
+
clearTimeout(reconnect);
|
|
245
|
+
reconnect = null;
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
ws?.close();
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
ws = null;
|
|
252
|
+
console.warn(`[vela] Hyperliquid: ${ticker} ${timeframe} stream delivered no data; falling back to polling.`);
|
|
253
|
+
polling = this.pollBars(ticker, timeframe, onBar);
|
|
254
|
+
};
|
|
255
|
+
const open = () => {
|
|
256
|
+
if (closed || polling) return;
|
|
257
|
+
ws = new WebSocket(WS_URL);
|
|
258
|
+
stall = setTimeout(fallToPolling, STREAM_STALL_MS);
|
|
259
|
+
ws.onopen = () => {
|
|
260
|
+
try {
|
|
261
|
+
ws?.send(JSON.stringify({ method: "subscribe", subscription: { type: "candle", coin, interval } }));
|
|
262
|
+
} catch {
|
|
263
|
+
}
|
|
264
|
+
ping = setInterval(() => {
|
|
265
|
+
try {
|
|
266
|
+
ws?.send(JSON.stringify({ method: "ping" }));
|
|
267
|
+
} catch {
|
|
268
|
+
}
|
|
269
|
+
}, 3e4);
|
|
270
|
+
};
|
|
271
|
+
ws.onmessage = (ev) => {
|
|
272
|
+
if (closed || polling) return;
|
|
273
|
+
try {
|
|
274
|
+
const msg = JSON.parse(typeof ev.data === "string" ? ev.data : "");
|
|
275
|
+
if (msg.channel === "candle" && msg.data && msg.data.s === coin) {
|
|
276
|
+
clearStall();
|
|
277
|
+
onBar(candleToOHLCV(msg.data));
|
|
278
|
+
}
|
|
279
|
+
} catch {
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
ws.onclose = () => {
|
|
283
|
+
clearPing();
|
|
284
|
+
if (!closed && !polling) reconnect = setTimeout(open, STREAM_RECONNECT_MS);
|
|
285
|
+
};
|
|
286
|
+
ws.onerror = () => {
|
|
287
|
+
try {
|
|
288
|
+
ws?.close();
|
|
289
|
+
} catch {
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
open();
|
|
294
|
+
return () => {
|
|
295
|
+
closed = true;
|
|
296
|
+
clearStall();
|
|
297
|
+
clearPing();
|
|
298
|
+
if (reconnect) clearTimeout(reconnect);
|
|
299
|
+
polling?.();
|
|
300
|
+
try {
|
|
301
|
+
ws?.close();
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/** Poll the forming candle (for aggregated timeframes / environments without WebSocket). */
|
|
307
|
+
pollBars(ticker, timeframe, onBar) {
|
|
308
|
+
let stopped = false;
|
|
309
|
+
let timer = null;
|
|
310
|
+
const poll = async () => {
|
|
311
|
+
if (stopped) return;
|
|
312
|
+
try {
|
|
313
|
+
const bars = await this.getBars(ticker, timeframe, { limit: 2 });
|
|
314
|
+
for (const b of bars) onBar(b);
|
|
315
|
+
} catch {
|
|
316
|
+
}
|
|
317
|
+
if (!stopped) timer = setTimeout(() => void poll(), 3e3);
|
|
318
|
+
};
|
|
319
|
+
timer = setTimeout(() => void poll(), 3e3);
|
|
320
|
+
return () => {
|
|
321
|
+
stopped = true;
|
|
322
|
+
if (timer) clearTimeout(timer);
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
fetchMeta() {
|
|
326
|
+
return this.metaPromise ?? (this.metaPromise = this.post({ type: "meta" }).then((d) => d));
|
|
327
|
+
}
|
|
328
|
+
fetchSpotMeta() {
|
|
329
|
+
return this.spotMetaPromise ?? (this.spotMetaPromise = this.post({ type: "spotMeta" }).then((d) => d));
|
|
330
|
+
}
|
|
331
|
+
async post(body) {
|
|
332
|
+
const res = await fetch(INFO_URL, {
|
|
333
|
+
method: "POST",
|
|
334
|
+
headers: { "Content-Type": "application/json" },
|
|
335
|
+
body: JSON.stringify(body)
|
|
336
|
+
});
|
|
337
|
+
if (!res.ok) throw new Error(`Hyperliquid HTTP ${res.status}`);
|
|
338
|
+
return res.json();
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
function symbolInfo(ticker, basecurrency, currency, type, description, mintick) {
|
|
342
|
+
return {
|
|
343
|
+
ticker,
|
|
344
|
+
// keep the original ticker (as Pine Script expects)
|
|
345
|
+
tickerid: `HYPERLIQUID:${ticker}`,
|
|
346
|
+
prefix: "HYPERLIQUID",
|
|
347
|
+
description,
|
|
348
|
+
type,
|
|
349
|
+
basecurrency,
|
|
350
|
+
currency,
|
|
351
|
+
mintick,
|
|
352
|
+
pricescale: Math.round(1 / mintick),
|
|
353
|
+
timezone: "Etc/UTC",
|
|
354
|
+
session: "24x7"
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function decimalsToTick(decimals) {
|
|
358
|
+
return Math.pow(10, -decimals);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
exports.HyperliquidProvider = HyperliquidProvider;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { O as OHLCV, U as Unsubscribe } from '../options-Q-576hIi.cjs';
|
|
2
|
+
import { D as DataProvider, P as ProviderInfo, B as BarRange, S as SymbolInfo, a as SymbolDescriptor } from '../DataProvider-DKNDHpNv.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hyperliquid market-data provider, built from scratch on the public info API — no
|
|
6
|
+
* third-party SDK, no API key. Serves USD-margined perpetuals (bare coins like `BTC`) and
|
|
7
|
+
* spot pairs (`PURR/USDC`), and aggregates timeframes Hyperliquid doesn't serve
|
|
8
|
+
* natively (e.g. `45`, `180`, `360`). Live ticks use a real WebSocket candle stream
|
|
9
|
+
* (`subscribe`).
|
|
10
|
+
*
|
|
11
|
+
* History note: Hyperliquid only serves the most recent ~5000 candles per interval
|
|
12
|
+
* (≈ 3.5d of 1m, ~7mo of 1h, daily back to listing) — there is no deeper backfill, so
|
|
13
|
+
* it's a live/recent-history venue rather than a deep-history source.
|
|
14
|
+
*
|
|
15
|
+
* import { HyperliquidProvider } from 'vela/providers/hyperliquid';
|
|
16
|
+
* chart.data.registerProvider('hyperliquid', new HyperliquidProvider());
|
|
17
|
+
*/
|
|
18
|
+
declare class HyperliquidProvider implements DataProvider {
|
|
19
|
+
/** Cached perp `meta` (universe is large; fetch once). */
|
|
20
|
+
private metaPromise;
|
|
21
|
+
/** Cached `spotMeta`. */
|
|
22
|
+
private spotMetaPromise;
|
|
23
|
+
/** Cached symbol enumeration. */
|
|
24
|
+
private symbolsPromise;
|
|
25
|
+
info(): ProviderInfo;
|
|
26
|
+
getBars(ticker: string, timeframe: string, range: BarRange): Promise<OHLCV[]>;
|
|
27
|
+
getSymbolInfo(ticker: string): Promise<SymbolInfo | undefined>;
|
|
28
|
+
listSymbols(): Promise<SymbolDescriptor[]>;
|
|
29
|
+
subscribe(ticker: string, timeframe: string, onBar: (bar: OHLCV) => void): Unsubscribe;
|
|
30
|
+
private listPerps;
|
|
31
|
+
private listSpot;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch candles for a time window. Hyperliquid's `candleSnapshot` has no count
|
|
34
|
+
* parameter — it returns candles in `[startTime, endTime]` (capped to the most
|
|
35
|
+
* recent ~5000). We translate a bar `limit` into a start offset; a `from` range
|
|
36
|
+
* (the cache's tail refresh) is used directly. The newest candle is the forming one.
|
|
37
|
+
*/
|
|
38
|
+
private fetchCandles;
|
|
39
|
+
private candleSnapshot;
|
|
40
|
+
/**
|
|
41
|
+
* Open a WebSocket candle stream; reconnects on unexpected close until unsubscribed.
|
|
42
|
+
* A stall watchdog falls the subscription back to polling if the socket opens but
|
|
43
|
+
* never delivers a candle (a blocked/silent stream) — so live updates never go
|
|
44
|
+
* silently dead. Mirrors the Binance provider's streaming resilience.
|
|
45
|
+
*/
|
|
46
|
+
private streamCandles;
|
|
47
|
+
/** Poll the forming candle (for aggregated timeframes / environments without WebSocket). */
|
|
48
|
+
private pollBars;
|
|
49
|
+
private fetchMeta;
|
|
50
|
+
private fetchSpotMeta;
|
|
51
|
+
private post;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { DataProvider, HyperliquidProvider, ProviderInfo, SymbolDescriptor };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { O as OHLCV, U as Unsubscribe } from '../options-Q-576hIi.js';
|
|
2
|
+
import { D as DataProvider, P as ProviderInfo, B as BarRange, S as SymbolInfo, a as SymbolDescriptor } from '../DataProvider-Dzd-Erlk.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hyperliquid market-data provider, built from scratch on the public info API — no
|
|
6
|
+
* third-party SDK, no API key. Serves USD-margined perpetuals (bare coins like `BTC`) and
|
|
7
|
+
* spot pairs (`PURR/USDC`), and aggregates timeframes Hyperliquid doesn't serve
|
|
8
|
+
* natively (e.g. `45`, `180`, `360`). Live ticks use a real WebSocket candle stream
|
|
9
|
+
* (`subscribe`).
|
|
10
|
+
*
|
|
11
|
+
* History note: Hyperliquid only serves the most recent ~5000 candles per interval
|
|
12
|
+
* (≈ 3.5d of 1m, ~7mo of 1h, daily back to listing) — there is no deeper backfill, so
|
|
13
|
+
* it's a live/recent-history venue rather than a deep-history source.
|
|
14
|
+
*
|
|
15
|
+
* import { HyperliquidProvider } from 'vela/providers/hyperliquid';
|
|
16
|
+
* chart.data.registerProvider('hyperliquid', new HyperliquidProvider());
|
|
17
|
+
*/
|
|
18
|
+
declare class HyperliquidProvider implements DataProvider {
|
|
19
|
+
/** Cached perp `meta` (universe is large; fetch once). */
|
|
20
|
+
private metaPromise;
|
|
21
|
+
/** Cached `spotMeta`. */
|
|
22
|
+
private spotMetaPromise;
|
|
23
|
+
/** Cached symbol enumeration. */
|
|
24
|
+
private symbolsPromise;
|
|
25
|
+
info(): ProviderInfo;
|
|
26
|
+
getBars(ticker: string, timeframe: string, range: BarRange): Promise<OHLCV[]>;
|
|
27
|
+
getSymbolInfo(ticker: string): Promise<SymbolInfo | undefined>;
|
|
28
|
+
listSymbols(): Promise<SymbolDescriptor[]>;
|
|
29
|
+
subscribe(ticker: string, timeframe: string, onBar: (bar: OHLCV) => void): Unsubscribe;
|
|
30
|
+
private listPerps;
|
|
31
|
+
private listSpot;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch candles for a time window. Hyperliquid's `candleSnapshot` has no count
|
|
34
|
+
* parameter — it returns candles in `[startTime, endTime]` (capped to the most
|
|
35
|
+
* recent ~5000). We translate a bar `limit` into a start offset; a `from` range
|
|
36
|
+
* (the cache's tail refresh) is used directly. The newest candle is the forming one.
|
|
37
|
+
*/
|
|
38
|
+
private fetchCandles;
|
|
39
|
+
private candleSnapshot;
|
|
40
|
+
/**
|
|
41
|
+
* Open a WebSocket candle stream; reconnects on unexpected close until unsubscribed.
|
|
42
|
+
* A stall watchdog falls the subscription back to polling if the socket opens but
|
|
43
|
+
* never delivers a candle (a blocked/silent stream) — so live updates never go
|
|
44
|
+
* silently dead. Mirrors the Binance provider's streaming resilience.
|
|
45
|
+
*/
|
|
46
|
+
private streamCandles;
|
|
47
|
+
/** Poll the forming candle (for aggregated timeframes / environments without WebSocket). */
|
|
48
|
+
private pollBars;
|
|
49
|
+
private fetchMeta;
|
|
50
|
+
private fetchSpotMeta;
|
|
51
|
+
private post;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { DataProvider, HyperliquidProvider, ProviderInfo, SymbolDescriptor };
|