UNPKG

@suyotech-dev/shoonya-js

Version:

Unofficial shoonya api sdk for internal use developed by suytoech.com

305 lines (272 loc) 8.63 kB
import axios from "axios"; import { createHash } from "crypto"; import { TOTP } from "totp-generator"; export class ShoonyaAPI { #baseURL = "https://api.shoonya.com/NorenWClientTP"; uid = ""; #password = ""; #vc = ""; #actid = ""; #apikey = ""; #totopkey = ""; susertoken = ""; /** * @type {import("axios").AxiosInstance} */ #apiClient; /** * * @param {String} uid //User ID * @param {String} password // User Password * @param {String} vc // Vendor Code * @param {String} apikey // Api Key * @param {String} totpkey // Totp Key */ constructor(uid, password, vc, apikey, totpkey) { this.uid = uid; this.#actid = uid; this.#password = password; this.#vc = vc; this.#apikey = apikey; this.#totopkey = totpkey; this.#apiClient = this.#createAxiosInstance(); } #routes = { login: "/QuickAuth", userdetails: "/UserDetails", orderBook: "/OrderBook", tradeBook: "/TradeBook", positionBook: "/PositionBook", placeOrder: "/PlaceOrder", modifyOrder: "/ModifyOrder", cancelorder: "/CancelOrder", chartdata: "/TPSeries", holding: "/Holdings", limits: "/Limits", }; #createAxiosInstance() { let axiosInstance = axios.create({ baseURL: this.#baseURL, timeout: 7000, }); axiosInstance.interceptors.request.use((config) => { if (config.data) { const objtostr = (obj) => { let newObj = {}; Object.keys(obj).forEach((key) => { newObj[key] = String(obj[key]); }); return newObj; }; let data = `jData=${JSON.stringify(objtostr(config.data))}`; if (this.susertoken) { data = data + `&jKey=${this.susertoken}`; } config.data = data; } return config; }); axiosInstance.interceptors.response.use( (response) => { if (response.data.stat !== "Ok" && !Array.isArray(response.data)) { throw new Error(`Server Error : ${response.data.emsg}`); } return response; }, (error) => { if (error.response) { throw new Error( `Response Error : ${error.response?.data.emsg || error.resonse?.message}` ); } else if (error.request) { throw new Error(`Request Error : ${error.request?.message}`); } else { throw new Error(`General Error : ${error?.message}`); } } ); return axiosInstance; } #hash(value) { return createHash("sha256").update(value).digest("hex"); } async login() { try { const otp = TOTP.generate(this.#totopkey).otp; const request_data = { source: "API", apkversion: "1.0.0", uid: this.uid, pwd: this.#hash(this.#password), vc: this.#vc, appkey: this.#hash(`${this.uid}|${this.#apikey}`), factor2: otp, imei: "123123", }; const resp = await this.#apiClient.post(this.#routes.login, request_data); if (resp.data.susertoken) { this.susertoken = resp.data.susertoken; } return resp.data; } catch (error) { throw new Error(error.message); } } setSessionDetails(uid, susertoken) { this.uid = uid; this.susertoken = susertoken; } async getUserDetails() { try { const request_data = { uid: this.uid }; const resp = await this.#apiClient.post(this.#routes.userdetails, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } async getOderBook() { try { const request_data = { uid: this.uid }; const resp = await this.#apiClient.post(this.#routes.orderBook, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } async getTradeBook() { try { const request_data = { uid: this.uid, actid: this.#actid }; const resp = await this.#apiClient.post(this.#routes.tradeBook, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } async getPositionBook() { try { const request_data = { uid: this.uid, actid: this.#actid }; const resp = await this.#apiClient.post(this.#routes.positionBook, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } /** * Get Candle data * @param {Object} params * @param {String} params.exch Exchange * @param {String} params.token Symbol Token * @param {String} params.st Start Time in seconds (epoch) * @param {String} params.et End Time in seconds (epoch) * @returns */ async getCandleData(params) { try { const request_data = { uid: this.uid, ...params }; const resp = await this.#apiClient.post(this.#routes.chartdata, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } /** * Place Order * @param {Object} params Place Order Params * @param {String} params.exch Exchange NSE/NFO/CDS/MCX/BSE/BFO * @param {String} params.tsym Trading Symbol * @param {Number} params.qty Order Quantity * @param {Number} [params.prc] Order Price * @param {Number} [params.trgprc] Trigger Price * @param {String} params.prd Product "C" For CNC, "M" FOR NRML, "I" FOR MIS, "B" BRACKET ORDER, "H" FOR COVER ORDER * @param {String} params.trantype Transaction Type B -> BUY, S -> SELL * @param {String} params.prctyp Price Type LMT / MKT / SL-LMT / SL-MKT */ async placeOrder(params) { try { if (!["exch", "tsym", "qty", "prd", "trantype", "prctyp"].every((key) => key in params)) { throw new Error("Fields required exch,tysm,qty,prd,trantype,prctyp"); } const request_data = { uid: this.uid, actid: this.#actid, exch: params.exch, tsym: params.tsym, qty: params.qty || 1, prc: params.prc || 0, trgprc: params.trgprc || 0, prd: params.prd || "I", trantype: params.trantype, prctyp: params.prctyp || "MKT", dscqty: 0, ret: "DAY", ordersource: "API", }; console.log("request ", request_data); const resp = await this.#apiClient.post(this.#routes.placeOrder, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } /** * Modify Pendig Order * @param {Object} params Place Order Params * @param {String} params.exch Exchange NSE/NFO/CDS/MCX/BSE/BFO * @param {String} params.norenordno Order Number * @param {String} params.tsym Order Number * @param {Number} params.qty Order Quantity * @param {Number} params.prc Order Price * @param {Number} params.trgprc Trigger Price * @param {String} params.trantype Transaction Type B -> BUY, S -> SELL * @param {String} params.prctyp Price Type LMT / MKT / SL-LMT / SL-MKT */ async modifyOrder(params) { try { if ( !["exch", "norenordno", "tsym", "qty", "prc", "trgprc", "prctyp"].every( (key) => key in params ) ) { throw new Error("Fields required exch,tysm,qty,prd,trantype,prctyp"); } const request_data = { uid: this.uid, norenordno: params.norenordno, exch: params.exch, tsym: params.tsym, qty: params.qty || 1, prc: params.prc || 0, trgprc: params.trgprc || 0, prctyp: params.prctyp || "MKT", ret: "DAY", }; console.log("request ", request_data); const resp = await this.#apiClient.post(this.#routes.modifyOrder, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } /** * * @param {String} orderid Order ID * @returns */ async modifyOrder(orderid) { try { if (!orderid) { throw new Error("Fields required orderid"); } const request_data = { uid: this.uid, norenordno: orderid, }; console.log("request ", request_data); const resp = await this.#apiClient.post(this.#routes.cancelorder, request_data); return resp.data; } catch (error) { throw new Error(error.message); } } }