@pear-protocol/market-sdk 0.0.4 → 0.0.6
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 +137 -12
- package/dist/funding-rate/fetcher/binance.d.ts +10 -0
- package/dist/funding-rate/fetcher/binance.js +26 -0
- package/dist/funding-rate/fetcher/bybit.d.ts +10 -0
- package/dist/funding-rate/fetcher/bybit.js +32 -0
- package/dist/funding-rate/fetcher/http-client.d.ts +5 -0
- package/dist/funding-rate/fetcher/http-client.js +40 -0
- package/dist/funding-rate/fetcher/hyperliquid.d.ts +10 -0
- package/dist/funding-rate/fetcher/hyperliquid.js +25 -0
- package/dist/funding-rate/fetcher/index.d.ts +10 -0
- package/dist/funding-rate/fetcher/index.js +24 -0
- package/dist/funding-rate/fetcher/lighter.d.ts +10 -0
- package/dist/funding-rate/fetcher/lighter.js +35 -0
- package/dist/funding-rate/fetcher/okx.d.ts +10 -0
- package/dist/funding-rate/fetcher/okx.js +33 -0
- package/dist/funding-rate/funding-rate.d.ts +28 -0
- package/dist/funding-rate/funding-rate.js +117 -0
- package/dist/funding-rate/types.d.ts +29 -0
- package/dist/funding-rate/types.js +1 -0
- package/dist/funding-rate/utils.d.ts +13 -0
- package/dist/funding-rate/utils.js +120 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @pear-protocol/market-sdk
|
|
2
2
|
|
|
3
|
-
SDK for real-time market data across cryptocurrency derivative exchanges. Provides charting with multiple visualization modes (weighted ratio, price ratio, performance)
|
|
3
|
+
SDK for real-time market data across cryptocurrency derivative exchanges. Provides charting with multiple visualization modes (weighted ratio, price ratio, performance), aggregated order book depth, and historical funding rate analysis through a unified, exchange-agnostic interface.
|
|
4
4
|
|
|
5
5
|
## Supported Exchanges
|
|
6
6
|
|
|
@@ -10,6 +10,7 @@ SDK for real-time market data across cryptocurrency derivative exchanges. Provid
|
|
|
10
10
|
| Bybit | `bybit` |
|
|
11
11
|
| Hyperliquid | `hyperliquid` |
|
|
12
12
|
| OKX | `okx` |
|
|
13
|
+
| Lighter | `lighter` |
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -20,7 +21,7 @@ npm install @pear-protocol/market-sdk
|
|
|
20
21
|
## Quick Start
|
|
21
22
|
|
|
22
23
|
```typescript
|
|
23
|
-
import { Chart, Orderbook, CreateTransport } from '@pear-protocol/market-sdk';
|
|
24
|
+
import { Chart, FundingRate, Orderbook, CreateTransport } from '@pear-protocol/market-sdk';
|
|
24
25
|
|
|
25
26
|
const transport = CreateTransport('hyperliquid');
|
|
26
27
|
|
|
@@ -38,6 +39,17 @@ const subId = chart.subscribeRealtimeBars('weighted-ratio', (bar) => {
|
|
|
38
39
|
console.log(bar.time, bar.open, bar.high, bar.low, bar.close);
|
|
39
40
|
});
|
|
40
41
|
|
|
42
|
+
// Funding rates
|
|
43
|
+
const fundingRate = new FundingRate({
|
|
44
|
+
transport,
|
|
45
|
+
longTokens: [{ symbol: 'ETH', weight: 0.6 }],
|
|
46
|
+
shortTokens: [{ symbol: 'BTC', weight: 0.4 }],
|
|
47
|
+
interval: '1d',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const rates = await fundingRate.getAssetRates('ETH');
|
|
51
|
+
const basketRates = await fundingRate.getBasketRates();
|
|
52
|
+
|
|
41
53
|
// Order book
|
|
42
54
|
const orderbook = new Orderbook({
|
|
43
55
|
transport,
|
|
@@ -53,6 +65,7 @@ orderbook.subscribe((snapshot) => {
|
|
|
53
65
|
// Cleanup
|
|
54
66
|
chart.unsubscribeRealtimeBars(subId);
|
|
55
67
|
chart.destroy();
|
|
68
|
+
fundingRate.destroy();
|
|
56
69
|
orderbook.destroy();
|
|
57
70
|
transport.destroy();
|
|
58
71
|
```
|
|
@@ -299,21 +312,133 @@ orderbook.destroy();
|
|
|
299
312
|
|
|
300
313
|
The underlying transport is owned by the caller and must be destroyed separately.
|
|
301
314
|
|
|
302
|
-
##
|
|
315
|
+
## Funding Rate
|
|
303
316
|
|
|
304
|
-
|
|
317
|
+
### Initialization
|
|
305
318
|
|
|
306
319
|
```typescript
|
|
307
|
-
import { CreateTransport } from '@pear-protocol/market-sdk';
|
|
320
|
+
import { FundingRate, CreateTransport } from '@pear-protocol/market-sdk';
|
|
308
321
|
|
|
309
322
|
const transport = CreateTransport('hyperliquid');
|
|
310
323
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
324
|
+
const fundingRate = new FundingRate({
|
|
325
|
+
transport,
|
|
326
|
+
longTokens: [{ symbol: 'ETH', weight: 0.6 }],
|
|
327
|
+
shortTokens: [{ symbol: 'BTC', weight: 0.4 }],
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### `FundingRateConfig`
|
|
332
|
+
|
|
333
|
+
| Field | Type | Default | Description |
|
|
334
|
+
|-------|------|---------|-------------|
|
|
335
|
+
| `transport` | `Transport` | — | Transport instance (used to determine the exchange) |
|
|
336
|
+
| `longTokens` | `TokenSelection[]` | `[]` | Tokens on the long side with weights |
|
|
337
|
+
| `shortTokens` | `TokenSelection[]` | `[]` | Tokens on the short side with weights |
|
|
338
|
+
|
|
339
|
+
### Aggregation and Duration
|
|
340
|
+
|
|
341
|
+
Aggregation level and lookback duration are passed per call to `getAssetRates` and `getBasketRates`.
|
|
342
|
+
|
|
343
|
+
#### `FundingRateAggregation`
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
'none' | '1d' | '1w' | '1M'
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
When set to `'none'`, raw funding rates are returned at each exchange's native settlement frequency (1h for Hyperliquid, 8h for Binance/Bybit/OKX). For `'1d'`, `'1w'`, and `'1M'`, rates are summed within each period.
|
|
350
|
+
|
|
351
|
+
#### `FundingRateDuration`
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
'1w' | '1m' | '1y'
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
The lookback window for fetching data, ending at the current time.
|
|
358
|
+
|
|
359
|
+
#### Minimum Duration per Aggregation
|
|
360
|
+
|
|
361
|
+
To avoid returning too few data points, each aggregation level enforces a minimum duration. If the requested duration is shorter than the minimum, it is automatically bumped up.
|
|
362
|
+
|
|
363
|
+
| Aggregation | Minimum Duration |
|
|
364
|
+
|-------------|------------------|
|
|
365
|
+
| `'none'` | `'1w'` |
|
|
366
|
+
| `'1d'` | `'1m'` |
|
|
367
|
+
| `'1w'` | `'1y'` |
|
|
368
|
+
| `'1M'` | `'1y'` |
|
|
369
|
+
|
|
370
|
+
### Per-Asset Funding Rates
|
|
371
|
+
|
|
372
|
+
Fetch funding rates for a single token.
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
// Defaults: aggregation='none', duration='1m'
|
|
376
|
+
const rates = await fundingRate.getAssetRates('ETH');
|
|
377
|
+
|
|
378
|
+
// Daily aggregation over the last year
|
|
379
|
+
const dailyRates = await fundingRate.getAssetRates('ETH', '1d', '1y');
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### Signature
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
getAssetRates(
|
|
386
|
+
symbol: string,
|
|
387
|
+
aggregation?: FundingRateAggregation, // default: 'none'
|
|
388
|
+
duration?: FundingRateDuration, // default: '1m'
|
|
389
|
+
): Promise<FundingRateEntry[]>
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Basket Funding Rates
|
|
393
|
+
|
|
394
|
+
Compute the weighted net funding rate across all configured tokens. Positive rate = user earns funding, negative = user pays.
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
const basketRates = await fundingRate.getBasketRates();
|
|
398
|
+
|
|
399
|
+
const monthlyBasket = await fundingRate.getBasketRates('1M', '1y');
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
The net rate at each time point is calculated as:
|
|
314
403
|
|
|
315
|
-
// Cleanup — destroy transport after all consumers
|
|
316
|
-
chart.destroy();
|
|
317
|
-
orderbook.destroy();
|
|
318
|
-
transport.destroy();
|
|
319
404
|
```
|
|
405
|
+
netRate = sum(shortWeight × rate) - sum(longWeight × rate)
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Only time points where all tokens have data are included.
|
|
409
|
+
|
|
410
|
+
#### Signature
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
getBasketRates(
|
|
414
|
+
aggregation?: FundingRateAggregation, // default: 'none'
|
|
415
|
+
duration?: FundingRateDuration, // default: '1m'
|
|
416
|
+
): Promise<FundingRateEntry[]>
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### `FundingRateEntry`
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
{
|
|
423
|
+
time: number; // bucket start timestamp (ms)
|
|
424
|
+
rate: number; // summed rate for the bucket (raw rate when aggregation='none')
|
|
425
|
+
annualizedRate?: number; // rate annualized to a yearly figure
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
For fixed aggregations the annualization multiplier is `365` (`1d`), `52` (`1w`), or `12` (`1M`). For `'none'`, the multiplier is inferred from the average gap between raw entries (`MS_PER_YEAR / avgGapMs`); if there are fewer than two entries to infer from, `annualizedRate` is omitted.
|
|
430
|
+
|
|
431
|
+
### Updating Tokens
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
fundingRate.setTokens(
|
|
435
|
+
[{ symbol: 'ETH', weight: 0.5 }, { symbol: 'SOL', weight: 0.5 }],
|
|
436
|
+
[{ symbol: 'BTC', weight: 1.0 }],
|
|
437
|
+
);
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Cleanup
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
fundingRate.destroy();
|
|
444
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FundingRateEntry } 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 function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
|
|
9
|
+
|
|
10
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { httpGet } from './http-client';
|
|
2
|
+
|
|
3
|
+
const BINANCE_FUTURES_URL = "https://fapi.binance.com/fapi/v1/fundingRate";
|
|
4
|
+
const MAX_LIMIT = 1e3;
|
|
5
|
+
async function fetchHistoricalFundingRates(symbol, startTime, endTime) {
|
|
6
|
+
const allRates = [];
|
|
7
|
+
let cursor = startTime;
|
|
8
|
+
while (cursor < endTime) {
|
|
9
|
+
const data = await httpGet(BINANCE_FUTURES_URL, {
|
|
10
|
+
symbol,
|
|
11
|
+
startTime: String(cursor),
|
|
12
|
+
endTime: String(endTime),
|
|
13
|
+
limit: String(MAX_LIMIT)
|
|
14
|
+
});
|
|
15
|
+
if (data.length === 0) break;
|
|
16
|
+
for (const entry of data) {
|
|
17
|
+
allRates.push({ time: entry.fundingTime, rate: Number(entry.fundingRate) });
|
|
18
|
+
}
|
|
19
|
+
const lastTime = data[data.length - 1]?.fundingTime;
|
|
20
|
+
if (!lastTime || lastTime <= cursor) break;
|
|
21
|
+
cursor = lastTime + 1;
|
|
22
|
+
}
|
|
23
|
+
return allRates.sort((a, b) => a.time - b.time);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FundingRateEntry } 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 function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
|
|
9
|
+
|
|
10
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { httpGet } from './http-client';
|
|
2
|
+
|
|
3
|
+
const BYBIT_URL = "https://api.bybit.com/v5/market/funding/history";
|
|
4
|
+
const MAX_LIMIT = 200;
|
|
5
|
+
async function fetchHistoricalFundingRates(symbol, startTime, endTime) {
|
|
6
|
+
const allRates = [];
|
|
7
|
+
let cursor = endTime;
|
|
8
|
+
const validate = (d) => d.retCode !== 0 ? `Bybit API error: ${d.retMsg}` : void 0;
|
|
9
|
+
while (cursor > startTime) {
|
|
10
|
+
const data = await httpGet(
|
|
11
|
+
BYBIT_URL,
|
|
12
|
+
{
|
|
13
|
+
category: "linear",
|
|
14
|
+
symbol,
|
|
15
|
+
startTime: String(startTime),
|
|
16
|
+
endTime: String(cursor),
|
|
17
|
+
limit: String(MAX_LIMIT)
|
|
18
|
+
},
|
|
19
|
+
validate
|
|
20
|
+
);
|
|
21
|
+
if (data.result.list.length === 0) break;
|
|
22
|
+
for (const entry of data.result.list) {
|
|
23
|
+
allRates.push({ time: Number(entry.fundingRateTimestamp), rate: Number(entry.fundingRate) });
|
|
24
|
+
}
|
|
25
|
+
const oldestTime = Number(data.result.list[data.result.list.length - 1]?.fundingRateTimestamp);
|
|
26
|
+
if (!oldestTime || oldestTime >= cursor) break;
|
|
27
|
+
cursor = oldestTime - 1;
|
|
28
|
+
}
|
|
29
|
+
return allRates.sort((a, b) => a.time - b.time);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type ResponseValidator<T> = (data: T) => string | undefined;
|
|
2
|
+
declare function httpGet<T>(url: string, params: Record<string, string>, validate?: ResponseValidator<T>): Promise<T>;
|
|
3
|
+
declare function httpPost<T>(url: string, body: unknown, validate?: ResponseValidator<T>): Promise<T>;
|
|
4
|
+
|
|
5
|
+
export { type ResponseValidator, httpGet, httpPost };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const BASE_DELAY_MS = 1e3;
|
|
2
|
+
const MAX_DELAY_MS = 6e4;
|
|
3
|
+
async function httpGet(url, params, validate) {
|
|
4
|
+
const qs = new URLSearchParams(params).toString();
|
|
5
|
+
return httpFetch(`${url}?${qs}`, void 0, validate);
|
|
6
|
+
}
|
|
7
|
+
async function httpPost(url, body, validate) {
|
|
8
|
+
return httpFetch(
|
|
9
|
+
url,
|
|
10
|
+
{
|
|
11
|
+
method: "POST",
|
|
12
|
+
headers: { "Content-Type": "application/json" },
|
|
13
|
+
body: JSON.stringify(body)
|
|
14
|
+
},
|
|
15
|
+
validate
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
async function httpFetch(url, init, validate) {
|
|
19
|
+
let attempt = 0;
|
|
20
|
+
while (true) {
|
|
21
|
+
const response = await fetch(url, init);
|
|
22
|
+
if (response.status === 429) {
|
|
23
|
+
const delay = Math.min(BASE_DELAY_MS * 2 ** attempt, MAX_DELAY_MS);
|
|
24
|
+
attempt++;
|
|
25
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`HTTP ${response.status} ${response.statusText} from ${url}`);
|
|
30
|
+
}
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
if (validate) {
|
|
33
|
+
const error = validate(data);
|
|
34
|
+
if (error) throw new Error(error);
|
|
35
|
+
}
|
|
36
|
+
return data;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { httpGet, httpPost };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FundingRateEntry } 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 function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
|
|
9
|
+
|
|
10
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { httpPost } from './http-client';
|
|
2
|
+
|
|
3
|
+
async function fetchHistoricalFundingRates(symbol, startTime, endTime) {
|
|
4
|
+
const allRates = [];
|
|
5
|
+
let cursor = startTime;
|
|
6
|
+
while (cursor < endTime) {
|
|
7
|
+
const data = await httpPost("https://api.hyperliquid.xyz/info", {
|
|
8
|
+
type: "fundingHistory",
|
|
9
|
+
coin: symbol,
|
|
10
|
+
startTime: cursor,
|
|
11
|
+
endTime
|
|
12
|
+
});
|
|
13
|
+
if (data.length === 0) break;
|
|
14
|
+
for (const entry of data) {
|
|
15
|
+
if (entry.time >= endTime) continue;
|
|
16
|
+
allRates.push({ time: entry.time, rate: Number(entry.fundingRate) });
|
|
17
|
+
}
|
|
18
|
+
const lastTime = data[data.length - 1]?.time;
|
|
19
|
+
if (!lastTime || lastTime <= cursor) break;
|
|
20
|
+
cursor = lastTime + 1;
|
|
21
|
+
}
|
|
22
|
+
return allRates.sort((a, b) => a.time - b.time);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Connector } from '@pear-protocol/types';
|
|
2
|
+
import { FundingRateDuration, FundingRateEntry } from '../types.js';
|
|
3
|
+
import '../../transport/index.js';
|
|
4
|
+
import '../../transport/base-transport.js';
|
|
5
|
+
import 'partysocket';
|
|
6
|
+
import '../../shared/types.js';
|
|
7
|
+
|
|
8
|
+
declare function fetchHistoricalFundingRates(connector: Connector, symbol: string, startTime: number, endTime: number, duration: FundingRateDuration): Promise<FundingRateEntry[]>;
|
|
9
|
+
|
|
10
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { fetchHistoricalFundingRates as fetchHistoricalFundingRates$4 } from './binance';
|
|
2
|
+
import { fetchHistoricalFundingRates as fetchHistoricalFundingRates$3 } from './bybit';
|
|
3
|
+
import { fetchHistoricalFundingRates as fetchHistoricalFundingRates$5 } from './hyperliquid';
|
|
4
|
+
import { fetchHistoricalFundingRates as fetchHistoricalFundingRates$1 } from './lighter';
|
|
5
|
+
import { fetchHistoricalFundingRates as fetchHistoricalFundingRates$2 } from './okx';
|
|
6
|
+
|
|
7
|
+
async function fetchHistoricalFundingRates(connector, symbol, startTime, endTime, duration) {
|
|
8
|
+
switch (connector) {
|
|
9
|
+
case "hyperliquid":
|
|
10
|
+
return fetchHistoricalFundingRates$5(symbol, startTime, endTime);
|
|
11
|
+
case "binance":
|
|
12
|
+
return fetchHistoricalFundingRates$4(symbol, startTime, endTime);
|
|
13
|
+
case "bybit":
|
|
14
|
+
return fetchHistoricalFundingRates$3(symbol, startTime, endTime);
|
|
15
|
+
case "okx":
|
|
16
|
+
return fetchHistoricalFundingRates$2(symbol, startTime, endTime);
|
|
17
|
+
case "lighter":
|
|
18
|
+
return fetchHistoricalFundingRates$1(symbol, startTime, endTime, duration);
|
|
19
|
+
default:
|
|
20
|
+
throw new Error(`Unsupported connector: ${connector}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FundingRateDuration, FundingRateEntry } 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 function fetchHistoricalFundingRates(symbol: string, startTime: number, endTime: number, _duration: FundingRateDuration): Promise<FundingRateEntry[]>;
|
|
9
|
+
|
|
10
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import BigNumber from 'bignumber.js';
|
|
2
|
+
import { httpGet } from './http-client';
|
|
3
|
+
|
|
4
|
+
const BASE_URL = "https://mainnet.zklighter.elliot.ai";
|
|
5
|
+
const MAX_LIMIT = 500;
|
|
6
|
+
async function fetchHistoricalFundingRates(symbol, startTime, endTime, _duration) {
|
|
7
|
+
const intervalMs = 60 * 60 * 1e3;
|
|
8
|
+
const allRates = [];
|
|
9
|
+
let cursor = startTime;
|
|
10
|
+
while (cursor < endTime) {
|
|
11
|
+
const countBack = Math.min(Math.ceil((endTime - cursor) / intervalMs) + 1, MAX_LIMIT);
|
|
12
|
+
const data = await httpGet(`${BASE_URL}/api/v1/fundings`, {
|
|
13
|
+
market_id: symbol,
|
|
14
|
+
resolution: "1h",
|
|
15
|
+
start_timestamp: String(cursor),
|
|
16
|
+
end_timestamp: String(endTime),
|
|
17
|
+
count_back: String(countBack)
|
|
18
|
+
});
|
|
19
|
+
const entries = data.fundings ?? [];
|
|
20
|
+
if (entries.length === 0) break;
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
const timeMs = entry.timestamp * 1e3;
|
|
23
|
+
const rate = entry.rate ? new BigNumber(entry.rate).dividedBy(100).times(entry.direction === "long" ? -1 : 1).toNumber() : 0;
|
|
24
|
+
allRates.push({ time: timeMs, rate });
|
|
25
|
+
}
|
|
26
|
+
const lastTimestamp = entries[entries.length - 1]?.timestamp;
|
|
27
|
+
if (!lastTimestamp) break;
|
|
28
|
+
const lastTimeMs = lastTimestamp * 1e3;
|
|
29
|
+
if (lastTimeMs <= cursor) break;
|
|
30
|
+
cursor = lastTimeMs + 1;
|
|
31
|
+
}
|
|
32
|
+
return allRates.sort((a, b) => a.time - b.time);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FundingRateEntry } 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 function fetchHistoricalFundingRates(instId: string, startTime: number, endTime: number): Promise<FundingRateEntry[]>;
|
|
9
|
+
|
|
10
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { httpGet } from './http-client';
|
|
2
|
+
|
|
3
|
+
const OKX_URL = "https://www.okx.com/api/v5/public/funding-rate-history";
|
|
4
|
+
const MAX_LIMIT = 400;
|
|
5
|
+
async function fetchHistoricalFundingRates(instId, startTime, endTime) {
|
|
6
|
+
const allRates = [];
|
|
7
|
+
let cursor = endTime;
|
|
8
|
+
const validate = (d) => d.code !== "0" ? `OKX API error: ${d.msg}` : void 0;
|
|
9
|
+
while (cursor > startTime) {
|
|
10
|
+
const data = await httpGet(
|
|
11
|
+
OKX_URL,
|
|
12
|
+
{
|
|
13
|
+
instId,
|
|
14
|
+
before: String(startTime),
|
|
15
|
+
after: String(cursor),
|
|
16
|
+
limit: String(MAX_LIMIT)
|
|
17
|
+
},
|
|
18
|
+
validate
|
|
19
|
+
);
|
|
20
|
+
if (data.data.length === 0) break;
|
|
21
|
+
let oldestTime = Infinity;
|
|
22
|
+
for (const entry of data.data) {
|
|
23
|
+
const time = Number(entry.fundingTime);
|
|
24
|
+
allRates.push({ time, rate: Number(entry.realizedRate) });
|
|
25
|
+
if (time < oldestTime) oldestTime = time;
|
|
26
|
+
}
|
|
27
|
+
if (oldestTime >= cursor) break;
|
|
28
|
+
cursor = oldestTime - 1;
|
|
29
|
+
}
|
|
30
|
+
return allRates.filter((r) => r.time >= startTime && r.time < endTime).sort((a, b) => a.time - b.time);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { fetchHistoricalFundingRates };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { FundingRateConfig, TokenSelection, FundingRateAggregation, FundingRateDuration, FundingRateEntry } 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 class FundingRate {
|
|
9
|
+
private transport;
|
|
10
|
+
private longTokens;
|
|
11
|
+
private shortTokens;
|
|
12
|
+
private cache;
|
|
13
|
+
constructor(config: FundingRateConfig);
|
|
14
|
+
setTokens(longTokens: TokenSelection[], shortTokens: TokenSelection[]): void;
|
|
15
|
+
clearCache(): void;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
getAssetRates(symbol: string, aggregation?: FundingRateAggregation, duration?: FundingRateDuration): Promise<FundingRateEntry[]>;
|
|
18
|
+
getBasketRates(aggregation?: FundingRateAggregation, duration?: FundingRateDuration): Promise<FundingRateEntry[]>;
|
|
19
|
+
private resolveAggregation;
|
|
20
|
+
private loadRates;
|
|
21
|
+
private getUncachedTokens;
|
|
22
|
+
private sliceCache;
|
|
23
|
+
private refetch;
|
|
24
|
+
private getAllTokens;
|
|
25
|
+
private assertTokenExists;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { FundingRate };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { fetchHistoricalFundingRates } from './fetcher';
|
|
2
|
+
import { aggregateRates, annualizeRates, computeBasketRates, computeStartTime } from './utils';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_AGGREGATION = "1d";
|
|
5
|
+
const DEFAULT_DURATION = "1m";
|
|
6
|
+
class FundingRate {
|
|
7
|
+
transport;
|
|
8
|
+
longTokens;
|
|
9
|
+
shortTokens;
|
|
10
|
+
cache = {};
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.transport = config.transport;
|
|
13
|
+
this.longTokens = config.longTokens ?? [];
|
|
14
|
+
this.shortTokens = config.shortTokens ?? [];
|
|
15
|
+
}
|
|
16
|
+
setTokens(longTokens, shortTokens) {
|
|
17
|
+
const prevSymbols = new Set(this.getAllTokens().map((t) => t.symbol));
|
|
18
|
+
this.longTokens = longTokens;
|
|
19
|
+
this.shortTokens = shortTokens;
|
|
20
|
+
const nextSymbols = new Set(this.getAllTokens().map((t) => t.symbol));
|
|
21
|
+
for (const symbol of Object.keys(this.cache)) {
|
|
22
|
+
if (!nextSymbols.has(symbol)) {
|
|
23
|
+
delete this.cache[symbol];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
for (const symbol of nextSymbols) {
|
|
27
|
+
if (!prevSymbols.has(symbol)) {
|
|
28
|
+
delete this.cache[symbol];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
clearCache() {
|
|
33
|
+
this.cache = {};
|
|
34
|
+
}
|
|
35
|
+
destroy() {
|
|
36
|
+
this.clearCache();
|
|
37
|
+
}
|
|
38
|
+
async getAssetRates(symbol, aggregation = DEFAULT_AGGREGATION, duration = DEFAULT_DURATION) {
|
|
39
|
+
this.assertTokenExists(symbol);
|
|
40
|
+
const resolvedAgg = this.resolveAggregation(aggregation, duration);
|
|
41
|
+
const rawByToken = await this.loadRates(duration);
|
|
42
|
+
const raw = rawByToken[symbol] ?? [];
|
|
43
|
+
const aggregated = aggregateRates(raw, resolvedAgg);
|
|
44
|
+
return annualizeRates(aggregated, resolvedAgg, raw);
|
|
45
|
+
}
|
|
46
|
+
async getBasketRates(aggregation = DEFAULT_AGGREGATION, duration = DEFAULT_DURATION) {
|
|
47
|
+
const resolvedAgg = this.resolveAggregation(aggregation, duration);
|
|
48
|
+
const rawByToken = await this.loadRates(duration);
|
|
49
|
+
const aggregatedByToken = {};
|
|
50
|
+
for (const [symbol, entries] of Object.entries(rawByToken)) {
|
|
51
|
+
aggregatedByToken[symbol] = aggregateRates(entries, resolvedAgg);
|
|
52
|
+
}
|
|
53
|
+
const basket = computeBasketRates(this.longTokens, this.shortTokens, aggregatedByToken);
|
|
54
|
+
const rawSample = Object.values(rawByToken)[0];
|
|
55
|
+
return annualizeRates(basket, resolvedAgg, rawSample);
|
|
56
|
+
}
|
|
57
|
+
resolveAggregation(aggregation, duration) {
|
|
58
|
+
if (duration === "1y" && aggregation === "none") return "1d";
|
|
59
|
+
return aggregation;
|
|
60
|
+
}
|
|
61
|
+
async loadRates(duration) {
|
|
62
|
+
const end = Math.floor(Date.now() / 36e5) * 36e5;
|
|
63
|
+
const start = computeStartTime(end, duration);
|
|
64
|
+
const uncached = this.getUncachedTokens(start, end);
|
|
65
|
+
if (uncached.length > 0) {
|
|
66
|
+
await this.refetch(uncached, start, end, duration);
|
|
67
|
+
}
|
|
68
|
+
return this.sliceCache(start, end);
|
|
69
|
+
}
|
|
70
|
+
getUncachedTokens(start, end) {
|
|
71
|
+
return this.getAllTokens().filter((t) => {
|
|
72
|
+
const cached = this.cache[t.symbol];
|
|
73
|
+
if (!cached) return true;
|
|
74
|
+
return cached.start > start || cached.end < end;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
sliceCache(start, end) {
|
|
78
|
+
const result = {};
|
|
79
|
+
for (const [symbol, cached] of Object.entries(this.cache)) {
|
|
80
|
+
result[symbol] = cached.entries.filter((r) => r.time >= start && r.time <= end);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
async refetch(tokens, start, end, duration) {
|
|
85
|
+
if (tokens.length === 0) return;
|
|
86
|
+
await Promise.all(
|
|
87
|
+
tokens.map(async (token) => {
|
|
88
|
+
const existing = this.cache[token.symbol];
|
|
89
|
+
const fetchStart = existing ? Math.min(start, existing.start) : start;
|
|
90
|
+
const fetchEnd = existing ? Math.max(end, existing.end) : end;
|
|
91
|
+
try {
|
|
92
|
+
const rates = await fetchHistoricalFundingRates(
|
|
93
|
+
this.transport.connector,
|
|
94
|
+
token.symbol,
|
|
95
|
+
fetchStart,
|
|
96
|
+
fetchEnd,
|
|
97
|
+
duration
|
|
98
|
+
);
|
|
99
|
+
this.cache[token.symbol] = { entries: rates, start: fetchStart, end: fetchEnd };
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.warn(`Failed to fetch funding rate data for ${token.symbol}:`, error);
|
|
102
|
+
this.cache[token.symbol] = { entries: [], start: fetchStart, end: fetchEnd };
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
getAllTokens() {
|
|
108
|
+
return [...this.longTokens, ...this.shortTokens];
|
|
109
|
+
}
|
|
110
|
+
assertTokenExists(symbol) {
|
|
111
|
+
if (!this.getAllTokens().some((t) => t.symbol === symbol)) {
|
|
112
|
+
throw new Error(`Symbol "${symbol}" is not part of the configured long or short tokens`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { FundingRate };
|
|
@@ -0,0 +1,29 @@
|
|
|
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 FundingRateAggregation = 'none' | '1d' | '1w' | '1M';
|
|
12
|
+
type FundingRateDuration = '1w' | '1m' | '1y';
|
|
13
|
+
interface FundingRateEntry {
|
|
14
|
+
time: number;
|
|
15
|
+
rate: number;
|
|
16
|
+
annualizedRate?: number;
|
|
17
|
+
}
|
|
18
|
+
interface FundingRateCacheEntry {
|
|
19
|
+
entries: FundingRateEntry[];
|
|
20
|
+
start: number;
|
|
21
|
+
end: number;
|
|
22
|
+
}
|
|
23
|
+
interface FundingRateConfig {
|
|
24
|
+
transport: Transport;
|
|
25
|
+
longTokens?: TokenSelection[];
|
|
26
|
+
shortTokens?: TokenSelection[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type { FundingRateAggregation, FundingRateCacheEntry, FundingRateConfig, FundingRateDuration, FundingRateEntry, TokenSelection };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FundingRateEntry, FundingRateAggregation, TokenSelection, FundingRateDuration } 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 function computeStartTime(endTime: number, duration: FundingRateDuration): number;
|
|
9
|
+
declare function aggregateRates(rawRates: FundingRateEntry[], aggregation: FundingRateAggregation): FundingRateEntry[];
|
|
10
|
+
declare function annualizeRates(entries: FundingRateEntry[], aggregation: FundingRateAggregation, rawEntriesForInference?: FundingRateEntry[]): FundingRateEntry[];
|
|
11
|
+
declare function computeBasketRates(longTokens: TokenSelection[], shortTokens: TokenSelection[], tokenRates: Record<string, FundingRateEntry[]>): FundingRateEntry[];
|
|
12
|
+
|
|
13
|
+
export { aggregateRates, annualizeRates, computeBasketRates, computeStartTime };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import BigNumber from 'bignumber.js';
|
|
2
|
+
|
|
3
|
+
function computeStartTime(endTime, duration) {
|
|
4
|
+
const date = new Date(endTime);
|
|
5
|
+
switch (duration) {
|
|
6
|
+
case "1w":
|
|
7
|
+
return endTime - 7 * 864e5;
|
|
8
|
+
case "1m":
|
|
9
|
+
date.setUTCMonth(date.getUTCMonth() - 1);
|
|
10
|
+
return date.getTime();
|
|
11
|
+
case "1y":
|
|
12
|
+
date.setUTCFullYear(date.getUTCFullYear() - 1);
|
|
13
|
+
return date.getTime();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function getBucketStart(timestamp, aggregation) {
|
|
17
|
+
const date = new Date(timestamp);
|
|
18
|
+
switch (aggregation) {
|
|
19
|
+
case "1d":
|
|
20
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
21
|
+
case "1w": {
|
|
22
|
+
const mondayOffset = (date.getUTCDay() + 6) % 7;
|
|
23
|
+
const monday = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
24
|
+
monday.setUTCDate(monday.getUTCDate() - mondayOffset);
|
|
25
|
+
return monday.getTime();
|
|
26
|
+
}
|
|
27
|
+
case "1M":
|
|
28
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function aggregateRates(rawRates, aggregation) {
|
|
32
|
+
if (aggregation === "none") {
|
|
33
|
+
return [...rawRates].sort((a, b) => a.time - b.time);
|
|
34
|
+
}
|
|
35
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
36
|
+
for (const rate of rawRates) {
|
|
37
|
+
const key = getBucketStart(rate.time, aggregation);
|
|
38
|
+
buckets.set(key, (buckets.get(key) ?? new BigNumber(0)).plus(rate.rate));
|
|
39
|
+
}
|
|
40
|
+
return Array.from(buckets.entries()).map(([time, rate]) => ({ time, rate: rate.toNumber() })).sort((a, b) => a.time - b.time);
|
|
41
|
+
}
|
|
42
|
+
function inferAvgIntervalMs(entries) {
|
|
43
|
+
if (entries.length < 2) return null;
|
|
44
|
+
const sorted = [...entries].sort((a, b) => a.time - b.time);
|
|
45
|
+
let totalGap = new BigNumber(0);
|
|
46
|
+
let count = 0;
|
|
47
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
48
|
+
const prev = sorted[i - 1];
|
|
49
|
+
const curr = sorted[i];
|
|
50
|
+
if (prev === void 0 || curr === void 0) continue;
|
|
51
|
+
const gap = curr.time - prev.time;
|
|
52
|
+
if (gap > 0) {
|
|
53
|
+
totalGap = totalGap.plus(gap);
|
|
54
|
+
count++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return count > 0 ? totalGap.div(count) : null;
|
|
58
|
+
}
|
|
59
|
+
const MS_PER_YEAR = 365 * 864e5;
|
|
60
|
+
function annualizeRates(entries, aggregation, rawEntriesForInference) {
|
|
61
|
+
let multiplier;
|
|
62
|
+
if (aggregation === "none") {
|
|
63
|
+
const sample = rawEntriesForInference ?? entries;
|
|
64
|
+
const avgMs = inferAvgIntervalMs(sample);
|
|
65
|
+
if (avgMs === null) return entries;
|
|
66
|
+
multiplier = new BigNumber(MS_PER_YEAR).div(avgMs);
|
|
67
|
+
} else {
|
|
68
|
+
const fixed = {
|
|
69
|
+
"1d": 365,
|
|
70
|
+
"1w": 52,
|
|
71
|
+
"1M": 12
|
|
72
|
+
};
|
|
73
|
+
multiplier = new BigNumber(fixed[aggregation]);
|
|
74
|
+
}
|
|
75
|
+
return entries.map((e) => ({
|
|
76
|
+
...e,
|
|
77
|
+
annualizedRate: new BigNumber(e.rate).times(multiplier).toNumber()
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
function computeBasketRates(longTokens, shortTokens, tokenRates) {
|
|
81
|
+
const allSymbols = [...longTokens, ...shortTokens].map((t) => t.symbol);
|
|
82
|
+
if (allSymbols.length === 0) return [];
|
|
83
|
+
const lookups = {};
|
|
84
|
+
const allTimestamps = /* @__PURE__ */ new Set();
|
|
85
|
+
for (const [symbol, entries] of Object.entries(tokenRates)) {
|
|
86
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
87
|
+
for (const entry of entries) {
|
|
88
|
+
lookup.set(entry.time, entry.rate);
|
|
89
|
+
allTimestamps.add(entry.time);
|
|
90
|
+
}
|
|
91
|
+
lookups[symbol] = lookup;
|
|
92
|
+
}
|
|
93
|
+
const sorted = Array.from(allTimestamps).sort((a, b) => a - b);
|
|
94
|
+
const result = [];
|
|
95
|
+
for (const time of sorted) {
|
|
96
|
+
if (!allSymbols.every((s) => lookups[s]?.has(time))) continue;
|
|
97
|
+
let total = new BigNumber(0);
|
|
98
|
+
let count = 0;
|
|
99
|
+
for (const t of longTokens) {
|
|
100
|
+
const rate = lookups[t.symbol]?.get(time);
|
|
101
|
+
if (rate !== void 0 && t.weight > 0) {
|
|
102
|
+
total = total.plus(new BigNumber(rate).negated().times(new BigNumber(t.weight).div(100)));
|
|
103
|
+
count++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const t of shortTokens) {
|
|
107
|
+
const rate = lookups[t.symbol]?.get(time);
|
|
108
|
+
if (rate !== void 0 && t.weight > 0) {
|
|
109
|
+
total = total.plus(new BigNumber(rate).times(new BigNumber(t.weight).div(100)));
|
|
110
|
+
count++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (count > 0) {
|
|
114
|
+
result.push({ time, rate: total.toNumber() });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { aggregateRates, annualizeRates, computeBasketRates, computeStartTime };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { Chart } from './chart/chart.js';
|
|
2
2
|
export { Bar, CandleData, CandleInterval, ChartConfig, ChartType, RealtimeBarCallback, RealtimeCandleCallback, TokenSelection } from './chart/types.js';
|
|
3
|
+
export { FundingRate } from './funding-rate/funding-rate.js';
|
|
4
|
+
export { FundingRateAggregation, FundingRateConfig, FundingRateDuration, FundingRateEntry } from './funding-rate/types.js';
|
|
3
5
|
export { Orderbook } from './orderbook/orderbook.js';
|
|
4
6
|
export { AggregationConfig, BBO, CexAggregationConfig, HyperliquidAggregationConfig, OrderbookCallback, OrderbookConfig, OrderbookLevel, OrderbookSnapshot } from './orderbook/types.js';
|
|
5
7
|
export { getAvailableAggregations } from './orderbook/utils.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { Chart } from './chart/chart';
|
|
2
|
+
export { FundingRate } from './funding-rate/funding-rate';
|
|
2
3
|
export { Orderbook } from './orderbook/orderbook';
|
|
3
4
|
export { getAvailableAggregations } from './orderbook/utils';
|
|
4
5
|
export { BaseTransport, CreateTransport } from './transport';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pear-protocol/market-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Pear Protocol Market SDK",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"typecheck": "tsc --noEmit"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@pear-protocol/types": "0.0.
|
|
28
|
+
"@pear-protocol/types": "0.0.16",
|
|
29
29
|
"bignumber.js": "^9.1.2",
|
|
30
30
|
"partysocket": "^1.0.3"
|
|
31
31
|
},
|