delta-india-sdk
v1.0.0
Published
TypeScript-first SDK for Delta Exchange India crypto derivatives API
Maintainers
Readme
delta-india-sdk
TypeScript-first, zero-dependency SDK for the Delta Exchange India crypto derivatives API.
Features
- Full REST + WebSocket coverage of Delta India's v2 API
- Complete TypeScript types for every request and response
- Zero runtime dependencies — uses native
fetchandWebSocket - Dual ESM + CommonJS build with
.d.tsfor both - Built-in HMAC SHA256 request signing
- Sliding-window rate limiter with auto-queue or throw modes
- Auto-reconnect WebSocket with exponential backoff and ping/pong
Requirements
- Node.js 22 or later (uses native
fetchandWebSocket)
Installation
npm install delta-india-sdkGet API keys
Generate an API key + secret from your Delta India account (or testnet). For trading you must enable the "Trade" permission. Store the secret in an environment variable, never in source code.
export DELTA_API_KEY=...
export DELTA_API_SECRET=...Quick Start
import { DeltaClient } from 'delta-india-sdk';
const client = new DeltaClient({
apiKey: process.env.DELTA_API_KEY,
apiSecret: process.env.DELTA_API_SECRET,
testnet: true,
});
// Public market data — no API key needed
const ticker = await client.products.ticker('BTCUSD');
console.log(`BTCUSD mark: ${ticker.mark_price}`);
// Authenticated call
const balances = await client.wallet.balances();
client.destroy(); // releases the rate-limiter timerCommon Recipes
Place a limit order
const order = await client.orders.create({
product_symbol: 'BTCUSD',
size: '1', // contracts, not USD
side: 'buy',
order_type: 'limit_order',
limit_price: '60000',
time_in_force: 'gtc',
});Cancel an order
await client.orders.cancel(order.id, order.product_id);Delta India's cancel is
DELETE /v2/orderswith{id, product_id}in the body —cancel(id, productId)handles that for you.
List options tickers (filtered)
The unfiltered /v2/tickers returns 10 000+ rows for options. Always filter:
const callsAndPuts = await client.products.tickers({
contract_types: 'call_options,put_options',
underlying_asset_symbols: 'BTC',
expiry_date: '27-12-2026', // DD-MM-YYYY
});
for (const t of callsAndPuts) {
console.log(t.symbol, t.strike_price, t.greeks?.delta);
}Positions for one underlying
// Single position by product
const btcPerpPos = await client.positions.list({ product_id: 27 });
// All positions on an underlying
const ethPositions = await client.positions.list({
underlying_asset_symbol: 'ETH',
});
list()returnsPosition[]even when Delta responds with a single object (filtered byproduct_id).
Bracket order with trigger method
await client.orders.create({
product_id: 27,
size: '1',
side: 'buy',
order_type: 'market_order',
bracket_stop_loss_price: '58000',
bracket_stop_trigger_method: 'mark_price', // or 'last_traded_price', 'spot_price'
bracket_take_profit_price: '65000',
});Batch operations
await client.orders.batchCreate({
product_id: 27, // required at the top level
orders: [
{ size: '1', side: 'buy', order_type: 'limit_order', limit_price: '59000' },
{ size: '1', side: 'sell', order_type: 'limit_order', limit_price: '61000' },
],
});
await client.orders.batchDelete({
product_id: 27,
orders: [{ id: 1234 }, { id: 1235 }],
});WebSocket — public channels
client.ws.on('connected', () => {
client.ws.subscribe('v2/ticker', ['BTCUSD']);
client.ws.subscribe('recent_trade', ['BTCUSD']);
});
client.ws.on('v2/ticker', (data) => console.log(data.symbol, data.close));
client.ws.on('recent_trade', (trade) => console.log('trade', trade));
client.ws.connect();Delta sends recent-trade messages typed
all_trades/all_trades_snapshot; the SDK re-emits them under the canonicalrecent_tradeevent so your handler always fires.
WebSocket — private channels (auto-auth)
const client = new DeltaClient({
apiKey: process.env.DELTA_API_KEY,
apiSecret: process.env.DELTA_API_SECRET,
});
client.ws.on('connected', () => {
client.ws.subscribe('orders');
client.ws.subscribe('positions');
});
client.ws.on('authenticated', () => console.log('private channels live'));
client.ws.on('orders', (o) => console.log('order update', o.id, o.state));
client.ws.connect();Working with numeric fields
Delta returns most numeric fields (size, entry_price, mark_price, greeks.delta, quotes.best_bid, …) as strings to preserve precision. Convert them at the edge using the bundled num() / int() helpers instead of scattering parseFloat(x) || 0 through your code:
import { DeltaClient, num, int } from 'delta-india-sdk';
const [pos] = await client.positions.list({ product_id: 27 });
const size = num(pos.size); // "1" -> 1
const entry = num(pos.entry_price ?? pos.avg_entry_price); // string-or-null -> number
const mark = num(pos.mark_price, num(ticker.mark_price)); // chained fallback
const productId = int(req.query.productId, 27); // URL/DB string -> intBoth helpers accept string | number | null | undefined and return a finite number, falling back to 0 (or your supplied default) for null, empty, NaN, and Infinity. int() additionally truncates the result.
API Reference
Client Options
const client = new DeltaClient({
apiKey: 'your-api-key', // required for authenticated endpoints + private WS
apiSecret: 'your-api-secret', // required for authenticated endpoints + private WS
testnet: true, // default false
baseUrl: 'https://...', // optional override (takes precedence over testnet)
wsUrl: 'wss://...', // optional WebSocket override
timeout: 10000, // ms, default 10000
rateLimitMode: 'auto', // 'auto' queues, 'manual' throws RateLimitError
maxQueueSize: 100, // queued requests cap in auto mode
});REST Sub-Clients
| Sub-client | Methods |
|---|---|
| client.assets | list, listIndices |
| client.products | list, getBySymbol, tickers, ticker |
| client.marketData | orderbook, recentTrades, candles, sparklines, settlementPrice |
| client.orders | create, get, getByClientId, list, edit, cancel, cancelAll, batchCreate, batchEdit, batchDelete, createBracket, editBracket, getLeverage, setLeverage |
| client.positions | list, listMargined, setMarginMode |
| client.history | orders, fills, fillsDownload |
| client.wallet | balances, transactions, transactionsDownload, transfer, transferHistory |
| client.account | getUser, getPreferences, updatePreferences, listSubaccounts, getRateLimitQuota |
| client.stats | volume |
| client.mmp | config, reset |
| client.heartbeat | create, ack, list |
WebSocket Channels
Public (no auth): v2/ticker, l2_orderbook, recent_trade, all_trades, mark_price, spot_price, funding_rate, product_updates, announcements
Private (auto-authenticated): orders, positions, margins, fills
Error Handling
import {
DeltaError, AuthenticationError, RateLimitError,
APIError, WebSocketError, TimeoutError, ValidationError,
} from 'delta-india-sdk';
try {
await client.orders.create({ /* ... */ });
} catch (err) {
if (err instanceof AuthenticationError) {
// 401/403 — bad keys or stale system clock
} else if (err instanceof RateLimitError) {
console.log(`retry after ${err.retryAfter}s`);
} else if (err instanceof TimeoutError) {
// request exceeded the configured timeout
} else if (err instanceof APIError) {
console.log(`API ${err.statusCode}: ${err.errorCode ?? err.message}`);
}
}Endpoints
| Environment | REST | WebSocket |
|---|---|---|
| Production | https://api.india.delta.exchange | wss://socket.india.delta.exchange |
| Testnet | https://cdn-ind.testnet.deltaex.org | wss://socket-ind.testnet.deltaex.org |
testnet: true selects the testnet pair automatically. Override either with baseUrl / wsUrl.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| AuthenticationError: invalid signature | System clock drift > a few seconds | Sync NTP / system clock |
| AuthenticationError on every authed call | Wrong key/secret or wrong env (test vs prod) | Verify key matches the env you're hitting |
| recent_trade listener never fires | Subscription succeeded but no live trades | Subscribe to a liquid symbol like BTCUSD; messages are re-emitted from all_trades automatically |
| tickers() returns thousands of rows | Unfiltered call | Pass contract_types, underlying_asset_symbols, and/or expiry_date |
| RateLimitError under load | Burst exceeded sliding window | Use rateLimitMode: 'auto' (default) so calls queue instead of throwing |
Examples
The examples/ folder is ordered so you can read it top-to-bottom; each file is a self-contained runnable script. Public examples (01–02, 10) need no API key; the rest read DELTA_API_KEY and DELTA_API_SECRET from the environment.
| # | File | What it covers |
|---|---|---|
| 01 | 01-basic-market-data.ts | products, tickers, orderbook, recent trades, candles, sparklines, assets |
| 02 | 02-options-chain.ts | filtered tickers, greeks, ATM strike selection |
| 03 | 03-place-order.ts | create / edit / cancel a limit order |
| 04 | 04-bracket-order.ts | bracket order with stop trigger method, edit bracket, set leverage |
| 05 | 05-batch-orders.ts | batch create / edit / delete (correct product_id body shape) |
| 06 | 06-positions.ts | list with filters, computed unrealized PnL using num() |
| 07 | 07-wallet.ts | balances, transactions, transfer, transfer history |
| 08 | 08-account.ts | profile, preferences, subaccounts, rate-limit quota |
| 09 | 09-history.ts | order history, fills, computed fees |
| 10 | 10-websocket-public.ts | ticker, l2 orderbook, recent_trade, mark_price |
| 11 | 11-websocket-private.ts | orders, positions, fills, margins (auto-auth) |
| 12 | 12-error-handling.ts | each error class, narrowing with instanceof |
Run any of them with tsx:
npx tsx examples/01-basic-market-data.ts
DELTA_API_KEY=... DELTA_API_SECRET=... npx tsx examples/03-place-order.tsDevelopment
npm install
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run build # tsup -> dist/License
MIT
