@pear-protocol/market-sdk 0.0.1-preview.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.
Files changed (82) hide show
  1. package/README.md +319 -0
  2. package/dist/chart/cache/index.d.ts +21 -0
  3. package/dist/chart/cache/index.js +101 -0
  4. package/dist/chart/chart.d.ts +25 -0
  5. package/dist/chart/chart.js +141 -0
  6. package/dist/chart/collector/binance.d.ts +10 -0
  7. package/dist/chart/collector/binance.js +27 -0
  8. package/dist/chart/collector/bybit.d.ts +10 -0
  9. package/dist/chart/collector/bybit.js +39 -0
  10. package/dist/chart/collector/helpers.d.ts +10 -0
  11. package/dist/chart/collector/helpers.js +21 -0
  12. package/dist/chart/collector/hyperliquid.d.ts +10 -0
  13. package/dist/chart/collector/hyperliquid.js +15 -0
  14. package/dist/chart/collector/index.d.ts +41 -0
  15. package/dist/chart/collector/index.js +202 -0
  16. package/dist/chart/collector/okx.d.ts +10 -0
  17. package/dist/chart/collector/okx.js +38 -0
  18. package/dist/chart/compute/asset.d.ts +11 -0
  19. package/dist/chart/compute/asset.js +24 -0
  20. package/dist/chart/compute/index.d.ts +10 -0
  21. package/dist/chart/compute/index.js +4 -0
  22. package/dist/chart/compute/performance.d.ts +11 -0
  23. package/dist/chart/compute/performance.js +81 -0
  24. package/dist/chart/compute/price-ratio.d.ts +11 -0
  25. package/dist/chart/compute/price-ratio.js +107 -0
  26. package/dist/chart/compute/weighted-ratio.d.ts +11 -0
  27. package/dist/chart/compute/weighted-ratio.js +109 -0
  28. package/dist/chart/types.d.ts +55 -0
  29. package/dist/chart/types.js +1 -0
  30. package/dist/chart/utils.d.ts +14 -0
  31. package/dist/chart/utils.js +91 -0
  32. package/dist/chart/ws/base-candle.d.ts +29 -0
  33. package/dist/chart/ws/base-candle.js +71 -0
  34. package/dist/chart/ws/binance.d.ts +19 -0
  35. package/dist/chart/ws/binance.js +43 -0
  36. package/dist/chart/ws/bybit.d.ts +18 -0
  37. package/dist/chart/ws/bybit.js +63 -0
  38. package/dist/chart/ws/hyperliquid.d.ts +31 -0
  39. package/dist/chart/ws/hyperliquid.js +40 -0
  40. package/dist/chart/ws/index.d.ts +11 -0
  41. package/dist/chart/ws/index.js +24 -0
  42. package/dist/chart/ws/okx.d.ts +18 -0
  43. package/dist/chart/ws/okx.js +60 -0
  44. package/dist/index.d.ts +10 -0
  45. package/dist/index.js +4 -0
  46. package/dist/orderbook/book/aggregate.d.ts +26 -0
  47. package/dist/orderbook/book/aggregate.js +38 -0
  48. package/dist/orderbook/book/local-book.d.ts +37 -0
  49. package/dist/orderbook/book/local-book.js +90 -0
  50. package/dist/orderbook/orderbook.d.ts +48 -0
  51. package/dist/orderbook/orderbook.js +111 -0
  52. package/dist/orderbook/types.d.ts +67 -0
  53. package/dist/orderbook/types.js +4 -0
  54. package/dist/orderbook/utils.d.ts +12 -0
  55. package/dist/orderbook/utils.js +35 -0
  56. package/dist/orderbook/ws/base-depth.d.ts +41 -0
  57. package/dist/orderbook/ws/base-depth.js +89 -0
  58. package/dist/orderbook/ws/binance.d.ts +23 -0
  59. package/dist/orderbook/ws/binance.js +126 -0
  60. package/dist/orderbook/ws/bybit.d.ts +15 -0
  61. package/dist/orderbook/ws/bybit.js +40 -0
  62. package/dist/orderbook/ws/hyperliquid.d.ts +20 -0
  63. package/dist/orderbook/ws/hyperliquid.js +87 -0
  64. package/dist/orderbook/ws/index.d.ts +11 -0
  65. package/dist/orderbook/ws/index.js +24 -0
  66. package/dist/orderbook/ws/okx.d.ts +15 -0
  67. package/dist/orderbook/ws/okx.js +33 -0
  68. package/dist/shared/types.d.ts +6 -0
  69. package/dist/shared/types.js +1 -0
  70. package/dist/transport/base-transport.d.ts +28 -0
  71. package/dist/transport/base-transport.js +95 -0
  72. package/dist/transport/binance.d.ts +13 -0
  73. package/dist/transport/binance.js +16 -0
  74. package/dist/transport/bybit.d.ts +13 -0
  75. package/dist/transport/bybit.js +16 -0
  76. package/dist/transport/hyperliquid.d.ts +13 -0
  77. package/dist/transport/hyperliquid.js +16 -0
  78. package/dist/transport/index.d.ts +10 -0
  79. package/dist/transport/index.js +24 -0
  80. package/dist/transport/okx.d.ts +13 -0
  81. package/dist/transport/okx.js +16 -0
  82. package/package.json +37 -0
@@ -0,0 +1,109 @@
1
+ import { createCandleLookups, getCompleteTimestamps } from '../utils';
2
+
3
+ function pow(base, exponent) {
4
+ if (base <= 0) return 0;
5
+ return Math.exp(exponent * Math.log(base));
6
+ }
7
+ function computeWeightedRatioCandles(longTokens, shortTokens, tokenCandles) {
8
+ if (longTokens.length === 0 && shortTokens.length === 0) return [];
9
+ const candleLookups = createCandleLookups(tokenCandles);
10
+ const allSymbols = [...longTokens, ...shortTokens].map((t) => t.symbol);
11
+ const completeTimestamps = getCompleteTimestamps(candleLookups, allSymbols);
12
+ const bars = [];
13
+ for (const timestamp of completeTimestamps) {
14
+ let longOpen = 1;
15
+ let longHigh = 1;
16
+ let longLow = 1;
17
+ let longClose = 1;
18
+ let shortOpen = 1;
19
+ let shortHigh = 1;
20
+ let shortLow = 1;
21
+ let shortClose = 1;
22
+ let missing = false;
23
+ for (const token of longTokens) {
24
+ const candle = candleLookups[token.symbol]?.get(timestamp);
25
+ if (!candle) {
26
+ missing = true;
27
+ break;
28
+ }
29
+ const w = token.weight / 100;
30
+ if (!(candle.o > 0 && candle.h > 0 && candle.l > 0 && candle.c > 0)) {
31
+ missing = true;
32
+ break;
33
+ }
34
+ longOpen *= pow(candle.o, w);
35
+ longHigh *= pow(candle.h, w);
36
+ longLow *= pow(candle.l, w);
37
+ longClose *= pow(candle.c, w);
38
+ }
39
+ if (missing) continue;
40
+ for (const token of shortTokens) {
41
+ const candle = candleLookups[token.symbol]?.get(timestamp);
42
+ if (!candle) {
43
+ missing = true;
44
+ break;
45
+ }
46
+ const w = -(token.weight / 100);
47
+ if (!(candle.o > 0 && candle.h > 0 && candle.l > 0 && candle.c > 0)) {
48
+ missing = true;
49
+ break;
50
+ }
51
+ shortOpen *= pow(candle.o, w);
52
+ shortHigh *= pow(candle.h, w);
53
+ shortLow *= pow(candle.l, w);
54
+ shortClose *= pow(candle.c, w);
55
+ }
56
+ if (missing) continue;
57
+ bars.push({
58
+ time: timestamp,
59
+ open: longOpen * shortOpen,
60
+ high: longHigh * shortHigh,
61
+ low: longLow * shortLow,
62
+ close: longClose * shortClose
63
+ });
64
+ }
65
+ return bars;
66
+ }
67
+ function computeRealtimeWeightedRatioBar(longTokens, shortTokens, snapshot) {
68
+ let longOpen = 1;
69
+ let longHigh = 1;
70
+ let longLow = 1;
71
+ let longClose = 1;
72
+ let shortOpen = 1;
73
+ let shortHigh = 1;
74
+ let shortLow = 1;
75
+ let shortClose = 1;
76
+ let time = null;
77
+ for (const token of longTokens) {
78
+ const c = snapshot[token.symbol];
79
+ if (!c) return null;
80
+ if (!(c.o > 0 && c.h > 0 && c.l > 0 && c.c > 0)) return null;
81
+ const w = token.weight / 100;
82
+ longOpen *= pow(c.o, w);
83
+ longHigh *= pow(c.h, w);
84
+ longLow *= pow(c.l, w);
85
+ longClose *= pow(c.c, w);
86
+ if (time === null) time = c.t;
87
+ }
88
+ for (const token of shortTokens) {
89
+ const c = snapshot[token.symbol];
90
+ if (!c) return null;
91
+ if (!(c.o > 0 && c.h > 0 && c.l > 0 && c.c > 0)) return null;
92
+ const w = -(token.weight / 100);
93
+ shortOpen *= pow(c.o, w);
94
+ shortHigh *= pow(c.h, w);
95
+ shortLow *= pow(c.l, w);
96
+ shortClose *= pow(c.c, w);
97
+ if (time === null) time = c.t;
98
+ }
99
+ if (time === null) return null;
100
+ return {
101
+ time,
102
+ open: longOpen * shortOpen,
103
+ high: longHigh * shortHigh,
104
+ low: longLow * shortLow,
105
+ close: longClose * shortClose
106
+ };
107
+ }
108
+
109
+ export { computeRealtimeWeightedRatioBar, computeWeightedRatioCandles };
@@ -0,0 +1,55 @@
1
+ import { Transport } from '../transport/index.js';
2
+ import '@pear-protocol/types';
3
+ import '../transport/base-transport.js';
4
+ import 'partysocket';
5
+ import '../shared/types.js';
6
+
7
+ interface TokenSelection {
8
+ symbol: string;
9
+ weight: number;
10
+ }
11
+ type CandleInterval = '1m' | '3m' | '5m' | '15m' | '30m' | '1h' | '2h' | '4h' | '8h' | '12h' | '1d' | '3d' | '1w' | '1M';
12
+ interface CandleData {
13
+ s?: string;
14
+ t: number;
15
+ T: number;
16
+ o: number;
17
+ c: number;
18
+ h: number;
19
+ l: number;
20
+ }
21
+ interface HistoricalRange {
22
+ start: number;
23
+ end: number;
24
+ }
25
+ interface TokenHistoricalPriceData {
26
+ symbol: string;
27
+ interval: CandleInterval;
28
+ candles: CandleData[];
29
+ oldestTime: number | null;
30
+ latestTime: number | null;
31
+ requestedRanges: HistoricalRange[];
32
+ noDataBefore: number | null;
33
+ }
34
+ interface ChartConfig {
35
+ transport: Transport;
36
+ longTokens?: TokenSelection[];
37
+ shortTokens?: TokenSelection[];
38
+ candleInterval?: CandleInterval;
39
+ }
40
+ type RealtimeCandleCallback = (symbol: string, candle: CandleData) => void;
41
+ type ChartType = 'weighted-ratio' | 'price-ratio' | 'performance' | 'price';
42
+ interface Bar {
43
+ time: number;
44
+ open: number;
45
+ high: number;
46
+ low: number;
47
+ close: number;
48
+ }
49
+ type RealtimeBarCallback = (bar: Bar) => void;
50
+ interface PerformanceResult {
51
+ bars: Bar[];
52
+ baselinePrices: Record<string, number>;
53
+ }
54
+
55
+ export type { Bar, CandleData, CandleInterval, ChartConfig, ChartType, HistoricalRange, PerformanceResult, RealtimeBarCallback, RealtimeCandleCallback, TokenHistoricalPriceData, TokenSelection };
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,14 @@
1
+ import { CandleData, CandleInterval, HistoricalRange } from './types.js';
2
+ import '../transport/index.js';
3
+ import '@pear-protocol/types';
4
+ import '../transport/base-transport.js';
5
+ import 'partysocket';
6
+ import '../shared/types.js';
7
+
8
+ declare const createKey: (symbol: string, interval: CandleInterval) => string;
9
+ declare const getIntervalSeconds: (interval: CandleInterval) => number;
10
+ declare const mergeRanges: (ranges: HistoricalRange[], newRange: HistoricalRange) => HistoricalRange[];
11
+ declare const createCandleLookups: (tokenCandles: Record<string, CandleData[]>) => Record<string, Map<number, CandleData>>;
12
+ declare const getCompleteTimestamps: (candleLookups: Record<string, Map<number, CandleData>>, requiredSymbols: string[]) => number[];
13
+
14
+ export { createCandleLookups, createKey, getCompleteTimestamps, getIntervalSeconds, mergeRanges };
@@ -0,0 +1,91 @@
1
+ const createKey = (symbol, interval) => `${symbol}-${interval}`;
2
+ const getIntervalSeconds = (interval) => {
3
+ switch (interval) {
4
+ case "1m":
5
+ return 60;
6
+ case "3m":
7
+ return 3 * 60;
8
+ case "5m":
9
+ return 5 * 60;
10
+ case "15m":
11
+ return 15 * 60;
12
+ case "30m":
13
+ return 30 * 60;
14
+ case "1h":
15
+ return 60 * 60;
16
+ case "2h":
17
+ return 2 * 60 * 60;
18
+ case "4h":
19
+ return 4 * 60 * 60;
20
+ case "8h":
21
+ return 8 * 60 * 60;
22
+ case "12h":
23
+ return 12 * 60 * 60;
24
+ case "1d":
25
+ return 24 * 60 * 60;
26
+ case "3d":
27
+ return 3 * 24 * 60 * 60;
28
+ case "1w":
29
+ return 7 * 24 * 60 * 60;
30
+ case "1M":
31
+ return 30 * 24 * 60 * 60;
32
+ }
33
+ };
34
+ const mergeRanges = (ranges, newRange) => {
35
+ const all = [...ranges, newRange].sort((a, b) => a.start - b.start);
36
+ const merged = [];
37
+ for (const r of all) {
38
+ const last = merged[merged.length - 1];
39
+ if (merged.length === 0 || !last || r.start > last.end) {
40
+ merged.push({ start: r.start, end: r.end });
41
+ } else {
42
+ last.end = Math.max(last.end, r.end);
43
+ }
44
+ }
45
+ return merged;
46
+ };
47
+ const createCandleLookups = (tokenCandles) => {
48
+ const lookups = {};
49
+ for (const [symbol, candles] of Object.entries(tokenCandles)) {
50
+ const lookup = /* @__PURE__ */ new Map();
51
+ for (const candle of candles) {
52
+ lookup.set(candle.t, candle);
53
+ }
54
+ lookups[symbol] = lookup;
55
+ }
56
+ return lookups;
57
+ };
58
+ const getCompleteTimestamps = (candleLookups, requiredSymbols) => {
59
+ if (requiredSymbols.length === 0) return [];
60
+ let baseSymbol;
61
+ let baseLookup;
62
+ let baseSize = Infinity;
63
+ for (const symbol of requiredSymbols) {
64
+ const lookup = candleLookups[symbol];
65
+ const size = lookup?.size ?? 0;
66
+ if (size === 0) return [];
67
+ if (size < baseSize) {
68
+ baseSize = size;
69
+ baseSymbol = symbol;
70
+ baseLookup = lookup;
71
+ }
72
+ }
73
+ if (!baseLookup || !baseSymbol) return [];
74
+ const result = [];
75
+ for (const timestamp of Array.from(baseLookup.keys())) {
76
+ let ok = true;
77
+ for (const symbol of requiredSymbols) {
78
+ if (symbol === baseSymbol) continue;
79
+ const lookup = candleLookups[symbol];
80
+ if (!lookup || !lookup.has(timestamp)) {
81
+ ok = false;
82
+ break;
83
+ }
84
+ }
85
+ if (ok) result.push(timestamp);
86
+ }
87
+ result.sort((a, b) => a - b);
88
+ return result;
89
+ };
90
+
91
+ export { createCandleLookups, createKey, getCompleteTimestamps, getIntervalSeconds, mergeRanges };
@@ -0,0 +1,29 @@
1
+ import { WsMessage } from '../../shared/types.js';
2
+ import { BaseTransport } from '../../transport/base-transport.js';
3
+ import { CandleInterval, CandleData } from '../types.js';
4
+ import '@pear-protocol/types';
5
+ import 'partysocket';
6
+ import '../../transport/index.js';
7
+
8
+ type CandleHandler = (symbol: string, candle: CandleData) => void;
9
+ declare abstract class BaseCandleWs {
10
+ protected transport: BaseTransport;
11
+ private onCandle;
12
+ private messageListenerId;
13
+ private openListenerId;
14
+ private subscribedKeys;
15
+ protected abstract buildSubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
16
+ protected abstract buildUnsubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
17
+ protected abstract parseMessage(data: string): {
18
+ symbol: string;
19
+ candle: CandleData;
20
+ } | null;
21
+ constructor(transport: BaseTransport, onCandle: CandleHandler);
22
+ start(): void;
23
+ stop(): void;
24
+ get connected(): boolean;
25
+ subscribe(symbol: string, interval: CandleInterval): void;
26
+ unsubscribe(symbol: string, interval: CandleInterval): void;
27
+ }
28
+
29
+ export { BaseCandleWs, type CandleHandler };
@@ -0,0 +1,71 @@
1
+ class BaseCandleWs {
2
+ transport;
3
+ onCandle;
4
+ messageListenerId = null;
5
+ openListenerId = null;
6
+ subscribedKeys = /* @__PURE__ */ new Set();
7
+ constructor(transport, onCandle) {
8
+ this.transport = transport;
9
+ this.onCandle = onCandle;
10
+ }
11
+ start() {
12
+ if (this.messageListenerId) return;
13
+ this.messageListenerId = this.transport.addMessageListener((data) => {
14
+ const result = this.parseMessage(data);
15
+ if (result) {
16
+ this.onCandle(result.symbol, result.candle);
17
+ }
18
+ });
19
+ this.openListenerId = this.transport.addOpenListener(() => {
20
+ for (const key of this.subscribedKeys) {
21
+ const [symbol, interval] = key.split("::");
22
+ this.transport.send(this.buildSubscribeMessage(symbol, interval));
23
+ }
24
+ });
25
+ if (!this.transport.connected) {
26
+ this.transport.connect();
27
+ }
28
+ if (this.transport.connected) {
29
+ for (const key of this.subscribedKeys) {
30
+ const [symbol, interval] = key.split("::");
31
+ this.transport.send(this.buildSubscribeMessage(symbol, interval));
32
+ }
33
+ }
34
+ }
35
+ stop() {
36
+ if (this.messageListenerId) {
37
+ this.transport.removeMessageListener(this.messageListenerId);
38
+ this.messageListenerId = null;
39
+ }
40
+ if (this.openListenerId) {
41
+ this.transport.removeOpenListener(this.openListenerId);
42
+ this.openListenerId = null;
43
+ }
44
+ for (const key of this.subscribedKeys) {
45
+ const [symbol, interval] = key.split("::");
46
+ this.transport.send(this.buildUnsubscribeMessage(symbol, interval));
47
+ }
48
+ this.subscribedKeys.clear();
49
+ }
50
+ get connected() {
51
+ return this.transport.connected;
52
+ }
53
+ subscribe(symbol, interval) {
54
+ const key = `${symbol}::${interval}`;
55
+ if (this.subscribedKeys.has(key)) return;
56
+ this.subscribedKeys.add(key);
57
+ if (this.transport.connected) {
58
+ this.transport.send(this.buildSubscribeMessage(symbol, interval));
59
+ }
60
+ }
61
+ unsubscribe(symbol, interval) {
62
+ const key = `${symbol}::${interval}`;
63
+ if (!this.subscribedKeys.has(key)) return;
64
+ this.subscribedKeys.delete(key);
65
+ if (this.transport.connected) {
66
+ this.transport.send(this.buildUnsubscribeMessage(symbol, interval));
67
+ }
68
+ }
69
+ }
70
+
71
+ export { BaseCandleWs };
@@ -0,0 +1,19 @@
1
+ import { WsMessage } from '../../shared/types.js';
2
+ import { CandleInterval, CandleData } from '../types.js';
3
+ import { BaseCandleWs } from './base-candle.js';
4
+ import '../../transport/index.js';
5
+ import '@pear-protocol/types';
6
+ import '../../transport/base-transport.js';
7
+ import 'partysocket';
8
+
9
+ declare class BinanceCandleWs extends BaseCandleWs {
10
+ private idCounter;
11
+ protected buildSubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
12
+ protected buildUnsubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
13
+ protected parseMessage(data: string): {
14
+ symbol: string;
15
+ candle: CandleData;
16
+ } | null;
17
+ }
18
+
19
+ export { BinanceCandleWs };
@@ -0,0 +1,43 @@
1
+ import { BaseCandleWs } from './base-candle';
2
+
3
+ const toStreamName = (symbol, interval) => `${symbol.toLowerCase()}@kline_${interval}`;
4
+ class BinanceCandleWs extends BaseCandleWs {
5
+ idCounter = 1;
6
+ buildSubscribeMessage(symbol, interval) {
7
+ return {
8
+ method: "SUBSCRIBE",
9
+ params: [toStreamName(symbol, interval)],
10
+ id: this.idCounter++
11
+ };
12
+ }
13
+ buildUnsubscribeMessage(symbol, interval) {
14
+ return {
15
+ method: "UNSUBSCRIBE",
16
+ params: [toStreamName(symbol, interval)],
17
+ id: this.idCounter++
18
+ };
19
+ }
20
+ parseMessage(data) {
21
+ let msg;
22
+ try {
23
+ msg = JSON.parse(data);
24
+ } catch {
25
+ return null;
26
+ }
27
+ if (msg.e !== "kline" || !msg.k) return null;
28
+ const k = msg.k;
29
+ return {
30
+ symbol: k.s,
31
+ candle: {
32
+ t: k.t,
33
+ T: k.T,
34
+ o: Number(k.o),
35
+ h: Number(k.h),
36
+ l: Number(k.l),
37
+ c: Number(k.c)
38
+ }
39
+ };
40
+ }
41
+ }
42
+
43
+ export { BinanceCandleWs };
@@ -0,0 +1,18 @@
1
+ import { WsMessage } from '../../shared/types.js';
2
+ import { CandleInterval, CandleData } from '../types.js';
3
+ import { BaseCandleWs } from './base-candle.js';
4
+ import '../../transport/index.js';
5
+ import '@pear-protocol/types';
6
+ import '../../transport/base-transport.js';
7
+ import 'partysocket';
8
+
9
+ declare class BybitCandleWs extends BaseCandleWs {
10
+ protected buildSubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
11
+ protected buildUnsubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
12
+ protected parseMessage(data: string): {
13
+ symbol: string;
14
+ candle: CandleData;
15
+ } | null;
16
+ }
17
+
18
+ export { BybitCandleWs };
@@ -0,0 +1,63 @@
1
+ import { BaseCandleWs } from './base-candle';
2
+
3
+ const intervalMap = {
4
+ "1m": "1",
5
+ "3m": "3",
6
+ "5m": "5",
7
+ "15m": "15",
8
+ "30m": "30",
9
+ "1h": "60",
10
+ "2h": "120",
11
+ "4h": "240",
12
+ "8h": "480",
13
+ "12h": "720",
14
+ "1d": "D",
15
+ "3d": "D",
16
+ "1w": "W",
17
+ "1M": "M"
18
+ };
19
+ const toTopic = (symbol, interval) => `kline.${intervalMap[interval]}.${symbol}`;
20
+ const fromTopic = (topic) => {
21
+ const parts = topic.split(".");
22
+ return parts[2] ?? "";
23
+ };
24
+ class BybitCandleWs extends BaseCandleWs {
25
+ buildSubscribeMessage(symbol, interval) {
26
+ return {
27
+ op: "subscribe",
28
+ args: [toTopic(symbol, interval)]
29
+ };
30
+ }
31
+ buildUnsubscribeMessage(symbol, interval) {
32
+ return {
33
+ op: "unsubscribe",
34
+ args: [toTopic(symbol, interval)]
35
+ };
36
+ }
37
+ parseMessage(data) {
38
+ let msg;
39
+ try {
40
+ msg = JSON.parse(data);
41
+ } catch {
42
+ return null;
43
+ }
44
+ const topic = msg.topic;
45
+ const msgData = msg.data;
46
+ if (!topic || !msgData || !Array.isArray(msgData) || msgData.length === 0) return null;
47
+ if (!topic.startsWith("kline.")) return null;
48
+ const d = msgData[0];
49
+ return {
50
+ symbol: fromTopic(topic),
51
+ candle: {
52
+ t: d.start,
53
+ T: d.end,
54
+ o: Number(d.open),
55
+ h: Number(d.high),
56
+ l: Number(d.low),
57
+ c: Number(d.close)
58
+ }
59
+ };
60
+ }
61
+ }
62
+
63
+ export { BybitCandleWs };
@@ -0,0 +1,31 @@
1
+ import { WsMessage } from '../../shared/types.js';
2
+ import { CandleInterval, CandleData } from '../types.js';
3
+ import { BaseCandleWs } from './base-candle.js';
4
+ import '../../transport/index.js';
5
+ import '@pear-protocol/types';
6
+ import '../../transport/base-transport.js';
7
+ import 'partysocket';
8
+
9
+ interface HyperliquidCandleSubscription {
10
+ type: 'candle';
11
+ coin: string;
12
+ interval: CandleInterval;
13
+ }
14
+ interface HyperliquidSubscribeMessage extends WsMessage {
15
+ method: 'subscribe';
16
+ subscription: HyperliquidCandleSubscription;
17
+ }
18
+ interface HyperliquidUnsubscribeMessage extends WsMessage {
19
+ method: 'unsubscribe';
20
+ subscription: HyperliquidCandleSubscription;
21
+ }
22
+ declare class HyperliquidCandleWs extends BaseCandleWs {
23
+ protected buildSubscribeMessage(symbol: string, interval: CandleInterval): HyperliquidSubscribeMessage;
24
+ protected buildUnsubscribeMessage(symbol: string, interval: CandleInterval): HyperliquidUnsubscribeMessage;
25
+ protected parseMessage(data: string): {
26
+ symbol: string;
27
+ candle: CandleData;
28
+ } | null;
29
+ }
30
+
31
+ export { HyperliquidCandleWs };
@@ -0,0 +1,40 @@
1
+ import { BaseCandleWs } from './base-candle';
2
+
3
+ class HyperliquidCandleWs extends BaseCandleWs {
4
+ buildSubscribeMessage(symbol, interval) {
5
+ return {
6
+ method: "subscribe",
7
+ subscription: { type: "candle", coin: symbol, interval }
8
+ };
9
+ }
10
+ buildUnsubscribeMessage(symbol, interval) {
11
+ return {
12
+ method: "unsubscribe",
13
+ subscription: { type: "candle", coin: symbol, interval }
14
+ };
15
+ }
16
+ parseMessage(data) {
17
+ let msg;
18
+ try {
19
+ msg = JSON.parse(data);
20
+ } catch {
21
+ return null;
22
+ }
23
+ if (msg.channel !== "candle" || !msg.data) return null;
24
+ const d = msg.data;
25
+ return {
26
+ symbol: d.s,
27
+ candle: {
28
+ s: d.s,
29
+ t: d.t,
30
+ T: d.T,
31
+ o: Number(d.o),
32
+ h: Number(d.h),
33
+ l: Number(d.l),
34
+ c: Number(d.c)
35
+ }
36
+ };
37
+ }
38
+ }
39
+
40
+ export { HyperliquidCandleWs };
@@ -0,0 +1,11 @@
1
+ import { Connector } from '@pear-protocol/types';
2
+ import { BaseTransport } from '../../transport/base-transport.js';
3
+ import { CandleHandler, BaseCandleWs } from './base-candle.js';
4
+ import 'partysocket';
5
+ import '../../shared/types.js';
6
+ import '../types.js';
7
+ import '../../transport/index.js';
8
+
9
+ declare function createCandleWs(transport: BaseTransport, connector: Connector, onCandle: CandleHandler): BaseCandleWs;
10
+
11
+ export { BaseCandleWs, CandleHandler, createCandleWs };
@@ -0,0 +1,24 @@
1
+ export { BaseCandleWs } from './base-candle';
2
+ import { BinanceCandleWs } from './binance';
3
+ import { BybitCandleWs } from './bybit';
4
+ import { HyperliquidCandleWs } from './hyperliquid';
5
+ import { OkxCandleWs } from './okx';
6
+
7
+ function createCandleWs(transport, connector, onCandle) {
8
+ switch (connector) {
9
+ case "hyperliquid":
10
+ return new HyperliquidCandleWs(transport, onCandle);
11
+ case "binance":
12
+ return new BinanceCandleWs(transport, onCandle);
13
+ case "bybit":
14
+ return new BybitCandleWs(transport, onCandle);
15
+ case "okx":
16
+ return new OkxCandleWs(transport, onCandle);
17
+ default: {
18
+ const _exhaustive = connector;
19
+ throw new Error(`Unsupported exchange: ${String(_exhaustive)}`);
20
+ }
21
+ }
22
+ }
23
+
24
+ export { createCandleWs };
@@ -0,0 +1,18 @@
1
+ import { WsMessage } from '../../shared/types.js';
2
+ import { CandleInterval, CandleData } from '../types.js';
3
+ import { BaseCandleWs } from './base-candle.js';
4
+ import '../../transport/index.js';
5
+ import '@pear-protocol/types';
6
+ import '../../transport/base-transport.js';
7
+ import 'partysocket';
8
+
9
+ declare class OkxCandleWs extends BaseCandleWs {
10
+ protected buildSubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
11
+ protected buildUnsubscribeMessage(symbol: string, interval: CandleInterval): WsMessage;
12
+ protected parseMessage(data: string): {
13
+ symbol: string;
14
+ candle: CandleData;
15
+ } | null;
16
+ }
17
+
18
+ export { OkxCandleWs };