npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pear-protocol/market-sdk

v0.0.7

Published

Pear Protocol Market SDK

Readme

@pear-protocol/market-sdk

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.

Supported Exchanges

| Exchange | Connector Name | |----------|---------------| | Binance | binance | | Bybit | bybit | | Hyperliquid | hyperliquid | | OKX | okx | | Lighter | lighter |

Installation

npm install @pear-protocol/market-sdk

Quick Start

import { Chart, FundingRate, Orderbook, CreateTransport } from '@pear-protocol/market-sdk';

const transport = CreateTransport('hyperliquid');

// Chart
const chart = new Chart({
  transport,
  longTokens: [{ symbol: 'BTC', weight: 50 }, { symbol: 'ETH', weight: 50 }],
  shortTokens: [{ symbol: 'SOL', weight: 100 }],
  candleInterval: '1h',
});

const bars = await chart.getBars('weighted-ratio', startTime, endTime);

const subId = chart.subscribeRealtimeBars('weighted-ratio', (bar) => {
  console.log(bar.time, bar.open, bar.high, bar.low, bar.close);
});

// Funding rates
const fundingRate = new FundingRate({
  transport,
  longTokens: [{ symbol: 'ETH', weight: 0.6 }],
  shortTokens: [{ symbol: 'BTC', weight: 0.4 }],
  interval: '1d',
});

const rates = await fundingRate.getAssetRates('ETH');
const basketRates = await fundingRate.getBasketRates();

// Order book
const orderbook = new Orderbook({
  transport,
  symbol: 'BTC',
  aggregation: 10,
  depth: 15,
});

orderbook.subscribe((snapshot) => {
  console.log('bids:', snapshot.bids, 'asks:', snapshot.asks);
});

// Cleanup
chart.unsubscribeRealtimeBars(subId);
chart.destroy();
fundingRate.destroy();
orderbook.destroy();
transport.destroy();

Chart

Initialization

import { Chart, CreateTransport } from '@pear-protocol/market-sdk';

const transport = CreateTransport('binance');

const chart = new Chart({
  transport,
  longTokens: [{ symbol: 'BTC', weight: 60 }, { symbol: 'ETH', weight: 40 }],
  shortTokens: [{ symbol: 'SOL', weight: 100 }],
  candleInterval: '1h',
});

ChartConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | transport | Transport | — | WebSocket transport instance | | longTokens | TokenSelection[] | [] | Tokens on the long side with weights | | shortTokens | TokenSelection[] | [] | Tokens on the short side with weights | | candleInterval | CandleInterval | '1h' | Candle timeframe |

TokenSelection

{ symbol: string; weight: number }

CandleInterval

'1m' | '3m' | '5m' | '15m' | '30m' | '1h' | '2h' | '4h' | '8h' | '12h' | '1d' | '3d' | '1w' | '1M'

Updating Tokens and Interval

Change the tokens or candle interval at any time. Both clear cached data and baseline prices.

chart.setTokens(
  [{ symbol: 'BTC', weight: 100 }],
  [{ symbol: 'ETH', weight: 100 }],
);

chart.setCandleInterval('15m');

Fetching Historical Bars

Fetch historical OHLC bars for a given chart type and time range.

const bars = await chart.getBars('weighted-ratio', startTime, endTime);

for (const bar of bars) {
  bar.time;   // timestamp (ms)
  bar.open;   // open price
  bar.high;   // high price
  bar.low;    // low price
  bar.close;  // close price
}

Chart Types

| Type | Description | |------|-------------| | 'weighted-ratio' | Geometric mean ratio using token weights as exponents | | 'price-ratio' | Weighted sum of long prices divided by weighted sum of short prices | | 'performance' | Percentage performance relative to the earliest bar in the range |

Single-Asset Bars

Fetch bars for one specific symbol in the configured token set.

const bars = await chart.getAssetBars('BTC', startTime, endTime);

Subscribing to Real-Time Bars

Subscribe to live bar updates. The WebSocket connection is established automatically on the first subscription.

const subId = chart.subscribeRealtimeBars('weighted-ratio', (bar) => {
  console.log(bar.time, bar.open, bar.high, bar.low, bar.close);
});

// Single-asset real-time bars
const assetSubId = chart.subscribeRealtimeAssetBars('ETH', (bar) => {
  console.log(bar.time, bar.close);
});

// Stop receiving updates
chart.unsubscribeRealtimeBars(subId);
chart.unsubscribeRealtimeBars(assetSubId);

Data Boundary

Get the earliest timestamp for which historical data is available.

const boundary = chart.getEffectiveDataBoundary(); // number | null

Cache Management

// Clear all cached historical data and baseline prices
chart.clearCache();

Cleanup

chart.destroy();

Order Book

Initialization

The Orderbook connects to the exchange WebSocket immediately on construction and begins receiving depth updates.

import { Orderbook, CreateTransport } from '@pear-protocol/market-sdk';

const transport = CreateTransport('hyperliquid');

const orderbook = new Orderbook({
  transport,
  symbol: 'BTC',
  aggregation: 10,
  depth: 15,
});

OrderbookConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | transport | Transport | — | WebSocket transport instance | | symbol | string | — | Trading pair symbol | | aggregation | number | 0 | Bucket size for price aggregation (0 = no aggregation) | | depth | number | 10 | Number of price levels per side | | snapshottedPrice | number | — | Current mid-price for server-side aggregation params |

Subscribing to Updates

Subscribe to real-time order book snapshots. The callback fires on every depth update from the exchange.

const subId = orderbook.subscribe((snapshot) => {
  snapshot.symbol;       // "BTC"
  snapshot.aggregation;  // active bucket size
  snapshot.ts;           // last update timestamp (ms)

  for (const bid of snapshot.bids) {  // price-descending
    bid.price;  // price level
    bid.size;   // base-asset quantity
  }

  for (const ask of snapshot.asks) {  // price-ascending
    ask.price;
    ask.size;
  }
});

// Stop receiving updates
orderbook.unsubscribe(subId);

Reading the Current Snapshot

Access the latest order book state without subscribing. Returns null if no data has been received yet.

const snapshot = orderbook.getSnapshot();
if (snapshot) {
  console.log(snapshot.bids, snapshot.asks);
}

Changing Aggregation

Change the price aggregation bucket size at any time. Listeners are notified immediately with a re-aggregated snapshot.

orderbook.setAggregation(100);  // aggregate to $100 buckets
orderbook.setAggregation(0);    // disable aggregation

const current = orderbook.getAggregation();

Best Bid / Offer (BBO)

Access the current best bid, best ask, spread, and spread percentage. Returns null values when the book has not loaded yet.

const { bestBid, bestAsk, spread, spreadPct } = orderbook.bbo;
// bestBid:    "65000.5" | null
// bestAsk:    "65001.0" | null
// spread:     "0.5"     | null
// spreadPct:  "0.00077" | null

Available Aggregation Levels

Compute recommended aggregation bucket sizes for a given connector and price level.

import { getAvailableAggregations } from '@pear-protocol/market-sdk';

// CEX exchanges (Binance, Bybit, OKX) — uses tick size
const levels = getAvailableAggregations('binance', { tickSize: 0.1, midPrice: 65000 });
// e.g. [0.1, 1, 10, 100, 1000]

// Hyperliquid — uses max decimal places
const levels = getAvailableAggregations('hyperliquid', { maxDecimals: 2, midPrice: 65000 });

Updating Snapshotted Price

Update the mid-price used for server-side aggregation parameters (e.g. Hyperliquid).

orderbook.setSnapshottedPrice(65250.5);

Cleanup

orderbook.destroy();

The underlying transport is owned by the caller and must be destroyed separately.

Funding Rate

Initialization

import { FundingRate, CreateTransport } from '@pear-protocol/market-sdk';

const transport = CreateTransport('hyperliquid');

const fundingRate = new FundingRate({
  transport,
  longTokens: [{ symbol: 'ETH', weight: 0.6 }],
  shortTokens: [{ symbol: 'BTC', weight: 0.4 }],
});

FundingRateConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | transport | Transport | — | Transport instance (used to determine the exchange) | | longTokens | TokenSelection[] | [] | Tokens on the long side with weights | | shortTokens | TokenSelection[] | [] | Tokens on the short side with weights |

Aggregation and Duration

Aggregation level and lookback duration are passed per call to getAssetRates and getBasketRates.

FundingRateAggregation

'none' | '1d' | '1w' | '1M'

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.

FundingRateDuration

'1w' | '1m' | '1y'

The lookback window for fetching data, ending at the current time.

Minimum Duration per Aggregation

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.

| Aggregation | Minimum Duration | |-------------|------------------| | 'none' | '1w' | | '1d' | '1m' | | '1w' | '1y' | | '1M' | '1y' |

Per-Asset Funding Rates

Fetch funding rates for a single token.

// Defaults: aggregation='none', duration='1m'
const rates = await fundingRate.getAssetRates('ETH');

// Daily aggregation over the last year
const dailyRates = await fundingRate.getAssetRates('ETH', '1d', '1y');

Signature

getAssetRates(
  symbol: string,
  aggregation?: FundingRateAggregation,  // default: 'none'
  duration?: FundingRateDuration,        // default: '1m'
): Promise<FundingRateEntry[]>

Basket Funding Rates

Compute the weighted net funding rate across all configured tokens. Positive rate = user earns funding, negative = user pays.

const basketRates = await fundingRate.getBasketRates();

const monthlyBasket = await fundingRate.getBasketRates('1M', '1y');

The net rate at each time point is calculated as:

netRate = sum(shortWeight × rate) - sum(longWeight × rate)

Only time points where all tokens have data are included.

Signature

getBasketRates(
  aggregation?: FundingRateAggregation,  // default: 'none'
  duration?: FundingRateDuration,        // default: '1m'
): Promise<FundingRateEntry[]>

FundingRateEntry

{
  time: number;             // bucket start timestamp (ms)
  rate: number;             // summed rate for the bucket (raw rate when aggregation='none')
  annualizedRate?: number;  // rate annualized to a yearly figure
}

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.

Updating Tokens

fundingRate.setTokens(
  [{ symbol: 'ETH', weight: 0.5 }, { symbol: 'SOL', weight: 0.5 }],
  [{ symbol: 'BTC', weight: 1.0 }],
);

Cleanup

fundingRate.destroy();