const axios = require("axios").default; import { dnetwork, TObject } from "."; import { dlog } from "./dlog"; import { dserialization } from "./dserialization"; import { dtime } from "./dtime"; export namespace yahooFin { export const IndexGroup = { WORLD_INDEX: [ { name: "S&P 500", key: "^GSPC" }, { name: "Dow Jones", key: "^DJI" }, { name: "NASDAQ", key: "^IXIC" }, { name: "RUT", key: "^RUT" }, { name: "FTSE 100", key: "^FTSE" }, { name: "DAX", key: "^GDAXI" }, { name: "CAC 40", key: "^FCHI" }, { name: "NIKKEI 225", key: "^N225 " }, { name: "HANG SENG", key: "^HSI " }, ], INDIA_INDEX: [ { name: "NIfty 50", key: "^NSEI" }, { name: "Nitfy Bank", key: "^NSEBANK" }, { name: "SENSEX", key: "^BSESN" }, ], }; // define types export type TStockInfo = { _id: string; ltp: number; open: number; symbol: string; name: string; exchange: TExchange; volume: number; high: number; low: number; change: number; pchange: number; timestamp: number; // opt week52High?: number; week52Low?: number; avgVolume?: number; yAnalystRating?: string; pre_ltp?: number; pre_pchange?: number; post_ltp?: number; post_pchange?: number; previousClose?: number; ltp_ext?: number; // this will inlcude the ltp with pre and post market clock_type: TClockType // extra [key: string]: any; // raw raw_payload?: any; }; const unknownValue: TStockInfo = { _id: 'unknown', ltp: 0, open: 0, symbol: 'unknown', name: 'unknown', exchange: "NASDAQ", volume: 0, high: 0, low: 0, change: 0, pchange: 0, timestamp: 0, clock_type: "OFF_MARKET" }; export type TExchange = "NSE" | "BSE" | "NASDAQ" | "LSE"; let hardMapping: TObject = { "ES=F": "ES1!", }; export function getTradingViewKey(key: string) { if (hardMapping[key]) { return hardMapping[key]; } let sym = ""; if (key.startsWith("^")) { sym = key.replace("^", ""); } else if (key.endsWith(".NS")) sym = "NSE:" + key.replace(".NS", ""); else if (key.endsWith(".BS")) sym = "BSE:" + key.replace(".BS", ""); else if (key.endsWith(".L")) sym = "LSE:" + key.replace(".L", ""); else sym = "NASDAQ:" + key.replace("", ""); sym = sym.replace("^", ""); return sym; } export function isSymbolSupportedByExchange(symbol: string, exchange: TExchange): boolean { if (symbol.endsWith(".NS")) return exchange == "NSE"; if (symbol.endsWith(".BS")) return exchange == "BSE"; if (symbol.endsWith(".L")) return exchange == "LSE"; return exchange == "NASDAQ"; } const extMap = { NSE: ".NS", BSE: ".BS", NASDAQ: "", LSE: ".L" }; export function getExchangeFromKey(id: string): TExchange { if (!id) { return "NASDAQ"; } if (id.endsWith(".BS")) return "BSE"; if (id.endsWith(".NS")) return "NSE"; if (id.endsWith(".L")) return "LSE"; return "NASDAQ"; } export function getSymbolFromFullKey(key: string) { if (!key) { return key; } return key.replace(".NS", "").replace(".L", "").replace(".BS", ""); } export function getKeyFromSymbol(symbol: string, exchange: TExchange) { if (exchange == "NSE") return symbol + ".NS"; if (exchange == "BSE") return symbol + ".BS"; if (exchange == "LSE") return symbol + ".L"; return symbol; } // If the Yfin -> TV is not mapped put a override here let overrideMap: TObject = { "ES=F": "ES1!", "^GSPC": "SPX", "^DJI": "DJI", "^IXIC": "IXIC", "^FTSC": "FTSE100", "^NSEI": "NSE:NANIFTY", "^NSEBANK": "NSE:BANKNIFTY", }; export function getTradingViewUrl(s: yahooFin.TStockInfo): string { if (overrideMap[s.symbol]) { return `https://www.tradingview.com/chart/?symbol=${overrideMap[s.symbol]}`; } else if (s.symbol.toLowerCase().endsWith('.ns')) { return `https://www.tradingview.com/chart/?symbol=NSE:${s.symbol.toLowerCase().replace('.ns', '')}`; } else if (s.symbol.toLowerCase().endsWith('.bs')) { return `https://www.tradingview.com/chart/?symbol=BSE:${s.symbol.toLowerCase().replace('.bs', '')}`; } else if (s.symbol.toLowerCase().endsWith('.l')) { return `https://www.tradingview.com/chart/?symbol=LSE:${s.symbol.toLowerCase().replace('.l', '')}`; } return `https://www.tradingview.com/chart/?symbol=${getYEx2TvEx(s.exchange)}:${s.symbol}`; } export function getYEx2TvEx(s: string): string { if (s === "NASDAQ") { return "NASDAQ"; } if (s === "NSI") { return "NSE"; } if (s === "LSE") { return "LSE"; } if (s === "NYQ") { return "NYSE"; } return "NASDAQ"; } // old yahoo API which not work anymore export async function getBulkStockQuoteWithFullKey1(symbols: string[]): Promise { if (!symbols || symbols.length == 0) { return []; } let result: TStockInfo[] = []; try { let data = await dnetwork.getAsFakeBrowser(`https://query1.finance.yahoo.com/v7/finance/quote?formatted=true&symbols=${symbols.join(",")}`); for (let d of data.quoteResponse.result) { //dlog.obj(d.postMarketChangePercent); try { let info: TStockInfo = { _id: d.symbol, symbol: getSymbolFromFullKey(d.symbol), name: d.shortName, exchange: getExchangeFromKey(d.symbol), ltp: d.regularMarketPrice.raw, open: d.regularMarketOpen.raw, low: d.regularMarketDayLow.raw, high: d.regularMarketDayHigh.raw, volume: d.regularMarketVolume.raw, avgVolume: d.averageDailyVolume3Month?.raw, week52High: d.fiftyTwoWeekHigh.raw, week52Low: d.fiftyTwoWeekLow.raw, change: d.regularMarketChange.raw, pchange: d.regularMarketChangePercent.raw, yAnalystRating: d.averageAnalystRating, post_ltp: d.postMarketPrice?.raw, post_pchange: d.postMarketChangePercent?.raw, pre_ltp: d.preMarketPrice?.raw, pre_pchange: d.preMarketChangePercent?.raw, previousClose: d.regularMarketPreviousClose?.raw, timestamp: d.regularMarketTime.raw, raw_payload: d, clock_type: 'OFF_MARKET' } processStockInfo(info) result.push(info); } catch (e) { dlog.e("Not getting data for " + e); } } //dlog.obj(result); return result; } catch (e) { dlog.ex(e as Error, true); } return result; } // This process will use quite api with indivisual data as the previous version stooped working export async function getBulkStockQuoteWithFullKey2(symbols: string[]): Promise { if (!symbols || symbols.length == 0) { return []; } let result: TStockInfo[] = []; for (let s of symbols) { try { let url = `https://query2.finance.yahoo.com/v10/finance/quoteSummary/${s}?modules=price` let data = await dnetwork.getAsFakeBrowser(url); let d = data.quoteSummary.result[0].price; let info: TStockInfo = { _id: d.symbol, symbol: getSymbolFromFullKey(d.symbol), name: d.shortName, exchange: getExchangeFromKey(d.symbol), ltp: d.regularMarketPrice?.raw || 0, open: d.regularMarketOpen?.raw || 0, low: d.regularMarketDayLow?.raw || 0, high: d.regularMarketDayHigh?.raw || 0, volume: d.regularMarketVolume?.raw || 0, avgVolume: d.averageDailyVolume3Month?.raw || 0, week52High: d.fiftyTwoWeekHigh?.raw || 0, week52Low: d.fiftyTwoWeekLow?.raw || 0, change: d.regularMarketChange?.raw || 0, pchange: (d.regularMarketChangePercent?.raw || 0) * 100, yAnalystRating: d.averageAnalystRating || 0, post_ltp: d.postMarketPrice?.raw || 0, post_pchange: (d.postMarketChangePercent?.raw || 0) * 100, pre_ltp: d.preMarketPrice?.raw || 0, pre_pchange: (d.preMarketChangePercent?.raw || 0) * 100, previousClose: d.regularMarketPreviousClose?.raw || 0, timestamp: d.regularMarketTime?.raw || 0, raw_payload: d, clock_type: 'OFF_MARKET' } processStockInfo(info) result.push(info); } catch (e) { dlog.ex(e as Error, true); } } return result; } // tipranks APi calls export async function getBulkStockQuoteWithFullKey3(symbols: string[]): Promise { if (!symbols || symbols.length == 0) { return []; } let url = `https://market.tipranks.com/api/details/GetRealTimeQuotes?tickers=${symbols.join(',')}` let data = await dnetwork.getAsFakeBrowser(url); let result: TStockInfo[] = []; for (let d of data) { result.push({ // required _id: d.ticker, ltp: d.price, open: d.openPrice, symbol: d.ticker, name: d.ticker, exchange: 'NASDAQ', volume: d.totalValue, high: d.high, low: d.low, change: d.changeAmount, pchange: d.changePercent, timestamp: d.lastTradeDate, clock_type: d.isMarketOpen ? 'ON_MARKET' : (d.isPreMarketTime ? 'PRE_MARKET' : 'OFF_MARKET'), // optinal week52High: d.high52Weeks, week52Low: d.low52Weeks, pre_ltp: d.preMarket?.price, pre_pchange: d.preMarket?.changePercent, post_ltp: d.afterHours?.price, post_pchange: d.afterHours?.changePercent, }) } return result; } export type TInterval = "1d" | "5m" | "15m" | "1h"; export type TRange = "1d" | "5d" | "1mo" | "3mo" | "6mo" | "1y" | "2y" | "5y" | "10y" | "ytd" | "max"; export type THistoryData = { timestamp: number[]; open: number[]; close: number[]; high: number[]; low: number[]; volume: number[]; date: Date[] }; export async function getHistoryData(symbol: string, interval: TInterval, candle_count?: number, range?:TRange): Promise { candle_count = candle_count || 1000; try { let resp = await axios.get(`https://query1.finance.yahoo.com/v8/finance/chart/${symbol}?range=${range || '1mo'}&interval=${interval}`); //console.log(resp); let head = resp.data.chart.result[0]; return { timestamp: head.timestamp.slice(-candle_count), date: head.timestamp.slice(-candle_count).map((x: number) => new Date(x * 1000)), open: head.indicators.quote[0].open.slice(-candle_count), close: head.indicators.quote[0].close.slice(-candle_count), high: head.indicators.quote[0].high.slice(-candle_count), low: head.indicators.quote[0].low.slice(-candle_count), volume: head.indicators.quote[0].volume.slice(-candle_count), }; } catch (e) { dlog.ex(e as Error, true); } return undefined; } export async function getHistoryDataInRage(symbol: string, startISO: string, endISO: string, interval: string): Promise { try { let url = `https://query1.finance.yahoo.com/v8/finance/chart/${symbol}?symbol=${symbol}&period1=${dtime.getEpocFromTime( startISO )}&period2=${dtime.getEpocFromTime(endISO)}&interval=${interval}`; let resp = await axios.get(url); let head = resp.data.chart.result[0]; return { timestamp: head.timestamp, date: head.timestamp.map((x: number) => new Date(x * 1000)), open: head.indicators.quote[0].open, close: head.indicators.quote[0].close, high: head.indicators.quote[0].high, low: head.indicators.quote[0].low, volume: head.indicators.quote[0].volume, }; } catch (e) { dlog.ex(e as Error, true); } return undefined; } // verified -- works fine export async function getBulkHistoryData( symbols: string[], interval: TInterval, candle_count?: number ): Promise | undefined> { let result = new Map(); for (let s of symbols) { let data = await getHistoryData(s, interval, candle_count); if (!data) { throw Error("not found"); } result.set(s, data); } return result; } // API for NSE // We should use 3p libs as it uses some cookies export type TSupportedNSEIndex = "NIFTY 50" | "NIFTY BANK" | "NIFTY ENERGY" | "NIFTY 200" | "NIFTY 500"; export async function fetchNSEIndexList(index: TSupportedNSEIndex): Promise { /*' try { let data = (await getIndex(index)) as any; let result: yahooFin.TStockInfo[] = []; for (var x of data.data) { // log.obj(x); try { let d: yahooFin.TStockInfo = { exchange: "NSE", _id: x.symbol + ".NS", symbol: x.symbol, change: x.change, pchange: x.pchange, name: x.meta?.companyName || x.symbol, week52Low: x.yearLow, week52High: x.yearHigh, volume: x.totalTradedVolume, ltp: x.lastPrice, low: x.dayLow, high: x.dayHigh, open: x.open, timestamp: 0, // todo }; result.push(d); } catch (e) { dlog.d("Not able to fetch latest stock info"); dlog.ex(e as Error, true); } } dlog.s(`NSE Data fetched ${result.length} item found`); return result; } catch (e) { dlog.d("Exception: Not able to fetch latest stock info may be NSE API is broken"); dlog.ex(e as Error, true); }*/ return []; } export async function getAllBSEData(): Promise { ` let result1 = axios.post("https://www.bseindia.com/markets/Equity/EQReports/MarketwatchDownloads.aspx",{ headers: { accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "accept-language": "en-US,en;q=0.9,bn;q=0.8", "cache-control": "max-age=0", "content-type": "application/x-www-form-urlencoded", "sec-ch-ua": '" Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"macOS"', "sec-fetch-dest": "document", "sec-fetch-mode": "navigate", "sec-fetch-site": "same-origin", "sec-fetch-user": "?1", "upgrade-insecure-requests": "1", cookie: '__gads=ID=b4e6e513492f9573:T=1646390043:S=ALNI_MYUrflGchnwGWTSzaBV4bVusI0ACg; _gid=GA1.2.1158531587.1647335036; gabseCookie=GA1.3.264675318.1642930805; gabseCookie_gid=GA1.3.48756904.1647335036; _ga_TM52BJH9HF=GS1.1.1647335036.5.1.1647335344.0; _ga=GA1.2.264675318.1642930805; ASP.NET_SessionId=pi2vjk3wcd1d3fb5wfxom0ps; RT="z=1&dm=bseindia.com&si=f47d3745-0426-490c-b4b4-239131217683&ss=l0rwr5cd&sl=6&tt=6gd&obo=1&rl=1&nu=1xsk887&cl=ba7a&ld=6idc&r=4hnwscbh&ul=ba7h"', Referer: "https://www.bseindia.com/markets/Equity/EQReports/MarketwatchDownloads.aspx", "Referrer-Policy": "strict-origin-when-cross-origin", }, body: , method: "POST", }); `; let url = "https://www.bseindia.com/markets/Equity/EQReports/MarketwatchDownloads.aspx"; let body = "__EVENTTARGET=ctl00%24ContentPlaceHolder1%24imgDownload&__EVENTARGUMENT=&__VIEWSTATE=R8ee%2FL%2Bl8UOfkriL3X5lfgdmiYXBmm%2Ffht5v2bFUBBjevr8o8XMv6cXpAosfxBjpIcLOBLaaUb8JWmbBTsLT7P3RVGyIZDLAL2cR73irXtN%2FoeDT0C95yW6xEe%2BTOVnAtMB8px5MN7dTepX7EMWgiafJ%2FV77z9CtzoHtSkz4sxNTpo3hCMpkCher%2Bv0%2FZys5mhHw5SHwSI2QMD%2B3Pv2Py1VeK8HdOCDIGZv6bMA9GwOHwQASdcOAyMGXLanTD3LHlOBi8SwQUC5UEDibsmWDanGGPdTcyKgX9pjYkcYxP8Ej63LqyvbknfmXCdPNhe2BB6I%2Bqq5ByNe%2BsMOgVfdDs%2B9uY9ExJqf%2BfJVdK0GN7GZnZhzBeVYZjO1Pk5kfDFirggBMQWqSYgUaTXRrGawVlWMv92BaRCXFovPhs%2FDP9PDaavDPjRTVSAiwc62n7wCm8YNyDFtM9cwfSoZJen27FDuufVMsD3r7MbSqOVGm7uoLW2uB0JV8q4sHtNDzCi52BI4G8LQhnRX5X2WJgAVjQzwt%2FpoyTrFVyyAwofZsD3dYLXzJ6K1PzO6TC5NUQA4do7YTjEyG1lVLxcAjnmeKp%2BFvc1iaf27sD7ywzobzLr8KPqJ0yVDQIjm1jHBz3si8LDVcCYDSx2%2FlNUd%2Bdw2fxeVAo1eRRUlSWimqyvVIOgpkaWbunnVLfvBA8o%2BYwfXK3I1%2B0vdxazYeGEhSAqWtZTky1pVGKaJf6jTIibD%2BLH4JtHu9w1Hk5Nw5Gg44JkQ14qHu9huANp%2FzJ31qUb2rwLm8ScifHmfdg9VxAiCEKbX%2Fvy9TsUVxxZ98pflV%2Fa%2F0Ronkkhfb4%2B2TUxquiInlB4%2FuK0T%2F%2FyB7A7AlPhqBioVUFfm6mRxpIaPjhaj9v%2Buf2sLx6bJP9%2FnwhDpPyzgMedvogwnwbkRvH7JZfGPIpqSfhGATrhHWhrgxLqUEjh%2F0Vgmi1yQ4d4WcPuEZX%2Fma2d3UmnV74dt4qawMe%2FHxm9jKOe1vQrvyoB5aO3mpTFkapnDq5XHqKBRzJpYEOPq%2BY1nWoU%2FcUs9kw2ebDcjgF3DJzW9a99MViktgMw7TmUtvoSRv3WnbKK8RgjnZJCLquIKg1ka%2F40rhNGADGaONZrtxGhH5WZyn8DRsYcYlaho3r52%2B3zHHB%2B4FkLk48BO%2BKmSDpk%2B9y2CeOQRcsgypXstgpANlH1%2BeG%2BAemhcMCtDnsyM0XIRUh4QH4IqSSe5MPOOEl7XqAIx3Fa3%2BrEqs1GRWF1gbGKml5CeGGFsx80p%2BPUnAiBeSjHOqv90GZxeAec5fLWSQD3HS24xClrkqzMKkB%2FGWjxc0zw0Gb9Q0inLcSlY8ur%2Fm4EFWeO9szg6wupQuLPWRZF9GzMvk7AioMRqZjIxHeATpaqUGdtFAfVRj4ZuNA0qLU%2FBDUMM9q8nZWz%2FRBVWkGg5ZMB9TYnIt6IawcVJwKGLv6pwRtO0IUcDt3gTCGQF9%2FLfRBR9pn30wLP4FPOA4W%2BEapAPAOW25CuZQfawa65Bzj8PrpnMw3oIsRdMwwp6gKqC5muLwHX4kUahR2hKvJ4N4L7L%2BMuZKEFA0duL78Y8RmIx7g85BTxpwP6faD1oCfaCrKP0NIeTYeaook1fZgm%2Fit4f4oXIhdTQlbJKaW3ZjSn2rXrXgOcMobnY3yZStgVfZvfX9RnkpqJ%2B3tF0aric1%2B10P3UkEgDAkYH7KP1lJndDsSI%2FJhLVEw74ABwjq4rzV5uwpV2bJ73qjZ1I7RkBY%2BLQ3spXJIvIuRunaDY%2F8mhivTEZ%2BAj3CEQz7otruBRIqMCSR8scIMELfe0O5x0XkhU1Qq%2FoV67YuVYpm5Qknlkh1ooTUzgnanpCVecr5GIn%2FUc4tqPWYhfIybF3f4xM7ACY%2FhLxjQ6UfTV8LC7WZyb28jmdnguHIb%2BLQB3FglhLzmWsSu569C6SDS5HrWVH0GtfgstAcGKDDHUN%2ByYSApF4SKl1pFN2sIsWMkLXvCHo%2BDFEyGp8pKAmHtfiWOxw1mN9AWfdgtKZPTHqsMmvoUTKehEW49cVrvKWswhENi7Lcy7TVZhpG6EYRyG9R1mbkYcysNi%2Fa6QrZgLEZV9M5MskfgCt03QvXExfPWYAvBHyCxZOYUEO%2FBkrV8FZwFwoMrPGbEx%2BEPK0sAdEhooGCEVAJg8E5VJVLV5l7ZtNM%2FefpPlx0djZYB2I4jEpNuMeEgtafHZHcqKBh2ZZEfa%2FhnnvO4gnH5tB%2BmW4FA%2FiyCZ3gl7htE6UAf8qZIc96Utk2%2F1gGtzeSEFLUUYoJaNVPVJDinwWvNfT2fjrFM3FxwC70NZg4pr0fDejasMgp70o%2FN%2BTPtp7YCgU1dxUjTp225hHTEN05t1AKM0HwI9qXotzdGg32ezhDTHzT%2FJB5E%2BKjdCyPIkHI6iZmnOX5Z5irG1lQvSP2R%2BF7hxqiQg6asfJUpghxLlryUiN%2FUZMU%2BJczpoWkq6a4CWHdb6tk9BNF2r%2Bqf1AiXClmQDF4P7WVcZAnn6LTrMhEJWa4jHwMJ8otlclrGCveXCXlLGdUwIsx7mHCRTh7j6lLiQF5wJA8nppNU8KNPQJ4oi9ZJNh5j8l6FyOmWJMTXnUp9ocfP3Iav3yPe%2BwtSmqEaF01XpFM6fnkFbzAeNXZNSLw0yLIaUutpiJSP4sX4hM%3D&__VIEWSTATEGENERATOR=8134D562&__VIEWSTATEENCRYPTED=&__EVENTVALIDATION=duWAPazV1Nf%2Bk64F%2F1GGVgclG3dvdvnLBCpG%2B2q7%2FXCtMir4Rvgx0SATj7z66G1uOc5nG81Py7oCF%2FVdKHs89Tkegw6QCIDNZi%2Fh9OodCOhjU0eTv%2FzPigvd5e9qA07AImYszq8o9g%2FkCJ8GtWX72CaCTIPJ%2FzsliyMUKzbmx6T6%2Bkoymynd%2BDaTyiifXd%2FrxYeEBZg9WAzNCsc6vZze2GxI0eHHVwkIPJeQT1PI0raj6XXux1b44iA0KovT800ZOGuUzBsJ%2FTOCmovZXb9T3FG%2Bb05kyZyw7l70UkmY4F7JLRDkdiQgFWszT7JTd6RwKY9oWHUnfbHZiGP41QFUV0NWkgMIFMIPt5v%2FHJvRiPBNPAdZ8gqxKTxe8rh%2B6dmLN2YzaXyn7wyDDhv%2Ff25FY2WC8jCgSMZFbes19doRrk87ueZfFkKGSTU2ZxMa%2Bl7JubzPusRBbixk3LBEvD%2F%2BUzQO5UI6IsVuqJaM6E8Nh1mLQUxYpas9z9fyPjwofjr6lFFoLiri7iE%2B0qL4DS8pV7ev3hUfPDT5Q2uLXnrDy6gVjECkoRhJMzU4MzyYiRMP44IpHG4tloBL2CWSCn3QCN1uXKDqlyxu49hDtzsiQQsnjdgB9k1AGjFjmgnRDCuz2IzFZLaoO5BtIpuNQeCkhN5fKpa3UzYag%2BuNRXl9wy37RqpTEqjUYYn1Go1fEtgTz%2BWWAWri7T%2BOFZBrolIJzZ38hDvp%2FreRhB4wJqF37ehouPFEXWVjwyz1MbL071RN%2FcAVzS8B4qkyXZz8a4N5RTyL0hoIsiIQGIBABfP8GVWUMlSfKDDE%2BAuuMH%2BuuG%2BBeusXHBzz6q59LVPbCJNu4VFN6DkPxPjCGmho3LuBU%2BgfVREFl3IZIilWJoBAUUqxZBhs2ghhDxWptt345gGdnEV5e1PN%2FGYuG7fvJeXYmWRk9BqdH%2Ft6FdyadQctTDhHYmTGKSQuecA7D00QuGb3jo7fIbaKBBWaX2VWaCp9oyO64tsX9yvHRP0FXG8T8hL3VzqsNg7992%2Fu8NdC%2BDc4PUgftoHru1i3a7mjCyR4%2BLanW5D8JDwxuQL%2FfcSlojIxwvspc5Z9MjS7l4QTxnsxsd%2FegiIjHFN8VbES%2BLE7PYDdmE7a1bhknnNeL7xVuwko19vtwLs9706kKonGQGHq%2FudE81FYeLUl6MykZlk2PAg0p8S0NByoYo50CsO%2B%2B10yKoypvyDNGeXlggQ0XIkFD5lnOuiDWVrJvyIbee5zDiXTgr19WN5oryDKItCv%2F%2BvLSi1FHdsgAx7juqRHsXu1i51142U0zUHSNV3OwhWqpB%2BTaMZP9gpTWMfEwWdjzySeZPcnMEiUYgLL5AbQorsjEn4ru2LHtojlzaq2dgseNHmGCvZ5MWWK%2BZP1n0NY%2F6rphdxzOXhnQmFHC2253Bj1ZMc2tmp2OXhReCTbQ%2BNb9avKhx%2F5mV1WQqUDIUcDe5HBcEiNaKw5j7viw5z5BsyQUpub9WCaIsHNmHvH4oDzJtm1m7490pRV9mLGimUUzjQ%2F6Hdx0X%2BBGe49XJE3v61CmjBcFNTs0ti%2F%2BWO69d8Mo945j1jCwCIjkZXrI2PtoMseKT%2BXyVuho9ZxcjaHQpe5Ncjb2f%2F6x7gVwQ%2B3VVSrGqcfe3dQ2bpVK0QyW7z0kZIuoYU1VFH2uhXd4ZweAB3olemQ2zE%2F3LJff7oYv7ZqMKh99ZCfyyd2kunQz6l90Xpgf%2FjphG6aY0GnBOX9dwgdoZeFropEXnj5I6sYaZtn1jAd3RtBpZV7cDuvZ8INFSfrXxgGbSQTHzQnoRl4y7Rp6M9UHc06QPZh3CWNDzHStvIht5tDIRCSUbH%2Fv8F9EpJvBzAikznGDZrdURqgKGrjxmA6AUzEloWyBUOmEEYvkQZS4pLrGe%2BP4Rf4wmR7Crzg1U2qMXzpYfOuyhwjzdjOLiJ0z4uwffYu2uECUbgmFPNw2Tq7xcVOKETbGxVzD5yuiO2tHLU7WEwJgWtJG%2FN6aLfEaIEUqutASrC20X9XA40fa7E0wNUaAEX6TDKzUjKSNlH2EZgwI14%2BBZS6qc3SdNAuo8bt4rIylgvDFMwWwlzKAzfBnlDDBY%2FNycRWYjLvImlzneHmLIZ%2F3CUyRZQBoimXu1uJTl4lQV7t8NkX6PK7NhGZ%2FqU%2BvvbwfkJmldFvtQgXI4f%2BEC%2BHWEr70Kx5E9CaQuGcrX69kXNDpvN3%2F84mkzFaKvMDWIeY3Waqd38TCVlmqqtQPavskHcR39fckv7BVNvCQOQO9A8DFWeqR6AZbCKC3qw5GwR2aMu1bkMJ&ctl00%24ContentPlaceHolder1%24hdfTy=AllMkt&ctl00%24ContentPlaceHolder1%24hdfFL=All&ctl00%24ContentPlaceHolder1%24hdfCOrder=TT&ctl00%24ContentPlaceHolder1%24DDate=&ctl00%24ContentPlaceHolder1%24ddlType=AllMkt&ctl00%24ContentPlaceHolder1%24ddlGrp=A&ctl00%24ContentPlaceHolder1%24ddlIndx=16&ctl00%24ContentPlaceHolder1%24ddlOrder=TT"; let csv = await dnetwork.post(url, body); let json = await dserialization.getJsonFromCSVString(csv); let result: TStockInfo[] = []; for (let r of json) { result.push({ _id: r["Security Name"] + ".NS", ltp: parseFloat(r.LTP), open: parseFloat(r.Open), symbol: r["Security Name"] + ".BS", name: r["Security Name"], exchange: "BSE", volume: 0, high: parseFloat(r.High), low: parseFloat(r.Low), change: 0, pchange: 0, timestamp: 0, clock_type: 'OFF_MARKET' }); } return result; } // API on Clock // Function to return clock typeing export function processStockInfo(info: TStockInfo) { info.ltp_ext = getLtpExtFromLtp(info) info.clock_type = getTradingClockType(info.exchange) } export type TClockType = 'PRE_MARKET' | 'ON_MARKET' | 'POST_MARKET' | 'OFF_MARKET' export function getTradingClockType(exchange: TExchange): TClockType { const currentDateTime = new Date(); if (isHoliday(currentDateTime)) { return 'OFF_MARKET'; } const tradingHours = getTradingHours(exchange); if (isWithinTradingHours(currentDateTime, tradingHours.preMarket)) { return 'PRE_MARKET'; } if (isWithinTradingHours(currentDateTime, tradingHours.onMarket)) { return 'ON_MARKET'; } if (isWithinTradingHours(currentDateTime, tradingHours.postMarket)) { return 'POST_MARKET'; } return 'OFF_MARKET'; } // ----- Helper functions ------ function getLtpExtFromLtp(info: TStockInfo) { switch (getTradingClockType(info.exchange)) { case 'POST_MARKET': return info.post_ltp || info.ltp case 'OFF_MARKET': return info.post_ltp || info.ltp case 'ON_MARKET': return info.ltp; case 'PRE_MARKET': return info.pre_ltp || info.post_ltp || info.ltp } } // helper function function isWithinTradingHours(dateTime: Date, tradingHours: [Date, Date]): boolean { const [start, end] = tradingHours; return dateTime >= start && dateTime <= end; } function isHoliday(dateTime: Date): boolean { const day = dateTime.getDay(); // Get the day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday) return day === 0 || day === 6; // Return true if it's Sunday (0) or Saturday (6), indicating a holiday } interface TradingHours { preMarket: [Date, Date]; onMarket: [Date, Date]; postMarket: [Date, Date]; } function getTradingHours(exchange: TExchange): { preMarket: [Date, Date]; onMarket: [Date, Date]; postMarket: [Date, Date] } { const tradingHours: Record = { /*NYSE: { preMarket: [new Date('9:00 AM'), new Date('9:30 AM')], onMarket: [new Date('9:30 AM'), new Date('4:00 PM')], postMarket: [new Date('4:00 PM'), new Date('6:30 PM')] },*/ NASDAQ: { preMarket: [new Date('4:00 AM'), new Date('9:30 AM')], onMarket: [new Date('9:30 AM'), new Date('4:00 PM')], postMarket: [new Date('4:00 PM'), new Date('8:00 PM')] }, LSE: { preMarket: [new Date('8:00 AM GMT'), new Date('8:30 AM GMT')], onMarket: [new Date('8:30 AM GMT'), new Date('4:30 PM GMT')], postMarket: [new Date('4:30 PM GMT'), new Date('5:00 PM GMT')] }, NSE: { preMarket: [new Date('9:00 AM IST'), new Date('9:15 AM IST')], onMarket: [new Date('9:15 AM IST'), new Date('3:30 PM IST')], postMarket: [new Date('3:30 PM IST'), new Date('4:00 PM IST')] }, BSE: { preMarket: [new Date('9:00 AM IST'), new Date('9:15 AM IST')], onMarket: [new Date('9:15 AM IST'), new Date('3:30 PM IST')], postMarket: [new Date('3:30 PM IST'), new Date('4:00 PM IST')] } }; return tradingHours[exchange]!!; } } // test (async () => { //dlog.d("hello") //let data = await yahooFin.getHistoryData("TCS.NS", "1h", 50); //dlog.obj(data); //dlog.obj(await yahooFin.getBulkStockQuoteWithFullKey2(["^GSPC"])) //dlog.obj(yahooFin.getTradingClockType('NASDAQ')) //let result = await yahooFin.getAllBSEData(); // let result = await yahooFin.getHistoryDataInRage("TCS.NS", "2022-03-16T00:00:00.000Z", "2022-03-17T00:00:00.000Z", "5m"); // dlog.obj(result); })(); (async () => { //dlog.obj(await yahooFin.getBulkStockQuoteWithFullKey(['MSFT', 'TSLA', '^SPX'])) })();