UNPKG

@zero65tech/indian-stock-market

Version:
224 lines (182 loc) 5.71 kB
import HOLIDAYS from "./build/holidays.json"; import SPECIAL_DAYS from "./build/special-days.json"; const IST_OFFSET_MILLIS = 5.5 * 60 * 60 * 1000; const MAHURAT_DAY = "2026-11-08"; function isHoliday(date = new Date()) { // Normalize input date if (typeof date === "string") { date = new Date(date); } else if (date instanceof Date) { // Apply IST offset date = new Date(date.getTime() + IST_OFFSET_MILLIS); } else { throw new TypeError("Invalid date input"); } let yyyy = date.getUTCFullYear(); let mm = date.getUTCMonth() + 1; let dd = date.getUTCDate(); // Check special days first if (SPECIAL_DAYS[yyyy]?.[mm]?.includes(dd)) { return false; } // Check if weekend (Saturday=6, Sunday=0) const dayOfWeek = date.getUTCDay(); if (dayOfWeek === 0 || dayOfWeek === 6) { return true; } // Check if holiday return HOLIDAYS[yyyy]?.[mm]?.includes(dd) ?? false; } function isOpen(date = new Date()) { if (isHoliday(date)) { return false; } // Apply IST offset date = new Date(date.getTime() + IST_OFFSET_MILLIS); const dateStr = `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}-${String(date.getUTCDate()).padStart(2, "0")}`; const hours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600; if (dateStr === MAHURAT_DAY) { return hours >= 18 && hours < 19.25; } else { return hours >= 9 && hours < 15.5; } } // TODO const specialday = new Date(MAHURAT_DAY).getTime() / 1000 / 60 / 60 / 24; // UTC function _istDayAndHr(date) { let hrs = date.getTime() / 1000 / 60 / 60 + 5.5; return [Math.floor(hrs / 24), hrs % 24]; } function eq(name) { const match = name.match(/^(.*?)-([A-Z]{1,2})$/); return match ? { symbol: match[1], scrip: match[1], series: match[2] } : { symbol: name, scrip: name, series: null }; } function monthlyExpiry(yy, mon, weekday) { const yyyy = 2000 + parseInt(yy); const mm = [ "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", ].indexOf(mon); let dd = new Date(yyyy, mm + 1, 0).getDate(); // Last day of the month while (new Date(yyyy, mm, dd).getDay() != weekday) dd--; for (; dd >= 1; dd--) { const date = `${yyyy}-${String(mm + 1).padStart(2, "0")}-${String(dd).padStart(2, "0")}`; if ( HOLIDAYS[yyyy] === undefined || HOLIDAYS[yyyy][mm + 1] === undefined || !HOLIDAYS[yyyy][mm + 1].includes(dd) ) return date; } } function weeklyExpiry(yy, m, dd) { const year = "20" + yy; const mm = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "O", "N", "D"].indexOf(m); return `${year}-${String(mm + 1).padStart(2, "0")}-${dd}`; } function info(symbol) { console.warn(".info() is deprecated. Use .fo() instead."); // FUT - Monthly Expiry (only) let match = symbol.match(/^(\S+?)(\d{2})([A-Z]{3})FUT$/); if (match) { let script = match[1]; let expiry = monthlyExpiry(match[2], match[3], script == "FINNIFTY" ? 2 : 4); return { script, exp: match[2] + match[3], expiry, type: "FUT" }; } // OPT - Monthly Expiry match = symbol.match(/^(\S+?)(\d{2})([A-Z]{3})([\d.]+)(PE|CE)$/); if (match) { let script = match[1]; let expiry = monthlyExpiry(match[2], match[3], script == "FINNIFTY" ? 2 : 4); return { script, exp: match[2] + match[3], expiry, strike: parseFloat(match[4]), type: match[5], }; } // OPT - Weekly Expiry match = symbol.match(/^(NIFTY|BANKNIFTY|FINNIFTY)(\d{2})(\w{1})(\d{2})([\d.]+)(PE|CE)$/); if (match) { let script = match[1]; let expiry = weeklyExpiry(match[2], match[3], match[4]); return { script, exp: match[2] + match[3] + match[4], expiry, strike: parseFloat(match[5]), type: match[6], }; } // MF & EQ return { script: symbol }; } function fo(name) { // FUT - Monthly Expiry (only) let match = name.match(/^(\S+?)(\d{2})([A-Z]{3})FUT$/); if (match) { let scrip = match[1]; let expiry = monthlyExpiry(match[2], match[3], scrip == "FINNIFTY" ? 2 : 4); return { symbol: scrip, scrip, exp: match[2] + match[3], expiry, type: "FUT" }; } // OPT - Monthly Expiry match = name.match(/^(\S+?)(\d{2})([A-Z]{3})([\d.]+)(PE|CE)$/); if (match) { let scrip = match[1]; let expiry = monthlyExpiry(match[2], match[3], scrip == "FINNIFTY" ? 2 : 4); return { symbol: scrip, scrip, exp: match[2] + match[3], expiry, strike: parseFloat(match[4]), type: match[5], }; } // OPT - Weekly Expiry match = name.match(/^(NIFTY|BANKNIFTY|FINNIFTY)(\d{2})(\w{1})(\d{2})([\d.]+)(PE|CE)$/); if (match) { let scrip = match[1]; let expiry = weeklyExpiry(match[2], match[3], match[4]); return { symbol: scrip, scrip, exp: match[2] + match[3] + match[4], expiry, strike: parseFloat(match[5]), type: match[6], }; } return null; } function hasOpened() { console.warn(".hasOpened() is deprecated. Shall be removed eventually."); let date = new Date(); if (isHoliday(date)) return false; let [day, hrs] = _istDayAndHr(date); if (day == specialday) return hrs >= 18; else return hrs >= 9; } function hasClosed() { console.warn(".hasClosed() is deprecated. Shall be removed eventually."); let date = new Date(); if (isHoliday(date)) return false; let [day, hrs] = _istDayAndHr(date); if (day === specialday) return hrs >= 19.25; else return hrs >= 15.5; } export default { eq, info, fo, isOpen, hasOpened, hasClosed, isHoliday }; export { isHoliday as isISMHoliday, isOpen as isISMOpen };