@extra-fyers/websocket
Version:
A Javascript interface for FYERS API {websocket}.
222 lines (219 loc) • 7.06 kB
JavaScript
import { WebSocket } from '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 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 !== 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 !== 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);
}
export { Connection, MARKET_DATA_URL, ORDER_UPDATE_URL, connectMarketData, connectOrderUpdate, subscribeMarketDepth, subscribeMarketQuote, subscribeOrderUpdate, unsubscribeMarketDepth, unsubscribeMarketQuote, unsubscribeOrderUpdate };