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

shark-exchange-sdk

v0.1.0

Published

TypeScript-first Node.js SDK for Shark Exchange REST and Socket.IO APIs.

Readme

Shark Exchange SDK

TypeScript-first Node.js SDK for Shark Exchange REST and Socket.IO APIs.

This SDK is designed to be used as a complete trading integration layer, not as a thin API wrapper. It gives you typed resource clients, request signing, rate limiting, retry handling, validation, order builders, websocket helpers, listen-key management, and examples for common workflows.

Source reference: Shark API Reference Documentation.

Requirements

  • Node.js 20 or newer.
  • Node.js 22 or newer is recommended for current production apps.
  • Shark API key and secret are required for authenticated account, order, wallet, position, and private stream APIs.
  • Public market REST and public market streams do not require credentials.

The package ships ESM, CommonJS, and TypeScript declarations.

Install

npm install shark-exchange-sdk

Import

ESM or TypeScript:

import { SharkExchange } from "shark-exchange-sdk";

CommonJS:

const { SharkExchange } = require("shark-exchange-sdk");

Client Setup

import { SharkExchange } from "shark-exchange-sdk";

export const shark = new SharkExchange({
  apiKey: process.env.SHARK_API_KEY,
  apiSecret: process.env.SHARK_API_SECRET,
});

Advanced setup:

const shark = new SharkExchange({
  apiKey: process.env.SHARK_API_KEY,
  apiSecret: process.env.SHARK_API_SECRET,
  timeoutMs: 30_000,
  retry: {
    retries: 2,
    baseDelayMs: 250,
    maxDelayMs: 2_000,
  },
  rateLimit: {
    enabled: true,
  },
  userAgent: "my-trading-app/1.0.0",
});

Environment Variables

SHARK_API_KEY=your-api-key
SHARK_API_SECRET=your-api-secret

Keep live trading controls in your application, not inside examples. The examples that place or cancel orders are intentionally guarded with RUN_LIVE_TRADING=true.

What The SDK Handles

  • HMAC-SHA256 signing for authenticated REST endpoints.
  • Timestamps for authenticated REST requests.
  • Public vs authenticated endpoint routing.
  • Endpoint-aware rate limiting based on Shark documentation.
  • Retry and timeout behavior.
  • Runtime validation for common order mistakes.
  • Fluent order builders.
  • Typed REST resources grouped by workflow.
  • Socket.IO public and authenticated stream helpers.
  • Listen-key creation, keepalive, and deletion.
  • Typed resource response unwrapping for { data: ... } and { result: ... } envelopes.
  • Raw request escape hatch for newly added or undocumented endpoints.

Resource Map

Market Data

Public REST data:

await shark.market.ticker24Hr("BTCINR");
await shark.market.aggregateTrade("BTCINR");
await shark.market.depth("BTCINR");
await shark.market.klines({
  pair: "BTCINR",
  interval: "1m",
  priceType: "MARK_PRICE",
  limit: 100,
});

Exchange

Exchange metadata and account-level preferences:

await shark.exchange.info({ market: "INR" });

await shark.exchange.updatePreference({
  contractName: "BTCINR",
  marginMode: "ISOLATED",
  leverage: 10,
});

await shark.exchange.updateLeverage({
  contractName: "BTCINR",
  leverage: 10,
});

Orders

Order placement, lookup, editing, margin, and cancellation:

await shark.orders.placeMarket({
  placeType: "ORDER_FORM",
  quantity: 0.002,
  side: "BUY",
  symbol: "BTCINR",
  reduceOnly: false,
  marginAsset: "INR",
});

await shark.orders.placeLimit({
  placeType: "ORDER_FORM",
  quantity: 0.002,
  price: 5_000_000,
  side: "BUY",
  symbol: "BTCINR",
  reduceOnly: false,
  marginAsset: "INR",
});

await shark.orders.edit({
  clientOrderId: "client-order-id",
  quantity: 0.003,
  price: 5_050_000,
});

await shark.orders.open({ symbol: "BTCINR", pageSize: 50, sortOrder: "desc" });
await shark.orders.history({ symbol: "BTCINR", pageSize: 50, sortOrder: "desc" });
await shark.orders.get("client-order-id");
await shark.orders.getMultiple(["client-order-id-1", "client-order-id-2"]);
await shark.orders.linked("link-id");
await shark.orders.referenced("ref-id");
await shark.orders.splitTpSl({
  positionId: "position-id",
  splitTakeProfitOrders: [{ quantity: 0.001, price: 5_500_000 }],
  splitStopLossOrders: [{ quantity: 0.001, price: 4_750_000 }],
});
await shark.orders.marginHistory({ symbol: "BTCINR" });
await shark.orders.delete("client-order-id");
await shark.orders.cancelAll();

Order Builder

Use the builder when you want to avoid assembling payloads by hand:

const payload = shark
  .order()
  .symbol("BTCINR")
  .buy()
  .marginAsset("INR")
  .limit(0.002, 5_000_000)
  .takeProfit(5_500_000)
  .stopLoss(4_750_000)
  .build();

await shark.orders.place(payload);

Stop orders:

const stopLimit = shark
  .order()
  .symbol("BTCINR")
  .sell()
  .marginAsset("INR")
  .stopLimit(0.002, 4_900_000, 4_890_000)
  .reduceOnly()
  .build();

Positions

await shark.positions.list("OPEN", { symbol: "BTCINR", pageSize: 100 });
await shark.positions.get("position-id");
await shark.positions.closeAll();

Wallet

await shark.wallet.futures({ marginAsset: "INR" });
await shark.wallet.funding({ marginAsset: "INR" });

User Data

await shark.userData.tradeHistory({
  symbol: "BTCINR",
  pageSize: 100,
  sortOrder: "desc",
});

await shark.userData.transactionHistory({
  symbol: "BTCINR",
  positionId: "position-id",
  pageSize: 100,
});

Listen Keys

const { listenKey } = await shark.listenKeys.create();
await shark.listenKeys.keepAlive();
await shark.listenKeys.delete();

Public Streams

Shark realtime uses Socket.IO. The SDK uses socket.io-client for the correct protocol.

import { SharkExchange, streamTopics } from "shark-exchange-sdk";

const shark = new SharkExchange();
const stream = shark.streams.public({ autoConnect: false });

stream.on("connect", () => {
  stream.subscribe([
    streamTopics.depth("BTCINR", "0.1"),
    streamTopics.kline("BTCINR", "1m"),
    streamTopics.markPrice("BTCINR"),
    streamTopics.aggregateTrade("BTCINR"),
    streamTopics.ticker("BTCINR"),
    streamTopics.marketInfo("BTCINR"),
    streamTopics.markPriceArray(),
    streamTopics.tickerArray(),
    streamTopics.allContractDetails(),
  ]);
});

stream.on("depthUpdate", console.log);
stream.on("kline", console.log);
stream.on("markPriceUpdate", console.log);
stream.on("aggTrade", console.log);
stream.on("24hrTicker", console.log);
stream.on("marketInfo", console.log);

stream.connect();

Live Data Pattern

For bots and dashboards, use REST for the initial snapshot and public streams for updates:

const symbols = ["BTCINR", "ETHINR"];
const snapshots = new Map<string, { lastPrice: number; bestBid: number; bestAsk: number }>();

for (const symbol of symbols) {
  const [ticker, depth] = await Promise.all([
    shark.market.ticker24Hr(symbol),
    shark.market.depth(symbol),
  ]);

  snapshots.set(symbol, {
    lastPrice: Number(ticker.c),
    bestBid: Number(depth.b?.[0]?.[0]),
    bestAsk: Number(depth.a?.[0]?.[0]),
  });
}

const stream = shark.streams.public({ autoConnect: false });
stream.on("connect", () => {
  stream.subscribe(symbols.flatMap((symbol) => [
    streamTopics.ticker(symbol),
    streamTopics.markPrice(symbol),
    streamTopics.depth(symbol, "0.1"),
  ]));
});
stream.on("24hrTicker", console.log);
stream.on("markPriceUpdate", console.log);
stream.on("depthUpdate", console.log);
stream.connect();

For a complete live-data cache with depth grouping, staleness checks, reconnect resubscription, and graceful shutdown, see examples/08-live-data-feed.ts.

Authenticated Streams

Managed authenticated streams create a listen key and refresh it automatically:

const stream = await shark.streams.managedAuthenticated({
  autoConnect: false,
  autoKeepAlive: true,
  keepAliveIntervalMs: 30 * 60_000,
});

stream.on("orderFilled", console.log);
stream.on("orderPartiallyFilled", console.log);
stream.on("orderCancelled", console.log);
stream.on("orderFailed", console.log);
stream.on("newOrder", console.log);
stream.on("updateOrder", console.log);
stream.on("newPosition", console.log);
stream.on("updatePosition", console.log);
stream.on("closePosition", console.log);
stream.on("balanceUpdate", console.log);
stream.on("newTrade", console.log);
stream.on("sessionExpired", console.log);

stream.connect();

If you already have a listen key:

const stream = shark.streams.authenticated("existing-listen-key");

Response Envelopes

Typed resource methods return the useful payload directly.

For example, if Shark returns:

{
  "data": {
    "s": "BTCINR",
    "c": "5271387.66"
  }
}

Then:

const ticker = await shark.market.ticker24Hr("BTCINR");
console.log(ticker.s);

Use raw.request() when you need the exact server response:

const raw = await shark.raw.request("GET", "/v1/market/ticker24Hr/BTCINR", {
  auth: false,
});

Compatibility Modes

The Shark docs currently show both path-style and query-style examples for a few public market endpoints. The SDK defaults to the documented JavaScript path style and keeps query mode available.

await shark.market.ticker24Hr("BTCINR");
await shark.market.ticker24Hr("BTCINR", { mode: "query" });

await shark.market.depth("BTCINR");
await shark.market.depth("BTCINR", { mode: "query" });

await shark.market.aggregateTrade("BTCINR");
await shark.market.aggregateTrade("BTCINR", { mode: "query" });

Order lookup methods also expose compatibility modes where the docs differ. Live testing showed single-order lookup should use query mode by default; path mode remains available when you need to match a path-style integration.

await shark.orders.linked("link-id", { mode: "query" });
await shark.orders.referenced("ref-id", { mode: "path" });
await shark.orders.get("client-order-id");
await shark.orders.get("client-order-id", { mode: "path" });

Error Handling

import {
  SharkApiError,
  SharkAuthError,
  SharkTimeoutError,
  SharkValidationError,
} from "shark-exchange-sdk";

try {
  await shark.orders.placeMarket({
    placeType: "ORDER_FORM",
    quantity: 0,
    side: "BUY",
    symbol: "BTCINR",
    reduceOnly: false,
    marginAsset: "INR",
  });
} catch (error) {
  if (error instanceof SharkValidationError) {
    console.error("Bad SDK input:", error.message);
  } else if (error instanceof SharkAuthError) {
    console.error("Missing or invalid local credentials:", error.message);
  } else if (error instanceof SharkTimeoutError) {
    console.error("Request timed out:", error.message);
  } else if (error instanceof SharkApiError) {
    console.error("Shark API error:", error.status, error.response);
  } else {
    throw error;
  }
}

Pagination Helper

Some Shark endpoints expose cursor-like timestamps. The SDK provides a generic helper so your app can keep its resource call readable.

for await (const order of shark.paginate((cursor) =>
  shark.orders.history({
    symbol: "BTCINR",
    pageSize: 100,
    endTimestamp: cursor,
  })
)) {
  console.log(order.clientOrderId);
}

If the API shape differs, pass getItems and getNextTimestamp.

Examples

The examples/ directory is designed as a user guide in code:

  • examples/01-public-market-data.ts: public market REST data.
  • examples/02-orders-and-builders.ts: market, limit, stop, edit, lookup, margin, and cancel flows.
  • examples/03-account-positions-wallet.ts: positions, wallet, user-data, exchange preferences.
  • examples/04-public-stream.ts: public Socket.IO market streams.
  • examples/05-authenticated-stream.ts: listen-key authenticated account stream.
  • examples/06-configuration-and-errors.ts: retry, timeout, rate limit, errors, abort signals.
  • examples/07-commonjs.js: CommonJS usage.
  • examples/08-live-data-feed.ts: REST bootstrap plus live Socket.IO market updates for bots and dashboards.

Run TypeScript examples with a runner such as tsx:

npx tsx examples/01-public-market-data.ts

Run CommonJS examples with Node:

node examples/07-commonjs.js

Scripts

npm run typecheck
npm test
npm run build

Publishing Checklist

npm run typecheck
npm test
npm run build
npm pack --dry-run

If your local npm cache has permission issues, use a temporary cache:

npm pack --dry-run --cache /private/tmp/npm-cache