JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 574
  • Score
    100M100P100Q81432F
  • License MIT

Unified broker abstraction for Indian stock markets - CCXT-like interface for NSE/BSE brokers

Package Exports

  • nsekit

Readme

nsekit

Unified broker abstraction for Indian stock markets. Write your trading logic once and run it against Zerodha, Finvasia (Shoonya), Dhan, or a paper trading engine with zero code changes.

npm install nsekit

AI-adding-a-broker.md | adding-a-broker.md | broker-credentials.md

Document Description
AI-adding-a-broker.md Self-contained prompt for any AI assistant to implement a new broker adapter end to end — from reading API docs to running tests to submitting a PR.
adding-a-broker.md Step-by-step manual guide covering file structure, implementation order, common pitfalls, the 13-checkpoint integration test, and pull request checklist.
broker-credentials.md Per-broker credential reference — which fields are required, where to get them, auth flow details, and security notes.

Supported Brokers

Broker Auth Flow WebSocket Instruments
Zerodha (Kite Connect) OAuth + request_token Binary (KiteTicker) CSV bulk dump
Finvasia (Shoonya) TOTP + vendor_code JSON (NorenWSTP) Per-exchange ZIPs + SearchScrip API
Dhan client_id + access_token Binary (Market Feed) CSV bulk dump + Search API
Paper Instant (no credentials) Proxied from live broker Delegated to data source

Before authenticating, review the credential fields each broker requires: docs/broker-credentials.md.


Quick Start

import { createBroker } from 'nsekit';

// 1. Create a broker instance
const broker = createBroker('finvasia');

// 2. Authenticate
const auth = await broker.authenticate({
  userId: 'FA12345',
  password: 'your_password',
  totpSecret: 'YOUR_BASE32_SECRET',
  apiKey: 'your_api_secret',
  vendorCode: 'FA12345_U',
});
// auth.value => { accessToken: '...', userId: 'FA12345', expiresAt: 1707523199000, ... }

// 3. Place an order
const order = await broker.placeOrder({
  tradingSymbol: 'RELIANCE-EQ',
  exchange: 'NSE',
  side: 'BUY',
  quantity: 1,
  type: 'LIMIT',
  product: 'INTRADAY',
  price: 2400,
  validity: 'DAY',
});
// order.value => { orderId: '26020900479551', status: 'PENDING', timestamp: 1707480649000 }

// 4. Get positions
const positions = await broker.getPositions();
// positions.value => [{ tradingSymbol: 'RELIANCE-EQ', side: 'LONG', quantity: 1, pnl: 12.50, ... }]

// 5. Cancel the order
const cancel = await broker.cancelOrder(order.value.orderId);
// cancel.value => { orderId: '26020900479551', status: 'CANCELLED' }

Switch to any other broker by changing a single line:

const broker = createBroker('zerodha');  // or 'dhan', 'paper'

Architecture

Mapper Pattern

Each broker has a dedicated mapper module with pure functions that translate between unified types and broker-specific API formats. Mappers have no side effects and no I/O, making them the most testable part of the system.

brokers/zerodha/
  ZerodhaBroker.ts          -- Implements IBroker
  zerodha-mapper.ts         -- Pure translation functions (toOrderParams, fromPosition, fromOrder, ...)
  zerodha-auth.ts           -- OAuth + request_token flow
  zerodha-socket.ts         -- KiteTicker WebSocket adapter
  zerodha-instruments.ts    -- CSV dump streaming + normalize
  zerodha-constants.ts      -- Bidirectional enum mappings (MIS <-> INTRADAY, etc.)
  index.ts                  -- Barrel exports

All four brokers follow this identical structure. The constants files handle the mapping differences:

Unified Zerodha Finvasia Dhan
INTRADAY MIS I INTRA
DELIVERY CNC C CNC
LIMIT LIMIT LMT LIMIT
SL SL SL-LMT STOP_LOSS
BUY BUY B BUY

Result Pattern

All methods return Result<T> instead of throwing exceptions. This makes error handling explicit at every call site.

import { Ok, Err, isOk, isErr, unwrap } from 'nsekit';

const result = await broker.placeOrder(params);

if (result.ok) {
  console.log('Order placed:', result.value.orderId);
} else {
  console.log('Failed:', result.error.message);
}

// Or unwrap (throws on Err):
const order = unwrap(result);

Instrument Master

The InstrumentMaster maintains a normalized lookup table of all tradeable instruments across brokers. Resolution follows a three-tier strategy:

  1. Redis hot cache (O(1) lookup for recently used instruments)
  2. In-memory index (built from broker dump files)
  3. Broker search API fallback (for brokers that support it)

Each broker implements IBrokerInstruments with streamDump(), normalize(), search(), and resolve() methods.

Paper Broker

PaperBroker implements the full IBroker interface using an in-memory fill engine. Orders are filled against live LTP data from a real broker's tick feed.

Fill logic per order type:

  • MARKET: fill immediately at LTP + slippage
  • LIMIT: fill when ltp <= price (BUY) or ltp >= price (SELL)
  • SL: trigger when price crosses trigger, then fill as LIMIT
  • SL_M: trigger when price crosses trigger, then fill as MARKET

Slippage model: baseSlippage + (quantity / avgDailyVolume) * impactFactor


Broker Credentials

Each broker requires different credential fields for authentication. See docs/broker-credentials.md for the full reference on where to obtain each value and how to pass them to authenticate().


Infrastructure Modules

SessionManager

Manages authentication lifecycle across multiple brokers with automatic refresh, Redis session persistence, and health monitoring.

import { SessionManager } from 'nsekit';

const sm = new SessionManager(redisClient);
await sm.authenticate('finvasia', credentials);
// Sessions are refreshed automatically before expiry

WSManager

Aggregates tick streams from multiple broker WebSocket connections. Handles reference-counted subscriptions, symbol resolution via InstrumentMaster, and publishes ticks to Redis.

import { WSManager } from 'nsekit';

const ws = new WSManager(instrumentMaster, redisClient);
ws.addBroker('finvasia', finvasiaBroker);
ws.subscribe(['NIFTY', 'RELIANCE'], (tick) => {
  console.log(tick.tradingSymbol, tick.ltp);
});

Add a New Broker

nsekit is designed to make adding new brokers straightforward. Every broker follows the same 7-file structure and implements the same IBroker interface.

Manual approach: Follow docs/adding-a-broker.md for a step-by-step walkthrough covering file structure, implementation order, common pitfalls, and the 13-checkpoint manual test.

With an AI assistant (Claude, Cursor, Copilot, GPT, etc.): Open docs/AI-adding-a-broker.md and paste it as context to your AI. The prompt walks the AI through the entire process — from reading the broker's API docs, to scaffolding all 7 files from skeleton templates, to running the integration test against your real broker account, to committing and submitting a pull request. You just provide your broker credentials in a .env file and let the AI handle the rest.


Project Structure

nsekit/
  src/
    brokers/
      zerodha/       -- Zerodha Kite Connect adapter (7 files)
      finvasia/      -- Finvasia Shoonya adapter (7 files)
      dhan/          -- Dhan adapter (7 files)
      paper/         -- Paper trading engine (3 files)
    errors/          -- Result<T>, BrokerError, typed error classes
    instruments/     -- InstrumentMaster (unified instrument index)
    interfaces/      -- IBroker contract
    session/         -- SessionManager (auth lifecycle)
    types/           -- All shared TypeScript types
    websocket/       -- WSManager (multi-broker tick aggregation)
    index.ts         -- Factory function + exports
  docs/
    adding-a-broker.md
    AI-adding-a-broker.md
    broker-credentials.md
  package.json
  tsconfig.json

Contributing

See docs/adding-a-broker.md for the implementation guide or docs/AI-adding-a-broker.md to let an AI do it for you.

nsekit is open source under the MIT license. Contributions, bug reports, and new broker implementations are welcome from anyone.