UNPKG

stock-nse-india

Version:

This package will help us to get equity/index details and historical data from National Stock Exchange of India.

921 lines 40.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NseIndia = exports.ApiList = void 0; const axios_1 = __importDefault(require("axios")); const axios_cookiejar_support_1 = require("axios-cookiejar-support"); const tough_cookie_1 = require("tough-cookie"); const user_agents_1 = __importDefault(require("user-agents")); const utils_1 = require("./utils"); const equity_mappers_1 = require("./equity-mappers"); var ApiList; (function (ApiList) { ApiList["GLOSSARY"] = "/api/cmsContent?url=/glossary"; ApiList["HOLIDAY_TRADING"] = "/api/holiday-master?type=trading"; ApiList["HOLIDAY_CLEARING"] = "/api/holiday-master?type=clearing"; ApiList["MARKET_STATUS"] = "/api/marketStatus"; ApiList["MARKET_TURNOVER"] = "/api/market-turnover"; ApiList["ALL_INDICES"] = "/api/allIndices"; ApiList["INDEX_NAMES"] = "/api/index-names"; ApiList["CIRCULARS"] = "/api/circulars"; ApiList["LATEST_CIRCULARS"] = "/api/latest-circular"; ApiList["EQUITY_MASTER"] = "/api/equity-master"; ApiList["MARKET_DATA_PRE_OPEN"] = "/api/market-data-pre-open?key=ALL"; ApiList["MERGED_DAILY_REPORTS_CAPITAL"] = "/api/merged-daily-reports?key=favCapital"; ApiList["MERGED_DAILY_REPORTS_DERIVATIVES"] = "/api/merged-daily-reports?key=favDerivatives"; ApiList["MERGED_DAILY_REPORTS_DEBT"] = "/api/merged-daily-reports?key=favDebt"; })(ApiList = exports.ApiList || (exports.ApiList = {})); class NseIndia { constructor() { this.baseUrl = 'https://www.nseindia.com'; this.cookieMaxAge = 60; // should be in seconds this.maxRetries = 3; this.apiHeaders = { 'Authority': 'www.nseindia.com', 'Referer': 'https://www.nseindia.com/', 'Accept': 'application/json, text/plain, */*', 'Origin': 'https://www.nseindia.com', 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive' }; this.nseJar = new tough_cookie_1.CookieJar(); this.chartingJar = new tough_cookie_1.CookieJar(); this.nseClient = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({ jar: this.nseJar })); this.chartingClient = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({ jar: this.chartingJar })); this.userAgent = ''; this.cookies = ''; this.cookieUsedCount = 0; this.cookieExpiry = 0; this.noOfConnections = 0; this.chartingBaseUrl = 'https://charting.nseindia.com'; this.chartingCookies = ''; this.chartingCookieUsedCount = 0; this.chartingCookieExpiry = 0; this.chartingUserAgent = ''; } resetNseClient() { this.nseJar = new tough_cookie_1.CookieJar(); this.nseClient = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({ jar: this.nseJar })); } resetChartingClient() { this.chartingJar = new tough_cookie_1.CookieJar(); this.chartingClient = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({ jar: this.chartingJar })); } invalidateNseSession() { this.cookies = ''; this.cookieExpiry = 0; this.cookieUsedCount = 0; this.resetNseClient(); } invalidateChartingSession() { this.chartingCookies = ''; this.chartingCookieExpiry = 0; this.chartingCookieUsedCount = 0; this.resetChartingClient(); } isAuthError(error) { var _a; if (axios_1.default.isAxiosError(error)) { const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status; return status === 401 || status === 403; } return false; } toHttpError(error) { var _a, _b, _c; if (axios_1.default.isAxiosError(error)) { const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status; const url = (_c = (_b = error.config) === null || _b === void 0 ? void 0 : _b.url) !== null && _c !== void 0 ? _c : 'unknown URL'; return new Error(`Request failed with status code ${status !== null && status !== void 0 ? status : 'unknown'} (${url})`); } if (error instanceof Error) { return error; } return new Error(String(error)); } async warmNsePage(path, referer = `${this.baseUrl}/`) { var _a; try { await this.nseClient.get(`${this.baseUrl}${path}`, { headers: { 'User-Agent': this.userAgent, Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br', Connection: 'keep-alive', Referer: referer } }); } catch (error) { // Warm-up is best-effort; NSE often returns 403/502/503 for HTML pages under load. if (axios_1.default.isAxiosError(error)) { const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status; if (status === 403 || status === 502 || status === 503) { return; } } throw this.toHttpError(error); } } async warmEquityQuotePage(symbol) { const upper = symbol.toUpperCase(); await this.warmNsePage(`/get-quotes/equity?symbol=${encodeURIComponent(upper)}`); } normalizeIndexDetails(raw) { var _a, _b; const data = ((_b = (_a = raw.data) !== null && _a !== void 0 ? _a : raw.records) !== null && _b !== void 0 ? _b : []); return { ...raw, data }; } /** * Bootstrap NSE session via homepage and persist all Set-Cookie values in the jar. * Note: some endpoints (e.g. /api/quote-equity) may still return 403 from Akamai WAF * even with a valid session. */ async ensureNseSession(force = false) { const needsRefresh = force || this.cookies === '' || this.cookieUsedCount > 10 || this.cookieExpiry <= Date.now(); if (needsRefresh) { this.userAgent = new user_agents_1.default().toString(); await this.nseClient.get(`${this.baseUrl}/`, { headers: { 'User-Agent': this.userAgent, Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br', Connection: 'keep-alive' } }); this.cookies = await this.nseJar.getCookieString(this.baseUrl); this.cookieUsedCount = 0; this.cookieExpiry = Date.now() + (this.cookieMaxAge * 1000); } this.cookieUsedCount++; return this.cookies; } /** @deprecated Use ensureNseSession internally; kept for tests that spy on cookie bootstrap. */ async getNseCookies() { return this.ensureNseSession(); } /** * Get cookies for charting.nseindia.com domain * Used as fallback when charting API fails with NSE cookies * @returns Charting domain cookies */ async ensureChartingSession(force = false) { const needsRefresh = force || this.chartingCookies === '' || this.chartingCookieUsedCount > 10 || this.chartingCookieExpiry <= Date.now(); if (needsRefresh) { this.chartingUserAgent = new user_agents_1.default().toString(); await this.chartingClient.get(`${this.chartingBaseUrl}/`, { headers: { 'Authority': 'charting.nseindia.com', 'Referer': `${this.chartingBaseUrl}/`, Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br', Connection: 'keep-alive', 'User-Agent': this.chartingUserAgent } }); this.chartingCookies = await this.chartingJar.getCookieString(this.chartingBaseUrl); this.chartingCookieUsedCount = 0; this.chartingCookieExpiry = Date.now() + (this.cookieMaxAge * 1000); } this.chartingCookieUsedCount++; return this.chartingCookies; } async getChartingCookies() { return this.ensureChartingSession(); } /** * * @param url NSE API's URL or charting API URL * @param domain Domain type: 'nse' for www.nseindia.com, 'charting' for charting.nseindia.com * @returns JSON data from NSE India or charting service */ async getData(url, domain = 'nse') { let retries = 0; let sessionRefreshed = false; while (retries < this.maxRetries) { while (this.noOfConnections >= 5) { await (0, utils_1.sleep)(500); } this.noOfConnections++; try { if (domain === 'charting') { const chartingHeaders = { 'Authority': 'charting.nseindia.com', 'Referer': `${this.chartingBaseUrl}/`, Accept: 'application/json, text/plain, */*', 'Accept-Language': 'en-GB,en;q=0.5', 'Accept-Encoding': 'gzip, deflate, br', Connection: 'keep-alive' }; await this.ensureNseSession(sessionRefreshed); let response; try { response = await this.chartingClient.get(url, { headers: { ...chartingHeaders, Cookie: this.cookies, 'User-Agent': this.userAgent } }); } catch (primaryError) { const chartingCookies = await this.ensureChartingSession(this.isAuthError(primaryError)); response = await this.chartingClient.get(url, { headers: { ...chartingHeaders, Cookie: chartingCookies, 'User-Agent': this.chartingUserAgent || this.userAgent } }); } this.noOfConnections--; return response.data; } await this.ensureNseSession(sessionRefreshed); const apiHeaders = { ...this.apiHeaders, 'User-Agent': this.userAgent }; if (url.includes('/api/quote-equity') || url.includes('/api/NextApi/apiClient/GetQuoteApi')) { const symbolMatch = url.match(/[?&]symbol=([^&]+)/); const apiSymbol = symbolMatch ? decodeURIComponent(symbolMatch[1]) : 'TCS'; const refererSymbol = (0, equity_mappers_1.equityRefererSymbol)(apiSymbol); await this.warmEquityQuotePage(refererSymbol); apiHeaders.Referer = `${this.baseUrl}/get-quotes/equity?symbol=${encodeURIComponent(refererSymbol)}`; } else if (url.includes('/api/equity-stockIndices')) { const indexMatch = url.match(/[?&]index=([^&]+)/); const index = indexMatch ? decodeURIComponent(indexMatch[1]) : 'NIFTY%2050'; const indexPath = `/market-data/live-equity-market?symbol=${encodeURIComponent(index)}`; await this.warmNsePage(indexPath); apiHeaders.Referer = `${this.baseUrl}${indexPath}`; } const response = await this.nseClient.get(url, { headers: apiHeaders }); this.noOfConnections--; return response.data; } catch (error) { this.noOfConnections--; retries++; if (this.isAuthError(error) && !sessionRefreshed) { this.invalidateNseSession(); sessionRefreshed = true; continue; } throw this.toHttpError(error); } } throw new Error(`NSE request failed after ${this.maxRetries} attempts`); } /** * * @param apiEndpoint * @returns */ async getDataByEndpoint(apiEndpoint) { return this.getData(`${this.baseUrl}${apiEndpoint}`); } /** * Get historical chart data from charting.nseindia.com * @param symbol Equity symbol with series (e.g., 'ONGC') * @param range Optional date range for chart data query * @param token NSE script code (token) for the symbol. If not provided, it is * automatically fetched via {@link getEquitySymbolInfo}. * @param symbolType Type of symbol (e.g., 'Equity', 'Index') * @param chartType Chart type (e.g., 'I' for intraday, 'D' for daily) * @param timeInterval Time interval in minutes (e.g., '5', '15', '60') * @returns Chart data from charting service */ async getEquityChartHistoricalData(symbol, range, token, symbolType = 'Equity', chartType = 'I', timeInterval = '5') { var _a, _b; const endDate = (_a = range === null || range === void 0 ? void 0 : range.end) !== null && _a !== void 0 ? _a : new Date(); const startDate = (_b = range === null || range === void 0 ? void 0 : range.start) !== null && _b !== void 0 ? _b : new Date(endDate.getTime() - 24 * 60 * 60 * 1000); const fromDate = Math.floor(startDate.getTime() / 1000); const toDate = Math.floor(endDate.getTime() / 1000); // Auto-fetch token (scripCode) when not supplied by the caller let resolvedToken = token; if (!resolvedToken) { const symbolInfo = await this.getEquitySymbolInfo(symbol); resolvedToken = symbolInfo.scripcode; } const url = `${this.chartingBaseUrl}/v1/charts/symbolHistoricalData?` + `fromDate=${fromDate}&` + `toDate=${toDate}&` + `symbol=${encodeURIComponent(symbol)}&` + `token=${resolvedToken}&` + `symbolType=${encodeURIComponent(symbolType)}&` + `chartType=${encodeURIComponent(chartType)}&` + `timeInterval=${timeInterval}`; return this.getData(url, 'charting'); } /** * Look up the NSE script code (token) for an equity symbol using the charting domain. * The `scripCode` in the returned object is the value that must be passed as `token` * to {@link getEquityChartHistoricalData}. * @param symbol Equity symbol with series code (e.g., 'ONGC') OR plain symbol (e.g., 'ONGC') * @param segment Optional market segment filter (default: empty string, returns all segments) * @returns Symbol information including scripCode / token */ async getEquitySymbolInfo(symbol, segment = '') { const url = `${this.chartingBaseUrl}/v1/exchanges/symbolsDynamic` + `?symbol=${encodeURIComponent(symbol)}&segment=${encodeURIComponent(segment)}`; const response = await this.getData(url, 'charting'); let symbolList = response; if (!Array.isArray(response) && response && typeof response === 'object' && Array.isArray(response.data)) { symbolList = response.data; } // The API returns an array; pick the best match: prefer exact symbol match if (!Array.isArray(symbolList) || symbolList.length === 0) { throw new Error(`No symbol info found for: ${symbol}`); } // Try exact match first (symbol === input), fall back to first result const upperSymbol = symbol.toUpperCase(); const exact = symbolList.find((s) => { var _a; return ((_a = s.symbol) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === upperSymbol; }); return exact !== null && exact !== void 0 ? exact : symbolList[0]; } /** * * @returns List of NSE equity symbols */ async getAllStockSymbols() { const { data } = await this.getDataByEndpoint(ApiList.MARKET_DATA_PRE_OPEN); return data.map((obj) => obj.metadata.symbol).sort(); } async getPreOpenMarketCached() { if (!this.preOpenCache || this.preOpenCache.expiry <= Date.now()) { const data = await this.getDataByEndpoint(ApiList.MARKET_DATA_PRE_OPEN); this.preOpenCache = { data, expiry: Date.now() + (this.cookieMaxAge * 1000) }; } return this.preOpenCache.data; } async resolveCapitalMarketType() { var _a, _b, _c; if (this.capitalMarketTypeCache && this.capitalMarketTypeCache.expiry > Date.now()) { return this.capitalMarketTypeCache.type; } try { const status = await this.getMarketStatus(); const capital = (_a = status.marketState) === null || _a === void 0 ? void 0 : _a.find((entry) => entry.market === 'Capital Market'); const marketStatus = (_c = (_b = capital === null || capital === void 0 ? void 0 : capital.marketStatus) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : ''; let type = 'NM'; if (marketStatus.includes('pre') && marketStatus.includes('open')) { type = 'preOpen'; } this.capitalMarketTypeCache = { type, expiry: Date.now() + (this.cookieMaxAge * 1000) }; return type; } catch (_d) { return 'NM'; } } async fetchEquityDetailsEnrichment(symbol) { const upper = symbol.toUpperCase(); let chartingName = ''; let chartingIsin = ''; let corporateName = ''; let corporateIsin = ''; let corporateIndustry = ''; await Promise.all([ this.getEquitySymbolInfo(upper) .then((info) => { var _a, _b, _c; chartingName = ((_a = info.companyName) === null || _a === void 0 ? void 0 : _a.trim()) || ((_b = info.description) === null || _b === void 0 ? void 0 : _b.trim()) || ''; chartingIsin = ((_c = info.isin) === null || _c === void 0 ? void 0 : _c.trim()) || ''; }) .catch(() => undefined), this.getDataByEndpoint(`/api/corporates-financial-results?index=equities&symbol=${encodeURIComponent(upper)}`) .then((rows) => { var _a, _b, _c, _d; if (!Array.isArray(rows) || rows.length === 0) return; const row = (_a = rows.find((entry) => entry.isin && entry.isin !== '-')) !== null && _a !== void 0 ? _a : rows[0]; corporateName = ((_b = row.companyName) === null || _b === void 0 ? void 0 : _b.trim()) || ''; corporateIsin = ((_c = row.isin) === null || _c === void 0 ? void 0 : _c.trim()) && row.isin !== '-' ? row.isin.trim() : ''; corporateIndustry = ((_d = row.industry) === null || _d === void 0 ? void 0 : _d.trim()) && row.industry !== '-' ? row.industry.trim() : ''; }) .catch(() => undefined) ]); const enrichment = {}; if (corporateName || chartingName) { enrichment.companyName = corporateName || chartingName; } if (corporateIsin || chartingIsin) { enrichment.isin = corporateIsin || chartingIsin; } if (corporateIndustry) { enrichment.industry = corporateIndustry; } return enrichment; } async enrichPreOpenEquityDetails(details, symbol) { const [marketType, enrichment] = await Promise.all([ this.resolveCapitalMarketType(), this.fetchEquityDetailsEnrichment(symbol) ]); return (0, equity_mappers_1.applyEquityDetailsEnrichment)(details, { ...enrichment, currentMarketType: marketType }); } /** * Equity quote with fallback when /api/quote-equity is blocked (Akamai 403). * Primary: quote-equity JSON; fallback: market-data-pre-open row for the symbol. */ async getEquityDetails(symbol) { var _a; const upper = symbol.toUpperCase(); const attempts = []; try { const raw = await this.getDataByEndpoint(`/api/quote-equity?symbol=${encodeURIComponent(upper)}`); if ((0, equity_mappers_1.isEquityDetailsShape)(raw)) { return (0, equity_mappers_1.mapQuoteEquityResponse)(raw); } attempts.push('quote-equity: unexpected response shape'); } catch (error) { const message = error instanceof Error ? error.message : String(error); attempts.push(`quote-equity: ${message}`); if (!(0, equity_mappers_1.isRetryableEquityEndpointError)(error)) { throw error instanceof Error ? error : new Error(message); } } try { const preOpen = await this.getPreOpenMarketCached(); const row = (_a = preOpen.data) === null || _a === void 0 ? void 0 : _a.find((entry) => { var _a; return ((_a = entry.metadata) === null || _a === void 0 ? void 0 : _a.symbol) === upper; }); if (row) { const mapped = (0, equity_mappers_1.mapPreOpenRowToEquityDetails)(row, upper); return this.enrichPreOpenEquityDetails(mapped, upper); } attempts.push('pre-open: symbol not found in market-data-pre-open'); } catch (error) { const message = error instanceof Error ? error.message : String(error); attempts.push(`pre-open: ${message}`); } throw new Error(`No equity quote available for ${upper}. Attempts: ${attempts.join('; ')}`); } /** * * @param symbol * @returns */ async getEquityTradeInfo(symbol) { var _a; const upper = symbol.toUpperCase(); const attempts = []; try { const raw = await this.getDataByEndpoint(`/api/quote-equity?symbol=${encodeURIComponent(upper)}&section=trade_info`); if ((0, equity_mappers_1.isEquityTradeInfoShape)(raw)) { return (0, equity_mappers_1.mapQuoteEquityTradeInfoResponse)(raw); } attempts.push('quote-equity trade_info: unexpected response shape'); } catch (error) { const message = error instanceof Error ? error.message : String(error); attempts.push(`quote-equity trade_info: ${message}`); if (!(0, equity_mappers_1.isRetryableEquityEndpointError)(error)) { throw error instanceof Error ? error : new Error(message); } } try { const preOpen = await this.getPreOpenMarketCached(); const row = (_a = preOpen.data) === null || _a === void 0 ? void 0 : _a.find((entry) => { var _a; return ((_a = entry.metadata) === null || _a === void 0 ? void 0 : _a.symbol) === upper; }); if (row) { return (0, equity_mappers_1.mapPreOpenRowToEquityTradeInfo)(row, upper); } attempts.push('pre-open: symbol not found in market-data-pre-open'); } catch (error) { const message = error instanceof Error ? error.message : String(error); attempts.push(`pre-open: ${message}`); } throw new Error(`No equity trade info available for ${upper}. Attempts: ${attempts.join('; ')}`); } /** * * @param symbol * @returns */ getEquityCorporateInfo(symbol) { return this.getDataByEndpoint(`/api/top-corp-info?symbol=${encodeURIComponent(symbol .toUpperCase())}&market=equities`); } /** * * @param symbol * @returns */ async getEquityIntradayData(symbol) { var _a; const upper = symbol.toUpperCase(); const attempts = []; const chartSymbols = [`${upper}-EQ`, upper]; for (const chartSymbol of chartSymbols) { try { const raw = await this.getDataByEndpoint(`/api/NextApi/apiClient/GetQuoteApi?functionName=getSymbolChartData` + `&symbol=${encodeURIComponent(chartSymbol)}&days=1D`); if ((0, equity_mappers_1.isIntradayDataShape)(raw)) { return (0, equity_mappers_1.mapIntradayApiResponse)(raw, upper); } attempts.push(`${chartSymbol}: unexpected response shape`); } catch (error) { const message = error instanceof Error ? error.message : String(error); attempts.push(`${chartSymbol}: ${message}`); if (!(0, equity_mappers_1.isRetryableEquityEndpointError)(error)) { throw error instanceof Error ? error : new Error(message); } } } try { const chart = await this.getEquityChartHistoricalData(upper, undefined, undefined, 'Equity', 'I', '5'); if ((_a = chart === null || chart === void 0 ? void 0 : chart.data) === null || _a === void 0 ? void 0 : _a.length) { return (0, equity_mappers_1.mapChartingToIntradayData)(chart, upper); } attempts.push('charting: empty data'); } catch (error) { const message = error instanceof Error ? error.message : String(error); attempts.push(`charting: ${message}`); } throw new Error(`No intraday data available for ${upper}. Attempts: ${attempts.join('; ')}`); } /** * * @param symbol * @param range * @returns */ async getEquityHistoricalData(symbol, range) { var _a, _b; const upper = symbol.toUpperCase(); let activeSeries = 'EQ'; if (!range) { const data = await this.getEquityDetails(upper); activeSeries = data.info.activeSeries.length ? data.info.activeSeries[0] : 'EQ'; const now = new Date(); const listingDate = new Date(data.metadata.listingDate); const hasValidListingDate = !Number.isNaN(listingDate.getTime()); const fallbackStart = new Date(now); fallbackStart.setFullYear(now.getFullYear() - 1); range = { start: hasValidListingDate ? listingDate : fallbackStart, end: now }; } else { try { const seriesData = await this.getEquitySeries(upper); const seriesList = (_a = seriesData.data) !== null && _a !== void 0 ? _a : []; activeSeries = seriesList.includes('EQ') ? 'EQ' : ((_b = seriesList[0]) !== null && _b !== void 0 ? _b : 'EQ'); } catch (_c) { activeSeries = 'EQ'; } } const dateRanges = (0, utils_1.getDateRangeChunks)(range.start, range.end, 66); const promises = dateRanges.map(async (dateRange) => { const url = `/api/NextApi/apiClient/GetQuoteApi?functionName=getHistoricalTradeData` + `&symbol=${encodeURIComponent(symbol.toUpperCase())}` + `&series=${encodeURIComponent(activeSeries)}` + `&fromDate=${dateRange.start}&toDate=${dateRange.end}`; const response = await this.getDataByEndpoint(url); // New API returns a direct array, wrap it in EquityHistoricalData structure for backward compatibility /* istanbul ignore next */ return { data: Array.isArray(response) ? response : [], meta: { series: [activeSeries], fromDate: dateRange.start, toDate: dateRange.end, symbols: [symbol.toUpperCase()] } }; }); return Promise.all(promises); } /** * * @param symbol * @returns */ async getEquitySeries(symbol) { const response = await this.getDataByEndpoint(`/api/NextApi/apiClient/GetQuoteApi?functionName=histTradeDataSeries` + `&symbol=${encodeURIComponent(symbol.toUpperCase())}`); // New API returns a direct array, wrap it in SeriesData structure for backward compatibility /* istanbul ignore next */ return { data: Array.isArray(response) ? response : [] }; } /** * * @param index * @returns */ async getEquityStockIndices(index) { var _a; const indexParam = encodeURIComponent(index.toUpperCase()); const legacyUrl = `${this.baseUrl}/api/equity-stockIndices?index=${indexParam}`; const summaryUrl = `${this.baseUrl}/api/equity-stockIndex?index=${indexParam}`; try { const legacy = await this.getData(legacyUrl); const normalized = this.normalizeIndexDetails(legacy); if ((_a = normalized.data) === null || _a === void 0 ? void 0 : _a.length) { return normalized; } } catch (legacyError) { const message = legacyError instanceof Error ? legacyError.message : ''; if (!message.includes('404')) { throw legacyError; } } const summary = await this.getData(summaryUrl); return this.normalizeIndexDetails(summary); } /** * * @param index * @returns */ async getIndexIntradayData(index) { const response = await this.getDataByEndpoint(`/api/NextApi/apiClient?functionName=getGraphChart` + `&type=${encodeURIComponent(index.toUpperCase())}&flag=1D`); // The API response is wrapped in a 'data' object /* istanbul ignore next */ return response.data || response; } /** * Get option chain contract information (expiry dates and strike prices) for an index * * @param indexSymbol * @returns */ getIndexOptionChainContractInfo(indexSymbol) { return this.getDataByEndpoint(`/api/option-chain-contract-info?symbol=${encodeURIComponent(indexSymbol.toUpperCase())}`); } /** * * @param indexSymbol * @param expiry Optional expiry date in DD-MMM-YYYY format (e.g., "23-Dec-2025"). * If not provided, will fetch nearest upcoming expiry * @returns */ async getIndexOptionChain(indexSymbol, expiry) { // If expiry not provided, fetch the nearest upcoming expiry date from the API if (!expiry) { /* istanbul ignore next */ const contractInfo = await this.getIndexOptionChainContractInfo(indexSymbol); /* istanbul ignore next */ if (contractInfo && contractInfo.expiryDates && Array.isArray(contractInfo.expiryDates)) { /* istanbul ignore next */ const today = new Date(); /* istanbul ignore next */ today.setHours(0, 0, 0, 0); // Reset time to start of day for comparison // Find the nearest upcoming expiry date /* istanbul ignore next */ let nearestExpiry = null; /* istanbul ignore next */ let nearestDate = null; /* istanbul ignore next */ for (const expiryDateStr of contractInfo.expiryDates) { // Parse date in DD-MMM-YYYY format /* istanbul ignore next */ const dateParts = expiryDateStr.split('-'); /* istanbul ignore next */ if (dateParts.length === 3) { /* istanbul ignore next */ const day = parseInt(dateParts[0], 10); /* istanbul ignore next */ const monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; /* istanbul ignore next */ const month = monthNames.indexOf(dateParts[1]); /* istanbul ignore next */ const year = parseInt(dateParts[2], 10); /* istanbul ignore next */ if (month !== -1) { /* istanbul ignore next */ const expiryDate = new Date(year, month, day); /* istanbul ignore next */ expiryDate.setHours(0, 0, 0, 0); // Check if this expiry is in the future or today /* istanbul ignore next */ if (expiryDate >= today) { /* istanbul ignore next */ if (!nearestDate || expiryDate < nearestDate) { /* istanbul ignore next */ nearestDate = expiryDate; /* istanbul ignore next */ nearestExpiry = expiryDateStr; } } } } } /* istanbul ignore next */ if (nearestExpiry) { /* istanbul ignore next */ expiry = nearestExpiry; } else { // Fallback: use the last expiry date if no upcoming date found /* istanbul ignore next */ expiry = contractInfo.expiryDates[contractInfo.expiryDates.length - 1]; } } else { // Fallback: use current date if API fails /* istanbul ignore next */ const today = new Date(); /* istanbul ignore next */ const day = today.getDate().toString().padStart(2, '0'); /* istanbul ignore next */ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; /* istanbul ignore next */ const month = months[today.getMonth()]; /* istanbul ignore next */ const year = today.getFullYear(); /* istanbul ignore next */ expiry = `${day}-${month}-${year}`; } } // Ensure expiry is defined (should always be set by this point) /* istanbul ignore next */ if (!expiry) { /* istanbul ignore next */ throw new Error('Failed to determine expiry date'); } return this.getDataByEndpoint(`/api/option-chain-v3?type=Indices` + `&symbol=${encodeURIComponent(indexSymbol.toUpperCase())}` + `&expiry=${encodeURIComponent(expiry)}`); } /** * * @param symbol * @returns */ getEquityOptionChain(symbol) { return this.getDataByEndpoint(`/api/NextApi/apiClient/GetQuoteApi?functionName=getSymbolDerivativesData` + `&symbol=${encodeURIComponent(symbol.toUpperCase())}`); } /** * * @param symbol * @returns */ getCommodityOptionChain(symbol) { return this.getDataByEndpoint(`/api/option-chain-com?symbol=${encodeURIComponent(symbol .toUpperCase())}`); } /** * Get NSE glossary content * @returns Glossary content */ getGlossary() { return this.getDataByEndpoint(ApiList.GLOSSARY); } /** * Get trading holidays * @returns List of trading holidays */ getTradingHolidays() { return this.getDataByEndpoint(ApiList.HOLIDAY_TRADING); } /** * Get clearing holidays * @returns List of clearing holidays */ getClearingHolidays() { return this.getDataByEndpoint(ApiList.HOLIDAY_CLEARING); } /** * Get market status * @returns Current market status */ getMarketStatus() { return this.getDataByEndpoint(ApiList.MARKET_STATUS); } /** * Get market turnover * @returns Market turnover data */ getMarketTurnover() { return this.getDataByEndpoint(ApiList.MARKET_TURNOVER); } /** * Get all indices * @returns List of all indices */ getAllIndices() { return this.getDataByEndpoint(ApiList.ALL_INDICES); } /** * Get index names * @returns List of index names */ getIndexNames() { return this.getDataByEndpoint(ApiList.INDEX_NAMES); } /** * Get circulars * @returns List of circulars */ getCirculars() { return this.getDataByEndpoint(ApiList.CIRCULARS); } /** * Get latest circulars * @returns List of latest circulars */ getLatestCirculars() { return this.getDataByEndpoint(ApiList.LATEST_CIRCULARS); } /** * Get equity master * @returns Equity master data with categorized indices */ getEquityMaster() { return this.getDataByEndpoint(ApiList.EQUITY_MASTER); } /** * Get pre-open market data * @returns Pre-open market data */ getPreOpenMarketData() { return this.getDataByEndpoint(ApiList.MARKET_DATA_PRE_OPEN); } /** * Get merged daily reports for capital market * @returns Daily reports for capital market */ getMergedDailyReportsCapital() { return this.getDataByEndpoint(ApiList.MERGED_DAILY_REPORTS_CAPITAL); } /** * Get merged daily reports for derivatives * @returns Daily reports for derivatives */ getMergedDailyReportsDerivatives() { return this.getDataByEndpoint(ApiList.MERGED_DAILY_REPORTS_DERIVATIVES); } /** * Get merged daily reports for debt market * @returns Daily reports for debt market */ getMergedDailyReportsDebt() { return this.getDataByEndpoint(ApiList.MERGED_DAILY_REPORTS_DEBT); } /** * Get technical indicators for a specific equity symbol * @param symbol - The equity symbol (e.g., 'RELIANCE', 'TCS') * @param period - Number of days for historical data (default: 200) * @param options - Optional configuration for indicators * @returns Promise<TechnicalIndicators> */ async getTechnicalIndicators(symbol, period = 200, options = {}) { const { getTechnicalIndicators } = await Promise.resolve().then(() => __importStar(require('./helpers'))); return getTechnicalIndicators(symbol, period, options); } } exports.NseIndia = NseIndia; //# sourceMappingURL=index.js.map