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
JavaScript
"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)}§ion=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