UNPKG

@extra-fyers/websocket

Version:

A Javascript interface for FYERS API {websocket}.

234 lines (230 loc) 7.39 kB
'use strict'; var ws = require('ws'); const MARKET_DATA_URL = "wss://api.fyers.in/socket/v2/dataSock"; const ORDER_UPDATE_URL = "wss://api.fyers.in/socket/v2/orderSock"; const MARKET_DATA_QUERY = "user-agent=fyers-api&type=symbolUpdate"; const ORDER_UPDATE_QUERY = "user-agent=fyers-api&type=orderUpdate"; const PING_INTERVAL = 5000; function writeHeader(a, x, i) { a.token = x.getBigUint64(i + 0); a.tt = x.getUint32(i + 8); a.fyCode = x.getUint16(i + 12); a.marketStat = x.getUint16(i + 14); a.pktlen = x.getUint16(i + 16); a.L2 = x.getUint8(i + 18); } function writeOiData(a, x, i) { a.oi = BigInt(x.getUint32(i + 0)); a.pdoi = BigInt(x.getUint32(i + 4)); } function writeCommonData(a, x, i, hasOi) { a.price_conv = x.getUint32(i + 0); a.ltp = x.getUint32(i + 4); a.open_price = x.getUint32(i + 8); a.high_price = x.getUint32(i + 12); a.low_price = x.getUint32(i + 16); a.prev_close_price = x.getUint32(i + 20); a.o = x.getUint32(i + 24); a.h = x.getUint32(i + 28); a.l = x.getUint32(i + 32); a.c = x.getUint32(i + 36); a.v = x.getBigUint64(i + 40); if (!hasOi) return; a.oi = x.getBigUint64(i + 48); a.pdoi = x.getBigUint64(i + 56); } function writeL1Data(a, x, i, bidAsk) { a.LTQ = x.getUint32(i + 0); a.L2_LTT = x.getUint32(i + 4); a.ATP = x.getUint32(i + 8); a.volume = x.getUint32(i + 12); a.tot_buy = x.getBigUint64(i + 16); a.tot_sell = x.getBigUint64(i + 24); if (!bidAsk) return; a.bid = x.getUint32(i + 32); a.ask = x.getUint32(i + 36); } function toL2MarketOffer(x, i) { return { price: x.getUint32(i + 0), volume: x.getUint32(i + 4), ord: x.getUint32(i + 8), }; } function writeL2Data(a, x, i) { var bids = [], asks = []; for (var j = 0; j < 60; j += 12) { bids.push(toL2MarketOffer(x, i + j)); asks.push(toL2MarketOffer(x, i + j + 60)); } a.bids = bids; a.asks = asks; } function writeMarketData(a, x, i) { writeHeader(a, x, i + 0); var hasOi = a.fyCode === 7202 || a.fyCode === 31038; var l1Off = hasOi ? 88 : 72; if (a.fyCode === 7202) writeOiData(a, x, i + 24); else writeCommonData(a, x, i + 24, hasOi); if (a.fyCode === 7208 || a.fyCode === 31038) writeL1Data(a, x, i + l1Off, a.L2 !== 1); if (a.L2 === 1) writeL2Data(a, x, i + l1Off + 32); } function toMarketData(x, i) { var a = { token: BigInt(0), tt: 0, fyCode: 0, marketStat: 0, pktlen: 0, L2: 0, price_conv: 0, ltp: 0, open_price: 0, high_price: 0, low_price: 0, prev_close_price: 0, o: 0, h: 0, l: 0, c: 0, v: BigInt(0), oi: BigInt(0), pdoi: BigInt(0), LTQ: 0, L2_LTT: 0, ATP: 0, volume: 0, tot_buy: BigInt(0), tot_sell: BigInt(0), bid: 0, ask: 0, bids: null, asks: null, }; writeMarketData(a, x, i); return a; } class Connection extends ws.WebSocket { constructor() { super(...arguments); this.recievers = []; } } function waitResponse(conn) { return new Promise((resolve, reject) => conn.recievers.push({ resolve, reject })); } function connectOrderUpdate(auth, fn) { return new Promise((resolve, reject) => { var { app_id, access_token } = auth; var query = `${ORDER_UPDATE_QUERY}&access_token=${app_id}:${access_token}`; var conn = new Connection(`${ORDER_UPDATE_URL}?${query}`); var ping = setInterval(() => { if (conn.readyState !== ws.WebSocket.OPEN) return; conn.send("ping"); }, PING_INTERVAL); conn.binaryType = "arraybuffer"; conn.onerror = e => { for (var r of conn.recievers) r.reject(e.error); clearInterval(ping); reject(e.error); }; conn.onopen = () => resolve(conn); conn.onmessage = e => { if (typeof e.data !== "string") return; if (e.data === "pong") return; var x = JSON.parse(e.data); fn(x); if (x.hasOwnProperty("d") || x.code === 0) return; if (conn.recievers.length > 0) conn.recievers.shift().resolve(x); }; }); } function subscribeOrderUpdate(conn) { var req = { T: "SUB_ORD", SLIST: ["orderUpdate"], SUB_T: 1 }; conn.send(JSON.stringify(req)); return waitResponse(conn); } function unsubscribeOrderUpdate(conn) { var req = { T: "SUB_ORD", SLIST: ["orderUpdate"], SUB_T: 0 }; conn.send(JSON.stringify(req)); return waitResponse(conn); } function connectMarketData(auth, fn) { return new Promise((resolve, reject) => { var { app_id, access_token } = auth; var query = `${MARKET_DATA_QUERY}&access_token=${app_id}:${access_token}`; var conn = new Connection(`${MARKET_DATA_URL}?${query}`); var ping = setInterval(() => { if (conn.readyState !== ws.WebSocket.OPEN) return; conn.send("ping"); }, PING_INTERVAL); conn.binaryType = "arraybuffer"; conn.onerror = e => { for (var r of conn.recievers) r.reject(e.error); clearInterval(ping); reject(e.error); }; conn.onopen = () => resolve(conn); conn.onmessage = e => { if (typeof e.data === "string") { if (e.data === "pong") return; var x = JSON.parse(e.data); fn(x); if (x.hasOwnProperty("d") || x.code === 0) return; if (conn.recievers.length > 0) conn.recievers.shift().resolve(x); } else { var binary = new DataView(e.data); fn({ s: "ok", d: toMarketData(binary, 0) }); } }; }); } function subscribeMarketQuote(conn, symbols) { var req = { T: "SUB_DATA", TLIST: symbols, SUB_T: 1 }; conn.send(JSON.stringify(req)); return waitResponse(conn); } function subscribeMarketDepth(conn, symbols) { var req = { T: "SUB_L2", L2LIST: symbols, SUB_T: 1 }; conn.send(JSON.stringify(req)); return waitResponse(conn); } function unsubscribeMarketQuote(conn, symbols) { var req = { T: "SUB_DATA", TLIST: symbols, SUB_T: 0 }; conn.send(JSON.stringify(req)); return waitResponse(conn); } function unsubscribeMarketDepth(conn, symbols) { var req = { T: "SUB_L2", L2LIST: symbols, SUB_T: 0 }; conn.send(JSON.stringify(req)); return waitResponse(conn); } exports.Connection = Connection; exports.MARKET_DATA_URL = MARKET_DATA_URL; exports.ORDER_UPDATE_URL = ORDER_UPDATE_URL; exports.connectMarketData = connectMarketData; exports.connectOrderUpdate = connectOrderUpdate; exports.subscribeMarketDepth = subscribeMarketDepth; exports.subscribeMarketQuote = subscribeMarketQuote; exports.subscribeOrderUpdate = subscribeOrderUpdate; exports.unsubscribeMarketDepth = unsubscribeMarketDepth; exports.unsubscribeMarketQuote = unsubscribeMarketQuote; exports.unsubscribeOrderUpdate = unsubscribeOrderUpdate;